From 1ba225eb9cc9c3594c4dd177b395ae5b2baa01fc Mon Sep 17 00:00:00 2001 From: garrytan Date: Mon, 26 Oct 2026 01:42:58 +0000 Subject: [PATCH] chore: ship coverage test, unattended doc and CHANGELOG for review fixes test/plan-reality.test.ts asserts each phase's gstack-plan-reality check line names PLAN_REALITY (Step 7 gap). docs/unattended.md names the unattended-session block the skill prose now cites (Step 14.5 audit). CHANGELOG [Unreleased] covers the hook pointer fix and the new tests. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- CHANGELOG.md | 5 ++++- docs/unattended.md | 7 +++++-- test/plan-reality.test.ts | 7 +++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c7a81c0b..1dac1942f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,15 +2,18 @@ ## [Unreleased] -**/plan-eng-review no longer points its reader at three things its own text never defines.** The plan-eng-review sections judge marked down clarity and actionability for these references. All three live in shared resolvers, so the fixes reach every skill that renders them: +**/plan-eng-review no longer points its reader at three things its own text never defines.** The plan-eng-review sections judge marked down clarity and actionability for these references. All three live in shared resolvers, so the fixes reach every skill that renders them. The Claude Code hook that backs up AskUserQuestion carried the same stale pointer, so it's fixed too: ### Fixed - **Claims Need Evidence kernel** (`scripts/resolvers/preamble/generate-evidence-directive.ts`): the evidence-kind bullet ended with "Reuse rules: Step 16." That step exists only in /ship, so in every other skill the pointer led nowhere. It's gone. /ship's Step 16 still states its own reuse rule ("Reuse a check when its inputs match"), and every tier's DONE line still asks you to name reuse. - **AskUserQuestion Tool resolution** (`generate-ask-user-format.ts`): "per its Unattended session block" read like a section of the skill, but the block is runtime output. Item 1 now names the `unattended-session` block that gstack-skill-start prints, which is the id on its `GSTACK_INSTRUCTION_BEGIN` line. The failure fallback's `unattended` branch dropped its repeat of that pointer, because item 1 already states the rule. +- **AskUserQuestion fallback hook** (`hosts/claude/hooks/auq-error-fallback-hook.ts`): its unattended directive ended with "GSTACK_RESULT status=gate_pending (Unattended session block).", the same section-style pointer to runtime output. The parenthetical is gone; the directive itself already states the rule. - **Reality rows, eng/ceo branch** (`scripts/resolvers/plan-reality.ts`): the Completion Summary row and plan-eng-review's checklist ask for the `PLAN_REALITY` line, but the operative block never said where that line comes from. It now says `gstack-plan-reality check` prints it. ### Tests - `test/honesty-kernel.test.ts` no longer requires the Step 16 pointer. It now rejects any `Step ` cross-reference in the kernel, which every skill renders. +- `test/resolver-ask-user-format.test.ts` checks across files that the unattended pointer names `unattended-session` and that gstack-skill-start really emits a block with that id, so renaming either side fails the test. `test/auq-error-fallback-hook.test.ts` asserts the hook's unattended directive no longer says "Unattended session block". +- `test/plan-reality.test.ts` checks that the reality-rows block, generated for each of the eng, ceo and devex phases, says its `gstack-plan-reality check` line prints `PLAN_REALITY`. - Every changed SKILL.md shrank, so 89 pins in `test/fixtures/skill-md-size-allowlist.json` were lowered to their new exact sizes (a ratchet: nothing grew). The /ship goldens were regenerated. ### Gate integrity diff --git a/docs/unattended.md b/docs/unattended.md index 249ff535c..fcd0c022c 100644 --- a/docs/unattended.md +++ b/docs/unattended.md @@ -16,8 +16,11 @@ it, so `headless` keeps its BLOCK semantics. ## What the session kind changes -`gstack-skill-start` prints `SESSION_KIND: unattended` and -`UNATTENDED_SESSION: true`, then applies these rules for the whole skill: +`gstack-skill-start` prints `SESSION_KIND: unattended`, +`UNATTENDED_SESSION: true` and the `unattended-session` instruction block +(`GSTACK_INSTRUCTION_BEGIN: unattended-session ` through +`GSTACK_INSTRUCTION_END`; skill prose cites it by that id), then applies these +rules for the whole skill: - **No prompts.** The update check, upgrade offer, telemetry and sync consent, onboarding tips and routing blocks are suppressed exactly as they are for diff --git a/test/plan-reality.test.ts b/test/plan-reality.test.ts index 175ff2706..29a1f5e33 100644 --- a/test/plan-reality.test.ts +++ b/test/plan-reality.test.ts @@ -216,6 +216,13 @@ describe('rendered templates carry the contract', () => { expect(eng).toContain('REALITY: pass|finding|n/a '); expect(generatePlanRealityRows(ctx('plan-ceo-review'))).toContain('--phase ceo'); expect(generatePlanRealityRows(ctx('plan-devex-review'))).toContain('--phase dx'); + // Generated by /ship Step 7 coverage audit (GSTA-91, PR #3421). + // Value: protects=the operative block says its check prints the PLAN_REALITY line the summary row asks for; + // fails_when=that pointer is dropped and PLAN_REALITY is undefined in the block; why_new=only the summary variant + // was asserted to name PLAN_REALITY; seam=none; no_claim=the bin's output (pinned by the check tests above) + for (const skill of ['plan-eng-review', 'plan-ceo-review', 'plan-devex-review']) { + expect(generatePlanRealityRows(ctx(skill)), skill).toMatch(/gstack-plan-reality check --phase [a-z]+ [^\n]*`PLAN_REALITY`/); + } const deep = generatePlanRealityRows(ctx('plan-eng-review'), ['deep']); for (const r of REALITY_ROWS) expect(deep).toContain(`| \`${r.id}\` | ${r.tier} | ${r.scope} |`); expect(deep).toBe(deep.replace(/\n{3,}/g, '\n\n'));