diff --git a/scripts/benchmark-live-providers.mjs b/scripts/benchmark-live-providers.mjs index 7d6810019..ffe2c8def 100644 --- a/scripts/benchmark-live-providers.mjs +++ b/scripts/benchmark-live-providers.mjs @@ -175,7 +175,13 @@ async function runGenerationOne({ liveSpec: loadedLiveSpec, providerConfig, stra if (typeof agent.generateFirstVariant === 'function') { firstOutput = await agent.generateFirstVariant(event, {}); firstReviewableMs = roundMs(performance.now() - startedAt); - output = await agent.generateRemainingVariants(event, { firstOutput }); + // Only ask for a tail when one was requested. tests/live-e2e/agent.mjs + // already gates its split-progressive path on `event.count > 1`; without the + // same guard here a one-variant request still ran the tail, and the + // parallel strategy would assemble its three fixed lanes regardless. + output = Number(event.count) > 1 + ? await agent.generateRemainingVariants(event, { firstOutput }) + : firstOutput; } else { output = await agent.generateVariants(event, {}); firstReviewableMs = roundMs(performance.now() - startedAt); diff --git a/scripts/lib/live-provider-benchmark.mjs b/scripts/lib/live-provider-benchmark.mjs index d6dcab112..4bfc82063 100644 --- a/scripts/lib/live-provider-benchmark.mjs +++ b/scripts/lib/live-provider-benchmark.mjs @@ -309,8 +309,16 @@ export function createProviderLiveAgent({ provider, model, strategy, liveSpec, o async generateRemainingVariants(event, context) { const first = pendingFirst.get(event.id) || context.firstOutput; if (!first?.variants?.[0]) throw new Error(`first variant state missing for ${event.id}`); + const tailCount = Number(event.count) - 1; + // A one-variant request has no tail. Math.max(1, ...) floored the count at + // one, so this fetched a second direction and assembled two variants for a + // set the caller asked to be one. + if (tailCount < 1) { + pendingFirst.delete(event.id); + return first; + } const remaining = await request({ - event: { ...event, count: Math.max(1, event.count - 1) }, + event: { ...event, count: tailCount }, phase: 'remaining-directions', firstVariant: first.variants[0], }); diff --git a/tests/live-provider-benchmark.test.mjs b/tests/live-provider-benchmark.test.mjs index 6d70f7320..0bd93ddfb 100644 --- a/tests/live-provider-benchmark.test.mjs +++ b/tests/live-provider-benchmark.test.mjs @@ -178,3 +178,43 @@ describe('parallel-compact lane orchestration', () => { assert.equal(output.variants.length, 3); }); }); + +describe('progressive-full variant count', () => { + const output = (n) => ({ + scopedCss: '@scope ([data-impeccable-variant="1"]) { .a { color: var(--color-ink); } }', + variants: Array.from({ length: n }, () => ({ innerHtml: VARIANT, params: [] })), + }); + + const agentWith = (onRequest) => createProviderLiveAgent({ + provider: 'anthropic', + model: 'test-model', + strategy: 'progressive-full', + liveSpec: '', + requestImpl: onRequest, + }); + + it('asks for no tail on a one-variant request', async () => { + // Math.max(1, count - 1) floored the tail at one, so a count:1 request + // fetched a second direction and returned two variants. + const phases = []; + const agent = agentWith(({ phase, event }) => { + phases.push(phase); + return Promise.resolve(output(event.count)); + }); + await agent.generateFirstVariant({ id: 'one', count: 1 }); + const result = await agent.generateRemainingVariants({ id: 'one', count: 1 }, {}); + assert.deepEqual(phases, ['first'], 'no remaining-directions call belongs on a one-variant set'); + assert.equal(result.variants.length, 1); + }); + + it('asks for exactly the tail on a three-variant request', async () => { + const counts = []; + const agent = agentWith(({ phase, event }) => { + if (phase === 'remaining-directions') counts.push(event.count); + return Promise.resolve(output(event.count)); + }); + await agent.generateFirstVariant({ id: 'three', count: 3 }); + await agent.generateRemainingVariants({ id: 'three', count: 3 }, {}); + assert.deepEqual(counts, [2], 'the tail is count - 1, not a floored 1'); + }); +});