From 0d88a721536d3b3991f65c1fd834bd2166cd9fc2 Mon Sep 17 00:00:00 2001 From: garrytan Date: Mon, 26 Oct 2026 00:47:06 +0000 Subject: [PATCH] fix: pre-landing review fixes Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- hosts/claude/hooks/auq-error-fallback-hook.ts | 2 +- test/resolver-ask-user-format.test.ts | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/hosts/claude/hooks/auq-error-fallback-hook.ts b/hosts/claude/hooks/auq-error-fallback-hook.ts index 28f4328a3..5f48215df 100755 --- a/hosts/claude/hooks/auq-error-fallback-hook.ts +++ b/hosts/claude/hooks/auq-error-fallback-hook.ts @@ -153,7 +153,7 @@ export function directiveFor(kind: SessionKind): string { 'with kind "auto"; do not emit prose, do not BLOCK. A question with no recommendation, a consent, ' + 'a destructive or irreversible option, or an approval gate is appended with kind "approval" and status ' + '"pending" — never chosen, never approved — and the skill ends at its next gate with ' + - 'GSTACK_RESULT status=gate_pending (Unattended session block).' + 'GSTACK_RESULT status=gate_pending.' ); case 'headless': // #2733 review (multi-specialist): a spawned-marked subagent under a diff --git a/test/resolver-ask-user-format.test.ts b/test/resolver-ask-user-format.test.ts index b8ce4322a..8196adff7 100644 --- a/test/resolver-ask-user-format.test.ts +++ b/test/resolver-ask-user-format.test.ts @@ -345,3 +345,24 @@ describe('CQ2 — cross-file invariant: auto-decide prefix matches the hook', () expect(hookSrc.includes(PREFIX) && out.includes(PREFIX)).toBe(true); }); }); + +// Generated by /ship Step 7 coverage audit (GSTA-91, PR #3421). +// Value: protects=the unattended rule names a block id gstack-skill-start actually prints; fails_when=either side +// renames the id or the old "Unattended session block" pointer returns; why_new=gstack-skill-start.test.ts pins the +// id but nothing ties the resolver prose to it; seam=none; no_claim=model behaviour under unattended (static read of +// the bin source; unit only) +describe('CQ3 — cross-file invariant: the unattended pointer names a block gstack-skill-start prints', () => { + const startSrc = fs.readFileSync(path.resolve(__dirname, '..', 'bin', 'gstack-skill-start'), 'utf-8'); + const emitted = new Set([...startSrc.matchAll(/_emit_block ([a-z][a-z-]*)/g)].map(m => m[1])); + + for (const skillName of ['test-skill', 'plan-eng-review']) { + test(`${skillName}: Tool resolution item 1 cites an emitted block id; no section-style pointer remains`, () => { + const out = generateAskUserFormat({ ...makeCtx(), skillName }); + expect(emitted.has('unattended-session')).toBe(true); + const cited = /Unattended \(per its printed `([a-z-]+)` block\)/.exec(out)?.[1]; + expect(cited, 'item 1 must name the printed unattended block').toBe('unattended-session'); + expect(emitted.has(cited!), `${cited} is not a block gstack-skill-start emits`).toBe(true); + expect(out).not.toContain('Unattended session block'); + }); + } +});