chore: release 2.0.0
Some checks failed
Tests / conformance test (macos-latest, 24) (pull_request) Blocked by required conditions
Tests / conformance test (windows-latest, 24, shard 1/3) (pull_request) Blocked by required conditions
Tests / conformance test (windows-latest, 24, shard 2/3) (pull_request) Blocked by required conditions
Tests / conformance test (windows-latest, 24, shard 3/3) (pull_request) Blocked by required conditions
Tests / Required tests (pull_request) Blocked by required conditions
Changeset Required / PR mergeability (pull_request) Successful in 17s
Default Flip Documentation / PR mergeability (pull_request) Successful in 10s
Dependabot Auto-Merge / auto-merge (pull_request) Has been skipped
Docs Required / PR mergeability (pull_request) Successful in 10s
Mutation Testing / PR mergeability (pull_request) Successful in 10s
Security Scan / PR mergeability (pull_request) Successful in 12s
Tests / PR mergeability (pull_request) Successful in 9s
Tests / Base branch health (pull_request) Successful in 10s
Tests / Detect test scope (pull_request) Successful in 17s
PR Target Validator / validate-target (pull_request_target) Successful in 14s
Branch Cleanup / Delete merged PR branch (pull_request) Failing after 10s
Branch Cleanup / Weekly orphaned branch sweep (pull_request) Has been skipped
Changeset Required / changeset-lint (pull_request) Successful in 29s
Default Flip Documentation / default-flip-documentation (pull_request) Successful in 30s
Docs Required / docs-lint (pull_request) Successful in 5m1s
Mutation Testing / Detect changed covered modules (pull_request) Successful in 19s
Security Scan / security (pull_request) Successful in 5m5s
Tests / lint-tests (pull_request) Failing after 1m48s
Tests / plugin-validate (pull_request) Successful in 1m4s
Tests / test (ubuntu-latest, 24, shard 1/3) (pull_request) Failing after 19s
Tests / test (ubuntu-latest, 24, shard 2/3) (pull_request) Failing after 20s
Tests / test (ubuntu-latest, 24, shard 3/3) (pull_request) Failing after 19s
Tests / test (ubuntu-latest, 24) (pull_request) Failing after 20s
Tests / test (inert CI) (pull_request) Has been skipped
Tests / QA loop walk (smell ratchet) (pull_request) Failing after 20s
Mutation Testing / Stryker (${{ matrix.name }}) (pull_request) Has been skipped
Tests / Coverage gate (merged shards) (pull_request) Has been skipped
Tests / Publish emitted-baseline artifact (pull_request) Has been skipped
Mutation Testing / Stryker mutation score (changed files only) (pull_request) Has been skipped
Some checks failed
Tests / conformance test (macos-latest, 24) (pull_request) Blocked by required conditions
Tests / conformance test (windows-latest, 24, shard 1/3) (pull_request) Blocked by required conditions
Tests / conformance test (windows-latest, 24, shard 2/3) (pull_request) Blocked by required conditions
Tests / conformance test (windows-latest, 24, shard 3/3) (pull_request) Blocked by required conditions
Tests / Required tests (pull_request) Blocked by required conditions
Changeset Required / PR mergeability (pull_request) Successful in 17s
Default Flip Documentation / PR mergeability (pull_request) Successful in 10s
Dependabot Auto-Merge / auto-merge (pull_request) Has been skipped
Docs Required / PR mergeability (pull_request) Successful in 10s
Mutation Testing / PR mergeability (pull_request) Successful in 10s
Security Scan / PR mergeability (pull_request) Successful in 12s
Tests / PR mergeability (pull_request) Successful in 9s
Tests / Base branch health (pull_request) Successful in 10s
Tests / Detect test scope (pull_request) Successful in 17s
PR Target Validator / validate-target (pull_request_target) Successful in 14s
Branch Cleanup / Delete merged PR branch (pull_request) Failing after 10s
Branch Cleanup / Weekly orphaned branch sweep (pull_request) Has been skipped
Changeset Required / changeset-lint (pull_request) Successful in 29s
Default Flip Documentation / default-flip-documentation (pull_request) Successful in 30s
Docs Required / docs-lint (pull_request) Successful in 5m1s
Mutation Testing / Detect changed covered modules (pull_request) Successful in 19s
Security Scan / security (pull_request) Successful in 5m5s
Tests / lint-tests (pull_request) Failing after 1m48s
Tests / plugin-validate (pull_request) Successful in 1m4s
Tests / test (ubuntu-latest, 24, shard 1/3) (pull_request) Failing after 19s
Tests / test (ubuntu-latest, 24, shard 2/3) (pull_request) Failing after 20s
Tests / test (ubuntu-latest, 24, shard 3/3) (pull_request) Failing after 19s
Tests / test (ubuntu-latest, 24) (pull_request) Failing after 20s
Tests / test (inert CI) (pull_request) Has been skipped
Tests / QA loop walk (smell ratchet) (pull_request) Failing after 20s
Mutation Testing / Stryker (${{ matrix.name }}) (pull_request) Has been skipped
Tests / Coverage gate (merged shards) (pull_request) Has been skipped
Tests / Publish emitted-baseline artifact (pull_request) Has been skipped
Mutation Testing / Stryker mutation score (changed files only) (pull_request) Has been skipped
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Added
|
||||
pr: 4111
|
||||
---
|
||||
**Opted-in bracket phase IDs now render consistently on progress surfaces** — `progress`, `stats`, manager init, and both statusline formats display canonical `[CODE.MM] NN` identities only when `phase_id_convention` is exactly `"bracket"`; other conventions retain their existing patterns and output shape. `config-set` now validates the convention's three supported values. (#3638)
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
type: Changed
|
||||
pr: 4676
|
||||
---
|
||||
<!-- docs-exempt: internal type surface + lint-guard capability only; no user-facing behavior. ADR-4629 section 8.1 Phase-1 scaffolding, enforcement is Required in Phase 2. -->
|
||||
Internal (ADR-4629 section 8.1, epic #4629 child C1): introduce the `StateWriteIntent` type, extending `StateTransaction`, and a `readModifyWriteStateMd` opaque-transform recognition capability in the STATE.md write-path drift guard. This is the foundation for verified, bounded STATE.md writes. No user-facing behavior changes and no caller is migrated (that is Phase 2 and later).
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4828
|
||||
---
|
||||
**Gap-closure plans can no longer silently reuse threat IDs that earlier plans in the same phase already assigned** — a `--gaps` re-plan numbered its `<threat_model>` registers from `T-{phase}-01` again, so the new plans claimed IDs that earlier plans had already given to different threats, and nothing detected it: `/gsd-secure-phase` builds `SECURITY.md` rows and `VALIDATION.md` carries a Threat Ref column keyed on that ID, leaving every consumer ambiguous. `init execute-phase` and `init plan-phase` now report cross-plan duplicates (`threat_id_duplicates` / `threat_id_duplicate_count` — register rows only, never prose; the reserved `T-{phase}-SC` row is exempt since every plan keeps it; superseded plans don't hold IDs against their replacements), execute-phase hard-stops on a non-empty list before dispatching any executor, and the planner (agent template + `planner-gap-closure.md` §9) is instructed to continue numbering after the phase's highest in-use `T-{phase}-NN`. (#4683)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4735
|
||||
---
|
||||
`verify.artifacts` no longer aborts a plan's whole artifact check when one listed path is a directory. Reading a directory raised `EISDIR` out of the per-artifact loop, so the command printed `Error: EISDIR: illegal operation on a directory, read` and reported nothing at all — neither the offending entry nor the plan's other, perfectly checkable artifacts. A directory now fails as its own entry, with an issue distinct from `File not found`, and every other artifact is still checked and reported independently. A path that stat or read fails on for any other reason (a permissions error, an unreachable mount, or an artifact that disappears mid-check) fails the same way, carrying its errno, instead of discarding the run.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Changed
|
||||
pr: 4874
|
||||
---
|
||||
**The planner and the phase researcher now query the knowledge graph through the `graphify` CLI when it is on `PATH`, falling back to the built-in reader otherwise** — the planner gets one graph query per phase and the researcher two or three, and that single shot decides which modules the plan treats as related, and therefore how tasks are ordered into waves. It was spent on `seedAndExpand`, which seeds by case-insensitive substring match over a node label and description and then expands a hardcoded two hops: the phase "User Authentication" seeds on `author`, `authoring` and `unauthorized` with the same weight as `authenticate`, and when the inflated payload exceeds `--budget` the trimmer drops edges by confidence tier. The CLI, already a hard dependency of `/gsd-graphify build`, ranks seeds (IDF weighting, trigram fuzzy matching) and context-filters before traversal; the planner additionally runs `graphify affected`, reverse traversal for the exact question its reference states as its own goal, which the built-in reader has no equivalent for and which is skipped on the fallback path. The branch is `command -v graphify`, the same degradation shape already used for Context7 to `ctx7` — no new config key (a graph can only exist if the binary built it, so binary presence is a self-satisfying gate) and no new tool grant (both agents already have `Bash`). `gsd-tools graphify status` now returns `graph_path`, the resolved absolute graph location, on both the present and the missing branch: the CLI takes the graph as `--graph`, and re-deriving `.planning/graphs/graph.json` would point it at a non-existent local mirror in exactly the umbrella multi-repo setup `graphify.graph_path` (#1825) exists to serve — for the same reason the presence gate in both prompts is now the `status` call rather than a bare `ls`, which was already blind to the override. Declared limit: the two paths return different shapes (CLI prose with no `--json`, built-in JSON with confidence tiers and `budget_met`/`budget_estimate`) and `--budget` counts rendered output on one and estimated payload bytes on the other; both prompts state this instead of implying a stable shape. With `graphify` absent from `PATH` the injected context is byte-identical to before. (#4836)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4723
|
||||
---
|
||||
**Commits are no longer blocked when a project configures a large `commit_types` list** — the commit validator built one regular expression out of every configured type, and on macOS (bash 3.2 / BSD libc) that pattern stopped compiling past roughly 6,000 types. The validator reported the compile failure as "this message is not a Conventional Commit" — rejecting a valid `feat(auth): …` while listing `feat` among the valid types it printed. At the same payload the hook could also abort outright with a broken-pipe error instead of returning a verdict. Linux (glibc) has no comparable limit and was never affected by this half. Both paths are fixed and now covered by regression tests. (#4429)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Removed
|
||||
pr: 4716
|
||||
---
|
||||
**Retired the Gemini CLI reviewer lane** — Google stopped serving Gemini CLI for free/Pro/Ultra on 2026-06-18, so `/gsd-review --gemini` spawned a binary that no longer answers for most users. The `--gemini` flag, its three `review.*.gemini` config keys, and its documentation in all five locales are gone; Antigravity's `--agy` lane already covers the Google slot. `gsd config-set review.models.gemini` now reports an unknown key — an existing key in `.planning/config.json` still parses and is simply never read. (#4709)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4896
|
||||
---
|
||||
**verification status and frontmatter get distinguish unparseable YAML from a missing report** — a VERIFICATION.md whose frontmatter has a YAML syntax error was reported as status "missing" (sending the operator to re-run execute-phase, which cannot fix a YAML typo), and frontmatter get answered "Field not found"; both now report a distinct parse error. (#4806)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Changed
|
||||
pr: 4912
|
||||
---
|
||||
**`checkpoint:decision` auto-selection is now opt-in via `auto_select`** — in auto-mode, a decision checkpoint with no `auto_select="<option-id>"` attribute now escalates to a human instead of silently picking the first `<option>`. Add `auto_select` naming the intended option's `id` to keep a plan fully unattended; an `auto_select` that names a non-existent option id now fails `verify plan-structure` at plan-parse time. (#4095)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4825
|
||||
---
|
||||
**TDD red evidence accepts Surefire/Failsafe XML** — the tdd-red-evidence gate parsed only node:test TAP, so a JVM project's genuine Maven red scored INVALID_RED while hand-written synthetic TAP scored RED_EVIDENCE_OK (the gate was passable only by fabricating its input). Surefire/Failsafe XML reports now classify by tag-boundary scanning: a testcase with a <failure> or <error> child for the target class is a real red; self-closing passing cases are never spanned into failing names. (#4724)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4749
|
||||
---
|
||||
**A phase's verification no longer goes `stale` because a repo-wide planning document was rewritten** — `covered_digest` hashed `.planning/ROADMAP.md` and `.planning/REQUIREMENTS.md` byte-for-byte, so completing any phase (or the phase's own `phase.complete` / `requirements mark-complete` bookkeeping) flipped every verification that had declared them to `stale`, failed `complete-milestone`'s `ALL_PHASES_VERIFIED` gate, and forced an `override_closeout` for phases whose implementation had not changed. Fingerprint v2 leaves the repo-wide planning documents — the direct children of the planning root, including a workstream's own — out of the digest by construction (they are still validated, only their bytes are ignored); an existing v1 digest keeps its old meaning until the report is re-fingerprinted, so upgrading stales nothing. Separately, `query verification.fingerprint` now accepts `--files a`, `--files a,b` and repeated `--files` alongside the bare positional form, reports an unknown flag as a usage error instead of "a covered file is missing", and rejects a missing phase directory instead of printing a digest over the wrong set at exit 0. (#4623)
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4813
|
||||
---
|
||||
**verify-work stops flagging honest plans as commit_claim_mismatch** — the reconciliation measured `plan_head_before..HEAD`, a window that grows with every later plan's commits and the phase-completion commit, so any plan except the last read as a BLOCKER. The executor now records `plan_head_after` (HEAD at its measurement moment) and verify-work reconciles against that bounded window with exact equality; legacy SUMMARYs without the anchor fall back to a warning, and the #3968 failure modes still block. (#4670)
|
||||
|
||||
<!-- #4670 un-established edges, per the issue: parallel worktree waves sharing a base and multi-repo commit-to-subrepo ledgers are not covered by the bounded window; the window strictly narrows relative to the previous check. -->
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4880
|
||||
---
|
||||
**roadmap update-plan-progress stops inserting a duplicate plan list beside hand-written ones** — plan checkbox rows written without the -PLAN.md suffix (the hand-written form) were not recognized, so the verb inserted its own canonical list above them, leaving two competing lists for the same plans; suffix-less rows are now recognized and ticked in place. (#4786)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4822
|
||||
---
|
||||
**Antigravity agents get native tool names as a YAML sequence** — converted agents carried Gemini CLI tool names (`read_file`, `search_file_content`, `run_shell_command`) as a comma-separated scalar, while Antigravity's documented subagent contract wants a YAML sequence of native names (`view_file`, `grep_search`, `run_command`, `replace_file_content`); wrong or malformed grants can hang the subagent. The installer's twin converter changes in lockstep. (#4705)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4718
|
||||
---
|
||||
**`/gsd:debug` no longer spawns duplicate debuggers that collide on the session file** — the debug session manager spawned its `gsd-debugger` without `run_in_background=false`, so Claude Code backgrounded it, the manager had no result to inspect, and it returned a non-terminal summary. The orchestrator's auto-resume then started a second debugger against the same `.planning/debug/<slug>.md`, up to the three-resume cap — which is why the collision showed up exactly three times per invocation. The spawn now blocks, matching the rule already applied one level up (#2196). (#4395)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4712
|
||||
---
|
||||
**Slash-command suggestions no longer show the retired `/gsd:` form** — a handful of shipped command descriptions, agent bodies and workflow instructions used `/gsd:` tokens the installer could not convert, so they reached you as the deprecated colon form after a fresh install. One consequence was functional, not cosmetic: `/gsd-help --brief <topic>` looked for a signature line that the installed reference never renders, so every topic silently fell back to its first paragraph. (#4324)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4878
|
||||
---
|
||||
**Claude installs no longer stage the 29 compact agent variants** — agents/*.compact.md shipped beside their canonical siblings with identical name frontmatter, leaving the harness's pick unstated; Claude never selects compact (it is a non-Claude-runtime payload), so the Claude agents directory now holds only the canonical agents, and upgrading removes the stale copies. (#4782)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4832
|
||||
---
|
||||
**`--auto` no longer stops on an artifact that already exists** — `/gsd-ui-phase <phase> --auto` blocked on "UI-SPEC.md already exists for Phase {N}" whenever the file was on disk, which is most often after an earlier run left an unverified draft, so a headless or board run stalled on a question nobody could answer. It now reuses the existing UI-SPEC untouched and proceeds to the checker. `/gsd-spec-phase --auto` had the opposite failure — it auto-selected "Update it" and regenerated a spec nobody was watching, discarding answers already recorded in it — and now also reuses it as-is. The same gap existed in three sibling commands with no prior `--auto` handling at all: `/gsd-ai-integration-phase --auto` now auto-selects Skip for an existing AI-SPEC, and `/gsd-eval-review --auto` / `/gsd-ui-review --auto` now auto-select View for an existing EVAL-REVIEW/UI-REVIEW instead of re-auditing. The max-revision-iterations escalation (Force approve / Edit manually / Abandon) still stops for a person under `--auto`, by design. (#4776)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Changed
|
||||
pr: 4585
|
||||
---
|
||||
**Planner stall detection can now be disabled explicitly** — set `planner.stall_detection_enabled` to `false` to use the runtime-native completion wait without watchdog polling; the default remains enabled, and disabling it gives up bounded automatic recovery.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4711
|
||||
---
|
||||
**Runtime detection no longer resolves a retired runtime to Claude Code** — workflows still mapped `/.gemini/` and `$GEMINI_CONFIG_DIR` to the `gemini` runtime that was removed in 1.8.0, and an unrecognized id silently falls back to Claude Code's config dir, label, and instruction file. Detection now maps Antigravity's real directories, the runtime menu no longer offers the retired Gemini CLI, and the model-tier table no longer advertises built-in defaults for a runtime the catalog does not define. (#4709)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Removed
|
||||
pr: 1
|
||||
---
|
||||
**Support for runtimes other than Claude Code, Codex, OpenCode, Cursor, ZCode and Antigravity has been dropped** — the installer, capabilities, hooks and docs for the other 12 runtimes (including Kimi) are gone, together with the descriptor-driven mechanisms that only they used.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4769
|
||||
---
|
||||
**Deferred UAT follow-ups stop blocking phase completion** — `/gsd-verify-work` deferrals (skipped with a "Deferred follow-up" reason) no longer fail the phase-completion predicate, and completing a session with deferrals now offers to promote them into a `999.x` ROADMAP backlog entry; plain unresolved skips still block as before. (#4546)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4858
|
||||
---
|
||||
**Codex installs rewrite @ includes to the codex root** — codex-installed agents and commands kept `@~/.claude/gsd-core/…` and `@$HOME/.claude/gsd-core/…` includes pointing into the Claude install (silently reading the wrong copy on dual-runtime machines, resolving to nothing on codex-only ones). The installer now rewrites the @-include form across manifest-tracked artifacts; the deliberate `$PREFERRED_CONFIG_DIR`/`_GSD_RUNTIME_ROOT` fallback chains and prose `.claude` mentions stay untouched. (#4667)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4737
|
||||
---
|
||||
**Windows CI chunks no longer exceed their own per-chunk timeout** — the Windows test runner packed up to 40 test files into a chunk that is killed at 600 seconds, but at the measured rate from the chunk that actually died (18,122 ms/file) 40 files need roughly 725 seconds. A chunk could therefore be killed with no test having failed, turning `next` red and blocking every open pull request. The Windows cap is now derived from measured cost rather than tuned by hand, and a test enforces the arithmetic so it cannot silently drift back. Alongside it, a test file absent from `tests/test-timings.json` is no longer priced at the table median — in a distribution skewed 18.8x that modelled an unknown file as roughly 19x cheaper than average, so files nobody had measured packed as though they were nearly free. The heaviest test files (e.g. `state.test.cjs`, `install-minimal-hooks.test.cjs`) now get their own dedicated chunk based on an absolute measured-time bar instead of a ratio of the per-platform file-count cap, so they can never again be crowded into a shared chunk that blows the timeout — and, unlike before, this now applies consistently on every platform and to heavy install-suite files, not only unit-suite ones. (#4733)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4744
|
||||
---
|
||||
**`/gsd-code-review`, `/gsd-code-review-fix`, `gsd-code-fixer`, `/gsd-execute-plan` and `/gsd-plan-phase` now accept letter-variant phase ids (`12A`, `3A`, `23A.1.2`)** — the six shell/markdown phase-number mirrors #4568 widened on the segment-count axis were still digit-only on the letter axis, so a documented, canonical-valid id like `12A` was refused with "Invalid phase number format" by the four validating sites and silently truncated to its digit prefix by the two extracting ones. All six now match the canonical grammar (`src/phase-id.cts`), a parity test proves both sides agree on the letter axis in both directions, and `lint-phase-id-drift` gains a ratchet so a digit-only mirror cannot re-diverge silently. (#4660)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4820
|
||||
---
|
||||
**phase complete no longer names an already-complete phase as next** — completing a reopened phase out of order (later phases already [x]) picked the numerically-next phase even when its checkbox was already ticked, persisting it to STATE.md as current_phase. next_phase now skips phases whose roadmap checkbox is already [x], agreeing with roadmap.analyze and init.progress. (#4699)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4715
|
||||
---
|
||||
**TDD mode no longer trips on every task in Go, Ruby, Elixir and Python projects** — the RED-commit gate looked only for `*.test.*`, `*.spec.*` and `tests/`, so a commit adding `foo_test.go` was invisible and every behaviour-adding task halted with `TDD GATE TRIPPED: missing RED commit`. It now recognises the conventions the TDD reference already advertises, and matches at the repo root as well as in subdirectories. Rust stays a documented gap: `#[test]` lives in the implementation file, so no path-based gate can see it. (#4379)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 1
|
||||
---
|
||||
**`/msd-update` and the update check work again** — they asked npm for a package that was never published, so they could never find an update. Releases are now `vX.Y.Z` git tags with a `stable` branch at the latest one: the update check reads those tags, `/msd-update --next` also considers `-rc.N` tags, and the update reruns the one-line installer pinned to the version it checked, showing that release's changelog first.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4895
|
||||
---
|
||||
**check.decision-coverage-plan stops answering an unmeasured shape** — on could-not-parse it reported covered: 0 / uncovered: [] (fields of a measurement that never happened) and a directory passed as the context path certified passed: true; the gate now answers covered: null / total: null with the unreadable decision ids (and omits uncovered), and a non-file context path fails closed naming the path. (#4794)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4902
|
||||
---
|
||||
**Workflows no longer run a foreign or outdated `gsd_run` from PATH** — the runtime launcher now resolves a project-local or runtime-config-directory install ahead of PATH, and a PATH `gsd_run` is used only when it proves it is @opengsd/gsd-core, so a leftover global install can no longer shadow a local one and trip the pre-commit branch guard. (#4834)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Security
|
||||
pr: 4723
|
||||
---
|
||||
**An exported `CONFIG_STATUS`, `CMD_STATUS`, or `CLASSIFY_STATUS` no longer disables the commit-message gate** — the hook captured each subprocess status with `|| VAR=\$?`, which assigns only when the subprocess fails, so on success the variable kept any value inherited from the environment. A CI wrapper, a `.envrc`, or another hook that exported one of those names made the validator report "validator disabled for this call" and accept a non-conforming commit. The statuses are now initialised before use; a genuine subprocess failure still passes the commit through, as before. (#4429)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4879
|
||||
---
|
||||
**The post-merge gate's Xcode detection works on real project layouts** — the gate resolved the .xcodeproj path but built its commands without -project (any project one directory down failed with exit 66) and hardcoded the iPhone 16 simulator name (a machine property); commands now carry -project, the destination resolves from the machine's available simulators, gates skip loudly when none exists, and the timeout message names the sysdiagnose collector. (#4784)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4755
|
||||
---
|
||||
verify-command-paths no longer reports a false missing_dir blocker when a plan's <automated> command spells the chain operator entity-escaped (cd src && npm test): the command text is now decoded to & before segment splitting, so the escaped and literal forms of the same command get identical verdicts (#4730)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4872
|
||||
---
|
||||
**Worktree cleanup-wave rescues SUMMARY artifacts from relative worktree paths** — a manifest entry carrying a relative `worktree_path` made the rescue walk the CLI's working directory instead of the repo root, finding nothing and blocking the entry `worktree_dirty` instead of rescuing; the rescue now resolves the path against the repo root, the same way every git consumer of the field already does. (#4758)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4842
|
||||
---
|
||||
**Markdown writes no longer insert a blank line between a paragraph and a following list** — every .md write re-normalized the whole document and split tight paragraph→list transitions, reflowing prose the command never touched (e.g. `roadmap.update-plan-progress` editing unrelated phase-section prose). Tight lists now stay byte-identical on disk. (#4725)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4509
|
||||
---
|
||||
**Whitespace-only planning scope values no longer create phantom directories** — `GSD_WORKSTREAM`, `GSD_PROJECT`, and their explicit equivalents now fall back to the root scope, while padded real names are normalized consistently.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4809
|
||||
---
|
||||
**verify-work no longer canonicalizes a vacuous pass** — a UAT session with zero logged issues but every row blocked (0 passed) flipped VERIFICATION.md to `passed`, leaving a phase whose central claim was never observed carrying a passed verification. The canonicalize flip now requires the same `phase uat-passed` predicate the phase-close uses (at least one pass, no blocked/pending/failed rows) and, when it refuses, says the verification stays human_needed with the blocker count. (#4663)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4877
|
||||
---
|
||||
**verify plan-structure stops warning that a logical-OR fallback swallows a failure** — the R4 scan read "||" as a pipe, so the standard "git cat-file -e <sha> || echo missing" ghost-control idiom was flagged as a swallowed failure when "||" is exactly the construct handling it; single pipes (including zsh "|&") still warn. (#4774)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4726
|
||||
---
|
||||
**Runtime-aware model overrides and `dynamic_routing` now affect the agents that actually spawn** — `model_profile_overrides.<runtime>.<tier>` only applied when you had written a `runtime` key into `.planning/config.json`, so it was silently inert for installs that identify their runtime through `GSD_RUNTIME` or the per-install marker. Separately, `dynamic_routing.tier_models` was consulted only on an explicit retry attempt, so the first spawn — the documented case — never used your configured tier. Both now resolve through the runtime that is actually running, and an explicit model pin like `claude-opus-4-8` is no longer collapsed to a Claude-only alias when a different runtime is active. Projects without `dynamic_routing` enabled are unaffected. Note that if your `.planning/config.json` already carries `dynamic_routing.tier_models` or a `model_profile_overrides` block for a runtime you resolve via `GSD_RUNTIME`, those settings were previously inert and now take effect — review them before upgrading. (#4505)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4868
|
||||
---
|
||||
**Harness-worktree waves no longer degrade to sequential on a stale origin/HEAD when the fork base is confirmed from a prior worktree** — the worktree base-check now observes the harness's actual fork behavior from a clean prior harness worktree at the orchestrator HEAD before degrading; every unobservable case still degrades exactly as before. (#4588)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4876
|
||||
---
|
||||
**init.manager stops reporting dates, shas and ledger ids as phase dependencies** — dep_phases scraped every digit run out of a phase's Depends-on prose, so phases whose prose declares no dependency read as blocked (dates split into year/month/day, git shas fragmenting, WINDOWS ledger ids, even the phase's own number); extraction now pulls only Phase-prefixed references — including "Phases 1, 2, and 3" lists and "Phase 1-3" ranges — and planning-inspect's dependencies field uses the same anchored grammar. (#4764)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4789
|
||||
---
|
||||
**The secret-read guard no longer blocks container --env-file** — `docker`/`docker compose`/`podman`/`nerdctl` --env-file passes a file to the runtime without its contents ever reaching the conversation, so the operational rebuild works again; direct reads of secrets still block. (#4639)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4920
|
||||
---
|
||||
**Codex agents with Write/Edit tool contracts now run under workspace-write** — the 17-role read-only hold is lifted: official OpenAI documentation establishes sandbox_mode as an enforced boundary, so each Codex agent's sandbox now derives purely from its own declared tools. (#4770)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4807
|
||||
---
|
||||
**The UI plan gate now recognizes native UI projects** — a SwiftUI, Jetpack Compose, Flutter, or .NET MAUI project never tripped the static frontend-evidence check, so the gate that requires a UI-SPEC before planning a UI phase silently never fired for them. A `.xaml` file, or a `.swift`/`.kt`/`.dart` file importing its ecosystem's UI framework, now counts as evidence; non-UI native packages (a Swift CLI, a plain Kotlin server) stay silent. (#4658)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4800
|
||||
---
|
||||
**The spec/ui zero-applicable guard now fires on the all-unclassified case** — probe coverage exposes an `unclassified` count beside `applicable`, and spec-phase/ui-phase warn when every requirement classifies to nothing instead of reporting a healthy non-zero total; `applicable` itself is count-preserving. (#4656)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4919
|
||||
---
|
||||
**`state record-session` reports the record it replaces** — overwriting a prior Stopped At or Resume File handoff now names the displaced text in the verb's payload instead of succeeding silently, and the executor decision loop passes --phase so decisions stop inheriting whichever phase the global pointer names. (#4763)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4826
|
||||
---
|
||||
**Roadmap queries read past hard-wrapped Goal/Requirements fields** — the roadmapper soft-wraps long fields at ~85 chars, but five single-line field regexes truncated every wrapped Goal/Requirements at the first line: plan-phase's phase_req_ids silently dropped continuation-line REQ IDs (escaping the Requirements Coverage Gate), get-phase/analyze cut the goal mid-sentence, and phase complete left later REQs Pending with empty warnings. A shared multiline extractor now reads wrapped fields to the next field label. (#4731)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4781
|
||||
---
|
||||
**phase-plan-index now exposes DAG-ready plans** — `ready_plans` (and per-plan `ready`/`unresolved_dependencies`) distinguish plans whose dependencies all have completion evidence from those merely unblocked by a halt; /gsd-execute-phase dispatches only ready plans and reports what it is waiting on instead of skipping incomplete predecessors. (#4628)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4950
|
||||
---
|
||||
**Windows conformance CI no longer times out on newly-added test files** — a chunk holding several files not yet in the timing table could blow the 600s per-chunk budget even though each looked individually affordable; unmeasured files are now capped at 2 per chunk on Windows so a batch of new conformance-tier tests can no longer compound into a red `next`. (#4949)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4898
|
||||
---
|
||||
**phase complete no longer rewrites prose outside the Current Position section** — the Current Plan reset's fallback matched any hard-wrapped line starting with "plan:" anywhere in STATE.md (case-insensitive, first match wins), silently replacing narrative text with "Not started"; the reset is now scoped to the Current Position section, while legacy sectionless layouts keep their recorded whole-body behavior. (#4823)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4778
|
||||
---
|
||||
**Codex orchestrator-worktree workers now persist a durable lifecycle record** — external executors dispatched by /gsd-execute-phase record their launch and terminal state (worktree worker-record/worker-status/worker-complete), so a resumed session reconciles finished or blocked workers from persisted state instead of manual PID discovery, and never re-dispatches a recorded plan. (#4624)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4425
|
||||
---
|
||||
**Local installs can keep `@` includes inside each worktree** — `--relative-includes` (or `GSD_RELATIVE_INCLUDES=1`) writes project-relative includes instead of binding every worktree to whichever checkout ran the installer. (#4377)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Changed
|
||||
pr: 3861
|
||||
---
|
||||
**`/gsd-execute-phase`'s code review gate now reports what it found and records what happened to it** — the gate parsed REVIEW.md's severity counts and discarded them, printing a message that was byte-identical for one `info` finding and for a Critical, and nothing recorded a per-finding disposition anywhere. It now states the breakdown (`23 findings — 1 critical, 9 warning, 8 info`, accepting `blocker:` as the documented tier-equivalent of `critical:`) and writes `<NN>-REVIEW-DISPOSITION.md` beside the review, one row per finding defaulting to `open`, preserving any disposition a human recorded, and carrying a row forward even after the review stops reporting it. `/gsd-code-review <N> --fix` reconciles `fixed`/`skipped` into the same ledger once its report exists, and `--auto`'s iterations are reconciled too — the loop overwrites its fix report each pass and the re-review drops what it fixed, so the gate reads the per-iteration backups before they are removed, and a finding closed in iteration 1 is recorded as `fixed` rather than as never triaged. A decision is carried forward only while the finding ID still names the same finding — the ledger records each finding's title, so a renumbered `CR-01` cannot inherit an earlier `CR-01`'s disposition; when an ID is reused the earlier decision loses its row and the drop is reported. Severity follows the section a finding is filed under, an out-of-vocabulary disposition falls back to `open` rather than counting as a decision, and a finding whose heading the gate cannot parse is reported rather than dropped. The gate stays advisory and never blocks. (#3829)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4810
|
||||
---
|
||||
**`/gsd-code-review --fix` now works on an existing REVIEW.md even when no source files changed** — incremental scoping (#3661) narrowed the review file set to empty for phases whose only post-review changes were planning artifacts, and the empty-scope check exited the whole workflow before the fix step, so standing findings could never be addressed. With `--fix` and an existing REVIEW.md, the empty scope now routes straight to the fix workflow instead of skipping. (#4665)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4892
|
||||
---
|
||||
**run-with-timeout works from project paths containing spaces on Windows** — the .cmd/.bat mediation quoted the shim path and cmd.exe /s stripped the wrong quotes, so every mediated call under a spaced project path failed with exit 1 and empty stdout (the /gsd-code-review fallow pre-pass included); the mediation now uses the same projectSpawnInvocation seam as every other Windows spawn site. (#4797)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Changed
|
||||
pr: 4249
|
||||
---
|
||||
**`gsd install` and `/gsd-update` now verify every GSD-managed runtime entrypoint before reporting success** — a hook script or its interpreter that is missing, unreadable, or not executable now fails the install with the offending paths named, instead of printing `Done!` over a configuration whose hooks can never fire.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4713
|
||||
---
|
||||
**Repeated reviews no longer overwrite each other's preserved evidence** — a second review of the same phase silently replaced the first run's lane reports and error stubs in `.review-diagnostics/`, because the copy used each file's lane-named basename and a lane slug is stable across runs. Each run's evidence now lands in its own subdirectory, named after that run, so repeat reviews accumulate diagnostics instead of clobbering them. (#4351)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4893
|
||||
---
|
||||
**init.manager resolves archived phase directories** — a phase archived to .planning/milestones/vX.Y-phases/ with a passing verification reported no_directory / phase_complete: false (indistinguishable from never started), so /gsd-autonomous's default discovery skipped or mis-sequenced it; the manager's phase lookup now threads the convention through findPhaseInternal, which resolves live directories first and archived milestones second. (#4801)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4861
|
||||
---
|
||||
**A genuinely installed non-Claude runtime now resolves its own models instead of an empty string** — the per-install runtime identity is materialized into the config, so a marker-detected Codex install resolves its tier map past a shared `resolve_model_ids:"omit"` that was written for Claude protection; Claude resolutions and garbage runtime values behave exactly as before. (#4717)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Added
|
||||
pr: 4918
|
||||
---
|
||||
**Planning documents are now read and written through one parse → mutate → serialize seam** — a new internal `PlanningDoc` layer composes the existing markdown-sectionizer, markdown-table and frontmatter seams so a verb can no longer bring its own regex to a `.planning/` artifact. A field write reaches only its own value token, leaving hand-written prose on the same line intact by construction; serialization splices into the original buffer, so untouched regions stay byte-identical; and a write refuses outright on a document containing any region the parser could not read. No command changes behavior yet — this phase adds the seam and migrates no call site. (#4906)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4533
|
||||
---
|
||||
**`/gsd-code-review` can parse phase SUMMARY files without shell syntax errors** — the embedded JavaScript now runs from a literal heredoc and receives the SUMMARY path through `argv`, so quotes and backticks cannot break the workflow command. (#4461)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4821
|
||||
---
|
||||
**mempalace capture queues instead of dropping writes** — the headless `mempalace mine` ran in the foreground, so a concurrent writer holding the palace lock made it exit 1 and the onError: skip step silently dropped the capture. The mine now queues via `--daemon --background` (MemPalace runs it when the lock frees), and the capture report surfaces the queued or skipped outcome instead of staying silent. (#4700)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4612
|
||||
---
|
||||
worktree cleanup-wave no longer blocks an entry whose worktree directory the harness already removed: the branch merges and teardown prunes the stale admin entry instead of failing. Identity still comes from git's own worktree registration, so a path registered to a different branch blocks exactly as before, and removal must be confirmed by an ENOENT — a worktree that merely cannot be read blocks rather than being treated as removed. Every entry in a wave is evaluated against the registration as it stood before any teardown pruned it, so one removed worktree no longer strands the rest.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Changed
|
||||
pr: 4732
|
||||
---
|
||||
**Antigravity's tool-name converter is named for Antigravity** — the helpers that map Claude tool names into Antigravity agent frontmatter were still named for the Gemini CLI runtime that was removed in 1.8.0, so anyone reading the installer saw a converter for a runtime GSD no longer supports. The mapping itself is unchanged: Antigravity runs on the Gemini backend and still receives the same tool names it always did. (#4727)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Changed
|
||||
pr: 4771
|
||||
---
|
||||
**`/gsd-autonomous --converge` now overrides the convergence config gate** — an explicit `--converge` or `--cross-ai` enables plan-review convergence for that run even when `workflow.plan_review_convergence` is `false`, instead of stopping with an enable instruction; without the flag, planning runs `gsd-plan-phase` as before, and the gate continues to govern standalone `/gsd-plan-review-convergence`. (#4600)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4753
|
||||
---
|
||||
**The four translated READMEs no longer advertise a retired runtime** — Japanese, Korean, Brazilian Portuguese and Simplified Chinese each still listed `Gemini CLI` among the supported runtimes and in the installer's runtime prompt, a year after #1928 removed it; all three sites per locale now match English. `VERSIONING.md` also listed a manifest that #1928 deleted, and omitted the VS Code manifest that replaced it. A new `lint-retired-runtime-name` check now fails CI if a retired runtime is named as live in shipped Markdown. (#4729)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4775
|
||||
---
|
||||
**run-with-timeout now kills the whole process tree on Windows** — a timed-out command's descendants (e.g. a model CLI wrapped via workflow.cross_ai_command) no longer survive the timeout and keep running unbounded; POSIX behavior is unchanged. (#4601)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4933
|
||||
---
|
||||
**ROADMAP.md's `**Plans:**` line no longer drops hand-written trailing notes when a phase completes.** Both writers of the Plans field — `phase complete` and `roadmap update-plan-progress` — now go through the parse -> mutate -> serialize seam ADR-4910 locks instead of their own regexes, so a phase-complete count bump can no longer replace-to-end-of-line and silently drop a trailing human annotation, and both writers now treat a fresh-template placeholder, a real count, and freeform/bracketed prose identically. (#4852)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4921
|
||||
---
|
||||
**`/gsd-execute-phase` waves no longer degrade to sequential on an unmerged branch when `worktree.baseRef:"head"` is set on a Claude Code host** — the pre-dispatch base check assumed the harness ignored the setting, a finding from an older Claude Code that upstream fixed in 2.1.128, and so reported `baseref-head-ignored-by-harness` for every wave whose HEAD differed from `origin/HEAD`. #4868 added an observation of a clean prior harness worktree at HEAD that lifts the degrade, but an `execute-phase` run never has one at the moment it checks, so the common case was unchanged. The check now trusts `"head"` in both isolation modes, the way the harness actually behaves (measured from all three settings layers on macOS, Windows and Linux), and gains a `--observed-fork-base <sha>` input so a measured fork base can replace the `origin/HEAD` inference — a mismatch under `"head"` still degrades and warns. A Claude Code `WorktreeCreate` hook in any of the settings files the check reads, or a settings file that does not parse, withholds that trust, because the hook creates the worktree without applying `worktree.baseRef`: the check then compares against `origin/HEAD` and degrades with `baseref-head-bypassed-by-hook`. The #4868 prior-worktree observation is withheld there rather than consulted: a worktree sitting at HEAD carries no record of which creator left it there, so one the plain harness created before the hook was configured is indistinguishable from one the hook created — on a hook host only `--observed-fork-base` restores a trusted verdict. Without the setting the harness does fork from `origin/HEAD`, and that degrade is unchanged. The spawn-time exit-42 guard remains the backstop on a host that does not honor the setting. (#4881)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4847
|
||||
---
|
||||
**OpenCode installs no longer flag all 72 GSD skills as custom files** — the installer's file manifest now records the skills it stages for OpenCode, matching every other skills-layout runtime, so clean installs report zero custom files. The first update after upgrading may show the custom-files backup prompt once while the manifest catches up; from then on updates run without it. (#4738)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Changed
|
||||
pr: 4742
|
||||
---
|
||||
**A workflow can no longer declare a loop-host agent role belonging to another step family** — the Loop Host Contract assigns each of the five loop steps a role family (orchestration, planning, execution), but nothing enforced it: adding `orchestrator` to an execute step `agent-roles` line compiled cleanly, and capability contributions could then target the orchestrator at execution points. Contract generation now rejects a cross-family role, a role outside the vocabulary, and an unknown step, reporting every offender rather than the first. No existing workflow or capability changes. (#4740)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4756
|
||||
---
|
||||
**Asking for a retired runtime no longer silently installs Claude Code** — passing a sunset runtime id resolved to Claude Code's label and config home, so `getGlobalConfigDir('gemini')` and `getGlobalConfigDir('claude')` returned byte-identical paths and the install reported itself as Claude Code. The four runtime-resolution accessors now fail with a message naming the successor and the retiring issue. Genuinely unknown and future runtime ids keep their existing safe defaults, which is a deliberate distinction: absence of knowledge is not the same as recorded retirement. (#4709)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4804
|
||||
---
|
||||
**The UI consideration probe reads an optional `text_en` field** — in a `response_language` project every UI element used to classify to zero categories and land in `unclassified`, dropping the whole state-coverage axis; a faithful English translation per element now classifies exactly like its English equivalent. Mirrors the edge probe's #3717 remedy; an empty or whitespace `text_en` fails closed. (#4657)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4719
|
||||
---
|
||||
**`verify references` no longer mishandles `:LINE` citations** — backtick citations with a line suffix (e.g. `src/foo.ts:42`) are now checked instead of silently dropped, and @-citations with a line suffix resolve against the underlying file instead of being reported missing (#4678).
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4875
|
||||
---
|
||||
**Installer stops warning that hooks may not load when they already load as CommonJS** — installing over an existing hooks/package.json that declares "type": "commonjs" (any hand-written or formatter-touched file) printed "GSD hooks may not resolve as CommonJS"; the warning now states will-not-load only for the case that is true, a declared "type": "module", matching the plugin-path wording. (#4759)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4883
|
||||
---
|
||||
**Decision bullets with code spans in their titles now parse** — a backticked token like `node:http` or `*-UAT.md` inside a decision's bold lead-in was treated as a malformed separator and the whole decisions block failed to parse, hard-blocking the decision-coverage gate; backticked spans are now opaque to the grammar, while a bare colon outside a code span still fails loud. (#4788)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4903
|
||||
---
|
||||
**Windows conformance-tier CI no longer blows its own chunk timeout on unmeasured test files.** `scripts/run-tests.cjs` now weighs a test file absent from `tests/test-timings.json` at the documented ~2.2x Windows-cost floor instead of the plain (Linux-measured) table mean, on win32 only — a cluster of unmeasured conformance-tier files could otherwise pack into one chunk and exceed the 600s per-chunk backstop even though the chunk looked in-budget. (#4434)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4766
|
||||
---
|
||||
**`worktree cleanup-wave` no longer kills an executor merge at the 10-second git plumbing timeout while a `pre-merge-commit` hook runs** — the merge step now carries its own 10-minute budget (`deps.mergeTimeoutMs`), a merge that does exceed it blocks on a distinct `merge_timed_out` reason naming the budget instead of a `merge_failed` carrying the hook's partial output, and the staged-but-no-`MERGE_HEAD` index a killed merge leaves in the primary checkout is detected and restored with `git reset --merge` (reported per path as `merge_residue_restored`; `merge_residue_left_staged` halts the wave when it cannot be), so committing from the primary after a killed merge no longer squashes the executor's history. (#4721)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Changed
|
||||
pr: 1
|
||||
---
|
||||
**MSD is a hard fork of GSD, renamed to MSD (Make Software Done)** — commands are now `/msd-*`, the CLI is `msd-tools`, the package is `@golem15/msd-core`, and the project lives at https://git.golem15.com/golem15/msd-core. MSD is not published to npm: install it with `curl -fsSL https://msd.golem15.com | bash`, which clones the latest release, builds it and installs it for Claude Code (pass `--codex`, `--opencode`, … or `--local` after `bash -s --`).
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4754
|
||||
---
|
||||
**Seeds minted by parallel workstreams no longer share an id by construction** — `/gsd:capture --seed` derives `SEED-YYMMDD-xxx` from the local date plus a random suffix instead of counting files in `.planning/seeds/`, which each worktree could only do from what had merged, so two workstreams planting before either merged both picked the same id; the residual same-day collision bound (~1 in 46,656 per pair) is the one the `.planning/quick/` scheme already accepts. Existing `SEED-NNN` seeds keep resolving in list, enrich, the new-milestone scan, and audit — whose scan now publishes the same canonical id as `list-seeds` and whose acknowledge resolves either id to the same file. (#4378)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4472
|
||||
---
|
||||
**`/gsd:undo --phase` and `--plan` no longer select commits from an unreachable branch, and refuse rather than anchor on a directory an earlier milestone used** — commit selection now anchors on the target phase's own directory (the `#3995` `PHASE_START` pattern already used by `code-review.md`) and runs over `PHASE_START^..HEAD` instead of a repository-wide `git log --all` commit-subject grep. The dead `.planning/.phase-manifest.json` primary path, which nothing in the repository writes, is removed rather than left as documented-but-unreachable behaviour, and both modes now fail closed when no anchor resolves instead of widening to an unbounded search. Two refusals cover the previous-milestone routes the anchor cannot distinguish on its own: a phase number that resolves to an archived `milestones/v<X.Y>-phases/` directory, and a **live** directory whose name also exists as a directory under an archived milestone (a later milestone reusing both the number and the slug re-creates the same literal path, so the oldest add there is the earlier occupant's). The first: `find-phase`'s ambiguity check does not span search directories, so a number that is no longer live resolves silently to the oldest archived milestone that has one — and anchoring there both misses that phase's real work and drags a *later* milestone's same-numbered phase into the window. `dependency_check` reads the workstream-resolved planning root, so an active workstream's roadmap and phase directories are consulted rather than the root's. (#4465)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4818
|
||||
---
|
||||
**Stale verification now routes to the verifier** — the `stale` status told users to re-run `/gsd-verify-work`, but that workflow never rewrites VERIFICATION.md, so following the advice looped forever. The routing now names the regeneration path (execute-phase resumes at the verification gates and re-runs the verifier), and verify-work's stale stop dispatches `gsd-verifier` and re-checks instead of self-referencing. (#4682)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Added
|
||||
pr: 4477
|
||||
---
|
||||
**`/gsd-ui-review` can capture post-interaction UI states** — a new default-off `workflow.ui_interaction_capture` key on the `ui` capability lets `gsd-ui-auditor` add hover, focus-ring, open-menu and filled-form captures through the `chrome-devtools` CLI, driven from Bash with no MCP server and no tool-surface change. Requires an installed Chrome; when off, or when none resolves, the Playwright-only static capture runs exactly as before. (#4223)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4798
|
||||
---
|
||||
**Seeds captured by /gsd-explore are now real seeds** — explore delegates to the plant-seed workflow (SEED- id, status, trigger_when) instead of writing a `.planning/seeds/{slug}.md` shape that list-seeds, audit-open and /gsd-new-milestone could never see. (#4648)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4843
|
||||
---
|
||||
**Agent dispatch no longer blocks on a project root that is not a git repository** — `worktree.base-check` now degrades to sequential when git definitively reports no repository, and the isolation guard's stale-sentinel fallback no longer demands `isolation="worktree"` where no worktree can be created (multi-repo workspace roots). Repos with a real HEAD behave exactly as before. (#4734)
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4851
|
||||
---
|
||||
**A superseded plan no longer reads as executed in the ROADMAP** — the roadmap update-plan-progress checkbox tick now skips plans the count already excludes as superseded, so the "N/M plans executed" line and the checkboxes below it always agree. (#4741)
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4743
|
||||
---
|
||||
**The docs and workflow prose no longer offer Gemini CLI as a runtime** — translated guides still walked readers through installing GSD for a runtime Google shut off in 2026-06, including an install command that now just prints a sunset notice and exits, and the workflow text the agent reads at runtime still named it as a non-Claude option. Antigravity is the documented successor and is what those surfaces name now. (#4728)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4760
|
||||
---
|
||||
**Codex rollback no longer leaves a partially-installed payload behind** — the installer's rollback snapshot now covers every file the previous install's manifest recorded (CHANGELOG.md, scripts/, .gsd-runtime, the manifest itself) plus the whole `hooks/` directory, instead of only config.toml, hooks.json, skills/, agents/ and VERSION, so a failed install reverts to the true pre-install state. (#4544)
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 4873
|
||||
---
|
||||
**`/gsd-execute-phase`, `/gsd-autonomous --from|--to|--only`, `/gsd-plan-review-convergence` and the TDD plan path now handle letter-variant phase ids (`12A`, `3A`, `23A.1.2`)** — seven shell sites outside #4660's six still assumed a phase number was digits-and-dots: the post-#4619 `$((10#$PHASE_INT))` split aborted bash on `03A`, the review-file lookup's `printf "%02d"` printed the wrong file (and read an already-padded `08` as octal), and the `--from`/`--to`/`--only` and plan-review-convergence extractions silently truncated `12A` to `12` (and `23.1.2` to `23.1`). The split now stops at the first non-digit, `init execute-phase` emits `padded_phase` for the lookup, the extractions use the canonical grammar, the legacy normalizer pads a letter id, a parity test drives every site's live shell against a letter-suffixed fixture, and `lint-phase-id-drift` gains three ratchets so none of the shapes can return silently. (#4748)
|
||||
@@ -9,7 +9,7 @@
|
||||
{
|
||||
"name": "msd-core",
|
||||
"description": "MSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
|
||||
"version": "1.14.0",
|
||||
"version": "2.0.0",
|
||||
"source": "./",
|
||||
"author": {
|
||||
"name": "golem15",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "msd-core",
|
||||
"displayName": "MSD Core",
|
||||
"version": "1.14.0",
|
||||
"version": "2.0.0",
|
||||
"description": "MSD Core is a meta-prompting, context engineering, and spec-driven development system for AI coding agents.",
|
||||
"author": {
|
||||
"name": "golem15",
|
||||
|
||||
113
CHANGELOG.md
113
CHANGELOG.md
@@ -1,11 +1,122 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to GSD will be documented in this file.
|
||||
All notable changes to MSD will be documented in this file.
|
||||
|
||||
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2.0.0] - 2026-10-09
|
||||
|
||||
First release of MSD, the golem15 hard fork of GSD. It renames everything GSD → MSD, keeps six runtimes (Claude Code, Codex, OpenCode, Cursor, ZCode, Antigravity), and installs and updates from git release tags instead of npm: `curl -fsSL https://msd.golem15.com | bash`. It also includes all GSD changes made after 1.14.0. See **Changed**, **Removed** and **Fixed** below for the fork-specific entries.
|
||||
|
||||
### Added
|
||||
|
||||
- **Opted-in bracket phase IDs now render consistently on progress surfaces** — `progress`, `stats`, manager init, and both statusline formats display canonical `[CODE.MM] NN` identities only when `phase_id_convention` is exactly `"bracket"`; other conventions retain their existing patterns and output shape. `config-set` now validates the convention's three supported values. (#3638) (#4111)
|
||||
- **Planning documents are now read and written through one parse → mutate → serialize seam** — a new internal `PlanningDoc` layer composes the existing markdown-sectionizer, markdown-table and frontmatter seams so a verb can no longer bring its own regex to a `.planning/` artifact. A field write reaches only its own value token, leaving hand-written prose on the same line intact by construction; serialization splices into the original buffer, so untouched regions stay byte-identical; and a write refuses outright on a document containing any region the parser could not read. No command changes behavior yet — this phase adds the seam and migrates no call site. (#4906) (#4918)
|
||||
- **`/gsd-ui-review` can capture post-interaction UI states** — a new default-off `workflow.ui_interaction_capture` key on the `ui` capability lets `gsd-ui-auditor` add hover, focus-ring, open-menu and filled-form captures through the `chrome-devtools` CLI, driven from Bash with no MCP server and no tool-surface change. Requires an installed Chrome; when off, or when none resolves, the Playwright-only static capture runs exactly as before. (#4223) (#4477)
|
||||
|
||||
### Changed
|
||||
|
||||
- Internal (ADR-4629 section 8.1, epic #4629 child C1): introduce the `StateWriteIntent` type, extending `StateTransaction`, and a `readModifyWriteStateMd` opaque-transform recognition capability in the STATE.md write-path drift guard. This is the foundation for verified, bounded STATE.md writes. No user-facing behavior changes and no caller is migrated (that is Phase 2 and later). (#4676)
|
||||
- **The planner and the phase researcher now query the knowledge graph through the `graphify` CLI when it is on `PATH`, falling back to the built-in reader otherwise** — the planner gets one graph query per phase and the researcher two or three, and that single shot decides which modules the plan treats as related, and therefore how tasks are ordered into waves. It was spent on `seedAndExpand`, which seeds by case-insensitive substring match over a node label and description and then expands a hardcoded two hops: the phase "User Authentication" seeds on `author`, `authoring` and `unauthorized` with the same weight as `authenticate`, and when the inflated payload exceeds `--budget` the trimmer drops edges by confidence tier. The CLI, already a hard dependency of `/gsd-graphify build`, ranks seeds (IDF weighting, trigram fuzzy matching) and context-filters before traversal; the planner additionally runs `graphify affected`, reverse traversal for the exact question its reference states as its own goal, which the built-in reader has no equivalent for and which is skipped on the fallback path. The branch is `command -v graphify`, the same degradation shape already used for Context7 to `ctx7` — no new config key (a graph can only exist if the binary built it, so binary presence is a self-satisfying gate) and no new tool grant (both agents already have `Bash`). `gsd-tools graphify status` now returns `graph_path`, the resolved absolute graph location, on both the present and the missing branch: the CLI takes the graph as `--graph`, and re-deriving `.planning/graphs/graph.json` would point it at a non-existent local mirror in exactly the umbrella multi-repo setup `graphify.graph_path` (#1825) exists to serve — for the same reason the presence gate in both prompts is now the `status` call rather than a bare `ls`, which was already blind to the override. Declared limit: the two paths return different shapes (CLI prose with no `--json`, built-in JSON with confidence tiers and `budget_met`/`budget_estimate`) and `--budget` counts rendered output on one and estimated payload bytes on the other; both prompts state this instead of implying a stable shape. With `graphify` absent from `PATH` the injected context is byte-identical to before. (#4836) (#4874)
|
||||
- **`checkpoint:decision` auto-selection is now opt-in via `auto_select`** — in auto-mode, a decision checkpoint with no `auto_select="<option-id>"` attribute now escalates to a human instead of silently picking the first `<option>`. Add `auto_select` naming the intended option's `id` to keep a plan fully unattended; an `auto_select` that names a non-existent option id now fails `verify plan-structure` at plan-parse time. (#4095) (#4912)
|
||||
- **Planner stall detection can now be disabled explicitly** — set `planner.stall_detection_enabled` to `false` to use the runtime-native completion wait without watchdog polling; the default remains enabled, and disabling it gives up bounded automatic recovery. (#4585)
|
||||
- **`/gsd-execute-phase`'s code review gate now reports what it found and records what happened to it** — the gate parsed REVIEW.md's severity counts and discarded them, printing a message that was byte-identical for one `info` finding and for a Critical, and nothing recorded a per-finding disposition anywhere. It now states the breakdown (`23 findings — 1 critical, 9 warning, 8 info`, accepting `blocker:` as the documented tier-equivalent of `critical:`) and writes `<NN>-REVIEW-DISPOSITION.md` beside the review, one row per finding defaulting to `open`, preserving any disposition a human recorded, and carrying a row forward even after the review stops reporting it. `/gsd-code-review <N> --fix` reconciles `fixed`/`skipped` into the same ledger once its report exists, and `--auto`'s iterations are reconciled too — the loop overwrites its fix report each pass and the re-review drops what it fixed, so the gate reads the per-iteration backups before they are removed, and a finding closed in iteration 1 is recorded as `fixed` rather than as never triaged. A decision is carried forward only while the finding ID still names the same finding — the ledger records each finding's title, so a renumbered `CR-01` cannot inherit an earlier `CR-01`'s disposition; when an ID is reused the earlier decision loses its row and the drop is reported. Severity follows the section a finding is filed under, an out-of-vocabulary disposition falls back to `open` rather than counting as a decision, and a finding whose heading the gate cannot parse is reported rather than dropped. The gate stays advisory and never blocks. (#3829) (#3861)
|
||||
- **`gsd install` and `/gsd-update` now verify every GSD-managed runtime entrypoint before reporting success** — a hook script or its interpreter that is missing, unreadable, or not executable now fails the install with the offending paths named, instead of printing `Done!` over a configuration whose hooks can never fire. (#4249)
|
||||
- **Antigravity's tool-name converter is named for Antigravity** — the helpers that map Claude tool names into Antigravity agent frontmatter were still named for the Gemini CLI runtime that was removed in 1.8.0, so anyone reading the installer saw a converter for a runtime GSD no longer supports. The mapping itself is unchanged: Antigravity runs on the Gemini backend and still receives the same tool names it always did. (#4727) (#4732)
|
||||
- **`/gsd-autonomous --converge` now overrides the convergence config gate** — an explicit `--converge` or `--cross-ai` enables plan-review convergence for that run even when `workflow.plan_review_convergence` is `false`, instead of stopping with an enable instruction; without the flag, planning runs `gsd-plan-phase` as before, and the gate continues to govern standalone `/gsd-plan-review-convergence`. (#4600) (#4771)
|
||||
- **A workflow can no longer declare a loop-host agent role belonging to another step family** — the Loop Host Contract assigns each of the five loop steps a role family (orchestration, planning, execution), but nothing enforced it: adding `orchestrator` to an execute step `agent-roles` line compiled cleanly, and capability contributions could then target the orchestrator at execution points. Contract generation now rejects a cross-family role, a role outside the vocabulary, and an unknown step, reporting every offender rather than the first. No existing workflow or capability changes. (#4740) (#4742)
|
||||
- **MSD is a hard fork of GSD, renamed to MSD (Make Software Done)** — commands are now `/msd-*`, the CLI is `msd-tools`, the package is `@golem15/msd-core`, and the project lives at https://git.golem15.com/golem15/msd-core. MSD is not published to npm: install it with `curl -fsSL https://msd.golem15.com | bash`, which clones the latest release, builds it and installs it for Claude Code (pass `--codex`, `--opencode`, … or `--local` after `bash -s --`). (#1)
|
||||
|
||||
### Removed
|
||||
|
||||
- **Retired the Gemini CLI reviewer lane** — Google stopped serving Gemini CLI for free/Pro/Ultra on 2026-06-18, so `/gsd-review --gemini` spawned a binary that no longer answers for most users. The `--gemini` flag, its three `review.*.gemini` config keys, and its documentation in all five locales are gone; Antigravity's `--agy` lane already covers the Google slot. `gsd config-set review.models.gemini` now reports an unknown key — an existing key in `.planning/config.json` still parses and is simply never read. (#4709) (#4716)
|
||||
- **Support for runtimes other than Claude Code, Codex, OpenCode, Cursor, ZCode and Antigravity has been dropped** — the installer, capabilities, hooks and docs for the other 12 runtimes (including Kimi) are gone, together with the descriptor-driven mechanisms that only they used. (#1)
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Gap-closure plans can no longer silently reuse threat IDs that earlier plans in the same phase already assigned** — a `--gaps` re-plan numbered its `<threat_model>` registers from `T-{phase}-01` again, so the new plans claimed IDs that earlier plans had already given to different threats, and nothing detected it: `/gsd-secure-phase` builds `SECURITY.md` rows and `VALIDATION.md` carries a Threat Ref column keyed on that ID, leaving every consumer ambiguous. `init execute-phase` and `init plan-phase` now report cross-plan duplicates (`threat_id_duplicates` / `threat_id_duplicate_count` — register rows only, never prose; the reserved `T-{phase}-SC` row is exempt since every plan keeps it; superseded plans don't hold IDs against their replacements), execute-phase hard-stops on a non-empty list before dispatching any executor, and the planner (agent template + `planner-gap-closure.md` §9) is instructed to continue numbering after the phase's highest in-use `T-{phase}-NN`. (#4683) (#4828)
|
||||
- `verify.artifacts` no longer aborts a plan's whole artifact check when one listed path is a directory. Reading a directory raised `EISDIR` out of the per-artifact loop, so the command printed `Error: EISDIR: illegal operation on a directory, read` and reported nothing at all — neither the offending entry nor the plan's other, perfectly checkable artifacts. A directory now fails as its own entry, with an issue distinct from `File not found`, and every other artifact is still checked and reported independently. A path that stat or read fails on for any other reason (a permissions error, an unreachable mount, or an artifact that disappears mid-check) fails the same way, carrying its errno, instead of discarding the run. (#4735)
|
||||
- **Commits are no longer blocked when a project configures a large `commit_types` list** — the commit validator built one regular expression out of every configured type, and on macOS (bash 3.2 / BSD libc) that pattern stopped compiling past roughly 6,000 types. The validator reported the compile failure as "this message is not a Conventional Commit" — rejecting a valid `feat(auth): …` while listing `feat` among the valid types it printed. At the same payload the hook could also abort outright with a broken-pipe error instead of returning a verdict. Linux (glibc) has no comparable limit and was never affected by this half. Both paths are fixed and now covered by regression tests. (#4429) (#4723)
|
||||
- **verification status and frontmatter get distinguish unparseable YAML from a missing report** — a VERIFICATION.md whose frontmatter has a YAML syntax error was reported as status "missing" (sending the operator to re-run execute-phase, which cannot fix a YAML typo), and frontmatter get answered "Field not found"; both now report a distinct parse error. (#4806) (#4896)
|
||||
- **TDD red evidence accepts Surefire/Failsafe XML** — the tdd-red-evidence gate parsed only node:test TAP, so a JVM project's genuine Maven red scored INVALID_RED while hand-written synthetic TAP scored RED_EVIDENCE_OK (the gate was passable only by fabricating its input). Surefire/Failsafe XML reports now classify by tag-boundary scanning: a testcase with a <failure> or <error> child for the target class is a real red; self-closing passing cases are never spanned into failing names. (#4724) (#4825)
|
||||
- **A phase's verification no longer goes `stale` because a repo-wide planning document was rewritten** — `covered_digest` hashed `.planning/ROADMAP.md` and `.planning/REQUIREMENTS.md` byte-for-byte, so completing any phase (or the phase's own `phase.complete` / `requirements mark-complete` bookkeeping) flipped every verification that had declared them to `stale`, failed `complete-milestone`'s `ALL_PHASES_VERIFIED` gate, and forced an `override_closeout` for phases whose implementation had not changed. Fingerprint v2 leaves the repo-wide planning documents — the direct children of the planning root, including a workstream's own — out of the digest by construction (they are still validated, only their bytes are ignored); an existing v1 digest keeps its old meaning until the report is re-fingerprinted, so upgrading stales nothing. Separately, `query verification.fingerprint` now accepts `--files a`, `--files a,b` and repeated `--files` alongside the bare positional form, reports an unknown flag as a usage error instead of "a covered file is missing", and rejects a missing phase directory instead of printing a digest over the wrong set at exit 0. (#4623) (#4749)
|
||||
- **verify-work stops flagging honest plans as commit_claim_mismatch** — the reconciliation measured `plan_head_before..HEAD`, a window that grows with every later plan's commits and the phase-completion commit, so any plan except the last read as a BLOCKER. The executor now records `plan_head_after` (HEAD at its measurement moment) and verify-work reconciles against that bounded window with exact equality; legacy SUMMARYs without the anchor fall back to a warning, and the #3968 failure modes still block. (#4670)
|
||||
|
||||
<!-- #4670 un-established edges, per the issue: parallel worktree waves sharing a base and multi-repo commit-to-subrepo ledgers are not covered by the bounded window; the window strictly narrows relative to the previous check. --> (#4813)
|
||||
- **roadmap update-plan-progress stops inserting a duplicate plan list beside hand-written ones** — plan checkbox rows written without the -PLAN.md suffix (the hand-written form) were not recognized, so the verb inserted its own canonical list above them, leaving two competing lists for the same plans; suffix-less rows are now recognized and ticked in place. (#4786) (#4880)
|
||||
- **Antigravity agents get native tool names as a YAML sequence** — converted agents carried Gemini CLI tool names (`read_file`, `search_file_content`, `run_shell_command`) as a comma-separated scalar, while Antigravity's documented subagent contract wants a YAML sequence of native names (`view_file`, `grep_search`, `run_command`, `replace_file_content`); wrong or malformed grants can hang the subagent. The installer's twin converter changes in lockstep. (#4705) (#4822)
|
||||
- **`/gsd:debug` no longer spawns duplicate debuggers that collide on the session file** — the debug session manager spawned its `gsd-debugger` without `run_in_background=false`, so Claude Code backgrounded it, the manager had no result to inspect, and it returned a non-terminal summary. The orchestrator's auto-resume then started a second debugger against the same `.planning/debug/<slug>.md`, up to the three-resume cap — which is why the collision showed up exactly three times per invocation. The spawn now blocks, matching the rule already applied one level up (#2196). (#4395) (#4718)
|
||||
- **Slash-command suggestions no longer show the retired `/gsd:` form** — a handful of shipped command descriptions, agent bodies and workflow instructions used `/gsd:` tokens the installer could not convert, so they reached you as the deprecated colon form after a fresh install. One consequence was functional, not cosmetic: `/gsd-help --brief <topic>` looked for a signature line that the installed reference never renders, so every topic silently fell back to its first paragraph. (#4324) (#4712)
|
||||
- **Claude installs no longer stage the 29 compact agent variants** — agents/*.compact.md shipped beside their canonical siblings with identical name frontmatter, leaving the harness's pick unstated; Claude never selects compact (it is a non-Claude-runtime payload), so the Claude agents directory now holds only the canonical agents, and upgrading removes the stale copies. (#4782) (#4878)
|
||||
- **`--auto` no longer stops on an artifact that already exists** — `/gsd-ui-phase <phase> --auto` blocked on "UI-SPEC.md already exists for Phase {N}" whenever the file was on disk, which is most often after an earlier run left an unverified draft, so a headless or board run stalled on a question nobody could answer. It now reuses the existing UI-SPEC untouched and proceeds to the checker. `/gsd-spec-phase --auto` had the opposite failure — it auto-selected "Update it" and regenerated a spec nobody was watching, discarding answers already recorded in it — and now also reuses it as-is. The same gap existed in three sibling commands with no prior `--auto` handling at all: `/gsd-ai-integration-phase --auto` now auto-selects Skip for an existing AI-SPEC, and `/gsd-eval-review --auto` / `/gsd-ui-review --auto` now auto-select View for an existing EVAL-REVIEW/UI-REVIEW instead of re-auditing. The max-revision-iterations escalation (Force approve / Edit manually / Abandon) still stops for a person under `--auto`, by design. (#4776) (#4832)
|
||||
- **Runtime detection no longer resolves a retired runtime to Claude Code** — workflows still mapped `/.gemini/` and `$GEMINI_CONFIG_DIR` to the `gemini` runtime that was removed in 1.8.0, and an unrecognized id silently falls back to Claude Code's config dir, label, and instruction file. Detection now maps Antigravity's real directories, the runtime menu no longer offers the retired Gemini CLI, and the model-tier table no longer advertises built-in defaults for a runtime the catalog does not define. (#4709) (#4711)
|
||||
- **Deferred UAT follow-ups stop blocking phase completion** — `/gsd-verify-work` deferrals (skipped with a "Deferred follow-up" reason) no longer fail the phase-completion predicate, and completing a session with deferrals now offers to promote them into a `999.x` ROADMAP backlog entry; plain unresolved skips still block as before. (#4546) (#4769)
|
||||
- **Codex installs rewrite @ includes to the codex root** — codex-installed agents and commands kept `@~/.claude/gsd-core/…` and `@$HOME/.claude/gsd-core/…` includes pointing into the Claude install (silently reading the wrong copy on dual-runtime machines, resolving to nothing on codex-only ones). The installer now rewrites the @-include form across manifest-tracked artifacts; the deliberate `$PREFERRED_CONFIG_DIR`/`_GSD_RUNTIME_ROOT` fallback chains and prose `.claude` mentions stay untouched. (#4667) (#4858)
|
||||
- **Windows CI chunks no longer exceed their own per-chunk timeout** — the Windows test runner packed up to 40 test files into a chunk that is killed at 600 seconds, but at the measured rate from the chunk that actually died (18,122 ms/file) 40 files need roughly 725 seconds. A chunk could therefore be killed with no test having failed, turning `next` red and blocking every open pull request. The Windows cap is now derived from measured cost rather than tuned by hand, and a test enforces the arithmetic so it cannot silently drift back. Alongside it, a test file absent from `tests/test-timings.json` is no longer priced at the table median — in a distribution skewed 18.8x that modelled an unknown file as roughly 19x cheaper than average, so files nobody had measured packed as though they were nearly free. The heaviest test files (e.g. `state.test.cjs`, `install-minimal-hooks.test.cjs`) now get their own dedicated chunk based on an absolute measured-time bar instead of a ratio of the per-platform file-count cap, so they can never again be crowded into a shared chunk that blows the timeout — and, unlike before, this now applies consistently on every platform and to heavy install-suite files, not only unit-suite ones. (#4733) (#4737)
|
||||
- **`/gsd-code-review`, `/gsd-code-review-fix`, `gsd-code-fixer`, `/gsd-execute-plan` and `/gsd-plan-phase` now accept letter-variant phase ids (`12A`, `3A`, `23A.1.2`)** — the six shell/markdown phase-number mirrors #4568 widened on the segment-count axis were still digit-only on the letter axis, so a documented, canonical-valid id like `12A` was refused with "Invalid phase number format" by the four validating sites and silently truncated to its digit prefix by the two extracting ones. All six now match the canonical grammar (`src/phase-id.cts`), a parity test proves both sides agree on the letter axis in both directions, and `lint-phase-id-drift` gains a ratchet so a digit-only mirror cannot re-diverge silently. (#4660) (#4744)
|
||||
- **phase complete no longer names an already-complete phase as next** — completing a reopened phase out of order (later phases already [x]) picked the numerically-next phase even when its checkbox was already ticked, persisting it to STATE.md as current_phase. next_phase now skips phases whose roadmap checkbox is already [x], agreeing with roadmap.analyze and init.progress. (#4699) (#4820)
|
||||
- **TDD mode no longer trips on every task in Go, Ruby, Elixir and Python projects** — the RED-commit gate looked only for `*.test.*`, `*.spec.*` and `tests/`, so a commit adding `foo_test.go` was invisible and every behaviour-adding task halted with `TDD GATE TRIPPED: missing RED commit`. It now recognises the conventions the TDD reference already advertises, and matches at the repo root as well as in subdirectories. Rust stays a documented gap: `#[test]` lives in the implementation file, so no path-based gate can see it. (#4379) (#4715)
|
||||
- **`/msd-update` and the update check work again** — they asked npm for a package that was never published, so they could never find an update. Releases are now `vX.Y.Z` git tags with a `stable` branch at the latest one: the update check reads those tags, `/msd-update --next` also considers `-rc.N` tags, and the update reruns the one-line installer pinned to the version it checked, showing that release's changelog first. (#1)
|
||||
- **check.decision-coverage-plan stops answering an unmeasured shape** — on could-not-parse it reported covered: 0 / uncovered: [] (fields of a measurement that never happened) and a directory passed as the context path certified passed: true; the gate now answers covered: null / total: null with the unreadable decision ids (and omits uncovered), and a non-file context path fails closed naming the path. (#4794) (#4895)
|
||||
- **Workflows no longer run a foreign or outdated `gsd_run` from PATH** — the runtime launcher now resolves a project-local or runtime-config-directory install ahead of PATH, and a PATH `gsd_run` is used only when it proves it is @opengsd/gsd-core, so a leftover global install can no longer shadow a local one and trip the pre-commit branch guard. (#4834) (#4902)
|
||||
- **The post-merge gate's Xcode detection works on real project layouts** — the gate resolved the .xcodeproj path but built its commands without -project (any project one directory down failed with exit 66) and hardcoded the iPhone 16 simulator name (a machine property); commands now carry -project, the destination resolves from the machine's available simulators, gates skip loudly when none exists, and the timeout message names the sysdiagnose collector. (#4784) (#4879)
|
||||
- verify-command-paths no longer reports a false missing_dir blocker when a plan's <automated> command spells the chain operator entity-escaped (cd src && npm test): the command text is now decoded to & before segment splitting, so the escaped and literal forms of the same command get identical verdicts (#4730) (#4755)
|
||||
- **Worktree cleanup-wave rescues SUMMARY artifacts from relative worktree paths** — a manifest entry carrying a relative `worktree_path` made the rescue walk the CLI's working directory instead of the repo root, finding nothing and blocking the entry `worktree_dirty` instead of rescuing; the rescue now resolves the path against the repo root, the same way every git consumer of the field already does. (#4758) (#4872)
|
||||
- **Markdown writes no longer insert a blank line between a paragraph and a following list** — every .md write re-normalized the whole document and split tight paragraph→list transitions, reflowing prose the command never touched (e.g. `roadmap.update-plan-progress` editing unrelated phase-section prose). Tight lists now stay byte-identical on disk. (#4725) (#4842)
|
||||
- **Whitespace-only planning scope values no longer create phantom directories** — `GSD_WORKSTREAM`, `GSD_PROJECT`, and their explicit equivalents now fall back to the root scope, while padded real names are normalized consistently. (#4509)
|
||||
- **verify-work no longer canonicalizes a vacuous pass** — a UAT session with zero logged issues but every row blocked (0 passed) flipped VERIFICATION.md to `passed`, leaving a phase whose central claim was never observed carrying a passed verification. The canonicalize flip now requires the same `phase uat-passed` predicate the phase-close uses (at least one pass, no blocked/pending/failed rows) and, when it refuses, says the verification stays human_needed with the blocker count. (#4663) (#4809)
|
||||
- **verify plan-structure stops warning that a logical-OR fallback swallows a failure** — the R4 scan read "||" as a pipe, so the standard "git cat-file -e <sha> || echo missing" ghost-control idiom was flagged as a swallowed failure when "||" is exactly the construct handling it; single pipes (including zsh "|&") still warn. (#4774) (#4877)
|
||||
- **Runtime-aware model overrides and `dynamic_routing` now affect the agents that actually spawn** — `model_profile_overrides.<runtime>.<tier>` only applied when you had written a `runtime` key into `.planning/config.json`, so it was silently inert for installs that identify their runtime through `GSD_RUNTIME` or the per-install marker. Separately, `dynamic_routing.tier_models` was consulted only on an explicit retry attempt, so the first spawn — the documented case — never used your configured tier. Both now resolve through the runtime that is actually running, and an explicit model pin like `claude-opus-4-8` is no longer collapsed to a Claude-only alias when a different runtime is active. Projects without `dynamic_routing` enabled are unaffected. Note that if your `.planning/config.json` already carries `dynamic_routing.tier_models` or a `model_profile_overrides` block for a runtime you resolve via `GSD_RUNTIME`, those settings were previously inert and now take effect — review them before upgrading. (#4505) (#4726)
|
||||
- **Harness-worktree waves no longer degrade to sequential on a stale origin/HEAD when the fork base is confirmed from a prior worktree** — the worktree base-check now observes the harness's actual fork behavior from a clean prior harness worktree at the orchestrator HEAD before degrading; every unobservable case still degrades exactly as before. (#4588) (#4868)
|
||||
- **init.manager stops reporting dates, shas and ledger ids as phase dependencies** — dep_phases scraped every digit run out of a phase's Depends-on prose, so phases whose prose declares no dependency read as blocked (dates split into year/month/day, git shas fragmenting, WINDOWS ledger ids, even the phase's own number); extraction now pulls only Phase-prefixed references — including "Phases 1, 2, and 3" lists and "Phase 1-3" ranges — and planning-inspect's dependencies field uses the same anchored grammar. (#4764) (#4876)
|
||||
- **The secret-read guard no longer blocks container --env-file** — `docker`/`docker compose`/`podman`/`nerdctl` --env-file passes a file to the runtime without its contents ever reaching the conversation, so the operational rebuild works again; direct reads of secrets still block. (#4639) (#4789)
|
||||
- **Codex agents with Write/Edit tool contracts now run under workspace-write** — the 17-role read-only hold is lifted: official OpenAI documentation establishes sandbox_mode as an enforced boundary, so each Codex agent's sandbox now derives purely from its own declared tools. (#4770) (#4920)
|
||||
- **The UI plan gate now recognizes native UI projects** — a SwiftUI, Jetpack Compose, Flutter, or .NET MAUI project never tripped the static frontend-evidence check, so the gate that requires a UI-SPEC before planning a UI phase silently never fired for them. A `.xaml` file, or a `.swift`/`.kt`/`.dart` file importing its ecosystem's UI framework, now counts as evidence; non-UI native packages (a Swift CLI, a plain Kotlin server) stay silent. (#4658) (#4807)
|
||||
- **The spec/ui zero-applicable guard now fires on the all-unclassified case** — probe coverage exposes an `unclassified` count beside `applicable`, and spec-phase/ui-phase warn when every requirement classifies to nothing instead of reporting a healthy non-zero total; `applicable` itself is count-preserving. (#4656) (#4800)
|
||||
- **`state record-session` reports the record it replaces** — overwriting a prior Stopped At or Resume File handoff now names the displaced text in the verb's payload instead of succeeding silently, and the executor decision loop passes --phase so decisions stop inheriting whichever phase the global pointer names. (#4763) (#4919)
|
||||
- **Roadmap queries read past hard-wrapped Goal/Requirements fields** — the roadmapper soft-wraps long fields at ~85 chars, but five single-line field regexes truncated every wrapped Goal/Requirements at the first line: plan-phase's phase_req_ids silently dropped continuation-line REQ IDs (escaping the Requirements Coverage Gate), get-phase/analyze cut the goal mid-sentence, and phase complete left later REQs Pending with empty warnings. A shared multiline extractor now reads wrapped fields to the next field label. (#4731) (#4826)
|
||||
- **phase-plan-index now exposes DAG-ready plans** — `ready_plans` (and per-plan `ready`/`unresolved_dependencies`) distinguish plans whose dependencies all have completion evidence from those merely unblocked by a halt; /gsd-execute-phase dispatches only ready plans and reports what it is waiting on instead of skipping incomplete predecessors. (#4628) (#4781)
|
||||
- **Windows conformance CI no longer times out on newly-added test files** — a chunk holding several files not yet in the timing table could blow the 600s per-chunk budget even though each looked individually affordable; unmeasured files are now capped at 2 per chunk on Windows so a batch of new conformance-tier tests can no longer compound into a red `next`. (#4949) (#4950)
|
||||
- **phase complete no longer rewrites prose outside the Current Position section** — the Current Plan reset's fallback matched any hard-wrapped line starting with "plan:" anywhere in STATE.md (case-insensitive, first match wins), silently replacing narrative text with "Not started"; the reset is now scoped to the Current Position section, while legacy sectionless layouts keep their recorded whole-body behavior. (#4823) (#4898)
|
||||
- **Codex orchestrator-worktree workers now persist a durable lifecycle record** — external executors dispatched by /gsd-execute-phase record their launch and terminal state (worktree worker-record/worker-status/worker-complete), so a resumed session reconciles finished or blocked workers from persisted state instead of manual PID discovery, and never re-dispatches a recorded plan. (#4624) (#4778)
|
||||
- **Local installs can keep `@` includes inside each worktree** — `--relative-includes` (or `GSD_RELATIVE_INCLUDES=1`) writes project-relative includes instead of binding every worktree to whichever checkout ran the installer. (#4377) (#4425)
|
||||
- **`/gsd-code-review --fix` now works on an existing REVIEW.md even when no source files changed** — incremental scoping (#3661) narrowed the review file set to empty for phases whose only post-review changes were planning artifacts, and the empty-scope check exited the whole workflow before the fix step, so standing findings could never be addressed. With `--fix` and an existing REVIEW.md, the empty scope now routes straight to the fix workflow instead of skipping. (#4665) (#4810)
|
||||
- **run-with-timeout works from project paths containing spaces on Windows** — the .cmd/.bat mediation quoted the shim path and cmd.exe /s stripped the wrong quotes, so every mediated call under a spaced project path failed with exit 1 and empty stdout (the /gsd-code-review fallow pre-pass included); the mediation now uses the same projectSpawnInvocation seam as every other Windows spawn site. (#4797) (#4892)
|
||||
- **Repeated reviews no longer overwrite each other's preserved evidence** — a second review of the same phase silently replaced the first run's lane reports and error stubs in `.review-diagnostics/`, because the copy used each file's lane-named basename and a lane slug is stable across runs. Each run's evidence now lands in its own subdirectory, named after that run, so repeat reviews accumulate diagnostics instead of clobbering them. (#4351) (#4713)
|
||||
- **init.manager resolves archived phase directories** — a phase archived to .planning/milestones/vX.Y-phases/ with a passing verification reported no_directory / phase_complete: false (indistinguishable from never started), so /gsd-autonomous's default discovery skipped or mis-sequenced it; the manager's phase lookup now threads the convention through findPhaseInternal, which resolves live directories first and archived milestones second. (#4801) (#4893)
|
||||
- **A genuinely installed non-Claude runtime now resolves its own models instead of an empty string** — the per-install runtime identity is materialized into the config, so a marker-detected Codex install resolves its tier map past a shared `resolve_model_ids:"omit"` that was written for Claude protection; Claude resolutions and garbage runtime values behave exactly as before. (#4717) (#4861)
|
||||
- **`/gsd-code-review` can parse phase SUMMARY files without shell syntax errors** — the embedded JavaScript now runs from a literal heredoc and receives the SUMMARY path through `argv`, so quotes and backticks cannot break the workflow command. (#4461) (#4533)
|
||||
- **mempalace capture queues instead of dropping writes** — the headless `mempalace mine` ran in the foreground, so a concurrent writer holding the palace lock made it exit 1 and the onError: skip step silently dropped the capture. The mine now queues via `--daemon --background` (MemPalace runs it when the lock frees), and the capture report surfaces the queued or skipped outcome instead of staying silent. (#4700) (#4821)
|
||||
- worktree cleanup-wave no longer blocks an entry whose worktree directory the harness already removed: the branch merges and teardown prunes the stale admin entry instead of failing. Identity still comes from git's own worktree registration, so a path registered to a different branch blocks exactly as before, and removal must be confirmed by an ENOENT — a worktree that merely cannot be read blocks rather than being treated as removed. Every entry in a wave is evaluated against the registration as it stood before any teardown pruned it, so one removed worktree no longer strands the rest. (#4612)
|
||||
- **The four translated READMEs no longer advertise a retired runtime** — Japanese, Korean, Brazilian Portuguese and Simplified Chinese each still listed `Gemini CLI` among the supported runtimes and in the installer's runtime prompt, a year after #1928 removed it; all three sites per locale now match English. `VERSIONING.md` also listed a manifest that #1928 deleted, and omitted the VS Code manifest that replaced it. A new `lint-retired-runtime-name` check now fails CI if a retired runtime is named as live in shipped Markdown. (#4729) (#4753)
|
||||
- **run-with-timeout now kills the whole process tree on Windows** — a timed-out command's descendants (e.g. a model CLI wrapped via workflow.cross_ai_command) no longer survive the timeout and keep running unbounded; POSIX behavior is unchanged. (#4601) (#4775)
|
||||
- **ROADMAP.md's `**Plans:**` line no longer drops hand-written trailing notes when a phase completes.** Both writers of the Plans field — `phase complete` and `roadmap update-plan-progress` — now go through the parse -> mutate -> serialize seam ADR-4910 locks instead of their own regexes, so a phase-complete count bump can no longer replace-to-end-of-line and silently drop a trailing human annotation, and both writers now treat a fresh-template placeholder, a real count, and freeform/bracketed prose identically. (#4852) (#4933)
|
||||
- **`/gsd-execute-phase` waves no longer degrade to sequential on an unmerged branch when `worktree.baseRef:"head"` is set on a Claude Code host** — the pre-dispatch base check assumed the harness ignored the setting, a finding from an older Claude Code that upstream fixed in 2.1.128, and so reported `baseref-head-ignored-by-harness` for every wave whose HEAD differed from `origin/HEAD`. #4868 added an observation of a clean prior harness worktree at HEAD that lifts the degrade, but an `execute-phase` run never has one at the moment it checks, so the common case was unchanged. The check now trusts `"head"` in both isolation modes, the way the harness actually behaves (measured from all three settings layers on macOS, Windows and Linux), and gains a `--observed-fork-base <sha>` input so a measured fork base can replace the `origin/HEAD` inference — a mismatch under `"head"` still degrades and warns. A Claude Code `WorktreeCreate` hook in any of the settings files the check reads, or a settings file that does not parse, withholds that trust, because the hook creates the worktree without applying `worktree.baseRef`: the check then compares against `origin/HEAD` and degrades with `baseref-head-bypassed-by-hook`. The #4868 prior-worktree observation is withheld there rather than consulted: a worktree sitting at HEAD carries no record of which creator left it there, so one the plain harness created before the hook was configured is indistinguishable from one the hook created — on a hook host only `--observed-fork-base` restores a trusted verdict. Without the setting the harness does fork from `origin/HEAD`, and that degrade is unchanged. The spawn-time exit-42 guard remains the backstop on a host that does not honor the setting. (#4881) (#4921)
|
||||
- **OpenCode installs no longer flag all 72 GSD skills as custom files** — the installer's file manifest now records the skills it stages for OpenCode, matching every other skills-layout runtime, so clean installs report zero custom files. The first update after upgrading may show the custom-files backup prompt once while the manifest catches up; from then on updates run without it. (#4738) (#4847)
|
||||
- **Asking for a retired runtime no longer silently installs Claude Code** — passing a sunset runtime id resolved to Claude Code's label and config home, so `getGlobalConfigDir('gemini')` and `getGlobalConfigDir('claude')` returned byte-identical paths and the install reported itself as Claude Code. The four runtime-resolution accessors now fail with a message naming the successor and the retiring issue. Genuinely unknown and future runtime ids keep their existing safe defaults, which is a deliberate distinction: absence of knowledge is not the same as recorded retirement. (#4709) (#4756)
|
||||
- **The UI consideration probe reads an optional `text_en` field** — in a `response_language` project every UI element used to classify to zero categories and land in `unclassified`, dropping the whole state-coverage axis; a faithful English translation per element now classifies exactly like its English equivalent. Mirrors the edge probe's #3717 remedy; an empty or whitespace `text_en` fails closed. (#4657) (#4804)
|
||||
- **`verify references` no longer mishandles `:LINE` citations** — backtick citations with a line suffix (e.g. `src/foo.ts:42`) are now checked instead of silently dropped, and @-citations with a line suffix resolve against the underlying file instead of being reported missing (#4678). (#4719)
|
||||
- **Installer stops warning that hooks may not load when they already load as CommonJS** — installing over an existing hooks/package.json that declares "type": "commonjs" (any hand-written or formatter-touched file) printed "GSD hooks may not resolve as CommonJS"; the warning now states will-not-load only for the case that is true, a declared "type": "module", matching the plugin-path wording. (#4759) (#4875)
|
||||
- **Decision bullets with code spans in their titles now parse** — a backticked token like `node:http` or `*-UAT.md` inside a decision's bold lead-in was treated as a malformed separator and the whole decisions block failed to parse, hard-blocking the decision-coverage gate; backticked spans are now opaque to the grammar, while a bare colon outside a code span still fails loud. (#4788) (#4883)
|
||||
- **Windows conformance-tier CI no longer blows its own chunk timeout on unmeasured test files.** `scripts/run-tests.cjs` now weighs a test file absent from `tests/test-timings.json` at the documented ~2.2x Windows-cost floor instead of the plain (Linux-measured) table mean, on win32 only — a cluster of unmeasured conformance-tier files could otherwise pack into one chunk and exceed the 600s per-chunk backstop even though the chunk looked in-budget. (#4434) (#4903)
|
||||
- **`worktree cleanup-wave` no longer kills an executor merge at the 10-second git plumbing timeout while a `pre-merge-commit` hook runs** — the merge step now carries its own 10-minute budget (`deps.mergeTimeoutMs`), a merge that does exceed it blocks on a distinct `merge_timed_out` reason naming the budget instead of a `merge_failed` carrying the hook's partial output, and the staged-but-no-`MERGE_HEAD` index a killed merge leaves in the primary checkout is detected and restored with `git reset --merge` (reported per path as `merge_residue_restored`; `merge_residue_left_staged` halts the wave when it cannot be), so committing from the primary after a killed merge no longer squashes the executor's history. (#4721) (#4766)
|
||||
- **Seeds minted by parallel workstreams no longer share an id by construction** — `/gsd:capture --seed` derives `SEED-YYMMDD-xxx` from the local date plus a random suffix instead of counting files in `.planning/seeds/`, which each worktree could only do from what had merged, so two workstreams planting before either merged both picked the same id; the residual same-day collision bound (~1 in 46,656 per pair) is the one the `.planning/quick/` scheme already accepts. Existing `SEED-NNN` seeds keep resolving in list, enrich, the new-milestone scan, and audit — whose scan now publishes the same canonical id as `list-seeds` and whose acknowledge resolves either id to the same file. (#4378) (#4754)
|
||||
- **`/gsd:undo --phase` and `--plan` no longer select commits from an unreachable branch, and refuse rather than anchor on a directory an earlier milestone used** — commit selection now anchors on the target phase's own directory (the `#3995` `PHASE_START` pattern already used by `code-review.md`) and runs over `PHASE_START^..HEAD` instead of a repository-wide `git log --all` commit-subject grep. The dead `.planning/.phase-manifest.json` primary path, which nothing in the repository writes, is removed rather than left as documented-but-unreachable behaviour, and both modes now fail closed when no anchor resolves instead of widening to an unbounded search. Two refusals cover the previous-milestone routes the anchor cannot distinguish on its own: a phase number that resolves to an archived `milestones/v<X.Y>-phases/` directory, and a **live** directory whose name also exists as a directory under an archived milestone (a later milestone reusing both the number and the slug re-creates the same literal path, so the oldest add there is the earlier occupant's). The first: `find-phase`'s ambiguity check does not span search directories, so a number that is no longer live resolves silently to the oldest archived milestone that has one — and anchoring there both misses that phase's real work and drags a *later* milestone's same-numbered phase into the window. `dependency_check` reads the workstream-resolved planning root, so an active workstream's roadmap and phase directories are consulted rather than the root's. (#4465) (#4472)
|
||||
- **Stale verification now routes to the verifier** — the `stale` status told users to re-run `/gsd-verify-work`, but that workflow never rewrites VERIFICATION.md, so following the advice looped forever. The routing now names the regeneration path (execute-phase resumes at the verification gates and re-runs the verifier), and verify-work's stale stop dispatches `gsd-verifier` and re-checks instead of self-referencing. (#4682) (#4818)
|
||||
- **Seeds captured by /gsd-explore are now real seeds** — explore delegates to the plant-seed workflow (SEED- id, status, trigger_when) instead of writing a `.planning/seeds/{slug}.md` shape that list-seeds, audit-open and /gsd-new-milestone could never see. (#4648) (#4798)
|
||||
- **Agent dispatch no longer blocks on a project root that is not a git repository** — `worktree.base-check` now degrades to sequential when git definitively reports no repository, and the isolation guard's stale-sentinel fallback no longer demands `isolation="worktree"` where no worktree can be created (multi-repo workspace roots). Repos with a real HEAD behave exactly as before. (#4734) (#4843)
|
||||
- **A superseded plan no longer reads as executed in the ROADMAP** — the roadmap update-plan-progress checkbox tick now skips plans the count already excludes as superseded, so the "N/M plans executed" line and the checkboxes below it always agree. (#4741)
|
||||
(#4851)
|
||||
- **The docs and workflow prose no longer offer Gemini CLI as a runtime** — translated guides still walked readers through installing GSD for a runtime Google shut off in 2026-06, including an install command that now just prints a sunset notice and exits, and the workflow text the agent reads at runtime still named it as a non-Claude option. Antigravity is the documented successor and is what those surfaces name now. (#4728) (#4743)
|
||||
- **Codex rollback no longer leaves a partially-installed payload behind** — the installer's rollback snapshot now covers every file the previous install's manifest recorded (CHANGELOG.md, scripts/, .gsd-runtime, the manifest itself) plus the whole `hooks/` directory, instead of only config.toml, hooks.json, skills/, agents/ and VERSION, so a failed install reverts to the true pre-install state. (#4544) (#4760)
|
||||
- **`/gsd-execute-phase`, `/gsd-autonomous --from|--to|--only`, `/gsd-plan-review-convergence` and the TDD plan path now handle letter-variant phase ids (`12A`, `3A`, `23A.1.2`)** — seven shell sites outside #4660's six still assumed a phase number was digits-and-dots: the post-#4619 `$((10#$PHASE_INT))` split aborted bash on `03A`, the review-file lookup's `printf "%02d"` printed the wrong file (and read an already-padded `08` as octal), and the `--from`/`--to`/`--only` and plan-review-convergence extractions silently truncated `12A` to `12` (and `23.1.2` to `23.1`). The split now stops at the first non-digit, `init execute-phase` emits `padded_phase` for the lookup, the extractions use the canonical grammar, the legacy normalizer pads a letter id, a parity test drives every site's live shell against a letter-suffixed fixture, and `lint-phase-id-drift` gains three ratchets so none of the shapes can return silently. (#4748) (#4873)
|
||||
|
||||
### Security
|
||||
|
||||
- **An exported `CONFIG_STATUS`, `CMD_STATUS`, or `CLASSIFY_STATUS` no longer disables the commit-message gate** — the hook captured each subprocess status with `|| VAR=\$?`, which assigns only when the subprocess fails, so on success the variable kept any value inherited from the environment. A CI wrapper, a `.envrc`, or another hook that exported one of those names made the validator report "validator disabled for this call" and accept a non-conforming commit. The statuses are now initialised before use; a genuine subprocess failure still passes the commit through, as before. (#4429) (#4723)
|
||||
|
||||
## [1.14.0] - 2026-09-14
|
||||
|
||||
### Added
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "ai-integration",
|
||||
"role": "feature",
|
||||
"version": "1.14.0",
|
||||
"version": "2.0.0",
|
||||
"title": "AI design contract",
|
||||
"description": "AI-SPEC design contract workflow for phases that build AI systems; owns the AI integration command, agents, and workflow.ai_integration_phase activation key.",
|
||||
"tier": "full",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "antigravity",
|
||||
"role": "runtime",
|
||||
"version": "1.14.0",
|
||||
"version": "2.0.0",
|
||||
"title": "Antigravity",
|
||||
"description": "Google Antigravity IDE — config/settings home nested under ~/.gemini/antigravity (probed across 1.x and 2.x layouts); global skills/agents install under ~/.gemini/config, the dir AGY scans for global discovery (#3738); Gemini hook event dialect; flat skill layout; tier-1 support.",
|
||||
"tier": "core",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "assumption-delta",
|
||||
"role": "feature",
|
||||
"version": "1.14.0",
|
||||
"version": "2.0.0",
|
||||
"title": "Assumption-delta architecture checkpoint",
|
||||
"description": "Rarely-firing advisory checkpoint that triggers when a phase makes something plural, optional, or chosen that used to be singular, required, or derived. Surfaces one identity-model question (promote the new general representation to primary, or add it alongside?) so a silent primary-key drift does not accumulate into a later user-facing bug. Non-blocking; fires only on a detected signal.",
|
||||
"tier": "full",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "audit",
|
||||
"role": "feature",
|
||||
"version": "1.14.0",
|
||||
"version": "2.0.0",
|
||||
"title": "Audit",
|
||||
"description": "Open-artifact audit and UAT-gap audit for milestone close gates; exposes `msd-tools audit-uat` (cross-phase UAT outstanding items) and `msd-tools audit-open` (structured open-artifact scan across debug, tasks, threads, todos, seeds, UAT, verification, context-questions).",
|
||||
"tier": "full",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "broken-windows",
|
||||
"role": "feature",
|
||||
"version": "1.14.0",
|
||||
"version": "2.0.0",
|
||||
"title": "Broken-windows ledger",
|
||||
"description": "Cross-phase defect register accumulating stubs, TODOs, skipped tests, unrun verifies, and unmet truths into .planning/WINDOWS.md. When enforcement is enabled, it blocks /msd-ship while any window is open unless explicitly waived with a recorded reason. Operationalizes MSD's no-defer discipline as a tracked artifact (issue #1950).",
|
||||
"tier": "full",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "claude-orchestration",
|
||||
"role": "feature",
|
||||
"version": "1.14.0",
|
||||
"version": "2.0.0",
|
||||
"title": "Claude orchestration (Workflow backend)",
|
||||
"description": "Default-off, BETA, claude-only capability that adopts Claude Code's Workflow tool (the engine behind /effort ultracode) as an optional parallel-execution backend for the MSD loop. When the runtime exposes the Workflow tool and claude_orchestration.execution_backend resolves to 'workflow', execute-phase emits a generated Workflow script (waves -> parallel() barriers, plans -> agent({ agentType: 'msd-executor', isolation: 'worktree' }), files_modified overlap -> separate sequential stages, resumeFromRunId wired to the phase run id, shared token budget) that composes the SAME msd-executor agent and worktree isolation the inline path uses, restoring the wave parallelism the #853 backgrounded-agent nesting limitation forces inline on Claude Code. (The plan-checker and verifier remain inline until separately wired — this capability delivers the parallel-execution backend, not those gates.) Also folds the ultraplan plan-offload under one runtime gate (plan:* surface). On any runtime lacking the Workflow tool, or when the capability is disabled, behaviour is byte-identical to today (inline/manual dispatch). Detection + emission live in msd-core/bin/lib/claude-orchestration.cjs (pure, fail-closed). Mirrors the existing msd-ultraplan-phase BETA-isolation posture.",
|
||||
"tier": "full",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "claude",
|
||||
"role": "runtime",
|
||||
"version": "1.14.0",
|
||||
"version": "2.0.0",
|
||||
"title": "Claude Code",
|
||||
"description": "Anthropic Claude Code — primary development runtime; tier-1 support with full hook surface and skills-based global install.",
|
||||
"tier": "core",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "code-review",
|
||||
"role": "feature",
|
||||
"version": "1.14.0",
|
||||
"version": "2.0.0",
|
||||
"title": "Code review",
|
||||
"description": "Source-file code review and review-fix workflow support for completed execution work.",
|
||||
"tier": "full",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user