diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 73e9c951b..4556731ca 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -54,8 +54,8 @@ GSD is a **meta-prompting framework** that sits between the user and AI coding a │ │ │ ┌──────▼──────────────▼─────────────────▼──────────────┐ │ CLI TOOLS LAYER │ -│ gsd-sdk query (sdk/src/query) + gsd-tools.cjs │ -│ Programmatic SDK bridge: GSDTools/query-runtime-bridge.ts │ +│ gsd-tools.cjs command families + domain modules │ +│ command-routing-hub + observability seams │ └──────────────────────┬───────────────────────────────┘ │ ┌──────────────────────▼───────────────────────────────┐ @@ -77,7 +77,7 @@ Every agent spawned by an orchestrator gets a clean context window (up to 200K t Workflow files (`get-shit-done/workflows/*.md`) never do heavy lifting. They: -- Load context via `gsd-sdk query init.` (or legacy `gsd-tools.cjs init `) +- Load context via `gsd-tools.cjs init ` - Spawn specialized agents with focused prompts - Collect results and route to the next step - Update state between steps @@ -134,7 +134,7 @@ The eager skill listing is one of two recurring per-turn token costs. The other Orchestration logic that commands reference. Contains the step-by-step process including: -- Context loading via `gsd-sdk query` init handlers (or legacy `gsd-tools.cjs init`) +- Context loading via `gsd-tools.cjs init` handlers - Agent spawn instructions with model resolution - Gate/checkpoint definitions - State update patterns @@ -236,7 +236,7 @@ The planner agent (`agents/gsd-planner.md`) was decomposed from a single monolit ### Templates (`get-shit-done/templates/`) -Markdown templates for all planning artifacts. Used by `gsd-sdk query template.fill` / `phase.scaffold` (and legacy `gsd-tools.cjs template fill` / top-level `scaffold`) to create pre-structured files: +Markdown templates for all planning artifacts. Used by `gsd-tools.cjs template fill` / `phase.scaffold` (and top-level `scaffold`) to create pre-structured files: - `project.md`, `requirements.md`, `roadmap.md`, `state.md` — Core project files - `phase-prompt.md` — Phase execution prompt template - `summary.md` (+ `summary-minimal.md`, `summary-standard.md`, `summary-complex.md`) — Granularity-aware summary templates @@ -266,20 +266,9 @@ Runtime hooks that integrate with the host AI agent: See [`docs/INVENTORY.md`](INVENTORY.md#hooks-11-shipped) for the authoritative 11-hook roster. -### SDK Runtime Bridge Module (`sdk/src/query-runtime-bridge.ts`) - -Programmatic SDK callers (`GSDTools`) route through one seam that owns query dispatch policy: - -- Native registry dispatch preference -- Explicit subprocess fallback policy (`allowFallbackToSubprocess`) -- Strict SDK mode (`strictSdk`) for fail-fast native-only enforcement -- Structured dispatch observability (`onDispatchEvent`) with mode, reason, duration, and outcome - -This keeps callers thin adapters and centralizes transport decisions for SDK publishability. - ### Command Routing Hub (`get-shit-done/bin/lib/command-routing-hub.cjs`) -CJS command family routers migrate to dispatch through `CommandRoutingHub` incrementally. `phase-command-router.cjs` is the first migration (issue #3788); remaining routers (`phases-command-router.cjs`, `roadmap-command-router.cjs`, etc.) continue using `routeCjsCommandFamily` until migrated in follow-up issues. The hub owns three cross-cutting concerns that each router previously duplicated: (1) mode selection (`sdk` when `tryLoadSdk()` succeeds and no `GSD_WORKSTREAM` is active, `cjs` otherwise), set once at construction; (2) a no-throw pure-result contract (`hub.dispatch()` catches all exceptions and returns `{ ok: false, errorKind, message, details }` instead of propagating); and (3) a closed six-value `errorKind` enum exported as the frozen `ERROR_KINDS` object. Router adapters remain thin CLI translators — they build the hub, call `dispatch`, then map the Result to `output()`/`error()` calls. No transparent SDK→CJS fallback: an SDK-mode hub that encounters a load or dispatch failure returns `SdkLoadFailed` or `SdkDispatchFailed` without retrying via CJS. See `docs/adr/0012-command-routing-hub.md`. +CJS command family routers dispatch through `CommandRoutingHub`. The hub owns the no-throw pure-result contract (`hub.dispatch()` catches internal exceptions and returns `{ ok: false, kind, ...typedPayload }`) and the closed runtime error taxonomy (`UnknownCommand`, `InvalidArgs`, `HandlerRefusal`, `HandlerFailure`). Router adapters remain thin CLI translators — they build the hub, call `dispatch`, then map the Result to `output()`/`error()` calls. The runtime is single-path (no dual-runtime mode selection). See `docs/adr/0174-retire-gsd-sdk-package-boundary.md`. ### CLI Tools (`get-shit-done/bin/`) @@ -319,10 +308,10 @@ Node.js CLI utility (`gsd-tools.cjs`) with domain modules split across `get-shit ``` Orchestrator (workflow .md) │ - ├── Load context: gsd-sdk query init. (or legacy gsd-tools.cjs init) + ├── Load context: gsd-tools.cjs init │ Returns JSON with: project info, config, state, phase details │ - ├── Resolve model: gsd-sdk query resolve-model + ├── Resolve model: gsd-tools.cjs resolve-model │ Returns: opus | sonnet | haiku | inherit │ ├── Spawn Agent (Task/SubAgent call) @@ -333,7 +322,7 @@ Orchestrator (workflow .md) │ ├── Collect result │ - └── Update state: gsd-sdk query state.update / state.patch / state.advance-plan (or legacy gsd-tools.cjs) + └── Update state: gsd-tools.cjs state update / state patch / state advance-plan ``` ### Primary Agent Spawn Categories @@ -384,7 +373,7 @@ When the context window is 500K+ tokens (1M-class models like Opus 4.6, Sonnet 4 - **Executor agents** receive prior wave SUMMARY.md files and the phase CONTEXT.md/RESEARCH.md, enabling cross-plan awareness within a phase - **Verifier agents** receive all PLAN.md, SUMMARY.md, CONTEXT.md files plus REQUIREMENTS.md, enabling history-aware verification -The orchestrator reads `context_window` from config (`gsd-sdk query config-get context_window`, or legacy `gsd-tools.cjs config-get`) and conditionally includes richer context when the value is >= 500,000. For standard 200K windows, prompts use truncated versions with cache-friendly ordering to maximize context efficiency. +The orchestrator reads `context_window` from config (`gsd-tools.cjs config-get context_window`) and conditionally includes richer context when the value is >= 500,000. For standard 200K windows, prompts use truncated versions with cache-friendly ordering to maximize context efficiency. #### Parallel Commit Safety diff --git a/docs/CLI-TOOLS.md b/docs/CLI-TOOLS.md index 3ac17f1dc..94bc78c06 100644 --- a/docs/CLI-TOOLS.md +++ b/docs/CLI-TOOLS.md @@ -1,6 +1,6 @@ # GSD CLI Tools Reference -> Surface-area reference for `get-shit-done/bin/gsd-tools.cjs` (legacy Node CLI). Workflows and agents should prefer `gsd-sdk query` or `@opengsd/gsd-sdk` where a handler exists — see [SDK and programmatic access](#sdk-and-programmatic-access). For slash commands and user flows, see [Command Reference](COMMANDS.md). +> Surface-area reference for `get-shit-done/bin/gsd-tools.cjs` (Node CLI). For slash commands and user flows, see [Command Reference](COMMANDS.md). --- @@ -13,7 +13,7 @@ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Shipped path** | `get-shit-done/bin/gsd-tools.cjs` | | **Implementation** | 20 domain modules under `get-shit-done/bin/lib/` (the directory is authoritative) | -| **Status** | Maintained for parity tests and CJS-only entrypoints; `gsd-sdk query` / SDK registry are the supported path for new orchestration (see [QUERY-HANDLERS.md](../sdk/src/query/QUERY-HANDLERS.md)). | +| **Status** | Primary runtime command surface for orchestration, workflows, and automation. | **Usage (CJS):** @@ -29,47 +29,9 @@ node gsd-tools.cjs [args] [--raw] [--cwd ] | -------------- | ---------------------------------------------------------------------------- | | `--raw` | Machine-readable output (JSON or plain text, no formatting) | | `--cwd ` | Override working directory (for sandboxed subagents) | -| `--ws ` | Workstream context (also honored when the SDK spawns this binary; see below) | +| `--ws ` | Workstream context for `.planning/workstreams/` paths | ---- - -## SDK and programmatic access - -Use this when authoring workflows, not when you only need the command list below. - -**1. CLI — `gsd-sdk query `** - -- Resolves argv with the same **longest-prefix** rules as the typed registry (`resolveQueryArgv` in `sdk/src/query/registry.ts`). Unregistered commands **fail fast** — use `node …/gsd-tools.cjs` only for handlers not in the registry. -- Full matrix (CJS command → registry key, CLI-only tools, aliases, golden tiers): [sdk/src/query/QUERY-HANDLERS.md](../sdk/src/query/QUERY-HANDLERS.md). - -**2. TypeScript — `@opengsd/gsd-sdk` (`GSDTools`, `createRegistry`)** - -- `GSDTools` now routes through the **SDK Runtime Bridge Module** (`sdk/src/query-runtime-bridge.ts`). Native registry dispatch is preferred; subprocess fallback is explicit policy (`allowFallbackToSubprocess`) and can be disabled for strict SDK-only execution. -- `strictSdk` mode fails fast when a command has no native adapter, making SDK publish/readiness checks deterministic. -- Structured bridge observability is available via `onDispatchEvent` (dispatch mode, fallback reason, duration, outcome, error kind). -- For direct typed dispatch without `GSDTools`, use `createRegistry()` from `sdk/src/query/index.ts`, or invoke `gsd-sdk query` (see [QUERY-HANDLERS.md](../sdk/src/query/QUERY-HANDLERS.md)). -- Conventions: mutation event wiring, `GSDError` vs `{ data: { error } }`, locks, and stubs — [QUERY-HANDLERS.md](../sdk/src/query/QUERY-HANDLERS.md). - -**CJS → SDK examples (same project directory):** - - -| Legacy CJS | Preferred `gsd-sdk query` (examples) | -| ---------------------------------------- | ------------------------------------ | -| `node gsd-tools.cjs init phase-op 12` | `gsd-sdk query init phase-op 12` | -| `node gsd-tools.cjs phase-plan-index 12` | `gsd-sdk query phase-plan-index 12` | -| `node gsd-tools.cjs state json` | `gsd-sdk query state json` | -| `node gsd-tools.cjs roadmap analyze` | `gsd-sdk query roadmap analyze` | - - -**SDK state reads:** `state.json` and `state.load` are both registered query handlers with parity coverage. You can invoke them through `gsd-sdk query …` and through the SDK Runtime Bridge (`GSDTools` → `sdk/src/query-runtime-bridge.ts`), honoring `allowFallbackToSubprocess` / `strictSdk` and emitting `onDispatchEvent` observability. For direct typed dispatch, use `createRegistry()` from `sdk/src/query/index.ts`. Full routing and golden rules: [QUERY-HANDLERS.md](../sdk/src/query/QUERY-HANDLERS.md). - -**CLI-only (not in registry):** e.g. **graphify**, **from-gsd2** / **gsd2-import** — call `gsd-tools.cjs` until registered. - -**Mutation events (SDK):** `QUERY_MUTATION_COMMANDS` in `sdk/src/query/index.ts` lists commands that may emit structured events after a successful dispatch. Exceptions called out in QUERY-HANDLERS: `state validate` (read-only), `skill-manifest` (writes only with `--write`), `intel update` (stub). - -**Golden parity:** Policy and CJS↔SDK test categories are documented under **Golden parity** in [QUERY-HANDLERS.md](../sdk/src/query/QUERY-HANDLERS.md). - --- ## State Commands @@ -340,7 +302,7 @@ node gsd-tools.cjs init milestone-op node gsd-tools.cjs init map-codebase node gsd-tools.cjs init progress -# Workstream-scoped init (SDK --ws flag) +# Workstream-scoped init (`--ws` flag) node gsd-tools.cjs init execute-phase --ws node gsd-tools.cjs init plan-phase --ws ``` @@ -438,7 +400,7 @@ node gsd-tools.cjs websearch [--limit N] [--freshness day|week|month] ## Graphify -Build, query, and inspect the project knowledge graph in `.planning/graphs/`. Requires `graphify.enabled: true` in `config.json` (see [Configuration Reference](CONFIGURATION.md#graphify-settings)). Graphify is **CJS-only**: `gsd-sdk query` does not yet register graphify handlers — always use `node gsd-tools.cjs graphify …`. +Build, query, and inspect the project knowledge graph in `.planning/graphs/`. Requires `graphify.enabled: true` in `config.json` (see [Configuration Reference](CONFIGURATION.md#graphify-settings)). ```bash # Build or rebuild the knowledge graph @@ -494,10 +456,10 @@ User-facing entry point: `/gsd-graphify` (see [Command Reference](COMMANDS.md#gs `review.models.` maps a reviewer flavor to a shell command invoked by the code-review workflow. Set via [`/gsd-config --integrations`](COMMANDS.md#gsd-config) or directly: ```bash -gsd-sdk query config-set review.models.codex "codex exec --model gpt-5" -gsd-sdk query config-set review.models.gemini "gemini -m gemini-2.5-pro" -gsd-sdk query config-set review.models.opencode "opencode run --model claude-sonnet-4" -gsd-sdk query config-set review.models.claude "" # clear — fall back to session model +node gsd-tools.cjs config-set review.models.codex "codex exec --model gpt-5" +node gsd-tools.cjs config-set review.models.gemini "gemini -m gemini-2.5-pro" +node gsd-tools.cjs config-set review.models.opencode "opencode run --model claude-sonnet-4" +node gsd-tools.cjs config-set review.models.claude "" # clear — fall back to session model ``` Slugs are validated against `[a-zA-Z0-9_-]+`; empty or path-containing slugs are rejected. See [`docs/CONFIGURATION.md`](CONFIGURATION.md#code-review-cli-routing) for the full field reference. @@ -510,6 +472,5 @@ API keys configured via `/gsd-settings` (`brave_search`, `firecrawl`, `exa_searc ## See also -- [sdk/src/query/QUERY-HANDLERS.md](../sdk/src/query/QUERY-HANDLERS.md) — registry matrix, routing, golden parity, intentional CJS differences -- [Architecture](ARCHITECTURE.md) — where `gsd-sdk query` fits in orchestration +- [Architecture](ARCHITECTURE.md) — orchestration and runtime layering - [Command Reference](COMMANDS.md) — user-facing `/gsd-` commands diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 46360b9ce..f662bf83b 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -73,8 +73,6 @@ - [v1.29 Features](#v129-features) - [Windsurf Runtime Support](#56-windsurf-runtime-support) - [Internationalized Documentation](#57-internationalized-documentation) -- [v1.30 Features](#v130-features) - - [GSD SDK](#58-gsd-sdk) - [v1.31 Features](#v131-features) - [Schema Drift Detection](#59-schema-drift-detection) - [Security Enforcement](#60-security-enforcement) @@ -134,7 +132,6 @@ - [Cross-AI Execution Delegation](#110-cross-ai-execution-delegation) - [Architectural Responsibility Mapping](#111-architectural-responsibility-mapping) - [Extract Learnings](#112-extract-learnings) - - [SDK Workstream Support](#113-sdk-workstream-support) - [Context-Window-Aware Prompt Thinning](#114-context-window-aware-prompt-thinning) - [Configurable CLAUDE.md Path](#115-configurable-claudemd-path) - [TDD Pipeline Mode](#116-tdd-pipeline-mode) @@ -155,7 +152,6 @@ - [Update Banner Opt-In](#128-update-banner-opt-in) - [Issue-Driven Orchestration Guide](#129-issue-driven-orchestration-guide) - [Graphify Commit-Based Staleness](#130-graphify-commit-based-staleness) - - [MVP Mode SDK Resolution Layer](#131-mvp-mode-sdk-resolution-layer) - [v1.42.1 Features](#v1421-features) - [Package Legitimacy Gate](#132-package-legitimacy-gate) - [Skill Surface Budgeting](#133-skill-surface-budgeting) @@ -1485,26 +1481,6 @@ Test suite that scans all agent, workflow, and command files for embedded inject --- -## v1.30 Features - -### 58. GSD SDK - -**Command:** Programmatic API (headless) - -**Purpose:** Headless TypeScript SDK for running GSD workflows programmatically without a CLI session. - -**Requirements:** -- REQ-SDK-01: SDK MUST expose GSD workflow operations as TypeScript functions -- REQ-SDK-02: SDK MUST support headless execution without interactive prompts -- REQ-SDK-03: SDK MUST produce the same artifacts as CLI-driven workflows - -**Process:** -1. **Import** — Import GSD SDK into a TypeScript/JavaScript project -2. **Configure** — Set project path and workflow options programmatically -3. **Execute** — Run GSD phases (discuss, plan, execute) via API calls - ---- - ## v1.31 Features ### 59. Schema Drift Detection @@ -1807,7 +1783,7 @@ Test suite that scans all agent, workflow, and command files for embedded inject ### 74. Context Reduction -**Part of:** GSD SDK prompt assembly +**Part of:** prompt assembly pipeline **Purpose:** Reduce context prompt sizes through markdown truncation and cache-friendly prompt ordering. @@ -2474,20 +2450,6 @@ Users who run a memory / knowledge-base MCP server (for example, ExoCortex-style --- -### 113. SDK Workstream Support - -**Command:** `gsd-sdk init @prd.md --ws my-workstream` - -**Purpose:** Route all SDK `.planning/` paths to `.planning/workstreams//`, enabling multi-workstream projects without "Project already exists" errors. The `--ws` flag validates the workstream name and propagates to all subsystems (tools, config, context engine). - -**Requirements:** -- REQ-WS-01: `--ws ` routes all `.planning/` paths to `.planning/workstreams//` -- REQ-WS-02: Without `--ws`, behavior is unchanged (flat mode) -- REQ-WS-03: Name validated to alphanumeric, hyphens, underscores, and dots only -- REQ-WS-04: Config resolves from workstream path first, falls back to root `.planning/config.json` - ---- - ### 114. Context-Window-Aware Prompt Thinning **Purpose:** Reduce static prompt overhead by ~40% for models with context windows under 200K tokens. Extended examples and anti-pattern lists are extracted from agent definitions into reference files loaded on demand via `@` required_reading. @@ -2621,7 +2583,7 @@ Users who run a memory / knowledge-base MCP server (for example, ExoCortex-style - REQ-GRAPH-02: Slash-command `/gsd-graphify` exposes subcommands `build`, `query `, `status`, `diff`. The programmatic CLI `node gsd-tools.cjs graphify …` additionally exposes `snapshot`, which is also invoked automatically as the final step of `graphify build`. - REQ-GRAPH-03: Build runs within the configurable `graphify.build_timeout` (seconds); exceeding the timeout aborts cleanly without leaving a partial graph. - REQ-GRAPH-04: `graphify.cjs` falls back to `graph.links` when `graph.edges` is absent so older graph artifacts keep rendering. -- REQ-GRAPH-05: CJS-only surface; `gsd-sdk query` does not yet register graphify handlers. +- REQ-GRAPH-05: Graphify is invoked through `gsd-tools.cjs graphify ...` command handlers. **Configuration:** `graphify.enabled`, `graphify.build_timeout` **Reference files:** `commands/gsd/graphify.md`, `bin/lib/graphify.cjs` @@ -2684,7 +2646,7 @@ Users who run a memory / knowledge-base MCP server (for example, ExoCortex-style **Requirements:** - REQ-CTX-GUARD-01: `/gsd-health --context` prints a structured status line with current utilization, threshold tier (`ok` / `warn` / `critical`), and a remediation suggestion. -- REQ-CTX-GUARD-02: The same triage is exposed as `gsd-sdk query validate.context --tokens-used --context-window ` — a structured envelope for status-line and hook callers (#125). Both flags are required; the handler returns the same `{ percent, state }` envelope as the pure classifier in REQ-CTX-GUARD-03. +- REQ-CTX-GUARD-02: The same triage is exposed as `gsd-tools.cjs validate context --tokens-used --context-window ` — a structured envelope for status-line and hook callers (#125). Both flags are required; the handler returns the same `{ percent, state }` envelope as the pure classifier in REQ-CTX-GUARD-03. - REQ-CTX-GUARD-03: The classifier (`bin/lib/context-utilization.cjs`) is pure: input `(tokensUsed, contextWindow)`, output `{ percent, state }`. Easy to unit-test, easy to reuse from any caller. **Reference issue:** [#2792](https://github.com/open-gsd/get-shit-done-redux/issues/2792) @@ -2836,27 +2798,6 @@ Source commit: abc1234 (3 commits behind HEAD) --- -### 131. MVP Mode SDK Resolution Layer - -**Purpose:** Replace per-workflow MVP-mode predicate duplication with three canonical SDK query verbs. All consuming workflows now call a single source of truth instead of inlining 4–8 bash lines each. - -**New query verbs:** - -| Verb | Returns | Used by | -|------|---------|---------| -| `gsd-sdk query phase.mvp-mode ` | `{active, source, roadmap_mode, config_mvp_mode, cli_flag_present}` | `plan-phase`, `execute-phase`, `verify-work`, `progress` | -| `gsd-sdk query task.is-behavior-adding ` | `{is_behavior_adding, checks: {tdd_true, has_behavior_block, has_source_files}, reason}` | `gsd-executor` agent | -| `gsd-sdk query user-story.validate ""` | `{valid, slots: {role, capability, outcome}, errors[]}` | `gsd-verifier`, `/gsd-mvp-phase` | - -**Resolution precedence for `phase.mvp-mode`:** -CLI flag → ROADMAP `**Mode:** mvp` → `workflow.mvp_mode` config → `false` - -**Bug fix:** `roadmap.get-phase --pick mode` in the SDK's `roadmap.ts` previously returned `null` for phases with `**Mode:** mvp`, causing MVP_MODE to silently fall through to false on the native dispatch path. Restores parity with the CJS implementation. - -**Reference issue:** [#3178](https://github.com/open-gsd/get-shit-done-redux/pull/3178) - ---- - ## v1.42.1 Features ### 132. Package Legitimacy Gate @@ -3058,7 +2999,7 @@ explicit reviewer flags -> --all -> review.default_reviewers -> all detected rev **CLI:** `gsd-tools --json-errors` -**Purpose:** Give SDK and automation callers stable machine-readable error envelopes. +**Purpose:** Give automation callers stable machine-readable error envelopes. **Behavior:** Commands that fail under `--json-errors` return structured `ok: false` payloads with error kind, message, command context, and exit mapping instead of prose-only stderr. diff --git a/docs/agents/cjs-sdk-seam.md b/docs/agents/cjs-sdk-seam.md deleted file mode 100644 index ba797fb62..000000000 --- a/docs/agents/cjs-sdk-seam.md +++ /dev/null @@ -1,269 +0,0 @@ -# CJS↔SDK Hard-Seam Migration: Complete Reference -## Issue #3575 (Parent: #3524) - ---- - -## Migration overview - -The CJS↔SDK hard-seam migration (#3524) eliminates a class of config-schema drift bugs by introducing single sources of truth at every decision point where CJS and SDK code previously diverged. The migration proceeded in six phases: - -| Phase | PR | Summary | -|-------|----|---------| -| Phase 1 | [#3531](https://github.com/open-gsd/get-shit-done-redux/pull/3531) | `state-document` Shared Module — source-of-truth at `sdk/src/state/` (`index.ts`), generator, freshness check, CJS Adapter (`state-document.generated.cjs`). Worked example for the pattern. | -| Phase 2 | [#3540](https://github.com/open-gsd/get-shit-done-redux/pull/3540) | `configuration` Shared Module — `sdk/shared/config-schema.manifest.json` + `sdk/shared/config-defaults.manifest.json` as data manifests; generator + freshness check + CJS Adapter. | -| Phase 3 | [#3548](https://github.com/open-gsd/get-shit-done-redux/pull/3548) | `workstream-inventory` Shared Module — source-of-truth at `sdk/src/workstream/`, builder, generator, freshness check, CJS Adapter. | -| Phase 4 | [#3554](https://github.com/open-gsd/get-shit-done-redux/pull/3554) | `project-root` Shared Module — source-of-truth at `sdk/src/project-root/`, generator, freshness check, CJS Adapter. | -| Phase 5.0 | [#3558](https://github.com/open-gsd/get-shit-done-redux/pull/3558) | `runtime-bridge-sync` worker — enables CJS-side execution of SDK native handlers; state.* family initial router delegation via `executeForCjs`. | -| Phase 5.1 | [#3574](https://github.com/open-gsd/get-shit-done-redux/pull/3574) | `state.*` router delegation complete — all known state subcommands delegated via `executeForCjs`; Phase 5.0 worker bug fix. | -| Phase 6 | [#3577](https://github.com/open-gsd/get-shit-done-redux/pull/3577) (closes [#3575](https://github.com/open-gsd/get-shit-done-redux/issues/3575)) | Enforcement hardening + Final completion — hand-sync drift lint, CODEOWNERS, 6 family-router migrations, 5 Shared Module migrations (plan-scan, secrets, schema-detect, decisions, workstream-name-policy), workstream native support, parity fixes. Migration feature-complete: 22 cooperating siblings, 0 backlog pairs. | - ---- - -## Phase 6 Retrospective: 15 config-schema drift bugs - -This section captures 15 recurring config-schema drift bugs that motivated the migration. For each, we record what drifted, the surgical fix, and which Phase 6 enforcement layer would have prevented it. - ---- - -### #1535 — Silent failure on unrecognized config.json keys -- **Drifted:** `loadConfig` silently ignored any top-level key in `.planning/config.json` not in `VALID_CONFIG_KEYS`, giving users no feedback when hand-edited or external-tool-added keys had no effect. -- **Fix landed:** PR #1542 — added stderr warning listing unrecognized keys. -- **Would have been blocked by:** **handsync lint** — a seam-aware linter would forbid having parallel hand-authored config validators (CJS `config.cjs` and SDK `config-mutation.ts`) that could silently diverge. - ---- - -### #1542 — fix(config): warn on unrecognized keys in config.json instead of silent drop -- **Drifted:** No drift in this bug itself; it *fixed* #1535's silent-drop behavior by adding the warning. -- **Fix landed:** PR #1542 — merged as the direct fix for #1535. -- **Would have been blocked by:** **per-Module drift lint** (freshness check on config validation) — both CJS and SDK config paths would be regenerated from a single source-of-truth schema module, eliminating the silent-drop risk. - ---- - -### #2047 — bug: config-set rejects intel.enabled despite being a documented config key -- **Drifted:** `intel.enabled` was documented in workflows and gated in runtime code (`intel.cjs:58`), but missing from `VALID_CONFIG_KEYS` in `config.cjs`, so `config-set` rejected it. -- **Fix landed:** PR #2021 — added `intel.enabled` to `VALID_CONFIG_KEYS` in CJS. -- **Would have been blocked by:** **handsync lint** — linter would enforce that every config key gated in runtime code or documented in workflows must appear in the validator allowlist. - ---- - -### #2052 — fix(config): add intel.enabled to VALID_CONFIG_KEYS -- **Drifted:** Same as #2047 (missing from allowlist). -- **Fix landed:** PR #2021 (same PR as #2047 fix). -- **Would have been blocked by:** **handsync lint** — same as #2047. - ---- - -### #2638 — bug: loadConfig writes sub_repos to top-level, then warns it's unknown -- **Drifted:** After #2561 canonicalized `sub_repos` to `planning.sub_repos`, the legacy migration and filesystem auto-sync in `loadConfig` still wrote to top-level `parsed.sub_repos`, which was then flagged as unknown. -- **Fix landed:** PR #2668 — rewrote both paths to target `parsed.planning.sub_repos` and deleted stale top-level copy. -- **Would have been blocked by:** **per-Module drift lint** (freshness check for config shape) — the canonical location for `sub_repos` would be codified in a schema, and any code path writing to it would be verified against that schema at lint time. - ---- - -### #2655 — fix(core): write sub_repos to planning.sub_repos, not top-level -- **Drifted:** Same as #2638. -- **Fix landed:** PR #2668 (same as #2638 fix). -- **Would have been blocked by:** **per-Module drift lint** — same as #2638. - ---- - -### #2653 — bug: SDK config-set rejects documented config keys accepted by CJS config-set -- **Drifted:** SDK's `config-mutation.ts` had a hand-maintained `VALID_CONFIG_KEYS` set that had drifted **28 keys** behind CJS's `config-schema.cjs`, so documented commands like `gsd-sdk query config-set planning.sub_repos` were rejected. -- **Fix landed:** PR #2670 — extracted shared `sdk/src/query/config-schema.ts` module mirroring CJS exactly; added parity test to fail on future drift. -- **Would have been blocked by:** **manifest data isolation** — the config schema would live in one place (e.g., `sdk/shared/config.manifest.json`), and both CJS and SDK would read it, eliminating the possibility of independent drift. - ---- - -### #2670 — fix(#2653): eliminate SDK↔CJS config-schema drift -- **Drifted:** Same as #2653 (28-key drift). -- **Fix landed:** PR #2670 (same as #2653 fix). -- **Would have been blocked by:** **manifest data isolation** — same as #2653. - ---- - -### #2687 — bug: loadConfig warns on valid dynamic-pattern containers in .planning/config.json -- **Drifted:** Keys like `review.models.` were registered in `config-schema.cjs`'s `DYNAMIC_KEY_PATTERNS` but absent from the hand-maintained `KNOWN_TOP_LEVEL` set in `core.cjs`, causing false-positive "unknown key" warnings. -- **Fix landed:** PR #2706 — added `topLevel` field to `DYNAMIC_KEY_PATTERNS` entries; derived `KNOWN_TOP_LEVEL` from schema instead of maintaining it manually. -- **Would have been blocked by:** **per-Module drift lint** — the validator that builds `KNOWN_TOP_LEVEL` would be regenerated from the schema each run, not hand-maintained. - ---- - -### #2706 — fix(#2687): loadConfig no longer warns on valid dynamic-pattern containers -- **Drifted:** Same as #2687 (false warnings on valid dynamic keys). -- **Fix landed:** PR #2706 (same as #2687 fix). -- **Would have been blocked by:** **per-Module drift lint** — same as #2687. - ---- - -### #2798 — context_window missing from VALID_CONFIG_KEYS -- **Drifted:** `context_window` was documented in workflows and read in SDK runtime (`init.js:190`, `validate.js:575`), but missing from allowlists in both `config-mutation.ts` and `config-schema.cjs`, so writes were rejected. -- **Fix landed:** PR #2816 — added `context_window` to `VALID_CONFIG_KEYS` in both SDK and CJS. -- **Would have been blocked by:** **handsync lint** — linter would enforce that every key read at runtime must be in the allowlist. - ---- - -### #2816 — fix(#2798): add context_window to VALID_CONFIG_KEYS allowlist -- **Drifted:** Same as #2798 (missing from allowlists). -- **Fix landed:** PR #2816 (same as #2798 fix). -- **Would have been blocked by:** **handsync lint** — same as #2798. - ---- - -### #3055 — bug: top-level branching_strategy silently becomes "none" -- **Drifted:** `.planning/config.json` with top-level `branching_strategy: "phase"` was flagged as unknown and dropped by validator, causing `loadConfig` to fall back to the `"none"` default, so phase commits landed on the operator's current branch instead of creating `gsd/phase-{N}` branches. -- **Fix landed:** PR #3116 — SDK-side only; added legacy normalization in `mergeDefaults()` to graft top-level value into canonical `git.branching_strategy` slot before validation. -- **Would have been blocked by:** **per-Module drift lint** — the canonical location for `branching_strategy` would be codified in schema; validator would not strip the value before migrations had a chance to run, or CJS and SDK would share the same migration code. - ---- - -### #3116 — fix: normalize legacy top-level branching_strategy into git config -- **Drifted:** Same as #3055 (legacy top-level shape not normalized before validator strips it). -- **Fix landed:** PR #3116 (SDK-side normalization in `mergeDefaults()`). -- **Would have been blocked by:** **per-Module drift lint** — same as #3055, but SDK-side fix would be shared with CJS via seam layer instead of being ported separately. - ---- - -### #3523 — bug: CJS loadConfig warns top-level branching_strategy 'will be ignored', but actively reads it -- **Drifted:** After PR #3116 fixed the SDK side, the CJS path still emitted false "will be ignored" warnings on the same legacy top-level key, because `KNOWN_TOP_LEVEL` derivation extracted top-level names from `VALID_CONFIG_KEYS` (which contains `'git.branching_strategy'` but not `'branching_strategy'`), and the warning was factually incorrect — `core.cjs:485` does read the legacy value via fallback logic. -- **Fix landed:** PR #3527 — added `'branching_strategy'` to the `KNOWN_TOP_LEVEL` hand-maintained list under the deprecated-keys bucket, suppressing the false warning. -- **Would have been blocked by:** **runtime-bridge delegation** — if CJS and SDK config loading shared a common normalization routine (via `executeForCjs` or a shared seam module), the SDK fix in #3116 would automatically apply to CJS; no separate CJS-side warning would be possible. - ---- - -## Surprises - -None. All 15 bugs are genuine CJS↔SDK schema/validation drift, exactly the class the seam migration prevents. - -## Phase 6 Enforcement Summary - -The seam migration introduces these layers: - -1. **handsync lint** (`scripts/lint-shared-module-handsync.cjs`) — Forbids parallel hand-authored validator modules; catches #1535, #2047, #2798. -2. **freshness check** (`sdk/scripts/check--fresh.mjs`) — Regenerates config validators from schema each run; catches #2687, #3055. -3. **manifest data isolation** (`sdk/shared/*.manifest.json`) — Single source-of-truth for schema; catches #2653. -4. **per-Module drift lint** — Combination of freshness checks and schema-derived allowlists; catches #2638, #2687, #3055. -5. **runtime-bridge delegation** (`executeForCjs` + shared seam modules) — Eliminates parallel CJS/SDK implementations; catches #3523 by preventing separate CJS warning logic. - -Together, these layers eliminate the 15-bug class by enforcing single sources of truth at each decision point. - ---- - -## Guide: Adding a new Shared Module - -Use this when you want to extract a new piece of data or logic that both CJS and SDK currently duplicate hand-by-hand. Phase 1's `state-document` migration is the worked example. - -**Step 1 — Create the source-of-truth file** - -```text -sdk/src//index.ts -``` - -This is the canonical definition. It may export a schema, a set of keys, a type, or a data object. It must not import from CJS or from generated files. - -**Step 2 — Write the generator script** - -```text -sdk/scripts/gen-.mjs -``` - -The generator reads `sdk/src//index.ts` (or `sdk/shared/.manifest.json` for pure-data manifests), produces a generated output file (either `sdk/src/.generated.ts` or `get-shit-done/bin/lib/.generated.cjs`), and exits 0. It must be idempotent: running it twice produces the same output. - -**Step 3 — Write the freshness check** - -```text -sdk/scripts/check--fresh.mjs -``` - -The freshness check re-runs the generator into a temp location, diffs against the committed file, and exits 1 with a clear message if they diverge. This is what CI runs. - -**Step 4 — Write the parity test** (optional but recommended) - -```text -tests/-parity.test.cjs -``` - -Assert that the CJS Adapter and the SDK source-of-truth agree on every field that matters (key sets, defaults, schema shape). This test catches generator bugs that the freshness check cannot. - -**Step 5 — Wire CI** - -Add a step in `.github/workflows/test.yml` after the existing freshness-check block (before "Run tests with coverage"), gated on `matrix.os == 'ubuntu-latest' && matrix.node-version == 24`: - -```yaml -- name: SDK generated artifact drift check - if: matrix.os == 'ubuntu-latest' && matrix.node-version == 24 - shell: bash - run: node sdk/scripts/check--fresh.mjs -``` - -**Step 6 — Run inventory regen** - -If the module affects `CONTEXT.md`'s module inventory, update that section. Also update `scripts/shared-module-handsync-allowlist.json`: move any matching entry from `migrateMeBacklog` to `cooperatingSiblings` (or remove it entirely if the CJS hand-copy is now deleted). - -**Step 7 — Update CODEOWNERS** - -Add the new source-of-truth path to `.github/CODEOWNERS` under the Phase 6 block to make the architectural ownership explicit. - -**Reference:** Phase 1 PR [#3531](https://github.com/open-gsd/get-shit-done-redux/pull/3531) — `state-document` migration. - ---- - -## Guide: Adding a new canonical command - -Use this when adding a new `gsd-sdk query .` that should be handled natively in the SDK (not delegated to CJS). Phase 5.1's `state.update` migration (PR [#3574](https://github.com/open-gsd/get-shit-done-redux/pull/3574)) is the worked example. - -**Step 1 — Declare in the command manifest** - -Add the command definition to `sdk/src/query/command-manifest..ts`. Include the full argument schema and a `handler` reference. - -**Step 2 — Implement the SDK handler** - -Write the handler in `sdk/src/query/.ts` (or inline in the manifest file for simple cases). The handler receives validated args and the runtime context; it must not shell out to CJS. - -**Step 3 — Add CJS router delegate (Phase 5.1+ pattern)** - -In the family's CJS command router (e.g. `get-shit-done/bin/lib/state-command-router.cjs`), add a delegate case that calls `executeForCjs(subcommand, args)` from `cjs-command-router-adapter.cjs`. This ensures the CJS binary dispatches to the SDK native handler rather than re-implementing the logic. - -**Step 4 — Add a golden parity test** - -Add a test in `tests/-command-router.test.cjs` (or a new file if the family has no test yet) that: -1. Invokes the command via the SDK query path. -2. Invokes the command via the CJS router path. -3. Asserts both produce identical output. - -This test enforces that the delegate and the native handler stay aligned. - -**Reference:** Phase 5.1 PR [#3574](https://github.com/open-gsd/get-shit-done-redux/pull/3574) — `state.update` delegation. - ---- - -## Phase 6 Final Completion Summary - -Phase 6 (issue #3575, PR #3577) is feature-complete. The migration is done. - -**What shipped in Phase 6:** - -- **Shared Modules migrated (5 total in Phase 6):** `plan-scan`, `secrets`, `schema-detect`, `decisions`, `workstream-name-policy`. Each follows the full pattern: SDK source-of-truth, generator (`gen-.mjs`), freshness check (`check--fresh.mjs`), generated CJS artifact (`.generated.cjs`), CJS shim re-export, parity test, CI step, pre-commit hook, CODEOWNERS entry. -- **Workstream native support:** The sync bridge worker now correctly threads `workstream` through to `registry.dispatch()`. `GSDTransport` no longer forces subprocess for workstream-scoped requests. Workstream-scoped state commands execute natively. -- **State parity divergences resolved:** `state.record-metric` and `state.prune` SDK handlers now match CJS semantics exactly. -- **MIGRATE_ME pairs resolved:** `decisions` and `workstream-name-policy` migrated from `migrateMeBacklog` to `cooperatingSiblings` as ADAPTER-OVER-MODULE. -- **Lint final state:** 22 cooperating siblings, 0 backlog pairs. - -**Decisions migration specifics (B1):** -- SDK `decisions.ts` regex aligned to CJS: `D-([A-Za-z0-9_-]+)` (alphanumeric IDs like `D-INFRA-01` accepted). -- SDK returns richer `{id, text, category, tags, trackable}`; CJS callers using only `{id, text}` safely ignore extras. -- Parity test: `tests/decisions-generator.test.cjs` (15 tests covering numeric IDs, alphanumeric IDs, richer schema fields). - -**Workstream-name-policy migration specifics (B2):** -- Added `hasInvalidPathSegment` and `isValidActiveWorkstreamName` to SDK `workstream-name-policy.ts`. -- `validateWorkstreamName` is now an alias for `isValidActiveWorkstreamName` (consistent with CJS semantics). -- Parity test: `tests/workstream-name-policy-generator.test.cjs` (19 tests covering all four exports). - ---- - -## Open follow-ups - -No migration items remain. The following are future quality candidates, not defects: - -- **`config.cjs` / `sdk/src/config.ts`** — These files are CJS-CLI-ONLY (per allowlist classification). The `config.cjs` file contains only CLI command handlers that use sync CJS APIs; `sdk/src/config.ts` provides the async SDK layer. They serve disjoint surfaces. A future migration would require converting the CLI handlers to async + SDK patterns, which is a larger refactor out of scope for this migration cycle. -- **`intel.cjs` / `sdk/src/query/intel.ts`** — Intentional architectural divergence (different file naming conventions between CJS and SDK; documented in allowlist). A future migration would require reconciling INTEL_FILES naming, which is a breaking change for existing consumers. -- **`model-catalog.cjs` / `sdk/src/model-catalog.ts`** — Both sides read from `sdk/shared/model-catalog.json` independently (ADAPTER-OVER-MODULE pattern). This is intentional; the shared JSON is the source-of-truth. No duplication of logic between CJS and SDK consumers. diff --git a/docs/gsd-sdk-query-migration-blurb.md b/docs/gsd-sdk-query-migration-blurb.md deleted file mode 100644 index 9eac9bde6..000000000 --- a/docs/gsd-sdk-query-migration-blurb.md +++ /dev/null @@ -1,22 +0,0 @@ -# GSD SDK query migration (summary blurb) - -Copy-paste friendly for Discord and GitHub comments. - ---- - -**@opengsd/gsd-sdk** replaces the untyped, monolithic `gsd-tools.cjs` subprocess with a typed, tested, registry-based query system and **`gsd-sdk query`**, giving GSD structured results, classified errors (`GSDError` with `ErrorClassification`), and golden-verified parity with the old CLI. That gives the framework one stable contract instead of a fragile, very large CLI that every workflow had to spawn and parse by hand. - -**What users can expect** - -- Same GSD commands and workflows they already use. -- Snappier runs (less Node startup on chained tool calls). -- Fewer mysterious mid-workflow failures and safer upgrades, because behavior is covered by tests and a single stable contract. -- Stronger predictability: outputs and failure modes are consistent and explicit. - -**Cost and tokens** - -The SDK does not automatically reduce LLM tokens per model call. Savings show up indirectly: fewer ambiguous tool results and fewer retry or recovery loops, which often lowers real-world session cost and wall time. - -**Agents then vs now** - -Agents always followed workflow instructions. What improved is the surface those steps run on. Before, workflows effectively said to shell out to `gsd-tools.cjs` and interpret stdout or JSON with brittle assumptions. Now they point at **`gsd-sdk query`** and typed handlers that return the shapes prompts expect, with clearer error reasons when something must stop or be fixed, so instruction following holds end to end with less thrash from bad parses or silent output drift.