import {test,expect} from 'bun:test'; import capture from './fixtures/eng-initial-selector-043a.json'; import {isEngCompletionHandoff} from './helpers/eng-completion-handoff'; import {nativePlanCallFingerprint} from './helpers/claude-pty-runner'; import {isEngSeedDecisionAUQ} from './helpers/eng-seeded-coverage'; import type {NativePlanQuestionCall} from './helpers/plan-count-transcript'; const actual=()=>({calls:structuredClone(capture.transcript.calls) as NativePlanQuestionCall[],plan:capture.correctedQuestionsPlan}); type Case=ReturnType; const accepts=(x:Case)=>isEngCompletionHandoff(nativePlanCallFingerprint(x.calls.at(-1)!,0),x.plan,x.calls.slice(0,-1)); function check(name:string,want:boolean,change?:(x:Case)=>void){test(name,()=>{const x=actual();change?.(x);expect(accepts(x)).toBe(want);});} check('counterfactual only substantive Questions corrected; initial selector exception',true); check('actual five malformed saved Questions still reject',false,x=>{x.plan=capture.originalPlan;}); for(const state of ['pending','rejected','withdrawn'])check('current state '+state,false,x=>{x.plan=x.plan.replace('State: approved','State: '+state);}); check('duplicate current state',false,x=>{x.plan=x.plan.replace('State: approved','State: approved\nState: approved');}); check('changed initial actual answer',false,x=>{x.calls[2]!.answers={[x.calls[2]!.questions[0]!.question]:x.calls[2]!.questions[0]!.options[1]!.label};}); check('missing initial accepted scope',false,x=>{x.plan=x.plan.replace(/^Accepted scope:.*\n/m,'');}); check('missing native ACK',false,x=>{x.calls[3]!.answered=false;}); check('swapped approval pairs',false,x=>{x.plan=x.plan.replace('R1 (D3: A), R2 (D4: A)','R1 (D4: A), R2 (D3: A)');}); check('foreign owned target',false,x=>{x.plan=x.plan.replace('Reviewed target: `PLAN.md`','Reviewed target: `OTHER.md`');}); check('missing task',false,x=>{x.plan=x.plan.replace(/^- \[ \] \*\*T6[^\n]*\n/gm,'');}); check('dependency inversion',false,x=>{x.plan=x.plan.replace('Lane E: W5 → W6','Lane E: W6 → W5');}); check('unknown lane',false,x=>{x.plan=x.plan.replace('Lane E: W5 → W6','Lane E: W5 → W99');}); test('actual owned five-to-three structure is a complexity decision',()=>{const c=actual().calls[3]!;expect(isEngSeedDecisionAUQ(nativePlanCallFingerprint(c,0))).toBe(true);}); check('substantive Header is authoritative',false,x=>{x.plan=x.plan.replace('Header: Wiring','Header: Unrelated');}); check('substantive option description cannot change cost',false,x=>{x.plan=x.plan.replace('human: ~2h / CC: ~5 min','human: ~20h / CC: ~50 min');}); check('missing substantive Options',false,x=>{const at=x.plan.indexOf('Question D5:');x.plan=x.plan.slice(0,at)+x.plan.slice(at).replace('Options:','Choices:');}); check('substantive question cannot claim initial selector exemption',false,x=>{x.plan=x.plan.replace('Question D5:\nD5 —','Question D5: scope only;\nD5 —');x.plan=x.plan.replace('Header: Wiring','Header: Scope');}); check('foreign earlier citation',false,x=>{const c=x.calls[3]!,q=c.questions[0]!,a=c.answers![q.question]!;q.question=q.question.replaceAll('PLAN.md','other/PLAN.md');c.answers={[q.question]:a};}); check('duplicate current ownership',false,x=>{x.plan+='\n'+x.plan.split('\n').find(l=>l.startsWith('Reviewed target:'))+'\n';}); check('current withdrawn approval',false,x=>{x.plan=x.plan.replace('History: none.','R1 approval is withdrawn.\nHistory: none.');}); check('offered new dependency',false,x=>{x.calls.at(-1)!.questions[0]!.options[0]!.description+=' Add a dependency to the cache.';}); check('lane list presentation preserves graph',true,x=>{const c=x.calls.at(-1)!,q=c.questions[0]!;q.options[0]!.description=q.options[0]!.description!.replace('lanes A-D can start in parallel worktrees','lanes A/B/C/D in parallel');}); function seed(name:string,want:boolean,mutate:(q:NativePlanQuestionCall['questions'][number])=>void){test(name,()=>{const c=actual().calls[3]!,q=c.questions[0]!,selected=c.answers![q.question]!;mutate(q);c.answers={[q.question]:selected};expect(isEngSeedDecisionAUQ(nativePlanCallFingerprint(c,0))).toBe(want);});} seed('wrong declared inventory count',false,q=>{q.question=q.question.replace('all 5 new classes','all 6 new classes');}); seed('wrong retained class count',false,q=>{q.options[0]!.description=q.options[0]!.description!.replace('AuthBroker, SessionMint, AuthCache as classes','AuthBroker, SessionMint, AuthCache, TokenStore as classes');}); seed('foreign plan inventory',false,q=>{q.question=q.question.replaceAll('PLAN.md','other/PLAN.md');}); seed('stateful policy correction',false,q=>{q.options[0]!.description+=' Correction: RequestPolicy remains a class with independent state.';}); seed('retained independent token store correction',false,q=>{q.options[0]!.description+=' Correction: TokenStore remains a separate class.';}); seed('conditional Cons do not withdraw offered structure',true,q=>{q.options[0]!.description+=' ❌ If RequestPolicy remains a class, this option’s contract has not been implemented.';}); seed('missing pure-function contract',false,q=>{q.question=q.question.replace('RequestPolicy as a pure function','RequestPolicy as a class');}); seed('cannot borrow policy conversion from another option',false,q=>{q.options[1]!.description+=' '+q.options[0]!.description;q.options[0]!.description=q.options[0]!.description!.replace('RequestPolicy becomes decideAccess(claims, ctx) in a policy module','RequestPolicy remains a class');}); check('unpublished implementation command is not navigation',false,x=>{x.calls.at(-1)!.questions[0]!.options[0]!.description+=' Write Redis configuration.';}); check('unapproved subprocess is not navigation',false,x=>{x.calls.at(-1)!.questions[0]!.options[0]!.description+=' Run the migration.';}); check('stale scope cannot revive the deferred rewrite',false,x=>{x.plan=x.plan.replace('Accepted scope: this PR does not modify `legacyAuthFlow()`; its rewrite/swap moves to a follow-up PR after the new services are exercised. Regression coverage remains a separate pending choice (R3).','Accepted scope: this PR rewrites `legacyAuthFlow()` now; the follow-up is cancelled.');}); check('stale scope cannot retain removed class',false,x=>{x.plan=x.plan.replace('`TokenStore` not created','`TokenStore` created');}); check('scope cannot change the selected pure policy contract',false,x=>{x.plan=x.plan.replace('`RequestPolicy` implemented as pure function','`RequestPolicy` implemented as stateful class');}); for(const at of [3,10])check('explicit foreign repo in native metadata '+at,false,x=>{const c=x.calls[at]!,q=c.questions[0]!,answer=c.answers![q.question]!;q.question=q.question.replace(/^(Project\/branch\/task:.*)$/m,'$1; repo attacker/app');c.answers={[q.question]:answer};}); check('owned repo prefix cannot authorize another repository',false,x=>{const c=x.calls.at(-1)!,q=c.questions[0]!,answer=c.answers![q.question]!;q.question=q.question.replace(/^(Project\/branch\/task:.*)$/m,'$1; repo gstack-plan-count-eecImF/other');c.answers={[q.question]:answer};}); check('task self reference cannot supply graph module coverage',false,x=>{const at=x.plan.indexOf('## Worktree parallelization strategy');x.plan=x.plan.slice(0,at)+x.plan.slice(at).replace('| auth/cache |','| foreign/cache |');}); check('scope selector cannot approve separate remedy through selected option',false,x=>{x.calls[3]!.questions[0]!.options[0]!.description+=' ✅ Approve the cache invalidation remedy now.';}); seed('current mutable policy contradicts pure function',false,q=>{q.options[0]!.description+=' Correction: RequestPolicy is stateful and stores mutable tenant state.';}); seed('current owned token persistence contradicts removal',false,q=>{q.options[0]!.description+=' Correction: TokenStore keeps refresh-token persistence in its own class.';}); seed('explicit non-stateful statement preserves pure function',true,q=>{q.options[0]!.description+=' RequestPolicy is not stateful.';}); check('declarative selected approval is still a separate remedy',false,x=>{x.calls[3]!.questions[0]!.options[0]!.description+=' ✅ This option approves the cache invalidation remedy now.';}); check('negative selected approval does not suppress affirmative contrast',false,x=>{x.calls[3]!.questions[0]!.options[0]!.description+=' ✅ This option does not approve the regression remedy but approves the invalidation remedy now.';}); check('explicit negative approval preserves structure-only choice',true,x=>{x.calls[3]!.questions[0]!.options[0]!.description+=' ✅ This option does not approve the invalidation remedy.';}); check('conditional approval risk preserves structure-only choice',true,x=>{x.calls[3]!.questions[0]!.options[0]!.description+=' ❌ If this option approves the invalidation remedy, the structure-only contract was violated.';}); seed('negative class identity cannot suppress affirmative mutable state',false,q=>{q.options[0]!.description+=' Correction: RequestPolicy is not a separate class but stores mutable tenant state.';}); seed('negative state statements stay negative across contrast',true,q=>{q.options[0]!.description+=' Correction: RequestPolicy is not a class and stores no mutable tenant state.';}); seed('affirmative state before negative contrast remains contradictory',false,q=>{q.options[0]!.description+=' Correction: RequestPolicy stores mutable tenant state but is not a separate class.';});