@opengsd/gsd-core 1.5.0-rc.2 → 1.5.0-rc.4

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 (131) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/agents/gsd-advisor-researcher.md +1 -1
  3. package/agents/gsd-assumptions-analyzer.md +1 -1
  4. package/agents/gsd-code-fixer.md +1 -1
  5. package/agents/gsd-code-reviewer.md +1 -1
  6. package/agents/gsd-codebase-mapper.md +1 -1
  7. package/agents/gsd-debugger.md +1 -1
  8. package/agents/gsd-doc-writer.md +1 -1
  9. package/agents/gsd-eval-auditor.md +1 -1
  10. package/agents/gsd-executor.md +1 -1
  11. package/agents/gsd-integration-checker.md +1 -1
  12. package/agents/gsd-mempalace-curator.md +47 -0
  13. package/agents/gsd-nyquist-auditor.md +1 -0
  14. package/agents/gsd-phase-researcher.md +1 -1
  15. package/agents/gsd-plan-checker.md +1 -1
  16. package/agents/gsd-planner.md +1 -1
  17. package/agents/gsd-project-researcher.md +1 -1
  18. package/agents/gsd-research-synthesizer.md +1 -1
  19. package/agents/gsd-roadmapper.md +55 -2
  20. package/agents/gsd-security-auditor.md +1 -0
  21. package/agents/gsd-ui-auditor.md +1 -1
  22. package/agents/gsd-ui-checker.md +1 -1
  23. package/agents/gsd-ui-researcher.md +1 -1
  24. package/agents/gsd-verifier.md +13 -2
  25. package/bin/install.js +61 -64
  26. package/commands/gsd/mempalace-capture.md +71 -0
  27. package/commands/gsd/mempalace-recall.md +102 -0
  28. package/commands/gsd/ns-context.md +4 -2
  29. package/commands/gsd/progress.md +2 -1
  30. package/gemini-extension.json +1 -1
  31. package/gsd-core/bin/gsd-tools.cjs +277 -95
  32. package/gsd-core/bin/lib/active-workstream-store.cjs +6 -0
  33. package/gsd-core/bin/lib/capability-activation.cjs +86 -0
  34. package/gsd-core/bin/lib/capability-registry.cjs +1468 -11
  35. package/gsd-core/bin/lib/capability-state.cjs +128 -21
  36. package/gsd-core/bin/lib/capability-writer.cjs +354 -0
  37. package/gsd-core/bin/lib/check-command-router.cjs +328 -1
  38. package/gsd-core/bin/lib/clusters.cjs +2 -0
  39. package/gsd-core/bin/lib/command-roster.cjs +19 -0
  40. package/gsd-core/bin/lib/commands.cjs +33 -10
  41. package/gsd-core/bin/lib/config-loader.cjs +7 -8
  42. package/gsd-core/bin/lib/config-schema.cjs +32 -3
  43. package/gsd-core/bin/lib/config.cjs +81 -26
  44. package/gsd-core/bin/lib/core.cjs +5 -2
  45. package/gsd-core/bin/lib/edge-probe.cjs +25 -2
  46. package/gsd-core/bin/lib/frontmatter.cjs +53 -1
  47. package/gsd-core/bin/lib/git-base-branch.cjs +194 -0
  48. package/gsd-core/bin/lib/init.cjs +36 -11
  49. package/gsd-core/bin/lib/install-profiles.cjs +57 -1
  50. package/gsd-core/bin/lib/installer-migration-report.cjs +1 -0
  51. package/gsd-core/bin/lib/loop-resolver.cjs +157 -16
  52. package/gsd-core/bin/lib/model-resolver.cjs +47 -5
  53. package/gsd-core/bin/lib/phase.cjs +99 -23
  54. package/gsd-core/bin/lib/plan-drift-guard.cjs +117 -0
  55. package/gsd-core/bin/lib/probe-core.cjs +117 -1
  56. package/gsd-core/bin/lib/profile-output.cjs +45 -4
  57. package/gsd-core/bin/lib/profile-pipeline-command-router.cjs +138 -0
  58. package/gsd-core/bin/lib/roadmap-parser.cjs +13 -3
  59. package/gsd-core/bin/lib/roadmap.cjs +97 -7
  60. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +1946 -0
  61. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +54 -30
  62. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +27 -19
  63. package/gsd-core/bin/lib/runtime-homes.cjs +26 -20
  64. package/gsd-core/bin/lib/state-command-router.cjs +15 -3
  65. package/gsd-core/bin/lib/state-document.cjs +46 -1
  66. package/gsd-core/bin/lib/state.cjs +461 -94
  67. package/gsd-core/bin/lib/verify.cjs +92 -8
  68. package/gsd-core/bin/lib/worktree-safety.cjs +2 -1
  69. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -2
  70. package/gsd-core/bin/shared/config-schema.manifest.json +0 -18
  71. package/gsd-core/bin/shared/model-catalog.json +1 -0
  72. package/gsd-core/references/edge-probe.md +11 -0
  73. package/gsd-core/references/loop-hook-dispatch.md +61 -0
  74. package/gsd-core/references/prohibition-probe-fixtures/01-streak-reminder/expected.json +14 -0
  75. package/gsd-core/references/prohibition-probe-fixtures/02-clean-utility/expected.json +4 -0
  76. package/gsd-core/references/prohibition-probe-fixtures/03-multi-prohibition/expected.json +32 -0
  77. package/gsd-core/references/prohibition-probe.md +248 -0
  78. package/gsd-core/templates/config.json +1 -1
  79. package/gsd-core/templates/spec.md +14 -0
  80. package/gsd-core/workflows/audit-milestone.md +5 -3
  81. package/gsd-core/workflows/autonomous.md +10 -5
  82. package/gsd-core/workflows/code-review-fix.md +9 -7
  83. package/gsd-core/workflows/code-review.md +8 -6
  84. package/gsd-core/workflows/complete-milestone.md +1 -5
  85. package/gsd-core/workflows/discuss-phase.md +14 -0
  86. package/gsd-core/workflows/execute-phase.md +86 -146
  87. package/gsd-core/workflows/execute-plan.md +21 -6
  88. package/gsd-core/workflows/help/modes/full.md +7 -1
  89. package/gsd-core/workflows/new-project.md +3 -3
  90. package/gsd-core/workflows/next.md +50 -2
  91. package/gsd-core/workflows/pause-work.md +7 -1
  92. package/gsd-core/workflows/plan-phase.md +91 -221
  93. package/gsd-core/workflows/plan-review-convergence.md +14 -4
  94. package/gsd-core/workflows/pr-branch.md +4 -2
  95. package/gsd-core/workflows/profile-user.md +3 -1
  96. package/gsd-core/workflows/progress.md +58 -1
  97. package/gsd-core/workflows/quick.md +12 -8
  98. package/gsd-core/workflows/resume-project.md +17 -1
  99. package/gsd-core/workflows/review.md +19 -2
  100. package/gsd-core/workflows/secure-phase.md +4 -2
  101. package/gsd-core/workflows/settings-advanced.md +2 -0
  102. package/gsd-core/workflows/settings.md +27 -1
  103. package/gsd-core/workflows/ship.md +58 -5
  104. package/gsd-core/workflows/spec-phase.md +75 -0
  105. package/gsd-core/workflows/validate-phase.md +4 -2
  106. package/gsd-core/workflows/verify-phase.md +14 -4
  107. package/gsd-core/workflows/verify-work.md +27 -11
  108. package/hooks/dist/gsd-ensure-canonical-path.js +305 -0
  109. package/hooks/dist/gsd-statusline.js +1 -1
  110. package/hooks/dist/managed-hooks-registry.cjs +1 -0
  111. package/hooks/gsd-ensure-canonical-path.js +305 -0
  112. package/hooks/gsd-statusline.js +1 -1
  113. package/hooks/hooks.json +1 -0
  114. package/hooks/managed-hooks-registry.cjs +1 -0
  115. package/package.json +5 -4
  116. package/scripts/affected-tests-lib.cjs +16 -4
  117. package/scripts/build-hooks.js +7 -0
  118. package/scripts/changeset/new.cjs +17 -3
  119. package/scripts/fix-slash-commands.cjs +15 -3
  120. package/scripts/gen-capability-registry.cjs +373 -49
  121. package/scripts/gen-inventory-manifest.cjs +1 -4
  122. package/scripts/gen-loop-host-contract.cjs +55 -0
  123. package/scripts/issue-version-gate.cjs +140 -0
  124. package/scripts/lint-allow-test-rule-refs.allowlist.json +327 -0
  125. package/scripts/lint-allow-test-rule-refs.cjs +162 -0
  126. package/scripts/lint-test-file-count.allowlist.json +14 -0
  127. package/scripts/mutation-matrix.cjs +108 -7
  128. package/scripts/pr-target-policy.cjs +63 -0
  129. package/scripts/release-tarball-smoke.cjs +7 -1
  130. package/scripts/research-profiles.cjs +5 -5
  131. package/scripts/run-tests.cjs +178 -17
@@ -0,0 +1,248 @@
1
+ # Prohibition-Probe — Spec-Completeness Must-NOT Reference
2
+
3
+ Shared reference for the spec/requirements phase. Companion to
4
+ `@~/.claude/gsd-core/references/edge-probe.md`: `edge-probe` reaches the
5
+ **data/behavior-shape axis** (boundaries, adjacency, encoding, ordering) — the things a
6
+ feature must *do*. This reference reaches the orthogonal **must-NOT axis** (product, values,
7
+ safety, ethics) — the things a feature must *never silently become*. The edge-probe caught
8
+ 0/8 of these in controlled testing because it is the wrong instrument: a shape taxonomy
9
+ cannot surface "the reminder must not shame the user." Walk each requirement through the
10
+ two-stage recall→precision protocol below and resolve each surfaced prohibition to exactly
11
+ one state.
12
+
13
+ This doc is written in generic `requirements → checks → verifier` terms with no
14
+ tool-specific vocabulary, so it is portable: copy it into any spec/requirements process.
15
+ A short mapping table at the end binds it to common host structures.
16
+
17
+ ## Why front-of-pipeline
18
+
19
+ A goal-backward verifier only checks assertions that exist; an assertion only exists for a
20
+ requirement that was written down. The class of constraint this probe targets — the
21
+ *"must-NOT"* the author assumed but never wrote — is invisible to the verifier in exactly
22
+ the same way an omitted edge is, but with a sharper failure mode: a `✅ done` that means
23
+ "the code matches the words in the spec" can still ship a feature that does what the author
24
+ explicitly would *not* want. The manipulative-streak reminder, the loan model that proxies
25
+ on zip code, the audit log that stores raw SSN — each one passes a literal spec while
26
+ violating the intent. The fix is not a better verifier; it is **spec completeness**: surface
27
+ the omitted prohibition into an explicit, checkable acceptance criterion *before* any code
28
+ exists, after which the verifier reliably enforces it.
29
+
30
+ The technique is adversarial elicitation, not deterministic computation. Unlike the edge
31
+ taxonomy (a closed eight categories a classifier can apply), the recall stage is inherently
32
+ model-driven: it asks an open question and reads prose. There is **no compiled
33
+ `prohibition-probe.cjs` engine** — the recall stage is an LLM prose pass, and only the
34
+ schema/projection layer is real code (ADR-550 Decision 7b). Building a deterministic
35
+ recall adapter would be the scope-creep the maintainer flags.
36
+
37
+ ## Inputs
38
+
39
+ A list of requirements, each a `{ id, text }` record where `text` is a testable statement.
40
+ There is no shape override and no taxonomy classifier — the recall stage reads the prose
41
+ directly and the precision stage filters its raw output. The probe runs **after** the
42
+ edge-probe in the spec phase, over the same requirement list.
43
+
44
+ ## Two-stage protocol (recall → precision)
45
+
46
+ The probe is a two-pass pipeline per requirement. Stage 1 maximizes recall (cast wide);
47
+ Stage 2 restores precision (drop the noise). Running them in this order — wide then narrow —
48
+ is what keeps the surfaced list both complete and short.
49
+
50
+ **Stage 1 — Recall (adversarial probe).** Ask the single adversarial question of each
51
+ requirement:
52
+
53
+ > *What could this feature silently become that the author would NOT want, but the spec
54
+ > does not forbid?*
55
+
56
+ This question is model-robust (17/17 holistic surfacing including smaller models in the N18
57
+ experiment). It deliberately over-produces: ~10 raw candidates per requirement, including
58
+ routine engineering items. That over-production is intentional — recall first.
59
+
60
+ **Stage 2 — Precision (one-pass classifier).** Filter the raw Stage-1 list in a single pass.
61
+ The rule is a drop/keep split:
62
+
63
+ - **DROP routine-engineering items** — anything that is a normal correctness or hygiene
64
+ concern rather than an intent constraint: "must not mutate its input", "must not throw on
65
+ empty list", "must return a primitive not an object", "must not leak a file handle". These
66
+ belong to the edge-probe or to ordinary code review, not here.
67
+ - **KEEP values / safety / ethics items** — anything that, if violated, makes the feature do
68
+ something the author would object to on product, fairness, privacy, transparency, or
69
+ safety grounds: "must not use shaming framing", "must not proxy on protected attributes",
70
+ "must not store raw PII in plaintext".
71
+
72
+ This collapses the raw ~10 to ~2–3 genuine prohibitions (GT 5/5, 0 false positives on the
73
+ N18 eight-spec battery). A requirement that yields zero kept prohibitions emits an empty
74
+ list — that is the correct precision outcome for a pure utility, not a failure.
75
+
76
+ ## Canon-referral (do not mint canon items)
77
+
78
+ Some kept candidates are not bespoke at all — they are **canon** security/compliance
79
+ constraints that a dedicated tool already owns. Do NOT mint a prohibition for them. Instead
80
+ emit a one-line breadcrumb and stop:
81
+
82
+ - OWASP / prototype-pollution / path-traversal / injection → breadcrumb to `/gsd:secure-phase`
83
+ and `eslint` (security plugins), not a minted prohibition.
84
+ - GDPR / data-retention / consent → breadcrumb to `/gsd:secure-phase`.
85
+ - Generic fairness/bias canon → breadcrumb to `/gsd:secure-phase`.
86
+
87
+ The breadcrumb reads like: *"prototype-pollution is canon — covered by /gsd:secure-phase +
88
+ eslint; not minted here."* This keeps the surfaced list to the ~2–3 **bespoke** items that
89
+ no other tool would catch — the manipulative-framing prohibition, the product-specific
90
+ fairness constraint — which is the whole value of the probe. Minting canon items both
91
+ duplicates other tooling and drowns the bespoke signal (ADR-550 Decision 6).
92
+
93
+ ## Resolution states
94
+
95
+ Each surfaced prohibition carries two orthogonal axes — a resolution **lifecycle** and, when
96
+ resolved, a **verification** tier (ADR-550 Decision 7, the shared probe-core model; the
97
+ lifecycle is identical to the edge-probe, the verification tiers differ):
98
+
99
+ - **status** — `resolved | dismissed | unresolved` (IDENTICAL to the edge-probe):
100
+ - **resolved** — the prohibition is addressed; *how* it is addressed is the verification tier.
101
+ - **dismissed** — not a genuine prohibition for this feature, accompanied by a required,
102
+ non-empty reason string. "N/A — this utility has no user-facing surface, no values
103
+ constraint applies" is valid; silence is not. The reason string is the audit trail.
104
+ - **unresolved** — carried forward and flagged; the author chose not to resolve it yet.
105
+ - **verification** (only when `status` is `resolved`; `null` otherwise) — `test | judgment`
106
+ (this REPLACES the edge-probe's `explicit | backstop`):
107
+ - **test** — the prohibition can be mechanically checked (a negative test, a lint rule, an
108
+ assertion that the audit log contains no raw SSN). A checkable assertion exists.
109
+ - **judgment** — the prohibition is real but cannot be reduced to a mechanical test (a
110
+ human/LLM judgment that the framing is not manipulative). It records intent and routes
111
+ to a judgment-based review rather than a green/red test.
112
+
113
+ Splitting these axes keeps the lifecycle enum free of a verification fact and lets the
114
+ prohibition adapter declare `test | judgment` without forking the shared lifecycle enum that
115
+ the edge-probe's `explicit | backstop` also uses.
116
+
117
+ ## Output schema
118
+
119
+ The probe emits, per kept prohibition, an item of the form:
120
+
121
+ ```
122
+ { requirement_id, category, status, verification, resolution, reason, statement }
123
+ ```
124
+
125
+ where `statement` is the must-NOT sentence and `category` is the values/safety/ethics class
126
+ (`values`, `fairness`, `privacy`, `transparency`, `safety`, …), plus a coverage summary:
127
+
128
+ ```
129
+ coverage: { applicable, resolved, unresolved, byVerification: { test, judgment } }
130
+ ```
131
+
132
+ `applicable` is the number of kept prohibitions, `resolved` = closed (`resolved` +
133
+ `dismissed`) status items, `unresolved` is the remainder, and `byVerification` breaks the
134
+ `resolved`-status items down by tier (`{ test, judgment }`). This JSON is the stable contract
135
+ both the reference implementation and any third-party port emit.
136
+
137
+ ## Generic mapping (requirements → checks → verifier)
138
+
139
+ | Host structure | "requirement" | a `resolved`/`test` prohibition becomes | a `resolved`/`judgment` prohibition becomes |
140
+ |----------------|---------------|------------------------------------------|----------------------------------------------|
141
+ | GSD SPEC | a SPEC Requirement | a SPEC acceptance criterion (marked prohibition) that `plan-phase` lifts into `must_haves.prohibitions` | a `must_haves.prohibitions` item routed to judgment review |
142
+ | Gherkin feature | a Scenario | a negative `Then` assertion / tagged negative scenario | a tagged scenario routed to manual review |
143
+ | OpenAPI operation | an operation | a contract test asserting the forbidden behavior never occurs | a documented constraint flagged for review |
144
+ | Docstring contract | a documented behavior | a negative assertion in the contract test | a documented must-NOT for reviewers |
145
+
146
+ The portable invariant: a `resolved`/`test` prohibition produces **a checkable negative the
147
+ verifier iterates over** (GSD: a `must_haves.prohibitions` item with a test); a
148
+ `resolved`/`judgment` prohibition produces a recorded intent routed to judgment review. An
149
+ `unresolved` prohibition is an explicit assumption the downstream planner must surface, not
150
+ silently drop.
151
+
152
+ ## Worked example (streak-reminder)
153
+
154
+ A single requirement to send a daily habit reminder. The edge-probe sees a `stateful`
155
+ requirement and asks about idempotency; the prohibition-probe asks the adversarial question
156
+ and surfaces what the reminder must never *become*. Stage 1 over-produces ("must not spam",
157
+ "must not throw on a deleted habit", "must not use shaming framing"); Stage 2 drops the
158
+ routine-engineering items and keeps the one genuine values prohibition:
159
+
160
+ ```json prohibition-probe:01-streak-reminder/expected.json
161
+ {
162
+ "items": [
163
+ {
164
+ "requirement_id": "R1",
165
+ "category": "values",
166
+ "status": "resolved",
167
+ "verification": "judgment",
168
+ "resolution": null,
169
+ "reason": null,
170
+ "statement": "MUST NOT use shaming, guilt, or loss-aversion streak framing (e.g. \"Don't lose your streak!\") — the reminder must encourage without penalty framing"
171
+ }
172
+ ],
173
+ "coverage": { "applicable": 1, "resolved": 1, "unresolved": 0, "byVerification": { "test": 0, "judgment": 1 } }
174
+ }
175
+ ```
176
+
177
+ The kept prohibition is `judgment`-tier: "manipulative framing" cannot be reduced to a
178
+ mechanical test, so it records intent and routes to judgment review — but it is now an
179
+ explicit acceptance criterion the spec must clear, not an unwritten assumption.
180
+
181
+ ## Worked example (clean-utility)
182
+
183
+ A pure utility requirement — "deduplicate a list of integers" — has no user-facing surface,
184
+ no values/safety/ethics dimension. Stage 1 still over-produces ("must not mutate the input",
185
+ "must not change order"), but every candidate is routine engineering that Stage 2 drops (and
186
+ the edge-probe already owns). The correct precision outcome is an empty prohibition list — a
187
+ zero, not a false positive:
188
+
189
+ ```json prohibition-probe:02-clean-utility/expected.json
190
+ {
191
+ "items": [],
192
+ "coverage": { "applicable": 0, "resolved": 0, "unresolved": 0, "byVerification": { "test": 0, "judgment": 0 } }
193
+ }
194
+ ```
195
+
196
+ This is the precision discipline that keeps the probe from crying wolf: a utility with no
197
+ intent surface produces zero prohibitions, so a non-empty list always carries signal.
198
+
199
+ ## Worked example (multi-prohibition)
200
+
201
+ A loan-decision requirement is the high-stakes case: it surfaces several distinct
202
+ prohibitions across categories. Stage 1 produces a long list including canon items
203
+ (prototype-pollution, generic GDPR retention) that canon-referral breadcrumbs out; Stage 2
204
+ keeps the three bespoke values/safety items — a `fairness` constraint, a `privacy` constraint
205
+ (`test`-tier, mechanically checkable against the audit log), and a `transparency` constraint:
206
+
207
+ ```json prohibition-probe:03-multi-prohibition/expected.json
208
+ {
209
+ "items": [
210
+ {
211
+ "requirement_id": "R1",
212
+ "category": "fairness",
213
+ "status": "resolved",
214
+ "verification": "judgment",
215
+ "resolution": null,
216
+ "reason": null,
217
+ "statement": "MUST NOT use protected attributes (race, gender, age, national origin) or their proxies (zip code, name) in the loan decision or rate"
218
+ },
219
+ {
220
+ "requirement_id": "R1",
221
+ "category": "privacy",
222
+ "status": "resolved",
223
+ "verification": "test",
224
+ "resolution": null,
225
+ "reason": null,
226
+ "statement": "MUST NOT store raw PII / financial secrets (SSN, full account or card numbers) in plaintext in the audit log"
227
+ },
228
+ {
229
+ "requirement_id": "R1",
230
+ "category": "transparency",
231
+ "status": "resolved",
232
+ "verification": "judgment",
233
+ "resolution": null,
234
+ "reason": null,
235
+ "statement": "MUST NOT mislead or omit the true rate/APR/terms in the explanation; an adverse decision must state the real principal reason (adverse-action)"
236
+ }
237
+ ],
238
+ "coverage": { "applicable": 3, "resolved": 3, "unresolved": 0, "byVerification": { "test": 1, "judgment": 2 } }
239
+ }
240
+ ```
241
+
242
+ The `privacy` row is `test`-tier — "no raw SSN in the audit log" is a mechanical assertion —
243
+ while `fairness` and `transparency` are `judgment`-tier. The byVerification rollup
244
+ `{ test: 1, judgment: 2 }` is the count-preserved breakdown of the three `resolved`-status
245
+ items. Each worked-example block above is kept byte-for-byte (parsed-JSON) identical to its
246
+ fixture under `gsd-core/references/prohibition-probe-fixtures/` by
247
+ `tests/prohibition-probe.docs-fixtures.test.cjs`, so the doc and the reference data cannot
248
+ silently drift.
@@ -58,5 +58,5 @@
58
58
  },
59
59
  "project_code": null,
60
60
  "agent_skills": {},
61
- "claude_md_path": "./CLAUDE.md"
61
+ "claude_md_path": "./.claude/CLAUDE.md"
62
62
  }
@@ -80,6 +80,20 @@ No "should feel good", "looks reasonable", or "generally works" — those are no
80
80
  Acceptance Criteria above; `backstop` rows must be carried into plan-phase `must_haves`.
81
81
  `⚠ UNRESOLVED` rows are flagged: planner must treat as assumption.]
82
82
 
83
+ ## Prohibitions (must-NOT)
84
+
85
+ **Coverage:** [resolved]/[applicable] applicable prohibitions resolved · [unresolved] unresolved
86
+
87
+ | Prohibition (must-NOT statement) | Requirement | Status | Verification / Reason |
88
+ |----------------------------------|-------------|--------|------------------------|
89
+ | [MUST NOT … must-NOT statement] | [Rn] | [resolved / dismissed / ⚠ UNRESOLVED] | [verification: test \| judgment, or dismissal reason] |
90
+
91
+ [Generated by the prohibition probe (Step 5.6). `resolved` prohibitions become NEGATIVE
92
+ acceptance criteria; a `resolved`/`test` row is a checkable negative the verifier iterates
93
+ over, a `resolved`/`judgment` row routes to judgment review. Resolved prohibitions are lifted
94
+ into `must_haves.prohibitions` by plan-phase. `dismissed` rows carry a required non-empty
95
+ reason. `⚠ UNRESOLVED` rows are flagged: planner must treat as assumption.]
96
+
83
97
  ## Ambiguity Report
84
98
 
85
99
  | Dimension | Score | Min | Status | Notes |
@@ -143,13 +143,15 @@ For each REQ-ID, determine status using all three sources:
143
143
 
144
144
  ## 5.5. Nyquist Compliance Discovery
145
145
 
146
- Skip if `workflow.nyquist_validation` is explicitly `false` (absent = enabled).
146
+ Skip if the Nyquist capability is inactive.
147
147
 
148
148
  ```bash
149
- NYQUIST_CONFIG=$(gsd_run query config-get workflow.nyquist_validation --raw --default true 2>/dev/null)
149
+ VERIFY_POST_HOOKS_JSON=$(gsd_run loop render-hooks verify:post --raw)
150
150
  ```
151
151
 
152
- If `false`: skip entirely.
152
+ Resolve active step hooks from `VERIFY_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "validate-phase"`.
153
+
154
+ If no active validate-phase step hook exists: skip entirely.
153
155
 
154
156
  For each phase directory, check `*-VALIDATION.md`. If exists, parse frontmatter (`nyquist_compliant`, `wave_0_complete`).
155
157
 
@@ -453,17 +453,22 @@ Skill(skill="gsd-execute-phase", args="${PHASE_NUM} --no-transition")
453
453
 
454
454
  Auto-invoke code review and fix chain. Autonomous mode chains both review and fix (unlike execute-phase/quick which only suggest fix).
455
455
 
456
- **Config gate:**
456
+ **Capability dispatch:**
457
457
  ```bash
458
- CODE_REVIEW_ENABLED=$(gsd_run query config-get workflow.code_review 2>/dev/null || echo "true")
458
+ EXECUTE_POST_HOOKS_JSON=$(gsd_run loop render-hooks execute:post --raw)
459
459
  ```
460
- If `"false"`: display "Code review skipped (workflow.code_review=false)" and proceed to 3d.
460
+
461
+ Resolve active step hooks from `EXECUTE_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "code-review"`.
462
+
463
+ If no active code-review step hook exists: display "Code review skipped (code-review capability inactive)" and proceed to 3d. This covers `workflow.code_review=false` through the Capability Registry; do not query the code-review toggle directly here.
464
+
465
+ For each active code-review step hook, dispatch the skill using the registry-provided stem:
461
466
 
462
467
  ```
463
- Skill(skill="gsd-code-review", args="${PHASE_NUM}")
468
+ Skill(skill="gsd-${ref.skill}", args="${PHASE_NUM}")
464
469
  ```
465
470
 
466
- Parse status from REVIEW.md frontmatter. If "clean" or "skipped": proceed to 3d. If findings found: auto-invoke:
471
+ Parse status from REVIEW.md frontmatter. If "clean" or "skipped": proceed to 3d. If findings found after the capability-dispatched review, auto-invoke the consolidated fix entry point:
467
472
  ```
468
473
  Skill(skill="gsd-code-review", args="${PHASE_NUM} --fix --auto")
469
474
  ```
@@ -74,21 +74,23 @@ FIX_REPORT_PATH="${PHASE_DIR}/${PADDED_PHASE}-REVIEW-FIX.md"
74
74
  </step>
75
75
 
76
76
  <step name="check_config_gate">
77
- Check if code review is enabled via config:
77
+ Check if code review is active via the capability registry:
78
78
 
79
79
  ```bash
80
- CODE_REVIEW_ENABLED=$(gsd_run query config-get workflow.code_review 2>/dev/null || echo "true")
80
+ EXECUTE_POST_HOOKS_JSON=$(gsd_run loop render-hooks execute:post --raw)
81
81
  ```
82
82
 
83
- If CODE_REVIEW_ENABLED is "false":
83
+ Resolve active step hooks from `EXECUTE_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "code-review"`.
84
+
85
+ If no active code-review step hook exists:
84
86
  ```
85
- Code review fix skipped (workflow.code_review=false in config)
87
+ Code review fix skipped (code-review capability inactive)
86
88
  ```
87
89
  Exit workflow.
88
90
 
89
- Default is true — only skip on explicit false. This check runs AFTER phase validation so invalid phase errors are shown first.
91
+ Default is active through the Capability Registry schema — only skip when the registry resolves no active code-review step hook. This check runs AFTER phase validation so invalid phase errors are shown first.
90
92
 
91
- Note: This reuses the `workflow.code_review` config key rather than introducing a separate `workflow.code_review_fix` key. Rationale: fixes are meaningless without review, so a single toggle makes sense. If independent control is needed later, a separate key can be added in v2.
93
+ Note: This reuses the code-review capability activation rather than introducing a separate code-review-fix capability. Rationale: fixes are meaningless without review, so a single activation boundary makes sense. If independent control is needed later, a separate key can be added in v2.
92
94
  </step>
93
95
 
94
96
  <step name="check_review_exists">
@@ -491,7 +493,7 @@ echo "════════════════════════
491
493
 
492
494
  <success_criteria>
493
495
  - [ ] Phase validated before config gate check
494
- - [ ] Config gate checked (workflow.code_review)
496
+ - [ ] Capability gate checked (execute:post code-review hook)
495
497
  - [ ] REVIEW.md existence verified (error if missing)
496
498
  - [ ] REVIEW.md status checked (skip if clean/skipped)
497
499
  - [ ] Agent spawned with correct config (review_path, fix_scope, fix_report_path)
@@ -73,19 +73,21 @@ fi
73
73
  </step>
74
74
 
75
75
  <step name="check_config_gate">
76
- Check if code review is enabled via config:
76
+ Check if code review is active via the capability registry:
77
77
 
78
78
  ```bash
79
- CODE_REVIEW_ENABLED=$(gsd_run query config-get workflow.code_review 2>/dev/null || echo "true")
79
+ EXECUTE_POST_HOOKS_JSON=$(gsd_run loop render-hooks execute:post --raw)
80
80
  ```
81
81
 
82
- If CODE_REVIEW_ENABLED is "false":
82
+ Resolve active step hooks from `EXECUTE_POST_HOOKS_JSON` where `kind == "step"` and `ref.skill == "code-review"`.
83
+
84
+ If no active code-review step hook exists:
83
85
  ```
84
- Code review skipped (workflow.code_review=false in config)
86
+ Code review skipped (code-review capability inactive)
85
87
  ```
86
88
  Exit workflow.
87
89
 
88
- Default is true — only skip on explicit false. This check runs AFTER phase validation so invalid phase errors are shown first.
90
+ Default is active through the Capability Registry schema — only skip when the registry resolves no active code-review step hook. This check runs AFTER phase validation so invalid phase errors are shown first.
89
91
  </step>
90
92
 
91
93
  <step name="resolve_depth">
@@ -678,7 +680,7 @@ If `--files` validation fails unexpectedly on macOS, install coreutils or use ab
678
680
 
679
681
  <success_criteria>
680
682
  - [ ] Phase validated before config gate check
681
- - [ ] Config gate checked (workflow.code_review)
683
+ - [ ] Capability gate checked (execute:post code-review hook)
682
684
  - [ ] --fix/--all/--auto flags parsed via code-review-flags.cjs typed IR (not ad-hoc bash)
683
685
  - [ ] Depth resolved with validation (quick|standard|deep)
684
686
  - [ ] File scope computed with 3 tiers: --files > SUMMARY.md > git diff
@@ -612,11 +612,7 @@ Extract `branching_strategy`, `phase_branch_template`, `milestone_branch_templat
612
612
 
613
613
  Detect base branch:
614
614
  ```bash
615
- BASE_BRANCH=$(gsd_run query config-get git.base_branch 2>/dev/null || echo "")
616
- if [ -z "$BASE_BRANCH" ] || [ "$BASE_BRANCH" = "null" ]; then
617
- BASE_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's|^refs/remotes/origin/||')
618
- BASE_BRANCH="${BASE_BRANCH:-main}"
619
- fi
615
+ BASE_BRANCH=$(gsd_run query git.base-branch)
620
616
  ```
621
617
 
622
618
  **If "none":** Skip to git_tag.
@@ -293,6 +293,13 @@ Read `@~/.claude/gsd-core/references/scout-codebase.md` — it contains the phas
293
293
  3. Build internal `<codebase_context>` per the reference's output schema
294
294
  </step>
295
295
 
296
+ <step name="dispatch_discuss_pre_hooks">
297
+ ```bash
298
+ DISCUSS_PRE_HOOKS_JSON=$(gsd_run loop render-hooks discuss:pre --raw)
299
+ ```
300
+ Apply each entry in `activeHooks` per @~/.claude/gsd-core/references/loop-hook-dispatch.md. Empty list → continue to `analyze_phase`.
301
+ </step>
302
+
296
303
  <step name="analyze_phase">
297
304
  Analyze the phase to identify gray areas. Use both `prior_decisions` and `codebase_context` to ground the analysis.
298
305
 
@@ -405,6 +412,13 @@ The template documents variable substitutions and conditional sections. Substitu
405
412
  Write the file.
406
413
  </step>
407
414
 
415
+ <step name="dispatch_discuss_post_hooks">
416
+ ```bash
417
+ DISCUSS_POST_HOOKS_JSON=$(gsd_run loop render-hooks discuss:post --raw)
418
+ ```
419
+ Apply each entry in `activeHooks` per @~/.claude/gsd-core/references/loop-hook-dispatch.md. Empty list → continue to `confirm_creation`.
420
+ </step>
421
+
408
422
  <step name="confirm_creation">
409
423
  Present summary and next steps:
410
424