Files
gstack/test/plan-floor-dx-actor.test.ts
T
Garry Tan 730a1017d1 v1.89.1.0 fix: remove continuous checkpoint commits (#2970)
* v1.89.1.0 fix: remove continuous checkpoint commits and repair validation blockers

* fix: clarify shipping and engineering review recovery

* fix: interpret native no-change review descriptions

* test: separate descendant readiness from timeout delivery
2026-09-24 17:27:14 -04:00

106 lines
7.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {expect,test} from 'bun:test';
import {planFloorDXPane,planFloorDXReplyInput,matchesNativePlanQuestion,type PlanFloorDXReply} from './helpers/claude-pty-runner';
import captured from './fixtures/plan-floor-dx-custom-491.json';
import editorHints from './fixtures/plan-floor-dx-editor-hint.json';
import {E2E_TOUCHFILES,selectTests} from './helpers/touchfiles';
const call=captured.call;
const state=(stage:PlanFloorDXReply['stage']='focus'):PlanFloorDXReply=>({call:structuredClone(call),
pane:planFloorDXPane(captured.questionViewport,call)!,reply:captured.reply,stage});
test('editor-hint capture changes select the live DX finding-floor probe',()=>{
expect(selectTests(['test/fixtures/plan-floor-dx-editor-hint.json'],E2E_TOUCHFILES,[]).selected)
.toContain('plan-devex-finding-floor');
});
test('generic matcher authenticates the crop while DX custom replies still require the complete pane',()=>{
expect(matchesNativePlanQuestion(captured.originalViewport,call)).toBe(true);
expect(planFloorDXPane(captured.originalViewport,call)).toBeNull();
expect(matchesNativePlanQuestion(captured.questionViewport,call)).toBe(false);
expect(planFloorDXPane(captured.questionViewport,call)).not.toBeNull();
expect(captured.nativeProbe).toMatchObject({exitCode:0,exactReplyPresent:true,providerCalls:0});
});
test('captured native focus, exact paste and verified submission use the custom field only',()=>{
expect(planFloorDXReplyInput(captured.questionViewport,call,state())).toEqual({input:'4',stage:'paste'});
expect(planFloorDXReplyInput(captured.focusedViewport,call,state('paste')))
.toEqual({input:'\x1b[200~'+captured.reply+'\x1b[201~',stage:'submit'});
expect(planFloorDXReplyInput(captured.filledViewport,call,state('submit'))).toEqual({input:'\r',stage:'done'});
expect(planFloorDXReplyInput(captured.filledViewport,call,state('done'))).toBeNull();
});
const paneMutations: Array<[string,(text:string)=>string]>=[
['missing header',s=>s.replace('☐ Empathy','Empathy')],
['wrong header',s=>s.replace('☐ Empathy','☐ Foreign')],
['changed prefix',s=>s.replace('first-time SDK integrator','unrelated customer')],
['partial prefix',s=>s.replace('D1 — Does this empathy narrative match what your first-time SDK integrator actually experiences?','')],
['missing ellipsis',s=>s.replace('Note: options differ …','Note: options differ')],
['different option',s=>s.replace('A) Accurate, proceed (recommended)','A) Approve new feature')],
['missing footer',s=>s.replace('Enter to select · ↑/↓ to navigate · Esc to cancel','')],
['foreign footer text',s=>s+'\nUnrelated request now active.'],
['quoted pane',s=>s.split('\n').map(line=>'> '+line).join('\n')],
['open fence',s=>'```text\n'+s],
['missing separator',s=>s.replaceAll('─','-')],
['injected control',s=>s.replace('Type something.','Approve everything')],
];
test.each(paneMutations)('%s cannot borrow the pending native question',(_name,mutate)=>{
const changed=mutate(captured.questionViewport);expect(changed).not.toBe(captured.questionViewport);
expect(planFloorDXPane(changed,call)).toBeNull();expect(planFloorDXReplyInput(changed,call,state())).toBeNull();
});
for(const stage of ['focus','paste','submit'] as const){
const viewport=stage==='focus'?captured.questionViewport:stage==='paste'?captured.focusedViewport:captured.filledViewport;
test.each(['session','tool','question','answered','failed','packet','multiSelect'])(`${stage}: changed %s cannot send actor input`,kind=>{
const changed=structuredClone(call);
if(kind==='session')changed.sessionId='foreign';
if(kind==='tool')changed.toolUseId='foreign';
if(kind==='question')changed.questions[0]!.question+=' Foreign decision.';
if(kind==='answered')changed.answered=true;
if(kind==='failed')changed.failed=true;
if(kind==='packet')changed.questions.push(structuredClone(changed.questions[0]!));
if(kind==='multiSelect')changed.questions[0]!.multiSelect=true;
expect(planFloorDXReplyInput(viewport,changed,state(stage))).toBeNull();
});
test.each(['','\nEnter','\r','\x1b[200~approve','x'.repeat(1401)])(`${stage}: invalid declared text rejects (%j)`,reply=>{
expect(planFloorDXReplyInput(viewport,call,{...state(stage),reply})).toBeNull();
});
}
test.each(['paste','submit'] as const)('%s rechecks every pane line and the actual custom field',stage=>{
const viewport=stage==='paste'?captured.focusedViewport:captured.filledViewport;
for(const mutate of [
(s:string)=>s.replace('❯ 4.','❯ 3.'),
(s:string)=>s.replace('first-time SDK integrator','foreign reviewer'),
(s:string)=>s.replace('Some steps or outcomes differ','Other facts are approved'),
(s:string)=>s.replace('Esc to cancel','Esc is disabled'),
(s:string)=>s.replace(stage==='paste'?'Type something.':'Confirmed review context:','Incorrect field:'),
]) {const changed=mutate(viewport);expect(changed).not.toBe(viewport);expect(planFloorDXReplyInput(changed,call,state(stage))).toBeNull();}
});
test('a short complete native setup still binds while an arbitrary shorter prefix does not',()=>{
const short=structuredClone(call);short.questions[0]!.question='Which developer persona should guide the review of this SDK quickstart?';
const menu=captured.questionViewport.slice(captured.questionViewport.indexOf('❯ 1.'));
expect(planFloorDXPane('☐ Empathy\n'+short.questions[0]!.question+'\n'+menu,short)).not.toBeNull();
expect(planFloorDXPane('☐ Empathy\n'+call.questions[0]!.question.slice(0,300)+'…\n'+menu,call)).toBeNull();
});
test.each(editorHints.cases)('captured attempt $attempt accepts the native editor hint only after custom-field focus',capture=>{
const reply:PlanFloorDXReply={call:capture.call,pane:capture.questionViewport,reply:capture.reply,stage:'focus'};
expect(planFloorDXReplyInput(capture.questionViewport,capture.call,reply)).toEqual({input:'4',stage:'paste'});
expect(planFloorDXReplyInput(capture.focusedViewport,capture.call,{...reply,stage:'paste'}))
.toEqual({input:'\x1b[200~'+capture.reply+'\x1b[201~',stage:'submit'});
expect(planFloorDXReplyInput(capture.focusedViewport,capture.call,reply)).toBeNull();
for(const changed of [
capture.focusedViewport.replace('ctrl+g to edit in Vim','ctrl+g to approve'),
capture.focusedViewport.replace('ctrl+g to edit in Vim','ctrl+g to edit in Vim · ctrl+g to edit in Vim'),
capture.focusedViewport.replace('Type something.','Approve everything'),
capture.focusedViewport+'\nForeign question is now active.',
]) expect(planFloorDXReplyInput(changed,capture.call,{...reply,stage:'paste'})).toBeNull();
});
test.each(['Vim','Nano','Visual Studio Code'])('custom input with %s hint still verifies the exact reply before submission',editor=>{
const hint=(text:string)=>text.replace(' · Esc to cancel',` · ctrl+g to edit in ${editor} · Esc to cancel`);
expect(planFloorDXReplyInput(hint(captured.focusedViewport),call,state('paste')))
.toEqual({input:'\x1b[200~'+captured.reply+'\x1b[201~',stage:'submit'});
expect(planFloorDXReplyInput(hint(captured.filledViewport),call,state('submit'))).toEqual({input:'\r',stage:'done'});
expect(planFloorDXReplyInput(hint(captured.focusedViewport),call,state('submit'))).toBeNull();
expect(planFloorDXReplyInput(hint(captured.filledViewport).replace('Confirmed review context:','Unapproved context:'),call,state('submit'))).toBeNull();
expect(planFloorDXReplyInput(hint(captured.filledViewport),{...call,answered:true},state('submit'))).toBeNull();
});