mandrel 1.88.0 → 1.90.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 (145) hide show
  1. package/.agents/README.md +18 -13
  2. package/.agents/audit-checklists/architecture.md +24 -0
  3. package/.agents/audit-checklists/clean-code.md +24 -0
  4. package/.agents/audit-checklists/dependencies.md +14 -0
  5. package/.agents/audit-checklists/devops.md +17 -0
  6. package/.agents/audit-checklists/documentation.md +22 -0
  7. package/.agents/audit-checklists/lighthouse.md +15 -0
  8. package/.agents/audit-checklists/navigability.md +14 -0
  9. package/.agents/audit-checklists/performance.md +22 -0
  10. package/.agents/audit-checklists/privacy.md +21 -0
  11. package/.agents/audit-checklists/quality.md +18 -0
  12. package/.agents/audit-checklists/security.md +22 -0
  13. package/.agents/audit-checklists/seo.md +16 -0
  14. package/.agents/audit-checklists/sre.md +24 -0
  15. package/.agents/audit-checklists/ux-ui.md +21 -0
  16. package/.agents/docs/SDLC.md +62 -27
  17. package/.agents/docs/configuration.md +5 -4
  18. package/.agents/instructions.md +51 -21
  19. package/.agents/personas/architect.md +10 -7
  20. package/.agents/personas/engineer.md +4 -3
  21. package/.agents/personas/project-manager.md +5 -2
  22. package/.agents/personas/refactorer.md +5 -3
  23. package/.agents/rules/git-conventions.md +77 -0
  24. package/.agents/schemas/agentrc.schema.json +10 -6
  25. package/.agents/schemas/audit-rules.json +16 -2
  26. package/.agents/schemas/audit-rules.schema.json +7 -6
  27. package/.agents/schemas/lifecycle/epic.blocked.schema.json +1 -1
  28. package/.agents/schemas/lifecycle/merge.unlanded.schema.json +39 -0
  29. package/.agents/schemas/signal-event.schema.json +28 -13
  30. package/.agents/scripts/acceptance-spec-reconciler.js +6 -4
  31. package/.agents/scripts/check-context-budget.js +320 -0
  32. package/.agents/scripts/coverage-capture.js +17 -0
  33. package/.agents/scripts/diagnose-friction.js +4 -4
  34. package/.agents/scripts/epic-audit-prepare.js +30 -2
  35. package/.agents/scripts/epic-audit-recheck.js +46 -13
  36. package/.agents/scripts/epic-deliver-prepare.js +80 -8
  37. package/.agents/scripts/epic-plan-spec.js +4 -8
  38. package/.agents/scripts/generate-lens-checklists.js +180 -0
  39. package/.agents/scripts/lib/audit-suite/checklist-threading.js +300 -0
  40. package/.agents/scripts/lib/audit-suite/findings.js +27 -0
  41. package/.agents/scripts/lib/audit-suite/index.js +9 -0
  42. package/.agents/scripts/lib/audit-suite/lens-checklist.js +212 -0
  43. package/.agents/scripts/lib/audit-suite/selector.js +136 -5
  44. package/.agents/scripts/lib/checks/loop-health.js +340 -0
  45. package/.agents/scripts/lib/cli-args.js +8 -0
  46. package/.agents/scripts/lib/close-validation/gates.js +64 -24
  47. package/.agents/scripts/lib/config/ci.js +12 -1
  48. package/.agents/scripts/lib/config/runners.js +13 -5
  49. package/.agents/scripts/lib/config/temp-paths.js +24 -0
  50. package/.agents/scripts/lib/config-settings-schema-delivery.js +28 -8
  51. package/.agents/scripts/lib/doc-tiers.js +291 -0
  52. package/.agents/scripts/lib/epic-body-sections.js +5 -2
  53. package/.agents/scripts/lib/epic-merge-lock.js +83 -0
  54. package/.agents/scripts/lib/epic-plan-clarity.js +3 -1
  55. package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +47 -15
  56. package/.agents/scripts/lib/feedback-loop/graduator-core.js +395 -86
  57. package/.agents/scripts/lib/feedback-loop/memory-freshness.js +299 -72
  58. package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +438 -0
  59. package/.agents/scripts/lib/gates/friction.js +15 -5
  60. package/.agents/scripts/lib/npm-scripts.js +55 -0
  61. package/.agents/scripts/lib/observability/perf-aggregator.js +30 -104
  62. package/.agents/scripts/lib/observability/perf-report-readers.js +1 -1
  63. package/.agents/scripts/lib/observability/signal-validator.js +204 -0
  64. package/.agents/scripts/lib/observability/signals-writer.js +157 -54
  65. package/.agents/scripts/lib/observability/tool-trace-hook.js +42 -4
  66. package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +1 -1
  67. package/.agents/scripts/lib/orchestration/code-review.js +74 -4
  68. package/.agents/scripts/lib/orchestration/consolidation-precondition.js +213 -0
  69. package/.agents/scripts/lib/orchestration/doc-reader.js +4 -96
  70. package/.agents/scripts/lib/orchestration/docs-digest.js +34 -0
  71. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/authoring-context.js +56 -19
  72. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +22 -0
  73. package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +193 -0
  74. package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +6 -0
  75. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +248 -13
  76. package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +109 -12
  77. package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +47 -61
  78. package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +46 -4
  79. package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +144 -0
  80. package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +258 -14
  81. package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +6 -0
  82. package/.agents/scripts/lib/orchestration/merge-block-class.js +246 -0
  83. package/.agents/scripts/lib/orchestration/plan-review-routing.js +1 -1
  84. package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -3
  85. package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +63 -34
  86. package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +167 -52
  87. package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +49 -2
  88. package/.agents/scripts/lib/orchestration/retro-proposals.js +12 -55
  89. package/.agents/scripts/lib/orchestration/retro-runner.js +9 -0
  90. package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +5 -1
  91. package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +8 -0
  92. package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +419 -0
  93. package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +35 -2
  94. package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +353 -69
  95. package/.agents/scripts/lib/orchestration/single-story-close/runner.js +66 -4
  96. package/.agents/scripts/lib/orchestration/spec-section-validator.js +60 -9
  97. package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +7 -5
  98. package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +24 -2
  99. package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +167 -8
  100. package/.agents/scripts/lib/orchestration/story-close/pre-merge-validation.js +8 -1
  101. package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +163 -0
  102. package/.agents/scripts/lib/orchestration/ticketing/reads.js +20 -9
  103. package/.agents/scripts/lib/planning-corpus.js +306 -0
  104. package/.agents/scripts/lib/signals/detectors/common.js +10 -10
  105. package/.agents/scripts/lib/signals/detectors/index.js +4 -4
  106. package/.agents/scripts/lib/signals/detectors/retry.js +19 -18
  107. package/.agents/scripts/lib/signals/detectors/rework.js +1 -1
  108. package/.agents/scripts/lib/signals/schema.js +56 -81
  109. package/.agents/scripts/lib/signals/span-tree.js +6 -5
  110. package/.agents/scripts/lib/story-plan.js +3 -0
  111. package/.agents/scripts/lib/wave-runner/tick.js +10 -2
  112. package/.agents/scripts/lifecycle-emit.js +39 -8
  113. package/.agents/scripts/providers/github/issues.js +12 -1
  114. package/.agents/scripts/resolve-doc-tiers.js +83 -0
  115. package/.agents/scripts/retro-run.js +51 -0
  116. package/.agents/scripts/signals-view.js +1 -1
  117. package/.agents/scripts/single-story-close.js +20 -1
  118. package/.agents/scripts/standalone-feedback-rollup.js +188 -0
  119. package/.agents/scripts/story-close.js +48 -0
  120. package/.agents/scripts/story-plan.js +51 -12
  121. package/.agents/scripts/validate-docs-freshness.js +69 -15
  122. package/.agents/skills/core/documentation-and-adrs/SKILL.md +58 -0
  123. package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +5 -3
  124. package/.agents/skills/core/epic-plan-spec-author/SKILL.md +20 -7
  125. package/.agents/skills/core/scope-triage/SKILL.md +61 -0
  126. package/.agents/skills/skills.index.json +3 -3
  127. package/.agents/workflows/audit-documentation.md +82 -2
  128. package/.agents/workflows/helpers/code-review.md +116 -43
  129. package/.agents/workflows/helpers/deliver-epic.md +123 -54
  130. package/.agents/workflows/helpers/deliver-stories.md +26 -0
  131. package/.agents/workflows/helpers/epic-audit.md +116 -366
  132. package/.agents/workflows/helpers/epic-deliver-story.md +14 -0
  133. package/.agents/workflows/helpers/epic-plan-decompose.md +18 -200
  134. package/.agents/workflows/helpers/epic-plan-spec.md +18 -180
  135. package/.agents/workflows/helpers/plan-epic.md +141 -105
  136. package/.agents/workflows/helpers/plan-story.md +32 -0
  137. package/.agents/workflows/helpers/single-story-deliver.md +43 -0
  138. package/.agents/workflows/loops/nightly-audit.md +9 -7
  139. package/docs/CHANGELOG.md +29 -0
  140. package/lib/cli/doctor.js +44 -0
  141. package/package.json +4 -3
  142. package/.agents/scripts/epic-plan-spec-validate.js +0 -111
  143. package/.agents/scripts/lib/feedback-loop/code-review-graduator.js +0 -224
  144. package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +0 -58
  145. package/.agents/scripts/lib/signals/detectors/hotspot.js +0 -292
@@ -34,6 +34,7 @@ allowed_tools:
34
34
 
35
35
  - Run only during `/plan` Phase 7, after `epic-plan-spec.js --emit-context` has written `temp/epic-<Epic_ID>/planner-context.json`; fail loudly if the file is missing rather than fabricating context.
36
36
  - Write exactly three artifacts and only inside `temp/epic-<Epic_ID>/`: `techspec.md`, `risk-verdict.json`, `acceptance-spec.md`. All three MUST exist on disk before returning.
37
+ - **Re-emit rule (amend, don't regenerate — Story #4431).** On a re-emit — the Phase 7 persist call rejecting an artifact (e.g. a missing `## Delivery Slicing` heading, a schema-invalid risk verdict) — apply **targeted edits** to the existing `temp/epic-<Epic_ID>/` artifact that fix only what the rejection named; do NOT rewrite an artifact wholesale from a blank draft. `helpers/plan-epic.md` bounds this to **one refinement pass** per invocation (the same shape as the Epic Clarity Gate's own "one refinement pass per invocation" contract) — do not loop.
37
38
  - Start each markdown artifact at the correct `##` heading (Tech Spec → `## Delivery Slicing`, Acceptance Spec → `## Acceptance Table` — never the Epic's own `## Acceptance Criteria` heading, which stays the ideation bullets) — never emit a top-level `#` heading. `risk-verdict.json` is raw JSON conforming to `.agents/schemas/risk-verdict.schema.json`.
38
39
  - The Tech Spec MUST open with `## Delivery Slicing` and MUST NOT restate the Epic's Context, Goal, or Scope — your output lands as sections of the same Epic body, which travels into every downstream story agent's prompt, so any restatement is duplication and a drift risk. A `## Technical Overview` section is optional and, when present, is a 2–3 sentence orientation of the *technical approach* only (which subsystems are touched and reused), never a re-narration of the problem statement, goals, or scope.
39
40
  - Judge risk from what the change *does* (the Epic body / Tech Spec you just wrote), never from keyword presence — "out of scope: billing" is not a billing change; "rotate the credential vault" is high-risk even without a security keyword.
@@ -75,15 +76,24 @@ reads:
75
76
  Fields:
76
77
  - `epic.id`, `epic.title`, `epic.body` (or `epic.bodySummary` when the
77
78
  planning-context budget downgrades the body to a summary)
78
- - `docsContext.items[]` — bounded project docs scraped from the configured
79
- `docsRoot` (start with these for "how does the codebase do X today?"
80
- context; the validator already capped their size)
79
+ - `docsContext` — digest-first (Story #4433, hard cutover of the § 3.1
80
+ planning read contract): `{ mode: 'digest', digestPath }` pointing at
81
+ the per-Epic docs digest (`<tempRoot>/epic-<Epic_ID>/docs-digest.md` —
82
+ the same file the `/deliver` story sub-agents already consume, Story
83
+ #4338 / #4324), or `null` when `project.docsContextFiles` is unset. Read
84
+ the digest at `digestPath` for "how does the codebase do X today?"
85
+ orientation (path, byte size, heading outline with line numbers, first
86
+ paragraph per `##` section), then pull the full file on demand with your
87
+ own Read tool — jump straight to the line the digest names — only when a
88
+ section bears on the spec. There is no full-content `items[]` field;
89
+ embedding whole/summarized doc bodies in this envelope was retired in
90
+ the same cutover that made the `/deliver` children digest-first.
81
91
  - `codebaseSnapshot` — Story #2634 structural view of the consumer repo
82
92
  (file tree, `package.json` exports + scripts, recently-touched
83
93
  directories, detected test runner + BDD feature roots, and — at the
84
94
  `medium` tier — per-file export signatures). Prefer module / file
85
95
  names that appear in this snapshot over names that appear only in
86
- `docsContext.items[]`; the docs may be stale relative to the actual
96
+ the docs digest; the docs may be stale relative to the actual
87
97
  source tree. When the spec needs to cite a file that is **not** in
88
98
  `codebaseSnapshot.files`, surface that as a `<!-- DRIFT -->` callout
89
99
  in the Tech Spec body naming the cited path, so the freshness gate
@@ -151,13 +161,16 @@ or (for the verdict) schema-invalid.
151
161
 
152
162
  Read `temp/epic-<Epic_ID>/planner-context.json` with the `Read` tool. Pull
153
163
  the Epic title, body (or body summary, including the Epic's `## User Stories`
154
- section), the `docsContext` items, and (for reference) the two system prompts.
164
+ section), and the `docsContext` digest pointer (`digestPath`, or `null`).
165
+ When non-null, read the digest file at `digestPath` next — that outline,
166
+ not the planner-context envelope, is where the actual doc orientation
167
+ lives; pull a full doc on demand only when a section looks relevant.
155
168
 
156
169
  ### Step 2 — Author the Tech Spec (Engineering Architect persona)
157
170
 
158
171
  Apply the Tech Spec system prompt below to the Epic body (Context / Goal /
159
- Scope / User Stories), the
160
- `docsContext` items, and the `codebaseSnapshot` envelope (so the spec is
172
+ Scope / User Stories), the docs digest (plus any full file pulled on
173
+ demand), and the `codebaseSnapshot` envelope (so the spec is
161
174
  grounded in the actual codebase, not hallucinated patterns). Cite module
162
175
  and file names from `codebaseSnapshot.files` / `codebaseSnapshot.signatures`
163
176
  before reaching for names that appear only in the documentation. Write to
@@ -86,6 +86,67 @@ or a small Epic, and neither call is clearly right. **Present the choice rather
86
86
  than deciding for the operator.** Do not force a verdict to avoid the third
87
87
  option; a borderline scope surfaced as borderline is the correct output.
88
88
 
89
+ ## Change-Request Triage Rubric
90
+
91
+ A **change request** — "fix this", "tweak that", "extend the existing X" —
92
+ is the common case this rubric routes cheaply: a delta against a surface the
93
+ project already shipped, not a from-scratch capability. Route it to `story`
94
+ by default when all three delta signals hold; treat any one signal's absence
95
+ as a prompt to re-check, not an automatic `epic` bump.
96
+
97
+ ### Delta signals
98
+
99
+ - **Delta to an already-delivered surface.** The request references a
100
+ concrete existing capability (a module, workflow, script, or shipped
101
+ feature) rather than proposing a new one. "Fix the flaky retry in
102
+ `evidence-gate.js`" is a delta; "add a retry framework" is not.
103
+ - **Existing corpus covers the touched area.** The project's docs digest
104
+ and/or an already-closed or in-flight Epic's Tech Spec section already
105
+ describe the surface being changed — the standalone-Story path can draft
106
+ against that inherited context (`corpusContext` in the `/plan --idea`
107
+ envelope) instead of re-deriving architecture from a blank slate. When no
108
+ corpus hit exists for the touched area, that is a signal the request may
109
+ be reaching into genuinely new territory — re-check the `epic` signals
110
+ below before defaulting to `story`.
111
+ - **Footprint fits Story sizing.** The plausible file footprint and
112
+ acceptance-criteria count still fit the Story width in
113
+ `DEFAULT_TASK_SIZING` (per the `story` verdict signals above) — a change
114
+ request that fans out across independent subsystems is sized like an Epic
115
+ regardless of how small the originating request sounded.
116
+
117
+ ### Story-verdict rationale template
118
+
119
+ Use this template to record the verdict — it names which delta signal
120
+ carried the call, so a reviewer can sanity-check the routing decision without
121
+ re-deriving it:
122
+
123
+ ```text
124
+ Verdict: story
125
+ Delta: <the existing surface this change targets>
126
+ Corpus hit: <docs digest section / Epic # and Tech Spec excerpt that covers
127
+ this area, or "none — re-checked epic signals, still story-sized">
128
+ Footprint: <rough file/AC count vs DEFAULT_TASK_SIZING>
129
+ ```
130
+
131
+ ### Worked example
132
+
133
+ > Request: "The `/plan` standalone-Story path always drafts from a blank
134
+ > slate even when a change request is a small delta against something we
135
+ > already shipped — thread the existing docs digest and matching Epic
136
+ > Tech Spec sections into the draft context."
137
+ >
138
+ > ```text
139
+ > Verdict: story
140
+ > Delta: story-plan.js's --emit-context envelope and the plan-story.md
141
+ > Phase 2 drafting instructions — both already exist and ship today.
142
+ > Corpus hit: Epic #4429's own Tech Spec section (this rubric's parent
143
+ > Epic) already describes the docs-digest reuse pattern from
144
+ > orchestration/docs-digest.js.
145
+ > Footprint: one new lib module (planning-corpus.js), one envelope field,
146
+ > one helper-doc instruction — comfortably inside DEFAULT_TASK_SIZING's
147
+ > softFiles/softAcceptanceCount band.
148
+ > ```
149
+
89
150
  ## Handoff & no-re-triage rule
90
151
 
91
152
  A workflow entered via a scope-triage **handoff** MUST NOT re-triage. A handoff
@@ -1,5 +1,5 @@
1
1
  {
2
- "generatedAt": "2026-07-08T12:24:41.101Z",
2
+ "generatedAt": "2026-07-11T11:32:48.235Z",
3
3
  "generator": "generate-skills-index.js@1",
4
4
  "skills": [
5
5
  {
@@ -138,7 +138,7 @@
138
138
  "category": "core",
139
139
  "path": ".agents/skills/core/epic-plan-decompose-author/SKILL.md",
140
140
  "description": "Author the Story ticket JSON for an Epic from the decomposer authoring context emitted by `epic-plan-decompose.js --emit-context`. Use during Phase 8 of `/plan` when the host LLM needs to write the ticket array before `epic-plan-decompose.js` validates and persists it.",
141
- "policyCapsuleBullets": 14,
141
+ "policyCapsuleBullets": 15,
142
142
  "allowedTools": ["Read", "Write", "Bash"],
143
143
  "vendor": null
144
144
  },
@@ -158,7 +158,7 @@
158
158
  "category": "core",
159
159
  "path": ".agents/skills/core/epic-plan-spec-author/SKILL.md",
160
160
  "description": "Author the Tech Spec, Acceptance Table markdown, and risk-verdict JSON for an Epic from the planner authoring context emitted by `epic-plan-spec.js --emit-context`. Use during Phase 7 of `/plan` when the host LLM needs to write the three artifacts before `epic-plan-spec.js` folds them into the Epic body's managed sections.",
161
- "policyCapsuleBullets": 13,
161
+ "policyCapsuleBullets": 14,
162
162
  "allowedTools": ["Read", "Write", "Bash"],
163
163
  "vendor": null
164
164
  },
@@ -135,6 +135,7 @@ node .agents/scripts/check-lifecycle-doc-drift.js
135
135
  node .agents/scripts/generate-config-docs.js --check
136
136
  node .agents/scripts/generate-lifecycle-docs.js --check
137
137
  node .agents/scripts/generate-workflows-doc.js --check
138
+ node .agents/scripts/resolve-doc-tiers.js --json
138
139
  ```
139
140
 
140
141
  Fold the results in as findings:
@@ -148,6 +149,13 @@ Fold the results in as findings:
148
149
  remediation is "rerun `npm run docs:gen` / `npm run sync:commands` and
149
150
  commit the regenerated output".
150
151
 
152
+ The **read-tier map** — `resolve-doc-tiers.js --json` — is not itself a
153
+ finding. It emits `{ tiers: { alwaysLoaded, mandatoryRead, digestVisible,
154
+ onDemand } }`, each a `[{ path, bytes }]` list classifying every doc by how
155
+ often it is loaded into agent context. Hold that map for the Context Economy
156
+ severity-weighting rule (Step 2.5) — it decides how much a Context-Economy
157
+ finding's location amplifies its cost.
158
+
151
159
  This lens orchestrates the existing checkers only; it does not add new
152
160
  deterministic checker scripts.
153
161
 
@@ -182,6 +190,56 @@ works (wrong command, deleted script, contract mismatch); **Medium** =
182
190
  materially outdated description or missing coverage of a major surface;
183
191
  **Low** = cosmetic drift, stale examples, tone/format inconsistencies.
184
192
 
193
+ ## Step 2.5: Context Economy
194
+
195
+ Steps 1–2 verify the docs are **accurate**. This step verifies they are
196
+ **economical** — that a doc still earns the context every reader (human or
197
+ agent) pays to load it. A doc can be entirely accurate and still cost far
198
+ more than it returns: it accretes finished-work history, states the same fact
199
+ two incompatible ways, or claims an authority the code has outgrown. Flag
200
+ these under the three Context Economy categories below. Each carries a
201
+ recognition heuristic — a shape you can spot from the prose itself.
202
+
203
+ - **History Bloat:** the doc carries verbatim finished-work history that
204
+ crowds out its live guidance — fully-checked (all-`[x]`) checklists,
205
+ step-by-step phase / rollout logs, and past-tense "shipped" / "completed"
206
+ narratives no reader acts on anymore. Recognition: a section whose every
207
+ checkbox is ticked, or a changelog / decision run whose historical rows
208
+ dwarf the live ones. **Remediation:** apply the documentation-and-adrs
209
+ [Pruning & Archiving](../skills/core/documentation-and-adrs/SKILL.md#pruning--archiving)
210
+ convention — lift any still-live gotcha into the live doc **first**, then
211
+ **archive, don't delete**: relocate the verbatim history to a dated
212
+ `docs/archive/<name>-<YYYY-MM>.md`, collapse each completed checklist to a
213
+ one-line outcome, and leave a one-line pointer behind. Never prune ADRs by
214
+ archiving — supersede them in place.
215
+ - **Contradiction:** the doc states the same fact two incompatible ways, so a
216
+ reader cannot tell which is current. Recognition: a footnote- or
217
+ parenthetical-corrected table cell (a value carrying an inline `(now X)` /
218
+ `~~old~~` correction), or two prose statements that assert different values
219
+ for the same command, path, count, or contract. **Remediation:** collapse
220
+ to the single verified-current statement and delete the stale twin.
221
+ - **Authority Drift:** the doc is crowned the source of truth for a surface
222
+ the verified code has since outgrown — the prose still presents itself as
223
+ canonical, but the implementation is now the real authority. Recognition: a
224
+ doc that declares itself SSOT / "canonical" / "single source of truth" for
225
+ a contract whose current shape you had to read the code to confirm, because
226
+ the doc no longer matches it. **Remediation:** either re-sync the doc to the
227
+ code and keep the SSOT claim, or demote the claim and point at the code as
228
+ the authority.
229
+
230
+ ### Read-tier severity weighting
231
+
232
+ A Context-Economy finding's cost scales with how often the doc is actually
233
+ read. Step 1 ran `resolve-doc-tiers.js --json`, which classifies every
234
+ target-set doc into a read tier (`alwaysLoaded`, `mandatoryRead`,
235
+ `digestVisible`, `onDemand`). **A finding whose doc falls in the
236
+ `alwaysLoaded` or `mandatoryRead` tier escalates one severity band**
237
+ (Low→Medium, Medium→High): bloat, contradiction, or drift in a doc every task
238
+ loads costs far more than the same defect in an on-demand reference. Apply the
239
+ escalation **after** assigning the base severity from the Step 2 guidance, and
240
+ name the doc's tier in the finding's Current State so the escalation is
241
+ auditable.
242
+
185
243
  ## Step 3: Output Requirements
186
244
 
187
245
  Generate and save a highly structured Markdown audit report to
@@ -208,8 +266,8 @@ match the code), the deterministic-gate verdicts, and primary drift themes.]
208
266
 
209
267
  ### [Short Title of the Issue]
210
268
 
211
- - **Category:** [Broken Instruction | Stale Description | Missing Coverage | Generator Drift | Link Integrity]
212
- - **Impact:** [High | Medium | Low]
269
+ - **Category:** [Broken Instruction | Stale Description | Missing Coverage | Generator Drift | Link Integrity | History Bloat | Contradiction | Authority Drift]
270
+ - **Impact:** [High | Medium | Low] — for a Context Economy finding, this is the base severity **after** any read-tier escalation (Step 2.5); state the doc's tier in Current State.
213
271
  - **Current State:** [The doc, the exact claim, and what the code actually
214
272
  does — cite file paths and lines on both sides]
215
273
  - **Recommendation & Rationale:** [The specific doc edit (or generator
@@ -218,6 +276,28 @@ match the code), the deterministic-gate verdicts, and primary drift themes.]
218
276
  `[A copy-pasteable, highly specific prompt to execute this doc fix independently]`
219
277
  ```
220
278
 
279
+ ## Periodic full-scope sweep
280
+
281
+ Context Economy findings accrete slowly — a doc that is lean today grows a
282
+ bloated tail over many Epics, and no single change-set-scoped `/deliver`
283
+ Phase 4 run sees the whole picture. Run this lens **full-scope** on a
284
+ recurring cadence so the drift is caught before it compounds:
285
+
286
+ - **Cron loop** — [`loops:nightly-audit`](loops/nightly-audit.md)
287
+ runs the audit sweep unattended each night; the host (`/schedule` or a
288
+ cron-driven `/loop`) owns the cadence. Point it at this lens full-scope
289
+ (no `--paths`, no change-set filter — the `{{changedFiles}}` block renders
290
+ the literal token, so the whole target-set union is audited).
291
+ - **Scheduled invocation** — `/schedule` running `/audit-documentation`
292
+ full-scope on a daily/weekly cron is the equivalent one-shot form when a
293
+ standing loop is not wired up.
294
+
295
+ Route the resulting `audit-documentation-results.md` through
296
+ [`/audit-to-stories`](audit-to-stories.md), which groups the findings,
297
+ deduplicates them against existing Issues by fingerprint, and opens
298
+ remediation Stories (or chains into `/plan --idea`) so the Context-Economy
299
+ findings land as actionable, tracked work rather than a report nobody reads.
300
+
221
301
  ## Constraint
222
302
 
223
303
  This workflow is **read-only** with respect to the repository: run the
@@ -64,7 +64,7 @@ envelope via
64
64
 
65
65
  It is an **input-only** signal: it changes *how thorough* the review is, never
66
66
  the findings envelope (`{ status, severity, posted, report, halted,
67
- blockerReason }`) nor the posted `code-review` structured-comment body. An
67
+ blockerReason }`) nor the posted `verification-results` structured-comment body. An
68
68
  absent or malformed `depth` is treated as `standard`, so an Epic that skipped
69
69
  `/plan` still gets a passing review with no new failure mode.
70
70
 
@@ -117,13 +117,82 @@ The pipeline will:
117
117
  - Run a focused lint check on the change set.
118
118
  - Post a structured summary report to the `[TICKET_ID]` issue.
119
119
 
120
+ ### Step 1a — Story-scope local-lens pass (`scope: story` only, Epic #4405)
121
+
122
+ When `scope === 'story'`, the shared review spine
123
+ [`runStoryReviewCore`](../../scripts/lib/orchestration/story-close/phases/code-review.js)
124
+ runs a **shift-left local-lens pass** in the same close subprocess, *before*
125
+ returning the review envelope. It:
126
+
127
+ 1. Enumerates the actual Story diff (`baseRef...headRef` via
128
+ `git diff --name-only`).
129
+ 2. Selects the **local-tier** lenses that own a concern decidable from a single
130
+ Story's diff — `resolveLensTier(lens) === 'local'` **plus** the pure
131
+ `matchesAnyFilePattern` matcher against the diff (the audit-suite SDK's
132
+ [`selectLocalLenses`](../../scripts/lib/audit-suite/selector.js)). This is
133
+ deliberately **not** `selectAudits`: `selectAudits` unions in keyword and
134
+ gate matches and has no per-tier gate, so it would widen the roster past the
135
+ footprint-matched local set this tier owns.
136
+ 3. Materializes the matched roster at **`light`** depth
137
+ (`STORY_SCOPE_LENS_DEPTH`) via `runAuditSuite`, surfacing the outcome on the
138
+ review envelope's `localLensReview` field.
139
+
140
+ A diff that matches no local lens adds **no** lens work (the roster is empty and
141
+ `runAuditSuite` is never invoked). The pass is advisory and best-effort: a git
142
+ or materialization failure degrades to a skipped envelope and never blocks the
143
+ close.
144
+
145
+ Both close entry points —
146
+ [`runStoryCodeReview`](../../scripts/lib/orchestration/story-close/phases/code-review.js)
147
+ (Epic-attached) and
148
+ [`runStoryScopeReview`](../../scripts/lib/orchestration/single-story-close/phases/code-review.js)
149
+ (standalone) — reach this pass through the single `runStoryReviewCore` spine, so
150
+ standalone Stories gain local-lens coverage for the first time. Because the pass
151
+ lives inside the close subprocess (invoked after the delivering child exits), it
152
+ honors the maker-blind invariant above: a maker never runs its own local-lens
153
+ review. This step does not apply to `scope: epic`, whose lens roster is the
154
+ cumulative + global + risk-routed set resolved at Epic close (Step 1b).
155
+
156
+ ### Step 1b — Epic-close lens roster (`scope: epic` only, Epic #4405)
157
+
158
+ When `scope === 'epic'`, the cumulative Epic diff is walked **once** at close:
159
+ the Epic-close lens roster is executed as **dimensions of this same review
160
+ pass**, not as a separate Phase 4 walk (Story #4412 folded the standalone
161
+ epic-audit lens walk into this pass). Resolve and walk the roster inline:
162
+
163
+ 1. Resolve the roster via [`helpers/epic-audit.md`](epic-audit.md) Step 1 —
164
+ run `epic-audit-prepare.js --gate gate3` and take its **`epicCloseLenses`**
165
+ field: the slim roster of cumulative + global + risk-routed lenses, with
166
+ every local-tier change-set lens excluded (routed off `resolveLensTier` in
167
+ [`selectEpicCloseLenses`](../../scripts/lib/orchestration/code-review.js)).
168
+ Local-tier concerns are already verified shift-left (write-time checklists +
169
+ the Story-scope local-lens pass), so they are **not** re-run here.
170
+ 2. Materialize each rostered lens via
171
+ [`runAuditSuite`](../../scripts/lib/audit-suite/index.js) at the envelope's
172
+ `depth`, applying the `{{changedFiles}}` substitution, and walk each lens's
173
+ `.agents/workflows/audit-<lens>.md` procedure over the cumulative
174
+ `main..epic/<epicId>` diff. Global lenses (`globalLenses`, e.g.
175
+ `audit-navigability`) run against the WHOLE route tree, exempt from the
176
+ change-set narrowing.
177
+ 3. Fold the lens findings into this pass's severity aggregate **alongside** the
178
+ Step 2 review pillars — one walk of the cumulative diff, one aggregate, one
179
+ `verification-results` comment (Step 4). An empty `epicCloseLenses` roster
180
+ (docs-only, or every selected lens already covered shift-left, and no
181
+ risk-routed lens) adds no lens dimension — the pillars still run.
182
+
183
+ This step does not apply to `scope: story` (its roster is the local-tier set of
184
+ Step 1a) and is skipped when `epic-audit-prepare.js` returns `degraded: true`
185
+ (propagate the reason and STOP, per `epic-audit.md`).
186
+
120
187
  ## Step 2 — Review Pillars
121
188
 
122
189
  For each changed file, execute a strict review against four pillars. The
123
190
  second pillar (**Integration Review**) deliberately defers the security /
124
- performance / quality / coverage sweeps to the change-set-scoped audits
125
- that already ran upstream — re-walking them here is duplication, not
126
- defense-in-depth.
191
+ performance / quality / coverage sweeps to the change-set-scoped lenses — at
192
+ `scope: story` those ran shift-left in the Story-scope local-lens pass (Step
193
+ 1a); at `scope: epic` they run inline in this same pass as the Epic-close lens
194
+ roster (Step 1b). Re-walking those sweeps a second time in this pillar is
195
+ duplication, not defense-in-depth.
127
196
 
128
197
  **Apply the `depth` lever** (see **Review depth** above) to how hard you walk
129
198
  these pillars: at `light`, focus on Pillar 1 and reduce Pillars 2–3 to a quick
@@ -151,11 +220,11 @@ The integration view depends on `scope`. The diff under review is always
151
220
  against differs:
152
221
 
153
222
  - **`scope: story`** — the diff is `epic/<epicId>..story-<storyId>` (i.e.
154
- one Story's contribution to the Epic). There is typically no
155
- `audit-results` comment on the Story; Phase 4 epic-level audits have not
156
- yet run for this change set. The integration view here focuses on
157
- cross-Task ripple within the Story and contract drift against the Epic
158
- branch tip. Look for:
223
+ one Story's contribution to the Epic). The Story-scope local-lens pass
224
+ (Step 1a) has already covered the local-tier concerns; the Epic-close lens
225
+ roster has not run for this change set (it runs once at Epic close). The
226
+ integration view here focuses on cross-Task ripple within the Story and
227
+ contract drift against the Epic branch tip. Look for:
159
228
  - Cross-Task contract drift inside the Story (one Task's API change vs.
160
229
  another Task's caller in the same branch).
161
230
  - Shared-module ripple effects from this Story onto siblings already
@@ -163,30 +232,31 @@ against differs:
163
232
  - Spec deviations that the per-Task commits papered over.
164
233
 
165
234
  - **`scope: epic`** — the diff is `main..epic/<epicId>` (the cumulative
166
- Epic change set). Read the **`audit-results` structured comment** posted
167
- on the Epic ticket by the [`epic-audit.md`](epic-audit.md) helper in
168
- Phase 4. That comment is the authoritative source of security, privacy,
169
- performance, code-quality, and test-coverage findings for this change
170
- set — they were produced by the change-set-aware lens selector and
171
- per-lens audit workflows under `.agents/workflows/audit-*.md`. Do **not**
172
- re-derive those findings inline here.
235
+ Epic change set). The Epic-close lens roster (`epicCloseLenses`) is walked
236
+ **inline as part of this pass** (Step 1b) — the cumulative diff is read once,
237
+ and the security, privacy, performance, code-quality, and test-coverage
238
+ findings the rostered lenses produce feed this pass's aggregate directly.
239
+ There is no separate `audit-results` comment to read (Story #4412 retired it);
240
+ the lens findings and the pillar findings share the single
241
+ `verification-results` comment this pass posts.
173
242
 
174
243
  The integration view at epic scope is what the per-lens audits cannot
175
244
  produce because each lens runs in isolation:
176
245
 
177
- - Cross-reference 🔴 / 🟠 audit findings against the spec deviations
246
+ - Cross-reference 🔴 / 🟠 lens findings against the spec deviations
178
247
  flagged in Pillar 1 — a finding that traces back to a deliberate
179
248
  Tech-Spec decision is different from one that traces back to an
180
249
  oversight.
181
250
  - Look for cross-cutting concerns no single lens owns: contract drift
182
251
  between Stories, shared-module ripple effects, boundary changes that
183
252
  thread security and performance implications together.
184
- - Note any audit finding that the operator's remediation flow should
253
+ - Note any lens finding that the operator's remediation flow should
185
254
  bundle (e.g. one refactor closes findings from multiple lenses).
186
255
 
187
- If the Epic has no `audit-results` comment (docs-only Epic, or Phase 4
188
- was skipped via `--skip-epic-audit`), record that explicitly in the
189
- findings report and proceed — there is nothing to integrate.
256
+ If the Epic-close roster is empty (docs-only Epic, every selected lens
257
+ already covered shift-left, or the pass was skipped via
258
+ `--skip-epic-audit` / `--skip-code-review`), record that explicitly in the
259
+ findings report and proceed — there is no lens dimension to integrate.
190
260
 
191
261
  ### Pillar 3: Documentation Integrity
192
262
 
@@ -261,9 +331,11 @@ prior baseline before merging.
261
331
 
262
332
  ## Step 4 — Produce Findings Report
263
333
 
264
- Findings are **persisted as a `code-review` structured comment on the
265
- `[TICKET_ID]` issue** by `runCodeReview`. The target ticket is the Story
266
- when `scope === 'story'` and the Epic when `scope === 'epic'`. The comment
334
+ Findings are **persisted as a `verification-results` structured comment on
335
+ the `[TICKET_ID]` issue** by `runCodeReview` (the unified findings contract of
336
+ Story #4411; at `scope: epic` this single comment also carries the Step 1b
337
+ Epic-close lens findings). The target ticket is the Story when
338
+ `scope === 'story'` and the Epic when `scope === 'epic'`. The comment
267
339
  is idempotent — re-runs replace the prior one — and its body includes
268
340
  severity-tier counts plus the full findings list so downstream workflows
269
341
  (notably the retro helper) can summarise blockers/high findings without
@@ -299,7 +371,8 @@ Findings that Step 4.5 remediated on `[HEAD_REF]` MUST be rendered under a
299
371
  dedicated **`## Fixed on-branch`** heading, **not** in the severity groups
300
372
  above. This is the contract seam that keeps remediated findings from
301
373
  spawning ghost follow-up issues: the
302
- [`code-review` graduator](../../scripts/lib/feedback-loop/code-review-graduator.js)
374
+ [audit-results graduator](../../scripts/lib/feedback-loop/audit-results-graduator.js)
375
+ (the sole canonical reader of the unified comment)
303
376
  skips every entry inside this section (both because a fixed entry is
304
377
  rendered with a **✅ prefix** — so it carries no leading severity emoji the
305
378
  parser would match — and because the parser has an explicit
@@ -322,8 +395,8 @@ their leading severity emoji so the graduator still files them.
322
395
 
323
396
  There is **no runtime auto-fix function** at this phase. The host LLM is
324
397
  the executor: it decides, per finding, between a focused fix on
325
- `[HEAD_REF]` and leaving the finding on the `code-review` structured
326
- comment for the operator.
398
+ `[HEAD_REF]` and leaving the finding on the `verification-results`
399
+ structured comment for the operator.
327
400
 
328
401
  ### Resolve the remediation threshold (Story #4399)
329
402
 
@@ -348,7 +421,7 @@ Cutovers — no back-compat flag; `high` is opt-in to the old routing.
348
421
  ### 🔴 / 🟠 findings — per-finding ceremony (unchanged)
349
422
 
350
423
  For each 🔴 / 🟠 finding from Step 4, decide between two paths and keep the
351
- `code-review` structured comment authoritative for anything not fixed
424
+ `verification-results` structured comment authoritative for anything not fixed
352
425
  in-place.
353
426
 
354
427
  1. **Apply a focused fix on `[HEAD_REF]`.** Permitted only when the
@@ -401,8 +474,8 @@ ceremony above:
401
474
  findings stay on the comment for Step 5.
402
475
 
403
476
  Record every remediated finding (🟠 or 🟡) in the **"Fixed on-branch"**
404
- section of the `code-review` comment (Step 4) so it does not graduate to a
405
- follow-up issue.
477
+ section of the `verification-results` comment (Step 4) so it does not graduate
478
+ to a follow-up issue.
406
479
 
407
480
  Do not invent a programmatic retry budget. The host LLM applies *at most
408
481
  one* focused-fix attempt per finding (or per batched finding) before
@@ -413,18 +486,18 @@ consumers) see exactly why each one was not auto-remediated.
413
486
  ## Step 4.6 — Cross-phase re-check trigger
414
487
 
415
488
  After the focused-fix routing in Step 4.5 completes, any host-LLM-applied
416
- fix commits have modified files on `[HEAD_REF]` that the Phase 4 audit
417
- lenses already walked. Some of those edits may overlap the `filePatterns`
418
- of one or more lenses (e.g. a fix landing in `**/auth/*.js` overlaps the
419
- `audit-security` lens). When that happens, the prior `audit-results`
420
- structured comment is **stale for the overlapping lenses only** — the
421
- non-overlapping findings remain authoritative and MUST NOT be
489
+ fix commits have modified files on `[HEAD_REF]` that the Epic-close lens
490
+ roster already walked (Step 1b). Some of those edits may overlap the
491
+ `filePatterns` of one or more lenses (e.g. a fix landing in `**/auth/*.js`
492
+ overlaps the `audit-security` lens). When that happens, the lens findings in
493
+ the `verification-results` comment are **stale for the overlapping lenses
494
+ only** — the non-overlapping findings remain authoritative and MUST NOT be
422
495
  re-derived.
423
496
 
424
497
  > **Scope note.** This cross-phase re-check applies only when
425
- > `scope === 'epic'`. Story-scope reviews run before Phase 4 epic audits
426
- > exist, so there is no `audit-results` comment to invalidate; skip this
427
- > step entirely for `scope === 'story'`.
498
+ > `scope === 'epic'`. Story-scope reviews carry no Epic-close lens roster,
499
+ > so there is nothing to invalidate; skip this step entirely for
500
+ > `scope === 'story'`.
428
501
 
429
502
  Invoke the re-check selector with the cumulative set of paths touched by
430
503
  the focused-fix commits:
@@ -445,11 +518,11 @@ no-op.
445
518
  When `selectedAudits` is non-empty:
446
519
 
447
520
  1. Re-invoke each listed lens prompt under
448
- [`../audit-*.md`](../) the same way Phase 4's `epic-audit.md` does —
521
+ [`../audit-*.md`](../) the same way the Step 1b Epic-close walk does —
449
522
  one lens at a time, against the current `[HEAD_REF]` tip.
450
523
  2. **Append** a `## Cross-phase re-check` section to the **existing**
451
- `audit-results` structured comment on the Epic ticket. Do **not** post
452
- a new comment; the comment is idempotent and downstream consumers
524
+ `verification-results` structured comment on the Epic ticket. Do **not**
525
+ post a new comment; the comment is idempotent and downstream consumers
453
526
  (the code-review trim, `/deliver` Pillar 2, the retro helper)
454
527
  read it once. The append carries the re-checked lens names, the new
455
528
  findings (if any), and the focused-fix commit SHAs that triggered the
@@ -459,7 +532,7 @@ When `selectedAudits` is non-empty:
459
532
  through Step 4.5's focused-fix routing. Findings that already
460
533
  received a focused-fix attempt in the first pass do not get a fresh
461
534
  attempt when the cross-phase re-check resurfaces an adjacent one —
462
- leave them on the `code-review` comment for the operator.
535
+ leave them on the `verification-results` comment for the operator.
463
536
 
464
537
  If `selectedAudits` is empty, skip silently and proceed to Step 5. The
465
538
  re-check trigger is **read-only signal** — it never mutates the Epic