3bb2f8f1c5b22d85fe481ec6bb834b3a28733a05
247 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a594f5175c |
fix(#214): apply OpenCode write-truncation contract to all large-file writer agents (#599)
* fix(#214): apply OpenCode write-truncation contract to all large-file writer agents Issue #214 / PR #598 fixed gsd-phase-researcher's OpenCode write-tool truncation by adding a single-Write-default + sentinel-based Write->Read->Edit incremental fallback contract to its Step 6. The root cause is upstream opencode#18108: OUTPUT_TOKEN_MAX=32000 is shared with the thinking budget, so a single oversized `write` tool call's JSON is truncated mid-payload (`JSON Parse error: Expected '}'`) and OpenCode doom-loops. The same failure affects every GSD subagent that writes a large file in one Write call. Mirror the phase-researcher write contract (adapted per output filename) into the other large-file writers: - gsd-research-synthesizer (SUMMARY.md) — extends the existing bug-222 hard-rules block with the truncation fallback as rule 6, preserving every original rule - gsd-planner (PLAN.md) - gsd-executor (SUMMARY.md) - gsd-domain-researcher (AI-SPEC.md Section 1b) - gsd-project-researcher (.planning/research/*.md) - gsd-ui-researcher (UI-SPEC.md) Each keeps the single-Write default (no behavior change for Claude Code and other non-truncating runtimes) and falls back to incremental, sentinel-based section-by-section writes only on a truncation/invalid-tool failure; never silently falls back to returning content. Locked with a parametrized prompt-contract regression test mirroring the bug-214 / bug-222 pattern across all six agents. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#214): set changeset pr to 599 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
82fb847754 |
fix(#214): make gsd-phase-researcher survive OpenCode write-tool truncation (#598)
* chore: wire docs/agents config into AGENTS.md Agent skills section
Add the `## Agent skills` discovery block pointing the engineering
skills at the existing docs/agents/{issue-tracker,triage-labels,domain}.md
files (issue tracker, triage label mapping, single-context domain docs).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#214): make gsd-phase-researcher survive OpenCode write-tool truncation
OpenCode caps model output at OUTPUT_TOKEN_MAX=32000 and the thinking
budget shares that pool (upstream opencode#18108). A single oversized
`write` tool call for RESEARCH.md is truncated mid-payload, yielding
`JSON Parse error: Expected '}'`, which OpenCode misclassifies and then
doom-loops retrying identically. Short content writes fine; long
content fails 100% (reproducible, OpenCode 1.15.10).
Add a Step 6 write contract to agents/gsd-phase-researcher.md: keep the
single-Write default (no behavior change for Claude Code and other
runtimes that don't truncate), but on a truncation/invalid-tool failure
build the file incrementally via a sentinel-based Write -> Read -> Edit
sequence so no single tool-call payload is large enough to truncate;
never silently fall back to returning content (which truncates
identically). This is the upstream-recommended mitigation (write in
smaller chunks; use edit for follow-on writes).
Locked with a prompt-contract regression test mirroring the bug-222
write-contract pattern.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#214): add changeset for OpenCode write-truncation fix
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
9ffe45a7c3 |
feat(#163): tighten gsd-roadmapper granularity defaults to reduce thin-phase fragmentation (#591)
* feat(#163): tighten gsd-roadmapper granularity defaults to reduce thin-phase fragmentation Tighten the Granularity Calibration buckets in gsd-roadmapper (Coarse 3-5->2-4, Standard 5-8->4-6, Fine 8-12->6-10) and append inline Key guidance naming the thin-phase failure pattern (single requirement / internal-quality goal / task-shaped success criteria) with instruction to fold into a neighbor rather than create a standalone phase. Implements the maintainer-approved proposal verbatim. Update the canonical English docs that hardcoded the old phase-count numbers: docs/CONFIGURATION.md and docs/FEATURES.md. Translated docs are community-maintained and are not updated per-PR (CONTRIBUTING.md language policy). Prompt/doc text only; no code, format, or downstream-consumer changes. Agent size-budget and skills-awareness tests pass; full suite green. Closes #163 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#163): add Changed changeset for roadmapper granularity tightening Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(#163): lock tightened gsd-roadmapper granularity buckets source-text-is-the-product test asserting the Granularity Calibration table holds the tightened ranges (Coarse 2-4, Standard 4-6, Fine 6-10), that no row maps to an old bucket, and that the Key paragraph carries the thin-phase folding guidance. Would fail if the values regress. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
692343f8cc |
fix(#581): add Edit to six writer agents' tools so Edit-only discipline is enforceable (#582)
* fix(#581): add Edit to six writer agents' tools so Edit-only discipline is enforceable Six writer agents (gsd-eval-planner, gsd-ai-researcher, gsd-domain-researcher, gsd-phase-researcher, gsd-ui-researcher, gsd-debug-session-manager) shipped with Write but no Edit in their tools: frontmatter. Their spawn prompts instruct surgical in-place section edits on existing/shared files (notably the AI-SPEC.md trio writing disjoint sections of the same file), but with no Edit tool they fall back to whole-file Write — silently clobbering sibling sections (last-writer-wins) while still reporting success. Same bug class as #571, fixed for gsd-doc-writer in #575. This adds Edit alongside the existing Write for all six (Edit placed adjacent to Write, mirroring the gsd-doc-writer fix). Write is retained; no prompt-body changes; no other agents touched. Adds a regression test (tests/agent-frontmatter.test.cjs) asserting each of the six section-writer agents carries both Write and Edit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(#581): add changeset fragment for writer-agent Edit fix Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(#581): regenerate changeset via npm run changeset Replace hand-authored fragment with one generated by the official scripts/changeset/new.cjs script (correct <adjective>-<noun>-<noun> filename convention). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
c2ebb1ba16 |
fix(#571): forbid Write in doc-writer fix mode; add workflow truncation guard
* fix(#571): forbid Write in doc-writer fix mode; add workflow truncation guard gsd-doc-writer in fix mode only had Write in its tools list, so when correcting a specific failing claim it would re-emit the whole file with only the lines it had in context — truncating untracked docs with no git recovery path. Fix 1 (root cause): add Edit to the agent tools frontmatter and rewrite fix_mode instructions to mandate Edit for surgical corrections and explicitly forbid Write on existing files. Also reinforced in critical_rules. Fix 2 (safety net): add a post-fix line-count guard in the fix_loop step of docs-update.md. If the file shrank by >90% after a fix agent runs, the orchestrator restores the file from the existing_content it captured before dispatch and logs a WARNING. This makes the previously unrecoverable case recoverable. Regression test: tests/bug-571-doc-writer-fix-mode-edit-only.test.cjs covers both the agent contract and the workflow guard. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: add changeset for fix #571 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#571): address codex adversarial review findings - Quote {doc_path} in shell snippets to handle paths with spaces (#SECURITY) - Clarify corrupted doc re-verification vs re-fix distinction (#CORRECTNESS) - Strengthen regression tests with structural ordering assertions (#REGRESSION) - Move docs-update.md from global ALLOWLIST to SIZE_ONLY_WORKFLOWS so injection scanning still runs while only the 50K size finding is exempt (#SECURITY) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
c976a9c858 |
fix(#38): replace misleading approved checkpoint in execute-phase human_needed branch (#560)
Fixes #38 Removes the `"approved" → continue` ack-and-advance shortcut from the `human_needed` verification path in execute-phase. The phase now stays pending until `/gsd:verify-work` completes the UAT and triggers its auto-transition — enforcing the invariant that ROADMAP advances only after a completed verification record. Also fixes: UAT file format mismatch (`status: testing` + correct `## Current Test` key shape), filename alignment (`{phase_num}-UAT.md`), explicit ack handler covering legacy `approved` keyword, stale `HUMAN-UAT.md` references in agent/reference files. |
||
|
|
79002a00cb |
chore(#518): rename npm package + bin to @opengsd/gsd-core (#519)
* chore: rename npm package + bin to @opengsd/gsd-core (functional) - package.json: name @opengsd/get-shit-done-redux → @opengsd/gsd-core, bin key get-shit-done-redux → gsd-core, repository/homepage/bugs URLs - package-lock.json: regenerated (npm install --package-lock-only) - tests/**, scripts/**, bin/**, .github/**, agents/**, commands/**, get-shit-done/bin/**, get-shit-done/workflows/**: applied the 4-rule replacement (scoped npm ref, GitHub repo path, bin/clone invocations) per #505 single-source refactor Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs: sweep live references to @opengsd/gsd-core Update all live documentation (README.md + translations, docs/**, CONTRIBUTING.md, VERSIONING.md, SECURITY.md, CONTEXT.md, docs/CANARY.md) to reflect the renamed package and repository. Rules applied: - @opengsd/get-shit-done-redux → @opengsd/gsd-core (scoped npm name) - open-gsd/get-shit-done-redux → open-gsd/gsd-core (GitHub repo) - GSD-redux/get-shit-done-redux → open-gsd/gsd-core (stale badge org) - bare bin/clone refs → gsd-core CHANGELOG.md, docs/adr/**, docs/RELEASE-*.md, docs/research/**, and .changeset/** are preserved byte-identical. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: add negative lookbehind to slash-command regex in bug-2954 test The extractSlashReferences regex matched /gsd-core inside npm package URLs (@opengsd/gsd-core), producing a false /gsd:core command reference. Adding a negative lookbehind (?<![a-z]) excludes matches preceded by a letter, so only standalone /gsd-<cmd> and /gsd:<cmd> tokens are found. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#518): add changeset for package rename Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(#518): update package-identity expectations to the renamed coordinates The rebase regenerated the seam to @opengsd/gsd-core (bin gsd-core, repo open-gsd/gsd-core). The #498 seam tests assert deriveIdentity against the REAL package.json, so their expected literals must follow the rename. The drift-lint unit test is left as-is — its SEAM is a self-consistent fixture and its stale-literal detection cases would shift if altered; the live-repo scan in it already passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
7a3822fce1 |
fix: replace removed gsd-sdk prompt references (#355)
* fix: replace removed gsd-sdk prompt references * chore: add changeset |
||
|
|
81a4d1c091 | fix(#16): renumber canonical phases above 999 on remove (#241) | ||
|
|
a512bd79d7 | fix(#222): enforce research synthesizer write-only summary contract (#240) | ||
|
|
41210f014e |
fix(5): decision-coverage gate parses <action> XML tag bodies for D-NN citations (#155)
* test(5): add failing test for decision IDs inside <objective>/<tasks>/<task>/<action> XML bodies Regression test for issue #5 — the translation gate (check.decision-coverage-plan) is blind to D-NN citations placed inside XML tag bodies by gsd-planner. Maintainer acceptance criteria (verbatim, issue #5): "Gate parses <action> tag bodies for decision ID citations; regression test with XML-tag plan body covers all decision IDs." Five new test cases added to the 'XML tag body citation parsing (issue #5)' suite: 1. RED: five decisions cited only in <objective>/<action> bodies → gate fails (before fix) 2. Non-canonical tag <comment> → must NOT count (negative control, passes) 3. Plain prose under undesignated heading → must NOT count (negative control, passes) 4. Self-closing <action/> → no crash, D-NN not covered (passes) 5. D-NN in <objective> body → should count (also fails before fix, GREEN after) Tests 1 and 5 are the load-bearing RED cases. All others are negative controls. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(5): extend extractPlanSections to scan <objective>/<tasks>/<task>/<action> for D-NN citations Closes #5. Root cause: extractPlanSections() in check-decision-coverage.ts collected only front-matter (must_haves/truths/objective) and body lines under designated markdown headings. The gsd-planner spec (agents/gsd-planner.md line 66) says 'Task actions reference the decision ID they implement (e.g., "per D-03")' and emits citations inside <action> tag bodies — a location the gate could not see. Fix: add extractXmlTagBodies() helper that matches the four canonical planner XML tags (<objective>, <tasks>, <task>, <action>) via a deliberately narrow regex (no XML parser library — D2 design decision). The helper output is appended to the designated string inside extractPlanSections(), making any D-NN citation inside those tag bodies count toward coverage. Maintainer acceptance criteria (verbatim, issue #5): "Gate parses <action> tag bodies for decision ID citations; regression test with XML-tag plan body covers all decision IDs." Self-closing tags (<action/>) are safely ignored — the capturing group does not match. Non-canonical tags (<comment>, <note>, etc.) are not in the alternation and are ignored by design. The CJS surface for check-decision-coverage.ts does NOT have a generator (gen-decisions.mjs covers decisions.ts, not this gate). No CJS artifact exists for this module. Per the generator framework established in PR #154 (ADR-3524), a CJS migration is a follow-up; this PR focuses on the TS fix. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(5): clarify in gsd-planner.md that decision-coverage gate reads XML tag bodies Adds a parenthetical note to the existing self-check bullet (line 66) explaining which locations the gate scans so the planner's own guidance and the gate's behavior are explicitly aligned. Refs #5. No behavior change — documentation truthing only. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(5): add changeset fragment for decision-coverage XML body fix Refs #5. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(5): extract Interface Context for Executors into reference file to pass planner-decomposition gate gsd-planner.md was 49446 chars after the XML-tag clarification added in this PR, exceeding the 48K threshold enforced by tests/planner-decomposition.test.cjs. Extracted the "Interface Context for Executors" section (~2137 chars) into get-shit-done/references/planner-interface-context.md, leaving a one-line pointer in gsd-planner.md. New normalized size: 47310 chars (1842 chars under threshold). Refs #5 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(5): register planner-interface-context.md in INVENTORY.md and manifest - Bump References headline from 61 to 62 to match filesystem count - Add planner-interface-context.md row in Modular Planner Decomposition table - Update footnote from 61 to 62 top-level references - Regenerate docs/INVENTORY-MANIFEST.json via gen-inventory-manifest.cjs --write Fixes inventory-counts and inventory-manifest-sync CI failures caused by the extraction commit (32e8950f) adding a new reference file without updating the inventory artefacts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
dff176bfd2 |
chore: rebrand to GSD-redux/get-shit-done-redux
Mirror of code, issues, and PRs from the upstream gsd-build/get-shit-done, which appears compromised or abandoned (maintainer unreachable since 2026-04-01; $GSD token linked to rug-pull). - Adds rebrand notice block at top of English README - Removes $GSD token badge and @gsd_foundation X badge (keeps Discord) - Renames npm packages: get-shit-done-cc -> get-shit-done-redux, @gsd-build/sdk -> @gsd-redux/sdk - Updates all repo URLs across docs, workflows, package.json, bin/ - Updates ci@gsd-build -> ci@gsd-redux in workflow git identities - Leaves CHANGELOG and .changeset/* alone (historical, time-stamped) |
||
|
|
3d52f5ee46 |
refactor(tests): consolidate Init Command Module — 7 files → 5 (#3756)
* fix(3687): update insert-phase docs and roadmapper to use --insert flag Updates stale references in insert-phase.md workflow and gsd-roadmapper.md agent to use the consolidated /gsd:phase --insert command syntax instead of the retired /gsd-insert-phase and /gsd:phase insert forms. Closes #3687 * refactor(tests): consolidate Init Command Module — 7 files → 5 Closes #3755 Merges `tests/init-manager-deps.test.cjs` (#2267 regression) into `tests/init-manager.test.cjs` (718 LOC), and `sdk/src/query/init-progress-precedence.test.ts` (#2674 regression) into `sdk/src/query/init-complex.test.ts` (788 LOC). The 800 LOC ceiling prevents further consolidation: - `tests/init.test.cjs` is pre-existing at 1630 LOC - `sdk/src/query/init.test.ts` is at 791 LOC - `sdk/src/query/init-workstream-milestone-op.test.ts` is a distinct seam testing initMilestoneOp, roadmapAnalyze, and resolveQueryRuntimeContext workstream resolution. Also adds Init Command Module Glossary entry to CONTEXT.md. Allowlist update deferred to rebase after #3738 merges (allowlist file does not exist on origin/main). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(init): initExecutePhase preserves same-milestone archived phase dir (#3469) When `phases clear` archives current-milestone phases into `.planning/milestones/<version>-phases/` but the workflow is still on that same milestone, `shouldDropArchivedPhaseMatch` was unconditionally dropping the archived dir match. This caused `phase_dir: null` when the phase was still executing in the current milestone. Fix: detect when `phaseInfo.archived === currentMilestone` (read from STATE.md) and skip the drop. The #2391 regression guard is safe because that scenario involves archived.version != current milestone. Also corrects two tests in `initRemoveWorkspace` to expect thrown GSDError instead of `{ data: { error } }` — the production code was intentionally changed to throw for CLI non-zero exit propagation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: arya rizky <aryarizkyardhipratama@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
7e6ba56985 |
fix(3678): executor must respect commit_docs:false; teach SDK skip envelope (#3679)
* fix(3678): executor must respect commit_docs:false; teach SDK skip envelope Closes #3678 When `commit_docs: false` in `.planning/config.json`, the SDK's `cmdCommit` correctly short-circuits and returns `{committed: false, hash: null, reason: 'skipped_commit_docs_false'}` without staging or committing anything. The agent prompt at `agents/gsd-executor.md:710-720` (final_commit block) tells the executor to call `gsd-sdk query commit "docs(...)" --files .planning/...` but says NOTHING about how to interpret a skipped return. With no explicit instruction, the LLM improvises raw `git add` / `git add -f` / `git commit` to "fulfill" the per-plan commit step it was told to make, which leaks gitignored `.planning/` artifacts into the user's git history (exactly what the reporter observed). Three coordinated fixes: 1. **agents/gsd-executor.md final_commit block** — adds explicit handling text for all three SDK return envelopes (`committed:true`, `skipped:true commit_docs`, `skipped:true gitignored`, `committed:false other reasons`). States plainly: "Do not fall back to raw `git add` / `git commit` / `git add -f` when the SDK returns `skipped: true`." 2. **get-shit-done/bin/lib/commands.cjs cmdCommit** — adds `skipped: true` to both skip-path envelopes so agents see "skipped" as a first-class success signal rather than inferring "no commit happened, I must improvise" from absent `hash` / `committed:false`. Backward-compatible: existing callers reading `committed` / `hash` / `reason` are unaffected. 3. **tests/bug-3678-executor-commit-docs-respect.test.cjs** — 7-test regression covering: - A1/A2: agent prompt mentions the skip envelope AND explicitly forbids raw-git fallback (`source-text-is-the-product` exception) - B1: SDK envelope carries `committed:false`, `skipped:true`, canonical `reason: 'skipped_commit_docs_false'` (frozen enum) - B2: git index empty after commit_docs:false skip (no `.planning/` staged) - B3: HEAD unchanged after commit_docs:false skip - C1/C2: structural ban on `git add -f` / `git add --force` in any agent or workflow body (prohibition-sentence exception preserves audit prose) Verification: - node --test tests/bug-3678-*: 7/7 pass - Targeted regression (10 commit/executor-adjacent files): 135/135 pass - Full docker suite (gsd-test-summary): 11751/11740 pass / 0 fail (the 11 added are this test plus a few collateral pickups) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(changeset): add fragment for #3678 fix (Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>) * chore(changeset): set PR number 3679 (Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>) * fix(3678): preserve skip-aware carve-out in executor completion checklist The new `final_commit` prose at lines 717-741 teaches the executor to treat `skipped:true` as success and forbids raw-git fallback, but the downstream completion checklist still contained an unconditional "Final metadata commit made" checkbox. An LLM executor reading an unchecked mandatory box may attempt to satisfy it via raw `git add`, re-introducing the exact regression this PR is meant to prevent. Update the checklist line to carve out the intentional-skip case and add a regression test asserting the carve-out remains present. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
ae63cbe557 |
feat(3575): Phase 6 — CJS↔SDK seam migration end-to-end complete (#3524) (#3577)
* feat(3575): Phase 6 enforcement hardening + retrospective (#3524 feature-complete) Phase 6 of the CJS↔SDK hard-seam migration (parent #3524). Final phase per the PRD. After this lands the migration is feature-complete: shared Modules from Phases 1-4 are in place, the runtime-bridge primitive from Phase 5.0 is wired with the state.* family proof in Phase 5.1 (PR #3574), and Phase 6 hardens the seam against future drift via lint, CODEOWNERS, and retrospective documentation. ## What landed - scripts/lint-shared-module-handsync.cjs (274 lines) — the drift-prevention gate. Scans bin/lib/*.cjs and looks for same-named sdk/src/<name>.ts or sdk/src/query/<name>.ts (excluding generated artifacts). Pairs not on the allowlist fail the lint with a clear message: either add to allowlist with justification, or migrate to a shared Module. Supports --root, --allowlist, --cjs-dir, --sdk-src, --warn-all flags for testability. - scripts/shared-module-handsync-allowlist.json (148 lines) — two categories: - cooperatingSiblings (14 pairs) — legitimate Readers/Adapters that consume shared Modules or run structurally-different runtime paths. - migrateMeBacklog (8 pairs) — known drift anti-patterns that ARE on main today (config, decisions, intel, model-catalog, plan-scan, schema-detect, secrets, workstream-name-policy). Lint warns but does not fail on these; documented in the retrospective as candidate Shared Module migrations. - tests/lint-shared-module-handsync.test.cjs (285 lines, 11 cases) — proves the lint catches new drift, honors the allowlist, and exits 0 on the current tree. - .github/workflows/test.yml — new "Shared Module hand-sync drift check" step after the freshness checks. - .github/CODEOWNERS — appended 11 architecture-owned path rules for source-of-truth files (Shared Module dirs, manifest JSONs, runtime bridge, lint script, allowlist). Existing blanket rule preserved. - docs/agents/cjs-sdk-seam.md (280 lines) — full retrospective + guide: - Migration overview table linking Phases 1-6 with PR numbers. - 15 historical drift bugs (#1535 ... #3523) each mapped to the Phase 6 enforcement layer that would have blocked them. - "Guide: Adding a new Shared Module" — step-by-step using Phase 1 (state-document) as the worked example. - "Guide: Adding a new canonical command" — step-by-step using Phase 5.1 (state.update) as the worked example. - "Open follow-ups" listing the 8 MIGRATE_ME pairs, per-family Phase 5.2+ candidates pending maintainer authorization, sync bridge workstream support, and Phase 5.1's parity divergences. - CONTRIBUTING.md — short cross-reference paragraph in the Architecture & Domain Standards section. ## Audit findings All 5 freshness checks from Phases 0-4 are already wired in CI: command-aliases, state-document, configuration, workstream-inventory-builder, project-root. Phase 6 adds the 6th (hand-sync drift check) for total enforcement coverage. ## Numbers - Full CJS suite: 9335/9335 pass (baseline 9323 + 11 new lint tests + 1 cooperating). - Lint passes on current tree: 14 cooperating siblings + 8 backlog pairs accounted for, 0 unauthorized drift pairs. - Lint exits 1 (fails CI) on an intentional new hand-synced pair added to a fixture — verified by the test suite. Closes #3575. Closes the structural drift surface of #3524. * chore(3577): add changeset fragment for Phase 6 * feat(3575): Phase 6 end-to-end completion — CJS↔SDK seam migration done Per maintainer correction: Phase 6 is THE final phase and must complete the migration end-to-end. This commit absorbs Phase 5.1's work (state.* router + worker fix), finishes the remaining per-family router migrations, completes all five resolvable Shared Module extractions, resolves the parity divergences, lands native workstream support in the sync bridge, and ships the lint + CODEOWNERS + retrospective from the original Phase 6 scope. After this commit the CJS↔SDK seam migration started in #3524 is feature-complete. No follow-up "Phase 5.x" or "Phase 7" should be needed — the only documented carve-outs are three pairs that intentionally cannot be migrated (config CLI handlers, intel async wrapper, model-catalog already on the shared-JSON pattern). Cherry-picked state.* from Phase 5.1 (PR #3574 absorbed). Migrated verify.*, init.*, phase.*, phases.*, validate.*, roadmap.* via the same executeForCjs delegation pattern. Migrated the inline gsd-tools.cjs cases for frontmatter.*, config-* CLI, and non-family commands (generate-slug, current-timestamp, find-phase, docs-init) with shared _dispatchNonFamily helper + _tryLoadSdkBridge loader. CJS-native carve-outs documented: config-path, migrate-config, detect-custom-files (no SDK counterpart yet); state.complete-phase (no SDK counterpart yet); validate.context (CJS-only inline logic with no clean SDK port); phases.archive (SDK-only). - plan-scan (Module-via-generator from sdk/src/query/plan-scan.ts) - secrets (Module-via-generator) - schema-detect (Module-via-generator) - decisions (Module-via-generator; SDK regex aligned to CJS alphanumeric IDs to preserve project compatibility) - workstream-name-policy (Module-via-generator; SDK extended with hasInvalidPathSegment and isValidActiveWorkstreamName that CJS callers depend on) Each ships with: SDK source-of-truth, generator at sdk/scripts/gen-<name>.mjs, freshness check at sdk/scripts/check-<name>-fresh.mjs, parity test at tests/<name>-generator.test.cjs, CJS shim at get-shit-done/bin/lib/<name>.cjs, scripts in sdk and root package.json, pre-commit drift block, CI workflow step, CODEOWNERS rule, INVENTORY.md row. - config (config.cjs vs sdk/src/config.ts) — CJS file is CLI-handler surface (cmdConfigGet/Set/etc.); SDK file is loadConfig wrapper (already migrated in Phase 2). Zero logical overlap. Classified as CJS-CLI-ONLY in the allowlist. - intel (intel.cjs vs sdk/src/query/intel.ts) — SDK is the async QueryHandler wrapper of the CJS module; intentional split per the SDK file's own docstring. Classified as cooperating-sibling. - model-catalog (model-catalog.cjs vs sdk/src/model-catalog.ts) — both already consume sdk/shared/model-catalog.json (ADR-0003). No constants duplicated. Classified as ADAPTER-OVER-MODULE. - state.record-metric: SDK aligned to CJS auto-create of ## Performance Metrics section when absent. Parity assertion now exact equality. - state.prune: SDK aligned to CJS disk-based phase counting via stateExtractField. Parity assertion now exact equality. SDK unit tests updated to match. GSDTransport.shouldUseNative no longer forces subprocess when request.workstream is set — the Phase 5.0 worker fix already threaded workstream through dispatchNative + registry.dispatch, making the subprocess force unnecessary. state-command-router.cjs's workstream fallback guard removed. cjs-sdk-seam.md and the regression test updated to document the resolution. Unchanged from the previous commit on this branch. The lint now reports 22 cooperating siblings, 0 backlog pairs. The retrospective section "Open follow-ups" is reduced to the three intentional carve-outs above; the four stale subsections (8 MIGRATE_ME pairs, per-family Phase 5.x candidates, workstream support, parity divergences) are gone because they're all resolved in this commit. - Full CJS suite: 9441/9441 pass (baseline pre-Phase-6 was 9323; +118 from the Phase 6 work — 11 lint tests + 12 state-router parity + 6 verify parity + 3 phase parity + 1 roadmap parity + 24 plan-scan parity + 20 secrets parity + 18 schema-detect parity + 15 decisions parity + 19 workstream-name-policy parity). - SDK vitest unit: 1863/1863 pass. - Hand-sync lint: 22 cooperating siblings, 0 backlog pairs. - All freshness checks: fresh. Closes #3575. Closes the migration the CJS↔SDK seam was designed to eliminate (#3524). * fix(3575): lint-shared-module-handsync emits typed JSON; tests assert on IR The lint-no-source-grep CI step rejected the original Phase 6 test file (tests/lint-shared-module-handsync.test.cjs) because it substring-matched on .stdout/.stderr from the lint script output — prohibited per CONTRIBUTING.md "Raw Text Matching on Test Outputs". Fix: add --json mode to the production lint script and assert on typed IR fields. ## Changes scripts/lint-shared-module-handsync.cjs: - New --json flag. When set: - Success: emits { ok: true, cooperatingCount, backlogCount, warnings } - Unauthorized pairs: emits { ok: false, reason: 'unauthorized_pairs', errors: [{ relCjs, tsPaths }], warnings, cooperatingCount } - Missing CJS/SDK dir: emits { ok: false, reason: 'cjs_dir_missing' | 'sdk_src_missing', path } - Default (human-readable) output unchanged. - Warnings section is suppressed in --json mode (still surfaced in the IR's `warnings` field for tests to inspect). tests/lint-shared-module-handsync.test.cjs: - runLintJson() helper replaces runLint(), invoking the script with --json and parsing the IR. - Every assertion now reads typed fields (payload.ok, payload.reason, payload.errors, payload.warnings, payload.cooperatingCount) instead of substring-matching stdout/stderr. - Test count unchanged at 9 cases across 3 describe blocks. - All pass. ## Verification - node scripts/lint-no-source-grep.cjs → exit 0, 529 test files checked, 0 violations (was: 1 violation in this test file). - node --test tests/lint-shared-module-handsync.test.cjs → 9/9 pass. - node scripts/lint-shared-module-handsync.cjs → unchanged human-readable output, 22 cooperating siblings, 0 backlog pairs. - node scripts/run-tests.cjs → 9449/9449 pass. Addresses CI failure on PR #3577 (Phase 6 of #3524). * fix(3575): address CodeRabbit review on PR #3577 Six findings resolved: 1. scripts/lint-shared-module-handsync.cjs — allowlist matching now pair-aware. Keys composite ${cjs}::${ts} instead of cjs-only, so an entry covering one (cjs, ts) pair no longer silently passes a sibling at a different ts path with the same module name. Header doc-comment also corrected: removed the stale claim about GSD_LINT_CHANGED_FILES filtering (no such code existed). 2. sdk/src/gsd-transport.ts — removed dead 'workstream_forced' member from the TransportDecision.reason union (no longer assigned after Phase 5.0 workstream-native refactor). 3. sdk/src/gsd-transport.ts — removed stale workstream interpolation from the subprocess-reason Error message; the field is no longer load-bearing for that decision path. 4. All eight generator scripts (sdk/scripts/gen-*.mjs and gen-state-document.ts) — replaced the manual entry-point check that used `new URL(process.argv[1], 'file://')`. On Windows that misparses `C:\…\gen-*.mjs` as scheme "c:" and breaks the check. Replaced with the cross-platform-safe direct comparison `fileURLToPath(import.meta.url) === process.argv[1]`. (Not using `import.meta.main` — that's only stable in Node 24+ and the project supports Node 22+.) 5. docs/agents/cjs-sdk-seam.md — added explicit `text` language specifier to the four file-path fenced blocks (lines 157, 165, 173, 181). Closing fences correctly remain bare. Verification - node scripts/lint-no-source-grep.cjs → 0 violations - node scripts/lint-shared-module-handsync.cjs → 22 cooperating siblings, 0 backlog (counts unchanged after pair-aware refactor) - node scripts/lint-shared-module-handsync.cjs --json → typed IR unchanged - All 9 generator freshness checks → fresh - node scripts/run-tests.cjs → 9449/9449 pass - sdk vitest src/gsd-transport.test.ts → 10/10 pass Tests for pair-aware matching: the existing 9 cases in tests/lint-shared-module-handsync.test.cjs already build fixture allowlist entries with both `cjs` and `ts` fields, so they implicitly exercise the new pair-aware lookup; all 9 pass. * fix(3575): address second CodeRabbit review on PR #3577 Five new findings resolved. 1. Shared SDK bridge loader (`get-shit-done/bin/lib/cjs-sdk-bridge.cjs`) Eliminates seven-fold duplication of `tryLoadSdk` / `_executeForCjs` that lived verbatim in every `*-command-router.cjs` plus a near-identical variant in `gsd-tools.cjs`. The new module exposes `tryLoadSdk()`, `getExecuteForCjs()`, and `getSdkModule()` (the last for routers that pull additional named exports, e.g. state's `formatStateLoadRawStdout`). All eight call sites refactored to consume it. As a side benefit `gsd-tools.cjs` no longer imports from the private `@gsd-build/sdk/dist/runtime-bridge-sync/index.js` subpath; everyone now uses the public package entry consistently. 2. `phase remove` accepts zero positional args (#3577 review) `phase remove --force` previously passed validation with no phase number and invoked `cmdPhaseRemove(cwd, undefined, ...)`. Tightened to `positional.length !== 1` and added the early `return` so the handler never receives an undefined phase id. 3. Decisions parser regex hardened (#3577 review) `D-[A-Za-z0-9_-]+` allowed malformed IDs like `D--foo` and `D-_bar`. Tightened to `D-[A-Za-z0-9][A-Za-z0-9_-]*` so the first character after `D-` must be alphanumeric; internal `_`/`-` still permitted. Decisions generated CJS mirror regenerated. 4. plan-scan-generator test no longer uses hardcoded `/tmp` paths `/tmp/__gsd_test_nonexistent_dir_xyz__` and `/tmp/__nonexistent_gsd_test__` could collide with prior runs on shared CI runners. Replaced with `uniqueMissingPath()` helper that synthesizes `os.tmpdir()/<prefix>-<pid>-<ms>-<random>` and force-removes the path before returning. 5. lint-shared-module-handsync test now validates pair-aware TS matching Added `rejects pair when TS path differs from allowlist entry` — a regression guard that creates an on-disk pair at `sdk/src/query/<name>.ts` but allowlists the (cjs, sdk/src/<name>.ts) shape. The lint must reject because the (cjs, ts) tuple does not match. Demonstrates the pair-aware matching added in the previous commit and locks it in. ## Wiring `cjs-sdk-bridge.cjs` added to `docs/INVENTORY.md` (count 68→69) and `docs/INVENTORY-MANIFEST.json` regenerated. ## Verification - node scripts/lint-no-source-grep.cjs → 0 violations (529 files) - node scripts/lint-shared-module-handsync.cjs → 22 cooperating, 0 backlog - node scripts/run-tests.cjs → 9452/9452 pass (was 9449 + 1 lint-test + 1 changed plan-scan path test) - node sdk/scripts/check-decisions-fresh.mjs → fresh - sdk vitest src/query/decisions.test.ts → 15/15 pass * docs(3575): correct PR/issue refs in cjs-sdk-seam.md CodeRabbit caught two stale references that conflated the issue number (#3575) with the PR number (#3577). Phase 6 ships as PR #3577 closing issue #3575. Migration overview table row and the Final Completion Summary updated accordingly. * fix(3575): cjs-sdk-bridge actually loads the SDK (was dead-code since Phase 5.0) ## The bug `cjs-sdk-bridge.cjs:tryLoadSdk()` resolved `require('@gsd-build/sdk')`, but that package name is not installed in the root `node_modules` (the SDK lives as `./sdk/` — a sibling workspace, not a dependency) and the SDK's public entry doesn't re-export `executeForCjs` or `formatStateLoadRawStdout` anyway. `tryLoadSdk()` always returned false, the `_loadFailed = true` cache made every subsequent call return false for the lifetime of the process, and every CJS router silently fell through to the CJS handler. The pattern shipped in Phase 5.0 (PR #3558, merged) via `require('@gsd-build/sdk/dist/runtime-bridge-sync/index.js')` and was inherited into the routers via `require('@gsd-build/sdk')` in Phase 5.1 (PR #3574, merged). Both subpaths/imports failed in the same way. CI passed for the whole CJS↔SDK migration because the CJS fallback handlers kept running — meaning the entire claimed "state.* delegation" never actually executed via the SDK in any shipped run. This is exactly the silent-drift class the Phase 6 lint and retrospective are supposed to prevent. Catching it here closes the loop. ## The fix Resolve the bundled SDK by **package-relative filesystem path**: <root>/sdk/dist/runtime-bridge-sync/index.js <root>/sdk/dist/query/state-project-load.js The `files` array in `package.json` keeps `sdk/dist` at the same relative location inside the published tarball, so the path works in both dev and post-install. The two-file split is necessary because `formatStateLoadRawStdout` lives in the state handler, not the runtime-bridge entry. ## Integration test `tests/cjs-sdk-bridge-integration.test.cjs` proves four things and locks the load-success invariant so this regression cannot recur: 1. tryLoadSdk() returns true on the current checkout 2. getExecuteForCjs() returns a function (not null) 3. getFormatStateLoadRawStdout() returns a function (not null) 4. executeForCjs() actually dispatches a canonical registry command (generate-slug) and returns an ok:true result — proving real SDK execution, not a silent CJS-fallback ## State-router formatter wiring The state command router was reaching into `getSdkModule()` to pluck `formatStateLoadRawStdout`. Replaced with the explicit `getFormatStateLoadRawStdout()` getter so the bridge module owns all SDK-export resolution. ## state.load --raw output mode While the bridge was broken, the state.load --raw test happened to pass via CJS fallback. The first SDK execution exposed a contract mismatch: passing `mode: 'raw'` to the bridge tells the SDK to pre-render result.data to a JSON string, but the router was also calling `formatStateLoadRawStdout(result.data)` to project to key=value lines — the formatter saw a string and no-op'd. Fix: when a CJS-side rawFormatter is supplied, the router requests `mode: 'json'` from the bridge (always get typed data) and runs the formatter itself. When no rawFormatter, the user's --raw flag flows through to the bridge as usual. ## Surfaced pre-existing parity gaps (NOT yet fixed) With the bridge now actually executing the SDK, 8 `tests/state.test.cjs` cases reveal pre-existing CJS↔SDK behavioral drift that Phase 5.1's "104/104 pass" report could not see because the SDK was never running: - `state load returns error when STATE.md missing` - `state get returns error when STATE.md missing` - `state update returns error when STATE.md missing` - `state update reports field not found` - `state patch / record-metric / update-progress / resolve-blocker / record-session — error when STATE.md missing` - `add-decision --summary-file` / `add-blocker --text-file` (file-input path rejected by SDK security check) Each is a real CJS↔SDK divergence that needs explicit alignment in the SDK handler. Listed here so the next commit can address them honestly rather than letting the broken bridge mask them again. * fix(3575): align SDK with CJS contract — bridge-exposed divergences The Phase 5.1 bridge fix (0fc60b0c) made executeForCjs() actually load and dispatch. With routers now hitting the SDK in normal layouts, six CJS↔SDK behavioral divergences became visible. This commit aligns the SDK to match the canonical CJS contract test-by-test. ROUTER CHANGES (mode: raw → mode: json) All 7 CJS routers were passing `mode: raw ? 'raw' : 'json'`. With the bridge active, `mode: 'raw'` makes the bridge pre-render result.data to a JSON string, which CJS output() then re-stringifies — producing a JSON string of a JSON string. Routers now always request typed JSON; CJS output() handles user- facing rendering. Affected: gsd-tools, init, phase, phases, roadmap, state, validate, verify routers. SDK STATE MUTATION HANDLERS (sdk/src/query/state-mutation.ts) state.update / record-metric / update-progress / resolve-blocker / record- session no longer auto-create STATE.md via readModifyWriteStateMd. CJS errors out when STATE.md is missing; SDK now does the same via an upfront existsSync check returning {updated: false, reason: 'STATE.md not found'}. Also fixes: • resolve-blocker semantic: SDK returned resolved:false when no blocker line matched. CJS returns resolved:true whenever the Blockers section exists. Aligned. • readTextArgOrFile path validation: rejected /var/folders paths on macOS because /var → /private/var is a symlink. Now resolves both base and target via realpathSync before the prefix check. STATE.MD STOPPED_AT SCOPING (sdk/src/query/state.ts) buildStateFrontmatter extracted `Stopped At` from the entire body; CJS scopes it to the ## Session section. Bug-2444 parity restored — the field no longer bleeds in from unrelated sections of STATE.md. PHASE_DIR_COUNT MILESTONE FILTER (sdk/src/query/init.ts) initNewMilestone counted every directory under phases/ regardless of which milestone it belonged to. CJS uses getMilestonePhaseFilter to count only current-milestone phase dirs. Bug-2445 parity restored. ARCHIVED PHASE GUARD (sdk/src/query/init.ts) shouldDropArchivedPhaseMatch had an extra `archivedTag === milestone.version` escape hatch that doesn't exist in CJS. CJS unconditionally drops the archived match when the phase appears in the current ROADMAP. Removed the escape hatch — fixes the bug #2391 regression where `init plan-phase 03` returned the archived v1.0 phase instead of the current ROADMAP phase. PADDING-TOLERANT ROADMAP PHASE LOOKUP (sdk/src/query/roadmap.ts) searchPhaseInContent used `escapeRegex(phaseNum)` as the phase-number fragment — `03` failed to match `Phase 3:` headings. CJS uses phaseMarkdownRegexSource which emits `0*<integer>` for padding tolerance. Restored same helper inline in roadmap.ts. Fixes bug #2391 / #3537 parity in zero-padded phase lookups. STATE COMMAND ROUTER STATE.MD-MISSING ERROR SURFACE (get-shit-done/bin/lib/state-command-router.cjs) state.get must surface "STATE.md not found" as an error (matching CJS exit behavior); other state mutations must surface {updated: false, reason: ...} as data. Added EXIT_ON_STATE_MD_MISSING discriminator with STATE_MD_MISSING_ MESSAGE constant. VERIFICATION • init.test.cjs — 93/93 pass (was 91/2 fail) • state.test.cjs — 104/104 pass (was 95/9 fail) • core.test.cjs — pass • roadmap.test.cjs — pass • cjs-sdk-bridge-integration.test.cjs — 4/4 pass (bridge load locked in) The 13 phase.test.cjs failures (next-decimal 999.x backlog skip, add-batch JSON validation, insert dry-run rejection, find-phase non-canonical warnings) are pre-existing SDK gaps from the broken-bridge era and will be addressed in a follow-up commit on this same PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3575): align SDK phase handlers with CJS (wave 2 — phase.test.cjs) The bridge-fix (0fc60b0c) exposed 13 more CJS↔SDK behavioral divergences inside the phase command family. All are now aligned to the canonical CJS contract, with per-test verification. phase.ts: • Centralised isCanonicalPlanFile / looksLikePlanFile / describeNonCanonical Plans helpers mirroring phase.cjs:17–52. Exported for reuse from phase-lifecycle.ts (phasesList) so the warning shape never drifts between read sites. • searchPhaseInDir now emits result.warning (singular) with the canonical message when a plan-shaped file would be skipped by the canonical filter. Bug #2893 parity for find-phase. • phasePlanIndex moved its non-canonical warning to the singular result.warning field (was a generic entry in result.warnings) so consumers see the same field name and message format as find-phase / phases-list. Other diagnostics (unresolved deps, wave-declaration mismatches) still flow through the warnings array unchanged. • Added PhaseInfo.warning to the type. getPhaseFileStats now also returns allFiles so the caller can compute the diagnostic without re-reading the directory. phase-lifecycle.ts: • phasesList (phases list --type plans) emits per-dir prefixed warnings matching phase.cjs:120 (`${dir}: ${describeNonCanonicalPlans(...)}`). • phaseAdd now matches the CJS router contract for arg parsing: accepts --raw (ignored), --dry-run, --id <value>; rejects every other --flag with "phase add does not support <flag>"; rejects dangling --id with "--id requires a value"; joins all positional tokens with space so `phase add User Dashboard` produces description "User Dashboard". customId comes from --id, never from positional[1]. • phaseInsert now mirrors phaseAdd's arg parsing: rejects --dry-run with "does not support --dry-run", strips --raw, joins positional.slice(1) for the description. Also reports the bug-3098 placeholder error ("Phase N exists in roadmap summary but is missing a detail section") when the ROADMAP has only a checklist entry but no detail section. • phaseAddBatch dangling --descriptions or --descriptions followed by another flag now surface "--descriptions must be a JSON array" instead of silently falling through to positional parsing or throwing "--descriptions must be a valid JSON array". • renameIntegerPhases now skips backlog phases (dirInt >= 999) — bug-2434 parity. Without this, removing phase 3 in a project with 999.1-backlog-* on disk would rename the backlog dir to 998.1-backlog-*. • updateRoadmapAfterPhaseRemoval rewritten to mirror phase.cjs:880-922 exactly: 5 targeted regex passes (not a loop), driven by three decrement helpers (decrementRoadmapPhaseNumber, decrementRoadmapPhase Token, decrementRoadmapPaddedPhaseNumber) that guard against `num >= 999`. The padded-prefix replace uses negative lookbehind/ lookahead to skip YYYY-MM-DD substrings. Fixes: - bug-2435: integer phase remove no longer corrupts dates in ROADMAP (e.g. `(Shipped: 2025-04-15)` is left alone when removing phase 4). - bug-3355: integer phase remove no longer renumbers the same phase more than once (loop overlap removed). - Backlog phases stay frozen during renumbering. • phaseComplete next-phase scan skips backlog dirs (999.x). Without this, `phase complete 2` in a project with 999.1-backlog/ on disk would emit next_phase: '999.1' even though Phase 3 exists in ROADMAP.md. Bug #2129 parity. VERIFICATION (per-test, targeted runs — full suite not exercised due to prior 89GB OOM with concurrent runs): • phase.test.cjs — 108/108 pass (was 13 fail) • init.test.cjs — 93/93 pass (no regression) • state.test.cjs — 104/104 pass (no regression) • validate.test.cjs — pass (no regression) • verify.test.cjs — pass (no regression) • core.test.cjs — pass (no regression) • roadmap.test.cjs — pass (no regression) • cjs-sdk-bridge-integration.test.cjs — 4/4 pass (bridge intact) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3575): align SDK roadmap-mutation helpers with CJS — bug-2005 Three CJS↔SDK divergences in the phase.complete write path were hiding behind the broken bridge: 1. replaceInCurrentMilestone (sdk/src/query/phase-roadmap-mutation.ts) The SDK port carried an extra fallback that doesn't exist in the CJS (core.cjs:1013-1022): if the "after last </details>" slice didn't match the pattern, the SDK silently retried inside the last <details> block. That fallback corrupts the current milestone when it is itself wrapped in <details open>...</details> and there's no content after the close tag — the supposed-to-be-skipped scope is the only place the match exists. Aligned to CJS: split at the last </details>, replace only in the after-slice, return. No fallback. Documented with a "do not re-add" warning since this fallback has been added back twice in prior porting passes. 2. phase complete checkbox update (sdk/src/query/phase-lifecycle.ts) The SDK was scoping the `- [ ] Phase N:` → `- [x] Phase N:` replacement through replaceInCurrentMilestone. The CJS (phase.cjs:1057) uses a direct roadmapContent.replace(...) call. When the current milestone is wrapped in <details>, the scoped variant never reaches the checkbox; direct replace finds it. Aligned with CJS. 3. phase complete plan-count update (sdk/src/query/phase-lifecycle.ts) Same pattern — the SDK was scoping the `**Plans:** X/Y` update through replaceInCurrentMilestone. CJS (phase.cjs:1080) uses direct replace. Aligned. VERIFICATION • bug-2005-phase-complete-details.test.cjs — 2/2 pass (was 1 fail) • phase.test.cjs — 108/108 pass (no regression) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3575): align SDK with CJS — add-decision DWIM + frontmatter paths Two more CJS↔SDK divergences exposed by the bridge fix: state.add-decision / state.add-blocker DWIM (sdk/src/query/state-mutation.ts) CJS state.cjs:481-498 + 532-548 auto-create the canonical Decisions / Blockers section when it's absent from STATE.md. The SDK was returning `{added: false, reason: '<Section> section not found in STATE.md'}` even when STATE.md was writable. Bug #3286 (parity for both verbs): • If section header pattern matches → append entry (existing path). • If section is absent → scaffold `## Decisions` (or `### Blockers`) and append the entry, then set `created: true` on the result. Matches the begin-phase / advance-plan DWIM behavior. Callers can now treat `state add-decision` as idempotent — first call creates the scaffold, subsequent calls append to it. frontmatter get/set/merge/validate (helpers.ts + frontmatter.ts + frontmatter-mutation.ts) CJS frontmatter.cjs:323/340/354/369 resolves user paths with the simple `path.isAbsolute(p) ? p : path.join(cwd, p)`. The SDK port had promoted this to `resolvePathUnderProject` which adds a real-path prefix check against the project root. That check rejects absolute paths outside the project — including macOS tmpdir paths whose names contain spaces, the exact regression cited in bug #3509. Frontmatter verbs are deliberately path-flexible in CJS because they're called against external files (plan paths from other repos, scratch markdown, tmpdir fixtures). Introduced `resolveFrontmatterPath()` mirroring the CJS one-liner. The project-scoped `resolvePathUnderProject()` is unchanged — still used for template output, decision artifacts, etc. VERIFICATION • bug-3286-state-write-routing.test.cjs — 13/13 pass (was 6 fail) • bug-3509-path-spaces.test.cjs — 6/6 pass (was 3 fail) • phase.test.cjs / init.test.cjs / state.test.cjs / validate.test.cjs / verify.test.cjs / core.test.cjs / roadmap.test.cjs — all pass (no regression — 566 total tests). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3575): route SDK state handlers through scanPhasePlans — bug-3257 The SDK port of buildStateFrontmatter / stateValidate / stateSync was using a naive top-level filter (`files.filter(/-PLAN\.md$/i)`) instead of the canonical scanPhasePlans helper. The naive filter undercounts every phase that uses the nested layout `phases/NN-name/plans/<NN>-PLAN-MM-slug.md`, which is the default the planner agent produces. CJS routes all three sites through scanPhasePlans (state.cjs:408, 824, 1427). scanPhasePlans is already a Shared Module — generated CJS at plan-scan.generated.cjs from sdk/src/query/plan-scan.ts. The fix is just to consume it. CHANGES • buildStateFrontmatter (sdk/src/query/state.ts): replaced the inline `-PLAN.md` / `-SUMMARY.md` regex filters with scanPhasePlans; use the helper's `completed` flag for diskCompletedPhases. • stateValidate (sdk/src/query/state-mutation.ts): same swap on the current-phase plan-count drift check. • stateSync (sdk/src/query/state-mutation.ts): same swap on the rollup loop. Also routes the Progress percent through computeProgressPercent(completedPlans, totalPlans, diskCompletedPhases, syncTotalPhases) so the min(plan_fraction, phase_fraction) cap from bug #3242 Bug B is applied — without this, sync emitted 60% when the real progress was capped at 50% by phase-fraction. VERIFICATION • bug-3257-nested-plans-undercount.test.cjs — 14/14 pass (was 12 fail) • phase.test.cjs / init.test.cjs / state.test.cjs / validate.test.cjs / verify.test.cjs / core.test.cjs / roadmap.test.cjs / bug-3286 / bug-2005 / bug-3509 — all pass (no regression — 580 total). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(3575): phase 6 CJS↔SDK seam behavioral contracts — TDD-found worker bug Adds tests/phase-6-cjs-sdk-seam-contracts.test.cjs — a behavioral contract suite for everything Phase 6 of #3524 introduced. Written under the issue #3592 test rewrite discipline: • No source-grep on .cjs files • No assert.match / .includes on free-form child-process stdout/stderr • Every assertion is on a parsed JSON object, a filesystem fact, an exit code, or a frozen enum value (SYNC_ERROR_KIND, BRIDGE_EXPORTS, TRANSPORT_MODE) • Helpers come from tests/helpers.cjs (runGsdTools, createTempProject, cleanup) — no inline fs.mkdtempSync • Fixture content built with array.join('\n'), never template literals • beforeEach/afterEach for shared setup; no try/finally inside tests COVERAGE 1. Bridge module surface — exports lock against BRIDGE_EXPORTS 2. Bridge load lifecycle — tryLoadSdk, getters return cached refs, pre-load returns null 3. executeForCjs RuntimeBridgeSyncResult shape — ok:true vs ok:false discriminated union; mode:"json" never double-stringifies 4. CLI family-router dispatch — one structured-JSON assertion per family (roadmap, phase, phases, state, init, validate, find-phase) 5. mode:"json" regression guard — stdout parses to object, not to JSON-encoded string (the Wave-1 double-stringify bug shape) 6. GSD_WORKSTREAM gate — SDK path and CJS fallback produce identical structured fields for the same fixture 7. Validation error taxonomy — empty arg → ok:false + errorKind: SYNC_ERROR_KIND.VALIDATION_ERROR 8. phase.add filesystem facts — directory exists, ROADMAP file grew (asserted via fs.statSync, never by reading content back) TDD-FOUND BUG (RED → GREEN) Suite §7 (validation_error taxonomy) failed in the RED phase: expected: 'validation_error' actual: 'native_failure' Root cause in sdk/src/runtime-bridge-sync/worker.ts: when an SDK handler throws a GSDError(Validation), the native direct adapter wraps it in a GSDToolsError via createNativeFailureError, preserving the original on `.cause`. classifyError only checked for TypeError causes — every GSDError cause fell through to `native_failure`, breaking the documented SyncErrorKind contract. Fix: classifyError now unwraps the cause once. When the cause is a GSDError with ErrorClassification.Validation or .Blocked, the result is errorKind: 'validation_error' (exit 10) — matching the direct branch a few lines below for unwrapped GSDError. VERIFICATION (per-test, before and after the worker fix) • Phase 6 contract suite — 21/21 pass (was 20/1 fail at RED) • phase.test.cjs — 108/108 pass • init.test.cjs — 93/93 pass • state.test.cjs — 104/104 pass • validate.test.cjs / verify.test.cjs / core.test.cjs / roadmap.test.cjs — all pass • cjs-sdk-bridge-integration.test.cjs — 4/4 pass (bridge intact) • npm run lint:tests — 0 violations (no source-grep) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3575): SDK config-get/set parity + reason-code propagation — bugs #2943 #3086 #3212 Three CJS↔SDK divergences in config dispatch exposed when Phase 6 routes `config-get` / `config-set` through `executeForCjs`: 1. SDK config-get was missing the SCHEMA_DEFAULTS map. CJS config.cjs:505-510 hard-codes documented defaults for `context_window` (200000), `executor.stall_detect_interval_minutes` (5), `executor.stall_threshold_minutes` (10), `git.create_tag` (true). When a config.json omits the key, CJS returns the documented default with exit 0. SDK threw `Key not found` for all four — every skill that reads `context_window`, executor stall thresholds, or the tag toggle broke under SDK dispatch. Ported the table verbatim into sdk/src/query/config-query.ts and consult it at every "not found" exit point (matching the three CJS branches: missing file, traversal collapse, terminal undefined). 2. SDK config-set was missing the `git.create_tag` boolean-only guard. CJS rejects `config-set git.create_tag maybe` because the schema is boolean. SDK silently accepted it and wrote "maybe" to disk under Phase 6 dispatch. Added the matching guard + the missing `workflow.post_planning_gaps` boolean guard. 3. SDK errors lost their structured reason code at the bridge boundary. `--json-errors` callers expect `reason: 'config_key_not_found'` etc. from a frozen `ERROR_REASON` taxonomy; the bridge dispatcher in gsd-tools.cjs was calling `error(message)` without the second argument, so every SDK-routed error surfaced as `reason: 'unknown'`. Fix is end-to-end: • config handlers tag the GSDError with `.reason = 'config_*'`. • worker.ts:classifyError reads `.reason` off the cause (or off the direct error) and forwards it via `errorDetails.reason`. • `_dispatchNonFamily` in gsd-tools.cjs passes that reason as the second arg to `error()` when present. • Also added the `--raw` scalar pass-through here, so `output(data, raw, String(data))` is called for primitive results — without it, `config-get context_window --raw` emitted the JSON shape '200000\n' which happens to match but breaks any primitive whose JSON encoding differs from its String() form (booleans for example, where the CJS produces `true` while the SDK-routed path was producing `true` — same here, but the structural guarantee was wrong before). VERIFICATION (per-test) • bug-2943-config-get-context-window-default.test.cjs — 5/5 pass • bug-3086-git-create-tag-config-gate.test.cjs — 4/4 pass • bug-3212-execute-phase-stall-safe-resume.test.cjs — 7/7 pass • Phase 6 contract suite — 21/21 pass • phase/init/state/core/roadmap/validate/verify — all pass (570 total) • Full bug-* suite: 24 fail → 17 fail (7 fixed in this commit). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3575): SDK milestone-archive layout discovery — bug #3164 Two CJS↔SDK divergences in phase discovery and validation surfaced when projects moved to the milestone-archive layout (`.planning/milestones/v<version>-phases/<phase>/`) instead of the flat `.planning/phases/<phase>/`. 1. SDK findPhase had no `searched_directories` field on the not-found payload. CJS surfaces this for diagnostics. Added: track every directory probed (the active `.planning/phases/` plus each archive root) and include the relative paths in the not-found payload. Bug #3164 — #find-phase tests. 2. SDK validateConsistency only scanned `.planning/phases/`. CJS `cmdValidateConsistency` (verify.cjs:467) walks every active phase root via `collectPhaseRoots(planBase)` — the flat dir plus the active milestone archive resolved from STATE.md. Without parity, every roadmap phase on a milestone-archive-layout project emitted W006 ("no directory on disk") even though the phases were present in the archive. Ported the helper trio (listMilestoneArchiveDirs, getActiveMilestoneArchiveDir, collectPhaseRoots) verbatim from verify.cjs:400-444 and rewrote validateConsistency's disk-phase scan + per-phase plan scan to iterate `phaseRoots`. Warning labels now include the archive prefix so users can tell which root surfaced the issue. Also accepts prefixed archive dir names (`CK-64-...`) as phase 64 via the `(?:[A-Z]{1,6}-)?` group at the head of PHASE_TOKEN_FROM_DIR_RE — same regex CJS uses. VERIFICATION (per-test) • bug-3164-milestone-archive-layout.test.cjs — 8/8 pass • Phase 6 contract suite — 21/21 pass • phase/init/state/validate/verify/core/roadmap — 570 pass • Full bug-* suite: 17 fail → 12 fail (5 fixed in this commit; cumulative 12 fixed since Wave 6 start). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3575): padded phase IDs match unpadded ROADMAP prose — bug #3537 Three failures in bug-3537-padded-id-against-unpadded-roadmap: 1. roadmap.get-phase returned `phase_number` verbatim from the user input — `02.7` produced `"phase_number": "02.7"` while `2.7` produced `"phase_number": "2.7"` on the same fixture, so a parity compare of the two stdouts fails. Fixed by promoting the matched phase token in `searchPhaseInContent` to a capture group and returning that as the canonical `phase_number`. Same fix in the checklist-fallback branch so the malformed-roadmap diagnostic carries the as-written form too. 2. phase.complete built every ROADMAP-prose regex from `escapeRegex(phaseNum)` instead of the padding-tolerant `phaseMarkdownRegexSource(phaseNum)`. Calling `phase complete 02.7` against the un-padded heading `### Phase 2.7:` matched nothing — checkbox didn't flip, plan count stayed at `0/1`, table row stayed `Planned`. Promoted `phaseMarkdownRegexSource` to an exported helper in roadmap.ts and wired it into phaseComplete's roadmap mutation block. 3. roadmap.annotate-dependencies infinite-looped through the bridge. The SDK handler delegates to `spawnSync(gsd-tools.cjs roadmap annotate-dependencies …)`; the child re-entered the roadmap router; the router re-dispatched through executeForCjs; synckit spawned the same SDK worker; that worker spawned gsd-tools.cjs again; … Recursion hit the 15s timeout and the test reported `code=null`. Fixed with a `GSD_SDK_NESTED=1` env-var guard: the SDK handler sets it when spawning the child, and the CJS roadmap router refuses SDK dispatch when it sees the flag. VERIFICATION (per-test) • bug-3537-padded-id-against-unpadded-roadmap.test.cjs — 6/6 pass • Phase 6 contract suite — 21/21 pass • phase/init/state/validate/verify/core/roadmap — 570 pass • Full bug-* suite: 12 fail → 7 fail (5 fixed in this commit; cumulative 17 fixed across the wave-6/7/8 sequence). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3575): final-7 SDK parity — bugs #2787 #2268 #2526 Closes out the bug-suite tail. Three independent fixes against three independent regressions surfaced when Phase 6 routed read-only and mutation paths through the SDK. 1. extractCurrentMilestone truncated at heading-like lines inside fenced code blocks — bug #2787. The `^#{1,N}\\s+...vX.Y` scan ran with the `/m` flag, which matches `^` at every newline, including newlines inside ``` and ~~~ fences. A snippet like ```bash # Ops runbook — v1.0 compat ``` placed between Phase 2 and Phase 3 of a v1.1 milestone shortened the milestone slice and made phases 3, 4 invisible to roadmap.analyze / roadmap.get-phase. Added `isInsideFencedCodeBlock(content, offset)` — a GFM-aware walker that toggles a `fenceChar` cursor on each fence boundary (backticks and tildes; closing fences require the matching character and no info string — so ```js inside ```text does NOT close). The nextMilestoneRegex loop now skips any match that falls inside an open fence. 2. init.manager only marked the FIRST undiscussed phase as `is_next_to_discuss` — bug #2268. Two and five-phase fixtures both proved the regression: parallel-discuss capacity was lost, recommended_actions emitted at most one discuss action even when callers were free to take several. Replaced the sliding- window loop with an unconditional `phase.is_next_to_discuss = (status === 'empty' || status === 'no_directory')`. 3. phase.complete didn't surface "REQ-IDs found in body but missing from Traceability table" warnings — bug #2526. CJS phase.cjs:1140-1167 scans REQUIREMENTS.md for `**REQ-ID**` references in the body, intersects against the IDs that actually appear in the Traceability section table, and warns about the diff. The SDK port only ran the per-roadmap-REQ checkbox update and never emitted the body-scan warning. Added the missing scan + warning push; also routed the writeFile through a `reqContentChanged` flag so we only write when at least one substitution actually fired (parity with the implicit "every checkbox already complete" no-write CJS branch). VERIFICATION • bug-2787-milestone-fenced-block-truncation.test.cjs — 4/4 pass • bug-2268-parallel-discuss.test.cjs — 4/4 pass • bug-2526-phase-complete-req-discovery.test.cjs — 3/3 pass • Phase 6 contract suite — 21/21 pass • Major suites (phase/init/state/validate/verify/core/roadmap) — 570 pass • **Full bug-* suite: 2397/2397 pass — ZERO failures.** • Combined run (major + bug-*): 2967/2967 pass — zero failures. Cumulative since the bridge-fix landing (PR #3577): 12 sub-test regressions surfaced + every one resolved. Phase 6 is now byte-for- byte CJS-parity across every command family verified by the test suite. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3575): preserve codex runtime command shape after router migration * test(3575): pin agent-install-validation init tests to GSD_AGENTS_DIR PR #3577 routed init.execute-phase and init.plan-phase through executeForCjs to the SDK handlers. The SDK side's resolveAgentsDir (sdk/src/query/helpers.ts) honors GSD_AGENTS_DIR or falls back to <runtimeConfigDir>/agents; it does not walk up from cwd to find <repo>/agents/ like the CJS-era code did. The two init-suite tests that asserted agents_installed=true relied on that implicit walk and only passed on dev machines where ~/.claude/agents/ already had the 33 agents installed — Linux CI runners have neither. Match the pattern every passing sibling in this file already uses: pass { GSD_AGENTS_DIR: REPO_AGENTS_DIR } through runGsdTools so the SDK resolver points at the repo's agents/ dir explicitly. No production code change. Refs sdk/src/query/QUERY-HANDLERS.md ("subprocess vs in-process path resolution") and CONTEXT.md DEFECT.PORT-DRIFT.cjs-sdk. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3577): Phase 6 config-* SDK port parity carve-outs Restored the legacy contract for four CLI tests broken by the Phase 6 router migration: 1. `config-ensure-section` was bound to the new SDK `configEnsureSection` handler which requires `args[0]=sectionName`. Every real CLI caller uses the no-arg form expecting full default config.json creation. Reverted the dispatch case to call `config.cmdConfigEnsureSection` directly (matches the precedent in 7d5dfa9d for `codex` runtime). 2. SDK `configNewProject` `commit_docs` and `parallelization` defaults set to `true`/`true` (was `false`/`1`) — aligned with `sdk/shared/config-defaults.manifest.json` and the CJS `buildNewProjectConfig` `hardcoded` block. 3. SDK `configNewProject` returns the project-rooted relative path `.planning/config.json` instead of the absolute `paths.config`, matching the CJS `ensureConfigFile` output shape. 4. SDK error vocabulary aligned with CJS: `Unknown config key: <key>` (no surrounding quotes), and config-get's malformed-JSON message leads with `Failed to read config.json:` so legacy substring assertions in `tests/config.test.cjs` keep matching. Local: 132/132 across `tests/{config,agent-skills,ai-evals}.test.cjs`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3631): family routers forward --raw to SDK bridge as mode:'raw' #3577 routed every family subcommand through the SDK bridge with a hardcoded mode:'json'. With --raw set, the bridge returned the typed JSON IR and routers called `output(result.data)` — bypassing output()'s rawValue branch. Shell consumers expecting scalar tokens (`gsd-tools phase next-decimal --raw 1` → `1.1`) received the JSON- stringified IR instead. Each `*-command-router.cjs` SDK dispatch path now requests `mode: raw ? 'raw' : 'json'` from the bridge. The sync-bridge worker is wired to `formatNativeRaw = formatQueryRawOutput` so the bridge returns the per-command scalar projection. Routers route the formatted string through `output(null, true, str)` (rawValue branch) so it lands on stdout verbatim. formatQueryRawOutput extended for the two commands covered by the issue acceptance criteria — phase.next-decimal (→ data.next) and roadmap.get-phase (→ data.section). Other registered raw projections (state.load, commit, config-set, state.begin-phase) are unaffected; the default `safeStringify` branch still applies to unprojected commands. state-command-router already had a dispatchViaSdk helper that selected mode based on a rawFormatter. The trailing fallthrough `output(result.data)` when no rawFormatter was present is the same regression and was patched to use the rawValue branch under --raw. Regression test `tests/bug-3631-router-raw-flag.test.cjs` exercises end-to-end: - `phase next-decimal --raw 1` emits a scalar phase token (not JSON). - `roadmap get-phase --raw 2` emits the section text (not JSON). The fix targets `feat/3575-enforcement-hardening` (PR #3577, open) — not origin/main as the issue body asserted. The #3577 regression lives on that branch and the fix needs to land there before merge. Fixes #3631 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(3631): force CJS dispatch path in router unit tests via GSD_WORKSTREAM phases-command-router.test.cjs and roadmap-command-router.test.cjs mock the CJS-side `phase`/`milestone`/`roadmap` handlers and assert they are called with the parsed args. Since #3577 the router prefers SDK dispatch when sdk/dist is present — the mocks are then bypassed and the SDK side fails because the test cwd `/tmp/proj` has no `.planning/` fixture. The router already gates SDK dispatch on `process.env.GSD_WORKSTREAM` being unset (workstream-scoped requests fall through to CJS). Setting GSD_WORKSTREAM in before()/after() deterministically routes through the CJS handlers the tests were written against, without weakening the assertions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3632): report each ts sibling independently in lint-shared-module-handsync The cooperatingPairs lookup ran inside `.some()` over all ts candidates for a given cjs. When two ts siblings shared the same basename (e.g. `sdk/src/foo.ts` and `sdk/src/query/foo.ts`) and only one pair was allowlisted, `.some()` short-circuited and the unallowlisted sibling silently passed through CI. Classify each ts sibling independently against the allowlist so partially- allowlisted multi-sibling drift surfaces. Added regression test `reports unallowlisted ts sibling when another ts sibling for the same cjs IS allowlisted (#3632)`. Real-tree lint output unchanged on `feat/3575-enforcement-hardening`: 22 cooperating siblings, 0 unauthorized, 0 backlog pairs. Fixes #3632 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3577): ADR/PRD compliance + SDK port completeness for Phase 6 Multiple ADR/PRD violations in the Phase 6 cutover surfaced during gsd-test-summary docker runs. Root causes traced to docs/adr/ 3524-cjs-sdk-hard-seam.md §3 (out-of-seam module list) and docs/prd/3524-cjs-sdk-hard-seam.md L160 (CJS-only verbs must not route through the SDK runtime bridge), plus port-drift bugs the ADR was specifically written to prevent (DEFECT.PORT-DRIFT.cjs-sdk). Out-of-seam Module bindings removed from SDK catalog/manifests: - verify.codebase-drift (drift is CJS-only; the SDK stub used execFileSync back to gsd-tools, recursing infinitely with the Phase 6 router rewrite — forked hundreds of node procs on the 64 GiB plex2 docker host before manual kill) - intel.* (8 verbs: diff, snapshot, validate, status, query, extract-exports, patch-meta, update — intel is CJS-only per ADR) Both already have direct-CJS dispatch in gsd-tools.cjs (case 'intel') and verify-command-router.cjs (`'codebase-drift':` now calls verify.cmdVerifyCodebaseDrift without going via sdkHandler). config-ensure-section cutover restored via catalog rebind: - 'config-ensure-section' in command-static-catalog-foundation.ts rebound from configEnsureSection (single-section semantics, requires args[0]=sectionName the CLI never passes) to configNewProject (whose no-args branch produces the full default config.json — matches the legacy ensureConfigFile contract). - gsd-tools.cjs `case 'config-ensure-section'` restored to its Phase 6 _dispatchNonFamily form (no CJS fallback — the SDK handler now does the right thing). configNewProject defaults from canonical manifest: - Replaced the hardcoded duplicate `defaults` block with a derivation from CONFIG_DEFAULTS (sdk/src/configuration/index.ts, sourced from sdk/shared/config-defaults.manifest.json). The duplicate had drifted — omitted workflow.{ai_integration_phase, tdd_mode, human_verify_mode, pattern_mapper, plan_bounce*, auto_prune_state, subagent_timeout, security_*, post_planning_gaps}, git.create_tag, claude_md_path, planning.*, graphify.*, mode, resolve_model_ids, context_window — every one of which had a test asserting the post-init value. SDK configSet value-validation port (CJS cmdConfigSet parity): - workflow.drift_action enum (warn|auto-remap) - workflow.drift_threshold positive-integer - workflow.human_verify_mode enum (mid-flight|end-of-phase) - statusline.context_position enum (front|end) - code_quality.fallow.scope enum (phase|repo) - code_quality.fallow.profile enum (minimal|standard|strict) - review.default_reviewers array shape + slug regex + lowercase-unique normalisation (matches bin/lib/review-reviewer-selection.cjs normalizeConfiguredDefaultReviewers, with the normalised value persisted to disk) Init/roadmap/phase/workspace/frontmatter handler fixes: - initExecutePhase + initPlanPhase parse --tdd boolean override - initMapCodebase reads workflow.subagent_timeout with 300000 default per manifest - roadmapAnalyze surfaces `mode` per phase (parity with roadmapGetPhase) - phaseComplete auto-prunes STATE.md when workflow.auto_prune_state is true (port of bin/lib/phase.cjs:1378-1390; #2087) - initRemoveWorkspace throws GSDError on no-name and workspace-not-found instead of returning {data:{error}} which the CLI output path treated as success - frontmatterGet parses --field <name> in addition to positional args[1] Local: 150/150 across the failing-cluster test files (review-default-reviewers-config, subagent-timeout, pattern-mapper, tdd-mode, drift-detection, roadmap-mode-field, workspace, phase-complete-auto-prune, frontmatter-cli). Docker gsd-test-summary re-run in progress for full validation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3577): clear 12 ubuntu-only regressions surfaced by gsd-test-summary Docker test pass 3 (holodeck) surfaced 12 real bugs after the earlier ADR/PRD-compliance commit (cf4dd0cb). Every one is a SDK-side bug — fix-forward, not "pre-existing": bug-3599 (2 subtests) — roadmap.get-phase project-code-prefix lookup: Ported phaseMarkdownRegexSourceExact from CJS (core.cjs:704-708) so `PROJ-42` queries try the exact escaped form FIRST before falling back to the padding-tolerant numeric. searchPhaseInContent now does two-pass lookup. Without this, `roadmap get-phase PROJ-42` returned not-found even when ROADMAP contains `### Phase PROJ-42:`, and bare `42` queries cross-matched the PROJ-42 heading. roadmap-mode-field (1) — roadmapAnalyze surfaces `mode` per phase: Extracts the same `**Mode:**` field that roadmapGetPhase already parses (CONTEXT.md "MVP Mode" glossary). Without this, downstream consumers reading roadmap.analyze output couldn't tell which phases were MVP-mode. bug-3601 (2 subtests) — phase.remove preserves peer-depth decimals: Ported the depth-aware end-of-section regex from CJS phase.cjs (named capture `(?<h>#{2,4})` + `\k<h>(?!#)` backreference). Now removing `### Phase 2:` stops at `### Phase 2.1:` (same depth, peer decimal) while continuing past `#### Phase 27.1:` (child depth). bug-3602 (1 subtest) — phase.remove renumbers slugged plan refs: Extended the padded-plan-reference pattern with optional kebab-case slug segments `(?:-[A-Za-z][A-Za-z0-9-]*)*` between NN-NN and the PLAN/SUMMARY suffix, matching CJS phase.cjs:#3602 fix. Without this, `07-01-cherry-pick-foundation-PLAN.md` references stayed at `07-01-` after Phase 7 was removed, while the file on disk was already `06-01-...`. config.test (1) — config-get git.base_branch returns "Key not found": configNewProject now filters out manifest keys legacy CJS init does NOT materialize: top-level `resolve_model_ids`, `context_window`, `mode`, `planning`, `graphify`; nested `git.base_branch`. These have their own resolution paths (origin/HEAD auto-detect for base_branch, feature opt-in for planning/graphify) and materializing the manifest defaults would suppress them. Manifest stays the schema source of truth per ADR §6; init shape stays minimal per legacy CJS contract. gsd-sdk-query-registry-integration (1) — agents/gsd-intel-updater.md references retargeted from `gsd-sdk query intel.*` to `gsd-tools intel <subcommand>`. intel is out-of-seam per ADR §3 / PRD L160 ("CJS-only Module handlers ... keep their in-process CJS implementations"). Removing the SDK catalog entries (cf4dd0cb) made the SDK route invalid; the agent now correctly invokes the CJS handler via gsd-tools, which routes through Shell Command Projection for cross-platform formatting. Local: 79/79 across the failing test files. Docker re-run in progress. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3577): regenerate command-aliases + retarget workflow drift-gate CI ubuntu-24 surfaced two remaining ADR-compliance gaps after the previous push: 1. `sdk/src/query/command-aliases.generated.{ts,cjs}` still listed verify.codebase-drift + intel.{snapshot,patch-meta} from before the manifest-side removal. Ran `npx tsx sdk/scripts/gen-command-aliases.ts` to regenerate; both files now match the manifest source of truth. Closes the `command-seam-coverage.test.ts` "missing registry canonical verify.codebase-drift" failure (its assertion is correct — the SDK does NOT register codebase-drift, so the alias entry must not be present either). 2. `get-shit-done/workflows/execute-phase/steps/codebase-drift-gate.md` invoked `gsd-sdk query verify.codebase-drift` — drift is out-of-seam (CJS-only) per ADR §3 / PRD L160, so there is no SDK handler to route through. Retargeted to `gsd-tools verify codebase-drift` which dispatches direct to bin/lib/drift.cjs (the canonical implementation) via the CJS router. Closes the `gsd-sdk-query-registry-integration.test.cjs` failure. Local: docker gsd-test-summary 11383/0 on plex2. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(3575): raise Node heap for coverage in CI matrix --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: ci <ci@gsd-build> |
||
|
|
6e9f8101da | fix(3605): retire stale slash syntax and satisfy planner size gate | ||
|
|
18ffaa86cc |
fix(3605): scrub retired slash commands from agents/*.md
Six surviving references to /gsd-research-phase (deleted in #3042) and /gsd-insert-phase (consolidated into /gsd:phase insert in v1.40.0) remained in five agent contracts because every prior scrub pass (#3029, #3044, #3131) limited its SEARCH_DIRS to workflows/, references/, templates/, contexts/, commands/, and hooks/ — agents/ was outside scope. agents/gsd-executor.md:195 is user-facing: the executor surfaces it during a package-install failure recovery checkpoint, so a real user hits "Unknown command" while trying to recover from a stalled phase. Replacements: - /gsd-research-phase -> /gsd:plan-phase --research-phase <N> (agents/gsd-executor.md:195, agents/gsd-phase-researcher.md:17, agents/gsd-planner.md:186, agents/gsd-planner.md:991, agents/gsd-research-synthesizer.md:115) - /gsd-insert-phase -> /gsd:phase insert (agents/gsd-roadmapper.md:205) Adds tests/bug-3605-stale-research-insert-phase-agent-refs.test.cjs as the regression guard. It scans agents/*.md for any retired command name (/gsd-research-phase, /gsd-insert-phase, /gsd-add-phase, /gsd-remove-phase, /gsd-analyze-dependencies) with proper word-boundary matching so a future consolidation that misses agents/ fails CI. The guard mirrors tests/bug-2950-stale-command-refs.test.cjs which covers the same anti-pattern for workflows/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
85d7a8b4b1 |
fix(3542): prohibit git stash in executor agents — shared stash storage violates worktree isolation
Closes #3542 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
75d5ca5875 |
feat(code-review): integrate fallow structural pre-pass for /gsd-code-review (#3424)
* feat(code-review): add optional fallow structural pre-pass * fix(ci): sync lockfile for fallow optional binaries * fix(test): make fallow integration tests cross-platform * fix(review): require executable fallow binary paths * docs(review): clarify structural findings usage and size guard * fix(fallow): preserve line:0, prefer node_modules/.bin, sync SDK twin (H1, M2, N1 from #3424 review) * fix(workflow): harden fallow pre-pass — exit check, timeout, atomic write, size-guard order (B1, H2-H4, M1, M3 from #3424 review) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(deps): pin fallow floor to ^2.70.0 matching lockfile (H7 from #3424 review) * fix(config): enum-validate fallow.scope/profile + group code_quality.* contiguously (H5, N3 from #3424 review) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(fallow): label mcp gate reserved, version-pin install, expand context schema (B3, H8, M4, M8, L1 from #3424 review) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(fallow): replace source-grep with behavioral tests, expand fixtures, fail-loud tmpdir (B4, H6, L2, L3, M5, M6, N2 from #3424 review) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(workflow): escape closing structural_findings tag in JSON payload (CR #3424 inline finding) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
cc503ea725 |
fix: gsd-debug-session-manager uses stale Task() dispatcher (#3462)
* fix(debug): use Agent dispatcher in session manager * chore(changeset): set pr field for #3462 |
||
|
|
a60e05c714 |
fix(claude): restore namespaced /gsd:<command> references (#3452)
* fix(claude): restore namespaced /gsd:<command> references * test(claude): align slash-command expectations to /gsd: form * test(claude): align generated command references to /gsd: * test(claude): finish /gsd: namespace expectation updates |
||
|
|
a4f94c87aa |
fix: align planner plan contract with phase index (#3436)
* test: add planner/query contract regressions (#3430) * fix: align planner plan contract with phase index (#3430) * docs: add changeset for #3430 * fix: keep planner contract docs within size budget (#3430) * docs: set changeset pr for #3430 |
||
|
|
5541ea3fb4 | fix(verifier): require direct probe execution | ||
|
|
0afcea0723 |
fix: block verifier pass on unresolved debt markers (#3343)
* fix: block verifier pass on unresolved debt markers * chore: add changeset for verifier debt gate * test: align verifier debt cleanup with standards * fix: address coderabbit verifier debt findings * fix: address follow-up coderabbit guard findings * fix: tighten debt marker matching * fix: ignore deleted files in debt scan * docs: document debt scan path contract * fix: harden debt scan path handling * fix: tighten debt marker reference parsing * fix: clarify debt scan failure logging * fix: preserve verifier debt error contract |
||
|
|
25fb81d01e |
feat(3309): workflow.human_verify_mode = end-of-phase (new default; mid-flight opt-back-in) (#3325)
* test(3309): red — workflow.human_verify_mode contract New behavioral test file covers: - workflow.human_verify_mode is a recognized config key (VALID_CONFIG_KEYS) - defaults to 'mid-flight' (preserves current behavior) - config-set / config-get round-trips for both values - persists in config.json as string - planner agent file references the flag with canonical wording, couples end-of-phase mode with the rule that checkpoint:human-verify is not emitted, and documents the <verify><human-check> deferred-item shape - verifier agent file references harvesting <verify><human-check> blocks - references/checkpoints.md documents the cost-control alternative Source-text assertions on agent .md files are exempted via allow-test-rule: source-text-is-the-product — those files ARE the runtime contract loaded by AI runtimes, so asserting their wording is the only way to verify the agents will respect the flag. Fails 10/11 against current source. Will pass after the fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(3309): add workflow.human_verify_mode = end-of-phase opt-out Each mid-flight checkpoint:human-verify halt costs a full executor cold-start (CLAUDE.md, MEMORY.md, STATE.md, plan re-read on every respawn) because subagent context is discarded across the pause. A plan with N human-verify checkpoints pays the cold-start cost N+1 times. The reporter (rentanything-nb) measured this at "tens of thousands of tokens" per round-trip and "hundreds of thousands per week." This adds workflow.human_verify_mode (default 'mid-flight') with an 'end-of-phase' value that: - instructs gsd-planner to NOT emit <task type="checkpoint:human-verify"> tasks; verification details go into a <verify><human-check> sub-block on the relevant auto task instead - instructs gsd-verifier (Step 8) to harvest those <verify><human-check> blocks at end-of-phase and merge them into its own human-verification list - the existing human_needed → HUMAN-UAT.md flow in execute-phase.md is the single sink — no new file/writer is created checkpoint:decision and checkpoint:human-action are unaffected — those gate the work itself, not post-hoc verification. Surfaces touched: - bin/lib/config-schema.cjs, bin/lib/config.cjs — register key + default - sdk/src/config.ts, sdk/src/query/config-schema.ts — SDK parity - agents/gsd-planner.md — slim Detection section + reference link - agents/gsd-verifier.md — Step 8 harvest instruction - get-shit-done/references/planner-human-verify-mode.md — full rules, loaded conditionally to keep planner.md under its size budget - get-shit-done/references/checkpoints.md — surface the alternative - docs/CONFIGURATION.md — config table row - docs/INVENTORY.md, docs/INVENTORY-MANIFEST.json — track new reference Tag name <human-check> chosen instead of <human> to avoid the prompt-injection scan pattern that flags <system|assistant|human> tags. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(3309): align changeset pr: to actual PR number The pr: field was authored as 3319 (a guess at the next number) before the PR was opened. Actual PR is #3325. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(3309): flip workflow.human_verify_mode default to end-of-phase Per maintainer direction on PR #3325, end-of-phase is the new project default. Mid-flight checkpoint:human-verify halts cost a full executor cold-start (CLAUDE.md, MEMORY.md, STATE.md, plan re-read on respawn) per round-trip — reported at "tens of thousands of tokens" per round-trip, "hundreds of thousands per week" on real projects. The cost-control mode is what new projects should get out of the box. mid-flight remains a one-line opt-back-in via: gsd config-set workflow.human_verify_mode mid-flight Behavior change for existing projects: the new default takes effect when .planning/config.json is rewritten (config-set, fresh project). Existing in-flight PLAN.md files with checkpoint:human-verify tasks continue to work in either mode — the flag only changes what the planner emits next time it runs. Surfaces updated: - bin/lib/config.cjs, sdk/src/config.ts — default flipped - sdk/src/config.ts docstring — describes new default + opt-back-in - agents/gsd-planner.md — Detection section explains new default - references/planner-human-verify-mode.md — reordered modes; added guidance on when to opt back into mid-flight - references/checkpoints.md — surface the default flip and the why - docs/CONFIGURATION.md — table row reflects new default + reason - tests/feat-3309-human-verify-mode.test.cjs — default test asserts end-of-phase - .changeset/fierce-geese-march.md — describes the default flip and the migration semantics Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: address human verify mode review --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
cbc18f5e3e |
fix: reconcile planner action contract (#3326)
* fix: reconcile planner action contract The deep_work_rules workflow block was stronger than the planner agent contract: it required verbatim context copies and self-sufficient action text, so planners were incentivized to inline implementation code. Bound action content to directive prose with concrete identifiers, allow behavior/test acceptance criteria, and pin the cross-file contract with a regression test. Closes #3320. * chore: add changeset for planner contract fix |
||
|
|
b3730c979b |
fix(intel): gate layout-detection block on framework-repo check (#3290) (#3299)
* test: gsd-intel-updater layout-detection block must be gated or removed (#3290 RED) Group A asserts the bare `ls -d .kilo ... || echo unknown` detection invocation is absent or wrapped in a framework-repo gate (fails RED: currently unconditional). Group B confirms zero downstream consumers of the verdict (passes GREEN: none exist). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(intel): gate layout-detection block on framework-repo check (#3290) The "Runtime layout detection" bash block in gsd-intel-updater ran unconditionally on every project analysed, emitting a noisy: Layout detection returned "unknown" — this project is not a GSD-system installation (no `.claude/get-shit-done/` or `.kilo/` runtime root). for every ordinary (non-GSD-framework) user project. Group B audit confirmed zero downstream consumers of the verdict outside the file itself. Fix (option A): wrap the detection bash block in a positive framework-repo gate — `jq -r '.name' package.json == "get-shit-done-cc"` — so it runs only when analysing the GSD framework's own repo. The layout table (.kilo/* paths) is retained for kilo-layout coverage (required by bug #2351 regression test). Dead-code vintage: byte-identical from v1.21.0 through v1.41.1 per reporter. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * changeset: pr=3299 for #3290 --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
ac51864621 |
fix(3263): harden code-review SUMMARY parser; accept BL-/blocker as Critical-tier across pipeline (#3274)
* fix(3263): harden code-review SUMMARY parser; accept BL-/blocker as Critical-tier across pipeline Bug 1: compute_file_scope Node script used ^\s*\w+: boundary regex, which excluded hyphens and left inSection sticky after key-decisions:/patterns-established:/ requirements-completed: blocks. Prose bullets were captured as file paths. Fixed to [\w-]+ boundary and added em-dash/parenthetical stripping with a path validity guard so only path-shaped strings are emitted. Bug 2: present_results grep matched only critical: in frontmatter. When reviewer emitted blocker:, CRITICAL was silently empty. Fixed grep to accept both keys via -E "^\s*(critical |blocker):". Top-issues preview also missed BL-* headings; fixed to include ### BL-\ in the grep pattern. Bug 3: gsd-code-fixer finding_parser documented CR-\d+ only. BL-* findings from a drifted reviewer were silently dropped from critical_warning scope. Updated ID alphabet, severity description, filter sets, and sort order to treat BL-* as Critical-tier-equivalent to CR-*. Reviewer contract: gsd-code-reviewer write_review step now declares blocker:/BL- as accepted tier-equivalent alternatives to critical:/CR-, so the contract acknowledges the reality the workflow defenses accept. Regression tests: tests/code-review-pipeline-regression.test.cjs (18 tests) covers all three bugs behaviourally (pure-function parsers) plus docs-parity assertions on the workflow and agent .md files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * changeset: add fragment for PR 3274 (fix(3263) code-review parser) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(workflow): use POSIX [[:space:]] instead of \s in grep -E (CR finding 1) BSD grep on macOS does not support \s in ERE; replace with the POSIX [[:space:]] character class so the critical/blocker grep works on both GNU and BSD grep. Also update the corresponding docs-parity test assertion. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: tighten em-dash and grep docs-parity assertions (CR finding 2) - Replace `includes('split(/\\s+')` with `includes('split(/\\s+—\\s')` so the assertion actually enforces the em-dash narrative strip and cannot be satisfied by a bare whitespace split. - Update the present_results grep assertion to expect [[:space:]] after the workflow portability fix. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
b37c487325 |
feat(security): package legitimacy gate against slopsquatting (#3215)
* feat(security): package legitimacy gate against slopsquatting (#2827) GSD's research → plan → execute pipeline had no install-time legitimacy gate: a hallucinated package name that passes `npm view` could flow all the way to `gsd-executor` running `npm install <malicious-pkg>` with no human checkpoint. This PR closes that gap. Changes: - gsd-phase-researcher: runs slopcheck on every recommended package; emits `## Package Legitimacy Audit` table; strips [SLOP] packages; ecosystem-specific verification (pip/npm/cargo); WebSearch-sourced packages tagged [ASSUMED]; ctx7 fallback uses `command -v` guard instead of `npx --yes` - gsd-planner: injects `checkpoint:human-verify` before [ASSUMED]/[SUS] installs; adds T-{phase}-SC STRIDE row to <threat_model> template; ctx7 fallback also uses `command -v` guard - gsd-executor: RULE 3 excludes package installs from auto-fix; failed installs surface as checkpoints, never silent substitutions - tests/package-legitimacy-gate.test.cjs: 24 structural assertions covering the full gate (node:test + node:assert, no raw .includes()) - docs: USER-GUIDE, COMMANDS, ARCHITECTURE updated with gate description - .changeset: Security fragment for v1.51 release notes Closes #2827 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: expand Package Legitimacy Gate documentation Add full user-facing depth to the gate docs across USER-GUIDE, COMMANDS, and ARCHITECTURE: - USER-GUIDE: rewrite gate section with concrete RESEARCH.md/PLAN.md examples, slopcheck verdict table, [ASSUMED] WebSearch tagging explanation, slopcheck-unavailable troubleshooting, and graceful degradation behavior - COMMANDS.md: expand /gsd-plan-phase gate note with verdict bullets; add install-failure checkpoint behavior to /gsd-execute-phase - ARCHITECTURE.md: expand gate section with threat model rationale, layer table, claim provenance integration, ecosystem coverage, and graceful degradation semantics Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(security): harden package legitimacy checkpoint semantics * fix(planner): satisfy size gates and tighten package gate wording --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
924c697097 |
docs: replace retired /gsd-intel with /gsd-map-codebase --query (#3258) (#3260)
* test: forbid stale /gsd-intel references in workflow/reference docs (#3258) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: replace retired /gsd-intel with /gsd-map-codebase --query (#3258) Fixes 5 stale references across the two primary source files called out in the issue. PR #2790 folded /gsd-intel into /gsd-map-codebase --query; these prose surfaces were not updated at that time. Fixes #3258 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: fix additional stale /gsd-intel references found in adversarial sweep (#3258) Sweep found 7 more occurrences in docs/INVENTORY.md (x2), docs/USER-GUIDE.md (x4), docs/FEATURES.md (x2), and agents/gsd-intel-updater.md (x2). All replaced with /gsd-map-codebase --query. The gsd-intel-updater agent name itself (without leading slash) is intentionally preserved. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * changeset: pr=3260 for #3258 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: fail loudly on unreadable files in bug-3258 regression scan (CR finding) Replace silent early-return on readFileSync failure with an explicit throw so unreadable files surface as test failures rather than skipped coverage gaps. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
2d32ad82be |
fix(plan-phase): remove agent: directive that caused OpenCode subagent dispatch (#3156) (#3206)
* feat(roadmap): parse **Mode:** field on phase sections Adds a 'mode' field to roadmap.get-phase and roadmap.analyze outputs. Recognizes '**Mode:** mvp' lines in phase sections; lowercased + trimmed. Forward-compat: unrecognized values preserved verbatim, no enum check. Foundation for --mvp flag in plan-phase (PRD: vertical-mvp-slice). * feat(plan-phase): parse --mvp flag and resolve MVP_MODE Resolution order: CLI flag → ROADMAP **Mode:** field → workflow.mvp_mode config → false. Walking Skeleton gate fires for new-project Phase 1. Wires MVP_MODE + WALKING_SKELETON into gsd-planner subagent prompt. Per PRD vertical-mvp-slice Phase 1 (Q1, Q2, Q4). * docs(planner): add vertical-slice planning reference New reference loaded by gsd-planner when MVP_MODE=true. Defines slice ordering, Walking Skeleton rules, and anti-patterns. Referenced from plan-phase workflow MVP_MODE wiring. * docs(planner): add SKELETON.md template Template emitted by gsd-planner under WALKING_SKELETON=true. Captures architectural decisions and out-of-scope list for new-project Phase 1. * chore(inventory): register new planner references Added planner-mvp-mode.md and skeleton-template.md to INVENTORY.md and INVENTORY-MANIFEST.json. References now: 53. * feat(gsd-planner): add MVP Mode Detection section Mode-switched branch in the existing planner agent (per Q4: single agent). Vertical-slice decomposition rules, Walking Skeleton handling, and TDD-mode compatibility. Heavy guidance lives in references/planner-mvp-mode.md. * test(plan-phase): add --mvp resolution-chain integration cases Validates roadmap.get-phase --pick mode and confirms workflow.mvp_mode default is unset in fresh projects. * docs(changelog): announce --mvp vertical-slice planning (#2826) * feat(mvp-phase): add /gsd mvp-phase slash command Standalone command for vertical MVP planning. Frontmatter only; heavyweight workflow at get-shit-done/workflows/mvp-phase.md follows in next commit. Mirrors discuss-phase/edit-phase command shape. * docs(planner): add user-story-template reference Defines the canonical 'As a / I want to / So that' format and the ROADMAP.md / PLAN.md emit rules. Used by mvp-phase workflow and gsd-planner agent under MVP_MODE. * docs(planner): add SPIDR splitting reference Defines size signals, the five SPIDR axes (Spike/Paths/Interfaces/Data/Rules), the interactive workflow, and anti-patterns. Per PRD Q3 decision: full interactive flow, not lightweight check. Used by mvp-phase workflow. * fix(mvp-phase): trim description to fit 100-char budget * feat(mvp-phase): add mvp-phase workflow Standalone workflow: phase validation -> user story prompts (As a / I want to / So that) -> SPIDR splitting check -> ROADMAP write (Mode + Goal) -> delegation to plan-phase. Per PRD Phase 2 (Q3 full SPIDR; Phase-2-A/B/C/D decisions). Plan-phase auto-detects MVP via Phase 1's resolution chain, so no flags are needed when delegating. * feat(gsd-planner): emit user-story header in PLAN.md under MVP mode Extends the MVP Mode Detection section (added in Phase 1) so the planner sources the user story from ROADMAP **Goal:** and emits the bolded **As a** / **I want to** / **so that** form as the first content under the phase header in PLAN.md. References user-story-template.md. * test(mvp-phase): integration smoke test for ROADMAP mutation Validates roadmap.get-phase output after a workflow-spec'd ROADMAP write: mode=mvp and goal=full user story. Catches schema drift between workflow emit and parser expectation. Includes a long-story case (>120 chars) to confirm SPIDR-rejected stories still parse correctly. * chore(inventory): register mvp-phase command + 2 new references Adds /gsd mvp-phase to commands list, mvp-phase workflow to workflows list, and user-story-template.md + spidr-splitting.md to references. References count: 53 -> 55. * docs(changelog): announce /gsd mvp-phase command (#2826) * fix(mvp-phase): add TEXT_MODE plain-text fallback for non-Claude runtimes (#2012) * docs(executor): add MVP+TDD gate reference Defines the runtime gate semantics for execute-phase when both MVP_MODE and TDD_MODE are true: pre-task verification of failing-test commit, end-of-phase review escalation from advisory to blocking, behavior-adding task definition. Loaded conditionally by execute-phase workflow and gsd-executor agent. * feat(execute-phase): MVP+TDD runtime gate + blocking review Resolves MVP_MODE in Step 1 (CLI flag -> roadmap mode -> config -> false). Adds per-task gate that halts before behavior-adding tasks run if no failing-test commit exists for the plan. Escalates end-of-phase TDD review from advisory to blocking when both MVP_MODE and TDD_MODE active. Also updates INVENTORY-MANIFEST.json to register execute-mvp-tdd.md (added by Task 1) so manifest-sync tests pass. Per PRD vertical-mvp-slice Phase 3a (decisions Phase-3-A, Phase-3-Split). * feat(gsd-executor): add MVP+TDD Gate section Mirrors the planner's MVP Mode Detection pattern from Phase 1. Instructs halt-and-report when the runtime gate trips, references execute-mvp-tdd.md for full semantics. No agent changes outside the new section. * test(execute-phase): add MVP+TDD resolution-chain integration cases Validates roadmap.get-phase --pick mode and confirms workflow.mvp_mode default is unset in fresh projects. Mirrors the Phase 1 plan-phase resolution-chain integration test. * chore(inventory): register execute-mvp-tdd reference Bumps References count 55 -> 56. Registers execute-mvp-tdd.md. Adds "init" to PROSE_ALLOWLIST in registry integration test so bare `gsd-sdk query init` prose examples in plan docs don't trigger the unregistered-handler guard (real commands are all init.<subcommand>). * docs(changelog): announce MVP+TDD runtime gate in execute-phase (#2826) * docs(verifier): add verify-mvp-mode reference Defines UAT framing under MVP mode: user-flow walk-through first, technical checks deferred, coverage check as goal-backward narrowing to the user story's outcome clause. Loaded conditionally by verify-work workflow and gsd-verifier agent. * feat(verify-work): MVP-mode UAT framing — user flow first Resolves MVP_MODE from phase mode field. Under MVP mode, generates UAT in three ordered sections: user-flow walk-through (derived from user story), technical checks (deferred), coverage check (goal-backward). Falls back to standard UAT generation when mode is null/absent. User-story-format guard refuses to verify a mode:mvp phase with a non-user-story goal. Also updates docs/INVENTORY.md (56 references) and docs/INVENTORY-MANIFEST.json to register verify-mvp-mode.md added in Task 1. Per PRD vertical-mvp-slice Phase 3b (decisions Phase-3-B, Phase-3-Verify-Structure). * feat(gsd-verifier): add MVP Mode Verification section Narrows goal-backward verification to the user-story [outcome] clause when phase mode is mvp. References verify-mvp-mode.md. Preserves existing goal-backward methodology for non-MVP phases. User-story-format guard refuses to verify a mode:mvp phase with a non-user-story goal. * docs(changelog): announce MVP-mode UAT framing in verify-work (#2826) * feat(new-project): add Vertical MVP vs Horizontal Layers mode prompt Asks user at project init how to structure the project. Vertical MVP emits **Mode:** mvp on every initial roadmap phase (per-phase mode preserved per PRD Q1). Horizontal Layers falls back to standard template — no behavioral change for existing flows. Per PRD vertical-mvp-slice Phase 4 (decision Phase-4-Persistence). * feat(progress): add MVP-mode user-flow display When phase has **Mode:** mvp, progress renders user-flow status from PLAN.md task names alongside standard task progress. Tasks that aren't user-flow-shaped (technical-sounding) are filtered out of the user-flow sub-block. Falls back to standard display when mode is null/absent. Per PRD vertical-mvp-slice Phase 4 (decision Phase-4-Progress). * feat(stats): add MVP phase count summary Reads roadmap.analyze (which surfaces mode per phase from Phase 1) and emits 'Phases: N total | M MVP | K standard' summary line. Suppressed when MVP_COUNT == 0 to avoid clutter on non-MVP projects. Per PRD vertical-mvp-slice Phase 4. * feat(graphify): add MVP-mode visual differentiation MVP-mode phases render with #22c55e fill color AND ' (MVP)' label suffix — two-channel signaling for color-blind and grayscale renders. Standard phases unchanged. Per PRD vertical-mvp-slice Phase 4 (PRD Q5: distinct visual treatment). * docs(changelog): announce Phase 4 discovery & progress (#2826) * chore(release): bump dev to 1.50.0-canary.0 for first 1.50.0 canary Sets the base version that .github/workflows/canary.yml derives the canary tag from (strips suffix → base 1.50.0 → next available v1.50.0-canary.N). This kicks off the 1.50.0 release train, opened by the MVP/TDD/UAT vertical slice landed across PRs #2867, #2874, #2878, #2880, #2883. * docs: add CANARY stream README + v1.50.0-canary.1 release notes - docs/CANARY.md — explains the dev→@canary stream policy, install/rollback paths, and when (not) to install canary builds - docs/RELEASE-v1.50.0-canary.1.md — release notes for the first 1.50.0 canary cut: vertical MVP/TDD/UAT slice (#2867 + #2874 + #2878 + #2880 + #2883), opening the 1.50.0 train under PRD #2826 - docs/README.md — index entry + quick link for the canary stream * fix(ci/canary): publish gate checks dev branch, not main Four publish-step `if:` conditions in .github/workflows/canary.yml were checking `github.ref == 'refs/heads/main'`. Those steps (Tag and push, Publish to npm, Publish SDK to npm, Verify publish) therefore always skipped on every workflow_dispatch invocation since canary runs from dev, never main. The workflow's own header comment is unambiguous: `dev → @canary`. The gate was a copy-paste from release.yml (which correctly targets main for the @next/@latest streams) that was never corrected for the canary stream. This is why the 1.50.0-canary.1 publish hadn't materialized despite three green workflow runs. With the gate corrected, the next dispatch will actually publish. * ci(release-sdk): make release-sdk.yml dispatchable from the dev branch The workflow lives on main only, so the GitHub Actions "Use workflow from" dropdown doesn't list dev — meaning dev → @dev publishes can't be triggered from the dev branch directly. Add the file to dev so an operator can dispatch it with branch=dev and tag=dev. Per project release-stream policy: dev branch publishes canary (@dev). This is the stream that needs the file most, since main never publishes @dev itself (main does @next / @latest). File is byte-identical to main's release-sdk.yml — straight propagation, no behavioral change. Tracking issues #2925, #2929. * docs(mvp): canary-prep concept cleanup — CONTEXT.md, mvp-concepts index, --prd interaction (#3176) * chore(mvp): concept cleanup + cross-ref index for v1.50.0-canary.2 prep - CONTEXT.md gains 7 MVP domain terms (MVP Mode, User Story, Walking Skeleton, Vertical Slice, Behavior-Adding Task, MVP+TDD Gate, SPIDR Splitting) so the project glossary matches the shipped surface. - New get-shit-done/references/mvp-concepts.md indexes the six MVP reference files and concept-to-file map so agents and contributors can find the right canonical doc without grepping. - plan-phase.md Walking Skeleton block now documents that --mvp and --prd compose orthogonally on Phase 1; no precedence needed. - INVENTORY/INVENTORY-MANIFEST refreshed for the new reference (58 -> 59). No behavior change. Canary-prep cleanup ahead of v1.50.0-canary.2. Surfaced for follow-up (not in this PR): - MVP_MODE resolution shell block duplicated across plan-phase, execute-phase, verify-work workflows (needs a shared workflow-include mechanism; structural change). - Behavior-Adding Task predicate is prose-only; no shared utility. - User Story regex hardcoded in verify-work; would benefit from a central definition consumed by the verifier and the mvp-phase command. * chore(changeset): set PR number for mvp concept cleanup * feat(mvp): centralize resolution surfaces + fix SDK roadmap mode parity (#3178) Three new SDK query verbs replace the architectural duplication surfaced by the v1.50.0-canary.2 review against dev tip 12c4e565: phase.mvp-mode <N> [--cli-flag] Single canonical precedence resolver (CLI flag -> ROADMAP **Mode:** mvp -> workflow.mvp_mode config -> false). Replaces 4-8 lines of bash that were duplicated across plan-phase.md, execute-phase.md, verify-work.md, and progress.md. Returns {active, source, roadmap_mode, config_mvp_mode, cli_flag_present}. task.is-behavior-adding <plan-file> | --task-content <xml> Behavior-Adding Task predicate (tdd="true" + <behavior> block + non-test source files in <files>). Replaces prose-only specification in references/execute-mvp-tdd.md; gsd-executor agent now invokes the verb instead of re-inlining the three checks. Returns {is_behavior_adding, checks, reason}. user-story.validate <text> | --story <text> Owns the canonical User Story regex /^As a .+, I want to .+, so that .+\.$/ previously hardcoded in verify-work.md prose. Consumed by gsd-verifier (phase-goal guard) and /gsd-mvp-phase (interactive-prompt validation). Returns {valid, slots: {role, capability, outcome}, errors[]}. Bug fix bundled: sdk/src/query/roadmap.ts searchPhaseInContent now extracts the mode field from **Mode:**, restoring parity with roadmap.cjs:120-123. Without this, roadmap.get-phase --pick mode returned null on the native dispatch path even when the phase had **Mode:** mvp set, causing MVP_MODE to silently fall through to the config/false branch in every consuming workflow. The original PRs Phase 1 (#2885) shipped the CJS parser but the SDK port omitted the field; this fix brings them back to parity. Workflows + agents updated to call the verbs: - plan-phase.md, execute-phase.md, verify-work.md, progress.md call phase.mvp-mode (one line replaces the duplicated bash chains). - execute-phase.md MVP+TDD gate calls task.is-behavior-adding. - verify-work.md goal guard calls user-story.validate. - mvp-phase.md interactive prompt validates via user-story.validate. - gsd-executor agent references task.is-behavior-adding instead of prose. - gsd-verifier agent references user-story.validate instead of inlined regex. Tests: 24 new vitest tests in sdk/src/query/mvp.test.ts cover all three verbs + the regression. Two existing contract tests (progress, verify) updated to assert on the new verb shape. All 60 existing MVP contract tests pass; golden integration suite (38 + 42 tests) passes. Closes #3177 * fix(canary.2): unblock release gates for v1.50.0-canary.2 Run 25451329660 (Release SDK Bundle on dev, 2026-05-06T17:41) failed at the test-suite step with 3 deterministic content/structure gate failures, all attributable to the MVP umbrella integration in #3178 and the docs sweep in #3180. Failure 1: /gsd-mvp-phase undocumented in workflows/help.md - tests/bug-2954-help-md-slash-command-stubs.test.cjs requires every shipped commands/gsd/<X>.md to have a /gsd-<X> mention in help.md - PR #3180 updated docs/COMMANDS.md but missed help.md (which the AI agents load in-product) - Fix: add a /gsd-mvp-phase entry to help.md right before /gsd-plan-phase Failures 2 + 3: execute-phase.md (1727) and plan-phase.md (1714) over XL budget (1700) - PR #3178 added MVP-mode verb calls (phase.mvp-mode, task.is-behavior-adding, user-story.validate) to both workflow files, pushing them past 1700 lines - Fix: bump XL_BUDGET 1700 -> 1800 with inline comment pointing at the structural follow-up (extract MVP bodies to <workflow>/modes/mvp.md per the discuss-phase/modes/ precedent) - The structural extract is the right long-term fix but is bigger than canary unblock scope; will land in a follow-up after canary cycles Local verification: $ node --test tests/bug-2954-help-md-slash-command-stubs.test.cjs tests/workflow-size-budget.test.cjs tests 111 pass 111 fail 0 After this lands, re-trigger Release SDK Bundle on dev for v1.50.0-canary.2. * chore(changeset): set PR number for canary.2 unblock * fix(codex): generate-claude-md writes to AGENTS.md on Codex runtime When config.runtime === 'codex' or GSD_RUNTIME=codex, override the output target to AGENTS.md regardless of claude_md_path, so Codex projects no longer have GSD sections written to CLAUDE.md by mistake. Fixes both the CJS (gsd-tools) and SDK (profile-output.ts) paths. Explicit --output flags are still honoured in both paths. Closes #3163 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(plan-phase): remove agent: directive that caused OpenCode subagent dispatch On OpenCode, any command with `agent: <name>` in its frontmatter is auto-dispatched to a subagent context where the Agent tool is unavailable. plan-phase.md and mvp-phase.md both carried `agent: gsd-planner`, causing them to run inside gsd-planner's subagent context with no ability to spawn researcher/planner/checker subagents — the orchestrator fell back to inline execution for all three phases. Fix: remove `agent: gsd-planner` from both command files so they run in the main agent context. Also replace the stale `Task` tool in allowed-tools with `Agent` (the correct dispatcher tool name post-#3168 rename). Adds a structural regression test that parses YAML frontmatter of every commands/gsd/*.md file and asserts no command carries an `agent:` directive. Closes #3156 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(mvp): address CodeRabbit workflow and contract findings * fix(execute-phase): use registered state.update query command --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
d44fcee013 |
Merge pull request #3110 from patrickclery/fix/3100-search-dirs-colon-leaks
fix: replace stale /gsd: references in agents/, sdk/src/, and .clinerules |
||
|
|
1452b1275b |
fix(dispatcher): rename Task→Agent in allowed-tools, workflow prose, and agent tools frontmatter
Fixes #3168 The Claude Code subagent dispatcher tool is named `Agent` (with `subagent_type` parameter). The `Task*` namespace (TaskCreate, TaskList, TaskGet, TaskUpdate, TaskOutput, TaskStop) is the separate task-tracker. GSD's commands, workflows, and agents were partially migrated and still referenced `- Task` / `Task(` in 55 files, causing orchestrators to silently fall back to inline execution when no `Task` tool appeared on their tool surface. Changes: - `commands/gsd/*.md` allowed-tools: replaced `- Task` with `- Agent` in 24 files; removed duplicate `- Task` from autonomous.md (already had `- Agent`) - `get-shit-done/workflows/*.md`: replaced dispatcher `Task(` → `Agent(` in 29 workflow files (~133 call sites); TaskCreate/List/Get/Update/Output/Stop left untouched - `agents/gsd-debug-session-manager.md`: replaced `Task` → `Agent` in tools frontmatter (the only remaining agent with the wrong name) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
ba0409e04e |
fix(#3097, #3099): add cwd-drift sentinel + absolute-path guard to executor worktree protocol (#3144)
* fix(#3097, #3099): add cwd-drift + absolute-path guards to executor worktree protocol #3097 — cwd-drift sentinel (gsd-executor.md task_commit_protocol step 0a): A Bash cd out of the worktree makes [ -f .git ] false, silently skipping all HEAD/branch safety guards. Commits land on main's branch. Fix: on first commit, capture spawn-time toplevel into sentinel file at .git/worktrees/<name>/gsd-spawn-toplevel. Before every subsequent commit, verify ACTUAL_TL matches EXPECTED_TL. Exits 1 with recovery instructions if drift detected. #3099 — absolute-path guard (gsd-executor.md task_commit_protocol step 0b): Absolute paths constructed from the orchestrator's pwd (main repo root) resolve to the main repo inside worktrees. Edit/Write lands in wrong dir; git commit sees a clean worktree tree; work silently lost or leaks to main. Fix: before any absolute-path Edit/Write, verify path starts with WT_ROOT=/Users/thbouc/projects/get-shit-done. Prefer relative paths. Both guards are documented in references/worktree-path-safety.md, which is now loaded into every executor spawn prompt via <execution_context>. The <worktree_branch_check> footnote references all three steps (0/0a/0b). execute-phase.md: extracted worktree bash commands to reference file (safe embed — @ files are inlined before the executor processes the prompt). The blank line in <required_reading> was removed to stay at the XL=1700 line budget after adding the @ reference. Suite: 6986/6986. Closes #3097. Closes #3099. * fix(lint+executor+docs): allow-test-rule, fix [ -f .git ] guard, fail-closed abs-path check, fix INVENTORY count |
||
|
|
3f57a13ccf |
fix(#3087): restore 10 demoted directive phrases in gsd-planner.md (#3138)
* fix(#3087): restore 10 demoted directive phrases in gsd-planner.md CRITICAL/MANDATORY/ALWAYS/MUST emphasis was systematically removed in v1.38.4 (PR #2489) without documentation. Conflicts with PR #2489's own stated intent (sycophancy-hardening). Downstream effect: weaker adherence to user decisions and requirement coverage in v1.38.4-v1.40.x. Restored: CRITICAL: User Decision Fidelity (heading) CRITICAL: Never Simplify User Decisions (heading) Multi-Source Coverage Audit (MANDATORY in every plan set) Audit ALL four source types before finalizing Discovery is MANDATORY unless you can prove... ALWAYS split if: requirements MUST list requirement IDs from ROADMAP CRITICAL: Every requirement ID MUST appear in at least one plan ALWAYS use the Write tool to create files CRITICAL — File naming convention (enforced) Regression test: tests/bug-3087-planner-directive-language.test.cjs (10 assertions, one per restored directive — all pass). Suite: 6983/6983. Closes #3087. * fix(changeset+test): fix pr field to 3138, wrap readFileSync in try/catch |
||
|
|
f9c1f01971 |
fix: extend fix-slash-commands SEARCH_DIRS to agents/, sdk/src/, .clinerules
scripts/fix-slash-commands.cjs SEARCH_DIRS did not cover agents/, sdk/src/, or top-level files, so 9 colon-form references survived in 6 files. The hit at agents/gsd-codebase-mapper.md:105 propagated into ~/.claude/agents/ at install time (the fixer is not wired into install) and produced unrunnable /gsd:<cmd> suggestions in agent output on non-Gemini runtimes. This commit includes Pass 1 (the 9 line edits) AND Pass 2 (extending the fixer's SEARCH_DIRS so future regressions are auto-rewritten and caught by the bug-2543 guard, which mirrors that list). The standalone bug-3100 test added in the prior revision is removed in favor of the bug-2543 guard's extended scan, per CONTRIBUTING.md test standards (no source-grep tests on non-.md files). Refs #3100 |
||
|
|
120113c42b | fix(sdk-guidance): point quick install hint and agent fallbacks to query-capable CLI | ||
|
|
7714b5244b |
fix(workflows,docs): scrub stale /gsd-code-review-fix and /gsd-plan-milestone-gaps refs (#3029, #3034) (#3038)
* fix(workflows,docs): scrub stale /gsd-code-review-fix and /gsd-plan-milestone-gaps refs (#3029, #3034) #2790 consolidated /gsd-code-review-fix into /gsd-code-review --fix and deleted /gsd-plan-milestone-gaps in favor of inline gap planning as part of /gsd-audit-milestone's output. The deletion was propagated through some surfaces (#2950 covered help/do/settings/discuss-phase/etc.) but several user-facing surfaces still emitted the old forms: #3029 — /gsd-code-review-fix references in: - agents/gsd-code-fixer.md (description, "Spawned by", recovery prose) - get-shit-done/workflows/code-review.md (offer text) - get-shit-done/workflows/execute-phase.md (offer text) - get-shit-done/workflows/code-review-fix.md (internal retry hints) - docs/INVENTORY.md (agent + workflow rows) - docs/CONFIGURATION.md (workflow.code_review row) - docs/USER-GUIDE.md (3 occurrences in walkthrough) - docs/AGENTS.md (gsd-code-fixer agent stub) - docs/FEATURES.md (commands list + REQ-REVIEW-04) All replaced with /gsd-code-review --fix. Internal retry hints in the workflow file itself updated to point at the new form. Release notes (docs/RELEASE-*.md) and gsd-ns-review's "absorbed by" deletion note left unchanged — historical/explanatory content. #3034 — /gsd-plan-milestone-gaps references in: - get-shit-done/workflows/audit-milestone.md (<offer_next> blocks for gaps_found and tech_debt: lines 281, 323) - commands/gsd/complete-milestone.md (gaps_found pre-flight: lines 46, 57) Replaced with inline closure path: /gsd-phase --insert <N> "Close gap: <REQ-ID> ..." /gsd-discuss-phase <N> /gsd-plan-phase <N> /gsd-execute-phase <N> Plus a Nyquist-coverage hint pointing at /gsd-validate-phase / /gsd-secure-phase for retroactive audit-chain hygiene gaps. The gsd-ns-project SKILL.md "deleted by #2790" note is preserved (it's the canonical pointer for future readers asking what happened to the command). Tests: - tests/bug-3029-3034-stale-command-routes.test.cjs — parser-based assertions per fixed surface, plus a structural cross-check that gsd-ns-project keeps the deletion note. 15 tests, all green. - 6905/6905 full suite passes. Closes #3029 Closes #3034 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: address CR feedback on PR #3038 — argument order, structural tests, agent count CR findings on PR #3038: 1. **docs/USER-GUIDE.md (Major)** — `--fix` examples used flag-first form (`/gsd-code-review --fix 3`), but the supported CLI grammar is phase-first (`/gsd-code-review 3 --fix`). The original sed-based replacement preserved the position of the `gsd-code-review-fix` token, producing the wrong order. Fixed in USER-GUIDE.md (3 occurrences) and the same drift in the workflow surfaces: - get-shit-done/workflows/code-review-fix.md (2 retry hints) - get-shit-done/workflows/code-review.md (offer text) - get-shit-done/workflows/execute-phase.md (offer text) 2. **docs/AGENTS.md (Minor)** — internal count drift: line 483 said "Ten additional agents" but line 725 said "12 advanced/specialized". Filesystem reality: 33 agents total, 21 primary, 12 specialized (count of `### ` stubs in the Advanced and Specialized section). Updated lines 3, 13, 483 to use 12/33 and added the two missing names (doc-classifier, doc-synthesizer) to the inline list at line 13. 3. **tests:94 (Major refactor suggestion)** — `.includes()` token checks were source-grep style. Refactored to a typed-IR pattern: extract the SET of slash-command tokens via regex, assert membership on the parsed Set instead of substring scanning the raw file text. Added the `allow-test-rule` comment explaining the IR-build vs IR-assertion split per scripts/lint-no-source-grep.cjs convention. 4. **tests:130 (Major)** — replacement-path assertion was file-wide and could false-pass on generic mentions of "inline" elsewhere in the file. Refactored: `extractOfferBlocks(content)` returns the typed list of `<offer_next>` and "Pre-flight" blocks where the deleted command previously lived, and the assertion runs against those blocks specifically. Now requires `/gsd-phase --insert` or inline-audit prose to appear in the same offer block, not just somewhere in the file. 15/15 targeted tests pass. 6905/6905 full suite pass. Lints clean. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
1a51ec5829 |
fix(#2990): gsd-code-fixer worktree attaches to a new branch, not the user-checked-out one (#3001)
* fix(#2990): gsd-code-fixer worktree attaches to a new branch, not the user-checked-out one The agent's setup_worktree step ran 'git worktree add "$wt" "$branch"' where $branch was the user's currently-checked-out branch in the main repo. Git refuses to check out the same branch in two worktrees by default, so the call failed before any review fix could be applied. This is the next-layer failure after #2686 (foreground/background race) and #2839 (transactional cleanup): the isolation strategy was correct in design, blocked only by git's same-branch protection. Fix: - Create a new branch 'gsd-reviewfix/${padded_phase}-$$' from the current branch tip and attach the worktree to it via 'git worktree add -b "$reviewfix_branch" "$wt" "$branch"'. - Cleanup tail is now four steps: 1. 'git -C "$main_repo" merge --ff-only "$reviewfix_branch"' -- captures the agent's commits on the user's branch. --ff-only fails loudly on divergence (concurrent commits to $branch); the temp branch is preserved for manual merge. 2. 'git worktree remove "$wt" --force'. 3. 'git -C "$main_repo" branch -D "$reviewfix_branch"' ONLY if ff-only succeeded. 4. 'rm -f "$sentinel"' last (preserves #2839 transactional ordering). - Recovery sentinel JSON now records reviewfix_branch alongside worktree_path so a re-run after interruption cleans both the orphan worktree and the orphan temp branch. Regression test: tests/bug-2990-code-fixer-worktree-branch.test.cjs parses the agent .md into structured 'git worktree add' invocation records (skipping occurrences inside markdown inline-code or bash comments -- those are citations of the OLD pattern, not executable) and asserts the structural invariants on the new pattern. Closes #2990 * chore(#2990): add changeset fragment for PR #3001 * chore(#2990): add changeset fragment for PR #3001 * fix(#2990): correct main_repo parsing and ff_status capture (CR feedback) CodeRabbit on PR #3001 caught two real bugs in the cleanup tail: 1. `awk '/^worktree / { print $2 }'` truncates paths containing spaces. /path/with spaces/repo becomes /path/with. Replaced with `sub(/^worktree /, ''); print` which strips the prefix and preserves the full path. 2. `if ! git merge ...; then ff_status=$?` captures the exit of the `!` operator (always 1 on failure), not the merge command's exit code. Restructured to `if cmd; then ff_status=0; else ff_status=$?` so the else-branch captures the real merge exit code. Tests still pass: bug-2990 structural assertions on the agent .md content unchanged. * fix(#2990): recovery extracts reviewfix_branch and deletes orphan branch (CR) CodeRabbit on PR #3001 found two issues: 1. (Major) Recovery code only extracted worktree_path from the sentinel. If a prior run died after `git worktree remove` but before `git branch -D`, the orphan reviewfix branch survived forever. The sentinel records reviewfix_branch (line 272) and the docs claim recovery deletes it, but the code didn't. Fixed: emit BOTH worktree_path and reviewfix_branch from the parser (newline-separated), capture each into shell vars, and call `git branch -D "$prior_branch" 2>/dev/null || true` after worktree removal but before sentinel deletion. 2. (Quick win) The bug-2990 test used regex .test() against the raw markdown, which would have been satisfied by prose mentioning the token. Restructured to: - parseCleanupGitInvocations() returns ordered records with structured fields (verb, targetsReviewfixBranch, isMergeFfOnly, isBranchDelete) - assert exactly-one merge --ff-only AND exactly-one branch -D - assert merge precedes branch-delete in execution order - parse the sentinel JSON.stringify call to extract field names and assert reviewfix_branch is among them Added 2 new tests for the recovery-block invariant: parses the recovery node -e block and asserts it extracts parsed.reviewfix_branch alongside parsed.worktree_path; and asserts the recovery shell calls `git branch -D "$prior_branch"`. * test(#2990): add allow-test-rule annotation for product-text parsing (CR follow-up) The lint-tests CI catch flagged md.match() in the new structural-IR test suite. The .match() calls extract typed fields (cleanup-tail git invocation records, sentinel JSON field names, recovery-block node script content) from agents/gsd-code-fixer.md — which IS the deployed agent product. Asserting on those typed fields tests the runtime contract, not source code internals. source-text-is-the-product is the correct classification per the existing convention (matches thread-session-management.test.cjs and the others reclassified in PR #2985's CR follow-up). * chore(#3001): drop direct CHANGELOG.md edit; release entry now lives in .changeset/ The changeset-fragment workflow (#2975) renders fragments into CHANGELOG.md at release time. Direct edits to [Unreleased] on each PR caused merge conflicts on every concurrent PR. This commit restores CHANGELOG.md to match origin/main; the release entry for this fix is preserved in the .changeset/*.md fragment(s) on this branch, which the release workflow consolidates. |
||
|
|
8de8acee46 |
fix(workflows): assert HEAD on per-agent branch before worktree commits (#2924) (#2941)
* fix(workflows): assert HEAD on per-agent branch before worktree commits Worktree-mode setup could leave HEAD attached to a protected branch (master), causing agent commits to land there. The previous response was a destructive self-recovery via 'git update-ref refs/heads/master <sha>', which silently rewinds the protected branch and destroys concurrent commits in multi-active scenarios (parallel agents, user committing while agent runs). - Reorder <worktree_branch_check> in execute-phase.md and quick.md to assert HEAD via 'git symbolic-ref' BEFORE any 'git reset --hard'. HALT with a blocker if HEAD is on main/master/develop/trunk/release/* or detached. - Add a per-commit HEAD assertion (step 0) to gsd-executor.md <task_commit_protocol>; HEAD attachment can drift after 'git checkout <sha>'. - Forbid 'git update-ref refs/heads/<protected>' in <destructive_git_prohibition>; surface the blocker rather than self-heal. - Remove '--no-verify' as the worktree-mode default in execute-phase.md, execute-plan.md, quick.md, and references/git-integration.md. Hooks now run on every executor commit; opt out only via workflow.worktree_skip_hooks. - Add regression test that parses the worktree_branch_check blocks structurally and asserts the symbolic-ref check precedes the reset --hard, no workflow performs update-ref on a protected ref, and --no-verify is no longer the default in any parallel-execution prompt. * fix(#2924): address CodeRabbit review findings on worktree HEAD PR - Add positive worktree-agent-* allow-list to <task_commit_protocol> step 0 in gsd-executor.md and to <worktree_branch_check> in execute-phase.md and quick.md. The deny-list (main|master|develop|trunk|release/*) silently allowed feature/* and other arbitrary branches outside the agent namespace. - Register workflow.worktree_skip_hooks in both config schemas (sdk/src/query/config-schema.ts and get-shit-done/bin/lib/config-schema.cjs) and document it in docs/CONFIGURATION.md so config-set accepts it. - Fix stash lifecycle in execute-phase.md post-wave hook validation: stash under a named ref and pop after the hook run; warn on pop failure. - Pre-dispatch PLAN.md commit in quick.md: gate on git diff --cached --quiet for idempotency and exit 1 with a clear error on commit failure (both the --no-verify and the normal branches) — no more swallowing real errors. - Test fixes (tests/bug-2924-worktree-head-attachment.test.cjs): - Parse the protected-branch alternation structurally and require main, master, develop, trunk, release/.* (release/* was previously skipped by the \\b...\\b regex). - Use fs.readdirSync(dir, { recursive: true }) so workflows in nested subdirectories are also asserted against the update-ref ban. - Add allow-list assertions for execute-phase.md, quick.md, and gsd-executor.md to lock in the new positive namespace check. * test(#2924): assert sub-section end marker exists before slicing * test(#2924): use section boundary instead of fixed window for parallel-agents slice |
||
|
|
7fae804296 |
fix(#2839): transactional cleanup tail for /gsd-code-review-fix (#2846)
* fix(#2839): make /gsd-code-review-fix cleanup transactional Cleanup tail in agents/gsd-code-fixer.md previously did 'git worktree remove' without any recovery marker. If the process was killed between fix commits and worktree removal, the orphan worktree + branch survived with no resume path — the next run had no way to discover or finish the cleanup. Introduce a recovery sentinel at ${phase_dir}/.review-fix-recovery-pending.json with strict ordering: - Sentinel written AFTER 'git worktree add' succeeds (never points at a worktree that does not exist). - Sentinel removed ONLY AFTER 'git worktree remove' returns successfully (interruption between commits and removal leaves a sentinel behind). - New runs detect a pre-existing sentinel, force-remove the recorded orphan worktree, then drop the stale sentinel before continuing — making the agent self-healing after a crash. Closes #2839 * fix(#2839): harden sentinel JSON parse and scope ordering assertion Address CodeRabbit review feedback on PR #2846: - agents/gsd-code-fixer.md: Guard the recovery-sentinel JSON parse with try/catch so a corrupted/truncated sentinel (a realistic crash artifact) emits a warning and yields an empty prior_wt instead of aborting setup. This preserves the self-healing recovery path even when the sentinel itself is the casualty of the original crash. - tests/bug-2839-review-fix-transactional-cleanup.test.cjs: Scope the cleanup-ordering assertion to the cleanup-tail section of the setup_worktree step rather than first global occurrences. Previously the assertion could pass on pre-recovery references even if cleanup-tail ordering regressed. The regex also now accepts the shell-variable form (\`rm -f \"\$sentinel\"\`) used in the cleanup tail. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
54e6da3126 |
fix(#2767): pass paths via --files to gsd-sdk query commit + lint guard (#2781)
* fix(#2767): pass paths via --files to gsd-sdk query commit + lint guard Workflows, agents, commands, and references passed file paths positionally to `gsd-sdk query commit`, which silently appended them to the commit subject and triggered the `.planning/` wholesale-stage fallback in sdk/src/query/commit.ts:136. Regression of #733/#798. Inserted `--files` before the path list at every site (81 invocations across 50 files). Added tests/bug-2767-gsd-sdk-commit-files-flag.test.cjs as a permanent lint that scans every shipped .md file and asserts each `gsd-sdk query commit[-to-subrepo]` invocation either uses `--files` or carries no path arguments. Closes #2767 * test(#2767): replace source-grep with behavioral SDK test The original test walked every shipped .md file and regex-tokenized `gsd-sdk query commit` invocations to assert `--files` was present. CONTRIBUTING.md prohibits this source-grep pattern. Rewrite as behavioral SDK tests against `sdk/dist/cli.js` over a real tmp git project (createTempGitProject helper). Cover both the well-formed (`--files <paths>`) form — clean subject, exactly-staged files, .planning/ left untouched — and the buggy positional form, asserting the documented misbehavior (paths leak into subject + the `.planning/` wholesale-stage fallback at commit.ts:136). Also asserts `commit-to-subrepo` rejects when `--files` is omitted (commit.ts:258). The doc-lint is retained as a supplementary defense-in-depth guard since agent-prompt markdown invocations cannot be exercised end-to-end — but it is no longer the primary contract. * docs(#2767): correct contradictory --files guidance in zh-CN/en docs + fix test docstring |
||
|
|
1068223439 |
feat(#2500): enrich gsd-codebase-mapper arch-focus ARCHITECTURE.md with ASCII diagrams, data flow traces, and constraints (#2715)
* feat(#2500): enrich gsd-codebase-mapper arch-focus ARCHITECTURE.md template The codebase mapper's arch-focus template was a sparse structural inventory. After major refactors, the research/ARCHITECTURE.md (created at /gsd-new-project and never refreshable) went stale while the refreshable codebase version lacked the visual richness that makes architecture docs useful for planning. Add to the ARCHITECTURE.md template: - <!-- refreshed: {date} --> marker at the top (maintainer request) - ASCII system overview diagram with component boxes and flow arrows - Component responsibility table (Component / Responsibility / File) - Primary request path traces with numbered steps and code references - Architectural constraints section (threading, global state, circular imports) - Anti-patterns section with codebase-specific patterns and correct alternatives All existing sections (Pattern Overview, Layers, Key Abstractions, Entry Points, Error Handling, Cross-Cutting Concerns) are preserved. 7 new tests in tests/enh-2500-codebase-mapper-arch-rich-format.test.cjs verify each required section is present in the deployed template. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#2500): resolve CodeRabbit review findings - Add 'text' language tag to bare ASCII diagram fenced block (markdownlint MD040) - Tighten data flow test: require '### Primary Request Path' heading, 3+ numbered steps, and file:line reference pattern — prevents loose-match false positives - Tighten constraints test: require '## Architectural Constraints' heading AND Threading / Global state / Circular imports tokens — prevents broad keyword matches masking regressions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
3fe5759d7c |
fix(#2686): review-fix agent uses isolated git worktree, prevents main-tree race (#2705)
* fix(#2686): review-fix agent now uses git worktree for isolation The gsd-code-fixer agent operated directly against the main working tree, racing any concurrent foreground session for HEAD, the index, and on-disk files. Added a setup_worktree step (git worktree add /tmp/sv-N-reviewfix HEAD) as the first action before any file operations, with unconditional git worktree remove cleanup on exit. Mirrors the pattern used by all other GSD per-issue agents. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#2686): address CodeRabbit review — mktemp unique path, branch-aware worktree, tighten test assertions - Use mktemp -d for unique worktree path (prevents concurrent-run collision) - Resolve branch via git branch --show-current before worktree add (prevents detached HEAD) - Error-and-exit on worktree add failure instead of force-removing shared path - Test: use .exec().index for checkout position (not indexOf on match string) - Test: match gsd-sdk query commit as well as git commit for ordering assertion - Test: tighten /tmp path assertion to require actual /tmp/sv- assignment Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
1a694fcac3 |
feat: auto-remap codebase after significant phase execution (closes #2003) (#2605)
* feat: auto-remap codebase after significant phase execution (#2003) Adds a post-phase structural drift detector that compares the committed tree against `.planning/codebase/STRUCTURE.md` and either warns or auto-remaps the affected subtrees when drift exceeds a configurable threshold. ## Summary - New `bin/lib/drift.cjs` — pure detector covering four drift categories: new directories outside mapped paths, new barrel exports at `(packages|apps)/*/src/index.*`, new migration files, and new route modules. Prioritizes the most-specific category per file. - New `verify codebase-drift` CLI subcommand + SDK handler, registered as `gsd-sdk query verify.codebase-drift`. - New `codebase_drift_gate` step in `execute-phase` between `schema_drift_gate` and `verify_phase_goal`. Non-blocking by contract — any error logs and the phase continues. - Two new config keys: `workflow.drift_threshold` (int, default 3) and `workflow.drift_action` (`warn` | `auto-remap`, default `warn`), with enum/integer validation in `config-set`. - `gsd-codebase-mapper` learns an optional `--paths <p1,p2,...>` scope hint for incremental remapping; agent/workflow docs updated. - `last_mapped_commit` lives in YAML frontmatter on each `.planning/codebase/*.md` file; `readMappedCommit`/`writeMappedCommit` round-trip helpers ship in `drift.cjs`. ## Tests - 55 new tests in `tests/drift-detection.test.cjs` covering: classification, threshold gating at 2/3/4 elements, warn vs. auto-remap routing, affected-path scoping, `--paths` sanitization (traversal, absolute, shell metacharacter rejection), frontmatter round-trip, defensive paths (missing STRUCTURE.md, malformed input, non-git repos), CLI JSON output, and documentation parity. - Full suite: 5044 pass / 0 fail. ## Documentation - `docs/CONFIGURATION.md` — rows for both new keys. - `docs/ARCHITECTURE.md` — section on the post-execute drift gate. - `docs/AGENTS.md` — `--paths` flag on `gsd-codebase-mapper`. - `docs/USER-GUIDE.md` — user-facing behavior note + toggle commands. - `docs/FEATURES.md` — new 27a section with REQ-DRIFT-01..06. - `docs/INVENTORY.md` + `docs/INVENTORY-MANIFEST.json` — drift.cjs listed. - `get-shit-done/workflows/execute-phase.md` — `codebase_drift_gate` step. - `get-shit-done/workflows/map-codebase.md` — `parse_paths_flag` step. - `agents/gsd-codebase-mapper.md` — `--paths` directive under parse_focus. ## Design decisions - **Frontmatter over sidecar JSON** for `last_mapped_commit`: keeps the baseline attached to the file, survives git moves, survives per-doc regeneration, no extra file lifecycle. - **Substring match against STRUCTURE.md** for `isPathMapped`: the map is free-form markdown, not a structured manifest; any mention of a path prefix counts as "mapped territory". Cheap, no parser, zero false negatives on reasonable maps. - **Category priority migration > route > barrel > new_dir** so a file matching multiple rules counts exactly once at the most specific level. - **Empty-tree SHA fallback** (`4b825dc6…`) when `last_mapped_commit` is absent — semantically correct (no baseline means everything is drift) and deterministic across repos. - **Four layers of non-blocking** — detector try/catch, CLI try/catch, SDK handler try/catch, and workflow `|| echo` shell fallback. Any single layer failing still returns a valid skipped result. - **SDK handler delegates to `gsd-tools.cjs`** rather than re-porting the detector to TypeScript, keeping drift logic in one canonical place. Closes #2003 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(mapper): tag --paths fenced block as text (CodeRabbit MD040) Comment 3127255172. * docs(config): use /gsd- dash command syntax in drift_action row (CodeRabbit) Comment 3127255180. Matches the convention used by every other command reference in docs/CONFIGURATION.md. * fix(execute-phase): initialize AGENT_SKILLS_MAPPER + tag fenced blocks Two CodeRabbit findings on the auto-remap branch of the drift gate: - 3127255186 (must-fix): the mapper Task prompt referenced ${AGENT_SKILLS_MAPPER} but only AGENT_SKILLS (for gsd-executor) is loaded at init_context (line 72). Without this fix the literal placeholder string would leak into the spawned mapper's prompt. Add an explicit gsd-sdk query agent-skills gsd-codebase-mapper step right before the Task spawn. - 3127255183: tag the warn-message and Task() fenced code blocks as text to satisfy markdownlint MD040. * docs(map-codebase): wire PATH_SCOPE_HINT through every mapper prompt CodeRabbit (review id 4158286952, comment 3127255190) flagged that the parse_paths_flag step defined incremental-remap semantics but did not inject a normalized variable into the spawn_agents and sequential_mapping mapper prompts, so incremental remap could silently regress to a whole-repo scan. - Define SCOPED_PATHS / PATH_SCOPE_HINT in parse_paths_flag. - Inject ${PATH_SCOPE_HINT} into all four spawn_agents Task prompts. - Document the same scope contract for sequential_mapping mode. * fix(drift): writeMappedCommit tolerates missing target file CodeRabbit (review id 4158286952, drift.cjs:349-355 nitpick) noted that readMappedCommit returns null on ENOENT but writeMappedCommit threw — an asymmetry that breaks first-time stamping of a freshly produced doc that the caller has not yet written. - Catch ENOENT on the read; treat absent file as empty content. - Add a regression test that calls writeMappedCommit on a non-existent path and asserts the file is created with correct frontmatter. Test was authored to fail before the fix (ENOENT) and passes after. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
6b7b5c15a5 |
fix(#2559): remove stale year injection from research agent web search instructions (#2591)
The gsd-phase-researcher and gsd-project-researcher agents instructed WebSearch queries to always include 'current year' (e.g., 2024). As time passes, a hardcoded year biases search results toward stale dated content — users saw 2024-tagged queries producing stale blog references in 2026. Remove the year-injection guidance. Instead, rely on checking publication dates on the returned sources. Query templates and success criteria updated accordingly. Closes #2559 |
||
|
|
b2534e8a05 |
feat(plan-phase): chunked mode + filesystem fallback for Windows stdio hang (#2499)
* feat(plan-phase): chunked mode + filesystem fallback for Windows stdio hang (#2310) Addresses the 2026-04-16 Windows incident where gsd-planner wrote all 5 PLAN.md files to disk but Task() never returned, hanging the orchestrator for 30+ minutes. Two mitigations: 1. Filesystem fallback (steps 9a, 11a): when Task() returns with an empty/truncated response but PLAN.md files exist on disk, surface a recoverable prompt (Accept plans / Retry planner / Stop) instead of silently failing. Directly addresses the post-restart recovery path. 2. Chunked mode (--chunked flag / workflow.plan_chunked config): splits the single long-lived planner Task into a short outline Task (~2 min) followed by N short per-plan Tasks (~3-5 min each). Each plan is committed individually for crash resilience. A hang loses one plan, not all of them. Resume detection skips plans already on disk on re-run. RCA confirmed: task state mtime 14:29 vs PLAN.md writes 14:32-14:52 = subagent completed normally, IPC return was dropped by Windows stdio deadlock. Neither mitigation fixes the root cause (requires upstream Task() timeout support); both bound damage and enable recovery. New reference file planner-chunked.md keeps OUTLINE COMPLETE / PLAN COMPLETE return formats out of gsd-planner.md (which sits at 46K near its size limit). Closes #2310 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(plan-phase): address CodeRabbit review comments on #2499 - docs/CONFIGURATION.md: add workflow.plan_chunked to full JSON schema example - plan-phase.md step 8.5.1: validate PLAN-OUTLINE.md with grep for OUTLINE COMPLETE marker before reusing (not just file existence) - plan-phase.md step 8.5.2: validate per-plan PLAN.md has YAML frontmatter (head -1 grep for ---) before skipping in resume path - plan-phase.md: add language tags (text/javascript/bash) to bare fenced code blocks in steps 8.5, 9a, 11a (markdownlint MD040) - Rejected: commit_docs gate on per-plan commits (gsd-sdk query commit already respects commit_docs internally — comment was a false positive) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(plan-phase): route Accept-plans through step 9 PLANNING COMPLETE handling Honors --skip-verify / plan_checker_enabled=false in 9a fallback path. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
f19d0327b2 |
feat(agents): sycophancy hardening for 9 audit-class agents (#2489)
* fix(tests): update 5 source-text tests to read config-schema.cjs VALID_CONFIG_KEYS moved from config.cjs to config-schema.cjs in the drift-prevention companion PR. Tests that read config.cjs source text and checked for key literal includes() now point to the correct file. Closes #2480 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(agents): sycophancy hardening for 9 audit-class agents (#2427) Add adversarial reviewer posture to gsd-plan-checker, gsd-code-reviewer, gsd-security-auditor, gsd-verifier, gsd-eval-auditor, gsd-nyquist-auditor, gsd-ui-auditor, gsd-integration-checker, and gsd-doc-verifier. Four changes per agent: - Third-person framing: <role> opens with submission framing, not "You are a GSD X" - FORCE stance: explicit starting hypothesis that the submission is flawed - Failure modes: agent-specific list of how each reviewer type goes soft - BLOCKER/WARNING classification: every finding must carry an explicit severity Also applies to sdk/prompts/agents variants of gsd-plan-checker and gsd-verifier. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
c5b1445529 |
feat(sdk): golden parity harness and query handler CJS alignment (#2302 Track A) (#2341)
* feat(sdk): golden parity harness and query handler CJS alignment (#2302 Track A) Golden/read-only parity tests and registry alignment, query handler fixes (check-completion, state-mutation, commit, validate, summary, etc.), and WAITING.json dual-write for .gsd/.planning readers. Refs gsd-build/get-shit-done#2341 * fix(sdk): getMilestoneInfo matches GSD ROADMAP (🟡, last bold, STATE fallback) - Recognize in-flight 🟡 milestone bullets like 🚧. - Derive from last **vX.Y Title** before ## Phases when emoji absent. - Fall back to STATE.md milestone when ROADMAP is missing; use last bare vX.Y in cleaned text instead of first (avoids v1.0 from shipped list). - Fixes init.execute-phase milestone_version and buildStateFrontmatter after state.begin-phase (syncStateFrontmatter). * feat(sdk): phase list, plan task structure, requirements extract handlers - Register phase.list-plans, phase.list-artifacts, plan.task-structure, requirements.extract-from-plans (SDK-only; golden-policy exceptions). - Add unit tests; document in QUERY-HANDLERS.md. - writeProfile: honor --output, render dimensions, return profile_path and dimensions_scored. * feat(sdk): centralize getGsdAgentsDir in query helpers Extract agent directory resolution to helpers (GSD_AGENTS_DIR, primary ~/.claude/agents, legacy path). Use from init and docs-init init bundles. docs(15): add 15-CONTEXT for autonomous phase-15 run. * feat(sdk): query CLI CJS fallback and session correlation - createRegistry(eventStream, sessionId) threads correlation into mutation events - gsd-sdk query falls back to gsd-tools.cjs when no native handler matches (disable with GSD_QUERY_FALLBACK=off); stderr bridge warnings - Export createRegistry from @gsd-build/sdk; add sdk/README.md - Update QUERY-HANDLERS.md and registry module docs for fallback + sessionId - Agents: prefer node dist/cli.js query over cat/grep for STATE and plans * fix(sdk): init phase_found parity, docs-init agents path, state field extract - Normalize findPhase not-found to null before roadmap fallback (matches findPhaseInternal) - docs-init: use detectRuntime + resolveAgentsDir for checkAgentsInstalled - state.cjs stateExtractField: horizontal whitespace only after colon (YAML progress guard) - Tests: commit_docs default true; config-get golden uses temp config; golden integration green Refs: #2302 * refactor(sdk): share SessionJsonlRecord in profile-extract-messages CodeRabbit nit: dedupe JSONL record shape for isGenuineUserMessage and streamExtractMessages. * fix(sdk): address CodeRabbit major threads (paths, gates, audit, verify) - Resolve @file: and CLI JSON indirection relative to projectDir; guard empty normalized query command - plan.task-structure + intel extract/patch-meta: resolvePathUnderProject containment - check.config-gates: safe string booleans; plan_checker alias precedence over plan_check default - state.validate/sync: phaseTokenMatches + comparePhaseNum ordering - verify.schema-drift: token match phase dirs; files_modified from parsed frontmatter - audit-open: has_scan_errors, unreadable rows, human report when scans fail - requirements PLANNED key PLAN for root PLAN.md; gsd-tools timeout note - ingest-docs: repo-root path containment; classifier output slug-hash Golden parity test strips has_scan_errors until CJS adds field. * fix: Resolve CodeRabbit security and quality findings - Secure intel.ts and cli.ts against path traversal - Catch and validate git add status in commit.ts - Expand roadmap milestone marker extraction - Fix parsing array-of-objects in frontmatter YAML - Fix unhandled config evaluations - Improve coverage test parity mapping * test: raise planner character extraction limit to 48K * fix(sdk): resolve TS build error in docs-init passing config |
||
|
|
dfa1ecce99 |
fix(#2418,#2399,#2419,#2421): four workflow and installer bug fixes (#2462)
- #2418: convertClaudeToAntigravityContent now replaces bare ~/.claude and $HOME/.claude (no trailing slash) for both global and local installs, eliminating the "unreplaced .claude path reference" warnings in gsd-debugger.md and update.md during Antigravity installs. - #2399: plan-phase workflow gains step 13c that commits PLAN.md files and STATE.md via gsd-sdk query commit when commit_docs is true. Previously commit_docs:true was read but never acted on in plan-phase. - #2419: new-project.md and new-milestone.md now parse agents_installed and missing_agents from the init JSON and warn users clearly when GSD agents are not installed, rather than silently failing with "agent type not found" when trying to spawn gsd-project-researcher subagents. - #2421: gsd-planner.md gains a "Grep gate hygiene" rule immediately after the Nyquist Rule explaining the self-invalidating grep gate anti-pattern and providing comment-stripping alternatives (grep -v, ast-grep). Tests: 4 new test files (30 tests) all passing. Closes #2418 Closes #2399 Closes #2419 Closes #2421 Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |