@pareto4/pp-core 1.12.1 → 1.17.1

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 (196) hide show
  1. package/.claude-plugin/plugin.json +3 -3
  2. package/README.md +26 -9
  3. package/agents/pp-code-reviewer.md +3 -2
  4. package/agents/pp-debug-session-manager.md +9 -6
  5. package/agents/pp-executor.md +7 -21
  6. package/agents/pp-plan-checker.md +4 -4
  7. package/agents/pp-planner.md +23 -9
  8. package/agents/pp-vault-reviewer.md +274 -0
  9. package/agents/pp-verifier.md +7 -3
  10. package/bin/install.js +10 -3
  11. package/commands/pp-execute-phase.md +1 -3
  12. package/commands/pp-ns-review.md +2 -1
  13. package/commands/pp-plan-phase.md +1 -2
  14. package/commands/pp-vault-review.md +35 -0
  15. package/commands/pp-verify-work.md +1 -2
  16. package/gemini-extension.json +1 -1
  17. package/hooks/dist/pp-check-update.js +0 -0
  18. package/hooks/dist/pp-cursor-session-start.js +1 -1
  19. package/hooks/dist/pp-statusline.js +1 -1
  20. package/hooks/dist/pp-update-banner.js +0 -0
  21. package/hooks/pp-check-update.js +0 -0
  22. package/hooks/pp-cursor-session-start.js +1 -1
  23. package/hooks/pp-statusline.js +1 -1
  24. package/hooks/pp-update-banner.js +0 -0
  25. package/package.json +14 -19
  26. package/pareto-skills/_shared/create-project-board.sh +0 -0
  27. package/pareto-skills/pp-project-setup/SKILL.md +1 -1
  28. package/pp-core/bin/check-latest-version.cjs +0 -0
  29. package/pp-core/bin/detect-build-commands.sh +2 -2
  30. package/pp-core/bin/lib/capability-activation.cjs +83 -9
  31. package/pp-core/bin/lib/capability-registry.cjs +526 -22
  32. package/pp-core/bin/lib/capability-state.cjs +160 -4
  33. package/pp-core/bin/lib/capability-writer.cjs +19 -5
  34. package/pp-core/bin/lib/check-command-router.cjs +3867 -274
  35. package/pp-core/bin/lib/clusters.cjs +4 -0
  36. package/pp-core/bin/lib/command-aliases.cjs +0 -28
  37. package/pp-core/bin/lib/commands.cjs +9 -4
  38. package/pp-core/bin/lib/compose-bindings.cjs +253 -76
  39. package/pp-core/bin/lib/config-loader.cjs +7 -103
  40. package/pp-core/bin/lib/config-schema.cjs +1 -1
  41. package/pp-core/bin/lib/config.cjs +154 -62
  42. package/pp-core/bin/lib/decisions.cjs +104 -27
  43. package/pp-core/bin/lib/discovery-vault-check.cjs +246 -0
  44. package/pp-core/bin/lib/frontmatter.cjs +1 -1
  45. package/pp-core/bin/lib/git-base-branch.cjs +138 -10
  46. package/pp-core/bin/lib/git-provider.cjs +4 -4
  47. package/pp-core/bin/lib/init-command-router.cjs +5 -8
  48. package/pp-core/bin/lib/init-contract.cjs +653 -629
  49. package/pp-core/bin/lib/init-interactive.cjs +77 -21
  50. package/pp-core/bin/lib/init.cjs +24 -51
  51. package/pp-core/bin/lib/install-profiles.cjs +1 -1
  52. package/pp-core/bin/lib/io.cjs +8 -0
  53. package/pp-core/bin/lib/loop-resolver.cjs +169 -47
  54. package/pp-core/bin/lib/org-profile.cjs +544 -53
  55. package/pp-core/bin/lib/package-identity.cjs +3 -3
  56. package/pp-core/bin/lib/phase-command-router.cjs +1 -23
  57. package/pp-core/bin/lib/phase-scope.cjs +1 -1
  58. package/pp-core/bin/lib/phase.cjs +11 -203
  59. package/pp-core/bin/lib/platform-bindings.cjs +40 -19
  60. package/pp-core/bin/lib/practices-review-check.cjs +15 -9
  61. package/pp-core/bin/lib/profile-output.cjs +1 -1
  62. package/pp-core/bin/lib/shell-command-projection.cjs +104 -1
  63. package/pp-core/bin/lib/state.cjs +11 -85
  64. package/pp-core/bin/lib/template.cjs +1 -1
  65. package/pp-core/bin/lib/vault-audit.cjs +2594 -0
  66. package/pp-core/bin/lib/vault-command-router.cjs +2756 -60
  67. package/pp-core/bin/lib/vault-coordinates.cjs +13 -4
  68. package/pp-core/bin/lib/vault-index.cjs +699 -0
  69. package/pp-core/bin/lib/vault-mode.cjs +235 -0
  70. package/pp-core/bin/lib/vault-practices.cjs +1194 -89
  71. package/pp-core/bin/lib/vault-review.cjs +2102 -0
  72. package/pp-core/bin/lib/vault-seal.cjs +1936 -0
  73. package/pp-core/bin/lib/vault-standards.cjs +1505 -0
  74. package/pp-core/bin/lib/vault-trace.cjs +3184 -0
  75. package/pp-core/bin/lib/vault-update.cjs +242 -0
  76. package/pp-core/bin/lib/vault-write-back.cjs +78 -31
  77. package/pp-core/bin/lib/vault.cjs +2713 -634
  78. package/pp-core/bin/lib/verify.cjs +0 -11
  79. package/pp-core/bin/portable-timeout.sh +1 -1
  80. package/pp-core/bin/pp-tools.cjs +184 -37
  81. package/pp-core/bin/shared/config-defaults.manifest.json +0 -7
  82. package/pp-core/bin/shared/config-schema.manifest.json +0 -3
  83. package/pp-core/bin/shared/model-catalog.json +1 -0
  84. package/pp-core/bin/verify-reapply-patches.cjs +0 -0
  85. package/pp-core/org-profile.json +26 -0
  86. package/pp-core/references/autonomous-best-effort.md +8 -7
  87. package/pp-core/references/loop-hook-dispatch.md +0 -14
  88. package/pp-core/references/planner-gap-closure.md +0 -1
  89. package/pp-core/references/planner-tdd.md +0 -1
  90. package/pp-core/references/planner-vault-practices.md +31 -3
  91. package/pp-core/references/planner-vault-standards.md +320 -0
  92. package/pp-core/references/planning-config.md +0 -8
  93. package/pp-core/references/practice-arithmetic-contract.md +121 -0
  94. package/pp-core/references/tdd.md +0 -1
  95. package/pp-core/references/verifier-practice-verdicts.md +263 -0
  96. package/pp-core/templates/README.md +1 -0
  97. package/pp-core/templates/VAULT-REVIEW.md +202 -0
  98. package/pp-core/templates/phase-prompt.md +2 -6
  99. package/pp-core/templates/practices/README.md +137 -11
  100. package/pp-core/templates/project-charter.md +226 -0
  101. package/pp-core/workflows/_runtime-launcher.snippet.sh +0 -0
  102. package/pp-core/workflows/add-tests.md +55 -0
  103. package/pp-core/workflows/audit-fix.md +63 -0
  104. package/pp-core/workflows/audit-milestone.md +1 -1
  105. package/pp-core/workflows/autonomous.md +85 -11
  106. package/pp-core/workflows/check-todos.md +13 -2
  107. package/pp-core/workflows/code-review-fix.md +59 -1
  108. package/pp-core/workflows/code-review.md +10 -1
  109. package/pp-core/workflows/complete-milestone.md +1 -1
  110. package/pp-core/workflows/debug.md +56 -2
  111. package/pp-core/workflows/discovery-sprint/prefill.md +21 -0
  112. package/pp-core/workflows/discovery-sprint/prototype.md +46 -48
  113. package/pp-core/workflows/discovery-sprint/session-13-gates.md +2 -0
  114. package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +1 -3
  115. package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +1 -3
  116. package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +1 -3
  117. package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +20 -24
  118. package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +1 -3
  119. package/pp-core/workflows/discovery-sprint/sessions/06-security.md +1 -3
  120. package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +1 -3
  121. package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +1 -3
  122. package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +1 -3
  123. package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +1 -6
  124. package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +1 -3
  125. package/pp-core/workflows/discovery-sprint/sessions/12-delivery-model.md +1 -3
  126. package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +1 -3
  127. package/pp-core/workflows/discovery-sprint/templates/context-template.md +1 -1
  128. package/pp-core/workflows/discovery-sprint/vault-context.md +213 -0
  129. package/pp-core/workflows/discovery-sprint.md +7 -3
  130. package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +4 -4
  131. package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +43 -1
  132. package/pp-core/workflows/discovery-to-build.md +9 -1
  133. package/pp-core/workflows/discuss-phase.md +3 -10
  134. package/pp-core/workflows/execute-phase/steps/check-query-gate.md +329 -0
  135. package/pp-core/workflows/execute-phase/steps/client-context-gate.md +3 -2
  136. package/pp-core/workflows/execute-phase/steps/cross-ai-delegation.md +1 -1
  137. package/pp-core/workflows/execute-phase/steps/execute-pre-dispatch.md +98 -0
  138. package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
  139. package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +6 -8
  140. package/pp-core/workflows/execute-phase/steps/vault-fetch.md +115 -14
  141. package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +322 -18
  142. package/pp-core/workflows/execute-phase/steps/verifier-practice-payload.md +165 -0
  143. package/pp-core/workflows/execute-phase/steps/verify-post-gate.md +163 -0
  144. package/pp-core/workflows/execute-phase.md +154 -110
  145. package/pp-core/workflows/execute-plan.md +58 -4
  146. package/pp-core/workflows/fast.md +53 -0
  147. package/pp-core/workflows/help/modes/full.md +1 -0
  148. package/pp-core/workflows/init/steps/client-context-capture.md +101 -0
  149. package/pp-core/workflows/init/steps/gitlab-provisioning.md +130 -0
  150. package/pp-core/workflows/init/steps/project-md-deferral-narration.md +66 -0
  151. package/pp-core/workflows/init/steps/reachability-outcome.md +70 -0
  152. package/pp-core/workflows/init.md +232 -272
  153. package/pp-core/workflows/new-project.md +31 -23
  154. package/pp-core/workflows/plan-phase.md +99 -43
  155. package/pp-core/workflows/quick.md +120 -2
  156. package/pp-core/workflows/secure-phase.md +1 -1
  157. package/pp-core/workflows/ship.md +57 -24
  158. package/pp-core/workflows/update.md +3 -3
  159. package/pp-core/workflows/validate-phase.md +60 -1
  160. package/pp-core/workflows/vault-review.md +325 -0
  161. package/pp-core/workflows/verify-work.md +13 -12
  162. package/scripts/changeset/cli.cjs +6 -5
  163. package/scripts/changeset/lint.cjs +0 -0
  164. package/scripts/changeset/new.cjs +33 -50
  165. package/scripts/dev-env.cjs +25 -85
  166. package/scripts/gen-capability-registry.cjs +199 -0
  167. package/scripts/gen-practice-arithmetic-contract.cjs +412 -0
  168. package/scripts/lib/allowlist-ratchet.cjs +1 -103
  169. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -2
  170. package/scripts/lint-docs-required.cjs +0 -0
  171. package/scripts/lint-pr-check-project-dir.cjs +1 -3
  172. package/scripts/lint-test-file-count.allowlist.json +13 -2
  173. package/scripts/practice-arithmetic-contract.allow.json +35 -0
  174. package/scripts/prompt-injection-scan.sh +22 -15
  175. package/scripts/record-vault-mode-golden.cjs +89 -0
  176. package/scripts/release-channel.cjs +0 -0
  177. package/scripts/sync-manifest-versions.cjs +5 -4
  178. package/scripts/sync-rulesets.sh +1 -1
  179. package/scripts/update-size-baseline.cjs +30 -274
  180. package/scripts/vault-calibrate.cjs +996 -0
  181. package/scripts/verify-opengsd-sweep.cjs +3 -5
  182. package/scripts/workflow-size.cjs +9 -61
  183. package/pp-core/bin/lib/dispatch-plan.cjs +0 -472
  184. package/pp-core/bin/lib/install-run.cjs +0 -536
  185. package/pp-core/bin/lib/phase-tier.cjs +0 -467
  186. package/pp-core/bin/lib/plan-graph.cjs +0 -368
  187. package/pp-core/references/planner-plan-graph.md +0 -66
  188. package/pp-core/workflows/execute-phase/steps/checkpoint-handling.md +0 -45
  189. package/pp-core/workflows/execute-phase/steps/install-run.md +0 -29
  190. package/pp-core/workflows/execute-phase/steps/phase-close-rebaseline.md +0 -23
  191. package/pp-core/workflows/execute-phase/steps/serial-group-dispatch.md +0 -72
  192. package/pp-core/workflows/plan-phase/steps/phase-tier.md +0 -34
  193. package/scripts/lib/size-budget.cjs +0 -311
  194. package/scripts/lint-neutrality-names.cjs +0 -694
  195. package/scripts/lint-org-coordinates.allowlist.json +0 -35
  196. package/scripts/lint-org-coordinates.cjs +0 -426
@@ -62,6 +62,137 @@ function _isSafePropKey(key) {
62
62
  return false;
63
63
  return true;
64
64
  }
65
+ // ─── Vault mode filter (Phase 15 D-02 / D-28) ──────────────────────────────────
66
+ /**
67
+ * Does a hook's declared `vaultMode` filter let it through under the resolved
68
+ * mode? THE ONE statement of the rule (Phase 15 D-02, amended by D-28). Both
69
+ * `resolveLoopHooks` (what renders) and `resolveCapabilityState` (what
70
+ * `capability state` reports) call it, so they cannot drift. It lives here, not
71
+ * in loop-resolver, because loop-resolver already requires this module and the
72
+ * reverse require would be a cycle.
73
+ *
74
+ * - no `vaultMode` on the hook → passes (a hook without the field behaves
75
+ * exactly as before Phase 15);
76
+ * - the input mode is `practices` or `standards` → passes iff the hook's
77
+ * `vaultMode` equals it;
78
+ * - any other input (`null`, absent, an unknown string) is an undefined mode:
79
+ * a filtered GATE passes and a filtered contribution or step drops (D-28).
80
+ * The trace points then still dispatch a gate that fails closed, and no
81
+ * contract renders for a mode nobody defined. The mode is never defaulted
82
+ * to `practices` here.
83
+ *
84
+ * Pure: no I/O, no config read. The mode arrives as a value.
85
+ */
86
+ function vaultModeFilterVerdict(hookMode, kind, inputMode) {
87
+ if (hookMode === undefined)
88
+ return true;
89
+ const resolved = (inputMode === 'practices' || inputMode === 'standards') ? inputMode : null;
90
+ if (resolved !== null)
91
+ return hookMode === resolved;
92
+ return kind === 'gate';
93
+ }
94
+ /**
95
+ * Call an injected `resolveVaultMode` (pp-tools builds it on `vaultModeVerdict`)
96
+ * and normalise its answer to `'practices' | 'standards' | null`. A missing
97
+ * resolver, a throw or any other answer is `null`, the undefined mode that
98
+ * `vaultModeFilterVerdict` treats fail-closed (D-28). Shared by both I/O entry
99
+ * points (`cmdLoopRenderHooks`, `cmdCapabilityState`) so the two read the
100
+ * injected mode identically.
101
+ */
102
+ function resolveInjectedVaultMode(resolveVaultMode) {
103
+ try {
104
+ const m = typeof resolveVaultMode === 'function' ? resolveVaultMode() : null;
105
+ return (m === 'practices' || m === 'standards') ? m : null;
106
+ }
107
+ catch {
108
+ return null;
109
+ }
110
+ }
111
+ // ─── Seal gates over recorded artifacts (Phase 16 D-18 / D-19 / D-26) ──────────
112
+ /**
113
+ * The per-hook seal field's name (Phase 16 D-19). One statement of it: the
114
+ * resolver reads the hook field under this name and the registry generator
115
+ * validates the same name, so the two cannot name different fields.
116
+ */
117
+ const SEAL_FIELD = 'onRecordedArtifacts';
118
+ /**
119
+ * How the resolver treats one GATE, given its seal field, its capability's
120
+ * state and the injected recorded-artifacts predicate. THE ONE statement of
121
+ * the seal rule (Phase 16 D-19), owned here for the same reason as
122
+ * `vaultModeFilterVerdict`: loop-resolver requires this module, never the
123
+ * reverse.
124
+ *
125
+ * Why a field and not a widened `when` (D-18, measured): the resolver drops a
126
+ * hook whose capability is not `active` BEFORE `when` is read, and `active`
127
+ * ANDs the capability's `activationKey`. With `vault.enabled` or
128
+ * `vault.practices_enabled` false no vault-practices hook can render, whatever
129
+ * its `when` says. So a seal gate bypasses the active check and the `when`,
130
+ * under this closed rule only:
131
+ *
132
+ * - no seal field (anything but literal `true`) → `'normal'` when the
133
+ * capability is active, else `'drop'`. That is the resolver's behaviour
134
+ * before Phase 16, exactly; `when` is then evaluated as before.
135
+ * - a seal gate whose capability is active → `'drop'`: the normal gates
136
+ * cover it, so a check is never dispatched twice.
137
+ * - a seal gate whose capability is not `enabled` (not installed or not
138
+ * surfaced), or has no state at all → `'drop'` (fail closed).
139
+ * - otherwise (enabled, config-inactive) → `'seal'` iff the predicate
140
+ * answers literal `true`, else `'drop'`. The predicate is called on this
141
+ * arm ONLY, so no other hook pays its planning-tree read.
142
+ *
143
+ * Mode filtering (`vaultModeFilterVerdict`) runs BEFORE this rule in the
144
+ * resolver, so a mode-filtered seal never consults the predicate (research
145
+ * C-1). Seals are declared on vault-practices only (D-26). Pure apart from the
146
+ * injected thunk.
147
+ */
148
+ function sealRenderVerdict(sealField, state, recordedArtifacts) {
149
+ const active = state !== undefined && state !== null && state.active === true;
150
+ if (sealField !== true)
151
+ return active ? 'normal' : 'drop';
152
+ if (active)
153
+ return 'drop';
154
+ if (state === undefined || state === null || state.enabled !== true)
155
+ return 'drop';
156
+ return recordedArtifacts() === true ? 'seal' : 'drop';
157
+ }
158
+ /**
159
+ * Call an injected `resolveRecordedArtifacts` (pp-tools builds it on the seal
160
+ * leaf's `hasRecordedVaultArtifacts`) and normalise its answer to a boolean:
161
+ * literal `true` is `true`; a missing resolver, a throw or any other answer
162
+ * (`'true'`, `1`, `undefined`) is `false`, the inert value under which no seal
163
+ * renders (Phase 16 D-19). The leaf itself answers `true` when it cannot prove
164
+ * absence (D-44); this normaliser only refuses answers that are not a boolean.
165
+ */
166
+ function resolveInjectedRecordedArtifacts(resolveRecordedArtifacts) {
167
+ try {
168
+ if (typeof resolveRecordedArtifacts !== 'function')
169
+ return false;
170
+ return resolveRecordedArtifacts() === true;
171
+ }
172
+ catch {
173
+ return false;
174
+ }
175
+ }
176
+ /**
177
+ * Quick 261015-ect (QD-13): call an injected `resolvePlatformBindingsPresent`
178
+ * (pp-tools builds it on the vault leaf's `hasPlatformBindings`) and normalise
179
+ * its answer: literal `false` is `false` (measured absent), literal `true` is
180
+ * `true`; a missing resolver, a throw or any other answer is `null`, "could not
181
+ * measure". The resolver drops a bindings-requiring capability's hooks only on
182
+ * `false`: a filter that cannot measure must never silence a gate on a governed
183
+ * project, so the unmeasured answer renders as before.
184
+ */
185
+ function resolveInjectedPlatformBindingsPresent(resolvePlatformBindingsPresent) {
186
+ try {
187
+ if (typeof resolvePlatformBindingsPresent !== 'function')
188
+ return null;
189
+ const answer = resolvePlatformBindingsPresent();
190
+ return answer === true || answer === false ? answer : null;
191
+ }
192
+ catch {
193
+ return null;
194
+ }
195
+ }
65
196
  // ─── Pure resolver ─────────────────────────────────────────────────────────────
66
197
  /**
67
198
  * Deterministic resolver: for each capability in the registry, produce the
@@ -85,9 +216,12 @@ function _isSafePropKey(key) {
85
216
  * @param input.cwd Optional; when provided, enables raw .planning/config.json
86
217
  * fallback reads (levels 2+3 of _resolveActivationValue
87
218
  * precedence). Omit for a pure in-memory resolution.
219
+ * @param input.vaultMode Optional resolved vault mode VALUE; a hook carrying
220
+ * `vaultMode` is configured only when
221
+ * `vaultModeFilterVerdict` passes it (Phase 15 D-02/D-28).
88
222
  */
89
223
  function resolveCapabilityState(input) {
90
- const { registry, installedSkills, surfacedSkills, config, cwd } = input;
224
+ const { registry, installedSkills, surfacedSkills, config, cwd, vaultMode } = input;
91
225
  // Guard: registry missing capabilities
92
226
  if (!registry || typeof registry !== 'object' || Array.isArray(registry)) {
93
227
  return { capabilities: [] };
@@ -217,6 +351,10 @@ function resolveCapabilityState(input) {
217
351
  // (mirrors loop-resolver.isActive: `typeof when !== 'string' || when.length === 0` → false)
218
352
  configured = false;
219
353
  }
354
+ // Phase 15 D-02/D-28: the mode filter folds into `configured`, through the
355
+ // same rule resolveLoopHooks applies. `vaultMode` is read, never emitted:
356
+ // HookEntry has no such field.
357
+ configured = configured && vaultModeFilterVerdict(h['vaultMode'], kind, vaultMode);
220
358
  // Hook active = capability-level active AND hook's own config gate.
221
359
  // The capability's `active` constant (= enabled && configActivation) is
222
360
  // used here so that a config-disabled capability (active=false) cannot
@@ -381,8 +519,12 @@ function _resolveManifest(commandsGsdDir, configDir) {
381
519
  * caught by the caller before invoking this function.
382
520
  * @param raw Whether to emit raw JSON (io.output raw mode)
383
521
  * @param _options Reserved for future use
522
+ * @param resolveOptions `{ vaultMode }`, the resolved vault mode VALUE passed
523
+ * through to resolveCapabilityState (Phase 15 D-02).
524
+ * Omitted by the loop resolver, which reads only the
525
+ * capability-level `active` and filters hooks itself.
384
526
  */
385
- function resolveCapabilityRuntimeState(cwd, runtimeConfigDir, configOverride) {
527
+ function resolveCapabilityRuntimeState(cwd, runtimeConfigDir, configOverride, resolveOptions = {}) {
386
528
  const warnings = [];
387
529
  // Resolve runtimeConfigDir using the canonical runtime-homes resolver.
388
530
  // When not provided, the active runtime is detected via the canonical
@@ -488,6 +630,7 @@ function resolveCapabilityRuntimeState(cwd, runtimeConfigDir, configOverride) {
488
630
  surfacedSkills,
489
631
  config,
490
632
  cwd,
633
+ vaultMode: resolveOptions.vaultMode,
491
634
  });
492
635
  return {
493
636
  runtimeConfigDir: resolvedConfigDir,
@@ -495,8 +638,11 @@ function resolveCapabilityRuntimeState(cwd, runtimeConfigDir, configOverride) {
495
638
  capabilities: result.capabilities,
496
639
  };
497
640
  }
498
- function cmdCapabilityState(cwd, runtimeConfigDir, raw, _options = {}) {
499
- const result = resolveCapabilityRuntimeState(cwd, runtimeConfigDir);
641
+ function cmdCapabilityState(cwd, runtimeConfigDir, raw, options = {}) {
642
+ // Phase 15 D-02: the same injected mode render-hooks uses, so a mode-filtered
643
+ // hook's `active` here agrees with whether it renders.
644
+ const vaultMode = resolveInjectedVaultMode(options['resolveVaultMode']);
645
+ const result = resolveCapabilityRuntimeState(cwd, runtimeConfigDir, undefined, { vaultMode });
500
646
  for (const warning of result.warnings) {
501
647
  coreError(`capability state: ${warning}`);
502
648
  }
@@ -533,6 +679,16 @@ module.exports = {
533
679
  resolveCapabilityRuntimeState,
534
680
  isCapabilityActive,
535
681
  cmdCapabilityState,
682
+ // Phase 15 D-02/D-28: the one mode-filter rule (loop-resolver imports it)
683
+ vaultModeFilterVerdict,
684
+ resolveInjectedVaultMode,
685
+ // Phase 16 D-19: the one seal rule, its injected-predicate normaliser and the
686
+ // field name the resolver and the registry generator both read.
687
+ SEAL_FIELD,
688
+ sealRenderVerdict,
689
+ resolveInjectedRecordedArtifacts,
690
+ // Quick 261015-ect (QD-13): the bindings measurement's normaliser.
691
+ resolveInjectedPlatformBindingsPresent,
536
692
  // Exported for tests
537
693
  _resolveCommandsGsdDir,
538
694
  _loadInstalledSkillsManifest,
@@ -28,6 +28,8 @@ const { output: coreOutput, error: coreError } = ioMod;
28
28
  // eslint-disable-next-line @typescript-eslint/no-require-imports
29
29
  const capabilityStateMod = require("./capability-state.cjs");
30
30
  const { resolveCapabilityRuntimeState, _resolveManifest, _resolveCommandsGsdDir } = capabilityStateMod;
31
+ // On its own line: the line above is baselined verbatim by scripts/verify-rename-guard.cjs.
32
+ const { resolveInjectedVaultMode } = capabilityStateMod;
31
33
  // eslint-disable-next-line @typescript-eslint/no-require-imports
32
34
  const surfaceMod = require("./surface.cjs");
33
35
  const { readSurface, writeSurface, applySurface } = surfaceMod;
@@ -67,8 +69,15 @@ const nodepath = require("path");
67
69
  function setCapabilityState(cwd, runtimeConfigDir, desired, opts) {
68
70
  const warnings = [];
69
71
  const errors = [];
72
+ // Phase 15 D-02 / 15-REVIEW WR-07: the mode every hook-level reader uses, so
73
+ // the hooks this command reports and warns about are the hooks that render.
74
+ // 15-REVIEW iter-2 WR-01: the mode is resolved PER READ, never once per
75
+ // command — `vaultModeVerdict` answers "no mode" while `vault.enabled` is off,
76
+ // so a command that itself turns the vault on must re-ask after its write.
70
77
  // ── Step 1: Resolve BEFORE state once ────────────────────────────────────
71
- const before = resolveCapabilityRuntimeState(cwd, runtimeConfigDir);
78
+ const before = resolveCapabilityRuntimeState(cwd, runtimeConfigDir, undefined, {
79
+ vaultMode: resolveInjectedVaultMode(opts?.resolveVaultMode),
80
+ });
72
81
  const resolvedConfigDir = before.runtimeConfigDir;
73
82
  // ── Load registry ─────────────────────────────────────────────────────────
74
83
  // eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -255,7 +264,11 @@ function setCapabilityState(cwd, runtimeConfigDir, desired, opts) {
255
264
  }
256
265
  }
257
266
  // ── Step 5: RE-RESOLVE ────────────────────────────────────────────────────
258
- const after = resolveCapabilityRuntimeState(cwd, resolvedConfigDir);
267
+ // Re-resolve the mode AFTER the writes above (iter-2 WR-01): the after-state
268
+ // must be judged under the mode `capability state` / render-hooks now see.
269
+ const after = resolveCapabilityRuntimeState(cwd, resolvedConfigDir, undefined, {
270
+ vaultMode: resolveInjectedVaultMode(opts?.resolveVaultMode),
271
+ });
259
272
  // ── Step 6: POST CHECKS ───────────────────────────────────────────────────
260
273
  // Check: desired enabled=true but not actually enabled after write
261
274
  // (catches the not-in-profile / not-surfaced silent no-op case).
@@ -313,9 +326,10 @@ function cmdCapabilitySet(cwd, runtimeConfigDir, capId, options, raw) {
313
326
  ...(options.gates ? { gates: options.gates } : {}),
314
327
  },
315
328
  ];
316
- const opts = options.runtime
317
- ? { materialize: { runtime: options.runtime, scope: options.scope ?? 'global' } }
318
- : undefined;
329
+ const opts = {
330
+ ...(options.runtime ? { materialize: { runtime: options.runtime, scope: options.scope ?? 'global' } } : {}),
331
+ resolveVaultMode: options.resolveVaultMode,
332
+ };
319
333
  const result = setCapabilityState(cwd, runtimeConfigDir, desired, opts);
320
334
  if (raw) {
321
335
  // Raw mode: emit JSON to stdout including errors; exit non-zero if errors present.