@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
@@ -1,11 +1,10 @@
1
1
  <purpose>
2
- Take one local practice file from preview to a confirmed, pushed promotion into the client
3
- vault — and nothing more. This workflow is the single human gate in front of an
4
- irreversible outward action: it shows the operator the complete preview, asks once whether
5
- to proceed, and only on explicit approval re-invokes the same guarded CLI arm in confirmed
6
- mode. It never authors, edits, or reformats the practice file, and it performs no direct git
7
- operation of its own — every outward action happens inside the promote verb, which this
8
- workflow only calls.
2
+ Take one local standards document from preview to a confirmed, pushed promotion into the client
3
+ vault, together with its INDEX.md entry, and nothing more. This workflow is the single human gate
4
+ in front of an irreversible outward action: it shows the operator the complete preview, asks once
5
+ whether to proceed, and only on explicit approval re-invokes the same guarded CLI verb in confirmed
6
+ mode. It never authors, edits or reformats the document, and it performs no git operation of its
7
+ own; every outward action happens inside `pp_run vault standards promote`.
9
8
  </purpose>
10
9
 
11
10
  <required_reading>
@@ -15,79 +14,64 @@ Read all files referenced by the invoking prompt's execution_context before star
15
14
  <process>
16
15
 
17
16
  <step name="text_mode">
18
- Resolve `TEXT_MODE` here, before the first question, mirroring the same resolution `init.md`
19
- does before its own first prompt. Set `TEXT_MODE=true` if `--text` is present in
20
- `$ARGUMENTS`. When `TEXT_MODE` is active, replace every `AskUserQuestion` call in this
21
- workflow — including the gate in Step 4 — with a plain-text numbered list, and ask the
22
- operator to type their choice number. This is required because non-Claude runtimes have no
23
- interactive question tool, and the confirmation in Step 4 is the entire point of this
24
- workflow — it must degrade to plain text, never disappear.
25
- </step>
26
-
27
- <step name="resolve_launcher">
28
- Resolve the `pp_run` launcher shim before any other step, so every call below goes through
29
- the repo-local or installed `pp-tools` binary rather than assuming a global install:
30
-
31
- ```bash
32
- ```
17
+ Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS`. When `TEXT_MODE` is active, replace
18
+ every `AskUserQuestion` call in this workflow, including the gate below, with a plain-text numbered
19
+ list, and ask the operator to type their choice number. The confirmation is the point of this
20
+ workflow: it must degrade to plain text, never disappear.
33
21
  </step>
34
22
 
35
23
  <step name="resolve_input">
36
- Take the practice file path from `$ARGUMENTS` (the first token that is not `--text`). When
37
- none was given, ask the operator for one with a plain prompt:
24
+ Take from `$ARGUMENTS`:
38
25
 
39
- ```text
40
- Path to the local practice file to promote (e.g. practices/my-practice.md):
41
- ```
26
+ - the document path: the first token that is not a flag (required; ask for it with a plain prompt
27
+ when it is missing: `Path to the local standards document to promote (e.g. docs/standards/api-errors.md):`);
28
+ - `--path <vault-path>`: where the document goes in the vault (optional; defaults to
29
+ `standards/<file name>`);
30
+ - `--entry "<what it is>; used when <…>"`: the document's INDEX.md entry text (required when the
31
+ vault's INDEX.md does not list the document yet; replaces the existing line when given for a
32
+ listed document);
33
+ - `--section <title>`: the INDEX.md `##` section a new entry goes under (optional).
34
+
35
+ When the document is new to the vault and no `--entry` was given, ask the operator for one plain
36
+ sentence of the form `<what the document is>; used when <when a plan should follow it>`. Never
37
+ invent it.
42
38
 
43
- Do not compose, author, rewrite, or reformat the practice file at this or any later step —
44
- authoring stays outside this guarded path entirely. Whatever bytes are on disk right now at
45
- that path are exactly the bytes that will be previewed and, if approved, pushed.
39
+ Do not compose, rewrite or reformat the document at this or any later step. Whatever bytes are on
40
+ disk at that path are exactly the bytes that will be previewed and, if approved, pushed.
46
41
 
47
42
  ```bash
48
- PRACTICE_FILE="<the resolved path>"
43
+ DOC_FILE="<the resolved path>"
44
+ PROMOTE_ARGS=() # add --path, --entry and --section with their values, as given
49
45
  ```
50
46
  </step>
51
47
 
52
48
  <step name="preview">
53
- Run the promote verb with the file path and `--raw`, capturing stdout, stderr, and the exit
54
- code. This invocation performs no outward action — it only clones into a disposable
55
- directory, computes the diff, and reports.
49
+ Run the promote verb without `--confirmed`, capturing stdout, stderr and the exit code. This
50
+ invocation performs no outward action: it clones the client vault into a disposable directory,
51
+ writes the change there, and reports the diff.
56
52
 
57
53
  ```bash
58
54
  _PP_SHIM_NAME="pp-tools.cjs"; _pp_root() { ( for _v in $(env | sed -n 's/^\(GIT_[A-Za-z0-9_]*\)=.*/\1/p'); do unset "$_v"; done; _c=$(git rev-parse --git-common-dir 2>/dev/null); if [ "${_c##*/}" = .git ] && cd "$_c/.." 2>/dev/null; then pwd -P; else git rev-parse --show-toplevel 2>/dev/null || pwd; fi ); }; pp_run() { case "$PP_TOOLS" in *.cjs) node "$PP_TOOLS" "$@";; *) "$PP_TOOLS" "$@";; esac; }; _PP_RUNTIME_ROOT="${RUNTIME_DIR:-$(_pp_root)}"; PP_TOOLS="${_PP_RUNTIME_ROOT}/pp-core/bin/${_PP_SHIM_NAME}"; if [ -f "$PP_TOOLS" ]; then :; elif [ -f "${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}"; elif command -v pp-tools >/dev/null 2>&1; then PP_TOOLS="$(command -v pp-tools)"; else echo "ERROR: pp-tools.cjs not found at $PP_TOOLS and pp-tools is not on PATH. Run: npx -y @pareto4/pp-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${PP_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${PP_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
59
55
  PROMOTE_PREVIEW_OUT=$(mktemp)
60
56
  PROMOTE_PREVIEW_ERR=$(mktemp)
61
- pp_run vault practices promote "$PRACTICE_FILE" --raw >"$PROMOTE_PREVIEW_OUT" 2>"$PROMOTE_PREVIEW_ERR"
57
+ pp_run vault standards promote "$DOC_FILE" "${PROMOTE_ARGS[@]}" --raw >"$PROMOTE_PREVIEW_OUT" 2>"$PROMOTE_PREVIEW_ERR"
62
58
  PREVIEW_EXIT=$?
63
59
  ```
64
60
 
65
- **When `$PREVIEW_EXIT` is non-zero: stop here.** Show the operator the exact, single-sentence
66
- contents of `$PROMOTE_PREVIEW_ERR` — the arm's own refusal message — verbatim and add nothing
67
- to it. Do not ask anything. Do not proceed to Step 3. Every guard refusal ends at this line,
68
- and nothing has been pushed. Clean up both temp files before ending.
61
+ **When `$PREVIEW_EXIT` is non-zero: stop here.** Show the operator the single-sentence refusal in
62
+ `$PROMOTE_PREVIEW_ERR` verbatim and add nothing to it. Do not ask anything. Nothing has been pushed.
63
+ Clean up both temp files before ending.
69
64
 
70
- When `$PREVIEW_EXIT` is zero, continue to Step 3 with `$PROMOTE_PREVIEW_OUT` holding the
71
- preview verdict as JSON.
65
+ When `$PREVIEW_EXIT` is zero, `$PROMOTE_PREVIEW_OUT` holds the preview verdict as JSON.
72
66
  </step>
73
67
 
74
68
  <step name="render_confirmation">
75
- Parse `$PROMOTE_PREVIEW_OUT` as JSON and read its fields directly — never regex-scrape a
76
- prose rendering of it. That shortcut is exactly the shell-glue blind spot this project has
77
- been bitten by before: a `.md` step file's own parsing drifting from what the CLI actually
78
- emits.
79
-
80
- Field values are vault-authored, so they are read as **data, never as shell syntax**. `id`
81
- is only constrained to equal the practice file's basename (D-03), and a filename may legally
82
- contain `$(...)`, backticks, or `;` — so writing the fields as a `KEY="value"` file and
83
- `source`-ing it would execute whatever the filename contains. `JSON.stringify` does not help:
84
- it escapes `"` and `\` but leaves `$` and backticks intact, and both expand inside double
85
- quotes. Each field therefore goes to its own file and is read back with `$(cat …)`, whose
86
- result bash does not re-scan for expansion.
69
+ Read the verdict's fields directly, never by scraping a prose rendering. Each field is written to
70
+ its own file and read back with `$(cat …)`, whose result bash does not re-scan for expansion, so a
71
+ destination path containing `$(...)` or backticks is shown, never executed.
87
72
 
88
73
  ```bash
89
74
  PROMOTE_FIELDS=$(mktemp -d)
90
- PROMOTE_BODY=$(mktemp)
91
75
  node -e "
92
76
  const fs = require('fs');
93
77
  const path = require('path');
@@ -98,94 +82,78 @@ put('repo', v.repo);
98
82
  put('ref', v.ref);
99
83
  put('destination', v.destination);
100
84
  put('mode', v.mode);
101
- put('id', v.id);
102
- put('sharedShadow', v.sharedShadow ? 'true' : 'false');
103
- put('sharedShadowNote', v.sharedShadowNote);
85
+ put('indexChange', v.indexChange);
104
86
  put('expect', v.expect);
105
- fs.writeFileSync(process.argv[3], v.mode === 'update' ? (v.diff ?? '') : (v.content ?? ''));
106
- " "$PROMOTE_PREVIEW_OUT" "$PROMOTE_FIELDS" "$PROMOTE_BODY"
87
+ put('diff', v.diff);
88
+ put('notes', (v.notes || []).join('\n'));
89
+ " "$PROMOTE_PREVIEW_OUT" "$PROMOTE_FIELDS"
107
90
  PROMOTE_REPO=$(cat "$PROMOTE_FIELDS/repo")
108
91
  PROMOTE_REF=$(cat "$PROMOTE_FIELDS/ref")
109
92
  PROMOTE_DEST=$(cat "$PROMOTE_FIELDS/destination")
110
93
  PROMOTE_MODE=$(cat "$PROMOTE_FIELDS/mode")
111
- PROMOTE_ID=$(cat "$PROMOTE_FIELDS/id")
112
- PROMOTE_SHARED=$(cat "$PROMOTE_FIELDS/sharedShadow")
113
- PROMOTE_SHARED_NOTE=$(cat "$PROMOTE_FIELDS/sharedShadowNote")
94
+ PROMOTE_INDEX=$(cat "$PROMOTE_FIELDS/indexChange")
114
95
  PROMOTE_EXPECT=$(cat "$PROMOTE_FIELDS/expect")
115
96
  ```
116
97
 
117
- Show the operator, in this exact order, reading every value from the parsed fields above —
118
- never truncated, summarized, or collapsed to "the first N lines":
98
+ Show the operator, in this order, never truncated or summarised:
119
99
 
120
100
  1. The target vault repository (`$PROMOTE_REPO`) and ref (`$PROMOTE_REF`).
121
- 2. The destination path inside that repository (`$PROMOTE_DEST`).
122
- 3. Whether this **creates** a new practice or **updates** an existing one
123
- (`$PROMOTE_MODE`, for id `$PROMOTE_ID`).
124
- 4. When `$PROMOTE_SHARED` is `true`, the shared-vault disclosure sentence verbatim from
125
- `$PROMOTE_SHARED_NOTE` — this id also exists in the shared Pareto vault, and promoting it
126
- here makes the client's version the one that applies for this client.
127
- 5. One line stating plainly that the secret scan already run inside the promote verb found
128
- nothing in this file — a file that failed that scan would have refused before a preview
129
- was ever produced, so reaching this line already proves the scan passed.
130
- 6. The complete contents of `$PROMOTE_BODY` — the full diff when `$PROMOTE_MODE` is
131
- `update`, or the full new-file content when it is `create`. Show every byte; the operator
132
- is about to approve exactly these bytes, so nothing here may be shortened.
101
+ 2. The destination path in the vault (`$PROMOTE_DEST`), and whether this **creates** a new
102
+ standards document or **updates** an existing one (`$PROMOTE_MODE`).
103
+ 3. What happens to INDEX.md (`$PROMOTE_INDEX`): `added` (a new line), `replaced` (its line gets the
104
+ new entry text) or `unchanged`.
105
+ 4. One line stating that the secret scan inside the promote verb found nothing; a document that
106
+ failed it would have been refused before any preview existed.
107
+ 5. Any notes in `$PROMOTE_FIELDS/notes`.
108
+ 6. The complete contents of `$PROMOTE_FIELDS/diff`: the document and the INDEX.md change, every
109
+ byte. The operator is about to approve exactly these bytes.
133
110
  </step>
134
111
 
135
112
  <step name="gate">
136
- Ask the operator with `AskUserQuestion` (or a numbered plain-text prompt when `TEXT_MODE` is
137
- active) whether to push this to the client vault. Offer exactly two outcomes — there is no
138
- default, no timeout, and no auto-advance, because this is an irreversible outward action and
139
- this confirmation is the whole review step:
113
+ Ask once whether to push. Exactly two outcomes, no default, no timeout, no auto-advance:
140
114
 
141
115
  ```text
142
116
  AskUserQuestion([
143
117
  {
144
118
  header: "Push to client vault",
145
- question: "Push this practice to the client vault now?",
119
+ question: "Push this standards document to the client vault now?",
146
120
  multiSelect: false,
147
121
  options: [
148
- { label: "Push it", description: "Push exactly the diff/content shown above" },
122
+ { label: "Push it", description: "Push exactly the diff shown above" },
149
123
  { label: "Stop", description: "Do not push anything — the vault stays unchanged" }
150
124
  ]
151
125
  }
152
126
  ])
153
127
  ```
154
128
 
155
- **When the operator chooses to stop:** print one sentence saying nothing was pushed and the
156
- client vault is unchanged, clean up the temp files, and end the workflow here.
129
+ **When the operator chooses to stop:** say in one sentence that nothing was pushed and the client
130
+ vault is unchanged, clean up the temp paths, and end.
157
131
 
158
- **When the operator chooses to push:** continue to Step 5.
132
+ **When the operator chooses to push:** continue.
159
133
  </step>
160
134
 
161
135
  <step name="push">
162
- Only inside this approved branch, run the promote verb again with the same file path, the
163
- confirmed flag, the expect token carried verbatim from the preview verdict, and `--raw`. This
164
- workflow never runs an outward git operation itself — the only thing it does here is invoke
165
- this verb a second time; every push, every commit, and every other outward action happens
166
- inside the verb, not in this shell block.
136
+ Only inside this approved branch, run the verb again with the same arguments, `--confirmed`, and the
137
+ expect token carried verbatim from the preview.
167
138
 
168
139
  ```bash
169
140
  PROMOTE_PUSH_OUT=$(mktemp)
170
141
  PROMOTE_PUSH_ERR=$(mktemp)
171
- pp_run vault practices promote "$PRACTICE_FILE" --confirmed --expect "$PROMOTE_EXPECT" --raw >"$PROMOTE_PUSH_OUT" 2>"$PROMOTE_PUSH_ERR"
142
+ pp_run vault standards promote "$DOC_FILE" "${PROMOTE_ARGS[@]}" --confirmed --expect "$PROMOTE_EXPECT" --raw >"$PROMOTE_PUSH_OUT" 2>"$PROMOTE_PUSH_ERR"
172
143
  PUSH_EXIT=$?
173
144
  ```
174
145
 
175
- **When `$PUSH_EXIT` is non-zero:** show the arm's own single-sentence refusal from
176
- `$PROMOTE_PUSH_ERR` verbatim and end — the arm has already guaranteed nothing was pushed on a
177
- refusal. A concurrent-edit refusal here is expected, ordinary behavior: it means someone else
178
- changed this same practice in the client vault between the preview in Step 2 and this push.
179
- The remedy is simply to run this workflow again from the top — the new preview will diff
180
- against their current version. Clean up all temp files before ending.
181
-
182
- When `$PUSH_EXIT` is zero, continue to Step 6 with `$PROMOTE_PUSH_OUT` holding the push
183
- verdict as JSON.
146
+ **When `$PUSH_EXIT` is non-zero:** show the verb's single-sentence refusal from `$PROMOTE_PUSH_ERR`
147
+ verbatim and end; a refusal guarantees nothing was pushed. A concurrent-edit refusal is ordinary:
148
+ someone changed the document or INDEX.md in the vault since the preview. The remedy is to run this
149
+ workflow again from the top. Clean up all temp paths before ending.
184
150
  </step>
185
151
 
186
152
  <step name="report">
187
- Parse `$PROMOTE_PUSH_OUT` the same way Step 3 parsed the preview verdict — direct field
188
- reads, never a prose scrape:
153
+ Read the push verdict's fields the same way, then show the operator the repository, the destination,
154
+ the new commit, what happened to INDEX.md, and whether the local vault cache was refreshed. When the
155
+ refresh did not succeed, say so plainly: the next vault fetch picks the change up; the push itself
156
+ succeeded.
189
157
 
190
158
  ```bash
191
159
  node -e "
@@ -195,19 +163,14 @@ process.stdout.write(
195
163
  'repo=' + (v.repo ?? '') + '\n' +
196
164
  'destination=' + (v.destination ?? '') + '\n' +
197
165
  'commit=' + (v.commit ?? '') + '\n' +
166
+ 'indexChange=' + (v.indexChange ?? '') + '\n' +
198
167
  'cacheRefreshed=' + String(!!v.cacheRefreshed) + '\n'
199
168
  );
200
169
  " "$PROMOTE_PUSH_OUT"
201
170
  ```
202
171
 
203
- Show the operator: the repository, the destination path, the new commit the push produced,
204
- and whether the local read cache of the vault was refreshed. When the local cache refresh did
205
- not succeed, say so plainly and note that the next vault fetch will pick up the change — this
206
- is a cosmetic staleness in the local cache only, not a sign the push failed.
207
-
208
- Clean up every temp path created in this workflow (`$PROMOTE_PREVIEW_OUT`,
209
- `$PROMOTE_PREVIEW_ERR`, `$PROMOTE_BODY`, `$PROMOTE_PUSH_OUT`, `$PROMOTE_PUSH_ERR`, and the
210
- `$PROMOTE_FIELDS` **directory**, which needs `rm -rf`) before ending.
172
+ Clean up every temp path created in this workflow (`$PROMOTE_PREVIEW_OUT`, `$PROMOTE_PREVIEW_ERR`,
173
+ `$PROMOTE_PUSH_OUT`, `$PROMOTE_PUSH_ERR`, and the `$PROMOTE_FIELDS` directory with `rm -rf`).
211
174
  </step>
212
175
 
213
176
  </process>
@@ -463,7 +463,7 @@ printf '%s' "$VERIFY_POST_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(requi
463
463
  SECURITY_FILE=$(ls "${PHASE_DIR}"/*-SECURITY.md 2>/dev/null | head -1)
464
464
  ```
465
465
 
466
- **Vault practice gates.** Read `pp-core/workflows/execute-phase/steps/verify-post-gate.md` — it
466
+ **Vault gates.** Read `pp-core/workflows/execute-phase/steps/verify-post-gate.md` — it
467
467
  dispatches this point's blocking gates to the generic enforcer, which owns the halt. Rendering the
468
468
  payload above is not enforcing it, and the branch below marks the phase complete.
469
469
 
@@ -1247,8 +1247,7 @@ function validateGate(gate, prefix) {
1247
1247
  * - contribution.into ∈ step's agentRoles, OR contribution.into names an agent
1248
1248
  * already registered by some capability's own `agents` array (a non-pipeline
1249
1249
  * consumer of the same loop point, e.g. code-review.md reading execute:post
1250
- * alongside execute-phase.md — see capabilities/vault-practices's
1251
- * execute:post -> pp-code-reviewer contribution)
1250
+ * alongside execute-phase.md)
1252
1251
  * - when references a config key in cap.config
1253
1252
  *
1254
1253
  * NOTE: step.consumes satisfiability is NOT checked here — it requires the full
@@ -1331,78 +1330,9 @@ function validateAgainstContract(cap, capId, knownAgentIds) {
1331
1330
  return errors;
1332
1331
  }
1333
1332
 
1334
- /**
1335
- * Phase 15 D-02: validate the per-hook `vaultMode` filter field.
1336
- *
1337
- * The pure loop resolver evaluates `vaultMode` against an injected mode value
1338
- * and never emits it, so an unknown or misplaced value must be refused HERE,
1339
- * at generation, never interpreted at runtime. Three rules, each reported on
1340
- * its own:
1341
- * (a) the field is allowed on contributions and gates only (a step is
1342
- * refused);
1343
- * (b) the value must be a string in the vault capability's declared
1344
- * `config["vault.mode"].values`. That enum declaration is the ONE owner of
1345
- * the closed set; it is read here, never restated. With no vault
1346
- * capability, or no such values array, there is no closed set and every
1347
- * `vaultMode` is refused (fail closed);
1348
- * (c) the declaring capability must be `vault` or list `vault` in `requires`,
1349
- * so a filtered hook can only exist where the vault gate's closure holds.
1350
- *
1351
- * Presence is own-property presence, so a JSON `null` is refused under (b).
1352
- *
1353
- * @param {Map<string, object>} capMap
1354
- * @returns {string[]} error strings; empty = all pass
1355
- */
1356
- function validateVaultModeField(capMap) {
1357
- const errors = [];
1358
- const vaultCap = capMap.get('vault');
1359
- const modeDecl = vaultCap && vaultCap.config && typeof vaultCap.config === 'object'
1360
- ? vaultCap.config['vault.mode']
1361
- : undefined;
1362
- const allowed = modeDecl && Array.isArray(modeDecl.values)
1363
- ? modeDecl.values.filter((v) => typeof v === 'string')
1364
- : null;
1365
- const KINDS = [['steps', 'step'], ['contributions', 'contribution'], ['gates', 'gate']];
1366
- for (const [capId, cap] of capMap) {
1367
- if (!cap || typeof cap !== 'object') continue;
1368
- const prefix = 'capability "' + capId + '"';
1369
- const requiresVault = Array.isArray(cap.requires) && cap.requires.includes('vault');
1370
- for (const [arrKey, kind] of KINDS) {
1371
- const arr = Array.isArray(cap[arrKey]) ? cap[arrKey] : [];
1372
- for (const hook of arr) {
1373
- if (!hook || typeof hook !== 'object') continue;
1374
- if (!Object.prototype.hasOwnProperty.call(hook, 'vaultMode')) continue;
1375
- const where = prefix + ' ' + kind + ' at point "' + String(hook.point) + '"';
1376
- const value = hook.vaultMode;
1377
- if (kind === 'step') {
1378
- errors.push(where + ': vaultMode is allowed on contributions and gates only');
1379
- }
1380
- if (allowed === null) {
1381
- errors.push(
1382
- where + ': vaultMode ' + JSON.stringify(value) + ' cannot be checked: the vault capability ' +
1383
- 'declares no "vault.mode" values, which own the closed set',
1384
- );
1385
- } else if (typeof value !== 'string' || !allowed.includes(value)) {
1386
- errors.push(
1387
- where + ': vaultMode ' + JSON.stringify(value) + ' is not one of [' + allowed.join(', ') +
1388
- '] (the closed set owned by the vault capability\'s "vault.mode" values)',
1389
- );
1390
- }
1391
- if (capId !== 'vault' && !requiresVault) {
1392
- errors.push(
1393
- where + ': vaultMode is allowed only on the "vault" capability or a capability that ' +
1394
- 'lists "vault" in requires',
1395
- );
1396
- }
1397
- }
1398
- }
1399
- }
1400
- return errors;
1401
- }
1402
-
1403
1333
  /**
1404
1334
  * Quick 261015-ect (QD-13): the vault-family rule for `requiresPlatformBindings`,
1405
- * the mirror of the vaultMode rule (c) above. A capability that is `vault` or
1335
+ * A capability that is `vault` or
1406
1336
  * lists `vault` in `requires` MUST declare the field, so a vault-family
1407
1337
  * capability added later cannot render hooks on a project the vault does not
1408
1338
  * govern by forgetting it. A capability outside the family may declare it too.
@@ -1441,18 +1371,15 @@ const SEAL_FIELD_NAME = 'onRecordedArtifacts';
1441
1371
  * A gate carrying the field renders for an enabled, config-inactive capability
1442
1372
  * over recorded vault artifacts, bypassing the capability's active check and
1443
1373
  * its `when` (D-18). That is a widening of render behaviour, so the field is
1444
- * closed HERE, at generation, to exactly the shape the two shipped seal gates
1445
- * have. Six rules, each reported on its own:
1374
+ * closed HERE, at generation, to exactly the shape the shipped seal gate has.
1375
+ * Five rules, each reported on its own:
1446
1376
  * (a) gates only (a step or contribution carrying it is refused);
1447
1377
  * (b) the value is literal `true` (`"true"`, `1`, `null`, `false` refused);
1448
- * (c) the declaring capability lists `vault` in `requires` and is not `vault`
1449
- * itself (D-26: with the vault off the injected mode is null, so both
1450
- * modes' filtered gates pass and sealing the vault capability too would
1451
- * dispatch `check vault.trace` twice);
1452
- * (d) the gate also carries `vaultMode` (the resolver filters by mode BEFORE
1453
- * the predicate, research C-1);
1454
- * (e) the gate is `blocking: true`;
1455
- * (f) the point is `ship:pre` (D-21: the requirement's block point; a seal at
1378
+ * (c) the declaring capability is `vault` or lists `vault` in `requires`.
1379
+ * A seal gate never dispatches twice: the resolver drops it whenever its
1380
+ * capability is active, so it renders only with the vault switched off;
1381
+ * (d) the gate is `blocking: true`;
1382
+ * (e) the point is `ship:pre` (D-21: the requirement's block point; a seal at
1456
1383
  * verify:post would halt execute-phase on a switch set on purpose).
1457
1384
  *
1458
1385
  * Presence is own-property presence.
@@ -1481,15 +1408,12 @@ function validateSealField(capMap) {
1481
1408
  if (value !== true) {
1482
1409
  errors.push(where + ': ' + SEAL_FIELD_NAME + ' must be literal true (got ' + JSON.stringify(value) + ')');
1483
1410
  }
1484
- if (capId === 'vault' || !requiresVault) {
1411
+ if (capId !== 'vault' && !requiresVault) {
1485
1412
  errors.push(
1486
- where + ': ' + SEAL_FIELD_NAME + ' is allowed only on a capability that lists "vault" in requires ' +
1487
- 'and is not "vault" itself',
1413
+ where + ': ' + SEAL_FIELD_NAME + ' is allowed only on the "vault" capability or a capability that ' +
1414
+ 'lists "vault" in requires',
1488
1415
  );
1489
1416
  }
1490
- if (!Object.prototype.hasOwnProperty.call(hook, 'vaultMode')) {
1491
- errors.push(where + ': a gate carrying ' + SEAL_FIELD_NAME + ' must also carry vaultMode');
1492
- }
1493
1417
  if (hook.blocking !== true) {
1494
1418
  errors.push(where + ': a gate carrying ' + SEAL_FIELD_NAME + ' must be blocking: true');
1495
1419
  }
@@ -1662,10 +1586,6 @@ const TIER_RANK = { core: 0, standard: 1, full: 2 };
1662
1586
  function validateCrossCapability(capMap, centralKeys) {
1663
1587
  const errors = [];
1664
1588
 
1665
- // Phase 15 D-02: the per-hook vaultMode filter field (needs capMap to read the
1666
- // vault capability's closed value set and every capability's `requires`).
1667
- errors.push(...validateVaultModeField(capMap));
1668
-
1669
1589
  // Phase 16 D-19: the per-hook seal field (needs capMap for every capability's
1670
1590
  // `requires`).
1671
1591
  errors.push(...validateSealField(capMap));
@@ -2841,7 +2761,6 @@ module.exports = {
2841
2761
  validateAgainstContract,
2842
2762
  validateConsumesGlobal,
2843
2763
  validateCrossCapability,
2844
- validateVaultModeField,
2845
2764
  validateSealField,
2846
2765
  validatePlatformBindingsField,
2847
2766
  SEAL_FIELD_NAME,
@@ -114,14 +114,6 @@
114
114
  ],
115
115
  "issue": "180"
116
116
  },
117
- "vault-review": {
118
- "files": [
119
- "vault-review.integration.test.cjs",
120
- "vault-review.security.test.cjs",
121
- "vault-review.test.cjs"
122
- ],
123
- "issue": "71924 — Vault Assurance phase 06 (06-03/06-04), three distinct concerns for pp-core/bin/lib/vault-review.cjs: vault-review.test (06-03 unit tests over every pure derivation — the verdict vocabularies, both derived-N-A arms, the counts arithmetic, the range resolver and the clean-render refusal predicate), vault-review.integration.test (06-04 SEAM tests — the deterministic validator of the agent-written artifact, plus the `check vault-review` arm driven through the real pp-core/bin/pp-tools.cjs, where the exit-0/no-block-key contract of D-06-01 and VERIFY-03 is proved at the boundary a gate enforcer actually reads, with RED control 2 proving that guard non-vacuous), and vault-review.security.test (06-04 ADVERSARIAL tests — a spoofed external-content fence-end marker, directive-shaped text and a forged tool-call block planted in real practice BODIES, proving 05-REVIEW's open Critical CR-02 is not repeated on this surface, plus the CR-03 class: no absolute filesystem path in any emitted byte). The split mirrors the `vault` cluster's own reasoning: the unit lane, the CLI seam and the security marker are independently load-bearing verification gates, and the `.security.test.cjs` marker is what makes the adversarial lane identifiable to a reader and to scripts/run-tests.cjs. Consolidating would blur three different questions into one file."
124
- },
125
117
  "verify": {
126
118
  "files": [
127
119
  "bug-2969-verify-reapply-patches.test.cjs",
@@ -189,22 +181,12 @@
189
181
  "files": [
190
182
  "feat-71924-vault-required-gate.test.cjs",
191
183
  "vault-doors.integration.test.cjs",
192
- "vault-practices.property.test.cjs",
193
184
  "vault-read-path.test.cjs",
194
185
  "vault-security.test.cjs",
195
186
  "vault-status-check.test.cjs",
196
187
  "vault.test.cjs"
197
188
  ],
198
- "issue": "v1.7.0 Client Vault Load — four distinct concerns: vault.test (fetch/status/summary unit), vault-security (VSEC-02/03 write-guard + secret/fence), vault-read-path (VGATE-03 SUMMARY pointer), vault-status-check (VGATE-02 gate-query handler). Phase 24-02 added vault-practices.property.test.cjs (fast-check fuzz of the practices glob-fallback compiler + a practices-frontmatter round-trip, PRAC-02) — it is grouped under this bucket rather than \"vault-practices\" because the test-file-count lint's hyphen-prefix matcher treats \"vault-practices.property\" (period before \"property\") as starting with \"vault-\" before it can match the more specific \"vault-practices-\" prefix; the module it actually tests is pp-core/bin/lib/vault-practices.cjs, not vault.cjs. Vault Assurance phase 02 (#71924) added feat-71924-vault-required-gate.test.cjs as the phase's ONE consolidated source-grep feature file — it owns the source-text assertions for GATE-02, GATE-03, GATE-06, GATE-08, GATE-09 and GATE-10 together, deliberately in a single file so the phase's six requirements do not each spawn a sibling; later plans in the phase extend it rather than adding files. Vault Assurance phase 16 plan 10 added vault-doors.integration.test.cjs as the phase's ONE door fence-proof owner (DOOR-01..05, D-09): every door's shipped fence (execute-plan, quick, fast, debug, the secondary doors) composed by tests/helpers/gate-fence-composer.cjs and run in bash and zsh, one describe per door plan, so 16-12..16-15 extend it rather than each adding a sibling. The hyphen-prefix matcher attributes it here because no vault-doors module exists; it tests workflow fences, not vault.cjs."
199
- },
200
- "vault-practices": {
201
- "files": [
202
- "vault-practices-examples.test.cjs",
203
- "vault-practices-matcher.test.cjs",
204
- "vault-practices.slow.test.cjs",
205
- "vault-practices.test.cjs"
206
- ],
207
- "issue": "Phase 24 (24-01/24-02/24-04) — three distinct concerns for pp-core/bin/lib/vault-practices.cjs: vault-practices.test (24-01 parser/validation/discovery unit tests), vault-practices-matcher.test (24-02 glob matcher + two-bucket result + report unit tests), vault-practices-examples.test (24-04 shipped-example drift guard + minimal-comments global-bucket smoke case, PRAC-03 Success Criterion 3). All three test the same production module and are each independently load-bearing; consolidating would blur distinct plan-level verification gates. Vault Assurance phase 05 (#71924) added vault-practices.slow.test.cjs — the >5 s six-axis worst-case matcher corpus for the same production module (pp-core/bin/lib/vault-practices.cjs), split out per the .slow suffix convention so the default suite stays fast; attributed here once the count lint learned to strip the .slow suffix."
189
+ "issue": "v1.7.0 Client Vault Load — four distinct concerns: vault.test (fetch/status/summary unit), vault-security (VSEC-02/03 write-guard + secret/fence), vault-read-path (VGATE-03 SUMMARY pointer), vault-status-check (VGATE-02 gate-query handler). Vault Assurance phase 02 (#71924) added feat-71924-vault-required-gate.test.cjs as the phase's ONE consolidated source-grep feature file — it owns the source-text assertions for GATE-02, GATE-03, GATE-06, GATE-08, GATE-09 and GATE-10 together, deliberately in a single file so the phase's six requirements do not each spawn a sibling; later plans in the phase extend it rather than adding files. Vault Assurance phase 16 plan 10 added vault-doors.integration.test.cjs as the phase's ONE door fence-proof owner (DOOR-01..05, D-09): every door's shipped fence (execute-plan, quick, fast, debug, the secondary doors) composed by tests/helpers/gate-fence-composer.cjs and run in bash and zsh, one describe per door plan, so 16-12..16-15 extend it rather than each adding a sibling. The hyphen-prefix matcher attributes it here because no vault-doors module exists; it tests workflow fences, not vault.cjs."
208
190
  }
209
191
  }
210
192
  }
@@ -80,12 +80,11 @@ function prodPrefix(filename) {
80
80
  // stamps. Five forms are stripped: `.integration`, `.slow`, `.security`,
81
81
  // `.install` and the bare `.test`.
82
82
  //
83
- // `.property` is DELIBERATELY NOT stripped. The `vault` entry in
84
- // scripts/lint-test-file-count.allowlist.json documents
85
- // vault-practices.property.test.cjs as parked in that bucket precisely because
86
- // this function leaves the suffix on — stripping it would re-cluster the file
87
- // into `vault-practices` and turn that entry's own explanation into a false
88
- // statement. Changing it is a deliberate allowlist migration, not a tidy-up.
83
+ // `.property` is DELIBERATELY NOT stripped: a `<name>.property.test.cjs` keeps
84
+ // the suffix in its prefix, so the hyphen-prefix matcher clusters it under the
85
+ // shortest matching module rather than under `<name>`. Stripping it would
86
+ // re-cluster every property test the allowlist has already counted. Changing
87
+ // it is a deliberate allowlist migration, not a tidy-up.
89
88
  function testEffectivePrefix(testName) {
90
89
  const bare = testName
91
90
  .replace(/\.(integration|slow|security|install)\.test\.(ts|cjs)$/, '')
@@ -95,9 +95,6 @@ ALLOWLIST=(
95
95
  'tests/fixtures/adversarial/security/::a directory of adversarial corpus files whose entire purpose is to BE injection payloads for the suites above; measured 20 pattern hits across its 7 tracked files at HEAD on 2026-09-19'
96
96
  'tests/discovery-vault-context.test.cjs::the DISCO-03/SC4 suite plants a real role-manipulation line (the PLANTED constant) into a fixture vault document and asserts the shipped scanner FINDS it, which is the non-vacuity partner for the assertion that the subflow itself scans clean; the payload has to be a literal for that half to mean anything, so the file matches the vocabulary it exists to prove is caught'
97
97
  'tests/vault-status-check.test.cjs::sanitisation seeds for the vault status message carry a real instruction and a real control character on purpose, each paired with a non-vacuity assertion that the RENDERED message does not carry it intact; measured 5 pattern hits at HEAD on 2026-09-19'
98
- 'tests/vault-practices-matcher.test.cjs::the CR-01 fence-spoof suite plants a real instruction-override line and a forged end-fence marker inside practice bodies on purpose, each paired with an assertion that the RENDERED practices block keeps the planted text inside the fence and leaves exactly one genuine closer, so the payload must be a literal for the defang proof to mean anything; measured 3 pattern hits at HEAD b4dd6b3 on 2026-10-04'
99
- 'tests/vault-review.security.test.cjs::the CR-02 suite seeds a practice body with directive-shaped text aimed at the practice judge (the DIRECTIVE_TEXT constant) and asserts the rendered review entry carries it only between the fence markers, after the reference-data preamble, so the judge reads it as data; the text must be a literal for that assertion to mean anything; measured 1 pattern hit at HEAD b4dd6b3 on 2026-10-04'
100
- 'tests/practices-review-check-property.test.cjs::a false positive rather than a payload, since the fence-parsing invariance property builds a never-closed fence whose second-opener line is ordinary English about whether the client line becomes a cut point, and one role-pattern regex matches that plain wording; the fixture text stays as written; measured 1 pattern hit at HEAD b4dd6b3 on 2026-10-04'
101
98
  'tests/vault-index.integration.test.cjs::the fence-spoof suite seeds a vault document heading and an INDEX description that carry a forged end-fence marker followed by an instruction-override phrase, and asserts the rendered SUMMARY keeps exactly one live end marker with the planted line defanged inside the fence, so the phrase must be a literal for the defang proof to mean anything; measured 4 pattern hits at HEAD 5ddb0b3 on 2026-10-12'
102
99
  'tests/vault-seal.integration.test.cjs::the uncovered-commit suite builds a commit whose subject is an instruction-override phrase padded past the cap, modelling a hostile commit message, and asserts the subject leaving the seal leaf is controls-collapsed and bounded to SEAL_SUBJECT_CAP before it can reach a record; measured 1 pattern hit at HEAD 5ddb0b3 on 2026-10-12'
103
100
  'tests/vault-standards.integration.test.cjs::the D-14 suites plant instruction-override lines in a standards document and in its INDEX description, each tagged with a random token, and assert that neither the token nor the phrase appears in any output of vault standards block or consulted, so the phrase must be a literal for the absence proof to mean anything; measured 6 pattern hits at HEAD 5ddb0b3 on 2026-10-12'