@pareto4/pp-core 1.13.0 → 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 (201) hide show
  1. package/.claude-plugin/plugin.json +3 -3
  2. package/README.md +26 -9
  3. package/agents/pp-code-reviewer.md +2 -1
  4. package/agents/pp-debug-session-manager.md +9 -6
  5. package/agents/pp-executor.md +10 -13
  6. package/agents/pp-plan-checker.md +4 -4
  7. package/agents/pp-planner.md +23 -9
  8. package/agents/pp-vault-reviewer.md +244 -21
  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 +1 -1
  13. package/commands/pp-plan-phase.md +1 -2
  14. package/commands/pp-vault-review.md +5 -3
  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 +396 -82
  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 +3334 -946
  35. package/pp-core/bin/lib/clusters.cjs +3 -0
  36. package/pp-core/bin/lib/command-aliases.cjs +0 -35
  37. package/pp-core/bin/lib/commands.cjs +9 -4
  38. package/pp-core/bin/lib/compose-bindings.cjs +251 -88
  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 +4 -4
  43. package/pp-core/bin/lib/discovery-vault-check.cjs +246 -0
  44. package/pp-core/bin/lib/frontmatter.cjs +1 -38
  45. package/pp-core/bin/lib/git-base-branch.cjs +13 -11
  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 +648 -738
  49. package/pp-core/bin/lib/init-interactive.cjs +76 -4
  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 +189 -129
  54. package/pp-core/bin/lib/org-profile.cjs +469 -152
  55. package/pp-core/bin/lib/package-identity.cjs +3 -3
  56. package/pp-core/bin/lib/phase-command-router.cjs +1 -29
  57. package/pp-core/bin/lib/phase-scope.cjs +1 -1
  58. package/pp-core/bin/lib/phase.cjs +11 -253
  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 +650 -126
  66. package/pp-core/bin/lib/vault-command-router.cjs +2604 -367
  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 +139 -72
  71. package/pp-core/bin/lib/vault-review.cjs +194 -451
  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 +607 -254
  75. package/pp-core/bin/lib/vault-update.cjs +9 -33
  76. package/pp-core/bin/lib/vault-write-back.cjs +70 -42
  77. package/pp-core/bin/lib/vault.cjs +2734 -920
  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 -54
  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 +2 -2
  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 -25
  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 +17 -34
  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 +20 -23
  100. package/pp-core/workflows/_runtime-launcher.snippet.sh +0 -0
  101. package/pp-core/workflows/add-tests.md +55 -4
  102. package/pp-core/workflows/audit-fix.md +63 -2
  103. package/pp-core/workflows/audit-milestone.md +1 -1
  104. package/pp-core/workflows/autonomous.md +85 -11
  105. package/pp-core/workflows/check-todos.md +13 -2
  106. package/pp-core/workflows/code-review-fix.md +59 -3
  107. package/pp-core/workflows/code-review.md +10 -1
  108. package/pp-core/workflows/complete-milestone.md +1 -1
  109. package/pp-core/workflows/debug.md +54 -4
  110. package/pp-core/workflows/discovery-sprint/prefill.md +19 -7
  111. package/pp-core/workflows/discovery-sprint/prototype.md +46 -49
  112. package/pp-core/workflows/discovery-sprint/session-13-gates.md +2 -0
  113. package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +1 -3
  114. package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +1 -3
  115. package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +1 -3
  116. package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +20 -24
  117. package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +1 -3
  118. package/pp-core/workflows/discovery-sprint/sessions/06-security.md +1 -3
  119. package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +1 -3
  120. package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +1 -3
  121. package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +1 -3
  122. package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +1 -6
  123. package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +1 -3
  124. package/pp-core/workflows/discovery-sprint/sessions/12-delivery-model.md +1 -3
  125. package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +1 -3
  126. package/pp-core/workflows/discovery-sprint/templates/context-template.md +1 -1
  127. package/pp-core/workflows/discovery-sprint/vault-context.md +213 -0
  128. package/pp-core/workflows/discovery-sprint.md +7 -3
  129. package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +4 -4
  130. package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +43 -1
  131. package/pp-core/workflows/discovery-to-build.md +10 -2
  132. package/pp-core/workflows/discuss-phase.md +3 -10
  133. package/pp-core/workflows/execute-phase/steps/check-query-gate.md +329 -0
  134. package/pp-core/workflows/execute-phase/steps/client-context-gate.md +3 -2
  135. package/pp-core/workflows/execute-phase/steps/cross-ai-delegation.md +1 -1
  136. package/pp-core/workflows/execute-phase/steps/execute-pre-dispatch.md +98 -0
  137. package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +94 -0
  138. package/pp-core/workflows/execute-phase/steps/post-merge-gate.md +6 -8
  139. package/pp-core/workflows/execute-phase/steps/vault-fetch.md +115 -14
  140. package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +322 -20
  141. package/pp-core/workflows/execute-phase/steps/verifier-practice-payload.md +165 -0
  142. package/pp-core/workflows/execute-phase/steps/verify-post-gate.md +163 -0
  143. package/pp-core/workflows/execute-phase.md +155 -128
  144. package/pp-core/workflows/execute-plan.md +56 -6
  145. package/pp-core/workflows/fast.md +53 -4
  146. package/pp-core/workflows/help/modes/full.md +3 -3
  147. package/pp-core/workflows/init/steps/client-context-capture.md +101 -0
  148. package/pp-core/workflows/init/steps/gitlab-provisioning.md +130 -0
  149. package/pp-core/workflows/init/steps/project-md-deferral-narration.md +66 -0
  150. package/pp-core/workflows/init/steps/reachability-outcome.md +70 -0
  151. package/pp-core/workflows/init.md +232 -272
  152. package/pp-core/workflows/new-project.md +31 -23
  153. package/pp-core/workflows/plan-phase.md +98 -45
  154. package/pp-core/workflows/quick.md +117 -3
  155. package/pp-core/workflows/secure-phase.md +1 -1
  156. package/pp-core/workflows/ship.md +57 -28
  157. package/pp-core/workflows/undo.md +1 -1
  158. package/pp-core/workflows/update.md +3 -3
  159. package/pp-core/workflows/validate-phase.md +58 -3
  160. package/pp-core/workflows/vault-review.md +282 -22
  161. package/pp-core/workflows/verify-work.md +12 -14
  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 -11
  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 +12 -10
  173. package/scripts/practice-arithmetic-contract.allow.json +35 -0
  174. package/scripts/prompt-injection-scan.sh +22 -17
  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 -483
  184. package/pp-core/bin/lib/install-run.cjs +0 -536
  185. package/pp-core/bin/lib/loop-gates.cjs +0 -213
  186. package/pp-core/bin/lib/phase-manifest.cjs +0 -527
  187. package/pp-core/bin/lib/phase-tier.cjs +0 -480
  188. package/pp-core/bin/lib/plan-graph.cjs +0 -368
  189. package/pp-core/references/executor-vault-trace.md +0 -47
  190. package/pp-core/references/planner-plan-graph.md +0 -66
  191. package/pp-core/workflows/discovery-sprint/vault-fetch.md +0 -37
  192. package/pp-core/workflows/execute-phase/steps/checkpoint-handling.md +0 -45
  193. package/pp-core/workflows/execute-phase/steps/install-run.md +0 -29
  194. package/pp-core/workflows/execute-phase/steps/phase-close-rebaseline.md +0 -23
  195. package/pp-core/workflows/execute-phase/steps/serial-group-dispatch.md +0 -73
  196. package/pp-core/workflows/execute-phase/steps/vault-door-gate.md +0 -19
  197. package/pp-core/workflows/plan-phase/steps/phase-tier.md +0 -43
  198. package/scripts/lib/size-budget.cjs +0 -311
  199. package/scripts/lint-neutrality-names.cjs +0 -694
  200. package/scripts/lint-org-coordinates.allowlist.json +0 -35
  201. package/scripts/lint-org-coordinates.cjs +0 -426
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  /**
3
- * src/vault-update.cts — `pp-tools vault update [<tag>] [--yes]`.
3
+ * src/vault-update.cts — `pp-tools vault update [<tag>] [--yes]` (PBI 74316).
4
4
  *
5
- * Moves a project to another version of its client vault. The
5
+ * FORK-ONLY. Moves a project to another version of its client vault. The
6
6
  * vault version is a PROJECT property: `client.vaultRef` in the committed
7
7
  * `.platform-bindings.json` is the one place it lives, so no pp-core release
8
8
  * can move it — changing it is a deliberate act, and this is its command.
@@ -20,15 +20,6 @@
20
20
  * vault version a project picks implies a minimum pp-core, never the reverse).
21
21
  * It never commits: the command it prints is the operator's to run.
22
22
  *
23
- * With no `<tag>` it proposes the newest stable `vX.Y.Z` tag of the configured
24
- * vault repository, listed with `git ls-remote` at the same clone target the
25
- * fetch uses (`resolveClientCoordinates` + `composeCloneTarget`). Nothing here
26
- * reads an org profile for a version: the vault version is the project's.
27
- *
28
- * Every repository coordinate it prints goes through `redactCloneTarget`, and
29
- * every value it echoes from the bindings file or the command line is
30
- * bounded to one short line.
31
- *
32
23
  * ADR-457 build-at-publish: this TypeScript file is the SOURCE OF TRUTH. It
33
24
  * compiles to the git-ignored `pp-core/bin/lib/vault-update.cjs`.
34
25
  */
@@ -48,8 +39,8 @@ const compose_bindings_cjs_1 = require("./compose-bindings.cjs");
48
39
  const git_provider_cjs_1 = require("./git-provider.cjs");
49
40
  const vault_coordinates_cjs_1 = require("./vault-coordinates.cjs");
50
41
  const platform_bindings_cjs_1 = require("./platform-bindings.cjs");
51
- // The one coordinate redactor. Cycle-free — src/vault.cts imports nothing from
52
- // this module; the lazy `require` in runFetch exists for the `_fetch` seam default.
42
+ // VAULT-EGRESS-1 (quick 261005-8py): the one coordinate redactor. Cycle-free — src/vault.cts imports
43
+ // nothing from this module; the lazy `require` in runFetch exists for the `_fetch` seam default.
53
44
  // eslint-disable-next-line @typescript-eslint/no-require-imports
54
45
  const vaultModule = require("./vault.cjs");
55
46
  const { redactCloneTarget } = vaultModule;
@@ -66,11 +57,6 @@ function isObject(v) {
66
57
  function usableString(v) {
67
58
  return typeof v === 'string' && v.trim() !== '' ? v.trim() : null;
68
59
  }
69
- /** A value from the bindings file or the command line, made safe to print: one line, at most 80 characters. */
70
- function shown(v) {
71
- const flat = v.replace(/[\u0000-\u001F\u007F]+/g, ' ').trim();
72
- return flat.length > 80 ? `${flat.slice(0, 80)}…` : flat;
73
- }
74
60
  function resolveRoot(cwd) {
75
61
  try {
76
62
  return (0, project_root_cjs_1.findProjectRoot)(cwd) || cwd;
@@ -103,7 +89,6 @@ function runFetch(root, opts) {
103
89
  return {
104
90
  source: typeof manifest.source === 'string' ? manifest.source : 'unknown',
105
91
  ref: typeof manifest.ref === 'string' ? manifest.ref : null,
106
- tier: typeof manifest.tier === 'string' ? manifest.tier : null,
107
92
  warnings,
108
93
  };
109
94
  }
@@ -173,8 +158,7 @@ function vaultUpdate(cwd, opts = {}) {
173
158
  let tags;
174
159
  try {
175
160
  const provider = (0, git_provider_cjs_1.resolveProvider)(root).provider;
176
- // The same host chain the fetch uses (client.vaultHost, platform host, provider default).
177
- const host = (0, vault_coordinates_cjs_1.resolveClientCoordinates)(root, provider).host;
161
+ const host = usableString(client.vaultHost) ?? (0, vault_coordinates_cjs_1.resolvePlatformHost)(root).host ?? (0, vault_coordinates_cjs_1.defaultHostForProvider)(provider);
178
162
  const target = (0, git_provider_cjs_1.composeCloneTarget)(provider, repo, host);
179
163
  tags = (0, compose_bindings_cjs_1.listStableTagsAt)(target.url, { _lsRemote: opts._lsRemote });
180
164
  }
@@ -190,10 +174,10 @@ function vaultUpdate(cwd, opts = {}) {
190
174
  const requested = usableString(opts.target);
191
175
  const to = requested ? matchRequestedTag(requested, tags) : tags[0];
192
176
  if (!to) {
193
- return fail('unknown_tag', `The vault repo has no tag "${shown(requested ?? "")}". Available (newest first): ${result.available.join(', ')}.`);
177
+ return fail('unknown_tag', `The vault repo has no tag "${requested}". Available (newest first): ${result.available.join(', ')}.`);
194
178
  }
195
179
  result.to = to;
196
- const fromLabel = result.from === null ? 'main (unpinned)' : shown(result.from);
180
+ const fromLabel = result.from ?? 'main (unpinned)';
197
181
  if (result.from === to) {
198
182
  return { ...result, ok: true, message: `The project is already on vault ${to}.` };
199
183
  }
@@ -227,7 +211,7 @@ function vaultUpdate(cwd, opts = {}) {
227
211
  applied.fetch = runFetch(root, opts);
228
212
  }
229
213
  catch {
230
- applied.fetch = { source: 'error', ref: null, tier: null, warnings: ['The vault could not be fetched at the new version — run "pp-tools vault fetch" to retry.'] };
214
+ applied.fetch = { source: 'error', ref: null, warnings: ['The vault could not be fetched at the new version — run "pp-tools vault fetch" to retry.'] };
231
215
  }
232
216
  try {
233
217
  applied.newerSchemaPractices = findNewerSchemaPractices(root, opts);
@@ -244,15 +228,7 @@ function renderVaultUpdate(r) {
244
228
  lines.push(`Newest available: ${r.latest}.`);
245
229
  }
246
230
  if (r.fetch) {
247
- if (r.fetch.tier !== null && r.fetch.tier !== 'client' && r.fetch.source !== 'error') {
248
- // A fallback-tier fetch is not the client vault at the new version, and
249
- // must not read as if it were.
250
- lines.push(`The client vault at ${r.to ?? 'the new version'} was NOT loaded: the fetch fell back to the ${r.fetch.tier} tier` +
251
- `${r.fetch.ref ? ` at ${r.fetch.ref}` : ''}. Check access to the client vault, then run "pp-tools vault fetch".`);
252
- }
253
- else {
254
- lines.push(`Fetched the vault: ${r.fetch.source}${r.fetch.ref ? ` at ${r.fetch.ref}` : ''}.`);
255
- }
231
+ lines.push(`Fetched the vault: ${r.fetch.source}${r.fetch.ref ? ` at ${r.fetch.ref}` : ''}.`);
256
232
  for (const w of r.fetch.warnings)
257
233
  lines.push(w);
258
234
  }
@@ -103,6 +103,8 @@ const PROMOTE_GUARD = Object.freeze({
103
103
  WRITE_TARGET: 'write_target',
104
104
  CONCURRENT_EDIT: 'concurrent_edit',
105
105
  TRANSPORT: 'transport',
106
+ // 13-07 (D-14): standards mode — write-back has no practice layer to write to.
107
+ MODE: 'mode',
106
108
  });
107
109
  // ─── Secret-content scanner (WRB-03 / D-13 / D-14) ──────────────────────────────
108
110
  //
@@ -200,7 +202,7 @@ function boundedToken(v, max = 80) {
200
202
  }
201
203
  // ─── Preflight guard chain ───────────────────────────────────────────────────────
202
204
  /**
203
- * Run the promote preflight guard chain: activation, input, format
205
+ * Run the promote preflight guard chain: activation, mode (13-07), input, format
204
206
  * validation (D-03), secret scan (D-13/D-14), target resolution, and the
205
207
  * write-target guard (D-05) — strictly in that order, refusing at the
206
208
  * first failing stage and never continuing past it. Makes no network
@@ -211,16 +213,37 @@ function promotePreflight({ cwd, filePath, _vault, _practices }) {
211
213
  const vault = _vault ?? require('./vault.cjs');
212
214
  // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment
213
215
  const practices = _practices ?? require('./vault-practices.cjs');
214
- // 1. Activation — both vault.enabled and vault.practices_enabled must be
215
- // strictly true. Runs before any filesystem access; rides the two
216
- // existing default-false config keys (no new config key, no capability
217
- // surface widening).
218
- const enabled = vault.cfgGet(cwd, 'vault.enabled', false);
219
- const practicesEnabled = vault.cfgGet(cwd, 'vault.practices_enabled', false);
220
- if (enabled !== true || practicesEnabled !== true) {
216
+ // 1. Activation — the vault-practices capability must be on. Runs before
217
+ // any filesystem access; rides the two existing default-false config keys
218
+ // (no new config key, no capability surface widening). Phase 15 D-24/D-25:
219
+ // asked of the ONE practices-switch reader, `isPracticesGateActive`, which
220
+ // resolves both keys exactly as the vault-practices gates' `when` does. The
221
+ // `cfgGet` pair it replaces read only the root config, so a workstream-scoped
222
+ // switch refused here while the gates rendered (15-RESEARCH C-1). Read from
223
+ // the REAL vault leaf, not the `_vault` seam, like the mode guard below: a
224
+ // mocked config read must not be able to switch promotion on.
225
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
226
+ const switchOwner = require('./vault.cjs');
227
+ if (!switchOwner.isPracticesGateActive(cwd)) {
221
228
  return refusal(PROMOTE_GUARD.ACTIVATION, ERROR_REASON.VAULT_PROMOTE_DISABLED, 'This practice was not promoted: vault write-back is switched off for this project. ' +
222
229
  'Set both vault.enabled and vault.practices_enabled to true in .planning/config.json and run the promotion again.');
223
230
  }
231
+ // 1b. Mode (13-07, D-14, PARK-03) — in standards mode the vault carries
232
+ // standards documents maintained through its INDEX.md, not practice files,
233
+ // so there is nothing a promotion could write. Refused here, after the
234
+ // activation guard and BEFORE the input guard reads `filePath` or any clone
235
+ // runs, so the preview and `--confirmed` share it (both call this chain
236
+ // first). Read from the REAL vault leaf, not the `_vault` seam: a governance
237
+ // decision must not be switchable by a test mock (the 13-06 precedent). The
238
+ // envelope carries NO mode key — a promote verdict already uses that key for
239
+ // create/update — so the mode is named in the message only.
240
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
241
+ const modeOwner = require('./vault.cjs');
242
+ if (modeOwner.isStandardsModeActive(cwd)) {
243
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
244
+ const { notApplicablePromoteMessage } = require('./vault-mode.cjs');
245
+ return refusal(PROMOTE_GUARD.MODE, ERROR_REASON.VAULT_PROMOTE_NOT_APPLICABLE, notApplicablePromoteMessage());
246
+ }
224
247
  // 2. Input — a path to an already-authored practice file (D-02); this
225
248
  // module never composes, rewrites, reformats, or extracts a practice.
226
249
  if (typeof filePath !== 'string' ||
@@ -242,21 +265,40 @@ function promotePreflight({ cwd, filePath, _vault, _practices }) {
242
265
  const cause = parsed.warning.replace(/^.*?\s+skipped:\s*/, '');
243
266
  return refusal(PROMOTE_GUARD.VALIDATION, ERROR_REASON.VAULT_PROMOTE_INVALID_PRACTICE, `This practice was not promoted: ${cause} Fix the practice file and run the promotion again.`);
244
267
  }
245
- // 3b. Degraded-parse refusal. Write-side strictness is deliberate: the read
246
- // side keeps a practice it does not fully understand, because it already
247
- // governs work and dropping it would silently un-govern that work; promoting
248
- // it would push the defect into the shared vault every machine fetches. Both
249
- // consumers of DOCUMENTED_FRONTMATTER_KEYS move in the one change that
250
- // widened it — had only the reader moved, an unknown key would have quietly
251
- // become promotable.
268
+ // 3b. Degraded-parse refusal (CHECK-02e, 05-01).
269
+ //
270
+ // WRITE-SIDE STRICTNESS IS DELIBERATE, and the asymmetry with the read side
271
+ // is the point. On the READ side a practice the engine does not fully
272
+ // understand is retained: it came from the vault, it already governs work,
273
+ // and dropping it would silently un-govern that work (ADR-71924 §5). On the
274
+ // WRITE side the same practice is refused, because promoting it pushes the
275
+ // defect INTO the fleet-wide vault that every developer machine and CI runner
276
+ // fetches — one unreviewed key becomes everyone's degraded warning. The read
277
+ // side tolerates what the write side refuses.
278
+ //
279
+ // Both consumers of DOCUMENTED_FRONTMATTER_KEYS therefore moved in the one
280
+ // change that widened it (T-4-49): had only the reader moved, an unknown key
281
+ // would have quietly become promotable.
252
282
  if (parsed.degradedWarnings !== undefined && parsed.degradedWarnings.length > 0) {
253
283
  const cause = parsed.degradedWarnings[0].replace(/^.*?\s+degraded:\s*/, '');
254
284
  return refusal(PROMOTE_GUARD.VALIDATION, ERROR_REASON.VAULT_PROMOTE_INVALID_PRACTICE, `This practice was not promoted: ${cause} Fix the practice file and run the promotion again.`);
255
285
  }
256
- // 3c. Invalid-check-block refusal. The reader reports this defect on its own
257
- // channel (`practice.checkInvalid`), which is neither `!parsed.ok` nor
258
- // `degradedWarnings` — discovery folds it into `degraded[]`, but this path
259
- // never calls discovery — so both rungs above miss it.
286
+ // 3c. Invalid-check-block refusal (CR-05 / G-3, 05-11).
287
+ //
288
+ // An invalid `check:` block is refused on the write side for the same reason
289
+ // 3b refuses a degraded parse, and the consequence here is worse. The reader
290
+ // reports this defect on a THIRD channel — `practice.checkInvalid` — which is
291
+ // neither `!parsed.ok` nor `degradedWarnings`, so both rungs above miss it;
292
+ // and the folding of `checkInvalid` into `degraded[]` happens inside
293
+ // `discoverPracticeFiles`, which this path never calls.
294
+ //
295
+ // Once such a practice is in the fleet vault the defect is not a warning for
296
+ // the next reader: `verdictForPractice`'s FIRST rung maps `checkInvalid` to a
297
+ // fail-closed FAIL(check_invalid), so it becomes `block: true` at ship:pre and
298
+ // verify:post on every machine that fetches the vault. One typo would stop the
299
+ // whole fleet's builds. The refusal covers ANY invalid block regardless of
300
+ // which assertion kind it declared (D-05-05), because `checkInvalid` is the
301
+ // single fail-closed signal for both.
260
302
  if (typeof parsed.practice.checkInvalid === 'string' && parsed.practice.checkInvalid.length > 0) {
261
303
  return refusal(PROMOTE_GUARD.VALIDATION, ERROR_REASON.VAULT_PROMOTE_INVALID_PRACTICE, `This practice was not promoted: ${parsed.practice.checkInvalid} ` +
262
304
  'Fix the practice file and run the promotion again.');
@@ -421,7 +463,9 @@ function buildExpectToken(localRaw, remoteBaseline) {
421
463
  // reading) — duplicating the fix a second time is exactly how that class of
422
464
  // bug recurs.
423
465
  function previewPromotion({ cwd, filePath, _exec, _vault, _practices }) {
424
- const gitExec = _exec ?? shell_command_projection_cjs_1.execGit;
466
+ const gitExec = _exec ?? shell_command_projection_cjs_1.execGitLocal;
467
+ // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment
468
+ const vault = _vault ?? require('./vault.cjs');
425
469
  // 1. Run the full preflight guard chain; refuse unchanged with no clone.
426
470
  const pre = promotePreflight({ cwd, filePath, _vault, _practices });
427
471
  if (pre.status !== 'ok')
@@ -459,7 +503,7 @@ function previewPromotion({ cwd, filePath, _exec, _vault, _practices }) {
459
503
  cloneDir,
460
504
  ], { timeout: 120_000 });
461
505
  if (cl.exitCode !== 0) {
462
- const cause = shownCause(cl.stderr);
506
+ const cause = boundedToken((cl.stderr || '').split(/\r?\n/)[0] || 'unknown error');
463
507
  return refusal(PROMOTE_GUARD.TRANSPORT, ERROR_REASON.VAULT_PROMOTE_TRANSPORT_FAILED, `This practice was not pushed: git could not reach the vault (${cause}). Check your access to the vault and run the promotion again.`);
464
508
  }
465
509
  // 3. Capture the baseline BEFORE writing — an id already present in the
@@ -571,13 +615,13 @@ function previewPromotion({ cwd, filePath, _exec, _vault, _practices }) {
571
615
  // sentence (plan 03); this note additionally explains why, in the
572
616
  // read-only preview an operator reads before confirming.
573
617
  if (pre.sharedSuppressed && pre.sharedSuppressedKind === 'provider-default-unavailable') {
574
- notes.push(`No shared vault is configured for the ${pre.provider} provider — the built-in Pareto shared default applies only to the gitlab provider. Set vault.fallback_repo to enable the shared tier.`);
618
+ notes.push(`No shared vault is configured for the ${pre.provider} provider — the built-in Pareto shared default applies only to the github provider. Set vault.fallback_repo to enable the shared tier.`);
575
619
  }
576
620
  // 7 & 8. Pin both sides in the opaque expect token, then return.
577
621
  const expect = buildExpectToken(pre.raw, baseline);
578
622
  return {
579
623
  status: 'preview',
580
- repo: shownRepo(pre.repo),
624
+ repo: vault.redactCloneTarget(pre.repo),
581
625
  ref: pre.ref,
582
626
  destination: pre.destination,
583
627
  mode,
@@ -596,25 +640,9 @@ function previewPromotion({ cwd, filePath, _exec, _vault, _practices }) {
596
640
  }
597
641
  }
598
642
  // ─── Confirm (write half of the write path) ──────────────────────────────────────
599
- /**
600
- * Pack 6 D-07: the display-safe forms used in every verdict and refusal this
601
- * module EMITS — the one owner in src/vault.cts, lazily required (the
602
- * module's `_vault` seam stays the fetch seam; redaction is never mocked).
603
- * Comparisons, the expect token and every git invocation keep the RAW values.
604
- */
605
- function shownRepo(repo) {
606
- // eslint-disable-next-line @typescript-eslint/no-require-imports
607
- const v = require('./vault.cjs');
608
- return v.redactCloneTarget(repo) ?? repo;
609
- }
610
- function shownCause(stderr) {
611
- // eslint-disable-next-line @typescript-eslint/no-require-imports
612
- const v = require('./vault.cjs');
613
- return boundedToken(v.redactRemoteText((stderr || '').split(/\r?\n/)[0] || 'unknown error'));
614
- }
615
643
  /** Build a TRANSPORT refusal from a failed git invocation's stderr (first line only). */
616
644
  function transportRefusal(res) {
617
- const cause = shownCause(res.stderr);
645
+ const cause = boundedToken((res.stderr || '').split(/\r?\n/)[0] || 'unknown error');
618
646
  return refusal(PROMOTE_GUARD.TRANSPORT, ERROR_REASON.VAULT_PROMOTE_TRANSPORT_FAILED, `This practice was not pushed: git could not reach the vault (${cause}). Check your access to the vault and run the promotion again.`);
619
647
  }
620
648
  /**
@@ -636,7 +664,7 @@ function transportRefusal(res) {
636
664
  * for free, so no separate `git show`/`cat-file` call is needed.
637
665
  */
638
666
  function confirmPromotion({ cwd, filePath, expect, _exec, _vault, _practices }) {
639
- const gitExec = _exec ?? shell_command_projection_cjs_1.execGit;
667
+ const gitExec = _exec ?? shell_command_projection_cjs_1.execGitLocal;
640
668
  // 1. Full preflight re-run — never trust the preview. Re-derives repo,
641
669
  // ref, host, and destination from scratch; never accepts a caller-
642
670
  // supplied id/destination/repo/ref.
@@ -774,7 +802,7 @@ function confirmPromotion({ cwd, filePath, expect, _exec, _vault, _practices })
774
802
  }
775
803
  return {
776
804
  status: 'pushed',
777
- repo: shownRepo(pre.repo),
805
+ repo: vault.redactCloneTarget(pre.repo),
778
806
  ref: pre.ref,
779
807
  destination: pre.destination,
780
808
  mode,