mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-17 09:41:28 +08:00
v1.39.1.0 feat: EXIT PLAN MODE GATE for plan-mode review skills (#1512)
* feat: EXIT PLAN MODE GATE for plan-mode review skills Add a terminal BLOCKING checklist that verifies the plan file ends with `## GSTACK REVIEW REPORT` before ExitPlanMode is called. Lives at EOF of all four plan-* review skills (eng/ceo/design/devex) and inside codex Step 2A. Tones down the preamble's "Plan Status Footer" to a neutral forward reference so review-report rules don't bleed into operational skills (/ship /qa /review). Single source of truth: `generateExitPlanModeGate` in scripts/resolvers/review.ts, registered as EXIT_PLAN_MODE_GATE in scripts/resolvers/index.ts. New test in test/gen-skill-docs.test.ts strips fenced code blocks before matching `## ` headings and asserts the gate is the terminal heading in all four plan-* review SKILL.md files. Codex's SKILL.md uses toContain (mid-file by design — Step 2B/2C are not plan-touching modes). Decisions locked via /plan-eng-review + /codex outside-voice: - D1=A: 4 plan-* reviews + codex (autoplan, office-hours deferred) - D2=B → D4=A: tone preamble down to neutral forward reference - D3=A: add automated test in test/gen-skill-docs.test.ts - D5=B: keep codex gate inside Step 2A (mid-file acceptable per gate self-gating) Codex pre-merge findings folded in: line numbers obsolete (use EOF), test regex must strip fences, fresh skill list (not stale REVIEW_SKILLS constant), gate check 4 short-circuits when no plan file in context. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore: bump version and changelog (v1.39.1.0) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: package.json build script uses subshells, not brace groups The three `{ git rev-parse HEAD 2>/dev/null || true; } > path/.version` brace groups in the build script regressed when v1.38.0.0 merged into this branch (resolved with --ours during conflict). Bun on Windows can't parse brace groups in this position; the v1.38.0.0 invariant requires `(...)` subshells. Windows CI test `package.json build scripts — POSIX shell compat` caught it. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ import { generateTestFailureTriage } from './preamble';
|
||||
import { generateCommandReference, generateSnapshotFlags, generateBrowseSetup } from './browse';
|
||||
import { generateDesignMethodology, generateDesignHardRules, generateDesignOutsideVoices, generateDesignReviewLite, generateDesignSketch, generateDesignSetup, generateDesignMockup, generateDesignShotgunLoop, generateTasteProfile, generateUXPrinciples } from './design';
|
||||
import { generateTestBootstrap, generateTestCoverageAuditPlan, generateTestCoverageAuditShip, generateTestCoverageAuditReview } from './testing';
|
||||
import { generateReviewDashboard, generatePlanFileReviewReport, generateAntiShortcutClause, generateSpecReviewLoop, generateBenefitsFrom, generateCodexSecondOpinion, generateAdversarialStep, generateCodexPlanReview, generatePlanCompletionAuditShip, generatePlanCompletionAuditReview, generatePlanVerificationExec, generateScopeDrift, generateCrossReviewDedup } from './review';
|
||||
import { generateReviewDashboard, generatePlanFileReviewReport, generateExitPlanModeGate, generateAntiShortcutClause, generateSpecReviewLoop, generateBenefitsFrom, generateCodexSecondOpinion, generateAdversarialStep, generateCodexPlanReview, generatePlanCompletionAuditShip, generatePlanCompletionAuditReview, generatePlanVerificationExec, generateScopeDrift, generateCrossReviewDedup } from './review';
|
||||
import { generateSlugEval, generateSlugSetup, generateBaseBranchDetect, generateDeployBootstrap, generateQAMethodology, generateCoAuthorTrailer, generateChangelogWorkflow } from './utility';
|
||||
import { generateLearningsSearch, generateLearningsLog } from './learnings';
|
||||
import { generateConfidenceCalibration } from './confidence';
|
||||
@@ -40,6 +40,7 @@ export const RESOLVERS: Record<string, ResolverFn> = {
|
||||
DESIGN_REVIEW_LITE: generateDesignReviewLite,
|
||||
REVIEW_DASHBOARD: generateReviewDashboard,
|
||||
PLAN_FILE_REVIEW_REPORT: generatePlanFileReviewReport,
|
||||
EXIT_PLAN_MODE_GATE: generateExitPlanModeGate,
|
||||
ANTI_SHORTCUT_CLAUSE: generateAntiShortcutClause,
|
||||
TEST_BOOTSTRAP: generateTestBootstrap,
|
||||
TEST_COVERAGE_AUDIT_PLAN: generateTestCoverageAuditPlan,
|
||||
|
||||
@@ -81,7 +81,5 @@ Replace \`SKILL_NAME\`, \`OUTCOME\`, and \`USED_BROWSE\` before running.
|
||||
|
||||
## Plan Status Footer
|
||||
|
||||
In plan mode before ExitPlanMode: if the plan file lacks \`## GSTACK REVIEW REPORT\`, run \`~/.claude/skills/gstack/bin/gstack-review-read\` and append the standard runs/status/findings table. With \`NO_REVIEWS\` or empty, append a 5-row placeholder with verdict "NO REVIEWS YET — run \`/autoplan\`". If a richer report exists, skip.
|
||||
|
||||
PLAN MODE EXCEPTION — always allowed (it's the plan file).`;
|
||||
Skills that run plan reviews (\`/plan-*-review\`, \`/codex review\`) include the EXIT PLAN MODE GATE blocking checklist at the end of the skill, which verifies the plan file ends with \`## GSTACK REVIEW REPORT\` before ExitPlanMode is called. Skills that don't run plan reviews (operational skills like \`/ship\`, \`/qa\`, \`/review\`) typically don't operate in plan mode and have no review report to verify; this footer is a no-op for them. Writing the plan file is the one edit allowed in plan mode.`;
|
||||
}
|
||||
|
||||
@@ -158,6 +158,33 @@ there — the user then sees a plan whose review report is not at the bottom and
|
||||
(correctly) rejects it.`;
|
||||
}
|
||||
|
||||
export function generateExitPlanModeGate(_ctx: TemplateContext): string {
|
||||
return `## EXIT PLAN MODE GATE (BLOCKING)
|
||||
|
||||
Before calling ExitPlanMode, run this self-check. If any item fails, do the
|
||||
missing work — do NOT call ExitPlanMode:
|
||||
|
||||
1. Read the plan file with the Read tool (after your most recent write to it).
|
||||
2. Confirm the LAST \`## \` heading in the file is \`## GSTACK REVIEW REPORT\`.
|
||||
In-body prose that mentions "outside voice", "codex findings", or similar
|
||||
does NOT count — only the structured \`## GSTACK REVIEW REPORT\` section
|
||||
satisfies this check.
|
||||
3. Confirm the report contains: a Runs / Status / Findings table, a VERDICT
|
||||
line, and absorbs CODEX / CROSS-MODEL / UNRESOLVED lines if applicable.
|
||||
4. If a plan file is in context for this skill invocation: confirm
|
||||
\`gstack-review-log\` was called and \`gstack-review-read\` was run at least
|
||||
once. If no plan file is in context (e.g. \`/codex consult\` against a
|
||||
diff with no plan), this check short-circuits — checks 1-3 already
|
||||
short-circuit when no plan file exists.
|
||||
|
||||
Failing this gate and calling ExitPlanMode anyway is a contract violation —
|
||||
the user will see a plan whose review report is missing or stale, and will
|
||||
(correctly) reject it. Self-deception failure mode to watch for: feeling
|
||||
"done" after writing review prose into the plan body. The body prose is not
|
||||
the report. The report is a separate, structured, table-bearing section that
|
||||
must be the file's terminal heading.`;
|
||||
}
|
||||
|
||||
export function generateAntiShortcutClause(_ctx: TemplateContext): string {
|
||||
return `**Anti-shortcut clause:** The plan file is the OUTPUT of the interactive review, not a substitute for it. Writing every finding into one plan write and calling ExitPlanMode without firing AskUserQuestion is the precise failure mode of the May 2026 transcript bug — the model explored, found issues, and dumped them into a deliverable rather than walking the user through them. If you have ANY non-trivial finding in any review section, the path from finding to ExitPlanMode goes THROUGH AskUserQuestion. Zero findings in every section is the only path to ExitPlanMode that bypasses AskUserQuestion. If you find yourself wanting to write a plan with findings before asking, stop and call AskUserQuestion now — that's the bug, recognize it.`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user