Commit Graph

14 Commits

Author SHA1 Message Date
Tom Boucher
b5676b59c0 fix: accept flag-first syntax for phase remove (#3416)
* fix(phase): parse remove --force regardless of position

* chore(changeset): add fragment for phase-remove flag fix

* fix(phase): fail when phase.remove target is missing
2026-05-11 21:13:07 -04:00
Tom Boucher
65abc4fc90 refactor(query): deepen phase lifecycle seams (#3267)
* refactor(query): extract phase lifecycle policy module

* refactor(query): extract phase fs and roadmap mutation adapters

* fix(sdk): propagate non-ENOENT readdir errors in phase-filesystem-adapter (CR finding 1)

Swallow only ENOENT in listDirectories; rethrow EACCES, EIO, and other
unexpected errors so callers surface real failures rather than silently
treating a permission-denied phases dir as empty.

Also adds regression test: EACCES from readdir now propagates as thrown
error instead of returning [].

* fix(sdk): propagate non-ENOENT readFile errors in phase-roadmap-mutation (CR finding 4)

readModifyWriteRoadmapMd now falls back to empty content only on ENOENT;
EACCES, EIO, and other errors are rethrown so a subsequent write cannot
clobber real roadmap content that is temporarily unreadable.

Regression tests: EACCES propagates; absent ROADMAP.md still starts empty.

* fix(sdk): omit Depends on: Phase 0 for first sequential phase; align prefix grammar (CR findings 2+3)

Finding 2: buildPhaseRoadmapEntry now omits the "Depends on" line when
phaseId == 1 (prevPhase would be 0, which is not a valid predecessor).
The guard is `prevPhase < 1` so future phase-0 configs are also safe.

Finding 3: collectDecimalSuffixesFromDirNames regex prefix pattern
updated from `[A-Z]{1,6}` to `[A-Z][A-Z0-9]*` (case-insensitive flag
added), matching the grammar used by scanSequentialMaxPhaseFromDirs.
Prevents k014 parity drift for alphanumeric project-code prefixes longer
than six characters or containing digits.

Regression tests for both fixes included.
2026-05-09 00:14:59 -04:00
Tom Boucher
288b3b4170 fix(3259): non-mutating --help guard for native query handlers (#3272)
* fix(3259): non-mutating --help guard for native query handlers; reject --help as milestone version

Adds a dispatcher-level guard in query-dispatch.ts that short-circuits
to a non-mutating help stub whenever --help/-h appears in args destined
for a native mutating handler (fail-closed by default). Adds defense-
in-depth in milestoneComplete to reject --help/-h as a version value
before any disk write. Regression tests cover: per-handler --help guard,
registry-driven invariant across all mutating commands, handler-level
GSDError for both flags, and preservation of the #3019 CJS fallback
contract.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: add changeset fragment for #3272

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 23:53:27 -04:00
Tom Boucher
447763411a fix(sdk): phase.add honors --dry-run; rejects unknown flags (#3226) (#3246)
* test: reproduce phase.add dry-run + flag validation gaps (#3226)

Add failing tests for:
- --dry-run silently absorbed into description (symptom A)
- Unknown --flag should return validation error (symptom C)
- ### Phase N: ROADMAP heading scan verification (symptom B)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(sdk): phase.add honors --dry-run; rejects unknown flags (#3226)

- Add flag parser to phaseAdd: strip recognized flags (--dry-run) from
  args before positional parsing so they never silently become description
  or customId values
- --dry-run computes the next phase number and roadmap_entry string but
  skips mkdir, writeFile, and readModifyWriteRoadmapMd; returns
  { dry_run: true, roadmap_entry } alongside normal fields
- Any unrecognized --flag throws a Validation GSDError naming the flag
- ROADMAP ### Phase N: heading scan for numbering (symptom B) was already
  correct; verified with new regression test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* changeset: pr=3246 for #3226

* fix(sdk): phase.add scans disk AND roadmap (union, not fallback)

Address CodeRabbit finding: the conditional `if (maxPhase === 0)` guard
around the filesystem scan meant that if ROADMAP had any phases but disk
was ahead (e.g. ROADMAP max=10, dirs include 12-*), phase.add would
pick 11 and collide with the existing directory.

Remove the guard: always scan on-disk phase directories and take the
max across both ROADMAP and filesystem (union semantics).

All 57 phase-lifecycle tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test: reproduce phase.add concurrent ID collision (CR finding)

Two concurrent phase.add calls against the same project observe
maxPhase before the lock is held, producing duplicate phase IDs.
Adds a Promise.all regression test that asserts both calls succeed
with distinct phase numbers {11, 12}.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(sdk): compute phase number under roadmap lock (CR finding)

Move maxPhase/newPhaseId/dirName computation inside the
readModifyWriteRoadmapMd callback so the entire read → compute → write
cycle is serialised under the lock. Previously, two concurrent
phase.add calls could both observe maxPhase=N before either acquired
the lock, then both write with phase ID N+1 — producing duplicate IDs.

In dry-run mode (no write, no race) the computation still happens
outside the lock to avoid unnecessary contention.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 08:40:24 -04:00
Tom Boucher
2b95ccbddd Merge pull request #2743 from gsd-build/fix/2714-workstream-config-inheritance
feat(config): workstream config.json inherits from root .planning/config.json
2026-04-26 11:49:30 -04:00
Tom Boucher
41787e361f Merge pull request #2740 from gsd-build/fix/2641-details-summary-milestone-detection
fix(phase-lifecycle): skip <details>-wrapped sections in milestone detection
2026-04-26 11:49:14 -04:00
Tom Boucher
9e63d14709 Merge pull request #2737 from gsd-build/fix/2726-phase-add-bullet-bold-roadmap
fix(phase-lifecycle): detect phases in bullet/bold ROADMAP formats for phase.add
2026-04-26 11:48:58 -04:00
Tom Boucher
76f1d20d80 test(phase-lifecycle): add regression for active <details> with trailing footer
Adds a case where the active milestone is the last <details> block but
footer text (--- / *Last updated*) follows </details>, triggering the
fast-path to replace in the footer instead of inside the block.

Closes #2743
2026-04-26 11:36:46 -04:00
Tom Boucher
8270f17773 fix(phase-lifecycle): handle project-code-prefixed dirs in phaseAdd fallback scan
Filesystem fallback regex /^(\d+)-/ missed directories like CK-45-foundation
when project_code is configured. Updated to /^(?:[A-Z][A-Z0-9]*-)?(\d+)-/i.

Addresses coderabbit finding on PR #2737.
2026-04-26 11:21:33 -04:00
Tom Boucher
a7d3bb948b test(phase-lifecycle): add failing test for active milestone in <details> block
Closes #2641
2026-04-26 10:23:41 -04:00
Tom Boucher
54cbc2ad96 fix(phase-lifecycle): detect phases in bullet/bold ROADMAP formats
phaseAdd's phase-number regex only matched heading format (## Phase N:),
missing bullet checklist (- [x] Phase N:) and bold (**Phase N:**) entries.
When zero regex matches, newPhaseId defaulted to 1.

Fix: broaden regex to match all three formats, and add filesystem fallback
scanning .planning/phases/ when ROADMAP scan finds nothing.

Closes #2726
2026-04-26 10:00:39 -04:00
Tom Boucher
394403ae06 test(phase-lifecycle): add failing regression test for #2728
When **Plans:** appears on its own line with no inline value, the
planCountPattern regex crosses the newline and destroys the first
plan checkbox line by replacing it with the literal "N/N plans complete"
string.

This test documents the expected correct behavior and will fail until
the planCountPattern regex is fixed.
2026-04-26 09:46:51 -04:00
Rezolv
c5b1445529 feat(sdk): golden parity harness and query handler CJS alignment (#2302 Track A) (#2341)
* feat(sdk): golden parity harness and query handler CJS alignment (#2302 Track A)

Golden/read-only parity tests and registry alignment, query handler fixes
(check-completion, state-mutation, commit, validate, summary, etc.), and
WAITING.json dual-write for .gsd/.planning readers.

Refs gsd-build/get-shit-done#2341

* fix(sdk): getMilestoneInfo matches GSD ROADMAP (🟡, last bold, STATE fallback)

- Recognize in-flight 🟡 milestone bullets like 🚧.
- Derive from last **vX.Y Title** before ## Phases when emoji absent.
- Fall back to STATE.md milestone when ROADMAP is missing; use last bare vX.Y
  in cleaned text instead of first (avoids v1.0 from shipped list).
- Fixes init.execute-phase milestone_version and buildStateFrontmatter after
  state.begin-phase (syncStateFrontmatter).

* feat(sdk): phase list, plan task structure, requirements extract handlers

- Register phase.list-plans, phase.list-artifacts, plan.task-structure,
  requirements.extract-from-plans (SDK-only; golden-policy exceptions).
- Add unit tests; document in QUERY-HANDLERS.md.
- writeProfile: honor --output, render dimensions, return profile_path and dimensions_scored.

* feat(sdk): centralize getGsdAgentsDir in query helpers

Extract agent directory resolution to helpers (GSD_AGENTS_DIR, primary
~/.claude/agents, legacy path). Use from init and docs-init init bundles.

docs(15): add 15-CONTEXT for autonomous phase-15 run.

* feat(sdk): query CLI CJS fallback and session correlation

- createRegistry(eventStream, sessionId) threads correlation into mutation events
- gsd-sdk query falls back to gsd-tools.cjs when no native handler matches
  (disable with GSD_QUERY_FALLBACK=off); stderr bridge warnings
- Export createRegistry from @gsd-build/sdk; add sdk/README.md
- Update QUERY-HANDLERS.md and registry module docs for fallback + sessionId
- Agents: prefer node dist/cli.js query over cat/grep for STATE and plans

* fix(sdk): init phase_found parity, docs-init agents path, state field extract

- Normalize findPhase not-found to null before roadmap fallback (matches findPhaseInternal)

- docs-init: use detectRuntime + resolveAgentsDir for checkAgentsInstalled

- state.cjs stateExtractField: horizontal whitespace only after colon (YAML progress guard)

- Tests: commit_docs default true; config-get golden uses temp config; golden integration green

Refs: #2302

* refactor(sdk): share SessionJsonlRecord in profile-extract-messages

CodeRabbit nit: dedupe JSONL record shape for isGenuineUserMessage and streamExtractMessages.

* fix(sdk): address CodeRabbit major threads (paths, gates, audit, verify)

- Resolve @file: and CLI JSON indirection relative to projectDir; guard empty normalized query command

- plan.task-structure + intel extract/patch-meta: resolvePathUnderProject containment

- check.config-gates: safe string booleans; plan_checker alias precedence over plan_check default

- state.validate/sync: phaseTokenMatches + comparePhaseNum ordering

- verify.schema-drift: token match phase dirs; files_modified from parsed frontmatter

- audit-open: has_scan_errors, unreadable rows, human report when scans fail

- requirements PLANNED key PLAN for root PLAN.md; gsd-tools timeout note

- ingest-docs: repo-root path containment; classifier output slug-hash

Golden parity test strips has_scan_errors until CJS adds field.

* fix: Resolve CodeRabbit security and quality findings
- Secure intel.ts and cli.ts against path traversal
- Catch and validate git add status in commit.ts
- Expand roadmap milestone marker extraction
- Fix parsing array-of-objects in frontmatter YAML
- Fix unhandled config evaluations
- Improve coverage test parity mapping

* test: raise planner character extraction limit to 48K

* fix(sdk): resolve TS build error in docs-init passing config
2026-04-20 18:09:02 -04:00
Tom Boucher
002bcf2a8a fix(2137): skip worktree isolation when .gitmodules detected (#2144)
* feat(sdk): add typed query foundation and gsd-sdk query (Phase 1)

Add sdk/src/query registry and handlers with tests, GSDQueryError, CLI query wiring, and supporting type/tool-scoping hooks. Update CHANGELOG. Vitest 4 constructor mock fixes in milestone-runner tests.

Made-with: Cursor

* fix(2137): skip worktree isolation when .gitmodules detected

When a project contains git submodules, worktree isolation cannot
correctly handle submodule commits — three separate gaps exist in
worktree setup, executor commit protocol, and merge-back. Rather
than patch each gap individually, detect .gitmodules at phase start
and fall back to sequential execution, which handles submodules
transparently (Option B).

Affected workflows: execute-phase.md, quick.md

---------

Co-authored-by: David Sienkowski <dave@sienkowski.com>
2026-04-12 08:33:04 -04:00