From ceed559fd437b037755249e6e36ee36d0d785852 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 30 Aug 2026 03:06:22 +0000 Subject: [PATCH] chore: promote CHANGELOG for v1.12.0 --- .changeset/agile-geese-squeak.md | 5 - .changeset/bold-bears-hum.md | 5 - .changeset/bold-jays-travel.md | 5 - .changeset/bold-lynx-cheer.md | 5 - .changeset/bold-moles-squeak.md | 5 - .changeset/bold-pandas-snooze.md | 5 - .changeset/brave-birds-travel.md | 5 - .changeset/brave-elks-climb.md | 5 - .changeset/brave-goats-march.md | 5 - .changeset/brave-jays-tumble.md | 5 - .changeset/brave-tunas-dart.md | 5 - .changeset/brave-wasps-leap.md | 5 - .changeset/calm-bears-travel.md | 5 - .changeset/calm-deer-hum.md | 5 - .changeset/calm-otters-refuse.md | 5 - .changeset/calm-pandas-greet.md | 5 - .changeset/calm-tunas-rally.md | 5 - .changeset/clever-eagles-jump.md | 5 - .changeset/clever-hawks-wave.md | 5 - .changeset/clever-jaguars-hum.md | 5 - .changeset/clever-jaguars-rally.md | 5 - .changeset/clever-pumas-march.md | 5 - .changeset/curious-birds-dance.md | 5 - .changeset/curious-cats-march.md | 5 - .changeset/curious-seals-wander.md | 5 - .changeset/curious-zebras-roam.md | 5 - .changeset/daring-deer-fly.md | 5 - .changeset/daring-jays-leap.md | 5 - .changeset/daring-newts-chatter.md | 5 - .changeset/daring-orcas-dart.md | 5 - .changeset/daring-tigers-squeak.md | 5 - .changeset/daring-voles-snooze.md | 5 - .changeset/eager-birds-sprint.md | 5 - .changeset/eager-cats-squeak.md | 5 - .changeset/eager-elks-snooze.md | 5 - .changeset/eager-ibex-hop.md | 5 - .changeset/eager-rams-jump.md | 5 - .changeset/eager-tigers-zip.md | 5 - .changeset/eager-tunas-parade.md | 5 - .changeset/eager-yaks-wander.md | 5 - .changeset/fierce-dogs-howl.md | 5 - .changeset/gallant-eagles-zip.md | 9 -- .changeset/gallant-jaguars-wander.md | 5 - .changeset/gallant-mice-snooze.md | 5 - .changeset/gallant-orcas-caper.md | 5 - .changeset/gallant-rams-gather.md | 5 - .changeset/gentle-otters-click.md | 5 - .changeset/graceful-bears-caper.md | 6 - .changeset/graceful-elks-wander.md | 5 - .changeset/graceful-foxes-dart.md | 5 - .changeset/graceful-jaguars-wave.md | 5 - .changeset/graceful-moles-travel.md | 5 - .changeset/graceful-pumas-roar.md | 5 - .changeset/graceful-rams-dance.md | 5 - .changeset/graceful-rams-roar.md | 5 - .changeset/happy-deer-roar.md | 5 - .changeset/happy-jaguars-climb.md | 5 - .changeset/humble-newts-parade.md | 5 - .changeset/jolly-badgers-cheer.md | 5 - .changeset/jolly-bears-sprint.md | 5 - .changeset/jolly-geese-roar.md | 5 - .changeset/jolly-newts-click.md | 5 - .changeset/jolly-quails-howl.md | 5 - .changeset/jolly-rams-march.md | 5 - .changeset/jolly-ravens-travel.md | 5 - .changeset/jolly-yaks-click.md | 5 - .changeset/kind-dogs-sing.md | 5 - .changeset/kind-eagles-rally.md | 5 - .changeset/kind-lynx-wake.md | 5 - .changeset/kind-orcas-sprint.md | 5 - .changeset/kind-quails-travel.md | 5 - .changeset/kind-ravens-dart.md | 5 - .changeset/lively-geese-run.md | 5 - .changeset/lively-mice-wave.md | 5 - .changeset/lively-sloths-wave.md | 5 - .changeset/lucky-cats-romp.md | 5 - .changeset/lucky-ibex-rally.md | 5 - .changeset/mellow-pandas-parade.md | 5 - .changeset/mellow-wasps-click.md | 5 - .changeset/merry-koalas-chatter.md | 5 - .changeset/merry-orcas-parade.md | 5 - .changeset/mindful-otters-guard.md | 5 - .changeset/nimble-cranes-rest.md | 5 - .changeset/nimble-lynx-caper.md | 5 - .changeset/nimble-quails-fly.md | 5 - .changeset/noble-foxes-gather.md | 5 - .changeset/noble-lemurs-sprint.md | 5 - .changeset/patient-cranes-parade.md | 5 - .changeset/patient-elks-glide.md | 5 - .changeset/patient-jaguars-frolic.md | 5 - .changeset/patient-koalas-roar.md | 5 - .changeset/patient-sloths-glide.md | 5 - .changeset/patient-zebras-climb.md | 5 - .changeset/plucky-birds-hum.md | 5 - .changeset/plucky-hawks-sing.md | 5 - .changeset/plucky-koalas-snooze.md | 5 - .changeset/plucky-moles-purr.md | 5 - .changeset/plucky-pandas-roam.md | 5 - .changeset/plucky-pandas-wave.md | 5 - .changeset/proud-sloths-cheer.md | 5 - .changeset/proud-sloths-frolic.md | 5 - .changeset/quick-bears-cheer.md | 5 - .changeset/quick-dogs-munch.md | 5 - .changeset/quick-foxes-click.md | 5 - .changeset/quick-mice-hop.md | 5 - .changeset/rapid-ibex-sprint.md | 5 - .changeset/rapid-lemurs-click.md | 5 - .changeset/rapid-quails-sing.md | 5 - .changeset/rapid-tunas-leap.md | 5 - .changeset/rapid-wasps-sing.md | 5 - .changeset/serene-bears-dance.md | 5 - .changeset/serene-goats-roam.md | 5 - .changeset/serene-goats-sprint.md | 5 - .changeset/serene-orcas-glide.md | 5 - .changeset/sharp-cranes-wander.md | 5 - .changeset/sharp-deer-forage.md | 5 - .changeset/sharp-foxes-tumble.md | 5 - .changeset/sharp-seals-run.md | 5 - .changeset/silly-finches-squeak.md | 5 - .changeset/silly-yaks-fly.md | 5 - .changeset/steady-foxes-rest.md | 5 - .changeset/steady-otters-roar.md | 5 - .changeset/steady-zebras-leap.md | 5 - .changeset/sturdy-deer-frolic.md | 5 - .changeset/sturdy-dogs-hop.md | 5 - .changeset/sturdy-eagles-leap.md | 5 - .changeset/sturdy-eagles-wave.md | 5 - .changeset/sturdy-jaguars-munch.md | 5 - .changeset/sturdy-otters-chatter.md | 5 - .changeset/sturdy-sloths-roar.md | 5 - .changeset/sunny-elks-dart.md | 5 - .changeset/sunny-foxes-click.md | 5 - .changeset/sunny-herons-hum.md | 5 - .changeset/sunny-seals-munch.md | 5 - .changeset/tidy-birds-march.md | 5 - .changeset/tidy-finches-dance.md | 5 - .changeset/tidy-finches-wave.md | 5 - .changeset/tidy-hawks-roar.md | 5 - .changeset/tidy-otters-squeak.md | 5 - .changeset/vivid-lynx-zip.md | 5 - .changeset/vivid-pumas-squeak.md | 5 - .changeset/wise-otters-greet.md | 5 - .changeset/wise-rams-travel.md | 5 - .changeset/witty-goats-purr.md | 5 - .changeset/witty-ibex-frolic.md | 5 - .changeset/witty-lynx-sing.md | 5 - .changeset/witty-tigers-romp.md | 5 - .changeset/zesty-ibex-chatter.md | 5 - .changeset/zesty-sloths-sprint.md | 5 - .changeset/zesty-yaks-hop.md | 5 - CHANGELOG.md | 171 +++++++++++++++++++++++++++ 151 files changed, 171 insertions(+), 755 deletions(-) delete mode 100644 .changeset/agile-geese-squeak.md delete mode 100644 .changeset/bold-bears-hum.md delete mode 100644 .changeset/bold-jays-travel.md delete mode 100644 .changeset/bold-lynx-cheer.md delete mode 100644 .changeset/bold-moles-squeak.md delete mode 100644 .changeset/bold-pandas-snooze.md delete mode 100644 .changeset/brave-birds-travel.md delete mode 100644 .changeset/brave-elks-climb.md delete mode 100644 .changeset/brave-goats-march.md delete mode 100644 .changeset/brave-jays-tumble.md delete mode 100644 .changeset/brave-tunas-dart.md delete mode 100644 .changeset/brave-wasps-leap.md delete mode 100644 .changeset/calm-bears-travel.md delete mode 100644 .changeset/calm-deer-hum.md delete mode 100644 .changeset/calm-otters-refuse.md delete mode 100644 .changeset/calm-pandas-greet.md delete mode 100644 .changeset/calm-tunas-rally.md delete mode 100644 .changeset/clever-eagles-jump.md delete mode 100644 .changeset/clever-hawks-wave.md delete mode 100644 .changeset/clever-jaguars-hum.md delete mode 100644 .changeset/clever-jaguars-rally.md delete mode 100644 .changeset/clever-pumas-march.md delete mode 100644 .changeset/curious-birds-dance.md delete mode 100644 .changeset/curious-cats-march.md delete mode 100644 .changeset/curious-seals-wander.md delete mode 100644 .changeset/curious-zebras-roam.md delete mode 100644 .changeset/daring-deer-fly.md delete mode 100644 .changeset/daring-jays-leap.md delete mode 100644 .changeset/daring-newts-chatter.md delete mode 100644 .changeset/daring-orcas-dart.md delete mode 100644 .changeset/daring-tigers-squeak.md delete mode 100644 .changeset/daring-voles-snooze.md delete mode 100644 .changeset/eager-birds-sprint.md delete mode 100644 .changeset/eager-cats-squeak.md delete mode 100644 .changeset/eager-elks-snooze.md delete mode 100644 .changeset/eager-ibex-hop.md delete mode 100644 .changeset/eager-rams-jump.md delete mode 100644 .changeset/eager-tigers-zip.md delete mode 100644 .changeset/eager-tunas-parade.md delete mode 100644 .changeset/eager-yaks-wander.md delete mode 100644 .changeset/fierce-dogs-howl.md delete mode 100644 .changeset/gallant-eagles-zip.md delete mode 100644 .changeset/gallant-jaguars-wander.md delete mode 100644 .changeset/gallant-mice-snooze.md delete mode 100644 .changeset/gallant-orcas-caper.md delete mode 100644 .changeset/gallant-rams-gather.md delete mode 100644 .changeset/gentle-otters-click.md delete mode 100644 .changeset/graceful-bears-caper.md delete mode 100644 .changeset/graceful-elks-wander.md delete mode 100644 .changeset/graceful-foxes-dart.md delete mode 100644 .changeset/graceful-jaguars-wave.md delete mode 100644 .changeset/graceful-moles-travel.md delete mode 100644 .changeset/graceful-pumas-roar.md delete mode 100644 .changeset/graceful-rams-dance.md delete mode 100644 .changeset/graceful-rams-roar.md delete mode 100644 .changeset/happy-deer-roar.md delete mode 100644 .changeset/happy-jaguars-climb.md delete mode 100644 .changeset/humble-newts-parade.md delete mode 100644 .changeset/jolly-badgers-cheer.md delete mode 100644 .changeset/jolly-bears-sprint.md delete mode 100644 .changeset/jolly-geese-roar.md delete mode 100644 .changeset/jolly-newts-click.md delete mode 100644 .changeset/jolly-quails-howl.md delete mode 100644 .changeset/jolly-rams-march.md delete mode 100644 .changeset/jolly-ravens-travel.md delete mode 100644 .changeset/jolly-yaks-click.md delete mode 100644 .changeset/kind-dogs-sing.md delete mode 100644 .changeset/kind-eagles-rally.md delete mode 100644 .changeset/kind-lynx-wake.md delete mode 100644 .changeset/kind-orcas-sprint.md delete mode 100644 .changeset/kind-quails-travel.md delete mode 100644 .changeset/kind-ravens-dart.md delete mode 100644 .changeset/lively-geese-run.md delete mode 100644 .changeset/lively-mice-wave.md delete mode 100644 .changeset/lively-sloths-wave.md delete mode 100644 .changeset/lucky-cats-romp.md delete mode 100644 .changeset/lucky-ibex-rally.md delete mode 100644 .changeset/mellow-pandas-parade.md delete mode 100644 .changeset/mellow-wasps-click.md delete mode 100644 .changeset/merry-koalas-chatter.md delete mode 100644 .changeset/merry-orcas-parade.md delete mode 100644 .changeset/mindful-otters-guard.md delete mode 100644 .changeset/nimble-cranes-rest.md delete mode 100644 .changeset/nimble-lynx-caper.md delete mode 100644 .changeset/nimble-quails-fly.md delete mode 100644 .changeset/noble-foxes-gather.md delete mode 100644 .changeset/noble-lemurs-sprint.md delete mode 100644 .changeset/patient-cranes-parade.md delete mode 100644 .changeset/patient-elks-glide.md delete mode 100644 .changeset/patient-jaguars-frolic.md delete mode 100644 .changeset/patient-koalas-roar.md delete mode 100644 .changeset/patient-sloths-glide.md delete mode 100644 .changeset/patient-zebras-climb.md delete mode 100644 .changeset/plucky-birds-hum.md delete mode 100644 .changeset/plucky-hawks-sing.md delete mode 100644 .changeset/plucky-koalas-snooze.md delete mode 100644 .changeset/plucky-moles-purr.md delete mode 100644 .changeset/plucky-pandas-roam.md delete mode 100644 .changeset/plucky-pandas-wave.md delete mode 100644 .changeset/proud-sloths-cheer.md delete mode 100644 .changeset/proud-sloths-frolic.md delete mode 100644 .changeset/quick-bears-cheer.md delete mode 100644 .changeset/quick-dogs-munch.md delete mode 100644 .changeset/quick-foxes-click.md delete mode 100644 .changeset/quick-mice-hop.md delete mode 100644 .changeset/rapid-ibex-sprint.md delete mode 100644 .changeset/rapid-lemurs-click.md delete mode 100644 .changeset/rapid-quails-sing.md delete mode 100644 .changeset/rapid-tunas-leap.md delete mode 100644 .changeset/rapid-wasps-sing.md delete mode 100644 .changeset/serene-bears-dance.md delete mode 100644 .changeset/serene-goats-roam.md delete mode 100644 .changeset/serene-goats-sprint.md delete mode 100644 .changeset/serene-orcas-glide.md delete mode 100644 .changeset/sharp-cranes-wander.md delete mode 100644 .changeset/sharp-deer-forage.md delete mode 100644 .changeset/sharp-foxes-tumble.md delete mode 100644 .changeset/sharp-seals-run.md delete mode 100644 .changeset/silly-finches-squeak.md delete mode 100644 .changeset/silly-yaks-fly.md delete mode 100644 .changeset/steady-foxes-rest.md delete mode 100644 .changeset/steady-otters-roar.md delete mode 100644 .changeset/steady-zebras-leap.md delete mode 100644 .changeset/sturdy-deer-frolic.md delete mode 100644 .changeset/sturdy-dogs-hop.md delete mode 100644 .changeset/sturdy-eagles-leap.md delete mode 100644 .changeset/sturdy-eagles-wave.md delete mode 100644 .changeset/sturdy-jaguars-munch.md delete mode 100644 .changeset/sturdy-otters-chatter.md delete mode 100644 .changeset/sturdy-sloths-roar.md delete mode 100644 .changeset/sunny-elks-dart.md delete mode 100644 .changeset/sunny-foxes-click.md delete mode 100644 .changeset/sunny-herons-hum.md delete mode 100644 .changeset/sunny-seals-munch.md delete mode 100644 .changeset/tidy-birds-march.md delete mode 100644 .changeset/tidy-finches-dance.md delete mode 100644 .changeset/tidy-finches-wave.md delete mode 100644 .changeset/tidy-hawks-roar.md delete mode 100644 .changeset/tidy-otters-squeak.md delete mode 100644 .changeset/vivid-lynx-zip.md delete mode 100644 .changeset/vivid-pumas-squeak.md delete mode 100644 .changeset/wise-otters-greet.md delete mode 100644 .changeset/wise-rams-travel.md delete mode 100644 .changeset/witty-goats-purr.md delete mode 100644 .changeset/witty-ibex-frolic.md delete mode 100644 .changeset/witty-lynx-sing.md delete mode 100644 .changeset/witty-tigers-romp.md delete mode 100644 .changeset/zesty-ibex-chatter.md delete mode 100644 .changeset/zesty-sloths-sprint.md delete mode 100644 .changeset/zesty-yaks-hop.md diff --git a/.changeset/agile-geese-squeak.md b/.changeset/agile-geese-squeak.md deleted file mode 100644 index e5c6e6c8e..000000000 --- a/.changeset/agile-geese-squeak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3815 ---- -**Workflows no longer send AI runtimes hunting the filesystem for the GSD shim** — 50 places across 23 runtime-loaded workflow, agent, reference, and command files told the agent to run `gsd-tools.cjs` by filename, which is not on PATH under any name. The agent got "command not found", fell back to locating the file, and on Git Bash for Windows `find /` walked the entire drive until someone killed it. Every one now calls the canonical `gsd_run` launcher. (#3809) diff --git a/.changeset/bold-bears-hum.md b/.changeset/bold-bears-hum.md deleted file mode 100644 index 5b2953ba4..000000000 --- a/.changeset/bold-bears-hum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3922 ---- -**`--pick ` now exits non-zero when a field is absent, and `parseNamedArgs` strictly rejects unrecognized flags and stray positionals** — previously an absent `--pick` field printed an empty string at exit 0 (indistinguishable from a genuinely empty answer, #3365), and a stray or unrecognized argv token was silently dropped rather than rejected, in one case corrupting STATE.md by running a command against the wrong phase (#3358). Both now fail loudly instead of silently: `X=$(gsd_run query V --pick F) || X=default` observes the real failure it was written for, and an unrecognized flag or positional exits non-zero naming what was wrong. (#3884) diff --git a/.changeset/bold-jays-travel.md b/.changeset/bold-jays-travel.md deleted file mode 100644 index 30aa2f954..000000000 --- a/.changeset/bold-jays-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3925 ---- -**Diagnostics stop reporting a clean result when they had to drop data to get one.** `intel query`'s recursive search now stops at 48 levels and marks the result `truncated: true` instead of quietly matching arbitrarily deep (a match past the ceiling now reports truncated rather than found, and no longer crashes with a stack overflow past ~12000 levels); `phase-plan-index` now names an unresolved `depends_on` token in its own warning instead of blaming the plan's declared `wave:` for a dependency edge the tool itself dropped, and that warning's own token is escaped so an attacker-authored token cannot forge a second warning line; and a code-review run where every lane failed no longer writes a `REVIEWS.md` synthesized from nothing, preserving each lane's raw output first. (#3885) diff --git a/.changeset/bold-lynx-cheer.md b/.changeset/bold-lynx-cheer.md deleted file mode 100644 index 8ad934c52..000000000 --- a/.changeset/bold-lynx-cheer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3670 ---- -**`/gsd-ingest-docs`, `/gsd-import`, `/gsd-audit-fix`, `/gsd-profile-user`, and `/gsd-docs-update` now honor model routing for their subagents** — the doc classifier/synthesizer/verifier, roadmapper, plan-checker, fix executor, and user-profiler subagents (plus the debugger spawned by the `diagnose-issues` workflow behind `/gsd-verify-work`) ran on the calling session's model, silently ignoring `dynamic_routing`/`model_profile` tier config. Each workflow now resolves the per-agent model and passes it on the spawn (omitting it when it resolves to inherit/empty per #2517). (#3602) diff --git a/.changeset/bold-moles-squeak.md b/.changeset/bold-moles-squeak.md deleted file mode 100644 index 3f55351a3..000000000 --- a/.changeset/bold-moles-squeak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3690 ---- -**Upgrading the Codex runtime no longer aborts when a top-level config key sits below the GSD marker** — the regenerated `[agents]` table captured such keys into its scope, so post-write schema validation rejected the merged `config.toml` and the install failed mid-flight. Surviving top-level keys are now hoisted above the managed block, preserving their file scope. (#3610) diff --git a/.changeset/bold-pandas-snooze.md b/.changeset/bold-pandas-snooze.md deleted file mode 100644 index 890375e32..000000000 --- a/.changeset/bold-pandas-snooze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3678 ---- -**Verify-command path grounding for phase planning** — a plan's `` verify command whose target directory does not exist (or holds no `package.json`) is now caught deterministically before execution instead of being hand-reasoned by the plan checker, which previously prescribed wrong replacement paths. The planner also inherits the nearest prior phase's proven verify commands at every context window, not only above 500k. (#2401) diff --git a/.changeset/brave-birds-travel.md b/.changeset/brave-birds-travel.md deleted file mode 100644 index 24bea7607..000000000 --- a/.changeset/brave-birds-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3826 ---- -**`phase complete` now reports `roadmap_updated` and `state_updated` honestly** — both flags read `fs.existsSync()`, so they were `true` for any project that had the file at all, and a rollup that silently wrote nothing was indistinguishable from one that landed. Each flag now reflects whether that file's content actually changed in the transaction, matching the contract `requirements_updated` already honored. (#3685) diff --git a/.changeset/brave-elks-climb.md b/.changeset/brave-elks-climb.md deleted file mode 100644 index 65a038096..000000000 --- a/.changeset/brave-elks-climb.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3733 ---- -**`windows` ledger commands survive a formatter pass** — the WINDOWS.md ledger's JSON block is written with a four-backtick fence, which Prettier and other CommonMark formatters legally narrow to three; the reader then rejected the file and every `gsd-tools windows` subcommand (status/append/waive/fixed) failed with "Ledger missing JSON code block". The reader now accepts any CommonMark-legal fence width (the writer still emits four), resolves the real block past fences planted in entry descriptions, and preserves user prose below the ledger; the refactor-trigger proposal reader gets the same fence tolerance. (#3657) diff --git a/.changeset/brave-goats-march.md b/.changeset/brave-goats-march.md deleted file mode 100644 index f11fb8cdd..000000000 --- a/.changeset/brave-goats-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3847 ---- -**Stage the emitted-drift-ack sweep around open PRs** — sweeping an all-spent fragment used to delete it unconditionally, handing any open PR that still touched the same file a modify/delete conflict it did not cause (#3330, #3774, #3648). The guard now holds a fragment back when an open PR still touches it, deferring the sweep until that PR merges or closes. (#3842) diff --git a/.changeset/brave-jays-tumble.md b/.changeset/brave-jays-tumble.md deleted file mode 100644 index a15f7dfa6..000000000 --- a/.changeset/brave-jays-tumble.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3814 ---- -**Resuming `/gsd-execute-phase` on a phase whose verification passed but whose run died before marking complete now finishes the job** — the phase is marked complete, progress state advances, phase todos close, and the transition handoff runs, instead of every resume reporting "nothing to do" while the roadmap checkbox stays unticked forever. Already-completed phases keep exiting cleanly, and verification is never redone. (#3684) diff --git a/.changeset/brave-tunas-dart.md b/.changeset/brave-tunas-dart.md deleted file mode 100644 index 26ef7dcd2..000000000 --- a/.changeset/brave-tunas-dart.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3844 ---- -**`state validate` now sees the `last_activity` invariant, and `--strict` makes the verdict gateable** — a STATE.md whose `Last activity` value no reader could parse used to validate clean (`{valid:true, warnings:[], scope:'complete'}`), and a wrapped description was silently truncated; both are now reported as coded diagnostics (`S008`/`S009`). `state validate --strict` exits non-zero when the report is not valid, so a CI step or git hook can gate on state correctness without parsing JSON — the default exit status is unchanged. (#3696) diff --git a/.changeset/brave-wasps-leap.md b/.changeset/brave-wasps-leap.md deleted file mode 100644 index f00fb9dd0..000000000 --- a/.changeset/brave-wasps-leap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3716 ---- -**Live-DOM UAT: browser-backed UI acceptance checks during execution** — a phase whose acceptance criteria needed a live DOM could not be finished by the agent that executed it, so it silently degraded to "executed, then finished by hand in the orchestrator". Enable `workflow.live_dom_uat` (default off) and a purpose-built `gsd-dom-verifier` checks those criteria after each wave and reports whether it looked, or could not. The plan executor's tool surface is unchanged in every configuration. (#2856) diff --git a/.changeset/calm-bears-travel.md b/.changeset/calm-bears-travel.md deleted file mode 100644 index 57c537297..000000000 --- a/.changeset/calm-bears-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3999 ---- -**A twelfth hand-rolled slug copy can no longer land, and two existing ones are fixed.** `generateSlugInternal` is the canonical slug owner, but nothing prevented a call site from re-deriving it — and two had: `qa-smell-ratchet` trimmed before truncating instead of after, so any non-ASCII input collapsed to just its ASCII tail, and a test helper claimed parity with a function that transliterates while itself not transliterating. A new drift guard now fails the build on an unsanctioned re-derivation, with three legitimately-different sites explicitly sanctioned. (#3987) diff --git a/.changeset/calm-deer-hum.md b/.changeset/calm-deer-hum.md deleted file mode 100644 index c445ae5cb..000000000 --- a/.changeset/calm-deer-hum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3728 ---- -**`/gsd:plan-phase` no longer writes gitignored install-mirror paths into plans** — `files_modified` and artifact paths are now verified against `git ls-files` and resolved to tracked source (e.g. a plugin's own tree) instead of a runtime mirror under `.gsd/capabilities/`, whose edits died on every capability sync; paths inherited from PATTERNS.md are re-verified so one mirror path can no longer self-propagate across phases. (#3645) diff --git a/.changeset/calm-otters-refuse.md b/.changeset/calm-otters-refuse.md deleted file mode 100644 index b3e0dffeb..000000000 --- a/.changeset/calm-otters-refuse.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3774 ---- -**`milestone complete` now requires an explicit `--confirm` to mutate** — the command irreversibly archives ROADMAP.md/REQUIREMENTS.md, MOVES every phase directory in the milestone, and rewrites STATE.md, yet ran unconditionally on first invocation through every invocation path, including `query milestone.complete `, whose `query` meta-prefix reads as a read-only namespace but performs no filtering. Without `--confirm` (and without `--dry-run`) the command now refuses before touching anything and names the flag that proceeds; `--dry-run` still previews the exact move list with no confirmation needed, and is now documented in the command's own usage block. `--force` keeps its narrow meaning (bypass the TRUNCATED-scope / unstarted-phase guards) and does not double as the mutation opt-in. The `/gsd-complete-milestone` workflow passes `--confirm` at its archive step. (#3726) diff --git a/.changeset/calm-pandas-greet.md b/.changeset/calm-pandas-greet.md deleted file mode 100644 index 9abc5a45a..000000000 --- a/.changeset/calm-pandas-greet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3725 ---- -**In-process installs can no longer write a kind's `home` override into your real home** — a runtime kind with a global `home` override (codex skills → `$HOME/.agents`) resolves from `os.homedir()`, not from the caller's config dir, so a test that sandboxed only its target directory pruned every `gsd-*` skill from the developer's real `~/.agents/skills` while the suite still passed and the manifest still reported a healthy install. All six writers that resolve a kind `home` now refuse when a `node --test` run would land inside the real home, compared by filesystem identity rather than pathname and decided on where the write resolves rather than how it is spelled. Scope is stated rather than implied: the six are the writers on the `installRuntimeArtifacts` call tree, and this covers destinations a runtime kind resolves through a `home` override, not every path the installer touches through `os.homedir()` (`writeNonClaudeDefaults`' `~/.gsd/defaults.json` is still reached by a spawned installer with an un-sandboxed HOME) and not writers off that tree (`cmdGenerateDevPreferences` resolves the same codex `home` override through `getGlobalSkillsBase` and writes `SKILL.md` beneath it unguarded; it has no in-process caller today, so it is latent rather than live). Canonicalization fails CLOSED rather than falling back to the lexical spelling — an unresolvable component (`EACCES`/`ELOOP`/`EIO`) is refused, since that fallback is the exact ALLOW an aliased `/.agents` needs; only `ENOENT`/`ENOTDIR` walk up, matching `identify`'s own errno split. Two limits are named in the source rather than papered over: a subordinate bind mount of the real directory into a sandbox is not detectable without mount-table introspection, and on a host with no readable passwd entry the guard falls back to a caller-set marker — which must itself identify, and must contain every destination, so a layout captured before the sandbox is still refused. Real installs are unaffected. (#3712) diff --git a/.changeset/calm-tunas-rally.md b/.changeset/calm-tunas-rally.md deleted file mode 100644 index 350590057..000000000 --- a/.changeset/calm-tunas-rally.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4049 ---- -writing any markdown file no longer converts tight multi-line lists to loose ones — a blank line was injected before every bullet following a wrapped item (61 blanks on a 1015-line ROADMAP via phase.complete; the defect sat in the write seam every .md write uses), and tight vs loose lists render differently so this was a rendering change plus large misleading diffs, not just whitespace (#3854) diff --git a/.changeset/clever-eagles-jump.md b/.changeset/clever-eagles-jump.md deleted file mode 100644 index 3ebbb7211..000000000 --- a/.changeset/clever-eagles-jump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3789 ---- -**Section separators now render responsively instead of wrapping** — stage banners, checkpoints, completion and error panels used fixed-width runs of box-drawing characters (a 53-column `━` rule, a 62-column `╔═╗` box). In a narrower pane those runs wrap and the border comes apart from the heading it framed. GSD now emits Markdown headings and `---` thematic breaks, which adapt to the available width in every runtime. (#3028) diff --git a/.changeset/clever-hawks-wave.md b/.changeset/clever-hawks-wave.md deleted file mode 100644 index 6b4bfb2c7..000000000 --- a/.changeset/clever-hawks-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3790 ---- -**Managed hooks now resolve the node binary at hook-fire time** — a config root shared across environments (WSL/Docker bind-mounts, mounted or synced `~/.claude`) no longer fails every managed hook with `node: not found` outside the machine that ran the installer, and updates from any environment converge stale runners instead of creating a mixed state where no environment works. `--portable-hooks` installs route through a staged `hooks/gsd-node-runner.sh` resolver (install-time path first, then `command -v node`, then well-known layouts); other installs carry an equivalent inline fallback chain. (#3662) diff --git a/.changeset/clever-jaguars-hum.md b/.changeset/clever-jaguars-hum.md deleted file mode 100644 index 8146e966a..000000000 --- a/.changeset/clever-jaguars-hum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3803 ---- -**/gsd-pr-branch now refuses to verify a PR branch that would delete planning files the target branch tracks** — the verification step counts planning-tree deletions via git diff --name-status and fails on any non-zero count, instead of reporting clean while pre-existing planning content was stripped. The underlying deletion class in the cherry-pick filter was already fixed by the strict-mode rewrite; this makes the workflow able to detect it. (#3679) diff --git a/.changeset/clever-jaguars-rally.md b/.changeset/clever-jaguars-rally.md deleted file mode 100644 index 7aaaf9afd..000000000 --- a/.changeset/clever-jaguars-rally.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3824 ---- -**GSD now publishes a machine-readable state snapshot at every step boundary** — external tools that show project state no longer have to parse STATE.md and ROADMAP.md heuristically. `.planning/state.json` carries a versioned `contract`, the current `milestone`, every phase with its `complete`/`in_progress`/`pending` status, and the same recommended `next` action the `/gsd` front door routes. The write is best-effort and can never fail, slow, or alter the command that triggered it. (#3227) diff --git a/.changeset/clever-pumas-march.md b/.changeset/clever-pumas-march.md deleted file mode 100644 index 874a7df4f..000000000 --- a/.changeset/clever-pumas-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3694 ---- -**Codex worktree-parallel executors now launch with the full executor contract** — the orchestrator-worktree process spawn handed its child a short objective-only prompt, so executors reconstructed their role by repository search and force-staged gitignored SUMMARY.md files (`git add -f`) to satisfy an unconditional commit criterion. The spawn prompt now carries the embedded executor workflow, required reading with the explicit plan path, the gsd-executor persona, and skip-aware success criteria, and halts before spawn when the contract embeds cannot be resolved. (#3637) diff --git a/.changeset/curious-birds-dance.md b/.changeset/curious-birds-dance.md deleted file mode 100644 index 74673963b..000000000 --- a/.changeset/curious-birds-dance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4019 ---- -**`workflow.inline_plan_threshold` now has one default owner** — the key is registered in the defaults manifest (default `2`), so `config-get` resolves the absent key instead of erroring, `settings-advanced` no longer misdocuments the default as 3, and every shipped surface (workflow fallback, reference tables) agrees. (#3801) diff --git a/.changeset/curious-cats-march.md b/.changeset/curious-cats-march.md deleted file mode 100644 index 9b412c2dd..000000000 --- a/.changeset/curious-cats-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4022 ---- -**`audit-uat` sees workstream phases again** — the audit now enumerates all three phase-archive layouts (flat `milestones/vX.Y-phases/`, archived workstream `milestones/ws-*/phases/`, and active workstream `workstreams//milestones/`), with workstream entries labeled `/` so acknowledge-by-milestone stays unambiguous. A project using workstreams no longer gets an All Clear audit while items are open, and `--ws` no longer empties the report. Phase lookups keep their #2855 workstream scoping unchanged. (#3804) diff --git a/.changeset/curious-seals-wander.md b/.changeset/curious-seals-wander.md deleted file mode 100644 index 9b27fa0db..000000000 --- a/.changeset/curious-seals-wander.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3967 ---- -**`workflow.use_worktrees=false` at the root now applies inside workstreams too** — the dispatch-isolation resolver inherits the root opt-out under `GSD_WORKSTREAM` exactly as `config-get` does, so a root-level opt-out no longer leaves workstream runs recording `harness-worktree` over the mandated `none`. (#3963) diff --git a/.changeset/curious-zebras-roam.md b/.changeset/curious-zebras-roam.md deleted file mode 100644 index 15e734d18..000000000 --- a/.changeset/curious-zebras-roam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3852 ---- -**`phase complete` no longer advances to an inserted phase that merely has a directory** — the next-phase resolution scanned phase directories first and only consulted ROADMAP.md when the disk turned up nothing, so an inserted decimal phase (whose directory `phase insert` scaffolds immediately) outranked the phases preceding it in roadmap order. The wrong successor was reported and written to STATE.md as the resume pointer. Roadmap order now decides which phase is next; the disk still supplies the on-disk spelling when both agree, and remains the fallback when no roadmap is readable. (#3701) diff --git a/.changeset/daring-deer-fly.md b/.changeset/daring-deer-fly.md deleted file mode 100644 index 2ae88cf89..000000000 --- a/.changeset/daring-deer-fly.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4050 ---- -the STATE.md Quick Tasks log accepts milestone-suffixed section headings (Quick Tasks Completed (v1.1+)) — the exact-anchored lookup never matched them, so every /gsd:fast append and milestone reset silently failed before the columns were even checked; among several matching sections the one with a recognized table schema wins (#3860) diff --git a/.changeset/daring-jays-leap.md b/.changeset/daring-jays-leap.md deleted file mode 100644 index 7facea508..000000000 --- a/.changeset/daring-jays-leap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3941 ---- -**Non-Claude installs now resolve their own runtime by default, and `depends_on` accepts the bare plan number.** A Codex, Cursor, or other non-Claude install with no `GSD_RUNTIME` set and no `config.runtime` key previously still reported `claude` everywhere, because the per-install runtime marker the installer writes was read by four hand-rolled copies but never by `resolveRuntime` itself; it is now the third precedence rung. Separately, `depends_on: ["01"]` now resolves to the in-phase sibling plan instead of silently dropping the dependency and collapsing the plan into wave 1 — a phase that previously ran all its plans in a single wave now executes in its declared waves. Codex sandbox permissions are also now derived from each agent's own tool contract instead of a hand-maintained map, and `validate agents` reports any drift via a new `sandbox_posture` field; both are byte-identical to today's behavior. (#3897) diff --git a/.changeset/daring-newts-chatter.md b/.changeset/daring-newts-chatter.md deleted file mode 100644 index 9426b6d08..000000000 --- a/.changeset/daring-newts-chatter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4013 ---- -**`--config-dir` installs no longer plan removals of the default home's live legacy install** — the legacy get-shit-done-cc cleanup is scoped to the resolved config dir when `--config-dir` redirects the install (scan, shared cache, and per-package cache alike), the `--dry-run` preview shows the same scoped plan the real install would apply, and `--no-legacy-cleanup` skips the scan entirely. (#3799) diff --git a/.changeset/daring-orcas-dart.md b/.changeset/daring-orcas-dart.md deleted file mode 100644 index c5b3fc0e9..000000000 --- a/.changeset/daring-orcas-dart.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4057 ---- -a spaced-hyphen thematic break (- - -) inside a UAT file ## Gaps section is no longer parsed as a gap entry — it fabricated a phantom open gap named "- -" with result unknown that audit-uat surfaced as outstanding work which could not be cleared by editing any entry (#3898) diff --git a/.changeset/daring-tigers-squeak.md b/.changeset/daring-tigers-squeak.md deleted file mode 100644 index 6fcbdb48e..000000000 --- a/.changeset/daring-tigers-squeak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3935 ---- -**No more console-window flash on Windows in non-GSD repositories** — the graphify auto-update hook ran a hidden `node` process to parse its payload before checking whether the project uses GSD at all; the cheap `.planning/config.json` and `CI` checks now run first, so non-GSD projects and CI pay for zero child processes per Bash tool call. (#3729) diff --git a/.changeset/daring-voles-snooze.md b/.changeset/daring-voles-snooze.md deleted file mode 100644 index 868ce43d2..000000000 --- a/.changeset/daring-voles-snooze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3700 ---- -**Statusline can now warn that STATE.md has fallen behind the code** — enable `statusline.show_state_freshness` and the GSD-state segment renders `state ~N commits back` once HEAD is 20+ commits past the commit STATE.md was written against, the same advisory threshold `/gsd-health`'s W024 uses. Off by default; costs one bounded git call per render only while enabled, and stays silent rather than guessing when freshness cannot be established. (#2734) diff --git a/.changeset/eager-birds-sprint.md b/.changeset/eager-birds-sprint.md deleted file mode 100644 index 780153a3a..000000000 --- a/.changeset/eager-birds-sprint.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3766 ---- -**docs/INVENTORY.md rows are now enforced** — a shipped agent, command, workflow, reference, CLI module, or hook could be added to the generated manifest with no row in the authoritative roster and still pass CI; the roster is now anchored the same way the manifest is, and 32 pre-existing gaps are backfilled. (#3762) diff --git a/.changeset/eager-cats-squeak.md b/.changeset/eager-cats-squeak.md deleted file mode 100644 index 953239c79..000000000 --- a/.changeset/eager-cats-squeak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3950 ---- -**`total_plans` no longer counts REPLAN/PLANNING documents as plans** — a phase directory carrying a `REPLAN-INPUTS` or `PLANNING-NOTES` document no longer inflates the plan count that STATE.md derives on every state-mutating call. (#3741) diff --git a/.changeset/eager-elks-snooze.md b/.changeset/eager-elks-snooze.md deleted file mode 100644 index 61696cd76..000000000 --- a/.changeset/eager-elks-snooze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3979 ---- -**The isolation guard no longer denies sequential dispatches a workstream explicitly opted out of** — the sentinel-absent fallback now reads `workflow.use_worktrees` through the same project/workstream-aware ladder as the resolver and `config-get`, instead of the flat root config where a workstream-local opt-out was invisible. (#3972) diff --git a/.changeset/eager-ibex-hop.md b/.changeset/eager-ibex-hop.md deleted file mode 100644 index 647612929..000000000 --- a/.changeset/eager-ibex-hop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3848 ---- -**The launcher now proves which `gsd-tools` it resolved before running any verb** — a project-local or config-directory install that cannot answer `runtime-identity` with an `@opengsd/gsd-core` payload now produces one actionable warning naming both causes (a foreign package, or a gsd-core older than the verb) and exports `GSD_IDENTITY_STATUS=unverified`, instead of silently handing a state-mutating verb to a tool written for a different contract. (#3841) diff --git a/.changeset/eager-rams-jump.md b/.changeset/eager-rams-jump.md deleted file mode 100644 index 694fc54be..000000000 --- a/.changeset/eager-rams-jump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4008 ---- -**`gsd-roadmapper` no longer contradicts itself on write-vs-approve ordering** — the agent's role, output format, and completion checklist now match its write-first execution flow (write for durability, return `## ROADMAP CREATED` with a preview; the orchestrator presents and owns the approval gate), and the orphaned `## ROADMAP DRAFT` template that matched no orchestrator branch is gone. (#3797) diff --git a/.changeset/eager-tigers-zip.md b/.changeset/eager-tigers-zip.md deleted file mode 100644 index 056f0032a..000000000 --- a/.changeset/eager-tigers-zip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3828 ---- -**`windows append`/`waive`/`fixed` no longer silently erase a hand-edited ledger table** — `.planning/WINDOWS.md` renders its table from the fenced JSON that is its source of truth, and every write regenerated that table without ever checking the two still agreed. A hand-edited cell was reverted and a table-only row vanished entirely, both at exit 0 with nothing on stdout. The write is now refused with a `windows_ledger_table_drift` error naming the offending row ids, and the file is left untouched. (#3689) diff --git a/.changeset/eager-tunas-parade.md b/.changeset/eager-tunas-parade.md deleted file mode 100644 index 9bd6a5ea9..000000000 --- a/.changeset/eager-tunas-parade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3863 ---- -**Agent frontmatter no longer reverts to catalog Anthropic models when `model_policy` is configured** — the install-time bake for the static-frontmatter runtimes (OpenCode, Kilo) read `model_profile` and `model_profile_overrides` but never `model_policy`, so every update rewrote agent `model:` fields to `anthropic/claude-*` IDs that a custom provider does not serve, while dispatch-time resolution honored the policy correctly. The bake now consults the same policy resolver dispatch uses, at the same precedence: an explicit per-agent `model_overrides` entry still wins, then `model_policy`, then the tier table. (#3705) diff --git a/.changeset/eager-yaks-wander.md b/.changeset/eager-yaks-wander.md deleted file mode 100644 index 3988afe95..000000000 --- a/.changeset/eager-yaks-wander.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3815 ---- -**`gsd-core/references/` is now covered by the bare-command guard** — the #2751 guard only ever scanned `agents/` and `gsd-core/workflows/`, so 37 bare `gsd-tools ` calls sat unguarded in a directory it never looked at. They now call the canonical `gsd_run` launcher, and the guard scans references too. (#2751) diff --git a/.changeset/fierce-dogs-howl.md b/.changeset/fierce-dogs-howl.md deleted file mode 100644 index f1abe41a3..000000000 --- a/.changeset/fierce-dogs-howl.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4069 ---- -**Release coverage gate no longer OOMs as the test suite grows** — `test:coverage:unit` (used by the release finalize/rc jobs) and `test:coverage:report` (the sharded coverage-gate merge step) now pass c8's `--merge-async` flag, so raw V8 coverage files are merged one at a time instead of all being loaded into memory at once. (#4068) diff --git a/.changeset/gallant-eagles-zip.md b/.changeset/gallant-eagles-zip.md deleted file mode 100644 index b770fc6c3..000000000 --- a/.changeset/gallant-eagles-zip.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -type: Fixed -pr: 3903 ---- -**UAT rows separated only by a lone carriage return were silently dropped from the audit-uat scan.** A `VERIFICATION.md` or `deferred-items.md` written with lone-CR line endings rendered normally to a human reader, but reported zero outstanding items to the audit, hiding real human-verification and deferred-work entries. Both file types now surface their rows exactly as their LF/CRLF equivalents do. - -**Planning-inspect now surfaces UAT rows separated only by a lone carriage return.** The same lone-CR line-ending gap also hid rows from planning-inspect's own UAT reporting; a row that previously vanished from `uat.unresolved` now appears there too, matching its LF/CRLF equivalents. - -**A UAT row whose `result:` line had trailing text containing a Unicode line or paragraph separator (U+2028/U+2029) is no longer dropped.** A column-0 `result:` line whose text after the token happened to contain one of these separators previously failed to parse at all, silently discarding an outstanding row; it now parses the same as its plain-line equivalent. (#3707) diff --git a/.changeset/gallant-jaguars-wander.md b/.changeset/gallant-jaguars-wander.md deleted file mode 100644 index babf3c731..000000000 --- a/.changeset/gallant-jaguars-wander.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3965 ---- -**Two lint rules that could not reach the code they govern now do, and `quick-tasks-append` stops overwriting curated progress values.** `local/no-adhoc-markdown-parsing` self-gated on its own filename, so it silently skipped every `.cts` file in a `src/` subdirectory and could not be widened by configuration alone; it now also covers `tests/` and `scripts/`, and the 80 hand-rolled markdown parses it surfaced are routed through the existing sectionizer and table seams — including one test that asserted against the wrong table column and so could never fail. `local/no-adhoc-regex-escape` examined only bare identifiers, missing the property-access shape runtime data actually arrives in, which is why it never caught a known ReDoS. Separately, `quick-tasks-append` gained optional `--quick-id`/`--slug`/`--directory` so a caller with a real quick task emits the canonical row, and a body-only append no longer forces a re-derive of disk-derived progress frontmatter that replaced curated values. (#3951) diff --git a/.changeset/gallant-mice-snooze.md b/.changeset/gallant-mice-snooze.md deleted file mode 100644 index 67b2913a2..000000000 --- a/.changeset/gallant-mice-snooze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3966 ---- -**~/.gsd/defaults.json is written under the install-migration lock and in a single atomic write** — concurrent installs for different runtimes can no longer lose each other's settings, and a crash mid-write can no longer truncate this machine-global file (which the read path treats as absent, silently degrading model resolution for every project on the machine). An install that changes nothing no longer rewrites the file. diff --git a/.changeset/gallant-orcas-caper.md b/.changeset/gallant-orcas-caper.md deleted file mode 100644 index 1199be8b0..000000000 --- a/.changeset/gallant-orcas-caper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3720 ---- -**`/gsd-pr-branch` gains a strict mode that keeps every planning artifact out of the PR branch** — set `planning.pr_strict: true` and the generated PR branch carries no `.planning/` path at all, structural files included, so a project can version its planning tree locally (keeping executor worktrees and `/gsd-undo` working) while publishing none of it. Defaults to `false`, which reproduces the previous classification and preservation exactly. (#2971) diff --git a/.changeset/gallant-rams-gather.md b/.changeset/gallant-rams-gather.md deleted file mode 100644 index 9b8a5bf98..000000000 --- a/.changeset/gallant-rams-gather.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3831 ---- -**Shipped workflows can no longer reach a different package's `gsd-tools`** — a second package publishes a binary of the same name whose `phases.clear` deletes where GSD's archives, so a workflow could destroy planning directories and still print success. Workflows now resolve `gsd_run`, which only this package publishes, and stop with an install message rather than falling back to whatever `gsd-tools` is on `PATH`. Adds `gsd-tools runtime-identity` for confirming by hand which tool a project is running against. (#3146) diff --git a/.changeset/gentle-otters-click.md b/.changeset/gentle-otters-click.md deleted file mode 100644 index 30f254ad1..000000000 --- a/.changeset/gentle-otters-click.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3720 ---- -**`/gsd-pr-branch` no longer deletes the base branch's planning files or silently drops commits** — the generated PR branch used to stage a deletion for any `.planning/` path the target branch already tracked, and a second commit touching the same planning file aborted the cherry-pick with "untracked working tree files would be overwritten", dropping that commit and every one after it. The filter now forces excluded paths back to what the target branch tracks in both the index and the working tree. Verification also asserts against the active filter mode instead of an unconditional zero, so a correct default-mode run that preserved `STATE.md` no longer reports itself as failed. (#2971) diff --git a/.changeset/graceful-bears-caper.md b/.changeset/graceful-bears-caper.md deleted file mode 100644 index e43db0aaa..000000000 --- a/.changeset/graceful-bears-caper.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: Changed -pr: 4029 ---- -**Removed a dead code path** — `listMilestoneArchiveDirs` (caller-less since the Phase-12 snapshot migration) and its test seam are gone; the #1883 unreadable-milestones regression suite now pins the live planning-snapshot path. (#3813) - diff --git a/.changeset/graceful-elks-wander.md b/.changeset/graceful-elks-wander.md deleted file mode 100644 index 3cce123e4..000000000 --- a/.changeset/graceful-elks-wander.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4034 ---- -audit-open summary counts now include the display-truncation remainder: a milestone with more than 5 open files reported counts capped at 5 because the _remainder_count display marker was counted as one item instead of the real files it records (#3817) diff --git a/.changeset/graceful-foxes-dart.md b/.changeset/graceful-foxes-dart.md deleted file mode 100644 index 04d05fba8..000000000 --- a/.changeset/graceful-foxes-dart.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4052 ---- -smart-entry classifies a STATE.md status of verified (or verification) as verify-pending instead of falling through to unknown — the classifier matched the exact word verify and missed the verif stem its own normalizeStateStatus uses (#3864) diff --git a/.changeset/graceful-jaguars-wave.md b/.changeset/graceful-jaguars-wave.md deleted file mode 100644 index 4f11d4005..000000000 --- a/.changeset/graceful-jaguars-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3924 ---- -**A second terminator for code that cannot wait for the event loop, and a versioned exit-code projection** — hooks and other write-then-exit callers can now terminate through the same registry lookup that `runMain` uses, so both agree on what every outcome means. Exit integers are versioned: today's behavior is `v1`, and `--exit-contract=v2` (or `GSD_EXIT_CONTRACT=v2`) opts into the registry's codes ahead of the next major. (#3906) diff --git a/.changeset/graceful-moles-travel.md b/.changeset/graceful-moles-travel.md deleted file mode 100644 index 182890946..000000000 --- a/.changeset/graceful-moles-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3980 ---- -**`milestone complete` blocks again when the roadmap still lists unstarted phases** — that guard had been silently swallowed, so milestones could be archived with work outstanding and nothing said so. Two more guards that inspected an error's message before deciding whether to re-raise were failing the same way and are fixed with it, and `extract-messages`/`profile-sample` no longer dump a raw Node stack trace on top of their error line. A new lint rule now rejects a raw `process.exit()` outside the sanctioned terminator, so a guard cannot quietly stop guarding this way again. (#3910) diff --git a/.changeset/graceful-pumas-roar.md b/.changeset/graceful-pumas-roar.md deleted file mode 100644 index 00da4ed57..000000000 --- a/.changeset/graceful-pumas-roar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3976 ---- -**New ESLint rule `local/no-exact-case-env-access`** — flags an exact-case read of a Windows case-varying environment variable (`PATH`, `PATHEXT`, `ComSpec`, `USERPROFILE`, `TEMP`, `TMP`, `APPDATA`) off any object other than `process.env` itself, closing the gap ADR-1703's portability catalog left on production Windows semantics. (#3624) diff --git a/.changeset/graceful-rams-dance.md b/.changeset/graceful-rams-dance.md deleted file mode 100644 index e222c9b6d..000000000 --- a/.changeset/graceful-rams-dance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3732 ---- -**`/gsd:config --integrations` no longer prescribes writes that fail** — the review-models section states the real rule (only reviewer lanes whose capability declares a modelConfigKey are settable; the nine settable lanes are enumerated; cursor/qwen/coderabbit named as keyless) instead of a validation pattern that never existed, and agent-skill lists are now written as JSON arrays instead of a comma-joined string that resolves as one broken skill path. (#3651) diff --git a/.changeset/graceful-rams-roar.md b/.changeset/graceful-rams-roar.md deleted file mode 100644 index 51a879472..000000000 --- a/.changeset/graceful-rams-roar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4054 ---- -the phase-taking init.* queries (execute-phase, plan-phase, verify-work, code-review, phase-op, review, discuss-phase-assumptions, todos) accept --phase as an alias for the positional form, matching phase list-plans; a valueless --phase is now a usage error instead of silently answering phase_found:false for a phase that has plans (#3865) diff --git a/.changeset/happy-deer-roar.md b/.changeset/happy-deer-roar.md deleted file mode 100644 index acc3e9d87..000000000 --- a/.changeset/happy-deer-roar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3880 ---- -**The STATE.md field reference is generated from one schema, and the status lifecycle now appears in every language** — the key set, its types, enums and cardinality are declared once and projected into the field-classification tables, the shipped template and all five reference documents, so a field can no longer be described one way in code and another in the docs. The `Status lifecycle` section, which documents the status values, was missing from the Japanese, Chinese, Korean and Portuguese references and is now present in all of them. (#3873) diff --git a/.changeset/happy-jaguars-climb.md b/.changeset/happy-jaguars-climb.md deleted file mode 100644 index bbafb56da..000000000 --- a/.changeset/happy-jaguars-climb.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3952 ---- -**STATE.md frontmatter comments now survive every state write** — a column-0 comment no longer depends on an unrelated body line being present, and an indented comment above the `progress:` counters (the natural provenance spot) is preserved instead of silently stripped. (#3742) diff --git a/.changeset/humble-newts-parade.md b/.changeset/humble-newts-parade.md deleted file mode 100644 index 1d5169daf..000000000 --- a/.changeset/humble-newts-parade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3727 ---- -**`state` no longer lets a lone non-matching milestone section's phases become another milestone's `total_phases`** — with exactly one milestone section in ROADMAP.md and a STATE.md asserting a different milestone, the section's phases were silently written as the asserted milestone's total (clobbering the stored value). Both that shape and the multi-section one now keep the stored total and warn, naming the asserted milestone. Flat roadmaps (no milestone headings at all) are unchanged. (#3642) diff --git a/.changeset/jolly-badgers-cheer.md b/.changeset/jolly-badgers-cheer.md deleted file mode 100644 index b1f50cd0b..000000000 --- a/.changeset/jolly-badgers-cheer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4041 ---- -the shipped hook tables documented gsd-validate-commit.sh as PostToolUse (it is registered PreToolUse — exit-2 blocking is its contract) and gsd-session-state.sh as PostToolUse (registered SessionStart); 18 wrong rows corrected across ARCHITECTURE.md and INVENTORY.md in en/ja-JP/zh-CN/ko-KR/pt-BR, with a new docs-vs-surface parity suite guarding all ten tables (#3839) diff --git a/.changeset/jolly-bears-sprint.md b/.changeset/jolly-bears-sprint.md deleted file mode 100644 index c23329e66..000000000 --- a/.changeset/jolly-bears-sprint.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3998 ---- -**`audit-open acknowledge` works on heading-shaped deferred-items.md** — the CLI writer previously refused every entry in any file using the heading-delimited (#3457) convention (a real project saw 0 of 107 items acknowledgeable); leaf headings and interleaved headless bullets now acknowledge through the same span-anchored, span-verified write the bullet shape uses, with a human `Status: resolved` never downgraded. Only entries embedding a GFM table row still refuse. (#3781) diff --git a/.changeset/jolly-geese-roar.md b/.changeset/jolly-geese-roar.md deleted file mode 100644 index b1d47ee78..000000000 --- a/.changeset/jolly-geese-roar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3888 ---- -**`.planning/` frontmatter is now parsed by a real YAML parser.** Block scalars, quoted keys and non-ASCII keys are read correctly instead of being mangled or silently dropped, and a document whose frontmatter cannot be parsed keeps its frontmatter block instead of losing it on the next write. (#3881) diff --git a/.changeset/jolly-newts-click.md b/.changeset/jolly-newts-click.md deleted file mode 100644 index 6b11c4f79..000000000 --- a/.changeset/jolly-newts-click.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3921 ---- -**Antigravity global skills and agents now install to `~/.gemini/config/`** — the directory Antigravity actually scans for machine-local discovery, so installed skills are no longer silently ignored at startup. Upgrading an existing install automatically removes the old artifacts from the deprecated `~/.gemini/antigravity` location (modified files are backed up; user-authored files are preserved). (#3738) diff --git a/.changeset/jolly-quails-howl.md b/.changeset/jolly-quails-howl.md deleted file mode 100644 index 22de0d64f..000000000 --- a/.changeset/jolly-quails-howl.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3891 ---- -**Codex worktree executors now run on the model you pinned for them.** With `model_overrides.gsd-executor` set, `$gsd-execute-phase` spawned its worktree executor with no `--model` argument at all, so the child silently fell back to the global Codex session model — and because this path spawns a process rather than dispatching a named agent, the model baked into `gsd-executor.toml` could not apply either. An explicitly pinned model is now passed to the spawned process. An unpinned, blank, or `inherit` configuration still emits no model argument and keeps the session-model fallback, so Codex's session-only model posture is unchanged and no tier-derived model is ever sent. A pin that is Anthropic-flavored (`sonnet`, `opus`, `claude-*`), flag-shaped (e.g. `-c`), or otherwise outside the model-id character set is now dropped with a stderr warning instead of being sent to Codex — which would 400 — or aborting the whole run. (#3714) diff --git a/.changeset/jolly-rams-march.md b/.changeset/jolly-rams-march.md deleted file mode 100644 index 8ae4bbf92..000000000 --- a/.changeset/jolly-rams-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3708 ---- -**New `planning inspect` query emits a schema-v1 snapshot of the whole planning state** — downstream harness UIs and dashboards can now read milestone identity, active position, per-phase verification/roadmap-acceptance/UAT evidence, requirement traceability, plan and task rows, and progress fractions from one read-only JSON document instead of parsing GSD's Markdown a second time. Unknown or conflicting evidence is reported as `unknown` with a coded diagnostic rather than inferred. (#2790) diff --git a/.changeset/jolly-ravens-travel.md b/.changeset/jolly-ravens-travel.md deleted file mode 100644 index f859b2f85..000000000 --- a/.changeset/jolly-ravens-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3896 ---- -**`generate-slug` and phase/workstream slugs no longer diverge from the canonical formula.** — Some slug-producing commands and internal call sites re-implemented the ASCII slug formula by hand instead of delegating to the shared one: Cyrillic and other non-Latin titles could collapse to an empty slug where the canonical transliterates them, and slug truncation could leave a dangling trailing hyphen (regression of #2849). Every slug call site now delegates to the single canonical implementation. (#3883) diff --git a/.changeset/jolly-yaks-click.md b/.changeset/jolly-yaks-click.md deleted file mode 100644 index 5e28ade3d..000000000 --- a/.changeset/jolly-yaks-click.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4006 ---- -**Interrupted executors can be resumed again** — execute-plan deleted `current-agent-id.txt` before the check that read it, so the interrupted-agent detection and its Task `resume` prompt were unreachable after a kill; the id is now captured before the stale marker is cleared. (#3795) diff --git a/.changeset/kind-dogs-sing.md b/.changeset/kind-dogs-sing.md deleted file mode 100644 index 6106a261e..000000000 --- a/.changeset/kind-dogs-sing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3961 ---- -**Workflow config comparisons work again for string values** — every shipped `config-get` bash call site now passes `--raw`, so string-typed values (runtime, response_language, discuss_mode, …) reach shell comparisons unquoted instead of as JSON with literal quotes that never matched. (#3763) diff --git a/.changeset/kind-eagles-rally.md b/.changeset/kind-eagles-rally.md deleted file mode 100644 index 520e07229..000000000 --- a/.changeset/kind-eagles-rally.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4048 ---- -gsd-mempalace-curator no longer hardcodes model: sonnet in its frontmatter — the only pin in the 34-agent fleet; it intercepted the deliberate inherit case (agents inherit the orchestrator model when resolution is inherit) and operators could not durably remove it. Default profiles keep sonnet via the model catalog; model_overrides and inherit now work (#3895) diff --git a/.changeset/kind-lynx-wake.md b/.changeset/kind-lynx-wake.md deleted file mode 100644 index 5e0c7a316..000000000 --- a/.changeset/kind-lynx-wake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3767 ---- -**A malformed config section no longer destroys the value it holds — or gets written back to disk.** If `.planning/config.json` had a `git` or `planning` key holding a string instead of an object, migrating a legacy top-level key into it expanded that string into numbered character keys (`"main"` became `{"0":"m","1":"a","2":"i","3":"n"}`), and the result was saved over the original file — so the value could not be recovered. Numbers and booleans were dropped outright. The migration is now declined instead: the section, the legacy key, and the file are left exactly as written, and a warning names the file so it can be fixed by hand. (#3760) diff --git a/.changeset/kind-orcas-sprint.md b/.changeset/kind-orcas-sprint.md deleted file mode 100644 index 91fb2f891..000000000 --- a/.changeset/kind-orcas-sprint.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3971 ---- -**`GSD_PROJECT`-scoped projects keep their signals and probes in their own tree** — `init manager`'s waiting signal, `map-codebase`'s dir/maps probes, `skill-manifest --write`, and `init.new-project`'s codebase-map readiness now all resolve through the project-aware planning dir instead of the repo root. (#3964) diff --git a/.changeset/kind-quails-travel.md b/.changeset/kind-quails-travel.md deleted file mode 100644 index bee0e69df..000000000 --- a/.changeset/kind-quails-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3933 ---- -**`/gsd-capture --backlog` no longer scatters backlog items across per-item branches** — `query commit`'s phase-branching arm now treats `999.x`/`0.x` backlog sentinels as non-phases, so a backlog capture commits on the current branch instead of silently creating and switching to a `gsd/phase-999.*` branch per item. (#3734) diff --git a/.changeset/kind-ravens-dart.md b/.changeset/kind-ravens-dart.md deleted file mode 100644 index 23718177e..000000000 --- a/.changeset/kind-ravens-dart.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3825 ---- -**Plans must now say what output constitutes failure** — every runnable `` acceptance command needs a `` sibling naming an observable failure signal, and `/gsd-plan-phase` blocks a plan that omits one. A command with no expressible failure mode is not an acceptance test. Breaking for phases planned before this release: re-check reports one blocker per unstated command until statements are added or the phase is re-planned. (#3172) diff --git a/.changeset/lively-geese-run.md b/.changeset/lively-geese-run.md deleted file mode 100644 index 3c0593cde..000000000 --- a/.changeset/lively-geese-run.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4042 ---- -phase add and phase add-batch now count phase numbers held by sibling git worktrees before allocating max+1, instead of colliding with them (the reported incident minted a second Phase 441 while a worktree already held one with six written plans); add-batch also now counts roadmap bullet rows (#1229 finally reaches the batch path) (#3849) diff --git a/.changeset/lively-mice-wave.md b/.changeset/lively-mice-wave.md deleted file mode 100644 index e778c94fe..000000000 --- a/.changeset/lively-mice-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3893 ---- -**Sentinel phases no longer skew estimation calibration.** Backlog and icebox phase directories (milestones 0 and 999) were counted as completed phases when rebuilding the calibration factor, so a single one could switch calibration on from phantom evidence and two could corrupt the factor outright. (#3882) diff --git a/.changeset/lively-sloths-wave.md b/.changeset/lively-sloths-wave.md deleted file mode 100644 index 293904c46..000000000 --- a/.changeset/lively-sloths-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3648 ---- -**`git.protected_branches` config field warns on additional shared branches, not just the resolved base branch** — a git-flow project whose GitHub-default branch differs from its actual integration branch (e.g. `main` vs. `develop`) can now list `develop`/`staging`/etc. so `execute-phase`'s `handle_branching` "none" strategy and `/gsd-ship`'s preflight warn on any of them, not only the one resolved base branch. Optional and additive — absent by default, existing projects see no behavior change. (#3552) diff --git a/.changeset/lucky-cats-romp.md b/.changeset/lucky-cats-romp.md deleted file mode 100644 index 752cb73cf..000000000 --- a/.changeset/lucky-cats-romp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3994 ---- -**Two QA oracles no longer report findings against the wrong field.** `routing-validity` demanded a live-command token from `recommended`, which is an action id by design, and also validated `recommended_command`, a field nothing in the repo produces; it now checks the fields that actually carry tokens. `value-hygiene` reported command tokens such as `/gsd:progress` as leaked absolute paths, and now exempts them by value shape rather than by key name, so a `command` field holding a genuine absolute path is still reported. (#3913) diff --git a/.changeset/lucky-ibex-rally.md b/.changeset/lucky-ibex-rally.md deleted file mode 100644 index bc0b5c96b..000000000 --- a/.changeset/lucky-ibex-rally.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4046 ---- -a timed-out git commit is now reported as commit_timeout with the stale .git/index.lock path surfaced in the error, instead of commit_failed with the killed hook's partial stderr; the commit call also moves to the 30s band the push call uses (pre-commit hooks alone can exceed the old 10s cap) (#3886) diff --git a/.changeset/mellow-pandas-parade.md b/.changeset/mellow-pandas-parade.md deleted file mode 100644 index 9adceda22..000000000 --- a/.changeset/mellow-pandas-parade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4001 ---- -**`/gsd-progress` no longer presents archived milestones\' verification debt as current-milestone debt** — the Verification Debt warning segments by the audit\'s `archived_milestone` stamp (current vs still-open-in-archived-mileses), keeps the archived segment visible with its own label, and no longer silently reads zero on large audits (`@file:` payload unwrap). (#3782) diff --git a/.changeset/mellow-wasps-click.md b/.changeset/mellow-wasps-click.md deleted file mode 100644 index 1f449a5b2..000000000 --- a/.changeset/mellow-wasps-click.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4025 ---- -**Acknowledged moot items stay closed in `audit-uat`** — the `audit_acknowledged` frontmatter marker (the documented, self-invalidating "this item is moot" seam) now suppresses items in `query audit-uat` exactly as it already does in `audit-open`, with the same snapshot keys and a visible `acknowledged_files` count — no more choosing between lying (`status: passed`), inventing tokens, or deleting the planning record. (#3805) diff --git a/.changeset/merry-koalas-chatter.md b/.changeset/merry-koalas-chatter.md deleted file mode 100644 index ca5ce7dae..000000000 --- a/.changeset/merry-koalas-chatter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3903 ---- -**A phase with an unreadable UAT row no longer reports an affirmative milestone completion percentage.** Previously, one specific unreadable class — UAT rows hidden inside a closed code fence — was exempted from degrading a phase's fold, so a milestone could still publish a completion percentage over work nobody could actually see. Every class of unreadable UAT content now withholds the milestone's percentages the same way. The per-phase signal is unchanged: a phase's own `uat.scope` already reported "truncated" for this case and still does. (#3707) diff --git a/.changeset/merry-orcas-parade.md b/.changeset/merry-orcas-parade.md deleted file mode 100644 index 70538ce8e..000000000 --- a/.changeset/merry-orcas-parade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3989 ---- -**`audit-open acknowledge` no longer silently strands or clobbers Title-case status lines** — a bare `Status:`/`STATUS:` marker is now acknowledged through a line the reader actually parses instead of being rewritten in place invisibly, and a human-written `Status: resolved` is left untouched rather than downgraded to `acknowledged`. (#3775) diff --git a/.changeset/mindful-otters-guard.md b/.changeset/mindful-otters-guard.md deleted file mode 100644 index 8fe460014..000000000 --- a/.changeset/mindful-otters-guard.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Security -pr: 3966 ---- -**Atomic config writes preserve hardened file permissions and create temp files exclusively** — a chmod 600 on settings.json, settings.local.json, or defaults.json now survives the temp+rename write instead of silently resetting to the umask default; temp files are opened with O_EXCL so a symlink pre-planted at the predictable temp path is never followed; and the install-migration lock writes its payload through the exclusively-created descriptor, closing a symlink-swap window between create and write. diff --git a/.changeset/nimble-cranes-rest.md b/.changeset/nimble-cranes-rest.md deleted file mode 100644 index e031a5767..000000000 --- a/.changeset/nimble-cranes-rest.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3966 ---- -**A malformed settings.local.json survives the #338 migration** — readSettings()'s null "could not parse, preserve existing" signal is now honored and the whole migration stands down, so the shared GSD entries are not stripped either. Also fixes two crashes on that path: an unparseable settings file previously aborted the install with a TypeError instead of skipping the file. diff --git a/.changeset/nimble-lynx-caper.md b/.changeset/nimble-lynx-caper.md deleted file mode 100644 index 23da170e5..000000000 --- a/.changeset/nimble-lynx-caper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4007 ---- -**The milestone audit report is written where its readers look for it** — `/gsd-audit-milestone` created the report at a doubled `.planning/v{version}-v{version}-MILESTONE-AUDIT.md` path while every downstream reference (Report pointers, the `cat`, the completion checklist) reads the single-version `v{version}-MILESTONE-AUDIT.md`, so the report silently landed unread. (#3796) diff --git a/.changeset/nimble-quails-fly.md b/.changeset/nimble-quails-fly.md deleted file mode 100644 index 70d326b7b..000000000 --- a/.changeset/nimble-quails-fly.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3680 ---- -**`check-glossary-refs` no longer reports a false clean** — backtick-pairing parity let stale file references in CONTEXT.md hide behind RULESET predicate lines, so renamed files stayed invisible to the drift gate. Visibility is now structural (per-line pairing + predicate-value harvesting), the renamed test reference is corrected, and retired-file mentions are exempted by name. (#3604) diff --git a/.changeset/noble-foxes-gather.md b/.changeset/noble-foxes-gather.md deleted file mode 100644 index 6a9d79ff0..000000000 --- a/.changeset/noble-foxes-gather.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3846 ---- -**`state update` now explains why a field was not written, instead of reporting it as absent** — asking to update a frontmatter key such as `stopped_at` returned "not found in STATE.md", byte-identical to a genuinely missing field and pointing away from the body field that does work. The refusal now names the body source, or names what derives the key when it has no body source. A document whose frontmatter carries a key with no body source at all — previously unrepairable through this command — can now be fixed by writing the key directly, reported as `wrote: "frontmatter"`. (#3699) diff --git a/.changeset/noble-lemurs-sprint.md b/.changeset/noble-lemurs-sprint.md deleted file mode 100644 index 4cae89f21..000000000 --- a/.changeset/noble-lemurs-sprint.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4018 ---- -**`local/require-registered-exit` now catches computed and optional-chained `process.exit()` calls.** The rule previously missed `process['exit']()` and `process?.[k]?.()` forms where the property name is a statically resolvable string, letting a raw terminator slip past the ADR-3889 registered-exit contract. It now resolves a computed property to a string literal (directly, or through a single never-reassigned string-literal-initialized binding) and flags those forms too. `n/no-process-exit` remains registered everywhere it already was — the two rules are complementary, not predecessor/successor, so neither is retired. (#3914) diff --git a/.changeset/patient-cranes-parade.md b/.changeset/patient-cranes-parade.md deleted file mode 100644 index 5db274f71..000000000 --- a/.changeset/patient-cranes-parade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3867 ---- -**OpenCode subagents now carry the reasoning effort GSD resolved for them** — `query resolve-execution` reported an effort level that never reached the generated OpenCode agent, so every subagent ran at whatever the runtime defaulted the model to, silently ignoring `effort` config. The bake now emits a `variant` key alongside `model`, and `effort sync` maintains it, so changing effort config no longer needs a reinstall. The key is written only when effort is actually configured; `inherit` and any level OpenCode does not accept omit it rather than naming a variant that cannot resolve. Config-supplied `model` and `variant` values are also quoted whenever YAML would not read them back verbatim — previously a value containing a newline could inject extra top-level keys into a generated agent file, and values like `no`, `12:30`, `@org/model` or a bare date were silently retyped or truncated. (#3706) diff --git a/.changeset/patient-elks-glide.md b/.changeset/patient-elks-glide.md deleted file mode 100644 index 8acffccaa..000000000 --- a/.changeset/patient-elks-glide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4059 ---- -**Raised the emitted-drift acknowledgment cap from 64 to 128** — a wide-touching maintenance PR could legitimately accumulate more distinct commit-trailer acknowledgments than the old ceiling allowed, failing CI even though nothing was wrong. (#4058) diff --git a/.changeset/patient-jaguars-frolic.md b/.changeset/patient-jaguars-frolic.md deleted file mode 100644 index ec0c91e38..000000000 --- a/.changeset/patient-jaguars-frolic.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3888 ---- -**`gsd-tools --project-dir ` now works** — the flag was documented in docs/CONFIGURATION.md's multi-repo workspace resolution section but wired nowhere, so it was silently ignored and every command still resolved the project root from cwd. Passing `--project-dir` now sets the project root directly and skips the ancestor walk-up, as documented. (#3881) diff --git a/.changeset/patient-koalas-roar.md b/.changeset/patient-koalas-roar.md deleted file mode 100644 index 25be33c78..000000000 --- a/.changeset/patient-koalas-roar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3695 ---- -**Code review depth can now be scoped by repository path** — set `workflow.code_review_depth_overrides` to a list of `{paths, depth}` rules and a review touching a sensitive directory such as `src/auth` automatically runs at the stronger tier, while the rest of the repository keeps the standard depth. Paths are matched as directory prefixes on whole path segments (glob syntax is rejected with a clear configuration error), `--depth=` still wins, and the resolved depth and the rule that matched are printed in the review output. (#2554) diff --git a/.changeset/patient-sloths-glide.md b/.changeset/patient-sloths-glide.md deleted file mode 100644 index 9176a7553..000000000 --- a/.changeset/patient-sloths-glide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4028 ---- -**`state advance-plan` refuses an ambiguous Current Position instead of silently advancing the first entry** — when the section carries more than one `Phase:` line (the wave-log style), the command now returns a typed `ambiguous_position_phase` error naming every candidate and leaves STATE.md byte-identical, instead of silently advancing the first entry's plan counter (in the reporting incident, a hard-gated final plan 7→8 of 8) with `advanced: true` and no ambiguity signal. (#3807) diff --git a/.changeset/patient-zebras-climb.md b/.changeset/patient-zebras-climb.md deleted file mode 100644 index 10961d04d..000000000 --- a/.changeset/patient-zebras-climb.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3832 ---- -**Every reviewer lane can now be given a prompt-token cap, and the documented global `review.max_prompt_tokens` finally works** — the nine CLI reviewer lanes declared no budget key, so no cap could reach them by any configuration, and the central global was advertised in the config schema but declared nowhere, so setting it changed nothing. Each CLI lane now accepts `review.max_prompt_tokens_per_reviewer.` on the same terms as the local-server lanes, and the global resolves as the documented fallback. Defaults are unchanged: with nothing configured, no lane trims. (#3691) diff --git a/.changeset/plucky-birds-hum.md b/.changeset/plucky-birds-hum.md deleted file mode 100644 index 4a0f55397..000000000 --- a/.changeset/plucky-birds-hum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3966 ---- -**The installer writes settings.json and settings.local.json atomically (temp+rename)** — a crash mid-write can no longer truncate the file. Hosts discard the entire settings file on a parse failure, so a truncated write previously cost users every hook, permission, env var, and statusline they had — not just GSD's. diff --git a/.changeset/plucky-hawks-sing.md b/.changeset/plucky-hawks-sing.md deleted file mode 100644 index 7bad0cb91..000000000 --- a/.changeset/plucky-hawks-sing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3944 ---- -**The API-coverage seal gate no longer clears a phase it never examined** — a phase with no plan body and no roadmap section previously ran the detector over zero bytes and sealed as "no external-API integration"; it is now held with `scope_unavailable`, and the assumption-delta checkpoint reports `skipped` instead of a fabricated `detected:false` when it cannot resolve a phase section. (#3909) diff --git a/.changeset/plucky-koalas-snooze.md b/.changeset/plucky-koalas-snooze.md deleted file mode 100644 index 148e1dada..000000000 --- a/.changeset/plucky-koalas-snooze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3687 ---- -**Capability hooks can no longer be silently registered-but-never-run** — the capability validator now checks that each host call site's dispatch text covers every hook KIND registered at that point (a gate-only consumer fails validation when a step or contribution hook is registered there), and the plan/execute/verify host consumers now dispatch steps and contributions generically per the loop hook contract instead of hand-rolling one kind. (#3606) diff --git a/.changeset/plucky-moles-purr.md b/.changeset/plucky-moles-purr.md deleted file mode 100644 index caf37a02c..000000000 --- a/.changeset/plucky-moles-purr.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3718 ---- -**The phase researcher no longer treats missing metadata as a compatibility constraint** — a claim like "this library does not support that runtime version", drawn from an absent `python_requires`, `engines` field, per-version classifier, changelog entry, or support-matrix row, no longer earns `[VERIFIED]` however authoritative the registry or docs consulted. An absence says nothing about the version being ruled out and nothing about the version being standardized on, so the same evidence would "prove" both; the only route from an absence to `[VERIFIED]` is a positive falsification attempt with its failing output pasted, and everything short of that stays `[ASSUMED]`, which already routes through a confirmation checkpoint before it can lock a decision. A present declared constraint and an affirmatively documented incompatibility are untouched. Previously an honestly-tagged absence could lock a CONTEXT.md decision and produce a real version downgrade that no downstream stage re-derived. (#2951) diff --git a/.changeset/plucky-pandas-roam.md b/.changeset/plucky-pandas-roam.md deleted file mode 100644 index d9822e407..000000000 --- a/.changeset/plucky-pandas-roam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 4043 ---- -**CI shard/job timeouts now self-report near-cap and accumulate a trending history.** Every matrixed CI job (test, test-full, mutate, smoke) warns in its own run once it crosses 90% of its timeout-minutes budget, and a new scheduled workflow keeps a durable, accumulating record of elapsed-vs-cap across runs — so a lane drifting toward its cap is visible before it actually breaches, not just after. (#4036) diff --git a/.changeset/plucky-pandas-wave.md b/.changeset/plucky-pandas-wave.md deleted file mode 100644 index 7c773a285..000000000 --- a/.changeset/plucky-pandas-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3978 ---- -**Reduced the complexity of the refactor-trigger evaluate handler.** `handleEvaluate` scored above the complexity-triggered-refactor feature's own default threshold; the read/analyze loop and the artifact/baseline/ledger write path are now separate named helpers, with no change to CLI behavior, output shape, or reason codes. (#3267) diff --git a/.changeset/proud-sloths-cheer.md b/.changeset/proud-sloths-cheer.md deleted file mode 100644 index c72d65a92..000000000 --- a/.changeset/proud-sloths-cheer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4015 ---- -**A killed test chunk now names the file that was hanging.** `scripts/run-tests.cjs` logged only chunk starts, so a chunk killed at the 600s cap printed ~55 basenames and left the operator to guess which one hung — and every timing figure had to be reconstructed from CI log timestamps. It now emits per-chunk elapsed time on every path, names the files still in flight on a kill with how stale the last event is (hang vs. merely slow), and ranks the chunk by known weight, flagging files missing from the timings table. (#4012) diff --git a/.changeset/proud-sloths-frolic.md b/.changeset/proud-sloths-frolic.md deleted file mode 100644 index a96ac1a4b..000000000 --- a/.changeset/proud-sloths-frolic.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3823 ---- -**A merged acknowledgment fragment no longer hard-blocks a later PR that grows the same workflow.** The `guard-no-ack-on-next` job only ever watched the legacy `tests/emitted-drift-ack.json`, on the premise that per-PR fragments cannot conflict. They do not share a file, but they do share a path key space — so a fully-spent fragment on `next` kept owning paths it could no longer gate, and the next PR to touch one of them could declare it neither there nor in its own fragment. The guard now sweeps fully-spent fragments, the duplicate-ack error names both resolutions, and the 45 spent fragments on `next` are removed. (#3078) diff --git a/.changeset/quick-bears-cheer.md b/.changeset/quick-bears-cheer.md deleted file mode 100644 index 8a5b718e1..000000000 --- a/.changeset/quick-bears-cheer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4063 ---- -**Local test runs no longer fail on machines with a global core.hooksPath** — the commit-docs-guard suites refused to install their pre-commit hook in every fresh fixture repo (18 tests read as a guard regression); the suites now pin GIT_CONFIG_GLOBAL to an empty file so children never inherit the host git config (#3901) diff --git a/.changeset/quick-dogs-munch.md b/.changeset/quick-dogs-munch.md deleted file mode 100644 index 28d21482d..000000000 --- a/.changeset/quick-dogs-munch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3723 ---- -**`roadmap validate` and `roadmap milestone-scope` now see bracket-convention phase entries (`### [GSD.04] 01:`)** — with `phase_id_convention: "bracket"` set, a genuinely truncated milestone window warned as nothing (V005 could never fire) while V004 falsely reported "no recognizable phase entries". Both now resolve the convention (config.json, ROADMAP frontmatter fallback) and route V004 through the shared entry predicate, so validate and the milestone-scope probe agree. Bracket milestone headings (`[GSD.02] Name`, no digit token) never count as entries. (#3641) diff --git a/.changeset/quick-foxes-click.md b/.changeset/quick-foxes-click.md deleted file mode 100644 index b8760c0bc..000000000 --- a/.changeset/quick-foxes-click.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3977 ---- -**Package-legitimacy-gate tests no longer silently drop malformed table rows.** The test suite's markdown-table parsing now reuses the ADR-2143 seam instead of two hand-rolled copies, so a ragged row or an escaped-pipe cell fails loudly instead of being silently mis-parsed. (#3239) diff --git a/.changeset/quick-mice-hop.md b/.changeset/quick-mice-hop.md deleted file mode 100644 index b83886915..000000000 --- a/.changeset/quick-mice-hop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3983 ---- -**Pending-outcome cell no longer leaks across calls in one process.** A CLI run that calls `output()` with a payload-carried error and later returns cleanly, or that runs a second `main()` in the same process, could inherit a stale DEGRADED exit code (80 under the v2 exit contract) from an earlier declaration. The cell now follows last-write-wins semantics and is cleared on consumption. (#3912) diff --git a/.changeset/rapid-ibex-sprint.md b/.changeset/rapid-ibex-sprint.md deleted file mode 100644 index bb29d4ac3..000000000 --- a/.changeset/rapid-ibex-sprint.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3755 ---- -**An unevidenced lone reviewer finding no longer forces an extra replan cycle** — with two or more reviewers running, `/gsd-plan-review-convergence` now weighs a single reviewer's HIGH by what it claims: an existence claim about a symbol, file or ID must be source-grounded or corroborated, while a design finding still counts on its own unless that reviewer cited no source evidence anywhere in its review. Findings that stop counting stay visible, tagged rather than dropped, and single-reviewer runs are unchanged. A design finding from a reviewer that did cite evidence still counts alone — deliberately, so that a real architectural concern only one reviewer noticed keeps blocking. (#2398) diff --git a/.changeset/rapid-lemurs-click.md b/.changeset/rapid-lemurs-click.md deleted file mode 100644 index 6493f4cf8..000000000 --- a/.changeset/rapid-lemurs-click.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3917 ---- -**A `scripts/`-side tool that fails unexpectedly under `--json-errors` now emits the documented `{ok:false, reason, message}` envelope** — it previously printed a raw stack trace, because the exit module under `scripts/` was a second hand-written copy that never gained the structured-error branch its `src/` twin has. The copy is now generated from one source and byte-compared in CI, so the two cannot drift again. (#3904) diff --git a/.changeset/rapid-quails-sing.md b/.changeset/rapid-quails-sing.md deleted file mode 100644 index 21d90bf99..000000000 --- a/.changeset/rapid-quails-sing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3736 ---- -**Worktree executors no longer fork from the wrong base on long-lived branches** — `worktree.baseRef:"head"` no longer silences the pre-dispatch base check on harness-managed runtimes: the check now compares HEAD against the actual fork base and auto-degrades to sequential execution before dispatch when they diverge, instead of letting every isolated executor die at the exit-42 guard. The suppress now applies only where GSD itself creates worktrees (where the setting is honored by construction). (#3659) diff --git a/.changeset/rapid-tunas-leap.md b/.changeset/rapid-tunas-leap.md deleted file mode 100644 index 97169faae..000000000 --- a/.changeset/rapid-tunas-leap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3887 ---- -**`audit-uat` no longer reports a clean result for UAT files it silently failed to read.** A phase with three outstanding tests reported zero and then vanished from the report entirely, so nothing cued the reader to go and look. Rows using the template's own `result: issue` outcome, or any wrapped or `expected: |` block-scalar description, were dropped — the second kind was never matched at all, so its result was never read whatever it said. A result token the parser does not recognize is now surfaced rather than discarded, uppercase tokens (`PENDING`, `Blocked`) categorize correctly, a result line with trailing text (`result: pending (blocked on staging)`) is matched again, and an interleaved `## Gaps` section no longer bleeds its reason onto the preceding row. A file whose blocks genuinely fail to parse is reported as a parse gap and counted, so `audit-uat` and `progress` stop declaring all-clear over it — including files in archived milestones, which can still hold a deferred scenario someone left open. (#3707) diff --git a/.changeset/rapid-wasps-sing.md b/.changeset/rapid-wasps-sing.md deleted file mode 100644 index 9e40f938b..000000000 --- a/.changeset/rapid-wasps-sing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4005 ---- -**`/gsd-quick` no longer authorizes edit/verification scope from historical state** — when scope depends on mutable external state (a fresh merge index, PR diffs, the working tree), the planner must observe it live or keep the plan's scope conditional; cached PR-diff paths and stale recovery notes are investigation guidance only, so a merge-conflict task can no longer provisionally "authorize" 65 historical paths. (#3786) diff --git a/.changeset/serene-bears-dance.md b/.changeset/serene-bears-dance.md deleted file mode 100644 index 10404b93d..000000000 --- a/.changeset/serene-bears-dance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3975 ---- -**CONTEXT.md seam claims are now checkable.** New `SEAM..owns`/`SEAM..enforced-by` predicates plus a `lint:ci` gate (`scripts/lint-seam-enforcement.cjs`) fail the build when a declared single-owner seam names no existing, registered lint rule or test file, so a seam claim can no longer silently decay into an unenforced assertion. (#3626) diff --git a/.changeset/serene-goats-roam.md b/.changeset/serene-goats-roam.md deleted file mode 100644 index 39ab3942a..000000000 --- a/.changeset/serene-goats-roam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3745 ---- -**UI-SPEC component inventories now record how they were produced** — a spec that lists the components a design system offers must name the command that enumerated them, the count it returned, the resolved package version and the date. `gsd-ui-checker` gains a seventh dimension that reports an inventory with no such line as a defect and downgrades it from a closed allowlist to a non-exhaustive list of known-good components, so an executor is never blocked from a component the spec merely failed to mention. (#2845) diff --git a/.changeset/serene-goats-sprint.md b/.changeset/serene-goats-sprint.md deleted file mode 100644 index 68e7e4a5f..000000000 --- a/.changeset/serene-goats-sprint.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4064 ---- -**The packaging guard stays armed on npm 12 (Node 26)** — npm 12 emits pack --json as an object keyed by package name, so parsed[0] was undefined, the before() hook threw, and all 6 packaging-guard tests (including both does-NOT-ship gates) went dark for Node 26 contributors (#3902) diff --git a/.changeset/serene-orcas-glide.md b/.changeset/serene-orcas-glide.md deleted file mode 100644 index bd55eeaba..000000000 --- a/.changeset/serene-orcas-glide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3954 ---- -**Emitted-drift acknowledgments move from a committed file to a commit trailer.** A PR that legitimately ripples emitted-artifact bytes now declares it with an `Emitted-Drift-Ack-Hash:` or `Emitted-Drift-Ack-Growth:` trailer on one of its own commits instead of adding a JSON fragment under `tests/emitted-drift-acks/`. The acknowledgment was only ever valid for the life of the PR, so keeping it in the working tree meant every merged one became cruft that had to be detected and garbage-collected; the trailer leaves nothing behind and cannot conflict. Removes the shipped `scripts/lint-emitted-drift-ack.cjs`, the scheduled sweep workflow, and the `guard-no-ack-on-next` job. (#3942) diff --git a/.changeset/sharp-cranes-wander.md b/.changeset/sharp-cranes-wander.md deleted file mode 100644 index 8d749e002..000000000 --- a/.changeset/sharp-cranes-wander.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3878 ---- -**`state.*` commands now report every field they actually changed, and only those** — the `updated` array is derived by diffing what was persisted against the pre-write state, so a counter the write genuinely moved is no longer suppressed, a field the write merely preserved is no longer claimed as an update, and a changed sub-counter is named at leaf granularity (`progress.total_plans`) instead of being dropped. Callers that compared the array exactly will see more, and truer, entries. (#3872) diff --git a/.changeset/sharp-deer-forage.md b/.changeset/sharp-deer-forage.md deleted file mode 100644 index 34ffa6341..000000000 --- a/.changeset/sharp-deer-forage.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3731 ---- -**Orphaned GSD hooks in `~/.kimi` can now be reclaimed** — a `--kimi-code` install older than 1.10.0 wrote its hooks block, hook bundle and CommonJS marker into Kimi CLI's `~/.kimi` instead of Kimi Code's own root, and upgrading stranded those artifacts with no path to remove them. Adding `--reclaim-kimi-legacy` to a `--kimi-code` install now clears them; it stays opt-in because the stale block is byte-identical to a legitimate Kimi CLI one, so an automatic cleanup could not tell the two apart. (#3031) diff --git a/.changeset/sharp-foxes-tumble.md b/.changeset/sharp-foxes-tumble.md deleted file mode 100644 index 98d344b0b..000000000 --- a/.changeset/sharp-foxes-tumble.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3983 ---- -**Global flags now work in any argv position, including before `run-with-timeout`.** Passing `--exit-contract=` before the subcommand — `gsd-tools --exit-contract=v2 state validate` — failed with `Error: Unknown command: --exit-contract=v2`, because the token was read for version resolution but never removed from argv, so the dispatcher treated it as the command name. Separately, `gsd-tools --json-errors run-with-timeout ...` failed with `Unknown command: run-with-timeout` and never ran the child, because `run-with-timeout` is intercepted before the flag is stripped. Both flags are now resolved and stripped ahead of that interception, and `--exit-contract` is listed in `gsd-tools --help`. (#3912) diff --git a/.changeset/sharp-seals-run.md b/.changeset/sharp-seals-run.md deleted file mode 100644 index 60093f7f9..000000000 --- a/.changeset/sharp-seals-run.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3793 ---- -**The stale-worktree health check no longer flags the worktree you are currently in on Windows** — paths that differ only by drive-letter or folder casing (as-typed vs git's canonical spelling) are now recognized as the same directory on Windows, while case-sensitive comparison is preserved on macOS/Linux. (#3663) diff --git a/.changeset/silly-finches-squeak.md b/.changeset/silly-finches-squeak.md deleted file mode 100644 index 25bd78049..000000000 --- a/.changeset/silly-finches-squeak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3960 ---- -**Every GSD enforcement hook now declares its crash policy.** Hooks used to end their outer catch with a bare `process.exit(0)` or `process.exit(2)`, so whether a hook fails open or closed on its own bug was invisible without reading its source; hooks now terminate through `allow`/`deny`/`crash` and declare a required `ON_CRASH` policy, with no change to any hook's effective exit code. Also fixes #3838: `gsd-validate-commit.sh`'s config/JSON/git-subcommand checks no longer treat "could not run" the same as a genuine negative — a failed check now says so on stderr instead of silently allowing every commit. (#3911) diff --git a/.changeset/silly-yaks-fly.md b/.changeset/silly-yaks-fly.md deleted file mode 100644 index 07cf0838f..000000000 --- a/.changeset/silly-yaks-fly.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3810 ---- -**Completing a phase with `features.global_learnings` enabled now produces the phase's LEARNINGS.md automatically and copies it to the global store** — previously three shipped consumers read an artifact nothing ever generated, and the copy command read a project-root path the extractor never wrote, so the store stayed empty even after manual extraction. Extraction and copy failures never block completion; with the gate off (the default) behavior is unchanged. (#3683) diff --git a/.changeset/steady-foxes-rest.md b/.changeset/steady-foxes-rest.md deleted file mode 100644 index 75b107720..000000000 --- a/.changeset/steady-foxes-rest.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3869 ---- -**Capabilities can now do work before UAT, not only block it** — the `verify:pre` extension point dispatched gate hooks only, so a capability declaring a step or contribution there was rejected at registry-build time and the whole verify lane was closed to anything that wanted to contribute to what UAT covers. It now dispatches contribution, step, and gate hooks, and `extract_tests` additively consumes the artefacts those steps declare via `produces`. (#3866) diff --git a/.changeset/steady-otters-roar.md b/.changeset/steady-otters-roar.md deleted file mode 100644 index ae4336854..000000000 --- a/.changeset/steady-otters-roar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4017 ---- -**`STATE.md`'s `## Current Position` section now documents that its fields are single-valued.** The section is overwritten rather than appended to, and a duplicated `Phase:` line does not simply resolve to the first occurrence — it resolves by form first (bold, then plain, then pipe-table), scoped to the `## Current Position` section, and only within the winning form does the first occurrence win. So a bold line added in good faith after an earlier plain line silently overrides it rather than being ignored. That behavior was always true and was never written down, which is what #3812 reported. Progress history belongs in `## Performance Metrics`, and the reference page now says so in all five languages. (#3812) diff --git a/.changeset/steady-zebras-leap.md b/.changeset/steady-zebras-leap.md deleted file mode 100644 index dbdd59d6a..000000000 --- a/.changeset/steady-zebras-leap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3713 ---- -**The spec-phase edge probe now classifies requirements in non-English projects** — a project running with `response_language` set had every requirement fall through the English-only shape cues into `unclassified`, silently disabling the whole edge taxonomy; Step 5.5 now feeds the probe an English translation of each requirement while the SPEC keeps its original language. (#2773) diff --git a/.changeset/sturdy-deer-frolic.md b/.changeset/sturdy-deer-frolic.md deleted file mode 100644 index 8755d9aa5..000000000 --- a/.changeset/sturdy-deer-frolic.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3920 ---- -**Exit codes are now allocated from one registry instead of invented per module** — a generated table records every non-standard exit code with its meaning, owning module and authorizing decision, and the build fails if two modules claim the same number or a code lands in a range Node or the shell reserves. Nothing emits a registered code yet; this is the allocator the following phases draw from. (#3905) diff --git a/.changeset/sturdy-dogs-hop.md b/.changeset/sturdy-dogs-hop.md deleted file mode 100644 index 125000e69..000000000 --- a/.changeset/sturdy-dogs-hop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4047 ---- -workflow.research_before_questions now works on /gsd:quick (research runs before discussion questions when enabled — a gray-area answer without research becomes a locked decision in the quick task context) and resolves from ~/.gsd/defaults.json like its sibling workflow.post_planning_gaps, which the global-defaults merge previously forwarded while silently dropping this key (#3894) diff --git a/.changeset/sturdy-eagles-leap.md b/.changeset/sturdy-eagles-leap.md deleted file mode 100644 index cd9270a4d..000000000 --- a/.changeset/sturdy-eagles-leap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3828 ---- -**Trailing prose below the ledger's JSON block is no longer destroyed when that prose contains its own fenced JSON array** — `writeLedgerAtomic` located the block to preserve prose after by passing the POST-mutation entry count as its disambiguation hint, which can never match the pre-image's own count. The lookup fell back to the last array-shaped fenced block in the file, so an operator's notes containing a ```json array bound the preservation to the wrong fence and everything above it was dropped on the next write — the exact loss the preservation exists to prevent. (#3689) diff --git a/.changeset/sturdy-eagles-wave.md b/.changeset/sturdy-eagles-wave.md deleted file mode 100644 index 31b19c611..000000000 --- a/.changeset/sturdy-eagles-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3994 ---- -**A generated exit-code reference at `docs/reference/exit-codes.md`.** Every registered exit code now has a page giving its number, name, meaning and owning band, alongside why `0` and `1` are unallocatable and why `3`-`13` are reserved by Node — so a `69` in a CI log has somewhere to be looked up. The page is generated from the same declaration the registry itself is built from and is `--check`-gated against drift. (#3913) diff --git a/.changeset/sturdy-jaguars-munch.md b/.changeset/sturdy-jaguars-munch.md deleted file mode 100644 index 553ec2582..000000000 --- a/.changeset/sturdy-jaguars-munch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3855 ---- -**The identity classifier and the launcher preamble now reach the same verdict for the same probe** — the two surfaces implement one decision and disagreed on two inputs, a tool that proves itself and then exits non-zero and a payload naming this package outside the anchored wire shape, so the announced hard-fail rollout would have refused installs the warn phase verifies and accepted ones it warns about. (#3841) diff --git a/.changeset/sturdy-otters-chatter.md b/.changeset/sturdy-otters-chatter.md deleted file mode 100644 index 70bd6d0e2..000000000 --- a/.changeset/sturdy-otters-chatter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3938 ---- -**`workflow.use_worktrees=false` now actually wins for executor dispatch** — `query dispatch-isolation` folds the project opt-out into the isolation sentinel it records, so a plain re-query can no longer re-persist the host's worktree capability over the mandated `none` record and have the isolation guard deny the sequential dispatch the project configured. (#3737) diff --git a/.changeset/sturdy-sloths-roar.md b/.changeset/sturdy-sloths-roar.md deleted file mode 100644 index b99e87298..000000000 --- a/.changeset/sturdy-sloths-roar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3918 ---- -**Global Claude installs now load agent-file `@`-includes** — agent files in a global Claude install (e.g. the planner) carried `@`-includes that silently loaded nothing, so guidance those agents were supposed to read — including the untrusted-input boundary — was absent from their context; those includes now resolve on `~/`. Also fixes a related path-rewrite bug where a `--config-dir` name extending `.claude` (e.g. `.claude-work`) doubled its own suffix in agent-file paths. (#3719) diff --git a/.changeset/sunny-elks-dart.md b/.changeset/sunny-elks-dart.md deleted file mode 100644 index 83f4ff926..000000000 --- a/.changeset/sunny-elks-dart.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3794 ---- -**Installing with --config-dir into a directory that already holds another harness's agent files now warns instead of failing silently** — the installer says the emitted artifacts are shaped for the selected runtime and their tool IDs and MCP grants may be inert or invalid for the destination harness, then proceeds. Fresh custom directories and GSD-only directories stay silent. (#3664) diff --git a/.changeset/sunny-foxes-click.md b/.changeset/sunny-foxes-click.md deleted file mode 100644 index 413dacbef..000000000 --- a/.changeset/sunny-foxes-click.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3874 ---- -**Curated STATE.md content survives writes that measured nothing** — `state record-session`, `state add-decision` and the other resyncing verbs no longer drop a curated `progress:` block once a milestone's phases have been archived, `state planned-phase` without `--name` no longer overwrites `current_phase_name` with a placeholder, `state complete-phase` no longer deletes that key while reporting it as updated, and `state json` no longer serves `last_activity_desc` from stale body prose. (#3871) diff --git a/.changeset/sunny-herons-hum.md b/.changeset/sunny-herons-hum.md deleted file mode 100644 index f38fe2d9b..000000000 --- a/.changeset/sunny-herons-hum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3940 ---- -**`audit-open acknowledge` no longer reports success on an entry it did not clear** — acknowledging a deferred item whose status is written as a nested list line now records a status the reader actually parses, so acknowledged entries drop out of audit counts instead of resurfacing forever. (#3740) diff --git a/.changeset/sunny-seals-munch.md b/.changeset/sunny-seals-munch.md deleted file mode 100644 index 1839b9e1c..000000000 --- a/.changeset/sunny-seals-munch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3955 ---- -**`migrate-config` and health repairs no longer write outside the scoped project under `GSD_PROJECT`** — planning-path composition now goes through the project-aware resolver everywhere, so a scoped migration no longer rewrites another project's `config.json`, `project_exists` answers for the project actually being queried, and `validate.health --repair` keeps its writes in one directory. (#3749) diff --git a/.changeset/tidy-birds-march.md b/.changeset/tidy-birds-march.md deleted file mode 100644 index 9c809103e..000000000 --- a/.changeset/tidy-birds-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3390 ---- -**Interactive runs no longer stop for a checkpoint after every tracer task** — under the `end-of-phase` default a tracer whose `` is automated-only is re-run and expansion continues with no `checkpoint:human-verify`; `mid-flight`, tracers carrying ``, and any tracer carrying `gate="blocking-human"` still stop for a human, and a failing tracer still halts. (#3299) diff --git a/.changeset/tidy-finches-dance.md b/.changeset/tidy-finches-dance.md deleted file mode 100644 index 07cbb101b..000000000 --- a/.changeset/tidy-finches-dance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3856 ---- -**Managed hooks no longer bake a prunable fnm version path on macOS and Linux** — `normalizeNodePath` matched only fnm's shim, but Node resolves `process.execPath` through that symlink to the concrete `node-versions//installation/bin/node` directory, so the branch never fired on POSIX and every managed hook was pinned to one Node version. `fnm uninstall` or fnm's own pruning then broke all of them. The versioned path now rewrites to the stable `aliases/default` path, matching how the Homebrew, mise and volta branches already behave. (#3704) diff --git a/.changeset/tidy-finches-wave.md b/.changeset/tidy-finches-wave.md deleted file mode 100644 index 51a29fed7..000000000 --- a/.changeset/tidy-finches-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3937 ---- -**A security scanner that cannot compute a diff now fails instead of reporting clean** — `secret-scan`, `base64-scan` and `prompt-injection-scan` previously exited 0 for a bad ref, a missing repository, or a repository with no commits, which is indistinguishable from a genuine all-clear to any CI gate. They now distinguish four outcomes: scanned clean, nothing was in scope, could not establish scope, and findings. The security workflow treats nothing-in-scope as a pass and could-not-scan as a failure. (#3908) diff --git a/.changeset/tidy-hawks-roar.md b/.changeset/tidy-hawks-roar.md deleted file mode 100644 index a2f5c3b86..000000000 --- a/.changeset/tidy-hawks-roar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3857 ---- -**A fully-spent ack fragment is no longer swept out from under an open pull request that changes more than 100 files** — `gh pr list --json files` truncates each PR file list at 100, so the fragment read as untouched and deleting it handed that PR the modify/delete conflict the staged sweep exists to prevent. (#3842) diff --git a/.changeset/tidy-otters-squeak.md b/.changeset/tidy-otters-squeak.md deleted file mode 100644 index 376016359..000000000 --- a/.changeset/tidy-otters-squeak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4009 ---- -**Tiered profiles install the agents their own skills spawn** — the profile closure now follows each command into the workflow files it references (including split workflows' steps/ and modes/ fragments) when deriving the agent set, so `--profile=standard` no longer omits `gsd-verifier` (phase-goal verification failed at the point of spawn, after execution work had landed) or the thirteen other spawn targets living only in workflow bodies. (#3798) diff --git a/.changeset/vivid-lynx-zip.md b/.changeset/vivid-lynx-zip.md deleted file mode 100644 index 14e3fd89b..000000000 --- a/.changeset/vivid-lynx-zip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4062 ---- -local test runs no longer fail when a daemon keeps a unix socket under the repo root — the overlay builder classified every non-directory entry as a file, so copyFileSync threw ENXIO and 32 tests failed in their before() hooks with no connection to the code under test (#3900) diff --git a/.changeset/vivid-pumas-squeak.md b/.changeset/vivid-pumas-squeak.md deleted file mode 100644 index 5656395bd..000000000 --- a/.changeset/vivid-pumas-squeak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 4037 ---- -gsd-ingest-docs new mode now requires an explicit routing approval (Create planning setup | Keep synthesized intel only | Abort) before creating the planning scaffold — approving document classification no longer also authorizes scaffold creation and commit (#3827) diff --git a/.changeset/wise-otters-greet.md b/.changeset/wise-otters-greet.md deleted file mode 100644 index e17afc127..000000000 --- a/.changeset/wise-otters-greet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3765 ---- -**Codex reasoning effort is now resolved per model, and every clamp is visible** — `max` reaches Codex instead of being silently downgraded to `xhigh`, `minimal` clamps up to `low` instead of being sent to models that reject it, and `resolve-execution` reports the level you asked for alongside the one actually rendered. `ultra` is refused outright because it switches Codex into proactive task delegation underneath GSD's own orchestration. (#3007) diff --git a/.changeset/wise-rams-travel.md b/.changeset/wise-rams-travel.md deleted file mode 100644 index d74c6ae9c..000000000 --- a/.changeset/wise-rams-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3757 ---- -**A plan that declares a file removal can now be merged by cleanup-wave** — add a `files_deleted:` list to a plan's frontmatter and the post-wave deletions guard authorizes exactly those paths, so a refactor that folds one file into another stops needing a manual merge outside the tool. Anything the plan did not declare still blocks that entry, and only that entry. Plans and manifests without the field behave exactly as before. (#3003) diff --git a/.changeset/witty-goats-purr.md b/.changeset/witty-goats-purr.md deleted file mode 100644 index 2c45fe194..000000000 --- a/.changeset/witty-goats-purr.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 4000 ---- -**Capabilities can now source a task's content from an external issue tracker.** A capability that declares a `taskContentResolver` for a tracker prefix lets a plan's `tracker-id` attribute resolve the task's action, verify, acceptance criteria, and done text from that external tracker at execution time instead of PLAN.md, and any resolution failure — ambiguous match, non-zero exit, timeout, or malformed output — hard-halts rather than silently falling back. (#3970) diff --git a/.changeset/witty-ibex-frolic.md b/.changeset/witty-ibex-frolic.md deleted file mode 100644 index ea6cfe76c..000000000 --- a/.changeset/witty-ibex-frolic.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3698 ---- -**Bracket-convention icebox and pre-milestone directories no longer produce spurious health warnings** — the disk-side guards could not see bracket sentinel-ness (it lives in the milestone portion of `GSD.999-07-icebox`), so icebox dirs false-fired as roadmap orphans. A dir-aware sentinel recognizer now excludes them exactly like their legacy twins. (#3639) diff --git a/.changeset/witty-lynx-sing.md b/.changeset/witty-lynx-sing.md deleted file mode 100644 index a366bbdf1..000000000 --- a/.changeset/witty-lynx-sing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3851 ---- -**A feature fragment declaring a malformed `order:` no longer sorts silently to the top of `docs/FEATURES.md`** — the generator validated that field by coercion, so an empty value read as `0` and hex, octal, binary and exponential values read as numbers, all placing the section ahead of every real feature with no violation and a clean `--check`. (#3840) diff --git a/.changeset/witty-tigers-romp.md b/.changeset/witty-tigers-romp.md deleted file mode 100644 index 48b800161..000000000 --- a/.changeset/witty-tigers-romp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 3845 ---- -**`docs/FEATURES.md` is now generated from per-feature fragments** — a feature no longer hand-allocates a section number or hand-edits the table of contents, the two cells that made almost every concurrent feature PR conflict; contributors add one file under `docs/features/` with any unique `id` and regenerate. (#3840) diff --git a/.changeset/zesty-ibex-chatter.md b/.changeset/zesty-ibex-chatter.md deleted file mode 100644 index e9318f57a..000000000 --- a/.changeset/zesty-ibex-chatter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 3693 ---- -**`verify plan-structure` no longer false-flags positively-asserted literals in entity-escaped verify chains** — planners emit `&&` as the chain operator, which the negative-grep gate's segment splitter did not recognize, so a `= 0` clause poisoned `-ge 3` clauses joined to it and pushed authors toward suppressing a real gate. The gate now scans the decoded text the shell would actually run. (#3611) diff --git a/.changeset/zesty-sloths-sprint.md b/.changeset/zesty-sloths-sprint.md deleted file mode 100644 index 3476c8b5f..000000000 --- a/.changeset/zesty-sloths-sprint.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 3822 ---- -**`/gsd-review` can now dispatch reviewer lanes concurrently** — a multi-reviewer pass cost roughly the sum of its lanes even though every lane inspects the same immutable plan snapshot and none depends on another. Set `review.parallel_lanes` to `true` to overlap them within a single pass; the default stays sequential and keeps the provider-rate-limit protection, and convergence cycles stay sequential either way. This also corrects `docs/COMMANDS.md`, which described `--all` as running every configured reviewer in parallel when dispatch was in fact sequential. (#3034) diff --git a/.changeset/zesty-yaks-hop.md b/.changeset/zesty-yaks-hop.md deleted file mode 100644 index 40dda8736..000000000 --- a/.changeset/zesty-yaks-hop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Removed -pr: 3932 ---- -Removed the hand-written root bin/lib/ui-safety-gate.cjs — the GSD installer and every shipped workflow only ever resolved gsd-core/bin/lib/ui-safety-gate.cjs, so the root copy was unused dead code. diff --git a/CHANGELOG.md b/CHANGELOG.md index 80c23e866..5436db55a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,177 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] +## [1.12.0] - 2026-08-30 + +### Added + +- **Verify-command path grounding for phase planning** — a plan's `` verify command whose target directory does not exist (or holds no `package.json`) is now caught deterministically before execution instead of being hand-reasoned by the plan checker, which previously prescribed wrong replacement paths. The planner also inherits the nearest prior phase's proven verify commands at every context window, not only above 500k. (#2401) (#3678) +- **Live-DOM UAT: browser-backed UI acceptance checks during execution** — a phase whose acceptance criteria needed a live DOM could not be finished by the agent that executed it, so it silently degraded to "executed, then finished by hand in the orchestrator". Enable `workflow.live_dom_uat` (default off) and a purpose-built `gsd-dom-verifier` checks those criteria after each wave and reports whether it looked, or could not. The plan executor's tool surface is unchanged in every configuration. (#2856) (#3716) +- **GSD now publishes a machine-readable state snapshot at every step boundary** — external tools that show project state no longer have to parse STATE.md and ROADMAP.md heuristically. `.planning/state.json` carries a versioned `contract`, the current `milestone`, every phase with its `complete`/`in_progress`/`pending` status, and the same recommended `next` action the `/gsd` front door routes. The write is best-effort and can never fail, slow, or alter the command that triggered it. (#3227) (#3824) +- **Statusline can now warn that STATE.md has fallen behind the code** — enable `statusline.show_state_freshness` and the GSD-state segment renders `state ~N commits back` once HEAD is 20+ commits past the commit STATE.md was written against, the same advisory threshold `/gsd-health`'s W024 uses. Off by default; costs one bounded git call per render only while enabled, and stays silent rather than guessing when freshness cannot be established. (#2734) (#3700) +- **`/gsd-pr-branch` gains a strict mode that keeps every planning artifact out of the PR branch** — set `planning.pr_strict: true` and the generated PR branch carries no `.planning/` path at all, structural files included, so a project can version its planning tree locally (keeping executor worktrees and `/gsd-undo` working) while publishing none of it. Defaults to `false`, which reproduces the previous classification and preservation exactly. (#2971) (#3720) +- **A second terminator for code that cannot wait for the event loop, and a versioned exit-code projection** — hooks and other write-then-exit callers can now terminate through the same registry lookup that `runMain` uses, so both agree on what every outcome means. Exit integers are versioned: today's behavior is `v1`, and `--exit-contract=v2` (or `GSD_EXIT_CONTRACT=v2`) opts into the registry's codes ahead of the next major. (#3906) (#3924) +- **New ESLint rule `local/no-exact-case-env-access`** — flags an exact-case read of a Windows case-varying environment variable (`PATH`, `PATHEXT`, `ComSpec`, `USERPROFILE`, `TEMP`, `TMP`, `APPDATA`) off any object other than `process.env` itself, closing the gap ADR-1703's portability catalog left on production Windows semantics. (#3624) (#3976) +- **New `planning inspect` query emits a schema-v1 snapshot of the whole planning state** — downstream harness UIs and dashboards can now read milestone identity, active position, per-phase verification/roadmap-acceptance/UAT evidence, requirement traceability, plan and task rows, and progress fractions from one read-only JSON document instead of parsing GSD's Markdown a second time. Unknown or conflicting evidence is reported as `unknown` with a coded diagnostic rather than inferred. (#2790) (#3708) +- **`git.protected_branches` config field warns on additional shared branches, not just the resolved base branch** — a git-flow project whose GitHub-default branch differs from its actual integration branch (e.g. `main` vs. `develop`) can now list `develop`/`staging`/etc. so `execute-phase`'s `handle_branching` "none" strategy and `/gsd-ship`'s preflight warn on any of them, not only the one resolved base branch. Optional and additive — absent by default, existing projects see no behavior change. (#3552) (#3648) +- **Code review depth can now be scoped by repository path** — set `workflow.code_review_depth_overrides` to a list of `{paths, depth}` rules and a review touching a sensitive directory such as `src/auth` automatically runs at the stronger tier, while the rest of the repository keeps the standard depth. Paths are matched as directory prefixes on whole path segments (glob syntax is rejected with a clear configuration error), `--depth=` still wins, and the resolved depth and the rule that matched are printed in the review output. (#2554) (#3695) +- **CI shard/job timeouts now self-report near-cap and accumulate a trending history.** Every matrixed CI job (test, test-full, mutate, smoke) warns in its own run once it crosses 90% of its timeout-minutes budget, and a new scheduled workflow keeps a durable, accumulating record of elapsed-vs-cap across runs — so a lane drifting toward its cap is visible before it actually breaches, not just after. (#4036) (#4043) +- **CONTEXT.md seam claims are now checkable.** New `SEAM..owns`/`SEAM..enforced-by` predicates plus a `lint:ci` gate (`scripts/lint-seam-enforcement.cjs`) fail the build when a declared single-owner seam names no existing, registered lint rule or test file, so a seam claim can no longer silently decay into an unenforced assertion. (#3626) (#3975) +- **UI-SPEC component inventories now record how they were produced** — a spec that lists the components a design system offers must name the command that enumerated them, the count it returned, the resolved package version and the date. `gsd-ui-checker` gains a seventh dimension that reports an inventory with no such line as a defect and downgrades it from a closed allowlist to a non-exhaustive list of known-good components, so an executor is never blocked from a component the spec merely failed to mention. (#2845) (#3745) +- **Exit codes are now allocated from one registry instead of invented per module** — a generated table records every non-standard exit code with its meaning, owning module and authorizing decision, and the build fails if two modules claim the same number or a code lands in a range Node or the shell reserves. Nothing emits a registered code yet; this is the allocator the following phases draw from. (#3905) (#3920) +- **A generated exit-code reference at `docs/reference/exit-codes.md`.** Every registered exit code now has a page giving its number, name, meaning and owning band, alongside why `0` and `1` are unallocatable and why `3`-`13` are reserved by Node — so a `69` in a CI log has somewhere to be looked up. The page is generated from the same declaration the registry itself is built from and is `--check`-gated against drift. (#3913) (#3994) +- **A plan that declares a file removal can now be merged by cleanup-wave** — add a `files_deleted:` list to a plan's frontmatter and the post-wave deletions guard authorizes exactly those paths, so a refactor that folds one file into another stops needing a manual merge outside the tool. Anything the plan did not declare still blocks that entry, and only that entry. Plans and manifests without the field behave exactly as before. (#3003) (#3757) +- **Capabilities can now source a task's content from an external issue tracker.** A capability that declares a `taskContentResolver` for a tracker prefix lets a plan's `tracker-id` attribute resolve the task's action, verify, acceptance criteria, and done text from that external tracker at execution time instead of PLAN.md, and any resolution failure — ambiguous match, non-zero exit, timeout, or malformed output — hard-halts rather than silently falling back. (#3970) (#4000) +- **`/gsd-review` can now dispatch reviewer lanes concurrently** — a multi-reviewer pass cost roughly the sum of its lanes even though every lane inspects the same immutable plan snapshot and none depends on another. Set `review.parallel_lanes` to `true` to overlap them within a single pass; the default stays sequential and keeps the provider-rate-limit protection, and convergence cycles stay sequential either way. This also corrects `docs/COMMANDS.md`, which described `--all` as running every configured reviewer in parallel when dispatch was in fact sequential. (#3034) (#3822) + +### Changed + +- **`--pick ` now exits non-zero when a field is absent, and `parseNamedArgs` strictly rejects unrecognized flags and stray positionals** — previously an absent `--pick` field printed an empty string at exit 0 (indistinguishable from a genuinely empty answer, #3365), and a stray or unrecognized argv token was silently dropped rather than rejected, in one case corrupting STATE.md by running a command against the wrong phase (#3358). Both now fail loudly instead of silently: `X=$(gsd_run query V --pick F) || X=default` observes the real failure it was written for, and an unrecognized flag or positional exits non-zero naming what was wrong. (#3884) (#3922) +- **Diagnostics stop reporting a clean result when they had to drop data to get one.** `intel query`'s recursive search now stops at 48 levels and marks the result `truncated: true` instead of quietly matching arbitrarily deep (a match past the ceiling now reports truncated rather than found, and no longer crashes with a stack overflow past ~12000 levels); `phase-plan-index` now names an unresolved `depends_on` token in its own warning instead of blaming the plan's declared `wave:` for a dependency edge the tool itself dropped, and that warning's own token is escaped so an attacker-authored token cannot forge a second warning line; and a code-review run where every lane failed no longer writes a `REVIEWS.md` synthesized from nothing, preserving each lane's raw output first. (#3885) (#3925) +- **A twelfth hand-rolled slug copy can no longer land, and two existing ones are fixed.** `generateSlugInternal` is the canonical slug owner, but nothing prevented a call site from re-deriving it — and two had: `qa-smell-ratchet` trimmed before truncating instead of after, so any non-ASCII input collapsed to just its ASCII tail, and a test helper claimed parity with a function that transliterates while itself not transliterating. A new drift guard now fails the build on an unsanctioned re-derivation, with three legitimately-different sites explicitly sanctioned. (#3987) (#3999) +- **Section separators now render responsively instead of wrapping** — stage banners, checkpoints, completion and error panels used fixed-width runs of box-drawing characters (a 53-column `━` rule, a 62-column `╔═╗` box). In a narrower pane those runs wrap and the border comes apart from the heading it framed. GSD now emits Markdown headings and `---` thematic breaks, which adapt to the available width in every runtime. (#3028) (#3789) +- **Non-Claude installs now resolve their own runtime by default, and `depends_on` accepts the bare plan number.** A Codex, Cursor, or other non-Claude install with no `GSD_RUNTIME` set and no `config.runtime` key previously still reported `claude` everywhere, because the per-install runtime marker the installer writes was read by four hand-rolled copies but never by `resolveRuntime` itself; it is now the third precedence rung. Separately, `depends_on: ["01"]` now resolves to the in-phase sibling plan instead of silently dropping the dependency and collapsing the plan into wave 1 — a phase that previously ran all its plans in a single wave now executes in its declared waves. Codex sandbox permissions are also now derived from each agent's own tool contract instead of a hand-maintained map, and `validate agents` reports any drift via a new `sandbox_posture` field; both are byte-identical to today's behavior. (#3897) (#3941) +- **The launcher now proves which `gsd-tools` it resolved before running any verb** — a project-local or config-directory install that cannot answer `runtime-identity` with an `@opengsd/gsd-core` payload now produces one actionable warning naming both causes (a foreign package, or a gsd-core older than the verb) and exports `GSD_IDENTITY_STATUS=unverified`, instead of silently handing a state-mutating verb to a tool written for a different contract. (#3841) (#3848) +- **Two lint rules that could not reach the code they govern now do, and `quick-tasks-append` stops overwriting curated progress values.** `local/no-adhoc-markdown-parsing` self-gated on its own filename, so it silently skipped every `.cts` file in a `src/` subdirectory and could not be widened by configuration alone; it now also covers `tests/` and `scripts/`, and the 80 hand-rolled markdown parses it surfaced are routed through the existing sectionizer and table seams — including one test that asserted against the wrong table column and so could never fail. `local/no-adhoc-regex-escape` examined only bare identifiers, missing the property-access shape runtime data actually arrives in, which is why it never caught a known ReDoS. Separately, `quick-tasks-append` gained optional `--quick-id`/`--slug`/`--directory` so a caller with a real quick task emits the canonical row, and a body-only append no longer forces a re-derive of disk-derived progress frontmatter that replaced curated values. (#3951) (#3965) +- **Shipped workflows can no longer reach a different package's `gsd-tools`** — a second package publishes a binary of the same name whose `phases.clear` deletes where GSD's archives, so a workflow could destroy planning directories and still print success. Workflows now resolve `gsd_run`, which only this package publishes, and stop with an install message rather than falling back to whatever `gsd-tools` is on `PATH`. Adds `gsd-tools runtime-identity` for confirming by hand which tool a project is running against. (#3146) (#3831) +- **Removed a dead code path** — `listMilestoneArchiveDirs` (caller-less since the Phase-12 snapshot migration) and its test seam are gone; the #1883 unreadable-milestones regression suite now pins the live planning-snapshot path. (#3813) (#4029) +- **`milestone complete` blocks again when the roadmap still lists unstarted phases** — that guard had been silently swallowed, so milestones could be archived with work outstanding and nothing said so. Two more guards that inspected an error's message before deciding whether to re-raise were failing the same way and are fixed with it, and `extract-messages`/`profile-sample` no longer dump a raw Node stack trace on top of their error line. A new lint rule now rejects a raw `process.exit()` outside the sanctioned terminator, so a guard cannot quietly stop guarding this way again. (#3910) (#3980) +- **The STATE.md field reference is generated from one schema, and the status lifecycle now appears in every language** — the key set, its types, enums and cardinality are declared once and projected into the field-classification tables, the shipped template and all five reference documents, so a field can no longer be described one way in code and another in the docs. The `Status lifecycle` section, which documents the status values, was missing from the Japanese, Chinese, Korean and Portuguese references and is now present in all of them. (#3873) (#3880) +- **`.planning/` frontmatter is now parsed by a real YAML parser.** Block scalars, quoted keys and non-ASCII keys are read correctly instead of being mangled or silently dropped, and a document whose frontmatter cannot be parsed keeps its frontmatter block instead of losing it on the next write. (#3881) (#3888) +- **Plans must now say what output constitutes failure** — every runnable `` acceptance command needs a `` sibling naming an observable failure signal, and `/gsd-plan-phase` blocks a plan that omits one. A command with no expressible failure mode is not an acceptance test. Breaking for phases planned before this release: re-check reports one blocker per unstated command until statements are added or the phase is re-planned. (#3172) (#3825) +- **The API-coverage seal gate no longer clears a phase it never examined** — a phase with no plan body and no roadmap section previously ran the detector over zero bytes and sealed as "no external-API integration"; it is now held with `scope_unavailable`, and the assumption-delta checkpoint reports `skipped` instead of a fabricated `detected:false` when it cannot resolve a phase section. (#3909) (#3944) +- **The phase researcher no longer treats missing metadata as a compatibility constraint** — a claim like "this library does not support that runtime version", drawn from an absent `python_requires`, `engines` field, per-version classifier, changelog entry, or support-matrix row, no longer earns `[VERIFIED]` however authoritative the registry or docs consulted. An absence says nothing about the version being ruled out and nothing about the version being standardized on, so the same evidence would "prove" both; the only route from an absence to `[VERIFIED]` is a positive falsification attempt with its failing output pasted, and everything short of that stays `[ASSUMED]`, which already routes through a confirmation checkpoint before it can lock a decision. A present declared constraint and an affirmatively documented incompatibility are untouched. Previously an honestly-tagged absence could lock a CONTEXT.md decision and produce a real version downgrade that no downstream stage re-derived. (#2951) (#3718) +- **An unevidenced lone reviewer finding no longer forces an extra replan cycle** — with two or more reviewers running, `/gsd-plan-review-convergence` now weighs a single reviewer's HIGH by what it claims: an existence claim about a symbol, file or ID must be source-grounded or corroborated, while a design finding still counts on its own unless that reviewer cited no source evidence anywhere in its review. Findings that stop counting stay visible, tagged rather than dropped, and single-reviewer runs are unchanged. A design finding from a reviewer that did cite evidence still counts alone — deliberately, so that a real architectural concern only one reviewer noticed keeps blocking. (#2398) (#3755) +- **Emitted-drift acknowledgments move from a committed file to a commit trailer.** A PR that legitimately ripples emitted-artifact bytes now declares it with an `Emitted-Drift-Ack-Hash:` or `Emitted-Drift-Ack-Growth:` trailer on one of its own commits instead of adding a JSON fragment under `tests/emitted-drift-acks/`. The acknowledgment was only ever valid for the life of the PR, so keeping it in the working tree meant every merged one became cruft that had to be detected and garbage-collected; the trailer leaves nothing behind and cannot conflict. Removes the shipped `scripts/lint-emitted-drift-ack.cjs`, the scheduled sweep workflow, and the `guard-no-ack-on-next` job. (#3942) (#3954) +- **`state.*` commands now report every field they actually changed, and only those** — the `updated` array is derived by diffing what was persisted against the pre-write state, so a counter the write genuinely moved is no longer suppressed, a field the write merely preserved is no longer claimed as an update, and a changed sub-counter is named at leaf granularity (`progress.total_plans`) instead of being dropped. Callers that compared the array exactly will see more, and truer, entries. (#3872) (#3878) +- **Every GSD enforcement hook now declares its crash policy.** Hooks used to end their outer catch with a bare `process.exit(0)` or `process.exit(2)`, so whether a hook fails open or closed on its own bug was invisible without reading its source; hooks now terminate through `allow`/`deny`/`crash` and declare a required `ON_CRASH` policy, with no change to any hook's effective exit code. Also fixes #3838: `gsd-validate-commit.sh`'s config/JSON/git-subcommand checks no longer treat "could not run" the same as a genuine negative — a failed check now says so on stderr instead of silently allowing every commit. (#3911) (#3960) +- **Capabilities can now do work before UAT, not only block it** — the `verify:pre` extension point dispatched gate hooks only, so a capability declaring a step or contribution there was rejected at registry-build time and the whole verify lane was closed to anything that wanted to contribute to what UAT covers. It now dispatches contribution, step, and gate hooks, and `extract_tests` additively consumes the artefacts those steps declare via `produces`. (#3866) (#3869) +- **A security scanner that cannot compute a diff now fails instead of reporting clean** — `secret-scan`, `base64-scan` and `prompt-injection-scan` previously exited 0 for a bad ref, a missing repository, or a repository with no commits, which is indistinguishable from a genuine all-clear to any CI gate. They now distinguish four outcomes: scanned clean, nothing was in scope, could not establish scope, and findings. The security workflow treats nothing-in-scope as a pass and could-not-scan as a failure. (#3908) (#3937) +- **Codex reasoning effort is now resolved per model, and every clamp is visible** — `max` reaches Codex instead of being silently downgraded to `xhigh`, `minimal` clamps up to `low` instead of being sent to models that reject it, and `resolve-execution` reports the level you asked for alongside the one actually rendered. `ultra` is refused outright because it switches Codex into proactive task delegation underneath GSD's own orchestration. (#3007) (#3765) +- **`docs/FEATURES.md` is now generated from per-feature fragments** — a feature no longer hand-allocates a section number or hand-edits the table of contents, the two cells that made almost every concurrent feature PR conflict; contributors add one file under `docs/features/` with any unique `id` and regenerate. (#3840) (#3845) + +### Removed + +- Removed the hand-written root bin/lib/ui-safety-gate.cjs — the GSD installer and every shipped workflow only ever resolved gsd-core/bin/lib/ui-safety-gate.cjs, so the root copy was unused dead code. (#3932) + +### Fixed + +- **Workflows no longer send AI runtimes hunting the filesystem for the GSD shim** — 50 places across 23 runtime-loaded workflow, agent, reference, and command files told the agent to run `gsd-tools.cjs` by filename, which is not on PATH under any name. The agent got "command not found", fell back to locating the file, and on Git Bash for Windows `find /` walked the entire drive until someone killed it. Every one now calls the canonical `gsd_run` launcher. (#3809) (#3815) +- **`/gsd-ingest-docs`, `/gsd-import`, `/gsd-audit-fix`, `/gsd-profile-user`, and `/gsd-docs-update` now honor model routing for their subagents** — the doc classifier/synthesizer/verifier, roadmapper, plan-checker, fix executor, and user-profiler subagents (plus the debugger spawned by the `diagnose-issues` workflow behind `/gsd-verify-work`) ran on the calling session's model, silently ignoring `dynamic_routing`/`model_profile` tier config. Each workflow now resolves the per-agent model and passes it on the spawn (omitting it when it resolves to inherit/empty per #2517). (#3602) (#3670) +- **Upgrading the Codex runtime no longer aborts when a top-level config key sits below the GSD marker** — the regenerated `[agents]` table captured such keys into its scope, so post-write schema validation rejected the merged `config.toml` and the install failed mid-flight. Surviving top-level keys are now hoisted above the managed block, preserving their file scope. (#3610) (#3690) +- **`phase complete` now reports `roadmap_updated` and `state_updated` honestly** — both flags read `fs.existsSync()`, so they were `true` for any project that had the file at all, and a rollup that silently wrote nothing was indistinguishable from one that landed. Each flag now reflects whether that file's content actually changed in the transaction, matching the contract `requirements_updated` already honored. (#3685) (#3826) +- **`windows` ledger commands survive a formatter pass** — the WINDOWS.md ledger's JSON block is written with a four-backtick fence, which Prettier and other CommonMark formatters legally narrow to three; the reader then rejected the file and every `gsd-tools windows` subcommand (status/append/waive/fixed) failed with "Ledger missing JSON code block". The reader now accepts any CommonMark-legal fence width (the writer still emits four), resolves the real block past fences planted in entry descriptions, and preserves user prose below the ledger; the refactor-trigger proposal reader gets the same fence tolerance. (#3657) (#3733) +- **Stage the emitted-drift-ack sweep around open PRs** — sweeping an all-spent fragment used to delete it unconditionally, handing any open PR that still touched the same file a modify/delete conflict it did not cause (#3330, #3774, #3648). The guard now holds a fragment back when an open PR still touches it, deferring the sweep until that PR merges or closes. (#3842) (#3847) +- **Resuming `/gsd-execute-phase` on a phase whose verification passed but whose run died before marking complete now finishes the job** — the phase is marked complete, progress state advances, phase todos close, and the transition handoff runs, instead of every resume reporting "nothing to do" while the roadmap checkbox stays unticked forever. Already-completed phases keep exiting cleanly, and verification is never redone. (#3684) (#3814) +- **`state validate` now sees the `last_activity` invariant, and `--strict` makes the verdict gateable** — a STATE.md whose `Last activity` value no reader could parse used to validate clean (`{valid:true, warnings:[], scope:'complete'}`), and a wrapped description was silently truncated; both are now reported as coded diagnostics (`S008`/`S009`). `state validate --strict` exits non-zero when the report is not valid, so a CI step or git hook can gate on state correctness without parsing JSON — the default exit status is unchanged. (#3696) (#3844) +- **`/gsd:plan-phase` no longer writes gitignored install-mirror paths into plans** — `files_modified` and artifact paths are now verified against `git ls-files` and resolved to tracked source (e.g. a plugin's own tree) instead of a runtime mirror under `.gsd/capabilities/`, whose edits died on every capability sync; paths inherited from PATTERNS.md are re-verified so one mirror path can no longer self-propagate across phases. (#3645) (#3728) +- **`milestone complete` now requires an explicit `--confirm` to mutate** — the command irreversibly archives ROADMAP.md/REQUIREMENTS.md, MOVES every phase directory in the milestone, and rewrites STATE.md, yet ran unconditionally on first invocation through every invocation path, including `query milestone.complete `, whose `query` meta-prefix reads as a read-only namespace but performs no filtering. Without `--confirm` (and without `--dry-run`) the command now refuses before touching anything and names the flag that proceeds; `--dry-run` still previews the exact move list with no confirmation needed, and is now documented in the command's own usage block. `--force` keeps its narrow meaning (bypass the TRUNCATED-scope / unstarted-phase guards) and does not double as the mutation opt-in. The `/gsd-complete-milestone` workflow passes `--confirm` at its archive step. (#3726) (#3774) +- **In-process installs can no longer write a kind's `home` override into your real home** — a runtime kind with a global `home` override (codex skills → `$HOME/.agents`) resolves from `os.homedir()`, not from the caller's config dir, so a test that sandboxed only its target directory pruned every `gsd-*` skill from the developer's real `~/.agents/skills` while the suite still passed and the manifest still reported a healthy install. All six writers that resolve a kind `home` now refuse when a `node --test` run would land inside the real home, compared by filesystem identity rather than pathname and decided on where the write resolves rather than how it is spelled. Scope is stated rather than implied: the six are the writers on the `installRuntimeArtifacts` call tree, and this covers destinations a runtime kind resolves through a `home` override, not every path the installer touches through `os.homedir()` (`writeNonClaudeDefaults`' `~/.gsd/defaults.json` is still reached by a spawned installer with an un-sandboxed HOME) and not writers off that tree (`cmdGenerateDevPreferences` resolves the same codex `home` override through `getGlobalSkillsBase` and writes `SKILL.md` beneath it unguarded; it has no in-process caller today, so it is latent rather than live). Canonicalization fails CLOSED rather than falling back to the lexical spelling — an unresolvable component (`EACCES`/`ELOOP`/`EIO`) is refused, since that fallback is the exact ALLOW an aliased `/.agents` needs; only `ENOENT`/`ENOTDIR` walk up, matching `identify`'s own errno split. Two limits are named in the source rather than papered over: a subordinate bind mount of the real directory into a sandbox is not detectable without mount-table introspection, and on a host with no readable passwd entry the guard falls back to a caller-set marker — which must itself identify, and must contain every destination, so a layout captured before the sandbox is still refused. Real installs are unaffected. (#3712) (#3725) +- writing any markdown file no longer converts tight multi-line lists to loose ones — a blank line was injected before every bullet following a wrapped item (61 blanks on a 1015-line ROADMAP via phase.complete; the defect sat in the write seam every .md write uses), and tight vs loose lists render differently so this was a rendering change plus large misleading diffs, not just whitespace (#3854) (#4049) +- **Managed hooks now resolve the node binary at hook-fire time** — a config root shared across environments (WSL/Docker bind-mounts, mounted or synced `~/.claude`) no longer fails every managed hook with `node: not found` outside the machine that ran the installer, and updates from any environment converge stale runners instead of creating a mixed state where no environment works. `--portable-hooks` installs route through a staged `hooks/gsd-node-runner.sh` resolver (install-time path first, then `command -v node`, then well-known layouts); other installs carry an equivalent inline fallback chain. (#3662) (#3790) +- **/gsd-pr-branch now refuses to verify a PR branch that would delete planning files the target branch tracks** — the verification step counts planning-tree deletions via git diff --name-status and fails on any non-zero count, instead of reporting clean while pre-existing planning content was stripped. The underlying deletion class in the cherry-pick filter was already fixed by the strict-mode rewrite; this makes the workflow able to detect it. (#3679) (#3803) +- **Codex worktree-parallel executors now launch with the full executor contract** — the orchestrator-worktree process spawn handed its child a short objective-only prompt, so executors reconstructed their role by repository search and force-staged gitignored SUMMARY.md files (`git add -f`) to satisfy an unconditional commit criterion. The spawn prompt now carries the embedded executor workflow, required reading with the explicit plan path, the gsd-executor persona, and skip-aware success criteria, and halts before spawn when the contract embeds cannot be resolved. (#3637) (#3694) +- **`workflow.inline_plan_threshold` now has one default owner** — the key is registered in the defaults manifest (default `2`), so `config-get` resolves the absent key instead of erroring, `settings-advanced` no longer misdocuments the default as 3, and every shipped surface (workflow fallback, reference tables) agrees. (#3801) (#4019) +- **`audit-uat` sees workstream phases again** — the audit now enumerates all three phase-archive layouts (flat `milestones/vX.Y-phases/`, archived workstream `milestones/ws-*/phases/`, and active workstream `workstreams//milestones/`), with workstream entries labeled `/` so acknowledge-by-milestone stays unambiguous. A project using workstreams no longer gets an All Clear audit while items are open, and `--ws` no longer empties the report. Phase lookups keep their #2855 workstream scoping unchanged. (#3804) (#4022) +- **`workflow.use_worktrees=false` at the root now applies inside workstreams too** — the dispatch-isolation resolver inherits the root opt-out under `GSD_WORKSTREAM` exactly as `config-get` does, so a root-level opt-out no longer leaves workstream runs recording `harness-worktree` over the mandated `none`. (#3963) (#3967) +- **`phase complete` no longer advances to an inserted phase that merely has a directory** — the next-phase resolution scanned phase directories first and only consulted ROADMAP.md when the disk turned up nothing, so an inserted decimal phase (whose directory `phase insert` scaffolds immediately) outranked the phases preceding it in roadmap order. The wrong successor was reported and written to STATE.md as the resume pointer. Roadmap order now decides which phase is next; the disk still supplies the on-disk spelling when both agree, and remains the fallback when no roadmap is readable. (#3701) (#3852) +- the STATE.md Quick Tasks log accepts milestone-suffixed section headings (Quick Tasks Completed (v1.1+)) — the exact-anchored lookup never matched them, so every /gsd:fast append and milestone reset silently failed before the columns were even checked; among several matching sections the one with a recognized table schema wins (#3860) (#4050) +- **`--config-dir` installs no longer plan removals of the default home's live legacy install** — the legacy get-shit-done-cc cleanup is scoped to the resolved config dir when `--config-dir` redirects the install (scan, shared cache, and per-package cache alike), the `--dry-run` preview shows the same scoped plan the real install would apply, and `--no-legacy-cleanup` skips the scan entirely. (#3799) (#4013) +- a spaced-hyphen thematic break (- - -) inside a UAT file ## Gaps section is no longer parsed as a gap entry — it fabricated a phantom open gap named "- -" with result unknown that audit-uat surfaced as outstanding work which could not be cleared by editing any entry (#3898) (#4057) +- **No more console-window flash on Windows in non-GSD repositories** — the graphify auto-update hook ran a hidden `node` process to parse its payload before checking whether the project uses GSD at all; the cheap `.planning/config.json` and `CI` checks now run first, so non-GSD projects and CI pay for zero child processes per Bash tool call. (#3729) (#3935) +- **docs/INVENTORY.md rows are now enforced** — a shipped agent, command, workflow, reference, CLI module, or hook could be added to the generated manifest with no row in the authoritative roster and still pass CI; the roster is now anchored the same way the manifest is, and 32 pre-existing gaps are backfilled. (#3762) (#3766) +- **`total_plans` no longer counts REPLAN/PLANNING documents as plans** — a phase directory carrying a `REPLAN-INPUTS` or `PLANNING-NOTES` document no longer inflates the plan count that STATE.md derives on every state-mutating call. (#3741) (#3950) +- **The isolation guard no longer denies sequential dispatches a workstream explicitly opted out of** — the sentinel-absent fallback now reads `workflow.use_worktrees` through the same project/workstream-aware ladder as the resolver and `config-get`, instead of the flat root config where a workstream-local opt-out was invisible. (#3972) (#3979) +- **`gsd-roadmapper` no longer contradicts itself on write-vs-approve ordering** — the agent's role, output format, and completion checklist now match its write-first execution flow (write for durability, return `## ROADMAP CREATED` with a preview; the orchestrator presents and owns the approval gate), and the orphaned `## ROADMAP DRAFT` template that matched no orchestrator branch is gone. (#3797) (#4008) +- **`windows append`/`waive`/`fixed` no longer silently erase a hand-edited ledger table** — `.planning/WINDOWS.md` renders its table from the fenced JSON that is its source of truth, and every write regenerated that table without ever checking the two still agreed. A hand-edited cell was reverted and a table-only row vanished entirely, both at exit 0 with nothing on stdout. The write is now refused with a `windows_ledger_table_drift` error naming the offending row ids, and the file is left untouched. (#3689) (#3828) +- **Agent frontmatter no longer reverts to catalog Anthropic models when `model_policy` is configured** — the install-time bake for the static-frontmatter runtimes (OpenCode, Kilo) read `model_profile` and `model_profile_overrides` but never `model_policy`, so every update rewrote agent `model:` fields to `anthropic/claude-*` IDs that a custom provider does not serve, while dispatch-time resolution honored the policy correctly. The bake now consults the same policy resolver dispatch uses, at the same precedence: an explicit per-agent `model_overrides` entry still wins, then `model_policy`, then the tier table. (#3705) (#3863) +- **`gsd-core/references/` is now covered by the bare-command guard** — the #2751 guard only ever scanned `agents/` and `gsd-core/workflows/`, so 37 bare `gsd-tools ` calls sat unguarded in a directory it never looked at. They now call the canonical `gsd_run` launcher, and the guard scans references too. (#2751) (#3815) +- **Release coverage gate no longer OOMs as the test suite grows** — `test:coverage:unit` (used by the release finalize/rc jobs) and `test:coverage:report` (the sharded coverage-gate merge step) now pass c8's `--merge-async` flag, so raw V8 coverage files are merged one at a time instead of all being loaded into memory at once. (#4068) (#4069) +- **UAT rows separated only by a lone carriage return were silently dropped from the audit-uat scan.** A `VERIFICATION.md` or `deferred-items.md` written with lone-CR line endings rendered normally to a human reader, but reported zero outstanding items to the audit, hiding real human-verification and deferred-work entries. Both file types now surface their rows exactly as their LF/CRLF equivalents do. + + **Planning-inspect now surfaces UAT rows separated only by a lone carriage return.** The same lone-CR line-ending gap also hid rows from planning-inspect's own UAT reporting; a row that previously vanished from `uat.unresolved` now appears there too, matching its LF/CRLF equivalents. + + **A UAT row whose `result:` line had trailing text containing a Unicode line or paragraph separator (U+2028/U+2029) is no longer dropped.** A column-0 `result:` line whose text after the token happened to contain one of these separators previously failed to parse at all, silently discarding an outstanding row; it now parses the same as its plain-line equivalent. (#3707) (#3903) +- **~/.gsd/defaults.json is written under the install-migration lock and in a single atomic write** — concurrent installs for different runtimes can no longer lose each other's settings, and a crash mid-write can no longer truncate this machine-global file (which the read path treats as absent, silently degrading model resolution for every project on the machine). An install that changes nothing no longer rewrites the file. (#3966) +- **`/gsd-pr-branch` no longer deletes the base branch's planning files or silently drops commits** — the generated PR branch used to stage a deletion for any `.planning/` path the target branch already tracked, and a second commit touching the same planning file aborted the cherry-pick with "untracked working tree files would be overwritten", dropping that commit and every one after it. The filter now forces excluded paths back to what the target branch tracks in both the index and the working tree. Verification also asserts against the active filter mode instead of an unconditional zero, so a correct default-mode run that preserved `STATE.md` no longer reports itself as failed. (#2971) (#3720) +- audit-open summary counts now include the display-truncation remainder: a milestone with more than 5 open files reported counts capped at 5 because the _remainder_count display marker was counted as one item instead of the real files it records (#3817) (#4034) +- smart-entry classifies a STATE.md status of verified (or verification) as verify-pending instead of falling through to unknown — the classifier matched the exact word verify and missed the verif stem its own normalizeStateStatus uses (#3864) (#4052) +- **`/gsd:config --integrations` no longer prescribes writes that fail** — the review-models section states the real rule (only reviewer lanes whose capability declares a modelConfigKey are settable; the nine settable lanes are enumerated; cursor/qwen/coderabbit named as keyless) instead of a validation pattern that never existed, and agent-skill lists are now written as JSON arrays instead of a comma-joined string that resolves as one broken skill path. (#3651) (#3732) +- the phase-taking init.* queries (execute-phase, plan-phase, verify-work, code-review, phase-op, review, discuss-phase-assumptions, todos) accept --phase as an alias for the positional form, matching phase list-plans; a valueless --phase is now a usage error instead of silently answering phase_found:false for a phase that has plans (#3865) (#4054) +- **STATE.md frontmatter comments now survive every state write** — a column-0 comment no longer depends on an unrelated body line being present, and an indented comment above the `progress:` counters (the natural provenance spot) is preserved instead of silently stripped. (#3742) (#3952) +- **`state` no longer lets a lone non-matching milestone section's phases become another milestone's `total_phases`** — with exactly one milestone section in ROADMAP.md and a STATE.md asserting a different milestone, the section's phases were silently written as the asserted milestone's total (clobbering the stored value). Both that shape and the multi-section one now keep the stored total and warn, naming the asserted milestone. Flat roadmaps (no milestone headings at all) are unchanged. (#3642) (#3727) +- the shipped hook tables documented gsd-validate-commit.sh as PostToolUse (it is registered PreToolUse — exit-2 blocking is its contract) and gsd-session-state.sh as PostToolUse (registered SessionStart); 18 wrong rows corrected across ARCHITECTURE.md and INVENTORY.md in en/ja-JP/zh-CN/ko-KR/pt-BR, with a new docs-vs-surface parity suite guarding all ten tables (#3839) (#4041) +- **`audit-open acknowledge` works on heading-shaped deferred-items.md** — the CLI writer previously refused every entry in any file using the heading-delimited (#3457) convention (a real project saw 0 of 107 items acknowledgeable); leaf headings and interleaved headless bullets now acknowledge through the same span-anchored, span-verified write the bullet shape uses, with a human `Status: resolved` never downgraded. Only entries embedding a GFM table row still refuse. (#3781) (#3998) +- **Antigravity global skills and agents now install to `~/.gemini/config/`** — the directory Antigravity actually scans for machine-local discovery, so installed skills are no longer silently ignored at startup. Upgrading an existing install automatically removes the old artifacts from the deprecated `~/.gemini/antigravity` location (modified files are backed up; user-authored files are preserved). (#3738) (#3921) +- **Codex worktree executors now run on the model you pinned for them.** With `model_overrides.gsd-executor` set, `$gsd-execute-phase` spawned its worktree executor with no `--model` argument at all, so the child silently fell back to the global Codex session model — and because this path spawns a process rather than dispatching a named agent, the model baked into `gsd-executor.toml` could not apply either. An explicitly pinned model is now passed to the spawned process. An unpinned, blank, or `inherit` configuration still emits no model argument and keeps the session-model fallback, so Codex's session-only model posture is unchanged and no tier-derived model is ever sent. A pin that is Anthropic-flavored (`sonnet`, `opus`, `claude-*`), flag-shaped (e.g. `-c`), or otherwise outside the model-id character set is now dropped with a stderr warning instead of being sent to Codex — which would 400 — or aborting the whole run. (#3714) (#3891) +- **`generate-slug` and phase/workstream slugs no longer diverge from the canonical formula.** — Some slug-producing commands and internal call sites re-implemented the ASCII slug formula by hand instead of delegating to the shared one: Cyrillic and other non-Latin titles could collapse to an empty slug where the canonical transliterates them, and slug truncation could leave a dangling trailing hyphen (regression of #2849). Every slug call site now delegates to the single canonical implementation. (#3883) (#3896) +- **Interrupted executors can be resumed again** — execute-plan deleted `current-agent-id.txt` before the check that read it, so the interrupted-agent detection and its Task `resume` prompt were unreachable after a kill; the id is now captured before the stale marker is cleared. (#3795) (#4006) +- **Workflow config comparisons work again for string values** — every shipped `config-get` bash call site now passes `--raw`, so string-typed values (runtime, response_language, discuss_mode, …) reach shell comparisons unquoted instead of as JSON with literal quotes that never matched. (#3763) (#3961) +- gsd-mempalace-curator no longer hardcodes model: sonnet in its frontmatter — the only pin in the 34-agent fleet; it intercepted the deliberate inherit case (agents inherit the orchestrator model when resolution is inherit) and operators could not durably remove it. Default profiles keep sonnet via the model catalog; model_overrides and inherit now work (#3895) (#4048) +- **A malformed config section no longer destroys the value it holds — or gets written back to disk.** If `.planning/config.json` had a `git` or `planning` key holding a string instead of an object, migrating a legacy top-level key into it expanded that string into numbered character keys (`"main"` became `{"0":"m","1":"a","2":"i","3":"n"}`), and the result was saved over the original file — so the value could not be recovered. Numbers and booleans were dropped outright. The migration is now declined instead: the section, the legacy key, and the file are left exactly as written, and a warning names the file so it can be fixed by hand. (#3760) (#3767) +- **`GSD_PROJECT`-scoped projects keep their signals and probes in their own tree** — `init manager`'s waiting signal, `map-codebase`'s dir/maps probes, `skill-manifest --write`, and `init.new-project`'s codebase-map readiness now all resolve through the project-aware planning dir instead of the repo root. (#3964) (#3971) +- **`/gsd-capture --backlog` no longer scatters backlog items across per-item branches** — `query commit`'s phase-branching arm now treats `999.x`/`0.x` backlog sentinels as non-phases, so a backlog capture commits on the current branch instead of silently creating and switching to a `gsd/phase-999.*` branch per item. (#3734) (#3933) +- phase add and phase add-batch now count phase numbers held by sibling git worktrees before allocating max+1, instead of colliding with them (the reported incident minted a second Phase 441 while a worktree already held one with six written plans); add-batch also now counts roadmap bullet rows (#1229 finally reaches the batch path) (#3849) (#4042) +- **Sentinel phases no longer skew estimation calibration.** Backlog and icebox phase directories (milestones 0 and 999) were counted as completed phases when rebuilding the calibration factor, so a single one could switch calibration on from phantom evidence and two could corrupt the factor outright. (#3882) (#3893) +- **Two QA oracles no longer report findings against the wrong field.** `routing-validity` demanded a live-command token from `recommended`, which is an action id by design, and also validated `recommended_command`, a field nothing in the repo produces; it now checks the fields that actually carry tokens. `value-hygiene` reported command tokens such as `/gsd:progress` as leaked absolute paths, and now exempts them by value shape rather than by key name, so a `command` field holding a genuine absolute path is still reported. (#3913) (#3994) +- a timed-out git commit is now reported as commit_timeout with the stale .git/index.lock path surfaced in the error, instead of commit_failed with the killed hook's partial stderr; the commit call also moves to the 30s band the push call uses (pre-commit hooks alone can exceed the old 10s cap) (#3886) (#4046) +- **`/gsd-progress` no longer presents archived milestones\' verification debt as current-milestone debt** — the Verification Debt warning segments by the audit\'s `archived_milestone` stamp (current vs still-open-in-archived-mileses), keeps the archived segment visible with its own label, and no longer silently reads zero on large audits (`@file:` payload unwrap). (#3782) (#4001) +- **Acknowledged moot items stay closed in `audit-uat`** — the `audit_acknowledged` frontmatter marker (the documented, self-invalidating "this item is moot" seam) now suppresses items in `query audit-uat` exactly as it already does in `audit-open`, with the same snapshot keys and a visible `acknowledged_files` count — no more choosing between lying (`status: passed`), inventing tokens, or deleting the planning record. (#3805) (#4025) +- **A phase with an unreadable UAT row no longer reports an affirmative milestone completion percentage.** Previously, one specific unreadable class — UAT rows hidden inside a closed code fence — was exempted from degrading a phase's fold, so a milestone could still publish a completion percentage over work nobody could actually see. Every class of unreadable UAT content now withholds the milestone's percentages the same way. The per-phase signal is unchanged: a phase's own `uat.scope` already reported "truncated" for this case and still does. (#3707) (#3903) +- **`audit-open acknowledge` no longer silently strands or clobbers Title-case status lines** — a bare `Status:`/`STATUS:` marker is now acknowledged through a line the reader actually parses instead of being rewritten in place invisibly, and a human-written `Status: resolved` is left untouched rather than downgraded to `acknowledged`. (#3775) (#3989) +- **A malformed settings.local.json survives the #338 migration** — readSettings()'s null "could not parse, preserve existing" signal is now honored and the whole migration stands down, so the shared GSD entries are not stripped either. Also fixes two crashes on that path: an unparseable settings file previously aborted the install with a TypeError instead of skipping the file. (#3966) +- **The milestone audit report is written where its readers look for it** — `/gsd-audit-milestone` created the report at a doubled `.planning/v{version}-v{version}-MILESTONE-AUDIT.md` path while every downstream reference (Report pointers, the `cat`, the completion checklist) reads the single-version `v{version}-MILESTONE-AUDIT.md`, so the report silently landed unread. (#3796) (#4007) +- **`check-glossary-refs` no longer reports a false clean** — backtick-pairing parity let stale file references in CONTEXT.md hide behind RULESET predicate lines, so renamed files stayed invisible to the drift gate. Visibility is now structural (per-line pairing + predicate-value harvesting), the renamed test reference is corrected, and retired-file mentions are exempted by name. (#3604) (#3680) +- **`state update` now explains why a field was not written, instead of reporting it as absent** — asking to update a frontmatter key such as `stopped_at` returned "not found in STATE.md", byte-identical to a genuinely missing field and pointing away from the body field that does work. The refusal now names the body source, or names what derives the key when it has no body source. A document whose frontmatter carries a key with no body source at all — previously unrepairable through this command — can now be fixed by writing the key directly, reported as `wrote: "frontmatter"`. (#3699) (#3846) +- **`local/require-registered-exit` now catches computed and optional-chained `process.exit()` calls.** The rule previously missed `process['exit']()` and `process?.[k]?.()` forms where the property name is a statically resolvable string, letting a raw terminator slip past the ADR-3889 registered-exit contract. It now resolves a computed property to a string literal (directly, or through a single never-reassigned string-literal-initialized binding) and flags those forms too. `n/no-process-exit` remains registered everywhere it already was — the two rules are complementary, not predecessor/successor, so neither is retired. (#3914) (#4018) +- **OpenCode subagents now carry the reasoning effort GSD resolved for them** — `query resolve-execution` reported an effort level that never reached the generated OpenCode agent, so every subagent ran at whatever the runtime defaulted the model to, silently ignoring `effort` config. The bake now emits a `variant` key alongside `model`, and `effort sync` maintains it, so changing effort config no longer needs a reinstall. The key is written only when effort is actually configured; `inherit` and any level OpenCode does not accept omit it rather than naming a variant that cannot resolve. Config-supplied `model` and `variant` values are also quoted whenever YAML would not read them back verbatim — previously a value containing a newline could inject extra top-level keys into a generated agent file, and values like `no`, `12:30`, `@org/model` or a bare date were silently retyped or truncated. (#3706) (#3867) +- **Raised the emitted-drift acknowledgment cap from 64 to 128** — a wide-touching maintenance PR could legitimately accumulate more distinct commit-trailer acknowledgments than the old ceiling allowed, failing CI even though nothing was wrong. (#4058) (#4059) +- **`gsd-tools --project-dir ` now works** — the flag was documented in docs/CONFIGURATION.md's multi-repo workspace resolution section but wired nowhere, so it was silently ignored and every command still resolved the project root from cwd. Passing `--project-dir` now sets the project root directly and skips the ancestor walk-up, as documented. (#3881) (#3888) +- **`state advance-plan` refuses an ambiguous Current Position instead of silently advancing the first entry** — when the section carries more than one `Phase:` line (the wave-log style), the command now returns a typed `ambiguous_position_phase` error naming every candidate and leaves STATE.md byte-identical, instead of silently advancing the first entry's plan counter (in the reporting incident, a hard-gated final plan 7→8 of 8) with `advanced: true` and no ambiguity signal. (#3807) (#4028) +- **Every reviewer lane can now be given a prompt-token cap, and the documented global `review.max_prompt_tokens` finally works** — the nine CLI reviewer lanes declared no budget key, so no cap could reach them by any configuration, and the central global was advertised in the config schema but declared nowhere, so setting it changed nothing. Each CLI lane now accepts `review.max_prompt_tokens_per_reviewer.` on the same terms as the local-server lanes, and the global resolves as the documented fallback. Defaults are unchanged: with nothing configured, no lane trims. (#3691) (#3832) +- **The installer writes settings.json and settings.local.json atomically (temp+rename)** — a crash mid-write can no longer truncate the file. Hosts discard the entire settings file on a parse failure, so a truncated write previously cost users every hook, permission, env var, and statusline they had — not just GSD's. (#3966) +- **Capability hooks can no longer be silently registered-but-never-run** — the capability validator now checks that each host call site's dispatch text covers every hook KIND registered at that point (a gate-only consumer fails validation when a step or contribution hook is registered there), and the plan/execute/verify host consumers now dispatch steps and contributions generically per the loop hook contract instead of hand-rolling one kind. (#3606) (#3687) +- **Reduced the complexity of the refactor-trigger evaluate handler.** `handleEvaluate` scored above the complexity-triggered-refactor feature's own default threshold; the read/analyze loop and the artifact/baseline/ledger write path are now separate named helpers, with no change to CLI behavior, output shape, or reason codes. (#3267) (#3978) +- **A killed test chunk now names the file that was hanging.** `scripts/run-tests.cjs` logged only chunk starts, so a chunk killed at the 600s cap printed ~55 basenames and left the operator to guess which one hung — and every timing figure had to be reconstructed from CI log timestamps. It now emits per-chunk elapsed time on every path, names the files still in flight on a kill with how stale the last event is (hang vs. merely slow), and ranks the chunk by known weight, flagging files missing from the timings table. (#4012) (#4015) +- **A merged acknowledgment fragment no longer hard-blocks a later PR that grows the same workflow.** The `guard-no-ack-on-next` job only ever watched the legacy `tests/emitted-drift-ack.json`, on the premise that per-PR fragments cannot conflict. They do not share a file, but they do share a path key space — so a fully-spent fragment on `next` kept owning paths it could no longer gate, and the next PR to touch one of them could declare it neither there nor in its own fragment. The guard now sweeps fully-spent fragments, the duplicate-ack error names both resolutions, and the 45 spent fragments on `next` are removed. (#3078) (#3823) +- **Local test runs no longer fail on machines with a global core.hooksPath** — the commit-docs-guard suites refused to install their pre-commit hook in every fresh fixture repo (18 tests read as a guard regression); the suites now pin GIT_CONFIG_GLOBAL to an empty file so children never inherit the host git config (#3901) (#4063) +- **`roadmap validate` and `roadmap milestone-scope` now see bracket-convention phase entries (`### [GSD.04] 01:`)** — with `phase_id_convention: "bracket"` set, a genuinely truncated milestone window warned as nothing (V005 could never fire) while V004 falsely reported "no recognizable phase entries". Both now resolve the convention (config.json, ROADMAP frontmatter fallback) and route V004 through the shared entry predicate, so validate and the milestone-scope probe agree. Bracket milestone headings (`[GSD.02] Name`, no digit token) never count as entries. (#3641) (#3723) +- **Package-legitimacy-gate tests no longer silently drop malformed table rows.** The test suite's markdown-table parsing now reuses the ADR-2143 seam instead of two hand-rolled copies, so a ragged row or an escaped-pipe cell fails loudly instead of being silently mis-parsed. (#3239) (#3977) +- **Pending-outcome cell no longer leaks across calls in one process.** A CLI run that calls `output()` with a payload-carried error and later returns cleanly, or that runs a second `main()` in the same process, could inherit a stale DEGRADED exit code (80 under the v2 exit contract) from an earlier declaration. The cell now follows last-write-wins semantics and is cleared on consumption. (#3912) (#3983) +- **A `scripts/`-side tool that fails unexpectedly under `--json-errors` now emits the documented `{ok:false, reason, message}` envelope** — it previously printed a raw stack trace, because the exit module under `scripts/` was a second hand-written copy that never gained the structured-error branch its `src/` twin has. The copy is now generated from one source and byte-compared in CI, so the two cannot drift again. (#3904) (#3917) +- **Worktree executors no longer fork from the wrong base on long-lived branches** — `worktree.baseRef:"head"` no longer silences the pre-dispatch base check on harness-managed runtimes: the check now compares HEAD against the actual fork base and auto-degrades to sequential execution before dispatch when they diverge, instead of letting every isolated executor die at the exit-42 guard. The suppress now applies only where GSD itself creates worktrees (where the setting is honored by construction). (#3659) (#3736) +- **`audit-uat` no longer reports a clean result for UAT files it silently failed to read.** A phase with three outstanding tests reported zero and then vanished from the report entirely, so nothing cued the reader to go and look. Rows using the template's own `result: issue` outcome, or any wrapped or `expected: |` block-scalar description, were dropped — the second kind was never matched at all, so its result was never read whatever it said. A result token the parser does not recognize is now surfaced rather than discarded, uppercase tokens (`PENDING`, `Blocked`) categorize correctly, a result line with trailing text (`result: pending (blocked on staging)`) is matched again, and an interleaved `## Gaps` section no longer bleeds its reason onto the preceding row. A file whose blocks genuinely fail to parse is reported as a parse gap and counted, so `audit-uat` and `progress` stop declaring all-clear over it — including files in archived milestones, which can still hold a deferred scenario someone left open. (#3707) (#3887) +- **`/gsd-quick` no longer authorizes edit/verification scope from historical state** — when scope depends on mutable external state (a fresh merge index, PR diffs, the working tree), the planner must observe it live or keep the plan's scope conditional; cached PR-diff paths and stale recovery notes are investigation guidance only, so a merge-conflict task can no longer provisionally "authorize" 65 historical paths. (#3786) (#4005) +- **The packaging guard stays armed on npm 12 (Node 26)** — npm 12 emits pack --json as an object keyed by package name, so parsed[0] was undefined, the before() hook threw, and all 6 packaging-guard tests (including both does-NOT-ship gates) went dark for Node 26 contributors (#3902) (#4064) +- **Orphaned GSD hooks in `~/.kimi` can now be reclaimed** — a `--kimi-code` install older than 1.10.0 wrote its hooks block, hook bundle and CommonJS marker into Kimi CLI's `~/.kimi` instead of Kimi Code's own root, and upgrading stranded those artifacts with no path to remove them. Adding `--reclaim-kimi-legacy` to a `--kimi-code` install now clears them; it stays opt-in because the stale block is byte-identical to a legitimate Kimi CLI one, so an automatic cleanup could not tell the two apart. (#3031) (#3731) +- **Global flags now work in any argv position, including before `run-with-timeout`.** Passing `--exit-contract=` before the subcommand — `gsd-tools --exit-contract=v2 state validate` — failed with `Error: Unknown command: --exit-contract=v2`, because the token was read for version resolution but never removed from argv, so the dispatcher treated it as the command name. Separately, `gsd-tools --json-errors run-with-timeout ...` failed with `Unknown command: run-with-timeout` and never ran the child, because `run-with-timeout` is intercepted before the flag is stripped. Both flags are now resolved and stripped ahead of that interception, and `--exit-contract` is listed in `gsd-tools --help`. (#3912) (#3983) +- **The stale-worktree health check no longer flags the worktree you are currently in on Windows** — paths that differ only by drive-letter or folder casing (as-typed vs git's canonical spelling) are now recognized as the same directory on Windows, while case-sensitive comparison is preserved on macOS/Linux. (#3663) (#3793) +- **Completing a phase with `features.global_learnings` enabled now produces the phase's LEARNINGS.md automatically and copies it to the global store** — previously three shipped consumers read an artifact nothing ever generated, and the copy command read a project-root path the extractor never wrote, so the store stayed empty even after manual extraction. Extraction and copy failures never block completion; with the gate off (the default) behavior is unchanged. (#3683) (#3810) +- **`STATE.md`'s `## Current Position` section now documents that its fields are single-valued.** The section is overwritten rather than appended to, and a duplicated `Phase:` line does not simply resolve to the first occurrence — it resolves by form first (bold, then plain, then pipe-table), scoped to the `## Current Position` section, and only within the winning form does the first occurrence win. So a bold line added in good faith after an earlier plain line silently overrides it rather than being ignored. That behavior was always true and was never written down, which is what #3812 reported. Progress history belongs in `## Performance Metrics`, and the reference page now says so in all five languages. (#3812) (#4017) +- **The spec-phase edge probe now classifies requirements in non-English projects** — a project running with `response_language` set had every requirement fall through the English-only shape cues into `unclassified`, silently disabling the whole edge taxonomy; Step 5.5 now feeds the probe an English translation of each requirement while the SPEC keeps its original language. (#2773) (#3713) +- workflow.research_before_questions now works on /gsd:quick (research runs before discussion questions when enabled — a gray-area answer without research becomes a locked decision in the quick task context) and resolves from ~/.gsd/defaults.json like its sibling workflow.post_planning_gaps, which the global-defaults merge previously forwarded while silently dropping this key (#3894) (#4047) +- **Trailing prose below the ledger's JSON block is no longer destroyed when that prose contains its own fenced JSON array** — `writeLedgerAtomic` located the block to preserve prose after by passing the POST-mutation entry count as its disambiguation hint, which can never match the pre-image's own count. The lookup fell back to the last array-shaped fenced block in the file, so an operator's notes containing a ```json array bound the preservation to the wrong fence and everything above it was dropped on the next write — the exact loss the preservation exists to prevent. (#3689) (#3828) +- **The identity classifier and the launcher preamble now reach the same verdict for the same probe** — the two surfaces implement one decision and disagreed on two inputs, a tool that proves itself and then exits non-zero and a payload naming this package outside the anchored wire shape, so the announced hard-fail rollout would have refused installs the warn phase verifies and accepted ones it warns about. (#3841) (#3855) +- **`workflow.use_worktrees=false` now actually wins for executor dispatch** — `query dispatch-isolation` folds the project opt-out into the isolation sentinel it records, so a plain re-query can no longer re-persist the host's worktree capability over the mandated `none` record and have the isolation guard deny the sequential dispatch the project configured. (#3737) (#3938) +- **Global Claude installs now load agent-file `@`-includes** — agent files in a global Claude install (e.g. the planner) carried `@`-includes that silently loaded nothing, so guidance those agents were supposed to read — including the untrusted-input boundary — was absent from their context; those includes now resolve on `~/`. Also fixes a related path-rewrite bug where a `--config-dir` name extending `.claude` (e.g. `.claude-work`) doubled its own suffix in agent-file paths. (#3719) (#3918) +- **Installing with --config-dir into a directory that already holds another harness's agent files now warns instead of failing silently** — the installer says the emitted artifacts are shaped for the selected runtime and their tool IDs and MCP grants may be inert or invalid for the destination harness, then proceeds. Fresh custom directories and GSD-only directories stay silent. (#3664) (#3794) +- **Curated STATE.md content survives writes that measured nothing** — `state record-session`, `state add-decision` and the other resyncing verbs no longer drop a curated `progress:` block once a milestone's phases have been archived, `state planned-phase` without `--name` no longer overwrites `current_phase_name` with a placeholder, `state complete-phase` no longer deletes that key while reporting it as updated, and `state json` no longer serves `last_activity_desc` from stale body prose. (#3871) (#3874) +- **`audit-open acknowledge` no longer reports success on an entry it did not clear** — acknowledging a deferred item whose status is written as a nested list line now records a status the reader actually parses, so acknowledged entries drop out of audit counts instead of resurfacing forever. (#3740) (#3940) +- **`migrate-config` and health repairs no longer write outside the scoped project under `GSD_PROJECT`** — planning-path composition now goes through the project-aware resolver everywhere, so a scoped migration no longer rewrites another project's `config.json`, `project_exists` answers for the project actually being queried, and `validate.health --repair` keeps its writes in one directory. (#3749) (#3955) +- **Interactive runs no longer stop for a checkpoint after every tracer task** — under the `end-of-phase` default a tracer whose `` is automated-only is re-run and expansion continues with no `checkpoint:human-verify`; `mid-flight`, tracers carrying ``, and any tracer carrying `gate="blocking-human"` still stop for a human, and a failing tracer still halts. (#3299) (#3390) +- **Managed hooks no longer bake a prunable fnm version path on macOS and Linux** — `normalizeNodePath` matched only fnm's shim, but Node resolves `process.execPath` through that symlink to the concrete `node-versions//installation/bin/node` directory, so the branch never fired on POSIX and every managed hook was pinned to one Node version. `fnm uninstall` or fnm's own pruning then broke all of them. The versioned path now rewrites to the stable `aliases/default` path, matching how the Homebrew, mise and volta branches already behave. (#3704) (#3856) +- **A fully-spent ack fragment is no longer swept out from under an open pull request that changes more than 100 files** — `gh pr list --json files` truncates each PR file list at 100, so the fragment read as untouched and deleting it handed that PR the modify/delete conflict the staged sweep exists to prevent. (#3842) (#3857) +- **Tiered profiles install the agents their own skills spawn** — the profile closure now follows each command into the workflow files it references (including split workflows' steps/ and modes/ fragments) when deriving the agent set, so `--profile=standard` no longer omits `gsd-verifier` (phase-goal verification failed at the point of spawn, after execution work had landed) or the thirteen other spawn targets living only in workflow bodies. (#3798) (#4009) +- local test runs no longer fail when a daemon keeps a unix socket under the repo root — the overlay builder classified every non-directory entry as a file, so copyFileSync threw ENXIO and 32 tests failed in their before() hooks with no connection to the code under test (#3900) (#4062) +- gsd-ingest-docs new mode now requires an explicit routing approval (Create planning setup | Keep synthesized intel only | Abort) before creating the planning scaffold — approving document classification no longer also authorizes scaffold creation and commit (#3827) (#4037) +- **Bracket-convention icebox and pre-milestone directories no longer produce spurious health warnings** — the disk-side guards could not see bracket sentinel-ness (it lives in the milestone portion of `GSD.999-07-icebox`), so icebox dirs false-fired as roadmap orphans. A dir-aware sentinel recognizer now excludes them exactly like their legacy twins. (#3639) (#3698) +- **A feature fragment declaring a malformed `order:` no longer sorts silently to the top of `docs/FEATURES.md`** — the generator validated that field by coercion, so an empty value read as `0` and hex, octal, binary and exponential values read as numbers, all placing the section ahead of every real feature with no violation and a clean `--check`. (#3840) (#3851) +- **`verify plan-structure` no longer false-flags positively-asserted literals in entity-escaped verify chains** — planners emit `&&` as the chain operator, which the negative-grep gate's segment splitter did not recognize, so a `= 0` clause poisoned `-ge 3` clauses joined to it and pushed authors toward suppressing a real gate. The gate now scans the decoded text the shell would actually run. (#3611) (#3693) + +### Security + +- **Atomic config writes preserve hardened file permissions and create temp files exclusively** — a chmod 600 on settings.json, settings.local.json, or defaults.json now survives the temp+rename write instead of silently resetting to the umask default; temp files are opened with O_EXCL so a symlink pre-planted at the predictable temp path is never followed; and the install-migration lock writes its payload through the exclusively-created descriptor, closing a symlink-swap window between create and write. (#3966) + ## [1.11.0] - 2026-08-19 ### Added