@hegemonart/get-design-done 1.55.0 → 1.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +90 -0
  4. package/README.md +6 -0
  5. package/SKILL.md +2 -0
  6. package/agents/design-fixer.md +16 -0
  7. package/dist/claude-code/.claude/skills/override/SKILL.md +86 -0
  8. package/dist/claude-code/.claude/skills/state/SKILL.md +106 -0
  9. package/hooks/gdd-decision-injector.js +58 -0
  10. package/hooks/gdd-fact-force.js +434 -0
  11. package/hooks/gdd-risk-gate.js +406 -0
  12. package/hooks/hooks.json +18 -0
  13. package/package.json +1 -1
  14. package/reference/schemas/events.schema.json +61 -1
  15. package/reference/skill-graph.md +3 -1
  16. package/scripts/lib/manifest/skills.json +16 -0
  17. package/scripts/lib/risk/calibration.cjs +385 -0
  18. package/scripts/lib/risk/compute-risk.cjs +229 -0
  19. package/scripts/lib/risk/consumers.cjs +211 -0
  20. package/scripts/lib/risk/override.cjs +87 -0
  21. package/scripts/lib/risk/route.cjs +59 -0
  22. package/scripts/lib/risk/tables.cjs +221 -0
  23. package/scripts/lib/state/migrate-to-sqlite.cjs +664 -0
  24. package/scripts/lib/state/query-surface.cjs +391 -0
  25. package/scripts/lib/state/render-markdown.cjs +717 -0
  26. package/scripts/lib/state/state-backend.cjs +345 -0
  27. package/scripts/lib/state/state-store.cjs +735 -0
  28. package/sdk/cli/index.js +193 -96
  29. package/sdk/dashboard/data/source.cjs +44 -5
  30. package/sdk/mcp/gdd-state/server.js +127 -30
  31. package/sdk/mcp/gdd-state/tools/get.ts +8 -0
  32. package/sdk/state/index.ts +267 -13
  33. package/sdk/state/lockfile.ts +48 -0
  34. package/sdk/state/schema.sql +218 -0
  35. package/skills/override/SKILL.md +86 -0
  36. package/skills/state/SKILL.md +106 -0
@@ -5,14 +5,14 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "Get Design Done — 5-stage agent-orchestrated design pipeline with 9 connections, handoff-first workflow, bidirectional Figma write-back, 22+ specialized agents, queryable knowledge layer (intel store, dependency analysis, learnings extraction), and a self-improvement loop (reflector, frontmatter + budget feedback, global-skills layer). v1.20.0 ships the SDK foundation: gdd-state MCP server (11 typed tools), lockfile-safe STATE.md mutations, event stream, and resilience primitives (jittered-backoff, rate-guard, error-classifier, iteration-budget) for rate-limit + 429 + context-overflow recovery. Full CI/CD pipeline (Node 22/24 × Linux/macOS/Windows) and release automation (auto-tag + GitHub Release + release-time smoke test).",
8
- "version": "1.55.0"
8
+ "version": "1.57.0"
9
9
  },
10
10
  "plugins": [
11
11
  {
12
12
  "name": "get-design-done",
13
13
  "source": "./",
14
14
  "description": "Agent-orchestrated 5-stage design pipeline: Brief → Explore → Plan → Design → Verify. 22+ specialized agents, 9 connections (Figma, Refero, Preview, Storybook, Chromatic, Figma Writer, Graphify, Pinterest, Claude Design), Claude Design handoff, bidirectional Figma write-back, and a queryable intel store (.design/intel/) for dependency and learnings queries. Standalone commands: style, darkmode, compare, figma-write, graphify, handoff, analyze-dependencies, skill-manifest, extract-learnings. Embeds NNG heuristics, WCAG thresholds, typographic systems, motion framework, and anti-pattern catalog. Ships with a full CI/CD pipeline (Node 22/24 × Linux/macOS/Windows) and release automation. Optimization layer (v1.0.4.1, retroactive): gdd-router + gdd-cache-manager skills, PreToolUse budget-enforcer hook, tier-aware agent frontmatter, lazy checker gates, streaming synthesizer, /gdd:warm-cache + /gdd:optimize commands, and cost telemetry at .design/telemetry/costs.jsonl — targeting 50-70% per-task token-cost reduction with no quality-floor regression. v1.20.0 SDK foundation: gdd-state MCP server (11 typed tools), lockfile-safe STATE.md mutations, event stream at .design/telemetry/events.jsonl, resilience primitives (jittered-backoff, rate-guard, error-classifier, iteration-budget) with rate-limit + 429 + context-overflow recovery, and TypeScript toolchain.",
15
- "version": "1.55.0",
15
+ "version": "1.57.0",
16
16
  "author": {
17
17
  "name": "hegemonart"
18
18
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "get-design-done",
3
3
  "short_name": "gdd",
4
- "version": "1.55.0",
4
+ "version": "1.57.0",
5
5
  "description": "Agent-orchestrated 5-stage design pipeline: Brief → Explore → Plan → Design → Verify. 59 specialized agents, 88 skills, 41 connection integrations (Figma, Refero, Preview, Storybook, Chromatic, Graphify, Slack, Linear, Jira, Notion, and more), handoff-first workflow via Claude Design bundles, bidirectional Figma write-back (annotations, Code Connect), queryable intel store (`.design/intel/`) for O(1) design surface lookups, and self-improvement loop (reflector agent, frontmatter + budget feedback, global-skills layer at `~/.claude/gdd/global-skills/`). Standalone commands: style, darkmode, compare, figma-write, graphify, handoff, analyze-dependencies, skill-manifest, extract-learnings, reflect, apply-reflections. Embeds NNG heuristics, WCAG thresholds, typographic systems, motion framework, and anti-pattern catalog. Ships with a full CI/CD pipeline (Node 22/24 × Linux/macOS/Windows, lint + schema + frontmatter + stale-ref + shellcheck + gitleaks + injection-scan + blocking size-budget) and release automation (auto-tag + GitHub Release + release-time smoke test). Optimization layer (v1.0.4.1, retroactive): gdd-router + gdd-cache-manager skills, PreToolUse budget-enforcer hook, tier-aware agent frontmatter, lazy checker gates, streaming synthesizer, /gdd:warm-cache + /gdd:optimize commands, and cost telemetry at .design/telemetry/costs.jsonl — targeting 50-70% per-task token-cost reduction with no quality-floor regression. v1.20.0 SDK foundation: gdd-state MCP server (11 typed tools), lockfile-safe STATE.md mutations, event stream at .design/telemetry/events.jsonl, resilience primitives (jittered-backoff, rate-guard, error-classifier, iteration-budget) with rate-limit + 429 + context-overflow recovery, and TypeScript toolchain. v1.27.7 ships gdd-mcp (Phase 27.7): 12 read-only MCP tools for sub-3s priming. v1.28.0 (Phase 28): Foundational References Tier 2 — 5 new reference files (color-theory, composition, proportion-systems, i18n, contrast-advanced), 2 verifier i18n probes + 1 explore i18n-readiness probe, 12 additive cross-link insertions across 10 existing references, 2 orthogonal audit-scoring lens-tags (composition_alignment + i18n_readiness).",
6
6
  "author": {
7
7
  "name": "hegemonart",
package/CHANGELOG.md CHANGED
@@ -4,6 +4,96 @@ All notable changes to get-design-done are documented here. Versions follow [sem
4
4
 
5
5
  ---
6
6
 
7
+ ## [1.57.0] - 2026-06-03
8
+
9
+ ### Phase 57 - SQLite State Backbone (Cross-Session Query Layer)
10
+
11
+ GDD project state lives in per-file markdown (STATE.md blocks, recall, instincts). Cross-cycle queries ("every decision
12
+ tagged accessibility across the last five cycles") require fan-out greps and are effectively infeasible. Phase 57 adds an
13
+ opt-in `.design/state.sqlite` as an indexed query layer over that state, while markdown stays the human-editable source of
14
+ truth. It is **built with zero new dependency**: SQLite is reached through the existing opportunistic
15
+ `probeOptional('better-sqlite3')` runtime probe (the same pattern Phase 51 uses for the instinct store), with a guaranteed
16
+ markdown / JS-scan fallback whenever the module is absent. Migration is opt-in (`--migrate-state`) in v1.57.0, dual-writes
17
+ for one minor version, and is fully reversible (`/gdd:state demigrate`). When better-sqlite3 is not installed, GDD behaves
18
+ exactly as before. Planned and executed via the GSD pipeline (3 + 1 + 2 parallel executors with one reconciliation pass).
19
+
20
+ ### Breaking changes
21
+
22
+ - **Opt-in SQLite state backbone.** Running `node scripts/lib/state/migrate-to-sqlite.cjs --migrate-state` builds
23
+ `.design/state.sqlite` (14 tables plus FTS5) from your STATE.md. After migration, state mutations dual-write: SQLite is
24
+ the authoritative store and STATE.md is rendered from it byte-for-byte (the existing `gdd-state` `read`/`mutate`/`transition`
25
+ API is unchanged). Without migration, or when better-sqlite3 is absent, nothing changes - markdown stays authoritative.
26
+ Markdown is always human-editable; a hand-edit is detected on the next write and folded back into SQLite.
27
+ - **New `/gdd:state` skill** with three subcommands: `query "<sql>"` (engine-level read-only SELECT over the
28
+ decisions/blockers/plans tables), `recover` (rebuild a corrupt `state.sqlite` from markdown), and `demigrate` (drop
29
+ `state.sqlite` and fall back to the markdown-only source of truth).
30
+
31
+ ### Added
32
+
33
+ - **`scripts/lib/state/`** - `state-backend.cjs` (`probeOptional('better-sqlite3')` + FTS5 probe -> `{Database, BACKEND}`;
34
+ WAL / busy_timeout / foreign_keys pragmas; engine-level readonly opens), `state-store.cjs` (dual-backend dispatch; the
35
+ SQLite-authoritative -> render-markdown -> write-STATE.md transaction; hand-edit freshness guard), `migrate-to-sqlite.cjs`
36
+ (idempotent UPSERT migration, `--migrate-state` opt-in, `--dry-run`), `render-markdown.cjs` (byte-equal STATE.md
37
+ reconstruction from SQLite via the proven serializer), `query-surface.cjs` (readonly SQL + first-token denylist, recover,
38
+ demigrate, cap-10 `.bak` rotation).
39
+ - **`sdk/state/schema.sql`** - 14 tables (state_position, decisions, blockers, must_haves, plans, findings, design_debt,
40
+ recall_records, instincts, sessions, worktree_state, conflict_incidents, plus `_meta`/`_block_meta`) with FTS5 virtual
41
+ tables on decisions/findings/recall/instincts.
42
+ - **Consumers read SQLite when migrated** - `gdd_state__get` and the dashboard data plane read SQLite-direct (markdown
43
+ scrape fallback; the MCP tool schema is unchanged), and the Phase 56 fact-force gate gains an FTS5 tier-0 lookup with the
44
+ grep fallback intact.
45
+
46
+ ### Changed
47
+
48
+ - **`sdk/state/index.ts`** routes `read`/`mutate`/`transition` through the SQLite dual-write path only when migration is
49
+ active for the resolved state file (a sibling `state.sqlite` exists); otherwise the markdown path runs byte-identically.
50
+ The new SQLite sibling lock (`state.sqlite.lock`) is always acquired before `STATE.md.lock`.
51
+
52
+ ## [1.56.0] - 2026-06-03
53
+
54
+ ### Phase 56 - Risk-Scoring + Fact-Forcing Gate (Quantified Action Confidence)
55
+
56
+ Every writer action now carries a quantified risk score instead of a binary allow/deny. Phase 56 adds a pure,
57
+ deterministic risk scorer (no I/O, frozen tables) that grades each Write / Edit / MultiEdit / Bash by tool, file
58
+ sensitivity, and input shape, then routes it through two PreToolUse hooks: a risk gate that emits a `risk_assessment`
59
+ event and blocks only genuinely dangerous actions, and a fact-force gate that holds the FIRST write to a file until its
60
+ graph consumers and recorded decisions have actually been read. Both are **dep-free** (a maintainer Rule-4 decision: a
61
+ pure scorer plus static tables, no ML, no new dependency). The gate softens to a warning whenever the Phase 52
62
+ DesignContext graph is absent, so greenfield projects are never over-blocked. A new `/gdd:override` escalation skill
63
+ clears a block or a fact-force hold with an approver and reason (audit-trailed as a `D-XX` override decision), and
64
+ `design-fixer` gains a confidence-times-risk routing step. Planned and executed via the GSD pipeline (3 + 2 parallel
65
+ executors).
66
+
67
+ ### Breaking changes
68
+
69
+ - **Writer actions are now risk-gated.** A new PreToolUse hook (`hooks/gdd-risk-gate.js`, matcher
70
+ `Write|Edit|MultiEdit|Bash`) scores every writer action and blocks the few that score at or above 0.85 (destructive
71
+ bash, high-sensitivity-file rewrites). Blocking uses the house-style `{continue:false, stopReason}` contract; `allow`
72
+ is silent, `review` and `require_confirmation` attach advisory context for the agent to surface. Read-only agents are
73
+ allowlisted through.
74
+ - **The first write to a file is fact-forced.** A second PreToolUse hook (`hooks/gdd-fact-force.js`, matcher
75
+ `Edit|Write|MultiEdit`) holds the first mutation of a file until its DesignContext consumers and any recorded
76
+ decisions or blockers for it have been Read this session. The hold is soft (a `stopReason` listing the missing facts)
77
+ and softens to a warning when no graph exists; clear it deliberately with `/gdd:override factforce <path>`.
78
+
79
+ ### Added
80
+
81
+ - **Risk scorer** `scripts/lib/risk/` - `compute-risk.cjs` (`computeRisk(tool, input) -> {score, reasons, suggested_action, breakdown}`,
82
+ pure and deterministic), `tables.cjs` (frozen BASE_TOOL_RISK / FILE_SENSITIVITY / INPUT_PATTERN_RISK / THRESHOLDS,
83
+ config-overridable extend-only), `route.cjs` (`route(confidence, action) -> auto|confirm|skip|override`),
84
+ `consumers.cjs` (best-effort file-to-node consumers lookup, soften-if-absent), `calibration.cjs` (rolling-50 per-agent
85
+ calibration plus drift detection feeding the bandit reward), `override.cjs`.
86
+ - **`/gdd:override`** - escalation surface for a risk-gate block or a fact-force hold; writes a `D-XX` override-tagged
87
+ decision (audit trail) or clears the `checked[path]` lock, always with an approver and reason.
88
+ - **`risk_assessment` event type** in `reference/schemas/events.schema.json` (score, suggested_action, reasons),
89
+ surfaced by the Phase 55 dashboard risk pane.
90
+ - **`design-fixer` Step 2.5** - a confidence-times-risk routing filter (auto-apply / confirm-with-diff / skip / escalate).
91
+
92
+ ### Changed
93
+
94
+ - **`hooks/gdd-decision-injector.js`** now records per-file reads so the fact-force gate can tell which files you have
95
+ legitimately reviewed this session.
96
+
7
97
  ## [1.55.0] - 2026-06-03
8
98
 
9
99
  ### Phase 55 - GDD Dashboard (Multi-Harness Control Plane + Graph Visualization + Session Surface)
package/README.md CHANGED
@@ -271,6 +271,10 @@ All 14 runtimes receive their native artifact layout (`skills/`, `command/`, `ag
271
271
 
272
272
  **GDD dashboard (v1.55.0).** A read-only multi-harness control plane. `gdd-dashboard` opens a terminal TUI with five panes (sessions per runtime, current cycle, cost telemetry, findings, a DesignContext tree); `gdd dashboard --web` opens an interactive browser view of the Phase 52 graph (layered Atomic/Molecular/Organism/Template layout, pan/zoom, click-to-inspect, type/tag filters, find-consumers highlight, PNG export, minimap). It is **built fully dep-free** (a maintainer decision over the roadmap's Ink + React Flow + Vite stack, which would have added ~100 packages): the TUI is a hand-rolled ANSI renderer, the graph view is a self-contained HTML file (inline SVG + vanilla JS, extending the export builder), and the data plane reads GDD state through the existing shared libraries in-process. Read-only by design (the action surface is open-file / copy-command / run-skill); the `--web` server is a local loopback that serves to your own browser and exits. **No new runtime dependency.**
273
273
 
274
+ **Risk-scoring and fact-forcing gate (v1.56.0).** Writer actions now carry a quantified risk score instead of a binary allow/deny. A pure, deterministic scorer (`scripts/lib/risk/compute-risk.cjs`, frozen tables, no I/O) grades each Write / Edit / MultiEdit / Bash by tool, file sensitivity, and input shape, then two PreToolUse hooks act on it: `gdd-risk-gate.js` emits a `risk_assessment` event and blocks only the genuinely dangerous actions (destructive bash, high-sensitivity-file rewrites at or above 0.85), while `gdd-fact-force.js` holds the first write to a file until its DesignContext consumers and recorded decisions have actually been read this session. The fact-force hold is soft and softens to a warning when the Phase 52 graph is absent, so greenfield projects are never over-blocked. `/gdd:override` clears a block or a fact-force hold with an approver and reason (audit-trailed as a `D-XX` override decision), and `design-fixer` routes findings by confidence times risk. **Built dep-free** (a maintainer decision: a pure scorer plus static tables, no ML). **No new runtime dependency.**
275
+
276
+ **SQLite state backbone (v1.57.0).** Project state (decisions, blockers, plans, findings, recall, instincts) lives in per-file markdown, which makes cross-cycle queries ("every accessibility decision across the last five cycles") infeasible. Phase 57 adds an opt-in `.design/state.sqlite` as an indexed query layer while markdown stays the human-editable source of truth. It is **built with zero new dependency**: SQLite is reached through the existing opportunistic `probeOptional('better-sqlite3')` runtime probe (the Phase 51 pattern), with a guaranteed markdown / JS-scan fallback whenever the module is absent. Run `migrate-to-sqlite.cjs --migrate-state` to build the database (14 tables plus FTS5); afterwards state mutations dual-write (SQLite authoritative, STATE.md rendered from it byte-for-byte) while the `gdd-state` read/mutate/transition API is unchanged. `/gdd:state query "<sql>"` runs read-only SELECTs (engine-level readonly), `/gdd:state recover` rebuilds a corrupt database from markdown, and `/gdd:state demigrate` reverts to markdown-only. When better-sqlite3 is not installed, GDD behaves exactly as before. **No new runtime dependency.**
277
+
274
278
  Verify with:
275
279
 
276
280
  ```
@@ -845,6 +849,8 @@ GDD ships defense-in-depth security since Phase 14.5:
845
849
 
846
850
  - **`hooks/gdd-bash-guard.js`** - PreToolUse:Bash blocks ~50 dangerous patterns (`rm -rf /`, `chmod 777`, `curl | sh`, `git reset --hard`, fork bombs) after Unicode NFKC + ANSI normalization.
847
851
  - **`hooks/gdd-protected-paths.js`** - PreToolUse:Edit/Write/Bash enforces `protected_paths` glob list (defaults: `reference/**`, `.design/archive/**`, `skills/**`, `commands/**`, `hooks/**`, `.design/config.json`, `.design/telemetry/**`).
852
+ - **`hooks/gdd-risk-gate.js`** - PreToolUse:Write/Edit/MultiEdit/Bash scores each writer action via the pure `scripts/lib/risk/compute-risk.cjs` (tool x file-sensitivity x input shape), emits a `risk_assessment` event, and blocks only actions at or above 0.85; `allow` is silent, `review` / `require_confirmation` attach advisory context. Clear a block with `/gdd:override`.
853
+ - **`hooks/gdd-fact-force.js`** - PreToolUse:Edit/Write/MultiEdit holds the first write to a file until its DesignContext consumers and recorded decisions have been Read this session; soft block, softens to a warning when the graph is absent, cleared with `/gdd:override factforce <path>`.
848
854
  - **`hooks/gdd-read-injection-scanner.ts`** - scans inbound Read content for invisible-Unicode (zero-width, word-joiner, BOM, bidi overrides) + HTML-comment + secret-exfil patterns.
849
855
  - **`scripts/lib/blast-radius.cjs`** - `design-executor` preflight refuses tasks above `max_files_per_task: 10` / `max_lines_per_task: 400`.
850
856
  - **`hooks/gdd-mcp-circuit-breaker.js`** - breaks consecutive-timeout loops on `use_figma` / `use_paper` / `use_pencil`.
package/SKILL.md CHANGED
@@ -116,6 +116,8 @@ Each stage produces artifacts in `.design/` inside the current project.
116
116
  | `locale [<code>]` | `get-design-done:gdd-locale` | Phase 40.5 - inspect or set the GDD CLI locale (en/ru/uk/de/fr/zh/ja) for `--help`, errors, and skill prompt headers; missing keys fall back to English. No arg reports the resolved locale + coverage |
117
117
  | `context [nodes --type X \| edges --type Z \| path <a> <b> \| consumers-of <id> \| unreachable \| cycles \| coverage]` | `get-design-done:gdd-context` | Phase 52 - read-only query front end for the typed DesignContext graph at `.design/context-graph.json`; lists/filters nodes and edges, traces a path between two nodes, finds a node's consumers, and reports unreachable nodes, dependency cycles, and coverage. Never writes |
118
118
  | `migrate-context [--dry-run]` | `get-design-done:gdd-migrate-context` | Phase 52 - migrate a pre-Phase-52 project from flat `.design/map/*.md` mapper notes to the typed DesignContext graph; runs the extract-*.mjs passes, merges fragments, validates with `validate-design-context.cjs`, and flags low-confidence transforms for review. Preview-first; `--dry-run` previews without writing |
119
+ | `override <finding-id \| factforce <path>> [--approver <who>] [--reason <text>]` | `get-design-done:gdd-override` | Phase 56 - escalation surface for a risk-gate block or a first-write fact-force hold; with an approver and reason, writes a `D-XX` override-tagged decision (audit trail) for a blocked finding, or clears the fact-force `checked[path]` lock for a path you have legitimately reviewed. Mirrors unlock-decision; never overrides silently |
120
+ | `state <query "<sql>" \| recover \| demigrate>` | `get-design-done:gdd-state` | Phase 57 - operate the opt-in SQLite state backbone: `query` runs a read-only SELECT over the decisions/blockers/plans tables (engine-level readonly), `recover` rebuilds a corrupt `state.sqlite` from the markdown STATE.md, `demigrate` removes `state.sqlite` to fall back to the markdown-only source of truth. Markdown stays the human-editable SoT; SQLite is opportunistic and reversible |
119
121
 
120
122
  ## Handoff Routing
121
123
 
@@ -125,6 +125,22 @@ f. **Record status.** Note `G-NN: fixed` in your running tracker.
125
125
  - **Rule 3 - Blocking issue:** If something prevents applying this specific fix (missing import, wrong file structure), resolve the blocking issue first, then apply the fix → continue.
126
126
  - **Rule 4 - Architectural change required:** If resolving the gap requires a new DB table, major schema change, switching libraries, or breaking API changes → DO NOT force a fix. Classify as unresolvable and proceed to Step 3 for this gap.
127
127
 
128
+ ### Step 2.5 - Confidence x risk routing (Phase 56)
129
+
130
+ Step 1's confidence filter (`scripts/lib/confidence-route.cjs`) already dropped tentative and low-confidence gaps. Step 2.5 adds the action-risk dimension: a fix that is correct can still be dangerous to APPLY (touching STATE.md, a schema, a hook, a large diff). Score the write, then combine score and confidence into one routing decision per gap.
131
+
132
+ For each in-scope gap, before applying its edit:
133
+
134
+ 1. **Score the write.** `risk = computeRisk('Edit', { file_path, new_string })` from `scripts/lib/risk/compute-risk.cjs` (use `MultiEdit` with `edits[]` for multi-hunk fixes, `Write` for full rewrites). `risk.suggested_action` is one of `allow | review | require_confirmation | block`.
135
+ 2. **Route.** `decision = route(gap.confidence, risk.suggested_action)` from `scripts/lib/risk/route.cjs`:
136
+ - `auto` (high confidence, low risk): apply the fix via the Step 2 sequence and commit.
137
+ - `confirm` (medium confidence, or `require_confirmation` risk): propose the fix with its diff via `AskUserQuestion` before writing. Apply only on approval; otherwise treat it as `skip`. This agent is the only place the confirmation prompt happens (the writer hooks just score and flag).
138
+ - `skip` (confidence below 0.5, non-block): leave the gap as a deferred finding; do not write. Note it in the tracker.
139
+ - `override` (risk `block`, at any confidence): do NOT auto-apply a block-risk write. Route the user to `{{command_prefix}}override <G-NN> --approver <who> --reason <text>`; apply only after the audited override is recorded.
140
+ 3. **Record.** Note each gap as `G-NN: auto | confirm | skip | override` in your running tracker, then carry the `auto` and approved-`confirm` gaps into the Step 2 fix sequence.
141
+
142
+ `route` and `computeRisk` are pure and dependency-free, so this filter is deterministic. A gap whose confidence field is missing is treated as the lowest tier (skip, unless the action is `block`, which routes to override).
143
+
128
144
  ### Step 3 - Handle unresolvable gaps
129
145
 
130
146
  A gap is unresolvable if:
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: gdd-override
3
+ description: "Escalation surface for a risk-blocked action or a fact-force gate. Use when the Phase 56 risk gate blocked a writer action (suggested_action=block) and a reviewer has signed off, or when the first-write fact-force gate is holding a file you have legitimately reviewed. Activates for requests involving overriding a blocked edit, approving a high-risk change, or clearing a fact-force hold on a path."
4
+ argument-hint: "<finding-id | factforce <path>> [--approver <who>] [--reason <text>]"
5
+ user-invocable: true
6
+ tools: Read, Write, Bash, Grep, Glob
7
+ ---
8
+
9
+ # /gdd:override
10
+
11
+ A risk-blocked action is hard: the Phase 56 risk gate routes `suggested_action=block`
12
+ to `override` (see `scripts/lib/risk/route.cjs`), and the fact-force gate holds the
13
+ first write to a file until its facts are read. This skill is the audited way past
14
+ either hold. It mirrors `/gdd:unlock-decision`: a named approver plus a
15
+ reason, recorded before anything is let through. Override is never silent.
16
+
17
+ ## Invocation
18
+
19
+ | Command | Behavior |
20
+ |---|---|
21
+ | `/gdd:override <finding-id> --approver <who> --reason <text>` | Record a `D-XX` `override`-tagged decision in STATE.md `<decisions>` and let the risk-blocked action through. |
22
+ | `/gdd:override factforce <path> --approver <who> --reason <text>` | Set `checked[path]` in the session fact-force state so the fact-force gate stops holding that path. |
23
+
24
+ Both modes ask for a rationale: the audit trail is the reason override exists.
25
+
26
+ ## Steps
27
+
28
+ 1. **Parse args.** Mode is `factforce` when the first token is the literal `factforce`
29
+ (the next token is the `<path>`); otherwise the first token is a `<finding-id>`.
30
+ `--approver` is required (a non-empty name). Missing `--approver` prints the usage
31
+ and changes nothing. If `--reason` is absent, ASK for one (AskUserQuestion or a
32
+ prompt) before continuing: an override with no rationale is rejected.
33
+
34
+ 2. **Preview.** Show what will be written and stop for confirmation:
35
+ - finding mode: the decision entry from `overrideDecisionEntry(<id>, {approver, reason})`
36
+ (its `text`, `status: locked`, and `override` tag) plus the action it unblocks.
37
+ - factforce mode: the `<path>` that will gain `checked[path] = true` and the
38
+ session-state file it lands in.
39
+
40
+ 3. **Apply (finding mode).** Record the audited decision via the STATE writer
41
+ `mcp__gdd_state__add_decision` (it auto-assigns the next `D-N`). Pass the `text`
42
+ from the pure builder so the `override` tag is embedded and greppable:
43
+
44
+ ```bash
45
+ node -e '
46
+ const o = require("./scripts/lib/risk/override.cjs");
47
+ const [id, who, reason] = process.argv.slice(1);
48
+ const entry = o.overrideDecisionEntry(id, { approver: who, reason });
49
+ console.log(JSON.stringify(entry));
50
+ ' "<finding-id>" "<who>" "<reason>"
51
+ ```
52
+
53
+ Then call `mcp__gdd_state__add_decision` with `{ text: <entry.text>, status: "locked" }`.
54
+ The blocked action is now approved on the audit record; proceed with it.
55
+
56
+ 4. **Apply (factforce mode).** Set `checked[path]` in the session state file at
57
+ `<cwd>/.design/locks/factforce-<session_id>.json` (atomic tmp then rename), using
58
+ the pure helper so the shape matches what the fact-force gate reads:
59
+
60
+ ```bash
61
+ node -e '
62
+ const fs = require("fs"); const path = require("path");
63
+ const o = require("./scripts/lib/risk/override.cjs");
64
+ const [file, p] = process.argv.slice(1);
65
+ let state = {}; try { state = JSON.parse(fs.readFileSync(file, "utf8")); } catch {}
66
+ const next = o.setFactForceChecked(state, p);
67
+ fs.mkdirSync(path.dirname(file), { recursive: true });
68
+ const tmp = file + ".tmp";
69
+ fs.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n");
70
+ fs.renameSync(tmp, file);
71
+ console.log(JSON.stringify(next.checked));
72
+ ' "<cwd>/.design/locks/factforce-<session_id>.json" "<path>"
73
+ ```
74
+
75
+ The fact-force gate stops holding `<path>` for the rest of the session.
76
+
77
+ 5. **Report** the recorded approver, the reason, and either the new `D-XX` id (finding
78
+ mode) or the unblocked path (factforce mode).
79
+
80
+ ## Do Not
81
+
82
+ - Do not skip the rationale: every override is audited.
83
+ - Do not override a finding that the risk gate did not actually block.
84
+ - Do not edit `scripts/lib/risk/route.cjs` or `compute-risk.cjs`: this skill consumes them.
85
+
86
+ ## OVERRIDE COMPLETE
@@ -0,0 +1,106 @@
1
+ ---
2
+ name: gdd-state
3
+ description: "Query, recover, or roll back the Phase 57 SQLite state backbone. Use when you need to inspect the decisions/blockers/plans tables with a raw SELECT, rebuild a corrupt state.sqlite from the markdown STATE.md, or revert to the markdown-only source of truth by removing state.sqlite. Activates for requests involving querying the SQLite state database, recovering from SQLite corruption, or reverting the migration (demigrate)."
4
+ argument-hint: "<query \"<sql>\" | recover | demigrate>"
5
+ user-invocable: true
6
+ tools: Read, Bash, Grep, Glob
7
+ ---
8
+
9
+ # /gdd:state
10
+
11
+ The Phase 57 SQLite state backbone is opt-in (`--migrate-state`) and fully reversible.
12
+ Markdown `.design/STATE.md` is always the human-editable SoT; SQLite is a faster query
13
+ layer derived from it. This skill exposes three subcommands for operating on that layer.
14
+
15
+ ## Subcommands
16
+
17
+ | Subcommand | What it does |
18
+ |---|---|
19
+ | `/gdd:state query "<sql>"` | Run a read-only SELECT against `.design/state.sqlite`. |
20
+ | `/gdd:state recover` | Rotate the current sqlite to a `.bak` and rebuild from markdown. |
21
+ | `/gdd:state demigrate` | Remove `.design/state.sqlite`; markdown becomes the SoT again. |
22
+
23
+ ---
24
+
25
+ ## query
26
+
27
+ Execute a read-only SELECT against the state database.
28
+
29
+ The engine opens the file with `readonly:true` so all writes are rejected at the
30
+ engine level. A first-token denylist (Set membership, no regex) additionally blocks
31
+ DROP, DELETE, UPDATE, INSERT, ALTER, ATTACH, CREATE, PRAGMA, VACUUM, ANALYZE,
32
+ REINDEX, and REPLACE before the connection is opened.
33
+
34
+ ```bash
35
+ node -e '
36
+ const qs = require("./scripts/lib/state/query-surface.cjs");
37
+ const result = qs.query(process.argv[1], { projectRoot: process.cwd() });
38
+ console.log(JSON.stringify(result, null, 2));
39
+ ' "<sql>"
40
+ ```
41
+
42
+ Outputs `{ rows: [...], backend: "sqlite" }` on success, or
43
+ `{ degraded: true, message: "..." }` when SQLite is not active.
44
+
45
+ Degrades gracefully (no throw) when `BACKEND==='markdown'` or when
46
+ `.design/state.sqlite` has not been created yet (run `--migrate-state` first).
47
+
48
+ ---
49
+
50
+ ## recover
51
+
52
+ Rotate the current (possibly corrupt) `.design/state.sqlite` to `.bak.0`, then
53
+ rebuild a fresh database from the markdown `.design/STATE.md` using
54
+ `migrate-to-sqlite.cjs` in force mode. Runs `PRAGMA integrity_check` on the
55
+ result and reports the outcome.
56
+
57
+ ```bash
58
+ node -e '
59
+ const qs = require("./scripts/lib/state/query-surface.cjs");
60
+ const result = qs.recover({ projectRoot: process.cwd() });
61
+ console.log(JSON.stringify(result, null, 2));
62
+ '
63
+ ```
64
+
65
+ Outputs `{ recovered: true, integrity: true, message: "..." }` on success.
66
+
67
+ Backup rotation keeps at most 10 files (`.bak.0` through `.bak.9`). The oldest
68
+ backup is overwritten when the cap is reached.
69
+
70
+ ---
71
+
72
+ ## demigrate
73
+
74
+ Remove `.design/state.sqlite` so the markdown `STATE.md` becomes the SoT again.
75
+ Idempotent: if the file does not exist, returns a clear no-op message without error.
76
+ A backup is taken in `.bak.0` before removal.
77
+
78
+ ```bash
79
+ node -e '
80
+ const qs = require("./scripts/lib/state/query-surface.cjs");
81
+ const result = qs.demigrate({ projectRoot: process.cwd() });
82
+ console.log(JSON.stringify(result, null, 2));
83
+ '
84
+ ```
85
+
86
+ Outputs `{ demigrated: true, message: "..." }` when the file was removed, or
87
+ `{ demigrated: false, message: "..." }` when it was already absent (no-op).
88
+
89
+ To re-enable SQLite after a demigrate, run `--migrate-state` again.
90
+
91
+ ---
92
+
93
+ ## Key design decisions
94
+
95
+ - **Markdown is always the SoT.** SQLite is opt-in via `--migrate-state` and
96
+ reversible via `demigrate`. The markdown file is never silently overwritten.
97
+ - **Read-only queries only.** The `query` subcommand enforces SELECT-only via both
98
+ the engine (`readonly:true`) and a defense-in-depth denylist. No writes
99
+ are possible through this skill.
100
+ - **Backup rotation cap.** `rotateBak` shifts `.bak.0..8` up by one index and caps
101
+ at `.bak.9` (10 files total). The oldest backup is overwritten automatically.
102
+ - **Graceful degradation.** All subcommands return a clear `{ degraded, message }`
103
+ object (no throw) when `better-sqlite3` is not installed or when
104
+ `GDD_STATE_BACKEND=markdown` is set.
105
+
106
+ ## STATE COMPLETE
@@ -524,6 +524,58 @@ function buildRecallBlock(matches, basename, backendLabel) {
524
524
  return lines.join('\n');
525
525
  }
526
526
 
527
+ /**
528
+ * Phase 56 (fact-force) read-tracking — ADDITIVE, best-effort, non-blocking.
529
+ *
530
+ * On every Read, record `reads[<normalizedRelPath>] = <ISO>` into the SAME
531
+ * session-state file the fact-forcing gate consults
532
+ * (`<cwd>/.design/locks/factforce-<sanitized session_id>.json`). This is how the
533
+ * gate knows which importer files an agent has already opened before its first
534
+ * mutation. Fully swallowed on any error so it can NEVER change this Read hook's
535
+ * existing decision-injection behavior or its `{ continue: true }` contract.
536
+ *
537
+ * Self-contained (no new import): mirrors the gate's session_id derivation
538
+ * (`payload.session_id ?? GDD_SESSION_ID ?? 'hook'`), path normalization, and
539
+ * atomic tmp+rename write so the two hooks agree byte-for-byte on the file.
540
+ */
541
+ function recordReadForFactForce(payload) {
542
+ try {
543
+ const fp = payload && payload.tool_input && payload.tool_input.file_path;
544
+ if (!fp) return;
545
+ const cwd = (payload && payload.cwd) || process.cwd();
546
+
547
+ let rel = String(fp);
548
+ if (rel.startsWith('/') || /^[A-Za-z]:[\\/]/.test(rel)) {
549
+ try { rel = path.relative(cwd, rel); } catch { /* keep rel */ }
550
+ }
551
+ rel = rel.replace(/\\/g, '/').replace(/^\.\//, '');
552
+ if (!rel) return;
553
+
554
+ const rawSid = (payload && (payload.session_id || payload.sessionId))
555
+ || process.env.GDD_SESSION_ID
556
+ || 'hook';
557
+ const sid = String(rawSid).replace(/[^A-Za-z0-9_-]+/g, '-').slice(0, 120) || 'hook';
558
+ const stateFile = path.join(cwd, '.design', 'locks', `factforce-${sid}.json`);
559
+
560
+ let state = { reads: {}, first_mutation_seen: {}, checked: {} };
561
+ try {
562
+ const parsed = JSON.parse(fs.readFileSync(stateFile, 'utf8'));
563
+ if (parsed && typeof parsed === 'object') {
564
+ state.reads = (typeof parsed.reads === 'object' && parsed.reads) || {};
565
+ state.first_mutation_seen = (typeof parsed.first_mutation_seen === 'object' && parsed.first_mutation_seen) || {};
566
+ state.checked = (typeof parsed.checked === 'object' && parsed.checked) || {};
567
+ }
568
+ } catch { /* missing/corrupt -> start fresh */ }
569
+
570
+ state.reads[rel] = new Date().toISOString();
571
+
572
+ fs.mkdirSync(path.dirname(stateFile), { recursive: true });
573
+ const tmp = `${stateFile}.tmp`;
574
+ fs.writeFileSync(tmp, JSON.stringify(state, null, 2));
575
+ fs.renameSync(tmp, stateFile);
576
+ } catch { /* best-effort: never let read-tracking affect the Read hook */ }
577
+ }
578
+
527
579
  async function main() {
528
580
  let buf = '';
529
581
  for await (const chunk of process.stdin) buf += chunk;
@@ -539,6 +591,11 @@ async function main() {
539
591
  return;
540
592
  }
541
593
 
594
+ // Phase 56: record this Read into the fact-force session state for EVERY
595
+ // Read (not just recall-matching .md files), before the recall matcher gate.
596
+ // Best-effort + fully swallowed — does not alter the behavior below.
597
+ recordReadForFactForce(payload);
598
+
542
599
  const fp = payload?.tool_input?.file_path || '';
543
600
  if (!MATCHER_RE.test(fp)) {
544
601
  process.stdout.write(JSON.stringify({ continue: true }));
@@ -651,5 +708,6 @@ module.exports = {
651
708
  buildInstinctsBlock,
652
709
  instinctTokens,
653
710
  queryInstinctsBlock,
711
+ recordReadForFactForce,
654
712
  main,
655
713
  };