@pareto4/pp-core 1.17.1 → 1.18.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 (86) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +5 -3
  3. package/agents/pp-code-fixer.md +0 -11
  4. package/agents/pp-code-reviewer.md +1 -78
  5. package/agents/pp-executor.md +9 -23
  6. package/agents/pp-planner.md +11 -11
  7. package/agents/pp-vault-reviewer.md +43 -189
  8. package/agents/pp-verifier.md +0 -6
  9. package/commands/pp-ns-manage.md +1 -1
  10. package/commands/pp-ns-review.md +1 -1
  11. package/commands/pp-vault-promote.md +7 -8
  12. package/commands/pp-vault-review.md +6 -7
  13. package/gemini-extension.json +1 -1
  14. package/package.json +3 -6
  15. package/pp-core/bin/lib/capability-registry.cjs +13 -355
  16. package/pp-core/bin/lib/capability-state.cjs +15 -79
  17. package/pp-core/bin/lib/capability-writer.cjs +2 -16
  18. package/pp-core/bin/lib/check-command-router.cjs +277 -2273
  19. package/pp-core/bin/lib/clusters.cjs +2 -2
  20. package/pp-core/bin/lib/compose-bindings.cjs +2 -2
  21. package/pp-core/bin/lib/config.cjs +3 -6
  22. package/pp-core/bin/lib/git-base-branch.cjs +10 -13
  23. package/pp-core/bin/lib/git-provider.cjs +5 -6
  24. package/pp-core/bin/lib/init-contract.cjs +7 -35
  25. package/pp-core/bin/lib/init-interactive.cjs +6 -20
  26. package/pp-core/bin/lib/io.cjs +2 -8
  27. package/pp-core/bin/lib/loop-resolver.cjs +8 -32
  28. package/pp-core/bin/lib/org-profile.cjs +16 -92
  29. package/pp-core/bin/lib/vault-command-router.cjs +174 -1206
  30. package/pp-core/bin/lib/vault-coordinates.cjs +3 -3
  31. package/pp-core/bin/lib/vault-index.cjs +27 -70
  32. package/pp-core/bin/lib/vault-seal.cjs +37 -122
  33. package/pp-core/bin/lib/vault-standards-promote.cjs +577 -0
  34. package/pp-core/bin/lib/vault-standards-review.cjs +293 -0
  35. package/pp-core/bin/lib/vault-standards.cjs +15 -16
  36. package/pp-core/bin/lib/vault-trace.cjs +40 -3016
  37. package/pp-core/bin/lib/vault-update.cjs +1 -26
  38. package/pp-core/bin/lib/vault.cjs +120 -314
  39. package/pp-core/bin/pp-tools.cjs +5 -32
  40. package/pp-core/references/autonomous-best-effort.md +1 -1
  41. package/pp-core/references/planner-vault-standards.md +16 -25
  42. package/pp-core/templates/README.md +1 -1
  43. package/pp-core/templates/VAULT-REVIEW.md +24 -170
  44. package/pp-core/workflows/add-tests.md +3 -3
  45. package/pp-core/workflows/audit-fix.md +3 -3
  46. package/pp-core/workflows/code-review-fix.md +3 -3
  47. package/pp-core/workflows/code-review.md +1 -57
  48. package/pp-core/workflows/debug.md +2 -2
  49. package/pp-core/workflows/discovery-sprint/prototype.md +2 -2
  50. package/pp-core/workflows/discovery-sprint/vault-context.md +4 -10
  51. package/pp-core/workflows/execute-phase/steps/check-query-gate.md +11 -13
  52. package/pp-core/workflows/execute-phase/steps/execute-pre-dispatch.md +5 -25
  53. package/pp-core/workflows/execute-phase/steps/vault-fetch.md +6 -6
  54. package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +6 -109
  55. package/pp-core/workflows/execute-phase/steps/verify-post-gate.md +1 -17
  56. package/pp-core/workflows/execute-phase.md +2 -5
  57. package/pp-core/workflows/execute-plan.md +6 -8
  58. package/pp-core/workflows/help/modes/full.md +1 -1
  59. package/pp-core/workflows/quick.md +8 -8
  60. package/pp-core/workflows/validate-phase.md +3 -3
  61. package/pp-core/workflows/vault-review.md +64 -186
  62. package/pp-core/workflows/vault-write-back.md +73 -110
  63. package/pp-core/workflows/verify-work.md +1 -1
  64. package/scripts/gen-capability-registry.cjs +12 -93
  65. package/scripts/lint-test-file-count.allowlist.json +1 -19
  66. package/scripts/lint-test-file-count.cjs +5 -6
  67. package/scripts/prompt-injection-scan.sh +0 -3
  68. package/pp-core/bin/lib/practices-review-check.cjs +0 -944
  69. package/pp-core/bin/lib/vault-audit.cjs +0 -2594
  70. package/pp-core/bin/lib/vault-mode.cjs +0 -235
  71. package/pp-core/bin/lib/vault-practices.cjs +0 -2057
  72. package/pp-core/bin/lib/vault-review.cjs +0 -2102
  73. package/pp-core/bin/lib/vault-write-back.cjs +0 -905
  74. package/pp-core/references/planner-vault-practices.md +0 -95
  75. package/pp-core/references/practice-arithmetic-contract.md +0 -121
  76. package/pp-core/references/verifier-practice-verdicts.md +0 -263
  77. package/pp-core/templates/practices/README.md +0 -248
  78. package/pp-core/templates/practices/error-handling.md +0 -18
  79. package/pp-core/templates/practices/minimal-comments.md +0 -14
  80. package/pp-core/templates/practices/naming-convention.md +0 -18
  81. package/pp-core/templates/practices/practice-template.md +0 -23
  82. package/pp-core/workflows/execute-phase/steps/verifier-practice-payload.md +0 -165
  83. package/scripts/gen-practice-arithmetic-contract.cjs +0 -412
  84. package/scripts/practice-arithmetic-contract.allow.json +0 -35
  85. package/scripts/record-vault-mode-golden.cjs +0 -89
  86. package/scripts/vault-calibrate.cjs +0 -996
@@ -62,52 +62,6 @@ 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
65
  // ─── Seal gates over recorded artifacts (Phase 16 D-18 / D-19 / D-26) ──────────
112
66
  /**
113
67
  * The per-hook seal field's name (Phase 16 D-19). One statement of it: the
@@ -118,15 +72,13 @@ const SEAL_FIELD = 'onRecordedArtifacts';
118
72
  /**
119
73
  * How the resolver treats one GATE, given its seal field, its capability's
120
74
  * 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.
75
+ * the seal rule (Phase 16 D-19), owned here because loop-resolver requires
76
+ * this module, never the reverse.
124
77
  *
125
78
  * Why a field and not a widened `when` (D-18, measured): the resolver drops a
126
79
  * 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`,
80
+ * ANDs the capability's `activationKey`. With `vault.enabled` false no vault
81
+ * hook can render, whatever its `when` says. So a seal gate bypasses the active check and the `when`,
130
82
  * under this closed rule only:
131
83
  *
132
84
  * - no seal field (anything but literal `true`) → `'normal'` when the
@@ -140,10 +92,7 @@ const SEAL_FIELD = 'onRecordedArtifacts';
140
92
  * answers literal `true`, else `'drop'`. The predicate is called on this
141
93
  * arm ONLY, so no other hook pays its planning-tree read.
142
94
  *
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.
95
+ * Pure apart from the injected thunk.
147
96
  */
148
97
  function sealRenderVerdict(sealField, state, recordedArtifacts) {
149
98
  const active = state !== undefined && state !== null && state.active === true;
@@ -216,12 +165,9 @@ function resolveInjectedPlatformBindingsPresent(resolvePlatformBindingsPresent)
216
165
  * @param input.cwd Optional; when provided, enables raw .planning/config.json
217
166
  * fallback reads (levels 2+3 of _resolveActivationValue
218
167
  * 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).
222
168
  */
223
169
  function resolveCapabilityState(input) {
224
- const { registry, installedSkills, surfacedSkills, config, cwd, vaultMode } = input;
170
+ const { registry, installedSkills, surfacedSkills, config, cwd } = input;
225
171
  // Guard: registry missing capabilities
226
172
  if (!registry || typeof registry !== 'object' || Array.isArray(registry)) {
227
173
  return { capabilities: [] };
@@ -351,16 +297,17 @@ function resolveCapabilityState(input) {
351
297
  // (mirrors loop-resolver.isActive: `typeof when !== 'string' || when.length === 0` → false)
352
298
  configured = false;
353
299
  }
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);
358
300
  // Hook active = capability-level active AND hook's own config gate.
359
301
  // The capability's `active` constant (= enabled && configActivation) is
360
302
  // used here so that a config-disabled capability (active=false) cannot
361
303
  // produce active hooks even when the hook's own `when` is unconditional
362
304
  // (configured=true). The capability gate cascades to all its hooks.
363
- hooks.push({ point, kind, when: whenRaw, configured, active: active && configured });
305
+ // A seal gate (`SEAL_FIELD`, Phase 16 D-19) never renders for an ACTIVE
306
+ // capability — `sealRenderVerdict` drops it, because the normal gates
307
+ // cover it — so it is reported inactive here, keeping this report in
308
+ // agreement with what `loop render-hooks` renders.
309
+ const seal = kind === 'gate' && h[SEAL_FIELD] === true;
310
+ hooks.push({ point, kind, when: whenRaw, configured, active: active && configured && !seal });
364
311
  }
365
312
  }
366
313
  const stepsRaw = capObj['steps'];
@@ -519,12 +466,8 @@ function _resolveManifest(commandsGsdDir, configDir) {
519
466
  * caught by the caller before invoking this function.
520
467
  * @param raw Whether to emit raw JSON (io.output raw mode)
521
468
  * @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.
526
469
  */
527
- function resolveCapabilityRuntimeState(cwd, runtimeConfigDir, configOverride, resolveOptions = {}) {
470
+ function resolveCapabilityRuntimeState(cwd, runtimeConfigDir, configOverride) {
528
471
  const warnings = [];
529
472
  // Resolve runtimeConfigDir using the canonical runtime-homes resolver.
530
473
  // When not provided, the active runtime is detected via the canonical
@@ -630,7 +573,6 @@ function resolveCapabilityRuntimeState(cwd, runtimeConfigDir, configOverride, re
630
573
  surfacedSkills,
631
574
  config,
632
575
  cwd,
633
- vaultMode: resolveOptions.vaultMode,
634
576
  });
635
577
  return {
636
578
  runtimeConfigDir: resolvedConfigDir,
@@ -638,11 +580,8 @@ function resolveCapabilityRuntimeState(cwd, runtimeConfigDir, configOverride, re
638
580
  capabilities: result.capabilities,
639
581
  };
640
582
  }
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 });
583
+ function cmdCapabilityState(cwd, runtimeConfigDir, raw, _options = {}) {
584
+ const result = resolveCapabilityRuntimeState(cwd, runtimeConfigDir);
646
585
  for (const warning of result.warnings) {
647
586
  coreError(`capability state: ${warning}`);
648
587
  }
@@ -679,9 +618,6 @@ module.exports = {
679
618
  resolveCapabilityRuntimeState,
680
619
  isCapabilityActive,
681
620
  cmdCapabilityState,
682
- // Phase 15 D-02/D-28: the one mode-filter rule (loop-resolver imports it)
683
- vaultModeFilterVerdict,
684
- resolveInjectedVaultMode,
685
621
  // Phase 16 D-19: the one seal rule, its injected-predicate normaliser and the
686
622
  // field name the resolver and the registry generator both read.
687
623
  SEAL_FIELD,
@@ -28,8 +28,6 @@ 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;
33
31
  // eslint-disable-next-line @typescript-eslint/no-require-imports
34
32
  const surfaceMod = require("./surface.cjs");
35
33
  const { readSurface, writeSurface, applySurface } = surfaceMod;
@@ -69,15 +67,8 @@ const nodepath = require("path");
69
67
  function setCapabilityState(cwd, runtimeConfigDir, desired, opts) {
70
68
  const warnings = [];
71
69
  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.
77
70
  // ── Step 1: Resolve BEFORE state once ────────────────────────────────────
78
- const before = resolveCapabilityRuntimeState(cwd, runtimeConfigDir, undefined, {
79
- vaultMode: resolveInjectedVaultMode(opts?.resolveVaultMode),
80
- });
71
+ const before = resolveCapabilityRuntimeState(cwd, runtimeConfigDir);
81
72
  const resolvedConfigDir = before.runtimeConfigDir;
82
73
  // ── Load registry ─────────────────────────────────────────────────────────
83
74
  // eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -264,11 +255,7 @@ function setCapabilityState(cwd, runtimeConfigDir, desired, opts) {
264
255
  }
265
256
  }
266
257
  // ── Step 5: RE-RESOLVE ────────────────────────────────────────────────────
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
- });
258
+ const after = resolveCapabilityRuntimeState(cwd, resolvedConfigDir);
272
259
  // ── Step 6: POST CHECKS ───────────────────────────────────────────────────
273
260
  // Check: desired enabled=true but not actually enabled after write
274
261
  // (catches the not-in-profile / not-surfaced silent no-op case).
@@ -328,7 +315,6 @@ function cmdCapabilitySet(cwd, runtimeConfigDir, capId, options, raw) {
328
315
  ];
329
316
  const opts = {
330
317
  ...(options.runtime ? { materialize: { runtime: options.runtime, scope: options.scope ?? 'global' } } : {}),
331
- resolveVaultMode: options.resolveVaultMode,
332
318
  };
333
319
  const result = setCapabilityState(cwd, runtimeConfigDir, desired, opts);
334
320
  if (raw) {