Merge origin/main into feat/3597-split-suites-node-matrix
Resolves conflict in .github/workflows/test.yml: keep the 6 new drift-check steps from main (plan-scan, secrets, schema-detect, decisions, workstream-name-policy, Shared Module hand-sync) before the split-lane test runs from this PR. PR's dedicated `coverage` job replaces main's per-matrix `Run tests with coverage` step. Other conflicting files (CONTRIBUTING.md, get-shit-done/bin/lib/init.cjs, package.json) auto-merged cleanly. Changeset files (.changeset/*) brought in from main as adds.
This commit is contained in:
21
.changeset/3577-adr-violations-and-validation-port.md
Normal file
21
.changeset/3577-adr-violations-and-validation-port.md
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 3577
|
||||
---
|
||||
**Phase 6 ADR/PRD compliance: out-of-seam Modules removed from SDK catalog; CJS-only verbs dispatch direct** — `verify.codebase-drift` and the eight `intel.*` verbs were wrongly bound in the SDK catalog/manifests, in violation of `docs/adr/3524-cjs-sdk-hard-seam.md` §3 and `docs/prd/3524-cjs-sdk-hard-seam.md` L160 which list `drift`, `intel`, `graphify`, `gsd2-import`, `schema-detect`, `fallow-runner`, `installer-migrations` as CJS-only ("...keep their in-process CJS implementations because no SDK counterpart exists"). The `verifyCodebaseDrift` SDK stub then `execFileSync`'d back to `gsd-tools verify codebase-drift`, which the router routed back through the SDK bridge — an infinite recursion that forked hundreds of node processes on the remote 64 GiB docker host before manual kill. All wrongly-bound entries removed; the CJS router and `gsd-tools.cjs` already had direct CJS dispatch paths for these verbs that are now the only path.
|
||||
|
||||
**Phase 6 `config-ensure-section` cutover via catalog rebind, not CJS fallback** — restored the legacy "no-arg full default config.json init" contract on the SDK path by binding the catalog entry `'config-ensure-section'` to `configNewProject` (whose no-args branch produces the same shape as the legacy `ensureConfigFile → buildNewProjectConfig` chain). The original Phase 6 binding to the new `configEnsureSection` handler (single-section ensure, requires `args[0]=sectionName`) broke every CLI caller, which all invoke the no-arg form.
|
||||
|
||||
**`configNewProject` defaults sourced from canonical Configuration Module manifest** — replaced the hardcoded duplicate `defaults` object with a derivation from `sdk/shared/config-defaults.manifest.json` (exported as `CONFIG_DEFAULTS` from `sdk/src/configuration/index.ts`). The previous duplicate had drifted from the manifest — omitted `workflow.{ai_integration_phase, tdd_mode, human_verify_mode, pattern_mapper, plan_bounce*, auto_prune_state, subagent_timeout, security_*, post_planning_gaps}`, `git.create_tag`, `claude_md_path`, `planning.*`, `graphify.*`, `mode`, `resolve_model_ids`, `context_window`. Closes the same `DEFECT.PORT-DRIFT.cjs-sdk` family the ADR was written to prevent.
|
||||
|
||||
**SDK `configSet` value-validation port from CJS `cmdConfigSet`** — added the missing enum/shape validators that the CJS handler enforced: `workflow.drift_action` (warn|auto-remap), `workflow.drift_threshold` (positive integer), `workflow.human_verify_mode` (mid-flight|end-of-phase), `statusline.context_position` (front|end), `code_quality.fallow.scope` (phase|repo), `code_quality.fallow.profile` (minimal|standard|strict), and `review.default_reviewers` (array of slug strings matching `^[a-zA-Z0-9_-]+$`, normalized to lowercase-unique, with the normalized value persisted to disk).
|
||||
|
||||
**Init handlers honor `--tdd` flag and `workflow.subagent_timeout`** — `initExecutePhase` and `initPlanPhase` now parse the `--tdd` boolean override (matching `parseNamedArgs(args, [], ['validate', 'tdd'])` in the CJS router and `options.tdd || config.tdd_mode || false` in the CJS handler), and `initMapCodebase` reads `subagent_timeout` from the canonical `workflow.subagent_timeout` location with the manifest-mandated 300000 default instead of an undefined fallback.
|
||||
|
||||
**`roadmap.analyze` surfaces `mode` per phase** — extracts the same `**Mode:**` field that `roadmapGetPhase` already parses, so consumers can read MVP-mode flagging from either query handler without divergence.
|
||||
|
||||
**SDK `phaseComplete` performs auto-prune of STATE.md when configured** — ported the `workflow.auto_prune_state === true` branch from CJS `cmdPhaseComplete`, calling `statePrune(['--keep-recent', '3', '--silent'], ...)` so completing phase N actually removes stale `[Phase 1..N-3]` decisions instead of leaving them forever. (#2087)
|
||||
|
||||
**SDK `initRemoveWorkspace` errors via thrown `GSDError`** — returning `{ data: { error } }` was treated as success by the CLI output path; the no-name and workspace-not-found branches now throw `GSDError(..., ErrorClassification.Validation)` so the CLI returns non-zero and writes the message to stderr.
|
||||
|
||||
**SDK `frontmatterGet` parses `--field <name>`** — the CLI invocation `frontmatter get <file> --field phase` was passing `args = [file, '--field', 'phase']`; the handler treated `args[1]` as the field name and saw the literal string `--field`. Now handles both `--field <name>` and positional `args[1]`.
|
||||
5
.changeset/3577-config-ensure-section-parity.md
Normal file
5
.changeset/3577-config-ensure-section-parity.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 3577
|
||||
---
|
||||
**Phase 6 `config-*` SDK port parity carve-outs** — restored the legacy contract for four CLI tests broken by the Phase 6 router migration. `config-ensure-section` no longer routes through the new SDK `configEnsureSection` handler (which expected a positional `<section>` arg the CLI never passes) and instead keeps the `cmdConfigEnsureSection → ensureConfigFile → buildNewProjectConfig` CJS path that produces the full default `.planning/config.json`. The SDK `configNewProject` defaults now match `sdk/shared/config-defaults.manifest.json` (`commit_docs: true`, `parallelization: true`) and report the project-rooted relative path `.planning/config.json` to mirror the CJS shape. SDK error vocabulary is aligned with CJS: `Unknown config key: <key>` (no quotes), and config-get's malformed-JSON error is led by `Failed to read config.json:` so legacy regression tests keep matching. Closes the `Usage: config-ensure-section <section>` regression seen in `tests/{config,agent-skills,ai-evals}.test.cjs`.
|
||||
11
.changeset/3577-docker-test-fixup.md
Normal file
11
.changeset/3577-docker-test-fixup.md
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 3577
|
||||
---
|
||||
**Docker test fix-forward: 12 ubuntu-only regressions surfaced by `gsd-test-summary` cleared** —
|
||||
- `agents/gsd-intel-updater.md` retargeted from `gsd-sdk query intel.*` to `gsd-tools intel <subcommand>` (intel is out-of-seam per ADR §3 / PRD L160; the SDK has no handler for it, so the agent's CLI calls were broken).
|
||||
- `roadmap.get-phase` two-pass lookup for project-code-prefixed IDs (port of CJS `phaseMarkdownRegexSourceExact`, #3599): a `PROJ-42` query now matches `### Phase PROJ-42:` directly without cross-matching a bare `### Phase 42:` that happens to share the trailing integer.
|
||||
- `roadmap.analyze` extracts the `**Mode:**` field per phase (parity with `roadmap.get-phase`).
|
||||
- `phase.remove` depth-aware end-of-section regex (port of CJS #3601 fix): removing `### Phase 2:` stops at `### Phase 2.1:` (peer-depth decimal preserved) but continues past `#### Phase 27.1:` (child-depth decimal of `### Phase 27:`). Named capture `(?<h>#{2,4})` + backreference `\k<h>(?!#)` enforces same-depth termination.
|
||||
- `phase.remove` slugged-plan reference renumbering (port of CJS #3602 fix): the padded-plan-reference pattern now allows arbitrary kebab-case slug segments between `NN-NN` and the `-PLAN.md` / `-SUMMARY.md` suffix, so references like `07-01-cherry-pick-foundation-PLAN.md` get renumbered to `06-01-…` when Phase 7 is removed.
|
||||
- `configNewProject` filters out manifest keys that legacy CJS init does not materialize (`git.base_branch`, `resolve_model_ids`, `context_window`, `mode`, `planning`, `graphify`): these have their own resolution paths (auto-detect, opt-in) and materializing manifest values would suppress them. `config-get git.base_branch` correctly returns "Key not found" so workflows can fall back to `origin/HEAD` resolution.
|
||||
5
.changeset/3643-resolve-model-claude-runtime.md
Normal file
5
.changeset/3643-resolve-model-claude-runtime.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 3648
|
||||
---
|
||||
**`gsd-sdk query resolve-model` now honors `resolve_model_ids: true` under `runtime: "claude"`** — previously the resolver bailed out of `resolveRuntimeTier` for Claude (because Claude is the implicit/default runtime in `config-query.ts:149`) and fell through to the alias-return path on line 243 without consulting the catalog. Consumers asking for resolved model IDs received the tier alias (`opus` / `sonnet` / `haiku`) instead of the full Claude model ID (`claude-opus-4-7` / `claude-sonnet-4-6` / `claude-haiku-4-5`). The CJS branch at `get-shit-done/bin/lib/core.cjs:1348-1350` (`if (config.resolve_model_ids) return MODEL_ALIAS_MAP[alias] || alias;`) was missing from the TS port. Added a `runtime === 'claude' && resolveModelIds === true` branch that calls `resolveRuntimeTierDefault('claude', tier)` from the shared model-catalog so both runtimes derive Claude IDs from the same source of truth. `model_overrides`, the phase-type tier override (`config.models[phaseType]`), and `resolve_model_ids: "omit"` all retain their existing precedence. (#3643)
|
||||
5
.changeset/clever-zebras-snooze.md
Normal file
5
.changeset/clever-zebras-snooze.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 3581
|
||||
---
|
||||
**`/gsd:plan-phase` now refuses to replan closed phases** — `init.plan-phase` exposes a new `phase_status` field and the workflow short-circuits on `Complete` phases (use `--force` to override; `--reviews` has no override).
|
||||
5
.changeset/fix-3406-detect-stale-sdk-shadow.md
Normal file
5
.changeset/fix-3406-detect-stale-sdk-shadow.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 3641
|
||||
---
|
||||
**Install-time warning when a stale `@gsd-build/sdk` shadows the bundled `gsd-sdk` shim** — global installs now run `npm ls -g @gsd-build/sdk` and, if the standalone 0.1.0 package is present (it never received `query` subcommand support), print a clear remediation block before the install completes. Detection is fail-closed: any npm/exec error silently returns no-stale. Gated by `GSD_SKIP_STALE_SDK_CHECK=1` for CI/test environments. Resolves #3406.
|
||||
5
.changeset/fix-3579-graphify-hook-publish.md
Normal file
5
.changeset/fix-3579-graphify-hook-publish.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 3579
|
||||
---
|
||||
**Graphify auto-update hook now ships to install targets** — `gsd-graphify-update.sh` was missing from `scripts/build-hooks.js` `HOOKS_TO_COPY`, so it never landed in `hooks/dist/` and the installer's flat-readdir loop never copied it to `~/.claude/hooks/`. The hook's detached rebuild helper at `hooks/lib/gsd-graphify-rebuild.sh` was also dropped because both `build-hooks.js` and `bin/install.js` only walked top-level files. Both gaps are fixed: the allowlist now includes the hook, `build-hooks.js` copies whitelisted hook subdirectories into `hooks/dist/`, and `bin/install.js` mirrors hook subdirs to the target. Added a coverage drift guard so every top-level `hooks/*.sh` must be listed in `HOOKS_TO_COPY` going forward (#3579).
|
||||
5
.changeset/fix-3588-npm-audit-clean.md
Normal file
5
.changeset/fix-3588-npm-audit-clean.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Security
|
||||
pr: 3588
|
||||
---
|
||||
**`npm audit --omit=dev` is clean** — bumped lockfile-pinned transitive versions of `fast-uri`, `@anthropic-ai/sdk`, `hono`, `ip-address`, and `express-rate-limit` (pulled in through `@anthropic-ai/claude-agent-sdk` and `@modelcontextprotocol/sdk`) to patched releases. Same pass applied to `sdk/package-lock.json` (was clean for production already; the test now locks it in). Resolves #3588.
|
||||
5
.changeset/fix-3631-sdk-raw-flag-routers.md
Normal file
5
.changeset/fix-3631-sdk-raw-flag-routers.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 3631
|
||||
---
|
||||
**SDK dispatch path in family routers now honours `--raw`** — `phase next-decimal --raw`, `roadmap get-phase --raw`, and other family-router commands that route through the SDK bridge now emit the same scalar string the CJS path emitted before #3577. Routers request `mode: 'raw'` from the bridge under `--raw`; the sync-bridge worker wires `formatNativeRaw` to `formatQueryRawOutput` so the bridge returns the per-command projection. Routers then pass the formatted string through `output()`'s rawValue branch instead of JSON-stringifying it.
|
||||
5
.changeset/fix-3632-lint-handsync-pair-fanout.md
Normal file
5
.changeset/fix-3632-lint-handsync-pair-fanout.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 3632
|
||||
---
|
||||
**`lint-shared-module-handsync` now reports unauthorized ts siblings even when a co-named sibling is allowlisted** — when a `bin/lib/<name>.cjs` had two ts candidates on disk (e.g. `sdk/src/<name>.ts` and `sdk/src/query/<name>.ts`) and only one pair was in the allowlist, the `.some()` short-circuit silently skipped the unallowlisted sibling. Each ts candidate is now classified independently so partial-allowlist drift surfaces correctly.
|
||||
5
.changeset/graceful-tigers-fly.md
Normal file
5
.changeset/graceful-tigers-fly.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 3583
|
||||
---
|
||||
Claude skill install (convertClaudeCommandToClaudeSkill + copyCommandsAsClaudeSkills) now normalizes retired /gsd:<cmd> references in SKILL.md bodies to the canonical gsd-<cmd> hyphen form using the new transformContentToHyphen from the shared fix-slash-commands.cjs transformer. Frontmatter name: was already correct since #2808; body leakage is now eliminated for Claude, Qwen, and Hermes. Added regression guard in bug-2808 test. Fixes #3583.
|
||||
8
.changeset/steady-zebras-click.md
Normal file
8
.changeset/steady-zebras-click.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
type: Added
|
||||
pr: 3213
|
||||
---
|
||||
**Added: `lint:docs` enforcement.** New `scripts/lint-docs-required.cjs` + `Docs Required` CI workflow fail any PR whose changeset fragment is typed `Added` / `Changed` / `Deprecated` / `Removed` without modifying at least one file under `docs/`. Escape hatches: the `no-docs` PR label, or a per-fragment HTML-comment marker on its own line at the end of the fragment body (extracted at the `parseFragment` seam so it never bleeds into CHANGELOG.md or GitHub release-notes output). `Fixed` and `Security` fragments are not gated. Malformed fragments now fail closed via the new `FAIL_MALFORMED_FRAGMENT` verdict — a triggering fragment with bad frontmatter cannot silently bypass docs enforcement. PR templates (`enhancement.md`, `feature.md`) gain a Documentation checklist; `CONTRIBUTING.md` adds a `Documentation Updates` section codifying the which-doc-to-update matrix and English-canonical language policy.
|
||||
|
||||
<!-- docs-exempt: bootstrap of docs-required lint itself; contributor-facing enforcement lives in CONTRIBUTING.md and the PR templates, while docs/ is reserved for end-user documentation -->
|
||||
|
||||
5
.changeset/sturdy-geese-glide.md
Normal file
5
.changeset/sturdy-geese-glide.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Fixed
|
||||
pr: 3577
|
||||
---
|
||||
**SDK validation errors no longer surface as native_failure** — the runtime-bridge-sync worker now unwraps GSDError causes wrapped in GSDToolsError. Empty/invalid command arguments produce errorKind: 'validation_error' (exit 10) as the SyncErrorKind taxonomy promises, instead of the misleading errorKind: 'native_failure'. Detected by new Phase 6 behavioral contract tests.
|
||||
5
.changeset/sturdy-pandas-rest.md
Normal file
5
.changeset/sturdy-pandas-rest.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
type: Added
|
||||
pr: 3577
|
||||
---
|
||||
**Shared Module hand-sync drift lint** — `scripts/lint-shared-module-handsync.cjs` runs in CI on every PR and fails when a new `bin/lib/<name>.cjs` and `sdk/src/<name>.ts` (or `sdk/src/query/<name>.ts`) pair is introduced without an entry in `scripts/shared-module-handsync-allowlist.json`. The allowlist documents 14 legitimate cooperating-sibling pairs (Adapters over generated Modules, Readers over shared Builders, runtime-distinct routing) plus 8 known drift pairs (`config`, `decisions`, `intel`, `model-catalog`, `plan-scan`, `schema-detect`, `secrets`, `workstream-name-policy`) flagged as future Shared-Module migration backlog. Phase 6 of #3524 also adds path-specific CODEOWNERS rules requiring architecture-team review for source-of-truth files (`sdk/src/<module>/`, `sdk/shared/*.manifest.json`, `sdk/src/runtime-bridge-sync/`, the lint script itself), publishes `docs/agents/cjs-sdk-seam.md` mapping all 15 historical drift bugs (#1535 … #3523) to the enforcement layer that would have blocked each, and adds a contributor guide for adding new Shared Modules and new canonical commands. After this PR the CJS↔SDK seam migration (#3524) is feature-complete. Closes #3575.
|
||||
Reference in New Issue
Block a user