* 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
19 KiB
Handover: Query layer + golden parity
Use this document at the start of a new session so work continues in context without re-deriving history.
Related: HANDOVER-PARITY-DOCS.md (#2302 scope); sdk/src/query/QUERY-HANDLERS.md (golden matrix, CJS↔SDK routing).
Goal for the next session (primary)
Track A (Golden/parity) is complete. 127/128 canonicals covered — the single exception (phases.archive) is permanent (SDK-only, no CJS analogue). Focus shifts to the remaining #2302 acceptance criteria.
Ongoing: pick next gap from GOLDEN_PARITY_EXCEPTIONS / registry orphans (run golden-policy.test.ts) or expand READ_ONLY_JSON_PARITY_ROWS for read-only handlers still on generic exceptions. The read-only batch in § Next batch below is done.
Follow-up: confirm GOLDEN_PARITY_EXCEPTIONS for any remaining read-only registry gaps (learnings.query, progress.bar, profile-questionnaire — still exception-only until strict rows); extend read-only-golden-rows.ts when aligned.
Remaining work — ordered by priority
-
Track C — Runner alignment (not started)
PhaseRunnerandInitRunnerboth takeGSDTools(subprocess bridge) as atoolsdependency (phase-runner.ts:55,init-runner.ts:70).- Issue #2302 says: "Align programmatic paths with the same contracts as query handlers (shared helpers or registry dispatch), without removing
GSDTools." - Concretely: where runners currently shell out via
GSDTools.run('state update …'), they could call the typed handler (stateUpdate()) directly or dispatch throughcreateRegistry(). This eliminates subprocess overhead on the hot path while keepingGSDToolsexported for backward compatibility. - Files to touch:
sdk/src/phase-runner.ts,sdk/src/init-runner.ts,sdk/src/index.ts(re-exports). Tests:phase-runner.integration.test.ts,init-e2e.integration.test.ts,lifecycle-e2e.integration.test.ts. - Risk: Runner integration tests are slow and sensitive to state. Approach: swap one
tools.run()call at a time, verify the integration test still passes, then proceed to the next.
-
Track B — CHANGELOG.md [Unreleased] entries (not started)
CHANGELOG.mdhas an[Unreleased]section but no Phase 3 entries yet.- Add entries covering: golden parity policy gate, mutation subprocess infrastructure, handler alignment, profile-output port, CJS deprecation header.
docs/CLI-TOOLS.mdalready referencesQUERY-HANDLERS.mdand SDK query layer — may need minor polish but is substantively done.QUERY-HANDLERS.mdis maintained and current.
-
Track D — CJS deprecation headers (done)
gsd-tools.cjsalready has@deprecatedJSDoc header (lines 3-6) pointing togsd-sdk queryand@gsd-build/sdk.- No additional CJS file deletion in scope per #2302.
-
CI verification (should run before any PR)
- Run full integration suite:
npx vitest run --project integration(mutation subprocess + read-only parity + golden composition). - Verify against CI matrix expectations: Ubuntu + macOS, Node 22 + 24.
- Run full integration suite:
Acceptance criteria from #2302 — status
| Criterion | Status | Notes |
|---|---|---|
| Policy gate | Done | verifyGoldenPolicyComplete() green; 0 orphan canonicals |
| Parity | Done | 127/128 covered; strict rows, mutation subprocess, composition goldens |
| Registry | Done | CJS-only matrix in QUERY-HANDLERS.md; docs/CLI-TOOLS.md updated |
| Runners (Track C) | Not started | PhaseRunner/InitRunner still use GSDTools subprocess bridge |
| Deprecation (Track D) | Done | @deprecated header on gsd-tools.cjs |
| Docs | Partial | QUERY-HANDLERS.md current; CHANGELOG.md [Unreleased] needs Phase 3 entries |
| CI | Not verified | Unit tests green (1261/1261); integration suite not run this session |
Repo / branch
- Workspace:
D:\Repos\get-shit-done(GSD PBR backport initiative). - Feature branch:
feat/sdk-phase3-query-layer(62 commits ahead ofmain; confirm againstoriginbefore merging). - Upstream PRs:
gsd-build/get-shit-doneissue #2302.
Golden parity architecture (current)
| Piece | Role |
|---|---|
sdk/src/golden/registry-canonical-commands.ts |
One canonical dispatch string per unique handler (pickCanonicalCommandName). |
sdk/src/golden/golden-integration-covered.ts |
Canonicals exercised by golden.integration.test.ts (subset/full/shape tests). |
sdk/src/golden/read-only-golden-rows.ts |
Strict JsonParityRow[] for read-only-parity.integration.test.ts (toEqual on parsed CJS JSON vs sdkResult.data). |
sdk/src/golden/read-only-parity.integration.test.ts |
Rows from READ_ONLY_JSON_PARITY_ROWS + config-path (plain stdout vs { path }, path.normalize) + verify.commits. |
sdk/src/golden/capture.ts |
captureGsdToolsOutput (JSON stdout); captureGsdToolsStdout (raw stdout, e.g. config-path). |
sdk/src/golden/golden-policy.ts |
GOLDEN_PARITY_INTEGRATION_COVERED = integration ∪ readOnlyGoldenCanonicals() ∪ GOLDEN_MUTATION_SUBPROCESS_COVERED; GOLDEN_PARITY_EXCEPTIONS includes NO_CJS_SUBPROCESS_REASON, then MUTATION_DEFERRED_REASON for remaining mutations, else read-only. |
sdk/src/golden/golden-mutation-covered.ts |
Canonicals exercised by mutation-subprocess.integration.test.ts (must match non-skipped tests). |
sdk/src/golden/mutation-subprocess.integration.test.ts |
Tmp fixture + captureGsdToolsOutput vs registry.dispatch; dual sandbox per comparison. |
sdk/src/golden/mutation-sandbox.ts |
createMutationSandbox({ git?: boolean }) — copy fixture, optional git init + commit. |
sdk/src/golden/golden-policy.test.ts |
Calls verifyGoldenPolicyComplete() so every canonical is covered or excepted. |
Invariant: Every canonical from getCanonicalRegistryCommands() is either in GOLDEN_PARITY_INTEGRATION_COVERED or has an exception string—never leave orphans by removing tests.
Reference pattern: porting like scan-sessions and workstream.status
These were fixed by aligning the TypeScript handler with the CJS implementation, then adding a row to READ_ONLY_JSON_PARITY_ROWS.
-
Find the CJS source of truth
scan-sessions:get-shit-done/bin/lib/profile-pipeline.cjs→cmdScanSessionsworkstream status:get-shit-done/bin/lib/workstream.cjs→cmdWorkstreamStatusgsd-tools.cjsrunCommandswitch shows the top-level command and argv.
-
Implement or adjust the SDK module
- Example:
sdk/src/query/profile-scan-sessions.tsmirrors the project-array build fromcmdScanSessions;scanSessionsinprofile.tsparses--path/--verbose, throws when no sessions root (same error text as CJS), returns{ data: projects }whereprojectsmatches CJS JSON array.
- Example:
-
Add a parity row in
read-only-golden-rows.tswithcanonical,sdkArgs,cjs,cjsArgs(must match whatexecFile(node, [gsdToolsPath, command, ...args])expects). -
Run
cd sdk && npm run build && npx vitest run src/golden/read-only-parity.integration.test.ts src/golden/golden-policy.test.ts --project integration --project unit -
Policy
readOnlyGoldenCanonicals()picks up new canonicals automatically; no manual duplicate if the canonical is already in the JSON row list.
When not to copy line-for-line: subprocess-only concerns (e.g. agents_installed / missing_agents differing from in-process ~ resolution). Then normalize in the test (see golden.integration.test.ts docs-init: sort existing_docs, omit install fields)—document in QUERY-HANDLERS.md, do not delete the assertion.
Completed — Track A (golden parity)
All 127 portable canonicals have subprocess or in-process parity coverage. Summary of completed work by batch:
Profile-output + milestone subprocess batch (latest)
write-profile, generate-claude-profile, generate-dev-preferences, generate-claude-md — implemented in sdk/src/query/profile-output.ts (templates from get-shit-done/templates/, same JSON as profile-output.cjs); re-exported from profile.ts. milestone.complete — full port of cmdMilestoneComplete in phase-lifecycle.ts; readModifyWriteStateMdFull in state-mutation.ts for STATE writes matching CJS.
Mutation subprocess infrastructure
mutation-subprocess.integration.test.ts — tmp fixture sdk/src/golden/fixtures/mutation-project/ + createMutationSandbox() (mutation-sandbox.ts). assertJsonParity runs CJS and SDK on two fresh sandboxes (factory fn) so neither run sees the other's filesystem mutations. GOLDEN_MUTATION_SUBPROCESS_COVERED lists canonicals with non-skipped subprocess assertions. Handlers covered: config-ensure-section, commit, commitToSubrepo, configSetModelProfile, state.patch, frontmatter.set/merge, workstream.progress, workstream.set, nine state.* subprocess tests, write-profile, generate-claude-profile, generate-dev-preferences, generate-claude-md, milestone.complete, init.remove-workspace.
CJS mutation handler alignment
commit.ts — --files argv boundary, commitToSubrepo config check, checkCommit allowed field. state-mutation.ts — readModifyWriteStateMdFull, statePlannedPhase=cmdStatePlannedPhase, record-session/add-decision/add-blocker/resolve-blocker/record-metric/update-progress JSON shapes. phase-lifecycle.ts — milestone.complete. workstream.ts — workstream.progress (cmdWorkstreamProgress), workstream.set. roadmap.ts — extracted roadmapUpdatePlanProgress to own module. frontmatter-mutation.ts — --field/--value, --data parsing. config-mutation.ts — configSetModelProfile CJS-shaped { updated, profile, previousProfile, agentToModelMap }. config-query.ts — getAgentToModelMapForProfile().
Read-only parity rows (earlier batches)
progress.table / stats.table, progress.bar, learnings.query, profile-questionnaire, verify.references, init.* composition goldens (9 handlers), profile-sample, extract-messages, uat.render-checkpoint, validate.agents + state.get, skill-manifest, audit-open + audit-uat, intel.extract-exports, summary-extract + history-digest, stats.json, todo.match-phase, verify.key-links, verify.schema-drift, state-snapshot, state.json/state.load, scan-sessions, workstream.status.
Next batch — summary / audit / skill / validate / UAT / intel / profile / init
Same workflow as above: read gsd-tools.cjs runCommand for argv → implement/adjust sdk/src/query/*.ts → add READ_ONLY_JSON_PARITY_ROWS and/or a named describe block with documented omissions → npm run build → read-only-parity.integration.test.ts + golden-policy.test.ts.
| Priority | Command (CLI) | gsd-tools.cjs case / args |
CJS implementation | SDK module | Notes |
|---|---|---|---|---|---|
summary-extract <path>[--fields a,b] |
summary-extract |
commands.cjs cmdSummaryExtract (~L425) |
summary.ts summaryExtract |
Done: strict READ_ONLY_JSON_PARITY_ROWS; summary.ts aligned with commands.cjs; extractFrontmatterLeading in frontmatter.ts for first-----block parity with frontmatter.cjs. |
|
history-digest |
history-digest |
commands.cjs cmdHistoryDigest (~L133) |
summary.ts historyDigest |
Done: same row / handler alignment as above. | |
audit-open |
audit-open [--json] |
audit.cjs auditOpenArtifacts + optional formatAuditReport |
audit-open.ts |
Done: --json parity test + scanned_at normalization; sanitizeForDisplay = security.cjs. |
|
audit-uat |
audit-uat |
uat.cjs cmdAuditUat |
uat.ts auditUat |
Done: auditUat ports cmdAuditUat (parseUatItems, milestone filter, summary.by_*); strict READ_ONLY_JSON_PARITY_ROWS row. |
|
skill-manifest |
skill-manifest + args |
init.cjs cmdSkillManifest (~L1829) |
skill-manifest.ts |
Done: strict row; extractFrontmatterLeading for CJS parity (see QUERY-HANDLERS.md). |
|
validate agents |
validate + agents |
verify.cjs cmdValidateAgents (~L997) |
validate.ts validateAgents |
Done: strict row; getAgentsDir parity with core.cjs; MODEL_PROFILES includes gsd-pattern-mapper (sync with model-profiles.cjs). |
|
uat render-checkpoint --file <path> |
uat subcommand |
uat.cjs cmdRenderCheckpoint |
uat.ts uatRenderCheckpoint |
Done: strict row; fixture sdk/src/golden/fixtures/uat-render-checkpoint-sample.md; see QUERY-HANDLERS.md. |
|
intel extract-exports <file> |
intel extract-exports |
intel.cjs intelExtractExports (~L502) |
intel.ts intelExtractExports |
Done: strict row + handler parity with intel.cjs (fixed file e.g. sdk/src/query/utils.ts). |
|
extract-messages |
extract-messages + project/session flags |
profile-pipeline.cjs |
profile.ts extractMessages |
Done: profile-extract-messages.ts + golden output_file strip + JSONL compare; fixture extract-messages-sessions/. |
|
profile-sample |
profile-sample |
profile-pipeline.cjs |
profile.ts profileSample |
Done: profile-sample.ts + golden output_file strip + JSONL compare; fixture profile-sample-sessions/. |
|
init.* read-only JSON |
various | init.cjs / init-complex |
init.ts, init-complex.ts |
Done: golden.integration.test.ts + nine init composition tests; withProjectRoot / subagent_timeout / GOLDEN_INTEGRATION_MAIN_FILE_CANONICALS; see QUERY-HANDLERS.md. |
Suggested order: Audit/read-only batch above is complete — follow-ups via GOLDEN_PARITY_EXCEPTIONS / new strict rows as needed (learnings.query, progress.bar, profile-questionnaire, etc.).
Done (this line of work): summary-extract + history-digest — strict READ_ONLY_JSON_PARITY_ROWS; summary.ts aligned with commands.cjs; extractFrontmatterLeading in frontmatter.ts for first-----block parity with frontmatter.cjs.
Done (profile-output + milestone mutation batch): write-profile, generate-claude-profile, generate-dev-preferences, generate-claude-md (profile-output.ts); milestone.complete (phase-lifecycle.ts + readModifyWriteStateMdFull); GOLDEN_MUTATION_SUBPROCESS_COVERED updated; MUTATION_SUBPROCESS_GAP_REASON removed from golden-policy.ts.
Mutations (QUERY_MUTATION_COMMANDS): subprocess coverage is mutation-subprocess.integration.test.ts + GOLDEN_MUTATION_SUBPROCESS_COVERED. Remaining mutation canonicals without a subprocess row use MUTATION_DEFERRED_REASON (see golden-policy.ts). For known gaps before parity, prefer it.skip with an explicit rationale in code comments or restore a dedicated gap map — do not rely on silent deferral alone.
Backlog: other read-only handlers (lower priority or follow-ups)
Confirm against GOLDEN_PARITY_EXCEPTIONS in golden-policy.ts for the live list.
Mutations: Prefer tmp fixture + dual sandbox (see mutation-sandbox.ts). Do not green the suite by deleting subprocess tests; skip with it.skip and document the gap (policy entry or comment) until parity is restored.
Not in the SDK registry (product decision)
graphify,from-gsd2/gsd2-import— CLI-only; no registry handler.
Files to know (updated)
| Path | Role |
|---|---|
sdk/src/query/index.ts |
createRegistry(), QUERY_MUTATION_COMMANDS. |
sdk/src/golden/golden-policy.ts |
Coverage set + exceptions; verifyGoldenPolicyComplete(). |
sdk/src/golden/read-only-golden-rows.ts |
Strict read-only JSON matrix. |
sdk/src/golden/read-only-parity.integration.test.ts |
Subprocess + dispatch parity tests. |
sdk/src/golden/capture.ts |
captureGsdToolsOutput, captureGsdToolsStdout. |
sdk/src/golden/fixtures/mutation-project/ |
Ephemeral copy for mutation subprocess tests. |
sdk/src/golden/mutation-subprocess.integration.test.ts |
Mutation handler subprocess parity. |
sdk/src/golden/mutation-sandbox.ts |
createMutationSandbox({ git?: boolean }). |
sdk/src/query/profile-output.ts |
CJS-parity profile output handlers. |
sdk/src/phase-runner.ts |
Track C target — currently uses GSDTools. |
sdk/src/init-runner.ts |
Track C target — currently uses GSDTools. |
sdk/src/gsd-tools.ts |
Subprocess bridge; not deleted in Phase 3 scope. |
get-shit-done/bin/gsd-tools.cjs |
runCommand — argv routing. Has @deprecated header. |
get-shit-done/bin/lib/*.cjs |
Per-command implementations (CJS source of truth). |
Commands (verification)
cd sdk
npm run build
npm run test:unit
npm run test:integration
Focused:
npx vitest run src/golden/read-only-parity.integration.test.ts src/golden/golden.integration.test.ts --project integration
npx vitest run src/golden/mutation-subprocess.integration.test.ts --project integration
npx vitest run src/golden/golden-policy.test.ts --project unit
Success criteria (extend, not replace)
- No regression:
golden-policy.test.ts/verifyGoldenPolicyComplete()stays green. - Track A complete: 127/128 covered; read-only rows, mutation subprocess, composition goldens all in place.
- Track C: Runner alignment —
PhaseRunnerandInitRunneruse typed handlers where possible;GSDToolsremains exported. - CHANGELOG.md [Unreleased] updated with Phase 3 entries.
QUERY-HANDLERS.mdupdated when assertion style changes (fulltoEqualvs normalized subset).
Do not "green the suite" by deleting or shrinking golden tests. If a handler cannot match CJS byte-for-byte without product decisions, use documented normalization in the test or fix the TypeScript handler — do not silently remove assertions.
Commit history (this branch)
62 commits ahead of main on feat/sdk-phase3-query-layer. Recent batch (5 commits):
95db59c docs(sdk): update handover for profile-output and mutation subprocess batch
05e8238 sdk(golden): mutation subprocess test infrastructure and golden policy
593d9be sdk(query): port profile output handlers from profile-output.cjs
a2d0eb6 sdk(query): CJS parity for state, phase-lifecycle, workstream, roadmap, frontmatter, config, and intel
8bd9f1d sdk(query): align commit handler with CJS --files argv and allowed field
Cherry-pick notes: Commits 1 (8bd9f1d) and 3 (593d9be) are independently cherry-pickable. Commit 2 (a2d0eb6) is a bulk handler alignment (13 files). Commit 4 (05e8238) depends on handlers from 2+3 at test-runtime but compiles independently. Commit 5 is docs-only.
Update this file when registry or golden milestones change.