fix(plan-ceo-review): restore experience-first expansion framing, require the mode handoff, skip pacing menus

Census 36597762183: both mode-routing runs logged provenance and moved on
without the mandated handoff chat; the EXPANSION run asked an unauthorized
batch/narrow pacing menu instead of the first per-addition question; the
expansion-energy proposals led with the spec because v1.87.6.0 dropped
'lead with the felt experience'. The HOLD review detector also rejected a
decision whose grounding line named no plan file although the owned source
Read binds it.
This commit is contained in:
garrytan committed 2026-09-29 16:57:54 +00:00
1 parent 45cdfab2a0
commit 75b22463f3
4 files changed
+18 -9

No files matched your search

+8
View File
@@ -276,3 +276,11 @@ for(const sourcePath of ['C:\\owned\\PLAN.md','\\\\server\\share\\PLAN.md'])test
expect(r.deadlines).toEqual([r.deadline]);expect(r.error).toBeUndefined();expect(r.snapshots.at(-1)).toBe('posture_confirmed');
}else{expect(r.error).toBeInstanceOf(Error);expect(r.snapshots.at(-1)).toBe('failed');}
});
test('a decision whose grounding line names no plan file stays bound by the owned source Read (census 36597762183 HOLD D2)',()=>{
const f=input();revise(f,q=>{q.question=q.question.replace(/Project\/branch\/task:[^\n]*/,'Project/branch/task: gstack-plan-count on main, HOLD SCOPE review of saved project views.');});
expect(buildCeoHoldPostureReview(f)!.plan).toBe(f.source.content);
const unread=input();revise(unread,q=>{q.question=q.question.replace(/Project\/branch\/task:[^\n]*/,'Project/branch/task: gstack-plan-count on main, HOLD SCOPE review of saved project views.');});
unread.publicTools=unread.publicTools.filter(e=>e.toolUseId!==sourceId);
expect(()=>buildCeoHoldPostureReview(unread)).toThrow('complete original source Read/ACK');
});
+2 -1
View File
@@ -64,7 +64,8 @@ export function buildCeoHoldPostureReview(input: CeoHoldPostureReviewInput): Pla
for (const call of [mode, decision]) {
const context = /Project\/branch\/task:([^\n]*)/i.exec(call.questions[0]!.question)?.[1] ?? '';
const plans = [...new Set(context.match(/(?<![\w.:/\\-])[\w.:/\\-]+\.md(?![\w.:/\\-])/gi) ?? [])];
if (plans.length !== 1 || (plans[0] !== name && plans[0] !== source.path)) fail('native source context differs from original plan');
// Naming no plan leaves the owned source Read below as the binding; naming another or several plans does not.
if (plans.length > 1 || (plans.length === 1 && plans[0] !== name && plans[0] !== source.path)) fail('native source context differs from original plan');
}
const decisionContext = /Project\/branch\/task:([^\n]*)/i.exec(decision.questions[0]!.question)?.[1] ?? '';
if (!/\bHOLD SCOPE\b/.test(decisionContext) ||