ef436aae625f64cb34c574bc388f16e7a1405079
322 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2ba6b69d53 |
feat(#49): provider-neutral model policy presets
* feat(#49): provider-neutral model policy presets Adds model_policy config surface with known-provider presets (openai/anthropic/google/qwen) and generic provider escape hatch. model_policy.runtime_tiers resolves before legacy model_profile_overrides. reasoning_effort is stripped for unsupported runtimes. Closes #49 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#49): replace unregistered /gsd-settings-advanced token in docs docs-parity-live-registry enforces every /token in docs/*.md maps to a live command. /gsd-settings-advanced is a workflow filename, not a registered command — use /gsd:settings instead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#49): update INVENTORY.md count and manifest for config-types.cjs inventory-counts and inventory-manifest-sync tests require the headline count and INVENTORY-MANIFEST.json to reflect every file in bin/lib/. config-types.cjs (new module added by feat(#49)) was missing from both. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
e3bc53f835 |
enhancement(#558): add liveness hints to all GSD spawn announcements (#566)
* enhancement(#558): add liveness hints to all GSD spawn announcements Append '(runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)' inline to every ◆ Spawning… banner and subagent dispatch instruction across 26 workflows. Silent subagents look identical to frozen sessions — this note sets the expectation so users wait instead of killing healthy in-progress work. Changes: - references/ui-brand.md: document liveness convention under Spawning Indicators - 10 banner workflows: append liveness note to ◆ Spawning… lines in-place - 18 subagent-only workflows: add print instruction with liveness phrase - tests/spawn-liveness-banner.test.cjs: new test; fails if any workflow with subagent_type omits 'runs in a subagent' - docs/USER-GUIDE.md: troubleshooting entry for frozen-looking spawns - .changeset/558-spawn-liveness-banner.md: changeset fragment Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#558): add missing pr field to changeset fragment The changeset lint requires pr: <NNN> in frontmatter; the fragment was written without it, causing parse.cjs to reject it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#558): address codex review — missed spawns and tighten test - plan-phase.md: add liveness note to chunked outline planner and per-plan chunked planner banners (two missed ◆ Spawning… lines) - quick.md: add liveness note to research banner and add missing display line before planner spawn in Step 5 - plan-review-convergence.md: add liveness note to initial planning and review-agent spawn Display lines - docs-update.md: add Print instructions with liveness note before gsd-doc-verifier spawns in Phase 1 and Phase 2 - autonomous.md: add Print instruction with liveness note before background plan-phase agent dispatch in step 3b - tests/spawn-liveness-banner.test.cjs: replace single file-level check with two assertions: (1) every ◆ Spawning… banner line carries the phrase on that line (2) every file with subagent_type contains the phrase somewhere The tighter test would have caught all five missed spawns. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#558): tighten spawn-liveness test regex to catch spawn-word-anywhere variants Previous SPAWN_BANNER_RE only matched ◆ immediately followed by Spawning|spawning. Replace with /◆[^\n]*\bspawning?\b/i which matches the spawn word anywhere on the ◆ line — catching "◆ Chunked mode: spawning outline planner..." and similar. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#558): rename changeset to PR number 566 and correct pr field Changeset was filed as 558-spawn-liveness-banner.md (issue#) but the convention is the PR number. Renamed to 566-spawn-liveness-banner.md and updated pr: 558 → pr: 566 so release notes link to the right PR. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
0a12b06381 |
feat(#39): milestone-prefixed phase IDs (M-NN convention) + migration tool + validation (#565)
* feat(#39): milestone-prefixed phase IDs (M-NN convention) + migration tool + validation - Add getMilestoneFromPhaseId() / getPhaseDirFromPhaseId() helpers to core.cjs - Fix isDirInMilestone to match M-NN-style dirs (02-01-setup) against M-NN ROADMAP headings - Extend heading regex to tolerate [bracket-token] scope prefix on phase headings - Add W021 validation rule for milestone prefix mismatch - Add gsd-tools roadmap validate + roadmap upgrade --convention milestone-prefixed - Add phase_id_convention config field (null default, backwards-compatible) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#39): address 4 Codex review findings in milestone-prefixed phase ID implementation - getMilestoneFromPhaseId: tighten regex to require a digit after the hyphen (rejects '1-' and '1-abc') - isDirInMilestone: use convention-aware regex — only capture M-NN segments when ROADMAP itself uses hyphenated phase IDs, preventing legacy dirs like '01-02-setup' from being misread as phase '1-02' - checkW021: add UNPREFIXED_PHASE_RE path so unprefixed headings (### Phase 1:) also fire W021 when convention is milestone-prefixed - roadmap-upgrade: remove isMigratedDirName dir-name check (false-positive for legacy dirs); config + ROADMAP heading checks at lines 194 and 212 are sufficient Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: update changeset pr reference to #565 * fix(#39): restore phaseDirNameRe 2-digit minimum; add roadmap-upgrade to inventory - validate.cjs: \d{1,} → \d{2,} to keep single-digit prefix rejection per W005 contract - docs/INVENTORY.md: 79 → 80, add roadmap-upgrade.cjs row - docs/INVENTORY-MANIFEST.json: regenerated (roadmap-upgrade.cjs entry) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
48c1827028 |
enhancement(#40): integrate branch pruning into /gsd-cleanup archival workflow (#564)
* enhancement(#40): integrate branch pruning into /gsd-cleanup archival workflow Adds a prune_local_branches step to cleanup.md (between archive_phases and commit) that force-deletes local branches whose upstream is gone — keeping local clones symmetric with delete_branch_on_merge on GitHub. Key design choices vs. PR #562 (the local-model draft): - dry-run step shows stale branches using cached tracking refs only; git fetch --prune is deferred to the execution step so the dry-run is non-side-effecting - awk uses { if ($1 != "*") print $1 } form to explicitly exclude the currently checked-out branch (the * prefix in git branch -vv output), not a prose note that lets xargs receive literal * as an argument - git fetch --prune runs exactly once, in prune_local_branches, eliminating the TOCTOU window between a preview fetch and an execution fetch - two new negative-contract tests: identify_completed_milestones must not run git branch commands; show_dry_run must not run git fetch --prune Closes #40 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: regenerate changeset using repo script (correct format) Replaces hand-written fragment (used `/** ... */` comment syntax) with one generated by `npm run changeset -- --type Changed --pr 562`. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: address codex review blockers — protect main/next/trunk, align dry-run with execution Codex adversarial review (pre-PR gate) flagged two blockers: 1. awk filter only excluded '*' (current branch) but not protected names. main/next/trunk/develop could be force-deleted if their upstream was gone. Fix: use !~ /^\*$|^main$|^next$|^trunk$|^develop$/ regex match. 2. Dry-run enumerated from cached tracking refs; execution re-ran git fetch --prune, creating a TOCTOU window between what the user confirmed and what got deleted. Fix: move git fetch --prune into show_dry_run (prefetch for display accuracy); prune_local_branches now enumerates from the already-fetched state with no second fetch. Updated 14 structural tests to match new design (added protected-name exclusion test; inverted show_dry_run fetch assertion). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
9b5ee37364 |
chore(#556): retire orphaned CJS↔SDK hand-sync tooling (#559)
The @opengsd/gsd-sdk package boundary was retired (ADR-0174, #191/#192) and the sdk/ tree is no longer tracked. ADR-0174's Supersedes table explicitly records that the generator-based Shared-Module hand-sync lint is deleted as part of that collapse. This removes the now-orphaned machinery it left behind: - scripts/lint-shared-module-handsync.cjs — paired bin/lib/*.cjs files with sdk/src/**/*.ts sources that no longer exist; wired into no CI workflow or npm script (dead). - scripts/shared-module-handsync-allowlist.json — the lint's allowlist; every entry pointed at a non-existent sdk/src source / generated artifact / freshness check. - tests/lint-shared-module-handsync.test.cjs — tested the deleted lint. Docs corrected to match: - CONTRIBUTING.md — removed the "CJS↔SDK seam" instruction (it linked the already-deleted docs/agents/cjs-sdk-seam.md and told contributors to maintain the allowlist under a retired generator pattern). - docs/prd/3524-cjs-sdk-hard-seam.md + docs/prd/README.md — marked the PRD Superseded by ADR-0174, matching the already-superseded ADR-3524. Added tests/no-cjs-sdk-handsync-tooling.test.cjs as a regression guard so the retired tooling stays removed and is not silently re-wired into package.json. ADR-3524 is left in place (already Superseded by ADR-0174); runtime modules and regression tests that cite it in comments keep resolving. No user-facing change. Closes #556 Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
de2f73d21a |
enhancement(#34): add Antigravity CLI (agy) as a peer reviewer in /gsd-review
Closes #34 Squash-merged via admin override — all CI green (28/28 checks), branch protection review gate bypassed with maintainer authorization. |
||
|
|
5cd52eb151 |
enhancement(#537): pilot TS build-at-publish for bin/lib (semver-compare) (#541)
* docs(#457): rewrite ADR-457 to ground truth and accept build-at-publish The prior draft asserted a codebase state that never existed (13 tsc-generated files, src/ trees, a tests/cjs-ts-parity.test.cjs). Corrected to verified ground truth (84 bin/lib .cjs, 1 value-baked package-identity.cjs, no tsc pipeline), distinguished value-baking from transpilation so package-identity stops being miscited as precedent, made check-in-the-artifact vs build-at-publish the central decision, and flipped status to Accepted (build-at-publish). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * build(#537): pilot TS build-at-publish for bin/lib (semver-compare) First hand-written module collapsed to a TypeScript source of truth per ADR-457. src/semver-compare.cts compiles (tsc, strict, noEmitOnError) to a gitignored get-shit-done/bin/lib/semver-compare.cjs. build:lib is wired into build, pretest, pretest:coverage, and prepublishOnly so the artifact is built before test and shipped on publish. Type-aware ESLint on src/**/*.cts immediately caught the params were over-typed as `unknown` (no-base-to-string); narrowed to a honest VersionInput domain type. Behavior preserved: semver-compare.test.cjs (14) and bug-10 (4) pass against the generated output; runtime consumer changeset/cli.cjs unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#537): make build-at-publish robust across all CI paths (codex review) Adversarial review found the pilot's generated artifact would be missing on clean CI checkouts. `pretest`/`pretest:coverage` only fire for `npm test`, but CI runs `test:unit`/`test:integration`/`test:install` and `node run-tests.cjs` directly — none of which built the artifact, so any suite requiring semver-compare.cjs would hit module-not-found on a clean checkout, and install-smoke's `npm pack` could ship without it. - Add a `prepare` script (`npm run build:lib`). `npm ci` runs it automatically, so every CI test job and install-smoke's pack emit the artifact before use. This is the idiomatic npm mechanism for compiled-output-not-in-git and fixes both the test and pack paths in one place. - Add `src/` + `tsconfig.build.json` to ci-test-scope and the install-smoke / mutation path filters, so a source-only edit to a migrated module still triggers its tests and mutation coverage (prevents silent CI skips). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#537): map src/*.cts to built artifact in mutation changed-files detection Follow-up to the codex re-review. The prior commit added src/**/*.cts to the mutation workflow's path trigger but left its "compute changed core lib files" step diffing only get-shit-done/bin/lib/**/*.cjs — which are now gitignored and never appear in a diff. A source-only edit would trigger the workflow then early-exit ("no core lib files changed"), silently skipping mutation testing. Map each changed src/*.cts to its built get-shit-done/bin/lib/*.cjs path (the on-disk artifact Stryker mutates after prepare/build:lib), merge with the hand-written .cjs diff, and apply the test/excluded-module filters once. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#537): use 'src/' pathspec in mutation diff (git glob doesn't match top-level) Codex review caught that `git diff -- 'src/**/*.cts'` returns empty for a top-level file like src/semver-compare.cts — git's default pathspec glob does not match `**` across zero directories (verified on git 2.50.1). The prior commit's src-detection therefore never fired, so source-only changes still skipped mutation. Switch to the dir-scoped pathspec 'src/' + a `.cts` grep (robust for flat and nested layouts), and broaden the workflow path trigger to 'src/**' to match install-smoke. Verified end-to-end: a change to src/semver-compare.cts now resolves to get-shit-done/bin/lib/semver-compare.cjs in the --mutate list. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#537): add changeset fragment for build-at-publish pilot Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#537): replace prepare with prepack + build-if-missing; defer mutation wiring CI surfaced three real issues the local run and codex review missed: 1. lockfile-sync failed on every platform. Root cause: `npm ci --dry-run` (the repo's lockfile health check) RUNS the `prepare` script, but in dry-run the devDependencies aren't installed, so `tsc` is not found (exit 127) and the check reports a misleading "out of sync". `prepare` is the wrong hook for a build needing a devDep. Replace it with `prepack` (runs only on pack/publish, when node_modules exists) for the tarball path, and build the artifact inside scripts/run-tests.cjs (build-if-missing) for the test path — the universal chokepoint every CI test invocation funnels through, including the direct `node run-tests.cjs --files-from` step that bypasses npm lifecycle hooks. The guard is a no-op once built, so the run-tests harness test is unaffected. 2. The Stryker mutation gate ran only 1 test against semver-compare (~0% score, 71/71 mutants surviving) — a Stryker test-selection problem orthogonal to the build migration, and raising the score needs property tests (ADR-456). Revert the mutation.yml src wiring; mutation coverage for src-authored modules is a separate follow-up tracked in #537. (The deletion of the gitignored top-level .cjs does not match the workflow's `bin/lib/**/*.cjs` git pathspec, so the gate skips cleanly.) Verified: clean-room `npm ci --dry-run` exits 0; deleting the artifact then running a suite rebuilds it; run-tests harness 22/22 green; `npm pack` includes the built artifact via prepack. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
6fc84528e5 |
fix(#448): resolve UI safety gate helper against the GSD install dir (#539)
* fix(#448): resolve UI safety gate helper against the GSD install dir The §5.6 UI Design Contract Gate (and autonomous §3a.5) resolved ui-safety-gate.cjs via `git rev-parse --show-toplevel`, i.e. the consuming project's git root — which has no bin/lib. The node call failed, its exit code was conflated with "no UI", and the gate silently no-opped so frontend phases skipped the UI-SPEC prompt. Resolve the helper against the GSD install dir via RUNTIME_DIR (the same idiom §1 uses for gsd-tools), with git-toplevel and $HOME/.claude fallbacks. When the helper genuinely can't be found, fail OPEN with a stderr warning (assume UI present) rather than silently skipping. Tests: bug-3706 structural guard now requires RUNTIME_DIR resolution and forbids the consuming-project GSD_REPO_ROOT anchor; a new behavioral test resolves and runs the helper from a temp consuming project (no bin/lib) with RUNTIME_DIR set. autonomous-ui-steps updated to match. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(#448): add changeset fragment for PR #539 * fix(#448): add get-shit-done/bin/lib/ to UI gate probe and deploy helper there The installer copies get-shit-done/ to the target but not root bin/lib/, so the helper was never found for installed users. Placing ui-safety-gate.cjs in get-shit-done/bin/lib/ ensures the installer deploys it, and probing that path first makes the gate work correctly in installed runtimes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: update changeset to cover get-shit-done/bin/lib/ deployment Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: update inventory for ui-safety-gate.cjs in get-shit-done/bin/lib/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
c6724ea947 | docs(#542): align README version source of truth | ||
|
|
ec8a08f2d2 | docs(#530): streamline README brand header | ||
|
|
c81d5fcb2c | docs(#523): rebrand public docs as GSD Core | ||
|
|
0fbe1d899e |
chore(#191): retire the gsd-sdk shim — route everything at gsd-tools (#522)
* chore(#191): migrate gsd-sdk query call sites to gsd-tools query Retiring the gsd-sdk shim. gsd-tools.cjs already accepts `query` as a meta-prefix (gsd-tools query <command>), so this is a behavior-preserving 1:1 swap across the runtime reference prompts, the graphify hook's commit-detection gate, and two bin/lib comment/message references. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#191): remove vestigial gsd-sdk shim code from installer + projection The gsd-sdk shim was already not wired up (no gsd-sdk bin in package.json; buildWindowsShimTriple had zero call sites). Remove the dead code: - shell-command-projection.cjs: buildWindowsShimTriple + formatSdkPathDiagnostic (+ their now-unused PACKAGE_NAME import) and exports - install.js: the re-export wrappers + imports, the #3406 stale-standalone-sdk detection (detectStaleStandaloneSdk/formatStaleStandaloneSdkWarning + its global-install call site), and the exports Preserved (retained, not gsd-sdk): buildCodexHookWindowsShimIR (#3426) — only its comments referenced the gsd-sdk pattern; reworded. Also kept the homePathCoveredByRc 'reopen your shell' branch in maybeSuggestPathExport — its logic is bin-dir-agnostic, only the message mentioned gsd-sdk; reworded to use the actual bin dir. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(#191): update tests for retired gsd-sdk shim - bug-3441/bug-3442: drop the formatSdkPathDiagnostic / buildWindowsShimTriple assertions (functions removed); retained PATH-action + drift-guard tests stay - bug-505: remove the 'still exported' assertions for detectStaleStandaloneSdk / formatStaleStandaloneSdkWarning / the shim contract surface (#505 kept them; #191 removes them) - graphify-auto-update: migrate the hook-dispatch inputs gsd-sdk query commit -> gsd-tools query commit to match the migrated commit hook Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(#191): point active docs at gsd-tools query (gsd-sdk shim retired) Update the user/agent-facing docs (AGENTS, COMMANDS, CONFIGURATION, USER-GUIDE, ship-pr-body-sections) that presented gsd-sdk query as a current command to gsd-tools query. Historical docs (ADRs, PRDs, release notes) left untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(#191): correct state.load vs state.json description for gsd-tools query Adversarial-review (codex) finding: the migrated USER-GUIDE line claimed both 'gsd-tools query state.json' and 'state.load' resolve to the frontmatter-rebuild handler. Verified they don't — state.load returns the CJS load shape (config + state_raw + flags), state.json returns the frontmatter shape. Both are available via gsd-tools query; corrected the text to say so. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#191): add changeset for gsd-sdk shim retirement Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
79002a00cb |
chore(#518): rename npm package + bin to @opengsd/gsd-core (#519)
* chore: rename npm package + bin to @opengsd/gsd-core (functional) - package.json: name @opengsd/get-shit-done-redux → @opengsd/gsd-core, bin key get-shit-done-redux → gsd-core, repository/homepage/bugs URLs - package-lock.json: regenerated (npm install --package-lock-only) - tests/**, scripts/**, bin/**, .github/**, agents/**, commands/**, get-shit-done/bin/**, get-shit-done/workflows/**: applied the 4-rule replacement (scoped npm ref, GitHub repo path, bin/clone invocations) per #505 single-source refactor Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs: sweep live references to @opengsd/gsd-core Update all live documentation (README.md + translations, docs/**, CONTRIBUTING.md, VERSIONING.md, SECURITY.md, CONTEXT.md, docs/CANARY.md) to reflect the renamed package and repository. Rules applied: - @opengsd/get-shit-done-redux → @opengsd/gsd-core (scoped npm name) - open-gsd/get-shit-done-redux → open-gsd/gsd-core (GitHub repo) - GSD-redux/get-shit-done-redux → open-gsd/gsd-core (stale badge org) - bare bin/clone refs → gsd-core CHANGELOG.md, docs/adr/**, docs/RELEASE-*.md, docs/research/**, and .changeset/** are preserved byte-identical. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: add negative lookbehind to slash-command regex in bug-2954 test The extractSlashReferences regex matched /gsd-core inside npm package URLs (@opengsd/gsd-core), producing a false /gsd:core command reference. Adding a negative lookbehind (?<![a-z]) excludes matches preceded by a letter, so only standalone /gsd-<cmd> and /gsd:<cmd> tokens are found. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#518): add changeset for package rename Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(#518): update package-identity expectations to the renamed coordinates The rebase regenerated the seam to @opengsd/gsd-core (bin gsd-core, repo open-gsd/gsd-core). The #498 seam tests assert deriveIdentity against the REAL package.json, so their expected literals must follow the rename. The drift-lint unit test is left as-is — its SEAM is a self-consistent fixture and its stale-literal detection cases would shift if altered; the live-repo scan in it already passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
05cdec5f47 |
feat(#22): plan-vs-codebase drift guard (source-grounded reviewer + intel surface) (#487)
* feat(#22): add plan_review.source_grounding + _authority config keys Two additive opt-out keys for the drift guard: source_grounding (bool, default true) gates the source-grounded reviewer pass; _authority (enum grep|intel|treesitter|lsp|scip, default grep) selects the resolver rung. No existing default changed. Refs #22 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(#22): add intel api-surface renderer + CLI subcommand Renders .planning/intel/api-map.json into a human-readable API-SURFACE.md for planner injection. Empty/missing map still writes a surface that announces itself incomplete (absence = unknown, not 'does not exist'). Gated on intel.enabled like all intel functions. Refs #22 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(#22): add source-grounding pass to plan-review-convergence Default-on reviewer pass (plan_review.source_grounding) that enumerates every symbol a plan cites, excludes declared new artifacts, resolves each against source via the configured authority adapter, and records three-valued verdicts. rung-0/1 MISSING is needs-acknowledgement, not a hard block; UNCHECKABLE is logged in a REVIEWS.md coverage section. Refs #22 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(#22): inject API-SURFACE.md into planner + require Artifacts section When intel.enabled, plan-phase regenerates API-SURFACE.md and injects it as a HINT (prefer, may be incomplete, absence = unknown), never a hard rule. Every plan must now emit an 'Artifacts this phase produces' section so the source-grounding reviewer can separate new symbols from references to existing code. Refs #22 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(#22): surface drift-guard in setup + settings, add docs /gsd:new-project asks to enable plan_review.source_grounding (default Y); /gsd:settings exposes the toggle and authority knob. Documents both config keys in CONFIGURATION.md, the intel api-surface command in COMMANDS.md, the drift guard in USER-GUIDE.md, and links ADR 22 from ARCHITECTURE.md. Refs #22 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#22): respect AskUserQuestion 4-option cap and plan-phase XL line budget settings drift-guard toggle moved to its own 2-option question; #22 plan-phase additions condensed to bring the file back under the 1810-line XL budget without dropping the intel gate, the incomplete-surface hint, or the Artifacts-section requirement. Refs #22 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#22): use live slash-command forms in drift-guard docs Doc-parity gate requires every slash-command token in docs/*.md to resolve to a registered command. Corrected the command form(s) referenced in the #22 drift-guard / api-surface documentation. The unresolved token was /gsd-core, matched from the GitHub repo reference "open-gsd/gsd-core#22" in docs/adr/22-plan-drift-guard.md. This is the same pattern as the existing 'test-runner' exemption (open-gsd/gsd-test-runner). Added 'core' to INTERNAL_COMPONENT_SLUGS with a matching explanatory comment. Refs #22 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(#22): add changeset fragment for drift guard (PR #487) Refs #22 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: CI Rebase Check <ci@gsd-redux> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
6f2520786d |
feat(#498): single Package Identity seam for /gsd:update + fix runtime undefined-name bug (#499)
* feat(#498): generated package-identity seam derived from package.json Introduce a single source for GSD's published-package coordinates: scripts/generate-package-identity.cjs (pure deriveIdentity + formatManualInstall + render) emits the generated get-shit-done/bin/lib/package-identity.cjs with values baked from package.json at build time. Baking is required because the installed tree carries only a synthetic {"type":"commonjs"} package.json, so a runtime require('package.json').name resolves to undefined (#378). Reconciles Wired into npm run build; a parity test fails CI if the committed file drifts from package.json. Refs #498 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#498): repoint update worker + check-latest-version at the seam - check-latest-version.cjs sources PACKAGE_NAME from the package-identity seam instead of a re-typed literal (single source; #2992's constant guarantee is preserved since the seam bakes from package.json). - gsd-check-update-worker.js no longer does require('../package.json').name (resolved to undefined in the installed tree → background update check silently broken, #378). It now delegates the latest-version lookup to checkLatestVersion(), collapsing the duplicated npm-view call onto the single deterministic adapter and inheriting its typed {ok,version,reason} surface. - Move the PR #3102 Windows shell-gate contract test onto execNpm (where the spawn now lives) and assert the worker no longer spawns npm directly. - Rewrite the #378 contract: worker must NOT use require(package.json).name and must delegate; check-latest-version PACKAGE_NAME is single-sourced from the seam. Fixes #378-class runtime breakage. Refs #498 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#498): changeset for package-identity seam + update-check fix Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(#498): drift-guard lint — value-check GSD coordinate literals against the seam scripts/lint-package-identity-drift.cjs scans the runtime/code surface (bin/, hooks/, scripts/, get-shit-done/) and asserts every GSD package name and GitHub repo slug literal equals the Package Identity seam's current value. Passes today; fails the moment a repoint isn't propagated (rename package.json, regenerate the seam, and stale literals are reported until updated). This is the second adapter that makes the seam real and a repoint mechanically safe. Enforced via tests/issue-498-identity-drift-lint.test.cjs (scanRepo === []) under npm test; also exposed as `npm run check:identity-drift`. Refs #498 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(#498): update-context projection — port update.md resolution to a tested seam Add get-shit-done/bin/lib/update-context.cjs: a pure, injected-fs port of update.md's ~280-line get_installed_version bash. resolveUpdateContext() reproduces the full precedence cascade (preferred fast-path -> local probe -> global probe via env overrides then $HOME -> LOCAL-if-distinct -> scope cascade -> UNKNOWN) and returns the 4-field contract { installedVersion, scope, runtime, gsdDir }. The fs is injected so every branch is finally testable without a live multi-runtime install. Expose it as `gsd-tools update-context [--config-dir <d>] [--runtime <r>] --json`. Purely additive — update.md is unchanged in this commit; the workflow swap follows separately. Refs #498 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(#498): swap update.md resolution to the update-context projection Replace ~280 lines of inline runtime/scope/config-dir bash in update.md's get_installed_version step with a call to `gsd-tools update-context --json` (60 lines: derive PREFERRED_* from execution_context, resolve gsd-tools.cjs, parse the 4-field JSON). Behavior is unchanged — the projection reproduces the same cascade — but the logic is now tested in update-context.cjs instead of untestable bash-in-markdown. Relocate the #3608 antigravity-first-class contract onto the projection (RUNTIME_DIRS order, inferPreferredRuntime, envRuntimeDirs) plus a behavioral test; keep the execution_context path-classification assertion on update.md. Re-point install.test's custom-config-dir assertion (kilo.jsonc/KILO_CONFIG) to update-context.cjs where that detection now lives. Full root suite: 2022 pass / 0 fail. Refs #498 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(#498): record Update Context Module in CONTEXT.md Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#498): CI — avoid bare gsd-tools in update.md; register new CLI modules - update.md update-context invocation: resolve the PATH gsd-tools shim into a variable and call "$GSD_TOOLS" (never a bare `gsd-tools` command) — satisfies the #2851 workflow-bare-gsd-tools guard. - Register package-identity.cjs and update-context.cjs in docs/INVENTORY.md (CLI Modules 76 -> 78 + rows) and regenerate docs/INVENTORY-MANIFEST.json, fixing inventory-counts and inventory-manifest-sync. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(#498): make update-context + parity tests OS-agnostic (Windows CI) Two Windows-only test failures, both test-portability (production code is fine — the real-fs CLI integration test passed on Windows): - update-context resolver tests + bug-3608 behavioral test used POSIX path-string keys in their fake fs, but the resolver builds lookups via path.join/resolve (backslash + drive letter on Windows) → keys never matched → everything resolved to UNKNOWN/claude. Normalize fake-fs keys and gsdDir comparisons through path.resolve so they match on both platforms. - package-identity parity test compared render() (LF) to the committed file, which Windows git checks out as CRLF (no .gitattributes eol rule). Normalize line endings before comparing, matching the repo convention (autonomous-decomposition, bug-3707). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#498): update.md backup must use GSD_DIR (adversarial-review finding) The get_installed_version rewrite emits GSD_DIR but dropped the probe-loop variables LOCAL_DIR/GLOBAL_DIR. The backup_custom_files step still read those, so RUNTIME_DIR went empty for every LOCAL/GLOBAL install and detect-custom-files was skipped — and since the update then runs a clean install that wipes managed dirs (commands/gsd, get-shit-done), user-added files could be deleted without the intended backup. Set RUNTIME_DIR="$GSD_DIR" directly (the resolved config dir; empty for UNKNOWN scope, which still skips the backup). Add a structural regression (tests/issue-498-update-backup-runtime-dir.test.cjs). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(#503): re-point Antigravity .agent detection at the #498 projection #499 moves the runtime/scope detection cascade out of update.md inline bash into get-shit-done/bin/lib/update-context.cjs. The #503 regression test asserted on the inline RUNTIME_DIRS array, which no longer exists, so it would fail against the projected update.md even though the .agent guarantee is preserved. Rewrite it to verify the surviving surfaces: - behavioral: resolveUpdateContext resolves a LOCAL ./.agent install to the antigravity runtime (the original root cause, now covered by adding ['antigravity', '.agent'] to the projection RUNTIME_DIRS table) - update.md prose classifier still maps /.agent/ -> antigravity - the post-update cache-clear for-dir loop still includes .agent Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(#498): finish de-hardcoding consumers + close adversarial-review parity gaps Restore the consumer de-hardcoding that is the point of the seam, and close the parity gaps an adversarial review (codex) found in the update-context projection. De-hardcode the repo slug + install command in the changeset tooling — #516 only single-sourced the package NAME, leaving 'open-gsd/get-shit-done-redux' hardcoded in scripts/changeset/cli.cjs and github-release-notes.cjs. Route both through the seam's repoSlug/packageName so a rename is a regenerate, not a hand edit. The drift-lint real scan now reports zero divergent coordinate literals. Projection parity vs the old inline bash, as ONE consistent rule (trustedVersionAt) applied on every path: - expand a leading ~/ in preferredConfigDir before the fast path (the bash ran expand_home first; a custom --config-dir ~/foo otherwise fell to UNKNOWN) - trust a version only when BOTH VERSION and the update.md marker exist — fast path AND LOCAL/GLOBAL cascade; a partial dir falls to 0.0.0 keeping scope - apply the same same-path dedup to the 0.0.0 fallback so a partial install probed from cwd===home is not misdetected as LOCAL Adds regression tests for tilde expansion, VERSION-only (cascade + fast path), and the cwd===home partial-install dedup. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
fbd555c2ce |
fix(#520): register package-identity.cjs in inventory (regression from #516) (#521)
#516 added get-shit-done/bin/lib/package-identity.cjs without regenerating the inventory, breaking inventory-manifest-sync and inventory-counts on next. Regenerate docs/INVENTORY-MANIFEST.json and bump docs/INVENTORY.md CLI-module count 76 -> 77 with the new row. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
d2ff4ac092 |
docs(#22): add ADR for plan-vs-codebase drift guard (defaults + resolver seam) (#484)
Consolidated decision record: source-grounding verification default-on (plan_review.source_grounding), intel.enabled stays opt-in, and the three-valued symbol-resolver seam with a climbable adapter ladder. Refs #22 Co-authored-by: CI Rebase Check <ci@gsd-redux> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
c7e5a88353 |
enh(#466): refresh opus-tier model IDs to current GA (Opus 4.8 / codex gpt-5.5) (#467)
* enh: bump opus-tier model IDs to current GA (Opus 4.8 / codex gpt-5.5) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(#466): changeset for opus-tier model-ID refresh Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: CI Rebase Check <ci@gsd-redux> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
b8c33647d8 |
refactor(tests): retire output-grep & source-grep via typed surfaces (finish #2974) (#462)
* refactor(#455): implement typed surfaces to retire grep tests Production surfaces added: - hooks/managed-hooks-registry.cjs: new CJS module exporting MANAGED_HOOKS as a typed array; gsd-check-update-worker.js now requires it instead of declaring an inline array - bin/install.js: elevate inline gsdHooks to module-level GSD_UNINSTALL_HOOKS, export it alongside runtimeMap/allRuntimes (already exported) - scripts/build-hooks.js: export HOOKS_TO_COPY; guard build() behind require.main===module so tests can require the file without triggering a build - get-shit-done/bin/lib/init.cjs: add --json mode to agent-skills command, emitting typed IR { agent_type, block, skills_count } for test assertions - get-shit-done/bin/gsd-tools.cjs: wire --json flag for agent-skills dispatch Category-B source-grep migrations: - tests/managed-hooks.test.cjs: require MANAGED_HOOKS from registry, drop fs.readFileSync+regex - tests/orphaned-hooks.test.cjs: require MANAGED_HOOKS+HOOKS_TO_COPY as typed exports - tests/hooks-opt-in.test.cjs: replace gsdHooks regex-parse with GSD_UNINSTALL_HOOKS import - tests/install-minimal-hooks.test.cjs: replace gsdHooks regex-parse with GSD_UNINSTALL_HOOKS - tests/copilot-install.test.cjs: replace src.includes() checks with typed assertions on runtimeMap, allRuntimes, parseRuntimeInput, buildRuntimePromptText - tests/agent-skills.test.cjs: migrate to --json typed IR assertions pending-migration-to-typed-ir token cleared (87 of 87 files): - 78 files already had source-text-is-the-product; removed duplicate token - 5 files already used typed assertions; reclassified or annotated - 4 files required individual reclassification to source-text-is-the-product or architectural-invariant Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#455): update workflow-guard test to typed GSD_UNINSTALL_HOOKS import; isolate HOME in runtime-launcher (D) test Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#455): guard install.js main() behind require.main===module so the typed export is require-safe Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(#455): document --json typed surfaces for agent-skills, progress, validate context Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(#455): add changeset fragment for new --json surfaces Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#455): complete grep migration for files flagged by lint-tests The branch commit 4e630d99 stripped `allow-test-rule: pending-migration-to-typed-ir` from ~80 test files without replacing their assertions or adding the correct exemption annotation. The files were NOT source-grep tests — they read .md workflow/agent/command/reference files (source-text-is-the-product) or hook source files for structural invariants (structural-regression-guard). No assertion logic was changed; only the correct allow-test-rule annotation was added to each file per CONTRIBUTING.md exception matrix. 73 files: `source-text-is-the-product` — workflow/agent/command/reference .md 7 files: `structural-regression-guard` — hook .js / bin/install.js structural checks Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: CI Rebase Check <ci@gsd-redux> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
bf68ad4d93 |
fix(tests): deterministic concurrency via injectable clock seam; delete flaky racing tests (#459)
* feat(#453): add deterministic clock seam to lock modules Introduces get-shit-done/bin/lib/clock.cjs exporting realClock with now() (Date.now) and sleep() (Atomics.wait). acquireStateLock, writeStateMd, and readModifyWriteStateMd in state.cjs each accept an optional trailing clock param (default: realClock). withPlanningLock in planning-workspace.cjs gains the same seam. No production behavior change — all callers that omit the param continue to use realClock. Adds tests/helpers/clock.cjs (makeFakeClock) and tests/clock-seam.test.cjs with 20 deterministic in-process tests covering: lock serialization, timeout throw at maxWaitMs boundary, stale-lock takeover, lock released on error path, withPlanningLock timeout recovery, exit-cleanup integration, readModifyWriteStateMd call-site coverage (7 cmd*), and roadmap analyze behavioral assertion (50 phases, no elapsed-time gate). Deletes/converts per research verdicts: removes 11 source-grep/elapsed-time/ non-deterministic-concurrent tests across concurrency-safety.test.cjs, locking-bugs-1909-1916-1925-1927.test.cjs, and bug-1974-context-exhaustion- record.test.cjs. All deleted tests have deterministic replacements in clock-seam.test.cjs or surviving barrier-based tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#453): update module inventory for clock.cjs; make EEXIST-retry assertion behavioral Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(#453): satisfy lint-tests — allow-test-rule annotation on readFileSync/includes runtime output check Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: CI Rebase Check <ci@gsd-redux> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
ed1c20061b |
docs(#456): add testing standards, ADRs 452/456/457, and CONTEXT.md entries (#458)
- docs/adr/452-eslint-lint-harness.md (Accepted): adopt ESLint flat config with typescript-eslint, eslint-plugin-n, eslint-plugin-no-only-tests, and local AST-rule plugin; retire homegrown scripts/lint-*.cjs regex checkers; three test-rigor rules ship at warn, promoted to error after #453 cleanup - docs/adr/456-test-rigor-architecture.md (Accepted): deterministic-over-racing via injectable clock seam + node:test mock.timers; antagonistic tier with fast-check + Stryker at 80% threshold; typed-surface mandate; delete-bad-tests policy with no-permanent-quarantine - docs/adr/457-generated-cjs-single-source.md (Proposed): future direction to collapse ~59 hand-written bin/lib/*.cjs to TS-generated single source; eliminates tsconfig.lint.json stopgap; marked Proposed / not yet executed - TESTING-STANDARDS.md: orients to existing docs; codifies six test-rigor contracts; adds new policies (no-timing-assertion, clock-seam, property-based, mutation-score, delete-bad-tests); pairs each with exact ESLint rule names; markdownlint-clean (MD040 fences, MD056 table columns) - CONTEXT.md: adds six RULESET.TESTS.* predicates (no-timing-assertion, clock-seam, property-based-testing, mutation-score, delete-bad-tests, eslint-harness) and five glossary terms (clock seam, deterministic scheduler, property-based test, mutation testing/score, ESLint harness) - docs/adr/README.md: adds index rows for ADRs 452, 456, 457 Co-authored-by: CI Rebase Check <ci@gsd-redux> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
5ca646f015 |
feat(#443): unified cross-provider effort controls + fast-mode-aware routing (#463)
* test(#443): RED unified effort + fast_mode + resolve-execution All 68 tests failing as expected — no implementation yet. Covers: effort cascade (tier defaults, overrides, invalid fallthrough), fast_mode cascade (boolean-only, tier defaults), resolveEffortForTier escalation, renderEffortForRuntime clamping, resolve-execution CLI, config schema new keys, QA hostile-input matrix. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(#443): unified cross-provider effort + fast_mode knobs and resolve-execution query Adds config-driven effort control (universal ladder: minimal<low<medium<high<xhigh<max) and fast_mode propagation knobs, with per-runtime rendering that clamps the unique tail values (max=Anthropic-only clamps to xhigh on Codex; minimal=Codex-only clamps to low on Claude). Key changes: - config-schema.manifest.json: add effort.default, fast_mode.enabled as validKeys; add 4 dynamicKeyPatterns for effort.routing_tier_defaults, effort.agent_overrides, fast_mode.routing_tier_defaults, fast_mode.agent_overrides; fix stale _comment - config-defaults.manifest.json: add effort and fast_mode blocks with tier defaults - model-catalog.cjs: add EFFORT_RENDERING map, renderEffortForRuntime(), RUNTIMES_WITH_FAST_MODE - model-profiles.cjs: re-export new catalog exports - core.cjs: add resolveEffortInternal, resolveFastModeInternal, resolveEffortForTier, VALID_EFFORTS, EFFORT_SET, nextEffort; pass effort/fast_mode through loadConfig - commands.cjs: replace reasoning_effort in cmdResolveModel with unified effort; add cmdResolveExecution (superset command with effort_rendered, effort_param, effort_propagation, fast_mode, fast_mode_supported) - gsd-tools.cjs: add resolve-execution case with --effort/--fast-mode/--attempt flags - tests/feat-443: 69 tests covering cascade, rendering, escalation, CLI, schema, QA matrix - tests/commands.test.cjs: convert 3 reasoning_effort assertions to unified effort - docs/CONFIGURATION.md: document effort + fast_mode + resolve-execution sections - settings-advanced.md: list new effort/fast_mode keys in confirmation table Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(#443): remove dead catalog effort lane; unify codex effort through renderEffortForRuntime - Remove resolveReasoningEffortInternal (catalog-driven effort function) from core.cjs and its export; remove from commands.cjs destructure import - Convert tests/issue-2517-runtime-aware-profiles.test.cjs: all 11 effort assertions now use resolveEffortInternal + renderEffortForRuntime; Claude effort is first-class (output_config.effort); unknown runtimes assert param===null - Convert tests/feat-3023-model-phase-types.test.cjs: replace the entire resolveReasoningEffortInternal describe with unified effort assertions; effort derives from AGENT_DEFAULT_TIERS routing tier, not phase-type tier Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(#443): ADR for unified cross-provider effort + fast-mode routing Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test(#443): architecture-level QA invariants + test-strategy doc Add 48-test integration suite (feat-443-effort-fast-mode.integration.test.cjs) covering 8 architectural invariants: cross-provider validity (never emit a value the real API would 400 on), param/channel contract stability, resolve-execution JSON contract (all 8 keys + correct types), totality across the full 33-agent registry, fast-mode honesty (claude always fast_mode_supported=false), precedence first-valid-wins matrix for both effort and fast_mode cascades, dynamic-routing composition (effort escalation independent of model tier), and config-set round-trip for all new effort/* and fast_mode/* key namespaces. Append test-strategy section with invariant rationale and E2E gap documentation to docs/TESTING-SUITES.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(#443): add failing install-wiring tests for effort per-runtime injection (RED) TDD RED: 10 failing tests covering: - Claude .md gets effort: injected per tier (planner=xhigh, mapper=low, executor=high) - Gemini .md does NOT get effort: (already passing — Gemini-safe) - Codex .toml gets model_reasoning_effort via unified resolver - Config-driven: effort.agent_overrides drives both Claude .md and Codex .toml - Source purity: agents/*.md have no effort: key (already passing) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(#443): wire effort per-runtime at install (Claude .md frontmatter + Codex .toml unified) - Import AGENT_DEFAULT_TIERS and renderEffortForRuntime from model-catalog.cjs - Add readGsdEffectiveEffortConfig(targetDir): reads merged effort config from .planning/config.json (per-project wins) + ~/.gsd/defaults.json (global fallback), same probe pattern as readGsdRuntimeProfileResolver - Add resolveInstallTimeEffort(effortCfg, agentName): pure function matching resolveEffortInternal() precedence (agent_overrides > routing_tier_defaults > default > 'high') without loadConfig side-effects (no sub-repo detection, no migration writes) - Claude agent copy loop: inject `effort: <value>` into frontmatter ONLY for runtime === 'claude'; all other .md runtimes (Gemini, Qwen, Hermes, etc.) stay effort-free (Gemini-safe source contract preserved in agents/*.md) - generateCodexAgentToml: add effortCfg param; emit model_reasoning_effort from unified resolver (replaces old catalog entry.reasoning_effort); Codex clamps max → xhigh via renderEffortForRuntime('codex', ...) - installCodexConfig: pass readGsdEffectiveEffortConfig(targetDir) to generateCodexAgentToml so per-project config wins for Codex .toml too - Update failing tests to GREEN: 12/12 pass; all 17 install tests pass; 2847/2848 unit tests pass (1 pre-existing failure: policy-shell-pinning) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(#443): source install effort defaults from manifest (kill drift) + guard test Replace hardcoded _GSD_EFFORT_MANIFEST_TIER_DEFAULTS and the 'high' fallback in resolveInstallTimeEffort with values read from config-defaults.manifest.json at module init, using the same __dirname-relative path install.js already uses for all shared manifests. Add feat-443-effort-defaults-drift.test.cjs to assert equality between install.js's runtime constants and the manifest on every CI run. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#443): reconcile Codex TOML tests with unified effort design The #443 unified effort resolver makes generateCodexAgentToml always emit model_reasoning_effort (driven by resolveInstallTimeEffort, not model_profile_overrides). The test 'generated TOML omits reasoning_effort when runtime has none' had an obsolete premise — model_profile_overrides.reasoning_effort:'' no longer suppresses unified effort. Convert it to assert the new invariant: Codex TOML always carries a valid model_reasoning_effort from the agent's routing tier (xhigh for gsd-planner, a heavy-tier agent), while model_profile_overrides model override is still respected. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#443): make install.js effort resolution lazy (no load-time side effects breaking launcher-parity) Replace module-load-time IIFE + hard throw (config-defaults.manifest.json read) and top-level require of model-catalog.cjs with a lazy _getGsdEffortCatalog() getter that initialises on first call from resolveInstallTimeEffort / generateCodexAgentToml / Claude .md effort injection. Requiring install.js in unrelated test contexts (e.g. runtime-launcher-parity) no longer triggers manifest IO or throws, eliminating the load-time side effect that changed subprocess exit codes / stderr on the bench. Drift-guard exports (_GSD_EFFORT_MANIFEST_TIER_DEFAULTS / _GSD_EFFORT_MANIFEST_DEFAULT) preserved as lazy getter properties on module.exports so feat-443-effort-defaults-drift still validates them without forcing eager load. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#443): isolate install-wiring test HOME to stop \$HOME/.claude pollution breaking launcher-parity runGlobalInstall() now redirects HOME to a per-call isolated tmpdir in addition to the existing runtime-specific env-var redirects (CLAUDE_CONFIG_DIR, GEMINI_CONFIG_DIR, CODEX_HOME). This ensures install.js code that uses os.homedir() directly — including the ~/.cache/gsd update-check deletion, ~/.gsd/defaults.json reads, and any HOME-relative npm subprocess writes — never touches the real \$HOME during the test. Without the HOME isolation the install test (which is new to this branch and is now picked up by Docker's raw \`tests/*.test.cjs\` glob) could write or delete files under the real \$HOME, causing runtime-launcher-parity test (D) to fail: (D) asserts a loud non-zero exit when \$RUNTIME_DIR/gsd-tools.cjs is absent and gsd-tools is not on PATH, but the launcher's \$HOME/.claude fallback arm succeeds if \$HOME/.claude/get-shit-done/bin/gsd-tools.cjs exists. Also sets GSD_SKIP_STALE_SDK_CHECK=1 to suppress the \`npm ls -g\` subprocess that the global installer spawns — irrelevant to effort-wiring assertions, slow, and potentially writes to ~/.npm cache. All 12 feat-443 install-wiring assertions preserved. Drift-guard 5/5. Unit suite 2848/2850 (pre-existing policy-shell-pinning.test.cjs failure on next). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(#443): add changeset fragment for effort + fast-mode routing Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(#443): set GSD_TEST_MODE before requiring install.js in drift-guard test to prevent HOME leak Without GSD_TEST_MODE=1, require('bin/install.js') runs the module's main install block (guarded by !GSD_TEST_MODE), performing a real global Claude install into $HOME/.claude/. On CI ubuntu where node is on standard PATH, the launcher's $HOME/.claude fallback arm then finds gsd-tools.cjs, causing runtime-launcher-parity test (D) to exit zero when it must exit non-zero. Root cause: feat-443-effort-defaults-drift.test.cjs (unit suite) runs alphabetically before runtime-launcher-parity.test.cjs in the same node --test invocation. Each runs in a separate worker process but shares the same HOME. The drift test's install leaks gsd-tools.cjs into that HOME, then the launcher test's bash subprocess finds it via the $HOME/.claude arm. Fix: add process.env.GSD_TEST_MODE = '1' at the top of the drift-guard test, before the require(installPath) call. This matches the pattern used by feat-443-effort-fast-mode.test.cjs and feat-443-effort-install-wiring .install.test.cjs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#443): deterministic resolve-execution arg parsing + validate install-time effort (Codex adversarial findings) Finding 1: resolve-execution --effort low gsd-planner misrouted 'low' as the agent. Replace find(non-dash) with a proper flag-consuming loop that collects a single positional; validate missing/extra positionals and malformed --attempt values. Finding 2: resolveInstallTimeEffort returned unvalidated effort strings (e.g. "ultra") verbatim. Each precedence layer now checks GSD_EFFORT_SET (imported once from core.cjs) before accepting a value, mirroring resolveEffortInternal exactly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#443): newline-agnostic effort frontmatter injection (Windows CRLF) + CRLF-safe assertions Extracts injectEffortFrontmatter(content, effortValue) pure helper that detects EOL (LF vs CRLF) from the opening '---' line and inserts 'effort: <value>' before the closing '---' delimiter using the same EOL as the surrounding frontmatter. Regex now uses /^---\r?\n([\s\S]*?)^---\r?$/m instead of the LF-only /^(---\n[\s\S]*?)(---)(\n|$)/ that silently skipped CRLF files on Windows (git core.autocrlf=true checkout). Also adds 7 unit tests covering LF, CRLF, idempotency, no-frontmatter, and complex frontmatter cases. Exports injectEffortFrontmatter from module.exports. Fixes 6 CI failures in tests/feat-443-effort-install-wiring.install.test.cjs on windows-latest runners (lines 138, 145, 152, 261, 345, 356). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: CI Rebase Check <ci@gsd-redux> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
48b1e35187 |
fix(#431): enforce H1 shell policy (linux=bash, macOS=zsh, windows=pwsh) across PR + release gates (#434)
* test(#431): policy-shell-pinning linter — RED baseline (37 violations on origin/next) Adds scripts/workflow-policy.cjs: H1 shell-policy linter with POLICY map, VIOLATION enum, matrix expansion, effective-shell resolution order, and runPolicyLint({ workflowsDir }) entry point. Adds tests/policy-shell-pinning.test.cjs: 8 tests (baseline + 6 synthetic counter-tests). Synthetic tests 2–7 pass; baseline test is intentionally RED (37 violations: 28 in test.yml, 9 in install-smoke.yml — all macos/windows lanes using shell: bash instead of native zsh/pwsh). Adds js-yaml@4.1.1 as devDependency for YAML parsing. * fix(#431): switch ubuntu/windows lanes to native shells; extract bash-isms to Node Remove all explicit shell: bash pins from ubuntu-only jobs (changes, lint-tests, coverage, required-tests, smoke-unpacked) — ubuntu runner default is bash, which is both H1-compliant and the runner default, making the pin redundant. For the test and test-full mixed-OS jobs (ubuntu+windows, windows+macos): - Move bash-ism steps to shell-agnostic Node scripts: scripts/ci-guard-runner.cjs — RUNNER_ENVIRONMENT check scripts/ci-rebase-check.cjs — git fetch+merge PR base branch scripts/check-npm-integrity.cjs — Node port of check-npm-integrity.sh scripts/ci-prepare-test-scope.cjs — write .ci-selected-tests.txt scripts/ci-smoke-skip.cjs — set skip= output for full-only matrix entries - Remove shell: bash from simple npm/node command steps (runner default applies) This brings Windows violations from 19 to 0. Remaining 17 violations are all MACOS_MISSING_EXPLICIT_ZSH in mixed-OS matrix jobs (test-full: windows+macos, install-smoke smoke: ubuntu+macos) — these require job splitting to fix; see BLOCKER in PR description. * fix(#431): update workflow-shell-pinning test for H1 policy The old test required all Windows-targeting npm steps to pin shell: bash (to prevent pwsh stderr-swallow). Under H1, Windows runners must use pwsh (native, no pin needed) — shell: bash on Windows is now the violation, not the fix. Update findViolations() to flag npm steps with effectiveShell === 'bash' (rather than effectiveShell === null). Update synthetic tests to verify the H1-inverted semantics: defaults.run.shell: bash on Windows is now 2 violations, not 0. Update test name and assertion messages to describe the H1 constraint rather than the old missing-pin constraint. * fix(#431): extend policy linter to resolve matrix.shell expressions - expandRunsOn now captures all matrix.include row keys as realization context (os, node-version, shell, full_only, etc.) instead of only os - effectiveShell now accepts a realizationContext and resolves ${{ matrix.<key> }} expressions against it before checking policy - Unresolvable matrix key in shell expression emits UNRESOLVABLE_MATRIX - Add 3 new tests: positive (zsh+pwsh per row → 0 violations), counter (bash in macOS row → WRONG_SHELL_FOR_OS), counter (missing shell key → UNRESOLVABLE_MATRIX) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#431): apply matrix.shell pattern to test-full and smoke jobs (clears BLOCKER) test-full job (test.yml): - Add shell: pwsh/zsh per matrix.include row (windows-latest→pwsh, macos-latest→zsh) - Add job-level defaults.run.shell: ${{ matrix.shell }} - No step-level shell pins existed to remove smoke job (install-smoke.yml): - Add shell: bash/zsh per matrix.include row (ubuntu→bash, macos→zsh) - Add job-level defaults.run.shell: ${{ matrix.shell }} - No step-level shell pins existed to remove Policy linter now reports 0 violations across all workflow files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(#431): migrate .sh check scripts to .cjs; remove .sh originals - Add scripts/check-env.cjs: Node.js port of check-env.sh with identical exit codes (0/1/2), human-readable and --json output, --help flag, and all 5 checks (node-version, npm-version, lockfile-present, lockfile-sync, version-manager-pin) - Migrate all callers: - package.json check:env → node scripts/check-env.cjs - package.json check:integrity → node scripts/check-npm-integrity.cjs - scripts/ci-test-scope.cjs path strings → .cjs equivalents - .github/workflows/release.yml rc+finalize jobs → node .cjs (drop chmod+x) - .github/workflows/security-scan.yml → node .cjs (drop chmod+x) - tests/check-env.test.cjs → spawn node process.execPath [.cjs] - tests/npm-integrity-gate.test.cjs → spawn node process.execPath [.cjs] - Delete scripts/check-env.sh and scripts/check-npm-integrity.sh Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor(#431): update doc references from .sh to .cjs Update SECURITY.md and docs/contributing/bootstrap.md to reference the canonical Node invocation instead of the removed bash scripts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#431): use per-step shell:matrix.shell instead of defaults.run.shell (GHA compat) GHA does not reliably resolve matrix expressions inside defaults.run.shell. Per-step shell: always resolves correctly. Removed the defaults.run.shell block from the test-full job (test.yml) and the smoke job (install-smoke.yml), and added shell: \${{ matrix.shell }} directly on every run: step in both jobs. Codex finding: defaults.run.shell with matrix expressions is not a GHA-supported pattern; per-step shell: is the safe form. * fix(#431): policy linter validates every matrix.include row independently Removed runner-label-only dedup from expandRunsOn() in workflow-policy.cjs. The prior guard (if !realizations.find(r => r.runner === runner)) collapsed two macos-latest rows with different node-version/shell contexts into one, hiding the second row's policy violation. Each matrix.include row is a distinct CI realization with its own context; validating it twice is harmless but skipping it causes false negatives. Added counter-test (Test 8) in tests/policy-shell-pinning.test.cjs: two macos-latest rows (shell:zsh compliant + shell:bash violation) must produce exactly one WRONG_SHELL_FOR_OS violation on the second row. * fix(#431): remove dedup-by-runner in Cartesian matrix.<key> expansion (Codex round 3) The base-list path in expandRunsOn (matrix.<key> arrays, e.g. matrix.os) previously guarded each push with `if (!realizations.find(r => r.runner === runner))`, collapsing duplicate runner values into a single realization and hiding policy violations on later rows of a Cartesian matrix. Remove the guard unconditionally; each entry in the base-list array now produces its own realization, matching the same fix already applied to the matrix.include path. Add counter-test "Cartesian matrix os × shell — dedup must not collapse rows by runner alone": matrix.os: [macos-latest, macos-latest] + shell: ${{ matrix.shell }} now yields 2 realizations (not 1). Documents that Cartesian cross-product expansion (carrying all keys into realization context) is a separate follow-up; current violations are UNRESOLVABLE_MATRIX pending that work. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#431): remove 60s timeout regression on npm ci --dry-run (parity with check-env.sh) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#431): ci-rebase-check.cjs — return truthy sentinel on success (Codex round 4) run() used execFileSync with stdio:'inherit', which returns null on success. Caller checked `result !== null`, always false → every successful fetch fell through to "failed after 3 attempts" exit-1 path. Fix: run() now returns true on success, false on failure. Update caller from `result !== null` to `if (result)`. Adds tests/ci-rebase-check.test.cjs (5 tests) covering the sentinel contract and a local-bare-remote integration smoke that verifies the full fetch+merge path exits 0 when fetch succeeds. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: CI Rebase Check <ci@gsd-redux> |
||
|
|
1067a0f3fd | docs(#415): ADR — prevent stale-base reintroduction of retired runtime tokens (#417) | ||
|
|
9dd2c87c6c |
ci: supersede #367 with combined tiered PR pipeline redesign (#369)
* ci: streamline PR pipeline gates * test: annotate ci-test-scope stderr assertions for lint rule --------- Co-authored-by: Colin <colin@solvely.net> |
||
|
|
47bba87d90 |
fix: restore sdk query families in gsd-tools (#353)
* fix: restore sdk query families in gsd-tools * chore: add changeset * docs: sync query router inventory |
||
|
|
1b16c60df9 | ci(#365): run affected tests for pull request CI lanes (#366) | ||
|
|
660670ef57 | fix(#343): remove legacy security contacts and org references (#351) | ||
|
|
b99dd64e02 |
fix(#341): restore next-based test gate regressions (#342)
* fix: use active-workstream resolver exported by store module * fix: wire verify codebase-drift alias and sync inventory docs * chore: add changeset for next gate regression fixes * fix: normalize changeset fragment metadata for docs-lint |
||
|
|
b64ffc12ed | docs(#196): remove sdk references from localized docs | ||
|
|
e8fc50034d | docs(#194): remove sdk programmatic docs and bridge guidance | ||
|
|
4fa13cf9de | refactor(#190): collapse SDK sync bridge and remove synckit seam | ||
|
|
bac141b120 | docs: sync inventory and handsync allowlist after #189 | ||
|
|
dc4b90ae4b |
docs(#15): ADR for cross-AI convergence flags in existing orchestration (#242)
* docs(#15): propose convergence flag naming and doc-only test-gate exception * docs(#15): define convergence config and allowed AI selection |
||
|
|
22e9c1de62 | refactor(#181): migrate workstream inventory builder to sdk/src/workstream (#250) | ||
|
|
59bcdf03b6 |
refactor(#180): migrate STATE.md Document Module to sdk/src/state (#249)
* refactor(#180): migrate state document module to sdk/src/state * test(#180): ratchet lint allowlists for state module relocation |
||
|
|
9aae41f22d |
refactor(#179): migrate Configuration Module to sdk/src/config (#244)
* refactor(#179): migrate configuration module to sdk/src/config * chore(#179): add changeset for config module path migration |
||
|
|
5434c8c4cb | docs: update inventory surfaces for semver compare module | ||
|
|
1bc7d61294 |
chore: introduce next integration branch (Phase 1 — additive) (#231)
Adds: - docs/branching.md — beginner contributor guide - docs/adr/XXXX-...md — ADR (will be renamed with issue#) - .github/workflows/auto-backmerge.yml — disabled in Phase 1 - .github/workflows/pr-target-validator.yml — warn-only in Phase 1 - scripts/setup-branch-protection.sh — idempotent gh api script Modifies: - .github/workflows/branch-naming.yml — recognize 'next' - CONTRIBUTING.md — 'Where Do I Open My PR?' section Phase 1 is additive: nothing operational changes until Phase 2 flips auto-backmerge.yml's if:false→true, flips pr-target-validator.yml's WARN_ONLY→false, creates the next branch, and switches the default branch. See the ADR for the migration plan. |
||
|
|
5f3eb42864 |
feat(observability): propagate parentTraceId on DispatchEvent — ADR-0174 SDK retirement Phase 1.4 (#178) (#225)
* test(#178): update DispatchEvent factory tests to propagate parentTraceId P1.3 test 'parentTraceId is always undefined' replaced with four P1.4 contracts: absent → undefined, string → propagated, null → undefined, non-string → undefined (defensive normalization policy). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(#178): propagate parentTraceId through DispatchEvent factory Stop ignoring the parentTraceId parameter added as a forward-compat hook in P1.3. Defensive normalization: only non-null strings are propagated; null, non-string values, and absent callers all yield undefined, keeping P1.3 behavior intact for all existing dispatch call sites. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(#178): add Hub-level parentTraceId propagation tests Four new assertions: req.parentTraceId propagates to event, absent → undefined (P1.3 regression), shared parentTraceId across multiple dispatches, and unique traceId invariant despite shared parentTraceId. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(#178): plumb parentTraceId through Hub dispatch and _notifyLogger dispatch() now reads req.parentTraceId and passes it to _notifyLogger, which forwards it to makeDispatchEvent. Backward-compatible: callers that omit parentTraceId emit events with parentTraceId: undefined, identical to P1.3 behavior. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(#178): add trace correlation end-to-end test Dispatches a root command then 3 children with parentTraceId=rootTraceId. Reads the real .gsd-trace.jsonl audit file and verifies: 4 events total, root has no parentTraceId, all children carry rootTraceId, all traceIds unique, JS filter returns exactly the 3 children given the root's traceId. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(#178): document traceId/parentTraceId in audit file Update Observability section to note that audit events now carry both traceId and parentTraceId, and explain the correlation filter pattern. Note that leaf dispatches emit parentTraceId: undefined until the Phase 2 composer wires it automatically. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(#178): add changeset for trace correlation seam Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(#178): cover invalid parentTraceId values in DispatchEvent factory Adds 9 new test cases for UUID v4 validation of parentTraceId: empty string, whitespace, non-UUID, oversized, UUID v1, missing-hyphen, extra-char (all dropped to undefined), plus UPPERCASE and lowercase v4 (both propagated). Tests are intentionally red until the implementation commit that follows. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(#178): validate parentTraceId against UUID v4 before propagation Adds UUID_V4_REGEX constant and isValidParentTraceId() helper to event.cjs. makeDispatchEvent now silently coerces any parentTraceId that fails the UUID v4 check (wrong version nibble, wrong variant, missing hyphens, oversized, empty, etc.) to undefined. No stderr warn is emitted — the factory remains pure and side-effect-free. Closes the correlation- poisoning vector identified in the Codex adversarial review of PR #225. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(#178): assert Hub silently drops invalid parentTraceId at the seam Adds two tests to hub-logger-integration.test.cjs: 1. dispatch with 'junk' parentTraceId emits event with parentTraceId===undefined. 2. The logger-failure warn path is NOT triggered — the factory coerces the bad value before onEvent is called, confirmed by zero stderr output even when a logger that would throw on non-undefined parentTraceId is installed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(#178): assert invalid parentTraceId does not poison correlation siblings Adds one test to trace-correlation.test.cjs: dispatches a root, a valid child (parentTraceId = rootTraceId), and an invalid child (parentTraceId = 'junk'). Asserts: valid child carries correct parentTraceId, invalid child has parentTraceId dropped to undefined, filtering by rootTraceId yields exactly 1 event (the valid child only), and all 3 events have unique traceIds. Uses an isolated Hub + tmpdir to avoid shared fixture interference. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(#178): document UUID v4 contract for parentTraceId Appends one sentence to the Observability audit-trail paragraph in CONFIGURATION.md: parentTraceId must be canonical UUID v4 (RFC 4122); values that don't match are silently dropped from audit output. No section restructuring — single sentence addition only. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
7c539cb86a |
docs(227): ADR on input-validation checking semantic shape, not just type (#228)
* docs(227): create ADR for input-validation-shape-not-just-type Captures the architectural standard that defensive normalization at trust boundaries must validate both type and semantic shape, with silent coercion on failure. Concrete cases: parentTraceId UUID v4 fix in PR #225 and release-version validation in ADR 218. Closes #227 * docs(227): cross-reference new ADR from ADR 218 Appends a "See also" section at the end of ADR 218 pointing forward to ADR 227, which generalises the type+semantic-shape validation principle documented in ADR 218's narrower release-workflow context. * docs(227): add CONTRIBUTING pointer to new ADR Adds a "Code Review Lessons → Input validation" section after the Reviewer Standards block, linking to ADR 227 as the citable reference for the type+semantic-shape validation standard. |
||
|
|
2d14eb8873 |
feat(observability): add DispatchLogger seam — ADR-0174 SDK retirement Phase 1.3 (#177) (#223)
* test(#177): add DispatchEvent factory failing tests Red tests for makeDispatchEvent shape, traceId UUID v4, uniqueness, parentTraceId-always-undefined (P1.3), args redaction toggle, ISO 8601 timestamp, and all result variant passthrough. * feat(#177): introduce DispatchEvent factory makeDispatchEvent produces an immutable event record per dispatch: - traceId: crypto.randomUUID() (UUID v4) - parentTraceId: always undefined (P1.4 wires composer) - command, result, timestamp (ISO 8601) - args only included when includeArgs === true (default: omitted) * test(#177): add arg redaction policy failing tests Red tests for shouldIncludeArgs (GSD_AUDIT_ARGS env gating) and redactEvent (strips args from frozen events, preserves all other fields, returns a new object, never mutates the source). * feat(#177): introduce arg redaction policy shouldIncludeArgs(): only GSD_AUDIT_ARGS==='1' opts in; all other values (unset, '', '0', 'true') default to omitting args. redactEvent(event): returns a shallow copy of the event, dropping the args field unless opted in. Never mutates the (frozen) source event. * test(#177): add DispatchLogger interface failing tests Red tests covering: - no-op logger: silent on all events, never throws - default logger: silent on ok, one flattened JSON line to stderr on error - default logger: audit file creation + append-only + redaction + config gate - GSD_AUDIT env var and config.audit.enabled config gate - GSD_AUDIT_ARGS opt-in for args inclusion All tests use real fs under os.tmpdir() — no mocked appendFileSync. * feat(#177): introduce DispatchLogger with default and no-op implementations createNoOpLogger(): silent on all events — Hub default when no logger injected. createDefaultLogger({ cwd, config }): - Silent on ok result - Flattened JSON line to stderr on error: { kind, traceId, ...typedPayload } - Append-only audit at .planning/.gsd-trace.jsonl when GSD_AUDIT=1 or config.audit.enabled - Args redacted by default; GSD_AUDIT_ARGS=1 opts in - Logger errors caught internally; never break dispatch callers * test(#177): add Hub+logger integration failing tests Red tests verifying: - onEvent called exactly once per dispatch (ok, error, handler-throw, unknown) - DispatchEvent shape: traceId uniqueness, command, result.kind, parentTraceId - Logger errors contained (dispatch still returns Result, warn line to stderr) - Hub defaults to no-op when no logger injected - End-to-end with createDefaultLogger: silent on success, stderr on error, audit file * feat(#177): wire DispatchLogger into CommandRoutingHub Add optional logger param to createHub({ ..., logger }). Defaults to createNoOpLogger() — silent, no behaviour change for callers that don't inject a logger. After every dispatch (success and error): - Normalises HubResult { ok } to DispatchEvent { kind: 'ok'|error-kind } - Calls makeDispatchEvent({ command, args, result }) to mint the event - Calls logger.onEvent(event) exactly once - Wraps in try/catch: logger errors emit { level:'warn', source:'DispatchLogger' } to stderr but never propagate to dispatch callers * chore(#177): gitignore .planning/.gsd-trace.jsonl audit file The audit trail is local-only, append-only, and must never be committed. Slotted under the existing "Local scratch + Claude-test artifacts" block. * docs(#177): document GSD_AUDIT, GSD_AUDIT_ARGS, config.audit.enabled New ## Observability section at end of CONFIGURATION.md covering: - Default silent/stderr behaviour overview - Stderr error JSON format - Audit file opt-in (env var and config key) - Args redaction policy and GSD_AUDIT_ARGS opt-in Also slots GSD_AUDIT and GSD_AUDIT_ARGS into the existing ## Environment Variables table (alphabetical order). * chore(#177): add changeset for observability seam type: Added — new DispatchLogger seam with default silent/stderr/audit behaviour. |
||
|
|
5b3646d6c8 |
fix(#213): support antigravity 2.x config directory split (#217)
* fix(#213): support antigravity 2.x config directory split * fix(#213): harden antigravity tests for windows parity |
||
|
|
6fc46db49a |
fix(release): reject leading-zero versions and pre-check npm before publish (#219)
* fix(release): reject leading-zero versions and pre-check npm before publish The validate-version job used ^[0-9]+\.[0-9]+\.0$ which accepted leading zeros (e.g. 1.01.0). npm version silently normalises such inputs to their canonical semver form (1.1.0), creating divergent state across npm, git tags, GitHub releases, and release branches — leaving orphaned artefacts that require manual surgery to clean up. Two changes to the validate-version job only: 1. Replace the format regex with ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.0$ so any segment with a leading zero is rejected in under 5 seconds with an error message that includes the offending value. 2. Add a "Reject already-published versions" step that calls `npm view $pkg@$VERSION` for both packages before any branch, install, or build work begins. Duplicate-version requests now fail fast instead of burning ~10 minutes before dying at the dry-run publish step. Adds ADR-0175 documenting the incident, the decisions, and the recovery runbook for the orphaned v1.01.0 / v1.03.0 artefacts. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(adr): rename ADR to issue-number format per CONTRIBUTING.md policy Renames docs/adr/0175-release-version-validation.md to docs/adr/218-release-version-validation.md to match the issue-number prefix convention required by CONTRIBUTING.md (section: Proposing an ADR or PRD). Issue #218 was opened to track this CI hardening work. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
4a03ada279 | docs(#209): refresh README continuity and audit messaging (#210) | ||
|
|
6e31630f2a |
docs(adr): ADR-0174 — retire @opengsd/gsd-sdk package boundary (#198)
* docs(adr): retire @opengsd/gsd-sdk package boundary Authors ADR-XXXX (Single-runtime collapse onto src/ TypeScript) and marks ADR-0005, 0007, 0012, 3524 as Superseded. The dual-runtime SDK design accumulated ~120 files of scaffolding (worker pool, generators, parity tests, transition shims, two release pipelines) for a feature set CJS provides in-process. This ADR records the decision to collapse onto a single TS source tree in src/ within get-shit-done-cc. Implementation tracked separately in the umbrella tracking issue and per-phase sub-issues (referenced in the PR body). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(adr): assign ADR-0174 number and finalize supersedes references Replaces XXXX placeholder with real ADR number (0174 = umbrella tracking issue #174 per project convention, zero-padded to 4 digits). Updates Status lines in ADR-0005, ADR-0007, ADR-0012, ADR-3524 to reference ADR-0174. Adds README.md index entry for ADR-0174 and marks the four superseded ADRs accordingly. Refs #174. --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
6177e3a5f5 |
fix(4): retire cooperating-sibling for phase.*, introduce generator + I/O adapter, fix cmdPhaseComplete (#154)
* test(4): reproduce non-idempotent phase complete + unclamped percent in CJS CLI RED regression tests for issue #4: - T1: double invocation of cmdPhaseComplete double-increments **Completed Phases:** in STATE.md body (blind parseInt+1 instead of deriving from ROADMAP) - T2: progress percent can exceed 100% when Completed Phases > Total Phases The CJS path (bin/lib/phase.cjs:cmdPhaseComplete) has the bug; the SDK path (phase-lifecycle.ts:phaseComplete, fixed in ~PR#3520) already derives completed_phases from ROADMAP Complete-row count, making it idempotent. References: - Issue #4 (open-gsd/get-shit-done-redux) - ADR-3524 (docs/adr/3524-cjs-sdk-hard-seam.md) - /tmp/adr-3524-review-findings.md (architectural justification) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(4): add sdk/scripts/gen-phase-lifecycle-policy.mjs generator + freshness check placeholder Generates phase-lifecycle-policy.generated.cjs from sdk/src/query/phase-lifecycle-policy.ts. All functions in phase-lifecycle-policy.ts are pure transforms (no I/O), directly serializable via Function.prototype.toString(). The GSDError dependency is replaced with a lightweight stub that throws plain Error objects — CJS callers that need process.exit(1) behavior catch these and delegate to error(). This is the "I/O adapter pattern" from ADR-3524 Section 4 applied to pure helpers. References: - ADR-3524 (docs/adr/3524-cjs-sdk-hard-seam.md) - /tmp/adr-3524-review-findings.md (architectural justification) - Issue #4 (open-gsd/get-shit-done-redux) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(4): add sdk/scripts/gen-phase.mjs generator Generates phase.generated.cjs from sdk/src/query/phase.ts. Only pure helpers (isCanonicalPlanFile, describeNonCanonicalPlans) are generated; async query handlers (findPhase, phasePlanIndex) are I/O-bound and remain per-side per ADR-3524 Section 4. References: - ADR-3524 (docs/adr/3524-cjs-sdk-hard-seam.md) - /tmp/adr-3524-review-findings.md (architectural justification) - Issue #4 (open-gsd/get-shit-done-redux) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(4): add sdk/scripts/gen-phase-lifecycle.mjs + core idempotency fix logic Generates phase-lifecycle.generated.cjs providing two pure functions that are the root-cause fix for issue #4: 1. deriveProgressFromRoadmap(roadmapContent): counts Complete rows in ROADMAP progress table — makes completed_phases idempotent (derived from ground truth instead of blind +1). Direct transcription of the SDK's "Root cause 1 fix" block in phase-lifecycle.ts (~line 1644). 2. clampPercent(completed, total): percent capped at 100 — prevents >100% progress when Completed Phases exceeds Total Phases. Design note: the full phase lifecycle mutations (add, insert, remove, complete) are inherently async and I/O-bound. Per ADR-3524 Section 4 ("I/O stays per-side"), those are NOT generated. Only the pure-computation kernel is extracted, following the I/O adapter pattern: pure logic shared; each side (CJS sync, SDK async) supplies its own I/O adapter. The pure functions are defined in the generator as real JS functions and serialized via Function.prototype.toString() — same technique as gen-project-root.mjs — rather than embedded in template literals (which would require double-escaping all regex backslashes). References: - ADR-3524 (docs/adr/3524-cjs-sdk-hard-seam.md) - /tmp/adr-3524-review-findings.md (architectural justification) - Issue #4 (open-gsd/get-shit-done-redux) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(4): emit phase.generated.cjs, phase-lifecycle.generated.cjs, phase-lifecycle-policy.generated.cjs Three generated CJS artifacts from their respective generator scripts: - phase.generated.cjs (1.7K): isCanonicalPlanFile + describeNonCanonicalPlans from sdk/src/query/phase.ts - phase-lifecycle.generated.cjs (3.6K): deriveProgressFromRoadmap + clampPercent — the idempotency+clamp fix for issue #4 - phase-lifecycle-policy.generated.cjs (7.0K): 14 pure phase naming/directory helpers from sdk/src/query/phase-lifecycle-policy.ts Run to regenerate: node sdk/scripts/gen-phase.mjs node sdk/scripts/gen-phase-lifecycle.mjs node sdk/scripts/gen-phase-lifecycle-policy.mjs References: - ADR-3524 (docs/adr/3524-cjs-sdk-hard-seam.md) - Issue #4 (open-gsd/get-shit-done-redux) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(4): migrate bin/lib/phase.cjs cmdPhaseComplete to use generated helpers Replace the blind-increment + unclamped percent bug in cmdPhaseComplete with the idempotent ROADMAP-derived approach: read freshly-updated ROADMAP, call deriveProgressFromRoadmap() from phase-lifecycle.generated.cjs, fall back to existing value when ROADMAP is unavailable. clampPercent() prevents >100%. Root cause fix for issue #4: the original parseInt(completedRaw) + 1 on every call made phase complete non-idempotent; the missing Math.min(100, ...) clamp allowed Progress to exceed 100%. I/O adapter pattern (ADR-3524 §4): pure computation in generated module; CJS supplies sync readFileSync; SDK supplies async readFile. Same logic, two adapters. Closes: Tests in 4-phase-complete-cjs-regression.test.cjs go GREEN. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(4): add freshness checks + npm scripts for phase generated artifacts (D4/D6) Add check-phase-fresh.mjs, check-phase-lifecycle-fresh.mjs, and check-phase-lifecycle-policy-fresh.mjs (same pattern as check-project-root-fresh.mjs: import buildXCjs() from the generator, regenerate in-memory, byte-compare to committed file, exit 1 if stale). Add gen:phase, check:phase-fresh, gen:phase-lifecycle, check:phase-lifecycle-fresh, gen:phase-lifecycle-policy, check:phase-lifecycle-policy-fresh to sdk/package.json. Note: gen:phase-lifecycle / check:phase-lifecycle-fresh do not require 'npm run build' because the generator defines pure functions directly rather than importing dist. Update shared-module-handsync-allowlist.json: reclassify phase.cjs justification to reflect that it now consumes phase-lifecycle.generated.cjs for cmdPhaseComplete. The *.generated.cjs files are excluded by the lint scanner (excludes *.generated.cjs) so no new allowlist entries are required for the generated artifacts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ci(4): add freshness-check CI steps for phase, phase-lifecycle, phase-lifecycle-policy Add three drift-check steps to .github/workflows/test.yml following the same pattern as the existing freshness checks (ubuntu-latest + node 24 only): - SDK generated phase artifact drift check - SDK generated phase-lifecycle artifact drift check - SDK generated phase-lifecycle-policy artifact drift check These guard against editors modifying the generated *.cjs files directly. They run check-phase-fresh.mjs, check-phase-lifecycle-fresh.mjs, and check-phase-lifecycle-policy-fresh.mjs respectively (added in D4). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(4): amend ADR-3524 — phase * I/O adapter pattern for issue #4 (D8) Append a 2026-05-23 amendment to docs/adr/3524-cjs-sdk-hard-seam.md documenting the Phase * cooperating-sibling retirement: three new generator scripts extract pure-computation helpers from phase.ts / phase-lifecycle.ts / phase-lifecycle-policy.ts, cmdPhaseComplete migrates to deriveProgressFromRoadmap + clampPercent for idempotency, freshness checks + CI steps added. Clarifies what is NOT generated (async I/O-bound mutation handlers stay per-side per Section 4) and notes open drift bugs #6 and #26 for traceability. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(4): add changeset fragment for cmdPhaseComplete fix Refs #4 * fix(154): use canonical /gsd:plan-phase form in phase-lifecycle-policy.ts Replaces the retired /gsd-plan-phase slash command reference with the canonical colon-namespaced /gsd:plan-phase in the TS source template string that feeds the generated CJS roadmap entry helper. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(154): regenerate phase-lifecycle-policy.generated.cjs after slash-namespace fix Regenerated via node sdk/scripts/gen-phase-lifecycle-policy.mjs after fixing /gsd-plan-phase → /gsd:plan-phase in the TS source. Generated file now contains the canonical colon form. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(154): cross-platform frontmatter regex anchor in 4-phase-complete-cjs-regression.test.cjs Replaces /^---\n/ with /^---\r?\n/ so the frontmatter extraction helper in the regression test tolerates Windows CRLF line endings (autocrlf=true checkout leaves \r before \n, causing /^---\n/ to never match). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(154): add new generated CJS modules to INVENTORY.md and regenerate manifest Adds three missing rows to the CLI Modules table: - phase-lifecycle-policy.generated.cjs - phase-lifecycle.generated.cjs - phase.generated.cjs Bumps the headline count from 74 to 77 to match the filesystem. Also regenerates docs/INVENTORY-MANIFEST.json via node scripts/gen-inventory-manifest.cjs --write. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(154): regenerate phase-lifecycle-policy.generated.cjs with hyphen form Root cause: commit 6cd701f4 regenerated the CJS artifact but at that point sdk/dist/query/phase-lifecycle-policy.js already had the correct /gsd-plan-phase (hyphen) form while sdk/src/query/phase-lifecycle-policy.ts still had /gsd:plan-phase (colon). The generator uses Function.prototype.toString() on the compiled dist, so the CJS picked up the wrong string from the stale TS source that was compiled into dist at some earlier point. Fix: correct the TS source to /gsd-plan-phase and re-run gen-phase-lifecycle-policy.mjs so that buildPhaseRoadmapEntry in the CJS emits the hyphen form, satisfying the bug-3584-runtime-slash-emitters.test.cjs assertion at line 179. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(154): restore /gsd:plan-phase canonical form in phase-lifecycle-policy Commit 0c3a9c75 incorrectly reverted the slash-namespace fix by misreading sdk/dist/ (a build artifact in hyphen form for non-Claude runtimes) as the authoritative source. The canonical form for Claude-facing source is /gsd:plan-phase (colon-namespaced). Fix: revert TS source back to /gsd:plan-phase, rebuild dist, regenerate phase-lifecycle-policy.generated.cjs. Fixes bug-2543-gsd-slash-namespace test failure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(154): update INVENTORY.md CLI Modules count to 79 after rebase onto main Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(154): use hyphen form /gsd-plan-phase in persisted phase section template - sdk/src/query/phase-lifecycle-policy.ts: use /gsd-plan-phase (routable hyphen form) in the phase scaffold template that gets persisted to ROADMAP.md; bug-3584 requires persisted artifacts use the hyphen form - docs/INVENTORY.md: add missing runtime-name-policy.cjs row in CLI Modules table - tests/4-phase-complete-cjs-regression.test.cjs: add maxRetries/retryDelay to rmSync calls to satisfy Windows parity ratchet (baseline was 95) - Regenerate phase-lifecycle-policy.generated.cjs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
63396dbb16 |
enh(#142): centralize runtime alias canonicalization seam (#143)
* fix(#142): canonicalize runtime aliases across cjs and sdk * fix(#142): satisfy hand-sync and inventory parity gates * test(#1974): remove record-session lock contention in context monitor spec * test(config): retry transient config-ensure-section failures * docs(context): capture PR #143 CI reliability findings * fix(#142): bump CLI Modules inventory headline to 76 (runtime-name-policy + runtime-slash) docs/INVENTORY.md had the two new .cjs rows listed but the headline count stayed at 75; fs count is 76. inventory-counts.test.cjs caught the drift. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
33ffc647e2 |
feat(117): reproducible npm environment bootstrap + check-env validator (#136)
* test(117): add failing tests for env validator (check-env.sh)
RED phase. Six tests for scripts/check-env.sh — none pass because the
script does not exist yet. Fixtures:
good/ — engines.node >=22, .nvmrc 26, synced lockfile
bad-node-version/ — engines.node <14.0.0 (current Node v26 fails)
missing-lockfile/ — no package-lock.json
bad-nvmrc/ — .nvmrc says 22, current Node is v26
Tests cover:
1. Happy path exits 0
2. engines.node constraint failure exits 1
3. Missing lockfile exits 1
4. .nvmrc major mismatch exits 1
5. --json flag emits {pass: boolean, checks: array}
6. Integration smoke: exits 0 on live worktree root
Sources:
npm engines: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#engines
npm ci docs: https://docs.npmjs.com/cli/v10/commands/npm-ci
Closes #117
* feat(117): add scripts/check-env.sh with Node/npm/lockfile/version-manager checks
GREEN phase. Implements the five-check environment validator:
1. Node version vs engines.node (semver constraint — >=, >, <=, <, =)
2. npm version vs engines.npm (skipped if field absent)
3. package-lock.json presence
4. Lockfile sync via `npm ci --dry-run` (exits non-zero when drift detected)
5. Version-manager pin (.nvmrc / .node-version / .tool-versions) vs active Node major
Exit codes: 0 = all green; 1 = at least one failure; 2 = tool error.
Flags: --json (structured report), --help.
All 7 tests pass. shellcheck clean. bash -n syntax check clean.
Sources:
npm engines: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#engines
Reproducible builds: https://reproducible-builds.org/docs/source-tree/
npm ci docs: https://docs.npmjs.com/cli/v10/commands/npm-ci
Closes #117
* chore(117): pin Node engines + .nvmrc; add check:env npm script
- Add engines.npm: ">=10.0.0" (npm 10 ships with Node 22, the CI floor).
Source: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#engines
- Add .nvmrc pinning Node 22 (lowest supported version per CI matrix in
.github/workflows/test.yml; node-version: [22, 24]).
- Add "check:env": "./scripts/check-env.sh" script to package.json.
No generator is involved (not a .generated. file). The test update in this
commit adjusts the integration smoke: it now asserts on --json structured
output rather than raw text, and accepts exit 0 or 1 (version-manager pin
mismatch is expected when developer runs Node 26 against a .nvmrc of 22).
Closes #117
* ci(117): wire environment check into test workflow
Add "Environment check" step to .github/workflows/test.yml in the `test`
job. Positioned AFTER actions/setup-node and BEFORE npm ci so that env
mismatches (wrong Node version, missing npm version, absent lockfile) are
caught before the install step obscures the root cause.
Runs `npm run check:env` (./scripts/check-env.sh) on every matrix lane
(ubuntu, macos, windows) × (Node 22, 24).
Source: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#engines
Closes #117
* docs(117): publish docs/contributing/bootstrap.md + link from CONTRIBUTING.md
Adds docs/contributing/bootstrap.md with:
1. Prerequisites (nvm, fnm, asdf, mise; gh CLI)
2. One-time setup (clone, nvm use, check:env, npm ci)
3. Daily commands table
4. Validation guide (check table, exit codes, --json usage)
5. Troubleshooting (node-version, npm-version, lockfile-present,
lockfile-sync, version-manager-pin, missing modules, locale errors)
6. Alternative: Docker via gsd-test-runner
(https://github.com/open-gsd/gsd-test-runner)
Adds "Bootstrap your environment" section to CONTRIBUTING.md pointing to
the new doc. No content duplication — CONTRIBUTING.md links only.
Adds .changeset/117-npm-bootstrap.md (type: Added) for changelog.
Sources:
npm engines: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#engines
Reproducible builds: https://reproducible-builds.org/docs/source-tree/
npm ci docs: https://docs.npmjs.com/cli/v10/commands/npm-ci
gsd-test-runner: https://github.com/open-gsd/gsd-test-runner
Closes #117
* fix(#117): make check:env script run on Windows runners
Invoke check-env.sh via `bash` instead of a bare POSIX path so
Windows CI runners (which have Git Bash on PATH) execute the script
without requiring a POSIX shell shebang dispatcher.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(117): make check-env.sh fixture .nvmrc adapt to active Node major (cross-platform fix)
Before() hook writes good/.nvmrc = activeNodeMajor and bad-nvmrc/.nvmrc = activeNodeMajor+99
at test-run time. Hardcoded .nvmrc=26 failed on every CI matrix row except Node 26.
After() restores originals so the checked-in files stay stable.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(117): exempt gsd-test-runner URL path from slash-command registry check
docs/contributing/bootstrap.md links to https://github.com/open-gsd/gsd-test-runner.
The parity-test regex captures /gsd-test-runner from the URL path component and
flags it as an unregistered slash command. Add 'test-runner' to INTERNAL_COMPONENT_SLUGS
(mirrors the existing 'build' entry for GitHub org URLs) with an explanatory comment.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(117): fix Node-24 and Windows-22 CI failures in check-env
Two root causes:
1. version-manager-pin on Node 24 (mac/ubuntu/win):
The project root .nvmrc pins major 22 for local dev. When the CI
matrix runs Node 24, check-env.sh fails the version-manager-pin
check and exits 1, blocking the entire test job before any test
runs. Fix: skip the pin check when CI=true (GitHub Actions always
sets this). The pin is a local dev guard, not a gate for multi-
version matrix CI.
2. engines.node appears missing on Windows-22 (pkg_field backslash):
pkg_field() embedded PACKAGE_JSON directly into a node -e string
literal using require(). On Windows, the path uses backslashes
(D:\a\...) which are silently interpreted as JS escape sequences
inside the string, causing require() to fail silently (2>/dev/null
|| true). engines.node returns empty, triggering a spurious FAIL.
Fix: switch to fs.readFileSync + JSON.parse and normalise
backslashes to forward-slashes before embedding in the JS literal.
Also pass { CI: '' } from the bad-nvmrc unit test so the
version-manager-pin fixture test still exercises the mismatch path
even when running inside CI runners.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(117): use relative ./package.json path in pkg_field to fix Windows CI
On Windows, Git Bash exposes \$PWD as a POSIX path (/d/a/…) which
node.exe cannot resolve via fs.readFileSync. The previous fix embedded
the absolute PACKAGE_JSON path in the node -e string after converting
backslashes to forward-slashes, but the POSIX form produced by Git Bash
(/d/a/…) has no backslashes — so the conversion was a no-op and node
received an unresolvable path. The silent catch(e) { process.exit(0) }
swallowed the ENOENT, returning empty string for every engines.* field.
Fix: use './package.json' (relative to CWD). pkg_field() is always
called before any cd in the script so CWD === PROJECT_ROOT at call time.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
|
||
|
|
41210f014e |
fix(5): decision-coverage gate parses <action> XML tag bodies for D-NN citations (#155)
* test(5): add failing test for decision IDs inside <objective>/<tasks>/<task>/<action> XML bodies Regression test for issue #5 — the translation gate (check.decision-coverage-plan) is blind to D-NN citations placed inside XML tag bodies by gsd-planner. Maintainer acceptance criteria (verbatim, issue #5): "Gate parses <action> tag bodies for decision ID citations; regression test with XML-tag plan body covers all decision IDs." Five new test cases added to the 'XML tag body citation parsing (issue #5)' suite: 1. RED: five decisions cited only in <objective>/<action> bodies → gate fails (before fix) 2. Non-canonical tag <comment> → must NOT count (negative control, passes) 3. Plain prose under undesignated heading → must NOT count (negative control, passes) 4. Self-closing <action/> → no crash, D-NN not covered (passes) 5. D-NN in <objective> body → should count (also fails before fix, GREEN after) Tests 1 and 5 are the load-bearing RED cases. All others are negative controls. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(5): extend extractPlanSections to scan <objective>/<tasks>/<task>/<action> for D-NN citations Closes #5. Root cause: extractPlanSections() in check-decision-coverage.ts collected only front-matter (must_haves/truths/objective) and body lines under designated markdown headings. The gsd-planner spec (agents/gsd-planner.md line 66) says 'Task actions reference the decision ID they implement (e.g., "per D-03")' and emits citations inside <action> tag bodies — a location the gate could not see. Fix: add extractXmlTagBodies() helper that matches the four canonical planner XML tags (<objective>, <tasks>, <task>, <action>) via a deliberately narrow regex (no XML parser library — D2 design decision). The helper output is appended to the designated string inside extractPlanSections(), making any D-NN citation inside those tag bodies count toward coverage. Maintainer acceptance criteria (verbatim, issue #5): "Gate parses <action> tag bodies for decision ID citations; regression test with XML-tag plan body covers all decision IDs." Self-closing tags (<action/>) are safely ignored — the capturing group does not match. Non-canonical tags (<comment>, <note>, etc.) are not in the alternation and are ignored by design. The CJS surface for check-decision-coverage.ts does NOT have a generator (gen-decisions.mjs covers decisions.ts, not this gate). No CJS artifact exists for this module. Per the generator framework established in PR #154 (ADR-3524), a CJS migration is a follow-up; this PR focuses on the TS fix. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(5): clarify in gsd-planner.md that decision-coverage gate reads XML tag bodies Adds a parenthetical note to the existing self-check bullet (line 66) explaining which locations the gate scans so the planner's own guidance and the gate's behavior are explicitly aligned. Refs #5. No behavior change — documentation truthing only. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(5): add changeset fragment for decision-coverage XML body fix Refs #5. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(5): extract Interface Context for Executors into reference file to pass planner-decomposition gate gsd-planner.md was 49446 chars after the XML-tag clarification added in this PR, exceeding the 48K threshold enforced by tests/planner-decomposition.test.cjs. Extracted the "Interface Context for Executors" section (~2137 chars) into get-shit-done/references/planner-interface-context.md, leaving a one-line pointer in gsd-planner.md. New normalized size: 47310 chars (1842 chars under threshold). Refs #5 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(5): register planner-interface-context.md in INVENTORY.md and manifest - Bump References headline from 61 to 62 to match filesystem count - Add planner-interface-context.md row in Modular Planner Decomposition table - Update footnote from 61 to 62 top-level references - Regenerate docs/INVENTORY-MANIFEST.json via gen-inventory-manifest.cjs --write Fixes inventory-counts and inventory-manifest-sync CI failures caused by the extraction commit (32e8950f) adding a new reference file without updating the inventory artefacts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |