Commit Graph

2702 Commits

Author SHA1 Message Date
Tom Boucher
eae1dc6f6b docs: keep inventory module rows sorted 2026-05-15 09:49:19 -04:00
Tom Boucher
fc4d005339 fix: satisfy inventory and changeset CI gates 2026-05-15 09:44:45 -04:00
Tom Boucher
6d65a1f52f chore: add changeset for workstream inventory builder 2026-05-15 09:36:47 -04:00
Tom Boucher
6a26e0c78b fix: remove unused path import in inventory builder 2026-05-15 09:35:02 -04:00
Tom Boucher
ed8f4c9a31 feat(3544): Workstream Inventory Builder/Reader split (Phase 3 of #3524)
Phase 3 of the CJS↔SDK hard-seam migration (parent #3524).
Introduces the Builder/Reader pattern for paired Modules with
mixed pure-and-I/O concerns — the template for Phase 4 and
follow-up enhancements that migrate other paired Modules.

Phase 1 and Phase 2 migrated Modules where both sides used
character-equivalent logic. Phase 3 introduces the case where
the pure logic is shareable but the I/O is legitimately per-side.
The Builder/Reader split resolves this:

- The Builder is pure — accepts pre-collected data
  (BuilderInputs struct), returns the typed projection. One
  source of truth; one generator-emitted CJS mirror. Drift
  is structurally impossible.
- The Readers are per-side hand-authored Adapters that do the
  fs reads in their native idiom (currently both sync; either
  side can go async later without touching the Builder), then
  delegate to the Builder.

- sdk/src/workstream-inventory/builder.ts — Builder source.
  170 lines. Pure. Exports buildWorkstreamInventory(inputs),
  isCompletedInventory(status), plus the three typed inventory
  interfaces (WorkstreamPhaseInventory, WorkstreamInventory,
  WorkstreamInventoryList).
- sdk/src/workstream-inventory/builder.test.ts — 18 vitest
  pinning fixtures across all status branches, progress-percent
  clamping, active-marker projection, and isCompletedInventory
  classifier.
- sdk/scripts/gen-workstream-inventory-builder.mjs — generator.
  Captures function bodies via Function.prototype.toString();
  emits with the standard GENERATED FILE banner. Includes a
  small `const relative = path.relative;` preamble in the
  output to handle ESM destructured imports in the compiled
  source.
- sdk/scripts/check-workstream-inventory-builder-fresh.mjs —
  freshness check. Imports the generator function directly
  (rather than duplicating logic) — a cleaner pattern than
  Phase 1/2's approach.
- get-shit-done/bin/lib/workstream-inventory-builder.generated.cjs —
  generator-emitted CJS mirror.
- tests/workstream-inventory-builder-generator.test.cjs — 16
  parity assertions confirming CJS-generated output ==
  SDK source output for every fixture.

- bin/lib/workstream-inventory.cjs: 159 → 132 lines.
  Projection logic gone. `inspectWorkstream` and
  `listWorkstreamInventories` collect BuilderInputs via the
  existing sync fs functions and delegate to the Builder.
  `isCompletedInventory` re-exported from the Builder (its
  signature changed from object→string, but no external
  callers exist so the change is safe).
- sdk/src/query/workstream-inventory.ts: 196 → 143 lines.
  Same shape, sync fs (the SDK was already sync — surprise from
  recon). Types re-exported from the Builder.

- sdk/package.json: gen:workstream-inventory-builder and
  check:workstream-inventory-builder-fresh scripts.
- package.json: proxy for the freshness check.
- .githooks/pre-commit: drift block.
- .github/workflows/test.yml: drift check step.
- CONTEXT.md: amended "Workstream Inventory Module" entry
  to document the Builder/Reader split.
- docs/INVENTORY.md, docs/INVENTORY-MANIFEST.json:
  +1 module count, +1 row for the generated builder.

- Full suite: 9229/9229 pass (baseline 9215 + 14 net new from
  the parity assertions).
- Vitest: 18 Builder fixtures pass.
- Reader shrink: -27 lines on CJS, -53 lines on SDK.
- Net diff (modified files only): +68 / -133 = 65-line
  reduction. New files (Builder, generator, freshness check,
  parity test) add ~600 lines of new structured code.

1. `isCompletedInventory` signature changed from
   isCompletedInventory(inventory: object) to
   isCompletedInventory(status: string). Original CJS exported
   the object form but no external caller passed an object —
   they all passed inventory.status. Verified by grep before
   committing.
2. Generator preamble. The compiled ESM uses
   `import { relative } from 'node:path'`, making `relative`
   a free variable in `buildWorkstreamInventory`. The generator
   emits `const relative = path.relative;` so the captured
   function body works in CJS.
3. Freshness check imports the generator. The freshness check
   imports the generator's buildWorkstreamInventoryBuilderCjs()
   function directly rather than duplicating generation logic.
   Cleaner than Phase 1/2; future generators should follow this.

Shareable via the Builder/Reader pattern in future enhancements:
- frontmatter (pure YAML/markdown parsing)
- plan-scan (pure PLAN.md structure parsing)
- decisions (pure decision-record parsing)
- secrets (regex-based detection in text)
- uat (UAT-criteria parsing)

Structural divergence — different approach needed:
- state — sync vs async file ops; mutation paths differ.
- workstream — lifecycle ops; per-side API surface differs.
- phase, roadmap, init, profile-output, template — large
  surfaces; each its own potential enhancement.

None of these is in scope for Phase 3.

Closes #3544.
2026-05-15 09:35:02 -04:00
Tom Boucher
fa862c77ee Merge pull request #3540 from gsd-build/feat/3536-configuration-module
feat(3536): Configuration Module via shared manifests + generator (Phase 2 of #3524)
2026-05-15 09:33:22 -04:00
Tom Boucher
173743fd9e fix: preserve canonical sub-repos normalization semantics 2026-05-15 09:25:49 -04:00
Tom Boucher
a31d45eedd Merge pull request #3547 from gsd-build/fix/3541-first-time-baseline-migration-prompt-use
fix(3541): resolve prompt-user migration actions in non-TTY runs; improve error grouping
2026-05-15 09:24:40 -04:00
Tom Boucher
ddd490a5e8 Merge pull request #3546 from gsd-build/fix/3542-worktree-stash-storage-is-shared-across-
fix(3542): prohibit git stash family in executor agents — shared stash storage violates worktree isolation
2026-05-15 09:19:12 -04:00
Tom Boucher
12a9f4f038 fix: harden configuration dynamic patterns and writes 2026-05-15 09:18:15 -04:00
Tom Boucher
544037e132 fix: honor installer migration resolution env override 2026-05-15 09:16:41 -04:00
Tom Boucher
8768e21204 chore(3549): finish CONTEXT.md pure-predicate refactor + capture parallel-fix-dispatch lessons (#3550)
* chore(3549): finish CONTEXT.md pure-predicate refactor + capture parallel-fix-dispatch lessons

Closes #3549

Part 1 — finish the pending refactor from mixed prose+predicates into pure
machine-greppable predicate format (one-line CLASS.subkey=value facts;
chronological prose moves to the append-only session log at the bottom).

Part 2 — append five new predicates from today's #3541 + #3542 + #3545
parallel-fix-dispatch session:

  DEFECT.HOOK-OVER-ENFORCEMENT.read-tool-tracking
  DEFECT.GSD-TEST-CONCURRENT-OUTPUT-COLLISION.{symptom,root-cause,detect,fix-forward,upstream}
  DEFECT.SUBAGENT-LONG-RUNNING-BG-STALL.{symptom,detect,fix-forward,anchor}
  DEFECT.AGENT-RETIRED-SLASH-SYNTAX-DRIFT.{symptom,examples,detect,fix-forward,lesson}
  PROC.PARALLEL-FIX-DISPATCH.{pattern,rationale,observed}

Plus SESSION.2026-05-15.parallel-fix-dispatch pointer line.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(3549): reword DEFECT.HOOK-OVER-ENFORCEMENT.write-bypass to avoid prompt-injection-scan trigger

The literal "exec(" string matched the scanner's child-process call-expression
pattern. The predicate is meta-documentation about a hook substring match;
the literal example token isn't load-bearing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:55:14 -04:00
Tom Boucher
db76cc8dd5 chore(3541): backfill PR number in changeset
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:36:39 -04:00
Tom Boucher
4e7d0c2bbf fix(3541): use /gsd:update colon syntax in comment (retired /gsd-update form)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:33:41 -04:00
Tom Boucher
0d9a800e56 chore(3542): backfill PR number in changeset
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:31:19 -04:00
Tom Boucher
24a992a05c chore(3536): add changeset fragment for user-facing surfaces
PR #3540 was originally labeled `no-changelog` on the premise that it
was a pure internal-module refactor. On second look, two surfaces are
actually user-facing and warrant a changelog entry:

  1. New `gsd-tools migrate-config` CLI subcommand — explicit, opt-in
     on-disk migration of legacy-key shapes. Idempotent.
  2. `mergeDefaults` semantic change — recursive deep-merge instead of
     spread-per-section. Preserves sibling keys under partial overlays.
     Strict improvement, but a behavior change.

Adds `.changeset/patient-lemurs-sing.md` (`type: Changed`). The
`no-changelog` label should be removed in tandem with this commit.
2026-05-15 08:25:06 -04:00
Tom Boucher
c39a7e1f6f fix(3541): resolve prompt-user migration actions in non-TTY runs; improve error grouping
Closes #3541

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 08:16:28 -04:00
Tom Boucher
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>
2026-05-15 08:16:26 -04:00
Tom Boucher
4b2de40f90 fix(3536): silence source-grep lint on config-schema parity test
The SDK side of the parity test asserts the source shape of
sdk/src/query/config-schema.ts (must re-export from
../configuration/index.js; must NOT contain inline `new Set([...])`
literals). Runtime/IR comparison cannot distinguish a re-export from
a redeclared Set with identical contents — only source inspection
catches drift back to inline literals.

Adds the documented `// allow-test-rule:` annotation explaining why
the three `src.includes()` calls are structurally necessary. Test
behavior unchanged; all 6 tests still pass; lint-no-source-grep now
reports 0 violations across 514 test files.
2026-05-15 08:14:28 -04:00
Tom Boucher
2de2d185fa feat(3536): Configuration Module via shared manifests + generator (Phase 2 of #3524)
Phase 2 of the CJS↔SDK hard-seam migration (parent #3524).
Eliminates the structural drift surface that produced bug class

After this phase, neither bin/lib/ nor sdk/src/ defines
CONFIG_DEFAULTS, VALID_CONFIG_KEYS, DYNAMIC_KEY_PATTERNS, or the
four legacy-key normalizations inline. All come from one canonical
source: the Configuration Module (sdk/src/configuration/index.ts)
+ two JSON manifests (sdk/shared/config-{defaults,schema}.manifest.json).
The CJS mirror is generator-emitted (get-shit-done/bin/lib/configuration.generated.cjs)
with a CI freshness check (sdk/scripts/check-configuration-fresh.mjs).

- sdk/shared/config-defaults.manifest.json — canonical nested defaults,
  union of CJS + SDK keys (includes security_*, post_planning_gaps,
  agent_skills, mode, every git/workflow/hooks sub-section).
- sdk/shared/config-schema.manifest.json — VALID_CONFIG_KEYS array,
  RUNTIME_STATE_KEYS array, DYNAMIC_KEY_PATTERNS array with source
  strings (regex reconstructed at runtime).
- sdk/src/configuration/index.ts — source of truth. Exports
  loadConfig (pure read), normalizeLegacyKeys (pure, idempotent,
  returns Normalization[]), mergeDefaults (deep-merge), migrateOnDisk
  (explicit opt-in disk writeback), plus CONFIG_DEFAULTS,
  VALID_CONFIG_KEYS, RUNTIME_STATE_KEYS, DYNAMIC_KEY_PATTERNS.
- sdk/src/configuration/index.test.ts — 29 vitest pinning tests.
- sdk/scripts/gen-configuration.mjs — generator (Function.prototype.toString()
  inspection of compiled SDK dist, plus brace-balanced text scan for
  internal helpers, matching the Phase 1 pattern).
- sdk/scripts/check-configuration-fresh.mjs — CI freshness gate.
- tests/configuration-generator.test.cjs — 27 parity assertions
  (CJS-generated == SDK source).
- tests/configuration-migrate-config.test.cjs — 3 cases for the new
  gsd-tools migrate-config subcommand.

- bin/lib/core.cjs: CONFIG_DEFAULTS literal now sources values from
  CANONICAL_CONFIG_DEFAULTS (the manifest), with a thin flat
  projection at the load boundary to preserve the existing
  flat-shape return contract for the ~21 CJS test files and 100+
  consumers. All four legacy-key migration blocks (branching_strategy,
  sub_repos, multiRepo, depth — historically lines 351-358, 388-397,
  401-408, 416-423) collapse to a single normalizeLegacyKeys call
  in each code path. The inline platformWriteSync writeback stays
  for now to preserve sync loadConfig semantics; the new async
  migrateOnDisk is reachable via gsd-tools migrate-config.
- bin/lib/config-schema.cjs: 135 → 31 lines. Re-exports from the
  generated Module.
- bin/lib/config.cjs: adds cmdMigrateConfig handler (calls
  migrateOnDisk on the explicit user-driven path).
- bin/gsd-tools.cjs: wires migrate-config into command dispatch.

- sdk/src/config.ts: re-exports CONFIG_DEFAULTS and mergeDefaults
  from the Module. loadConfig now calls normalizeLegacyKeys before
  mergeDefaults (replaces the inline branching_strategy graft).
- sdk/src/query/config-schema.ts: 160 → 36 lines. Re-exports from
  the Module.

- tests/config-schema-sdk-parity.test.cjs: refactored from
  "CJS Set equals SDK Set" (trivially true post-migration) to
  "both sides source from the manifest" — structural plus runtime
  invariant.
- Four other tests that text-grepped source files for valid keys
  (plan-review-convergence, bug-3212, bug-2492, feat-3210) are
  updated to use runtime VALID_CONFIG_KEYS.has() or manifest JSON
  lookups.

- CONTEXT.md: new Configuration Module entry with full Interface
  contract.
- Root package.json: check:configuration-fresh proxy script.
- sdk/package.json: gen:configuration + check:configuration-fresh.
- .githooks/pre-commit: configuration drift block.
- .github/workflows/test.yml: configuration drift step after the
  alias drift check.

- 9201 CJS tests pass (baseline pre-cycle: 9195; +6 net new tests
  across migrate-config + parity refactor)
- 1872 SDK vitest tests pass
- 29 Configuration Module vitest fixtures
- 27 CJS/SDK parity fixtures
- Net diff: +388 / −519 = 131-line reduction across the seven cycles,
  despite adding the new Module, manifests, generator, freshness
  check, and two new test files.

1. SDK CONFIG_DEFAULTS now includes manifest-canonical keys
   (resolve_model_ids: false, context_window: 200000, phase_naming,
   claude_md_path, git.create_tag, workflow.security_*,
   workflow.code_review_*, planning.*, hooks.workflow_guard, ship.*).
   Consumers accessing via [key: string]: unknown index get
   the manifest default instead of undefined.
2. SDK mergeDefaults is now proper recursive deep-merge instead of
   spread-per-section. Overlay { workflow: { research: false } }
   now preserves sibling workflow keys; previously it replaced
   the entire workflow section with only research + the section's
   defaults. Semantically identical for the common case;
   strictly better for partial nested overrides.
3. New gsd-tools migrate-config CLI subcommand for the explicit,
   opt-in on-disk migration path.

Closes #3536.
2026-05-15 00:02:56 -04:00
Tom Boucher
a7f0af2ce9 fix(3537): route every phase-number ROADMAP regex through phaseMarkdownRegexSource (#3538)
* fix(3537): route every phase-number ROADMAP regex through phaseMarkdownRegexSource

v1.42.1 added the padding-tolerant `phaseMarkdownRegexSource()` helper but
wired it into only 1 of 8 call sites that build phase-number regexes against
ROADMAP/STATE prose. The other 7 used raw `escapeRegex(phaseNum)` or partial
`0*${escapeRegex(...)}` (tolerated extra padding, not missing), so when
skills passed the resolved padded form (`02.7`) against un-padded ROADMAP
prose (`### Phase 2.7:`, `- [ ] **Phase 2.7:**`), the verbs silently no-op'd
while reporting success.

This consolidates every phase-number ROADMAP/STATE regex through the
canonical helper:

- Promote `phaseMarkdownRegexSource` from `roadmap.cjs` to `core.cjs` so
  `phase.cjs` and `core.cjs` itself can consume it (no circular dep —
  both already import `core.cjs`).
- Wire the helper into the 7 remaining sites:
  - `core.cjs:getRoadmapPhaseInternal` (replaces hand-rolled `isNumeric`
    branch that only padded integers, not decimals).
  - `roadmap.cjs:cmdRoadmapGetPhase` (searchPhaseInContent escapedPhase).
  - `roadmap.cjs:cmdRoadmapAnalyze` checkbox lookup.
  - `roadmap.cjs:cmdRoadmapAnnotateDependencies` phase header lookup.
  - `phase.cjs:cmdPhaseNextDecimal` ROADMAP prose scan.
  - `phase.cjs:cmdPhaseInsert` target anchor + decimal scan + header.
  - `phase.cjs:cmdPhaseComplete` (3 regexes: checkbox, plan-count,
    REQUIREMENTS extraction).

Adds `tests/bug-3537-padded-id-against-unpadded-roadmap.test.cjs` — a
parity-style regression matching CONTEXT.md DEFECT.GENERATIVE-FIX: for
each user-facing verb, asserts that the padded form (`02.7`) and the
un-padded form (`2.7`) produce identical ROADMAP.md against an identical
fixture. Includes one control case (`update-plan-progress`, already wired
in 1.42.1) to prove the parity assertion is non-vacuous.

Closes #3537

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(3537): add changeset fragment (pr: placeholder, amended post-create)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(3537): pin changeset pr: field to #3538

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 23:17:38 -04:00
Tom Boucher
bfd7ddbad3 feat(3530): STATE.md Document Module via generator (Phase 1 of #3524) (#3531)
* feat(3530): STATE.md Document Module via generator (Phase 1 of #3524)

Phase 1 of the CJS↔SDK hard-seam migration (parent #3524).
Converts the hand-synced state-document.cjs/state-document.ts pair
into a generator-driven seam, modeled on the existing
command-aliases.generated.* precedent.

What landed:
- sdk/src/query/state-document.ts is the source of truth.
- sdk/scripts/gen-state-document.ts emits
  get-shit-done/bin/lib/state-document.generated.cjs from the
  compiled SDK dist via Function.prototype.toString() inspection
  for the 7 public exports and 3 internal helpers.
- sdk/scripts/check-state-document-fresh.mjs is the CI freshness
  gate; pre-commit hook also runs it when relevant files change.
- get-shit-done/bin/lib/state-document.cjs is reduced to a one-line
  re-export from state-document.generated.cjs so existing callers
  (state.cjs, workstream-inventory.cjs, init.cjs) need no changes.
- New CI step in .github/workflows/test.yml after the existing alias
  drift check.
- sdk/package.json: gen:state-document, check:state-document-fresh
  scripts. tsx added as devDep.
- Root package.json: proxy script for the freshness check.
- CONTEXT.md: one-sentence amendment on STATE.md Document Module
  recording the source-of-truth file path.

Tests:
- sdk/src/query/state-document.test.ts: 34 vitest fixtures across
  the 7 public exports (TDD pinning safety net).
- tests/state-document-generator.test.cjs: 31 node:test parity
  assertions comparing SDK source vs generated CJS for every
  fixture.
- Full suite: 9177/9177 pass (baseline was 9146; +31 new tests).

One subtle behavior change worth flagging: the old hand-written
state-document.cjs used String(str) coercion inside escapeRegex,
which the SDK source does not. The generator faithfully matches
the SDK (the source of truth per ADR-3524), so the new CJS no
longer coerces non-string input to string before regex-escaping.
No current caller passes non-string input, so no observable
regression in the test suite. Flagged in the PR body for
reviewers.

Closes #3530.

* fix(3530): address state-document review findings
2026-05-14 22:17:20 -04:00
Tom Boucher
e437ded6fc docs(3524): CJS↔SDK hard-seam ADR + phased PRD (#3529)
* docs(3524): propose CJS↔SDK hard-seam ADR + phased PRD

Adds docs/adr/3524-cjs-sdk-hard-seam.md (Proposed) and
docs/prd/3524-cjs-sdk-hard-seam.md (Reference) tracking #3524.
Updates the ADR and PRD index READMEs.

The ADR defines one canonical owner per responsibility across the
CJS (bin/lib/*.cjs) and SDK (sdk/src/**/*.ts) sides, eliminating the
recurring drift bug class (#1535, #1542, #2047, #2638, #2653, #2687,
#2798, #3055, #3523). Three layers: shared data (sdk/shared/*.json),
shared core logic (sdk/src/core/ → dual CJS+ESM build), thin adapters.
Enforcement is layered: build-time grep, type-level contract test,
mutation parity test, CODEOWNERS gate, in-file banner.

The PRD phases the migration in five independently shippable steps —
shared data first (closes constant drift), then config consolidation
(closes #3523 class), then project-root + path projection, then state
and verify handlers, then enforcement hardening + retrospective.

* docs(3524): revise seam ADR + PRD after architecture review

Architecture-review pass (via /improve-codebase-architecture) found
seven deepening opportunities; this commit applies all of them.

1. Re-anchor on the existing generator precedent. The repo already
   has sdk/scripts/gen-command-aliases.ts emitting both
   .generated.ts and .generated.cjs from one TS source, with
   sdk/scripts/check-command-aliases-fresh.mjs as the CI freshness
   gate. The ADR's invented dual CJS+ESM bundler pipeline is
   dropped. Each Shared Module gets one generator script and one
   freshness check, modeled on that precedent.

2. Drop the generic sdk/src/core/ container. The canonical-owner
   table is now indexed by Module, using the CONTEXT.md domain
   vocabulary (STATE.md Document Module, Configuration Module,
   etc.) rather than file-path-based pseudo-modules.

3. Split the coarse "State management" row into three: the pure
   STATE.md Document Module (already a character-identical
   hand-synced pair — perfect Phase 1 target), the Planning
   Workspace Module (defer to ADR-0004), and per-side state I/O
   Adapters (legitimately differ sync vs async).

4. Defer to existing ADRs. Planning Path Projection (ADR-0006),
   Model Catalog (ADR-0003), Planning Workspace (ADR-0004),
   Dispatch Policy (ADR-0001), Shell Command Projection (ADR-0009
   post-Phase 3-4 expansion which absorbed superseded ADR-0010).
   The stale ADR-0010 reference is fixed.

5. Define a Configuration Module entry in CONTEXT.md as a Phase 2
   deliverable, with explicit Interface contract for loadConfig,
   normalizeLegacyKeys, mergeDefaults, migrateOnDisk.

6. Split the Workstream Inventory Module into a pure Builder
   (generated, shared) and per-side Reader Adapters (hand-authored,
   sync vs async). Same pattern generalizes to other paired Modules.

7. Match enforcement to existing scripts. Per-Module freshness
   checks (precedent: check-command-aliases-fresh.mjs), per-Module
   drift lints (precedent: lint-shell-command-projection-drift.cjs),
   and one hand-sync pair lint that blocks the #3523 anti-pattern
   at PR time.

PRD phases reordered: STATE.md Document Module ships first as a
proof of pattern (two identical files become one source plus one
generated artifact). Configuration Module ships second, closing
the #3523 class. Workstream Inventory Builder split third.
Project-Root Resolution fourth. Enforcement and retrospective
fifth.

* docs(3524): expand scope — CJS router delegates to SDK runtime bridge

User flagged that the original "Out of scope" list was my unilateral
scoping call, not theirs. After review, the CJS router consolidation
(formerly out-of-scope item #1) is brought into scope.

ADR additions:
- CJS Command Router Adapter Module row added to canonical-owner
  table. Existing Module (per CONTEXT.md) is amended so the
  per-family `handlers` map delegates to `QueryRuntimeBridge.execute()`
  in-process. Per-side CJS handler files for canonical families
  (state.cjs, verify.cjs, init.cjs, phase.cjs, etc.) shrink to
  delegates or are deleted.
- Per-side I/O Adapter consequence updated to clarify the bridge
  preserves the in-process model. No subprocess hop is added.
- "Out of scope" stripped of router item; CJS-only seam migration
  and verify-Module-first work remain out of scope.

PRD additions:
- New Phase 5: CJS Command Router Adapter delegates to SDK runtime
  bridge, family-by-family, with golden parity matrix per family
  gating each PR.
- Old Phase 5 (enforcement) renumbered to Phase 6, expanded to cover
  Phase 5's parity matrix and runtime-bridge CODEOWNERS.
- Open question #4 added for the synchronous-bridging mechanism
  (`deasync` vs `Atomics.wait` vs sync-handler refactor) — resolved
  in the Phase 5 spike before any family migration begins.
- Open question #5 added for family migration order (recommended:
  smallest read-only family first).
- Risks table expanded with three Phase 5 rows: bridging-mechanism
  uncertainty, observable-output regression, startup-time impact.
- Done-when updated for six phases and five enforcement layers.

Non-goals updated: CJS-only Module migration and verify-Module
deepening remain out of scope. CJS CLI removal explicitly stays
off the table — the external `gsd-tools` contract is preserved.

* docs(3524): address CodeRabbit review

* docs(3524): fix PRD issue reference markdown
2026-05-14 22:08:33 -04:00
Tom Boucher
55c72f47ff Docs: align v1.42.1 release notes format
Closes #3534

Docs-only follow-up to align v1.42.1 release notes with prior stable release format.
2026-05-14 20:49:01 -04:00
Tom Boucher
cbe8326d71 Merge pull request #3533 from gsd-build/docs/v1.42.1-release-update
Docs: update v1.42.1 release documentation
2026-05-14 20:44:26 -04:00
Tom Boucher
5c202372ed docs: update v1.42.1 release documentation 2026-05-14 20:42:35 -04:00
Tom Boucher
d4d4178603 Merge pull request #3483 from radioflyer28/feat/agent-launch-reasoning-transport-3474
feat: transport resolved reasoning effort to agent launches
2026-05-14 20:01:32 -04:00
Tom Boucher
9ccd97a9e0 Merge pull request #3528 from gsd-build/fix/3522-gsd-sdk-query-commit-files-silently-over
feat(sdk): add --respect-staged opt-in to commit --files
2026-05-14 19:58:36 -04:00
Tom Boucher
e6790238aa Merge pull request #3527 from gsd-build/fix/3523-bug-cjs-loadconfig-warns-top-level-branc
fix(3523): stop false 'branching_strategy will be ignored' warning in CJS loadConfig
2026-05-14 19:58:08 -04:00
Tom Boucher
cda6cd3e06 Merge pull request #3526 from gsd-build/fix/3521-workflows-quick-md-two-bugs-in-post-merg
fix(quick): pin cleanup-loop CWD to project root before bare git commands (#3521)
2026-05-14 19:57:45 -04:00
Tom Boucher
f737fd37a6 Merge pull request #3525 from gsd-build/fix/3516-reapply-patches-md-filter-on-line-231-mi
fix(reapply-patches): add gsd-update filter arm to git-enhanced two-way merge (#3516)
2026-05-14 19:57:15 -04:00
Tom Boucher
7c5adeaad1 test: allow runtime output assertions 2026-05-14 19:47:48 -04:00
Tom Boucher
585e417f9e fix: harden respect-staged pathspec handling 2026-05-14 19:44:04 -04:00
Tom Boucher
75dffc8069 fix: address branching strategy review findings 2026-05-14 19:44:01 -04:00
Tom Boucher
085154ace7 docs: clarify gsd-update reapply changeset 2026-05-14 19:43:59 -04:00
Tom Boucher
017abd9236 feat(sdk): add --respect-staged opt-in to gsd-sdk query commit --files (#3522)
Closes #3522. When --respect-staged is passed the git add loop is skipped
entirely so per-hunk staging from git add -p is preserved. Default behavior
(full re-stage) is unchanged. The #3061 pathspec invariant holds under both
modes. Nothing-staged within scope returns { committed: false, reason:
'nothing staged' } without error.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 19:08:08 -04:00
Tom Boucher
0f7b018d4d chore: changeset for fix/3523 (branching_strategy false warning)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 19:03:42 -04:00
Tom Boucher
3ab24c6c56 fix(3523): self-healing migration of legacy top-level branching_strategy
Three-part fix for the false "unknown config key(s)" warning fired for
top-level `branching_strategy` in .planning/config.json:

1. On-disk migration (option 3, mirroring multiRepo → planning.sub_repos):
   When loadConfig reads a config.json with top-level `branching_strategy`
   set and `git.branching_strategy` unset, it grafts the value into
   `git.branching_strategy` and deletes the top-level key, then persists.
   If `git.branching_strategy` is already set, the nested value wins
   (matches SDK mergeDefaults precedence, PR #3116).

2. KNOWN_TOP_LEVEL safety net: 'branching_strategy' added to the deprecated-
   keys bucket so the warning never fires even on the first read of a root
   config that feeds a workstream merge (where `parsed` may still carry it).

3. Double-emission guard: a module-level `_warnedUnknownConfigKeys` Set
   deduplicates the unknown-key warning across multiple loadConfig calls
   within a single CLI invocation (init phase-op N called it twice).

Closes #3523

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 19:03:39 -04:00
Tom Boucher
e4ed71bf79 test(3523): red — legacy top-level branching_strategy warning + migration + parity
Six failing tests covering all Done-when criteria from #3523:
  1. No warning emitted for top-level branching_strategy
  2. Value still surfaced via git.branching_strategy after loadConfig
  3. Double-emission capped to single-emission per process
  4-5. On-disk migration (option 3): write-back + no-clobber guard
  6. CJS↔SDK contract: both agree on legacy-shape fixture

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 19:03:31 -04:00
Tom Boucher
c974d9de74 chore: pin changeset pr field to #3526
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 19:02:53 -04:00
Tom Boucher
e1270c3547 fix(quick): pin cleanup-loop CWD to project root before bare git commands (#3521)
The post-merge worktree-cleanup loop in quick.md issued bare `git diff`,
`git merge`, and related commands relying on CWD = project root. An LLM
orchestrator that reformats bash across separate tool calls can leak CWD
into a worktree, causing the merge to silently no-op.

At the top of each iteration body, resolve PROJECT_ROOT via
`git -C "$WT" rev-parse --git-common-dir` and `cd "$PROJECT_ROOT"`.
If the root cannot be resolved or reached, log a skip message and
continue to the next manifest entry. All existing guards (pre-merge
deletion guard #1756, STATE.md/ROADMAP.md backup/restore, resurrection
guard #2501/#3195) remain intact after the CWD pin.

Closes #3521 (bug 1 — CWD safety only; bug 2 / resurrection guard was
already fixed in a6beac40 / PR #3201 and is pending reporter retest).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 19:02:16 -04:00
Tom Boucher
9fb549e499 test(3521): add regression test for quick.md cleanup-loop CWD safety
Simulates orchestrator-leaked CWD in the post-merge cleanup loop and
asserts that PROJECT_ROOT is resolved via `git -C "$WT" rev-parse
--git-common-dir` before any bare git command, that a missing root
causes a logged skip/continue, and that the existing pre-merge deletion
guard (#1756) and STATE.md/ROADMAP.md backup/restore remain in-place
after the CWD pin.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 19:02:06 -04:00
Tom Boucher
04c1296aed chore: add changeset fragment for #3516 filter fix 2026-05-14 19:00:41 -04:00
Tom Boucher
8cbb0cbc45 fix(reapply-patches): add gsd-update arm to git-enhanced two-way merge filter (#3516)
The grep -v alternation in the git-enhanced two-way merge step was missing
the 'gsd-update' arm after the slash-command rename from /gsd:update to
/gsd-update. Commits authored by the current update flow fell through the
filter and were misclassified as user customizations, causing spurious merge
prompts during /gsd-update --reapply.

Adds 'gsd-update' between 'gsd:update' and 'GSD update'. The legacy
'gsd:update' arm is preserved for back-compat; 'GSD update' and 'gsd-install'
exclusions are unchanged.
2026-05-14 19:00:38 -04:00
Tom Boucher
490b2706f2 test(3516): add failing regression for missing gsd-update filter arm
Adds bug-3516-reapply-patches-gsd-update-filter.test.cjs — 7 tests that
assert all four exclusion patterns (gsd:update, gsd-update, GSD update,
gsd-install) are present in the git-enhanced two-way merge filter inside
get-shit-done/workflows/reapply-patches.md.

Two tests fail before the fix: 'filter excludes renamed gsd-update commits'
and 'all four expected exclusion patterns are present in the filter'.
2026-05-14 19:00:32 -04:00
Tom Boucher
7212e61142 Merge pull request #3520 from gsd-build/fix/3517-phase-complete-leaves-state-md-body-fron
fix(sdk): derive STATE.md fields from ROADMAP and refresh all stale fields after phase.complete (#3517)
2026-05-14 18:35:38 -04:00
Tom Boucher
2bee9ffb88 test(3517): add allow-test-rule exemption — STATE.md is the runtime contract 2026-05-14 17:40:45 -04:00
Tom Boucher
16eee9606a chore: pin changeset pr field to #3520 2026-05-14 17:22:34 -04:00
Tom Boucher
200c012f84 fix(sdk): derive completed_phases from ROADMAP and refresh all STATE.md fields after phase.complete
Fixes two root causes behind bug #3517:

1. Idempotency: completed_phases was blindly incremented (parseInt + 1),
   causing phase.complete N run twice to double-count (4 → 5 → 6).
   Now derives from ROADMAP progress table Complete-row count, making
   the operation idempotent.

2. Field coverage: eight STATE.md fields were left stale after phase
   completion. Now updates in the same atomic lock section:
   - frontmatter: stopped_at, last_updated, total_plans, completed_plans
   - body: Current focus, Status line, By Phase table row

   completed_plans = count of *-SUMMARY.md files across all phase dirs
   total_plans = sum of M/N plan counts from ROADMAP progress table
   percent = recomputed from fresh derived counts

Closes #3517

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 16:56:18 -04:00
Tom Boucher
f45f2ec746 Merge pull request #3515 from gsd-build/feat/2937-enhancement-statusline-opt-in-context-po
feat(statusline): opt-in context_position config for narrow terminals
2026-05-14 16:41:38 -04:00