Commit Graph

3119 Commits

Author SHA1 Message Date
Tom Boucher
091b7e2c4b perf(#305): single-pass max-by-mtime for statusline todo lookup (#385)
Replace the per-render readdirSync().filter().map(statSync).sort() chain
with a single-pass max-by-mtime loop. Drops the O(n log n) sort and the
throwaway intermediate array; I/O and resolved-file behavior are identical.
Adds the first behavior-lock test for the todo-resolution path.

The larger disk-backed cache win from the issue is deferred: statusline is
a fresh child process per render, so any cache must be disk-backed with
invalidation/atomic-write design that needs maintainer input.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 20:21:15 -04:00
Tom Boucher
51aac62e9a perf(#307): use head-index queue for phase dependency BFS (O(V^2) -> O(V+E)) (#383)
The Pass-2 topological level assignment in cmdPhasePlanIndex dequeued its
Kahn's-algorithm queue with Array.shift(), which is O(n) per call in V8, so the
BFS was O(V^2) and slowed superlinearly on deep queues (wide fan-in plan
graphs). Extract the traversal into a pure, exported computeDependencyLevels
(rawPlans, planMap, canonicalToId) and dequeue via a head index (queue[head++])
-> O(V+E). Behavior is identical: same FIFO order, same longest-path levels,
same visited-count cycle detection. A complexity-contract comment above the loop
documents why shift() must not be reintroduced.

Adds tests/phase-dependency-levels.test.cjs with deterministic behavior and
edge-case coverage (linear chain, diamond longest-path, independent set, cycle,
canonical-prefix resolution, empty, self-loop, duplicate edge, external dep). A
timing-based complexity guard was intentionally omitted: the O(V+E) Map-build
constant dilutes the O(V^2) signal until impractical N (~1e6), so an empirical
guard is inherently flaky on contended CI — the contract is enforced by the
inline comment and correctness tests instead.

Fixes #307

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 20:21:12 -04:00
Tom Boucher
d17bb4ea1e fix(#145): extractCurrentMilestone selects active sub-milestone over closed sibling (#380)
* fix(#145): extractCurrentMilestone selects active sub-milestone over closed sibling

extractCurrentMilestone used a non-global regex with content.match()
(first-match) to locate the milestone section for the STATE.md version.
When the milestone is a shared semver prefix (e.g. v8.0) and ROADMAP.md
holds both a closed sub-milestone (## v8.0 ... CLOSED/FAIL) and an active
one (## v8.0-B ... STARTED), the first match was always the closed
heading, so the active section and its phases were excised from the slice
and downstream phase ops failed with "Phase N not found in current
milestone".

Switch to a global matchAll over candidate headings, skip headings
carrying a closed marker (CLOSED/ARCHIVED/ABANDONED/SHIPPED/FAILED/FAIL/
✅/🗄️), and select the first non-closed match (falling back to the first
match when every candidate is closed, preserving legacy behavior). Anchor
the preamble slice to the first heading index so a closed sibling's body
no longer leaks into the preamble when the selected section is later.

Harden version matching with a trailing word boundary (so v8.0-B does not
match v8.0-Beta), narrow the FAIL marker to FAILED, match a bare 🗄, and
add an active-marker override (STARTED/🚧/ACTIVE) so a heading carrying an
explicit active status is never treated as closed even if its name contains
a completion word. Also anchor the preamble at the first any-version
milestone heading so unmatched sibling sections do not leak into the
preamble.

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

* ci(#145): add changeset fragment for milestone-selection fix

Adds the required .changeset/*.md fragment for this user-facing fix
(changeset-lint gate).

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 20:21:08 -04:00
Tom Boucher
2b9fa009d3 fix(#373): replace unquoted $GSD_SDK with space-safe gsd_run launcher (#379)
* fix(#373): replace unquoted $GSD_SDK with space-safe gsd_run launcher

Workflow bash blocks resolved the runtime as GSD_SDK="node $GSD_TOOLS" and
invoked it unquoted ($GSD_SDK query ...). On install paths containing spaces
(e.g. /Volumes/Mini Me/...) the unquoted expansion word-split into
`node /Volumes/Mini gsd-tools.cjs ...`, failing with "Cannot find module
'/Volumes/Mini'" and getting masked by `2>/dev/null || echo "{}"` into a
silent empty state.

Replace the string variable with a single-line shell launcher that defines a
gsd_run function, invokes the runtime with a fully-quoted path and "$@", and
preserves the local-cjs / installed-gsd-tools-on-PATH fallback (#3668) plus
the loud not-found error and install hint. The launcher uses _GSD_SHIM_NAME
indirection so no workflow emits the /gsd-tools substring that the do.md
dispatcher-parity scanner would misread, and is single-line to stay within
the per-file progressive-disclosure line budgets (#2551).

The canonical launcher lives in
get-shit-done/workflows/_runtime-launcher.snippet.sh, is propagated once per
file by scripts/sync-runtime-launcher.cjs, and is locked by
tests/runtime-launcher-parity.test.cjs (fails CI on drift, on a reappearing
$GSD_SDK token, or on a /gsd-tools substring). Dependent workflow-assertion
tests are updated from $GSD_SDK to gsd_run, and the runtime launcher is
registered in CONTEXT.md.

Fixes #373

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

* ci(#373): add changeset fragment and allow-test-rule for parity guard

The runtime-launcher parity test is a structural drift guard that reads
workflow markdown to assert the canonical launcher is present and the
retired $GSD_SDK / /gsd-tools tokens are absent; annotate it with
allow-test-rule per the no-source-grep lint escape hatch. Add the required
.changeset fragment for this user-facing fix.

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

* test(#373): make parity PATH-fallback assertion cross-platform (Windows)

Subtest (E) compared GSD_TOOLS against the Node-side absolute temp path,
but the value originates from git-bash which reports the POSIX form, so the
prefix comparison failed on windows-latest while the launcher itself worked
(the installed stub was invoked). Assert the resolved binary by normalized
suffix (/bin/gsd-tools, not .cjs) instead of the absolute prefix; the
behavioral stub-invocation assertion is unchanged.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 20:21:05 -04:00
Tom Boucher
33ebd1de19 fix(#371): invoke installed bin via shell for Windows .cmd shims in release-tarball-smoke (#375)
* fix(#371): invoke installed bin via shell for Windows .cmd shims in release-tarball-smoke

`node <gsd-tools.cmd>` cannot execute a Windows batch shim as a JS script, so
runSmoke returned bin_not_callable for every check on Windows. Route .cmd/.bat
shims through shell:true (required by Node >=18.20/20.12) and keep the POSIX
node-invocation path unchanged. Add an exported binInvocation seam plus a
platform-agnostic regression test.

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

* chore(#371): surface bin-invocation failure details in release-tarball-smoke

The smoke harness captured stderr/stdout in `details` but never printed
them, so Windows bin_not_callable failures gave no actionable cause in CI.
Log the resolved bin, invocation descriptor, exit status/signal/error, and
captured stderr/stdout on spawn-derived failures so the real error is visible.

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

* chore(#371): include smoke result details in install-test assertion messages

The node --test TAP runner swallows in-test console.error, so Windows
bin_not_callable failures gave no cause. Embed code + details (incl. captured
stderr/stdout) into the assertion messages, which DO reach the CI log, so the
real Windows failure is diagnosable.

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

* fix(#371): resolve installed bin from prefix root on Windows

npm install -g --prefix X writes bin shims to X\ (the prefix root) on
Windows, not X\node_modules\.bin\. The smoke harness only searched
node_modules\.bin on win32, so the installed gsd-tools/installer bin was
never found and runSmoke returned bin_not_callable before invoking anything.
Search the prefix root first (then node_modules/.bin as fallback), report the
searched candidates on miss, and drop the TAP-swallowed console.error probes.
The .cmd-via-shell binInvocation fix remains for actually running the shim.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 22:46:09 -04:00
Tom Boucher
4fbb61c915 fix(#372): harden bug-3668 resolver test for Windows/CI (non-login shell + CRLF) (#374)
* fix(#372): use non-login shell in bug-3668 resolver test for hermetic PATH

bash -lc re-sourced profile files (e.g. Homebrew shellenv) that prepended
real bin dirs ahead of the test's injected PATH, so the installed-gsd-tools
fallback subtest resolved a host-global gsd-tools instead of the injected
fake — failing on dev machines and CI-adjacent benches while passing on
clean CI. Use bash -c (non-login) so the injected PATH is authoritative.

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

* fix(#372): split workflow snippet on CRLF in bug-3668 resolver test

extractResolverSnippet split on '\n' and exact-matched the closing \`fi\`
line, so on a Windows checkout (CRLF) the line was \`fi\r\`, the end marker
was never found, and the test failed with "SDK resolution snippet must end
with fi". Split on /\r?\n/ so extraction works on LF and CRLF checkouts and
the snippet handed to bash is carriage-return-free.

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

* fix(#372): assert resolver bin by normalized suffix, not exact OS path

On Windows the snippet runs under Git bash, so GSD_TOOLS is reported POSIX-
style / mixed-separator while the test built its expected regex from Node
path.join (backslashes) — the resolver was correct (installed:/runtime: output
proves the right bin ran) but the exact-path assertions failed. Normalize
separators and assert the GSD_TOOLS path suffix, keeping the behavioral
installed:/runtime: assertions as the primary checks.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 22:33:49 -04:00
Tom Boucher
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>
2026-05-26 19:11:58 -04:00
Colin Johnson
aaa19b0609 fix: resolve installed gsd-tools in workflows (#354)
* fix: resolve installed gsd-tools in workflows

* chore: add changeset
2026-05-26 18:56:21 -04:00
Colin Johnson
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
2026-05-26 18:56:00 -04:00
Colin Johnson
7a3822fce1 fix: replace removed gsd-sdk prompt references (#355)
* fix: replace removed gsd-sdk prompt references

* chore: add changeset
2026-05-26 18:55:40 -04:00
Colin Johnson
ed149ff283 fix: accept json input for state patch (#356)
* fix: accept json input for state patch

* chore: add changeset
2026-05-26 18:55:20 -04:00
Colin Johnson
b496737ae1 fix: sync lockfile bin metadata (#357)
* fix: sync lockfile bin metadata

* chore: add changeset
2026-05-26 18:54:57 -04:00
Tom Boucher
1b16c60df9 ci(#365): run affected tests for pull request CI lanes (#366) 2026-05-26 18:54:27 -04:00
Tom Boucher
58b442b1ae docs(#358): clarify local test-runner guidance in CONTRIBUTING (#359) 2026-05-26 17:17:55 -04:00
Tom Boucher
660670ef57 fix(#343): remove legacy security contacts and org references (#351) 2026-05-26 17:03:49 -04:00
Tom Boucher
ec8aaf11ea fix(#344): force JS actions to Node 24 in test workflow (#350) 2026-05-26 16:25:52 -04:00
Tom Boucher
bd8b9eaf9d fix(#344): harden windows test assertions and pin windows-2025 labels (#349) 2026-05-26 16:14:15 -04:00
Tom Boucher
70c092ecd4 fix(#344): remove retired SDK steps from test workflows (#348) 2026-05-26 15:46:12 -04:00
Tom Boucher
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
2026-05-26 13:49:07 -04:00
Tom Boucher
de08c8cd60 feat(#301): remove retired sdk command-contract drift (#302) 2026-05-26 12:25:52 -04:00
Tom Boucher
aec61416d8 refactor(#299): deepen active workstream resolution context (#300) 2026-05-26 12:25:32 -04:00
Tom Boucher
1f2ef131c5 fix(#322): normalize surface manifest inputs before profile resolution (#325) 2026-05-26 12:22:08 -04:00
Tom Boucher
e5a5a75938 fix(#321): replace JSON config default clone with structuredClone (#324) 2026-05-26 12:22:02 -04:00
Tom Boucher
e4f29feabc refactor: remove stale SDK router shim wrappers (#298)
* refactor(#297): remove stale sdk router shim wrappers

* test: remove sdk-era refusal wording fixtures
2026-05-26 12:21:04 -04:00
Tom Boucher
e905ca1c32 feat(#293): stabilize workstream inventory ordering (#294) 2026-05-26 12:20:40 -04:00
Tom Boucher
e08fea7ef2 fix(#280): anchor execute-phase subagent reads to project root (#286) 2026-05-26 12:09:26 -04:00
Tom Boucher
c66705d6ba fix(#279): document Agent mapping and deferred tool discovery (#285) 2026-05-26 12:08:53 -04:00
Tom Boucher
90ea3a3297 fix(#278): detect codex .toml agent role files (#284) 2026-05-26 12:08:18 -04:00
Tom Boucher
ce945ef753 fix(#275): accept top-level decision gate result fields (#283) 2026-05-26 12:07:40 -04:00
Tom Boucher
afba2afbe7 fix(#229): normalize gsd-hook-version substitution in verify-reapply (#282) 2026-05-26 12:06:57 -04:00
Tom Boucher
6a94bb6afb refactor(#287): deepen active workstream pointer store seam (#288) 2026-05-26 11:57:39 -04:00
Tom Boucher
f76a53e055 feat(#291): deepen workstream name policy seam (#292) 2026-05-26 11:24:12 -04:00
Tom Boucher
a361da689b feat(#295): deepen runtime name policy seam (#296) 2026-05-26 11:24:01 -04:00
Tom Boucher
43eafea3d5 fix(#303): deepen command routing seams and alias parity guard (#304) 2026-05-26 11:23:53 -04:00
Tom Boucher
06cf7826e3 test: deepen fixture module v2 for reliability (#329)
* test: deepen fixture seam for init/state/workstream suites

* test: deepen fixture module v2 with declarative builders
2026-05-26 11:23:42 -04:00
Tom Boucher
656bff8b73 test: add process-state isolation helper for reliability (#331) 2026-05-26 11:23:35 -04:00
Tom Boucher
0a43185510 test: add typed failure classification module (#333) 2026-05-26 11:23:29 -04:00
Tom Boucher
8ad0c0d546 test: add cross-platform test run module (#335) 2026-05-26 11:23:23 -04:00
Tom Boucher
fd7c82149c test: add generator freshness contract module (#337) 2026-05-26 11:23:16 -04:00
Colin Johnson
80d971d01e Merge pull request #265 from open-gsd/issue/261-bug-worktree-executor-force-adds-gitigno-1779717159
fix(issue): bug: worktree executor force-adds gitignored .planning/SUMMARY.md into worktree branch (regression of the skipped_gitignored SDK contract)
2026-05-25 13:13:28 -04:00
Tom Boucher
45bb3ac95e Merge pull request #273 from open-gsd/fix/196-i18n-remove-sdk-doc-refs
docs(#196): align localized docs with sdk retirement wording
2026-05-25 12:07:13 -04:00
Tom Boucher
b64ffc12ed docs(#196): remove sdk references from localized docs 2026-05-25 12:06:18 -04:00
Tom Boucher
58439a770d Merge pull request #272 from open-gsd/fix/195-claude-workflows-remove-gsd-sdk
docs(#195): migrate workflow markdown from gsd-sdk query to gsd-tools
2026-05-25 12:04:33 -04:00
Tom Boucher
0e6907050e docs(#195): migrate workflow markdown off gsd-sdk query 2026-05-25 12:03:10 -04:00
Tom Boucher
954f036829 Merge pull request #271 from open-gsd/fix/194-docs-remove-sdk-programmatic
docs(#194): remove sdk programmatic sections from core docs
2026-05-25 11:58:21 -04:00
Tom Boucher
e8fc50034d docs(#194): remove sdk programmatic docs and bridge guidance 2026-05-25 11:57:24 -04:00
Tom Boucher
a7eb4bd51e Merge pull request #270 from open-gsd/fix/193-context-sdk-retirement-doc
docs(#193): update CONTEXT glossary for single-runtime seams
2026-05-25 11:52:41 -04:00
Tom Boucher
87ef25b1bb docs(#193): align CONTEXT module glossary with sdk retirement 2026-05-25 11:51:22 -04:00
Tom Boucher
b3ccc9b189 Merge pull request #269 from open-gsd/fix/192-retire-sdk-release-pipeline
fix(#192): retire sdk release pipeline and align smoke/test seams
2026-05-25 11:45:58 -04:00
Tom Boucher
b393e98078 docs(#192): mark changeset as docs-exempt for internal cleanup 2026-05-25 11:43:29 -04:00