@hegemonart/get-design-done 1.28.7 → 1.30.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 (71) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +116 -0
  4. package/README.de.md +37 -0
  5. package/README.fr.md +37 -0
  6. package/README.it.md +37 -0
  7. package/README.ja.md +37 -0
  8. package/README.ko.md +37 -0
  9. package/README.md +44 -0
  10. package/README.zh-CN.md +37 -0
  11. package/SKILL.md +12 -10
  12. package/agents/design-reflector.md +50 -0
  13. package/package.json +3 -1
  14. package/reference/capability-gap-stage-gate.md +261 -0
  15. package/reference/known-failure-modes.md +185 -0
  16. package/reference/pseudonymization-rules.md +189 -0
  17. package/reference/registry.json +22 -1
  18. package/reference/schemas/events.schema.json +97 -3
  19. package/reference/schemas/generated.d.ts +319 -4
  20. package/scripts/build-distribution-bundles.cjs +549 -0
  21. package/scripts/cli/gdd-events.mjs +35 -2
  22. package/scripts/gsd-cleanup-incubator.cjs +367 -0
  23. package/scripts/install.cjs +61 -0
  24. package/scripts/lib/apply-reflections/incubator-proposals.cjs +448 -0
  25. package/scripts/lib/bandit-router.cjs +92 -9
  26. package/scripts/lib/gsd-health-mirror/index.cjs +37 -1
  27. package/scripts/lib/incubator-author.cjs +845 -0
  28. package/scripts/lib/install/config-dir.cjs +26 -0
  29. package/scripts/lib/install/converters/codex-plugin.cjs +407 -0
  30. package/scripts/lib/install/converters/cursor-marketplace.cjs +309 -0
  31. package/scripts/lib/install/doctor-codex-plugin.cjs +388 -0
  32. package/scripts/lib/install/doctor-cursor-marketplace.cjs +366 -0
  33. package/scripts/lib/install/doctor-tier2.cjs +586 -0
  34. package/scripts/lib/install/runtimes.cjs +48 -0
  35. package/scripts/lib/issue-reporter/cli-flag-report.cjs +153 -0
  36. package/scripts/lib/issue-reporter/consent-prompt.cjs +231 -0
  37. package/scripts/lib/issue-reporter/dedup.cjs +458 -0
  38. package/scripts/lib/issue-reporter/destination.cjs +37 -0
  39. package/scripts/lib/issue-reporter/draft-writer.cjs +157 -0
  40. package/scripts/lib/issue-reporter/gh-absent-fallback.cjs +220 -0
  41. package/scripts/lib/issue-reporter/gh-submit.cjs +114 -0
  42. package/scripts/lib/issue-reporter/kill-switch.cjs +122 -0
  43. package/scripts/lib/issue-reporter/payload-assembly.cjs +367 -0
  44. package/scripts/lib/issue-reporter/privacy-diff.cjs +385 -0
  45. package/scripts/lib/issue-reporter/report-flow.cjs +269 -0
  46. package/scripts/lib/issue-reporter/triage-matcher.cjs +270 -0
  47. package/scripts/lib/pseudonymize.cjs +444 -0
  48. package/scripts/lib/reflections-cycle-writer.cjs +172 -0
  49. package/scripts/lib/reflector/capability-gap-scan.cjs +751 -0
  50. package/scripts/lib/reflector-capability-gap-aggregator.cjs +320 -0
  51. package/scripts/lint-agentskills-spec.cjs +457 -0
  52. package/scripts/release-smoke-test.cjs +33 -2
  53. package/scripts/validate-incubator-scope.cjs +133 -0
  54. package/skills/apply-reflections/SKILL.md +16 -1
  55. package/skills/apply-reflections/apply-reflections-procedure.md +71 -3
  56. package/skills/compare/SKILL.md +2 -2
  57. package/skills/compare/compare-rubric.md +1 -1
  58. package/skills/darkmode/SKILL.md +2 -2
  59. package/skills/darkmode/darkmode-audit-procedure.md +1 -1
  60. package/skills/fast/SKILL.md +46 -0
  61. package/skills/figma-write/SKILL.md +2 -2
  62. package/skills/graphify/SKILL.md +2 -2
  63. package/skills/reflect/SKILL.md +9 -0
  64. package/skills/reflect/procedures/capability-gap-scan.md +120 -0
  65. package/skills/report-issue/SKILL.md +53 -0
  66. package/skills/report-issue/report-issue-procedure.md +120 -0
  67. package/skills/router/SKILL.md +5 -0
  68. package/skills/router/capability-gap-emitter.md +65 -0
  69. package/skills/style/SKILL.md +2 -2
  70. package/skills/style/style-doc-procedure.md +1 -1
  71. package/skills/update/SKILL.md +3 -2
@@ -35,6 +35,18 @@ Read flow:
35
35
 
36
36
  Legacy grep-based parsing of skill outputs is preserved as a fallback for skills that haven't yet migrated to emit `reflection.proposal` events (Phase 22 scope). If no `reflection.proposal` events are present in the stream, run the legacy harvest across `.design/learnings/*.md` and `.design/intel/` exactly as before — both paths produce the same Proposals section format.
37
37
 
38
+ ## Capability-gap pattern scan (Phase 29 Plan 02)
39
+
40
+ During the reflection pass, also run the capability-gap pattern scan to detect recurring patterns lacking a dedicated executable owner. The scan emits `capability_gap` events with `source: "reflector_pattern"` for Plan 29-03 to aggregate.
41
+
42
+ ```
43
+ node -e "console.log(JSON.stringify(require('./scripts/lib/reflector/capability-gap-scan.cjs').runCapabilityGapScan(), null, 2))"
44
+ ```
45
+
46
+ The scan reads three signal sources: `.design/intel/*.md` `Touches:` clusters, `.design/telemetry/posterior.json` high-usage arms with no specialized agent, and recent `.design/gep/events.jsonl` decision sequences. MCP-probe failures (`outcome === 'connection-error'`, `agent === 'mcp-probe'`, or `mcp_probe: true`) do NOT trigger gap events (CONTEXT D-08). See @skills/reflect/procedures/capability-gap-scan.md for the full contract.
47
+
48
+ Cite the returned `emittedEventIds` in the run summary under a `## Capability gaps emitted` heading. The threshold knob is `reflector.capability_gap_threshold` in `.design/config.json` (default `N=3`, integer ≥ 1).
49
+
38
50
  ## Required Reading
39
51
 
40
52
  The orchestrating stage supplies a `<required_reading>` block in the prompt. Read every listed file before acting — this is mandatory.
@@ -52,6 +64,8 @@ Minimum expected inputs (skip gracefully if absent, note what's missing):
52
64
 
53
65
  Write `.design/reflections/<cycle-slug>.md`. If `--dry-run` is set in the spawning prompt, print proposals to stdout only — do not write the file.
54
66
 
67
+ If the capability-gap pattern scan emitted any events during this run, include a `## Capability gaps emitted` heading listing each `event_id` with the source signal kind (`intel` | `posterior` | `trajectory`) and the `suggested_kind` (`agent` | `skill`) per event. Plan 29-03 reads these events from `.design/gep/events.jsonl` to cluster recurring `capability_gap` events for `/gdd:apply-reflections`.
68
+
55
69
  Terminate with `## REFLECTION COMPLETE`.
56
70
 
57
71
  ## Reflection Sections
@@ -203,6 +217,42 @@ Render each `bandit_arbitrage` entry into the Proposals section as a `[FRONTMATT
203
217
 
204
218
  ---
205
219
 
220
+ ### 9. Capability gaps observed (Phase 29 — D-01 / D-03)
221
+
222
+ **Why this exists:** Plans 29-01 and 29-02 emit `capability_gap` events to `.design/gep/events.jsonl` whenever `/gdd:fast`, `gdd-router`, or the reflector pattern-detection pass identifies a lookup-fail with no dedicated owner. This section surfaces those events as clusters in the cycle markdown and evaluates the Stage-0 → Stage-1 gate per `reference/capability-gap-stage-gate.md`.
223
+
224
+ **Data sources:**
225
+
226
+ - `.design/gep/events.jsonl` — the Phase 22 causal event chain. Rows where `type === 'capability_gap'` (or `outcome === 'capability_gap'`) are aggregated by `payload.context_hash`.
227
+ - `.design/config.json` (optional) — `capability_gap_gate.{K, M, stddev_threshold}` overrides. Defaults: `K=3`, `M=10`, `stddev_threshold=0.05` per D-03.
228
+
229
+ **The mechanism:**
230
+
231
+ 1. Invoke `scripts/lib/reflections-cycle-writer.cjs` via Bash with `--chain=.design/gep/events.jsonl` and (when available) `--history=<path>` pointing at an array of prior cycle cluster lists.
232
+ 2. The shim calls `aggregateCapabilityGaps()` from `scripts/lib/reflector-capability-gap-aggregator.cjs` which clusters events by `context_hash`, caps each cluster's example evidence at 3, and orders by size desc.
233
+ 3. The shim calls `renderGapsSection(clusters)` which returns the `## Capability gaps observed` markdown block. The block is empty (no header emitted) when there are no clusters in this cycle — the cycle markdown is unchanged.
234
+ 4. When `--history` is supplied AND at least M cycles have been observed, the shim also calls `evaluateStageGate(history, config)`. If the gate is crossed AND `.design/config.json` does NOT already carry `capability_gap_gate.user_prompted_at`, a one-time prompt block is appended (verbatim text in `reference/capability-gap-stage-gate.md` § 5).
235
+
236
+ **Bash invocation (executor follows verbatim):**
237
+
238
+ ```bash
239
+ node scripts/lib/reflections-cycle-writer.cjs \
240
+ --chain=.design/gep/events.jsonl \
241
+ --config=.design/config.json
242
+ ```
243
+
244
+ Append stdout to the cycle markdown body (after Section 8 / before the Proposals header). If `--history=<path>` is wired by a future cycle-aggregator, add the flag. For Stage 0 (this phase), per-cycle cluster aggregation alone is the deliverable — gate evaluation surfaces additively when history is present.
245
+
246
+ **Important discipline (D-01 lock):**
247
+
248
+ - This section NEVER auto-flips `capability_gap_gate.stage` or any other runtime state. The output is markdown only; the user opts in via Plan 29-05's apply-reflections extension.
249
+ - The shim is read-only with respect to `.design/config.json`. The only state-mutating writer is the user-driven opt-in path (deferred to 29-05).
250
+ - `evidence_refs[]` content is rendered as-is in the markdown table examples column — per the plan's threat model T-29.03-04, evidence refs are trusted-content (file:line or event-id strings from the 29-01 schema).
251
+
252
+ **Helper:** `scripts/lib/reflector-capability-gap-aggregator.cjs` exports `aggregateCapabilityGaps`, `renderGapsSection`, `evaluateStageGate`. The shim wraps these for invocation from the agent prompt; tests in `tests/reflector-capability-gap-aggregation.test.cjs` cover the helper directly with synthetic fixtures (D-11).
253
+
254
+ ---
255
+
206
256
  ## Proposals
207
257
 
208
258
  After all sections, write a **Proposals** section. Number proposals sequentially. Every proposal must include evidence — no vague observations.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hegemonart/get-design-done",
3
- "version": "1.28.7",
3
+ "version": "1.30.0",
4
4
  "description": "A design-quality pipeline for AI coding agents: brief, plan, implement, and verify UI work against your design system.",
5
5
  "author": "Hegemon",
6
6
  "homepage": "https://github.com/hegemonart/get-design-done",
@@ -38,11 +38,13 @@
38
38
  "provenance": true
39
39
  },
40
40
  "scripts": {
41
+ "build:bundles": "node scripts/build-distribution-bundles.cjs",
41
42
  "test": "node --test --experimental-strip-types \"tests/**/*.test.cjs\" \"tests/**/*.test.ts\"",
42
43
  "typecheck": "tsc --noEmit",
43
44
  "codegen:schemas": "node --experimental-strip-types scripts/codegen-schema-types.ts",
44
45
  "lint:md": "npx --yes markdownlint-cli2 \"**/*.md\" \"#node_modules\" \"#.planning\" \"#.claude\" \"#test-fixture/baselines\"",
45
46
  "lint:links": "npx --yes lychee --no-progress --accept 200,206,403,429 \"**/*.md\" || true",
47
+ "lint:agentskills": "node scripts/lint-agentskills-spec.cjs",
46
48
  "validate:schemas": "node --experimental-strip-types scripts/validate-schemas.ts",
47
49
  "validate:frontmatter": "node --experimental-strip-types scripts/validate-frontmatter.ts agents/",
48
50
  "detect:stale-refs": "node scripts/detect-stale-refs.cjs",
@@ -0,0 +1,261 @@
1
+ # Capability-Gap Stage-0 → Stage-1 Gate Specification
2
+
3
+ > Phase 29 reference doc. Specifies the deterministic gate that decides when
4
+ > the reflector has gathered enough `capability_gap` signal to surface a
5
+ > one-time opt-in prompt for Stage-1 (incubator authoring of new agents /
6
+ > skills). **No code path in this repository auto-flips the stage** —
7
+ > D-01 is the discipline.
8
+
9
+ ---
10
+
11
+ ## 1. Overview
12
+
13
+ Phase 29 ships in two stages:
14
+
15
+ - **Stage 0** (Wave A, v1.29.0) emits `capability_gap` events from
16
+ `/gdd:fast` no-skill-match (Plan 29-01), `gdd-router` unmatched-intent
17
+ (Plan 29-01), and the reflector pattern-detection pass (Plan 29-02).
18
+ - **Stage 1** (Wave B) layers incubator authoring of agents and skills on
19
+ top of the Stage-0 signal (Plans 29-04 / 29-05 / 29-06).
20
+
21
+ The transition Stage 0 → Stage 1 is **gated on data**, not on a calendar
22
+ date or a release. The reflector aggregates events into per-cycle
23
+ clusters (`scripts/lib/reflector-capability-gap-aggregator.cjs`) and
24
+ evaluates a deterministic stability function against the project's
25
+ cycle history. When the gate is crossed, `/gdd:apply-reflections`
26
+ emits a **one-time user-facing prompt** in the cycle markdown — never
27
+ an auto-stage-flip. The user opting in is a separate explicit action,
28
+ out of scope for this gate spec.
29
+
30
+ Reference: **Phase 29 CONTEXT.md decision D-01** (two-stage approach;
31
+ user opts in per a one-time prompt; if data is thin, Stage 1 never
32
+ auto-enables).
33
+
34
+ ---
35
+
36
+ ## 2. Default thresholds
37
+
38
+ The gate has three knobs, all set in `.design/config.json`
39
+ under the `capability_gap_gate` key. Defaults:
40
+
41
+ | Knob | Default | Meaning |
42
+ |------|---------|---------|
43
+ | `K` | `3` | Minimum number of **stable clusters** required to cross the gate. |
44
+ | `M` | `10` | Minimum number of **consecutive cycles** a cluster must appear in to be considered for stability. |
45
+ | `stddev_threshold` | `0.05` | Maximum allowed posterior `stddev(Beta(α, β))` for a cluster to be considered stable. |
46
+
47
+ All three are overridable via `.design/config.json`:
48
+
49
+ ```jsonc
50
+ {
51
+ "capability_gap_gate": {
52
+ "K": 3,
53
+ "M": 10,
54
+ "stddev_threshold": 0.05
55
+ }
56
+ }
57
+ ```
58
+
59
+ Reference: **Phase 29 CONTEXT.md decision D-03** (defaults are starting
60
+ points; first-N-users data should refine).
61
+
62
+ Validation: `K` must be a positive integer, `M` a positive integer,
63
+ `stddev_threshold` a number in `(0, 1]`. The evaluator silently falls
64
+ back to defaults if any value is invalid (T-29.03-02 mitigation in the
65
+ plan's threat model).
66
+
67
+ ---
68
+
69
+ ## 3. Stability formula
70
+
71
+ A cluster `c` is **stable** iff both conditions hold:
72
+
73
+ 1. **Consecutive presence.** `c` appears in `≥ M` consecutive cycles
74
+ somewhere within the observed history. (The most recent unbroken
75
+ run is what matters — if a cluster missed a cycle, the run resets
76
+ and only the longest streak counts.)
77
+ 2. **Narrow posterior.** The closed-form posterior standard deviation
78
+ of the Beta distribution satisfies:
79
+
80
+ ```
81
+ stddev(Beta(α, β)) = sqrt( (α · β) / ((α + β)² · (α + β + 1)) )
82
+ ```
83
+
84
+ with the Laplace prior (matches Phase 23.5's bandit-router posterior
85
+ store):
86
+
87
+ ```
88
+ α = appearances + 1
89
+ β = (cycles_observed − appearances) + 1
90
+ ```
91
+
92
+ where `appearances` is the total number of cycles in which `c` was
93
+ present (across the full history, not just the M-window) and
94
+ `cycles_observed = history.length`.
95
+
96
+ **Worked example.** A cluster present in 25 of the 30 observed cycles
97
+ with a longest consecutive run of 18 has `α = 26`, `β = 6`, so
98
+ `stddev ≈ sqrt((26·6)/(32²·33)) ≈ sqrt(0.0154) ≈ 0.124`. That fails
99
+ the default `stddev_threshold = 0.05`. To clear `0.05`, that same
100
+ cluster would need closer to 30/30 presence or a longer history.
101
+
102
+ **Cross-link.** The closed-form Beta-stddev is shared with Phase 23.5
103
+ (see `scripts/lib/bandit-arbitrage.cjs` and the
104
+ "Bandit-arbitrage analysis" section in `agents/design-reflector.md`).
105
+ The same posterior is what gates frontmatter-tier corrections; here it
106
+ gates stage transition.
107
+
108
+ ---
109
+
110
+ ## 4. Evaluation cadence
111
+
112
+ Gate evaluation runs every time `/gdd:apply-reflections` is invoked.
113
+ Inputs:
114
+
115
+ 1. The reflector pass collects all cycle markdown files in
116
+ `.design/reflections/` and parses the `## Capability gaps observed`
117
+ sections (emitted by `renderGapsSection` in
118
+ `scripts/lib/reflector-capability-gap-aggregator.cjs`).
119
+ 2. The per-cycle cluster lists are folded into a history array of
120
+ `{ cycle_slug, clusters }` entries.
121
+ 3. `evaluateStageGate(history, config)` is called once and returns:
122
+
123
+ ```ts
124
+ { crossed: boolean, stable_cluster_ids: string[], cycles_observed: number }
125
+ ```
126
+
127
+ 4. If `crossed === true` and the project has not previously opted in
128
+ (see § 6), the prompt in § 5 is emitted into the cycle markdown.
129
+
130
+ The evaluation is **deterministic** (no randomness), **idempotent**
131
+ (no side-effects in the evaluator), and **read-only** with respect to
132
+ `.design/config.json` — that file is only updated by the user's
133
+ explicit opt-in action, never by the reflector.
134
+
135
+ ---
136
+
137
+ ## 5. Gate-crossed prompt
138
+
139
+ When the gate crosses for the first time, `/gdd:apply-reflections`
140
+ appends the following verbatim block to the cycle markdown:
141
+
142
+ > ```markdown
143
+ > ## Stage-0 → Stage-1 gate crossed — opt-in required
144
+ >
145
+ > Capability-gap detection has accumulated enough signal across recent
146
+ > cycles to consider enabling Stage-1 (incubator authoring of new
147
+ > agents / skills). The gate is informational only — **nothing has
148
+ > changed in the runtime**, and Stage-1 will NOT auto-enable. Per
149
+ > Phase 29 CONTEXT.md decision D-01, the user opts in explicitly.
150
+ >
151
+ > - Stable clusters observed: **<N>** (≥K = <K>)
152
+ > - Cycles observed: **<cycles_observed>** (≥M = <M>)
153
+ > - Stable cluster IDs (truncated):
154
+ > - `<cluster_id_1>`
155
+ > - `<cluster_id_2>`
156
+ > - `<cluster_id_3>`
157
+ >
158
+ > If you want to enable Stage-1 incubator authoring (Plans 29-04 / 29-05),
159
+ > opt in with the project-local command below. You can always opt out
160
+ > later by deleting the timestamps from `.design/config.json` (§ 7).
161
+ >
162
+ > <!-- TODO: confirm opt-in command — likely
163
+ > `node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config set capability_gap_gate.opted_in_at "$(date -Iseconds)"`
164
+ > or a project-local equivalent. Plan 29-05 (apply-reflections
165
+ > extension) will land the canonical command. -->
166
+ >
167
+ > This prompt is emitted at most once per project. If you ignore it,
168
+ > the gate continues to evaluate every cycle but does not re-prompt
169
+ > (the `user_prompted_at` timestamp in `.design/config.json` suppresses
170
+ > it). To re-trigger the prompt for a fresh round of evaluation, delete
171
+ > `capability_gap_gate.user_prompted_at` from `.design/config.json`.
172
+ > ```
173
+
174
+ The wiring side of this — actually writing the `user_prompted_at`
175
+ timestamp and routing the opt-in confirmation — is deferred to
176
+ **Plan 29-05** (`/gdd:apply-reflections` extension). This document
177
+ specifies the prompt text and behavior; 29-05 implements the
178
+ state-machine that consumes it.
179
+
180
+ ---
181
+
182
+ ## 6. Opt-in semantics
183
+
184
+ Two timestamps in `.design/config.json` track the project's gate state:
185
+
186
+ ```jsonc
187
+ {
188
+ "capability_gap_gate": {
189
+ "K": 3,
190
+ "M": 10,
191
+ "stddev_threshold": 0.05,
192
+ "user_prompted_at": "2026-05-19T22:00:00.000Z", // set when § 5 emitted
193
+ "opted_in_at": "2026-05-19T22:05:00.000Z" // set when user opts in
194
+ }
195
+ }
196
+ ```
197
+
198
+ - **`user_prompted_at`** is set the first time the gate crosses and the
199
+ prompt block is rendered. The prompt is not re-emitted while this
200
+ timestamp is present.
201
+ - **`opted_in_at`** is set when the user explicitly opts into Stage-1.
202
+ Stage-1 incubator authoring (Plans 29-04+) becomes active once this
203
+ timestamp is present. **Stage 1 is NEVER enabled by the reflector
204
+ setting this timestamp itself** — D-01 lock.
205
+
206
+ Once `opted_in_at` is set, the gate stops emitting prompts entirely
207
+ (it's a one-shot mechanism, not a continuous nudge).
208
+
209
+ ---
210
+
211
+ ## 7. Reset / override
212
+
213
+ Operators can manually reset the gate by editing `.design/config.json`:
214
+
215
+ | Effect desired | Action |
216
+ |----------------|--------|
217
+ | Re-prompt on next gate cross | Delete `capability_gap_gate.user_prompted_at`. |
218
+ | Revert from Stage-1 to Stage-0 | Delete `capability_gap_gate.opted_in_at`. (Stage-1 artifacts in `.design/reflections/incubator/` are NOT removed by this; deletion is the user's call.) |
219
+ | Tighten / loosen thresholds | Edit `K` / `M` / `stddev_threshold` directly. Out-of-range values silently fall back to defaults (§ 2). |
220
+
221
+ Reset is **explicit** and **idempotent**. The reflector never writes
222
+ to these fields on its own — the only writers are (a) the
223
+ `/gdd:apply-reflections` opt-in path (Plan 29-05) and (b) the human
224
+ operator editing the file by hand.
225
+
226
+ ---
227
+
228
+ ## 8. Test fixtures
229
+
230
+ Executable examples that exercise the gate live in
231
+ `tests/reflector-capability-gap-aggregation.test.cjs`:
232
+
233
+ - **T3** — 30 cycles × 3 always-present clusters → gate crosses with
234
+ default K=3 / M=10 / stddev_threshold=0.05.
235
+ - **T3b** — 10 cycles × 1 always-present cluster → gate does NOT
236
+ cross (posterior stddev ≈ 0.077 with α=11, β=1 is above the 0.05
237
+ threshold; M=10 is the lower bound on observations, not a
238
+ sufficient condition for stability).
239
+ - **T4** — 30 cycles, 2 always-present clusters + 1 "noisy" cluster
240
+ present in only the first 4 cycles → gate does NOT cross
241
+ (`stable_cluster_ids.length === 2 < K=3`).
242
+ - **T4b** — 5 cycles total → gate does NOT cross (`cycles_observed < M`).
243
+ - **T7** — Confirms `K` and `stddev_threshold` overrides flow through
244
+ `normalizeConfig` and reach the evaluation.
245
+
246
+ These fixtures are synthetic and inline (D-11). The gate evaluator
247
+ never reads `.design/gep/events.jsonl` directly in CI — fixtures
248
+ seed the cluster lists by hand.
249
+
250
+ ---
251
+
252
+ ## Decisions referenced
253
+
254
+ - **D-01** — Two-stage approach: Stage 0 telemetry-only ships first;
255
+ Stage 1 authoring gated on data; user opts in per a one-time prompt;
256
+ no auto-flip.
257
+ - **D-03** — Default `K=3` / `M=10` / `stddev_threshold=0.05`,
258
+ overridable via `.design/config.json`.
259
+ - **D-11** — Tests use synthetic fixtures (no live event chain reads).
260
+ - **Phase 23.5** — Posterior `stddev(Beta(α, β))` closed form and
261
+ Laplace prior convention reused here.
@@ -0,0 +1,185 @@
1
+ # Known Failure Modes (Phase 30 Triage Gate)
2
+
3
+ This file is the **catalogue of locally-fixable failure modes** that the
4
+ Phase 30 issue-reporter consults *before* prompting the user to file a
5
+ GitHub issue. The triage gate runs first (D-07): when an entry matches
6
+ the user's error, the gate surfaces `this looks like X — try Y` and
7
+ exits the report flow without prompting. `--force-report` bypasses the
8
+ gate but still requires consent (D-11).
9
+
10
+ ## Schema
11
+
12
+ Each entry is a single fenced ```yaml block with this flat key:value shape:
13
+
14
+ - `id` — stable identifier (kebab-case or `KFM-NNN` numeric). Required.
15
+ - `pattern` — JavaScript regex string. Matched against
16
+ `[error.message, error.stack].filter(Boolean).join("\n")`. Required.
17
+ - `diagnosis` — one-sentence plain-English root cause. Required.
18
+ - `remedy` — one-sentence user-runnable action. Required.
19
+ - `severity` — advisory only, one of `low` / `medium` / `high`. Required.
20
+ - `propose_report` — boolean. If `true`, this mode is on the D-11
21
+ whitelist: 30-04 may *propose* `--report` at error time for this
22
+ class. Defaults to `false`. Advisory; the matcher does not act on it.
23
+
24
+ ## Matching policy
25
+
26
+ - **First match wins.** Entries are evaluated in file order. The matcher
27
+ returns the first entry whose regex tests true against the haystack.
28
+ No severity ranking, no aggregation, no blending.
29
+ - **Invalid regex is non-fatal.** An entry whose `pattern` fails to
30
+ compile is skipped with a `console.warn`, never crashes the matcher.
31
+ - **Missing catalogue is non-fatal.** If this file is absent or
32
+ unparseable, `matchKnownFailure` returns `{ matched: false }` and
33
+ warns once.
34
+
35
+ Consumed by `scripts/lib/issue-reporter/triage-matcher.cjs`
36
+ (`matchKnownFailure(errorContext)`). Wired into `skills/report-issue`
37
+ (Plan 30-04) before the consent prompt.
38
+
39
+ ## Entries
40
+
41
+ ### KFM-001 — EACCES on `.design/` write
42
+
43
+ Permission failure when the plugin writes into `.design/`. Common after
44
+ `sudo`-cloning a repo or running CI as a user without write access to
45
+ the project root.
46
+
47
+ ```yaml
48
+ id: KFM-001
49
+ pattern: 'EACCES.*\.design'
50
+ diagnosis: 'Permission denied writing to .design/ — the plugin cannot persist its work-product directory.'
51
+ remedy: 'Run `chown -R "$USER" .design` (or recreate the directory as your normal user) and retry the command.'
52
+ severity: medium
53
+ propose_report: false
54
+ ```
55
+
56
+ ### KFM-002 — `gh` CLI not on PATH
57
+
58
+ The Phase 30 outbound submission path requires the user's `gh` CLI
59
+ (D-05). If it's missing, Plan 30-06 falls back to clipboard + URL.
60
+ This entry catches the typical shell-spawn error.
61
+
62
+ ```yaml
63
+ id: KFM-002
64
+ pattern: '(gh: command not found|spawn gh ENOENT|''gh'' is not recognized)'
65
+ diagnosis: 'GitHub CLI (`gh`) is not installed or not on PATH; the issue reporter''s outbound path relies on it.'
66
+ remedy: 'Install gh from https://cli.github.com and run `gh auth login`, then retry. (Or use the clipboard fallback: the payload is already on disk under .design/issue-drafts/.)'
67
+ severity: low
68
+ propose_report: false
69
+ ```
70
+
71
+ ### KFM-003 — Node.js version mismatch
72
+
73
+ `package.json` declares `engines.node: ">=22"`. Older Node versions
74
+ crash on the `--experimental-strip-types` test runner, or fail subtle
75
+ TypeScript-import behaviour.
76
+
77
+ ```yaml
78
+ id: KFM-003
79
+ pattern: '(engine "node" is incompatible|Unsupported engine|SyntaxError.*Unexpected token.*satisfies|--experimental-strip-types)'
80
+ diagnosis: 'Active Node.js version is below the plugin''s required >=22; modern syntax features and the strip-types test runner are unavailable.'
81
+ remedy: 'Upgrade Node to >=22 (e.g. `nvm install 22 && nvm use 22`) and rerun.'
82
+ severity: high
83
+ propose_report: false
84
+ ```
85
+
86
+ ### KFM-004 — Figma token missing
87
+
88
+ Figma-aware flows expect `FIGMA_TOKEN` (or the documented env-var alias)
89
+ to be present. The 401/missing-env error class is recognisable.
90
+
91
+ ```yaml
92
+ id: KFM-004
93
+ pattern: '(FIGMA_TOKEN.*(not set|missing|undefined)|Figma.*401|figma.*unauthor)'
94
+ diagnosis: 'FIGMA_TOKEN environment variable is missing or invalid; Figma-dependent commands cannot authenticate.'
95
+ remedy: 'Generate a personal access token at https://www.figma.com/developers/api#access-tokens and `export FIGMA_TOKEN=<token>` in your shell profile.'
96
+ severity: medium
97
+ propose_report: false
98
+ ```
99
+
100
+ ### KFM-005 — Git working tree dirty
101
+
102
+ Several phase-tooling commands assume a clean working tree (clean
103
+ checkpoints between cycles). A dirty tree surfaces as a stderr line
104
+ the matcher can recognise.
105
+
106
+ ```yaml
107
+ id: KFM-005
108
+ pattern: '(working tree (is )?(not clean|dirty)|uncommitted changes|Changes not staged for commit)'
109
+ diagnosis: 'Git working tree has uncommitted changes; the command requires a clean checkpoint before proceeding.'
110
+ remedy: 'Commit, stash (`git stash -u`), or discard your local changes, then rerun the command.'
111
+ severity: low
112
+ propose_report: false
113
+ ```
114
+
115
+ ### KFM-006 — `.planning/` directory missing
116
+
117
+ GSD/GDD project commands assume `.planning/` has been initialised by
118
+ `/gsd:new-project`. A bare ENOENT on that path is a clear self-fix.
119
+
120
+ ```yaml
121
+ id: KFM-006
122
+ pattern: 'ENOENT.*\.planning'
123
+ diagnosis: '.planning/ directory does not exist; the project has not been initialised yet.'
124
+ remedy: 'Run `/gsd:new-project` to bootstrap the planning structure, then retry.'
125
+ severity: medium
126
+ propose_report: false
127
+ ```
128
+
129
+ ### KFM-007 — `reference/registry.json` invalid JSON
130
+
131
+ The Phase 14.5 registry is hand-edited; a stray trailing comma or
132
+ unquoted key surfaces here. Self-fixable, not a maintainer issue.
133
+
134
+ ```yaml
135
+ id: KFM-007
136
+ pattern: '(reference/registry\.json.*(SyntaxError|JSON|Unexpected token)|Unexpected token.*registry\.json)'
137
+ diagnosis: 'reference/registry.json failed to parse as JSON — likely a trailing comma or unbalanced brace from a recent edit.'
138
+ remedy: 'Open reference/registry.json in your editor; the JSON parser error message will pinpoint the line. Fix the syntax and retry.'
139
+ severity: medium
140
+ propose_report: false
141
+ ```
142
+
143
+ ### KFM-008 — MCP server unreachable
144
+
145
+ When the Figma / GDD MCP servers are not running, commands depending
146
+ on them fail with a clear connection-refused class of error.
147
+
148
+ ```yaml
149
+ id: KFM-008
150
+ pattern: '(MCP.*(unreachable|ECONNREFUSED|not connected)|mcp.*server.*not.*running|connection refused.*ws://)'
151
+ diagnosis: 'An MCP server (Figma, GDD-state, or GDD-tools) is not reachable; the plugin cannot route tool calls through it.'
152
+ remedy: 'Start the relevant MCP server (see scripts/mcp-servers/) and confirm `claude mcp list` shows it as connected.'
153
+ severity: medium
154
+ propose_report: true
155
+ ```
156
+
157
+ ### KFM-009 — Plugin file accidentally deleted
158
+
159
+ A user-side `git clean -fdx` or aggressive editor refactor can remove
160
+ plugin files. This is a re-install path, not a bug report path — but
161
+ it's on the whitelist because users typically can't tell it apart from
162
+ an upstream regression.
163
+
164
+ ```yaml
165
+ id: KFM-009
166
+ pattern: 'Cannot find module.*(scripts/lib/|skills/.*SKILL\.md|reference/.*\.md)'
167
+ diagnosis: 'A plugin file is missing — most often the result of a local `git clean` or a partial install.'
168
+ remedy: 'Reinstall the plugin: `npm install -g @hegemonart/get-design-done` (or pull the repo fresh in dev). If the file should exist, the error message gives its path.'
169
+ severity: medium
170
+ propose_report: true
171
+ ```
172
+
173
+ ### KFM-010 — Disk full / ENOSPC
174
+
175
+ Out-of-space failures masquerade as obscure write errors. Self-fixable
176
+ by freeing space; not a maintainer report path.
177
+
178
+ ```yaml
179
+ id: KFM-010
180
+ pattern: '(ENOSPC|no space left on device|disk full)'
181
+ diagnosis: 'Disk is full — no space left on the device the plugin is writing to.'
182
+ remedy: 'Free space (e.g. clear `.design/cache/`, prune old worktrees, empty trash) and retry.'
183
+ severity: high
184
+ propose_report: false
185
+ ```