mandrel 1.87.0 → 1.89.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.
- package/.agents/README.md +18 -13
- package/.agents/audit-checklists/architecture.md +24 -0
- package/.agents/audit-checklists/clean-code.md +24 -0
- package/.agents/audit-checklists/dependencies.md +14 -0
- package/.agents/audit-checklists/devops.md +17 -0
- package/.agents/audit-checklists/documentation.md +22 -0
- package/.agents/audit-checklists/lighthouse.md +15 -0
- package/.agents/audit-checklists/navigability.md +14 -0
- package/.agents/audit-checklists/performance.md +22 -0
- package/.agents/audit-checklists/privacy.md +21 -0
- package/.agents/audit-checklists/quality.md +18 -0
- package/.agents/audit-checklists/security.md +22 -0
- package/.agents/audit-checklists/seo.md +16 -0
- package/.agents/audit-checklists/sre.md +24 -0
- package/.agents/audit-checklists/ux-ui.md +21 -0
- package/.agents/docs/SDLC.md +63 -16
- package/.agents/docs/configuration.md +5 -3
- package/.agents/instructions.md +51 -21
- package/.agents/personas/architect.md +10 -7
- package/.agents/personas/engineer.md +4 -3
- package/.agents/personas/project-manager.md +5 -2
- package/.agents/personas/refactorer.md +5 -3
- package/.agents/rules/git-conventions.md +77 -0
- package/.agents/schemas/agentrc.schema.json +16 -4
- package/.agents/schemas/audit-rules.json +16 -2
- package/.agents/schemas/audit-rules.schema.json +7 -6
- package/.agents/schemas/lifecycle/merge.unlanded.schema.json +38 -0
- package/.agents/schemas/signal-event.schema.json +28 -13
- package/.agents/scripts/acceptance-spec-reconciler.js +6 -4
- package/.agents/scripts/check-context-budget.js +320 -0
- package/.agents/scripts/diagnose-friction.js +4 -4
- package/.agents/scripts/epic-audit-prepare.js +30 -2
- package/.agents/scripts/epic-audit-recheck.js +46 -13
- package/.agents/scripts/epic-deliver-prepare.js +80 -8
- package/.agents/scripts/epic-plan-spec.js +4 -8
- package/.agents/scripts/generate-lens-checklists.js +180 -0
- package/.agents/scripts/lib/audit-suite/checklist-threading.js +300 -0
- package/.agents/scripts/lib/audit-suite/findings.js +27 -0
- package/.agents/scripts/lib/audit-suite/index.js +9 -0
- package/.agents/scripts/lib/audit-suite/lens-checklist.js +212 -0
- package/.agents/scripts/lib/audit-suite/selector.js +136 -5
- package/.agents/scripts/lib/checks/loop-health.js +340 -0
- package/.agents/scripts/lib/cli-args.js +8 -0
- package/.agents/scripts/lib/config/explain.js +4 -0
- package/.agents/scripts/lib/config/runners.js +21 -2
- package/.agents/scripts/lib/config/temp-paths.js +24 -0
- package/.agents/scripts/lib/config-settings-schema-delivery.js +23 -3
- package/.agents/scripts/lib/config-settings-schema-quality.js +7 -0
- package/.agents/scripts/lib/doc-tiers.js +291 -0
- package/.agents/scripts/lib/epic-body-sections.js +5 -2
- package/.agents/scripts/lib/epic-merge-lock.js +83 -0
- package/.agents/scripts/lib/epic-plan-clarity.js +3 -1
- package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +66 -20
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +395 -86
- package/.agents/scripts/lib/feedback-loop/memory-freshness.js +299 -72
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +438 -0
- package/.agents/scripts/lib/gates/friction.js +15 -5
- package/.agents/scripts/lib/observability/perf-aggregator.js +30 -104
- package/.agents/scripts/lib/observability/perf-report-readers.js +1 -1
- package/.agents/scripts/lib/observability/signal-validator.js +204 -0
- package/.agents/scripts/lib/observability/signals-writer.js +157 -54
- package/.agents/scripts/lib/observability/tool-trace-hook.js +42 -4
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +1 -1
- package/.agents/scripts/lib/orchestration/code-review.js +74 -4
- package/.agents/scripts/lib/orchestration/consolidation-precondition.js +213 -0
- package/.agents/scripts/lib/orchestration/doc-reader.js +4 -96
- package/.agents/scripts/lib/orchestration/docs-digest.js +34 -0
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/authoring-context.js +56 -19
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/run-spec-phase.js +22 -0
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +188 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +6 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-armer.js +69 -8
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/automerge-predicate.js +11 -2
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/finalizer.js +47 -61
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/index.js +39 -3
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/label-transitioner.js +144 -0
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/merge-watcher.js +258 -14
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/notify-dispatcher.js +6 -0
- package/.agents/scripts/lib/orchestration/merge-block-class.js +218 -0
- package/.agents/scripts/lib/orchestration/plan-review-routing.js +1 -1
- package/.agents/scripts/lib/orchestration/post-merge/phases/worktree-reap.js +3 -3
- package/.agents/scripts/lib/orchestration/retro/phases/compose-body.js +63 -34
- package/.agents/scripts/lib/orchestration/retro/phases/gather-signals.js +167 -52
- package/.agents/scripts/lib/orchestration/retro/phases/post-and-mirror.js +49 -2
- package/.agents/scripts/lib/orchestration/retro-proposals.js +12 -55
- package/.agents/scripts/lib/orchestration/retro-runner.js +9 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +8 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +419 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +35 -2
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +353 -69
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +66 -4
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +60 -9
- package/.agents/scripts/lib/orchestration/story-close/auto-refresh-runner.js +7 -5
- package/.agents/scripts/lib/orchestration/story-close/merge-runner.js +24 -2
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +167 -8
- package/.agents/scripts/lib/orchestration/story-close/shared-checkout-guard.js +163 -0
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +20 -9
- package/.agents/scripts/lib/planning-corpus.js +306 -0
- package/.agents/scripts/lib/signals/detectors/common.js +10 -10
- package/.agents/scripts/lib/signals/detectors/index.js +4 -4
- package/.agents/scripts/lib/signals/detectors/retry.js +19 -18
- package/.agents/scripts/lib/signals/detectors/rework.js +1 -1
- package/.agents/scripts/lib/signals/schema.js +56 -81
- package/.agents/scripts/lib/signals/span-tree.js +6 -5
- package/.agents/scripts/lib/story-plan.js +3 -0
- package/.agents/scripts/lib/wave-runner/tick.js +10 -2
- package/.agents/scripts/lifecycle-emit.js +39 -8
- package/.agents/scripts/providers/github/issues.js +12 -1
- package/.agents/scripts/resolve-doc-tiers.js +83 -0
- package/.agents/scripts/retro-run.js +51 -0
- package/.agents/scripts/signals-view.js +1 -1
- package/.agents/scripts/single-story-close.js +20 -1
- package/.agents/scripts/standalone-feedback-rollup.js +188 -0
- package/.agents/scripts/story-close.js +48 -0
- package/.agents/scripts/story-plan.js +51 -12
- package/.agents/scripts/validate-docs-freshness.js +69 -15
- package/.agents/skills/core/documentation-and-adrs/SKILL.md +58 -0
- package/.agents/skills/core/epic-plan-decompose-author/SKILL.md +5 -3
- package/.agents/skills/core/epic-plan-spec-author/SKILL.md +20 -7
- package/.agents/skills/core/scope-triage/SKILL.md +61 -0
- package/.agents/skills/skills.index.json +3 -3
- package/.agents/workflows/audit-documentation.md +82 -2
- package/.agents/workflows/helpers/code-review.md +193 -44
- package/.agents/workflows/helpers/deliver-epic.md +128 -39
- package/.agents/workflows/helpers/deliver-stories.md +26 -0
- package/.agents/workflows/helpers/epic-audit.md +116 -283
- package/.agents/workflows/helpers/epic-deliver-story.md +14 -0
- package/.agents/workflows/helpers/epic-plan-decompose.md +18 -200
- package/.agents/workflows/helpers/epic-plan-spec.md +18 -180
- package/.agents/workflows/helpers/plan-epic.md +141 -105
- package/.agents/workflows/helpers/plan-story.md +32 -0
- package/.agents/workflows/helpers/single-story-deliver.md +43 -0
- package/.agents/workflows/loops/nightly-audit.md +9 -7
- package/docs/CHANGELOG.md +29 -0
- package/lib/cli/doctor.js +44 -0
- package/package.json +4 -3
- package/.agents/scripts/epic-plan-spec-validate.js +0 -111
- package/.agents/scripts/lib/feedback-loop/code-review-graduator.js +0 -207
- package/.agents/scripts/lib/orchestration/epic-plan-spec/phases/prompts.js +0 -58
- package/.agents/scripts/lib/signals/detectors/hotspot.js +0 -292
|
@@ -1,44 +1,53 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: >-
|
|
3
|
-
|
|
4
|
-
envelope,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
Resolve the slim Epic-close (gate3) lens roster for /deliver. Consumes the
|
|
4
|
+
epic-audit-prepare envelope, restricts it to the cumulative + global +
|
|
5
|
+
risk-routed lenses the Epic-close tier owns, and hands that roster to the
|
|
6
|
+
Phase 5 code-review pass — which walks the cumulative Epic diff once and folds
|
|
7
|
+
the lens findings into its single verification-results comment.
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
# Epic
|
|
10
|
+
# Epic-close lens roster (helper)
|
|
11
11
|
|
|
12
12
|
> **Helper module.** Not a slash command. Invoked automatically from
|
|
13
13
|
> `/deliver` Phase 4 once the wave loop completes (all Stories at
|
|
14
|
-
> `agent::done`)
|
|
15
|
-
>
|
|
14
|
+
> `agent::done`) to resolve the Epic-close lens roster that the Phase 5
|
|
15
|
+
> code-review pass walks. To run delivery, use `/deliver [Epic_ID]` (or pass
|
|
16
|
+
> `--skip-epic-audit` to bypass the Epic-close lens tier).
|
|
17
|
+
|
|
18
|
+
This helper resolves the **change-set-aware Epic-close lens roster** for an
|
|
19
|
+
Epic branch. Under the three-tier verification model (Epic #4405) it does
|
|
20
|
+
**not** run a standalone lens walk of its own and does **not** post its own
|
|
21
|
+
structured comment. It selects the slim roster and hands it to the Phase 5
|
|
22
|
+
[`code-review.md`](code-review.md) pass, which walks the cumulative Epic diff
|
|
23
|
+
**once** — executing these lenses as review dimensions — and folds their
|
|
24
|
+
findings into the single `verification-results` comment it posts on the Epic.
|
|
25
|
+
|
|
26
|
+
> **Three-tier model — where each lens concern is verified.** A lens's `scope`
|
|
27
|
+
> field in [`audit-rules.json`](../../schemas/audit-rules.json) (resolved by
|
|
28
|
+
> [`resolveLensTier`](../../scripts/lib/audit-suite/selector.js)) decides the
|
|
29
|
+
> **one** tier that owns its concern:
|
|
30
|
+
>
|
|
31
|
+
> - **`local`** — decidable from a single Story's diff. Verified **write-time**
|
|
32
|
+
> (the distilled checklist threaded into the Story implementation prompt,
|
|
33
|
+
> Story #4410) and at **Story-scope** (the maker-blind local-lens pass in
|
|
34
|
+
> `story-close`, Story #4409). **Not** re-run at Epic close.
|
|
35
|
+
> - **`cumulative`** — only decidable across the Epic's combined diff. Verified
|
|
36
|
+
> at **Epic close** only.
|
|
37
|
+
> - **`global`** — evaluates a whole-product property regardless of the diff
|
|
38
|
+
> (exempt from the cross-epic-leak change-set narrowing). Verified at **Epic
|
|
39
|
+
> close** only.
|
|
40
|
+
>
|
|
41
|
+
> No lens concern is verified at more than one tier: the Epic-close roster
|
|
42
|
+
> below deliberately **excludes every local-tier change-set lens** and keeps
|
|
43
|
+
> only cumulative + global + risk-routed lenses.
|
|
16
44
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
asks the [`selectAudits`](../../scripts/lib/audit-suite/index.js) SDK which
|
|
21
|
-
lenses are actually relevant to **this** Epic's change set, then dispatches
|
|
22
|
-
only the matching audit workflows. Docs-only Epics select zero lenses and
|
|
23
|
-
exit cleanly.
|
|
45
|
+
**When to run**: After Phase 3 close-validation passes, to resolve the roster
|
|
46
|
+
the Phase 5 code-review pass consumes. `/deliver` invokes this automatically
|
|
47
|
+
once the wave loop completes and all Stories reach `agent::done`.
|
|
24
48
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
`planningRisk` envelope off the `epic-plan-state` checkpoint and routes each
|
|
28
|
-
high-risk axis to its mapped lens via
|
|
29
|
-
[`resolveAuditLenses`](../../scripts/lib/orchestration/code-review.js)
|
|
30
|
-
(`security` → `audit-security`, `public-api` → `audit-architecture`). A
|
|
31
|
-
high-risk Epic therefore auto-runs its mapped lenses even when the change
|
|
32
|
-
set alone did not select them; a low-risk Epic adds nothing beyond the
|
|
33
|
-
change-set selection. Both lens sources fire through the **same**
|
|
34
|
-
`runAuditSuite` dispatch below — no new audit machinery.
|
|
35
|
-
|
|
36
|
-
> **When to run**: After Phase 3 close-validation passes and before Phase 5
|
|
37
|
-
> code-review. `/deliver` invokes this automatically once the wave loop
|
|
38
|
-
> completes and all Stories reach `agent::done`.
|
|
39
|
-
>
|
|
40
|
-
> **Persona**: `architect` · **Skills**: `core/code-review-and-quality`,
|
|
41
|
-
> `core/security-and-hardening`
|
|
49
|
+
**Persona**: `architect` · **Skills**: `core/code-review-and-quality`,
|
|
50
|
+
`core/security-and-hardening`
|
|
42
51
|
|
|
43
52
|
## Step 0 — Resolve Context
|
|
44
53
|
|
|
@@ -53,14 +62,13 @@ change-set selection. Both lens sources fire through the **same**
|
|
|
53
62
|
- **Tech Spec** — the folded Tech Spec sections (opening with
|
|
54
63
|
`## Delivery Slicing`) inside the body's managed region.
|
|
55
64
|
5. Read the Epic body fully (including its Tech Spec sections) to
|
|
56
|
-
understand the intended
|
|
57
|
-
scope, selected lenses, and acceptance criteria.
|
|
65
|
+
understand the intended scope, selected lenses, and acceptance criteria.
|
|
58
66
|
|
|
59
67
|
## Step 1 — Prepare (`epic-audit-prepare.js`)
|
|
60
68
|
|
|
61
69
|
Run the prepare CLI to compute the change-set, ask `selectAudits` which
|
|
62
|
-
lenses fire at `gate3` (the Epic close gate),
|
|
63
|
-
JSON envelope on stdout:
|
|
70
|
+
lenses fire at `gate3` (the Epic close gate), union in the model-judged
|
|
71
|
+
risk-routed lenses, and emit the helper-consumable JSON envelope on stdout:
|
|
64
72
|
|
|
65
73
|
```bash
|
|
66
74
|
node .agents/scripts/epic-audit-prepare.js \
|
|
@@ -76,55 +84,54 @@ envelope:
|
|
|
76
84
|
"epicId": 2586,
|
|
77
85
|
"epicBranch": "epic/2586",
|
|
78
86
|
"depth": "deep",
|
|
79
|
-
"selectedAudits": ["audit-security", "audit-privacy"],
|
|
80
|
-
"
|
|
87
|
+
"selectedAudits": ["audit-security", "audit-architecture", "audit-privacy"],
|
|
88
|
+
"epicCloseLenses": ["audit-architecture", "audit-security"],
|
|
89
|
+
"changeSetAudits": ["audit-architecture", "audit-privacy"],
|
|
81
90
|
"riskRoutedAudits": ["audit-security"],
|
|
91
|
+
"globalLenses": [],
|
|
82
92
|
"changedFiles": ["src/api/admin/users.ts", "..."],
|
|
83
93
|
"changedFilesCount": 47,
|
|
84
94
|
"substitutionsPayload": "src/api/admin/users.ts\n..."
|
|
85
95
|
}
|
|
86
96
|
```
|
|
87
97
|
|
|
88
|
-
`
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
98
|
+
- **`epicCloseLenses` is the roster you hand to Phase 5.** It is the slim
|
|
99
|
+
Epic-close roster — `selectedAudits` restricted to the tiers the Epic-close
|
|
100
|
+
tier owns via
|
|
101
|
+
[`selectEpicCloseLenses`](../../scripts/lib/orchestration/code-review.js):
|
|
102
|
+
every **cumulative** and **global** change-set lens, plus every **risk-routed**
|
|
103
|
+
lens, with every **local-tier** change-set lens dropped (its concern is
|
|
104
|
+
already verified shift-left). In the example above `audit-privacy` (local) is
|
|
105
|
+
excluded from `epicCloseLenses` while `audit-architecture` (cumulative) is
|
|
106
|
+
kept and `audit-security` (risk-routed) is kept.
|
|
107
|
+
- **`selectedAudits` / `changeSetAudits` / `riskRoutedAudits`** are surfaced for
|
|
108
|
+
observability so the operator can see the pre-slim union and why each lens
|
|
109
|
+
fired. Do **not** walk `selectedAudits` — walk `epicCloseLenses`.
|
|
110
|
+
- **`globalLenses`** is the subset of the roster on the global-lens allowlist
|
|
111
|
+
(e.g. `audit-navigability`) that the Phase 5 walk runs against the WHOLE
|
|
112
|
+
route tree, exempt from the cross-epic-leak guard's change-set narrowing
|
|
113
|
+
(Epic #4131, F2).
|
|
93
114
|
|
|
94
115
|
### The `depth` field (Story #3939)
|
|
95
116
|
|
|
96
117
|
`depth` is `light`, `standard`, or `deep` — an **orthogonal** signal that
|
|
97
|
-
tells
|
|
98
|
-
resolved by the shared `resolveDepth` resolver from the Epic's
|
|
99
|
-
risk envelope (`overallLevel` off the `epic-plan-state`
|
|
100
|
-
with `changedFilesCount`: a high-risk **or** wide-footprint
|
|
101
|
-
`deep`, a low-risk small one to `light`, and everything else
|
|
102
|
-
Epic that skipped `/plan` and has no checkpoint — to `standard`.
|
|
103
|
-
|
|
104
|
-
Depth changes **how deeply** each lens runs, never **which** lenses fire:
|
|
105
|
-
|
|
106
|
-
- **`light`** — run each selected lens against the **changed surface only**
|
|
107
|
-
and report **only Critical/High** findings. Skip the Medium/Suggestion
|
|
108
|
-
sweep. Light **never skips a selected lens** — including the alwaysRun
|
|
109
|
-
floor (`audit-clean-code`, `audit-architecture`) — it only **shrinks the
|
|
110
|
-
selected lens's sweep**. An easy, low-risk Epic still runs its audits;
|
|
111
|
-
they just run lighter.
|
|
112
|
-
- **`standard`** — today's behavior: walk each selected lens's full
|
|
113
|
-
procedure over the changed surface at every severity.
|
|
114
|
-
- **`deep`** — run the full lens procedure over the changed surface **plus
|
|
115
|
-
the modules it directly touches**, at every severity.
|
|
116
|
-
|
|
117
|
-
Depth never changes the severity taxonomy, the findings-report shape, or the
|
|
118
|
-
Phase 4 halting rule below (a 🔴 Critical Blocker halts at every depth;
|
|
119
|
-
everything else logs). Thread the resolved `depth` into each lens walk in
|
|
120
|
-
Step 2 — it scopes the sweep, it does not gate the roster.
|
|
118
|
+
tells the Phase 5 pass how thorough each **rostered** lens should be on this
|
|
119
|
+
Epic. It is resolved by the shared `resolveDepth` resolver from the Epic's
|
|
120
|
+
model-judged risk envelope (`overallLevel` off the `epic-plan-state`
|
|
121
|
+
checkpoint) folded with `changedFilesCount`: a high-risk **or** wide-footprint
|
|
122
|
+
Epic resolves to `deep`, a low-risk small one to `light`, and everything else
|
|
123
|
+
— including an Epic that skipped `/plan` and has no checkpoint — to `standard`.
|
|
124
|
+
Depth changes **how deeply** each lens runs, never **which** lenses fire.
|
|
121
125
|
|
|
122
126
|
### Outcomes
|
|
123
127
|
|
|
124
|
-
- **`
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
+
- **`epicCloseLenses` is non-empty** — pass the roster (and `depth`,
|
|
129
|
+
`globalLenses`, `substitutionsPayload`) to the Phase 5 code-review pass.
|
|
130
|
+
- **`epicCloseLenses` is empty** (docs-only change set, or every selected lens
|
|
131
|
+
was a local-tier change-set lens already covered shift-left, and no high-risk
|
|
132
|
+
axis routed a lens) — there is no Epic-close lens dimension to walk; the
|
|
133
|
+
Phase 5 pass still runs its review pillars and posts the
|
|
134
|
+
`verification-results` comment.
|
|
128
135
|
- **`degraded: true`** — the selector aborted. Possible `reason` codes:
|
|
129
136
|
`GIT_DIFF_TIMEOUT` (git-diff timed out), `HEAD_REF_UNRESOLVED` (the
|
|
130
137
|
Epic's branch `refs/heads/epic/<id>` is not present in this checkout),
|
|
@@ -135,222 +142,48 @@ Step 2 — it scopes the sweep, it does not gate the roster.
|
|
|
135
142
|
roster — that defeats the change-set scoping, and an unresolved/mismatched
|
|
136
143
|
ref means the change set would belong to the wrong Epic.
|
|
137
144
|
|
|
138
|
-
## Step 2 —
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
node .agents/scripts/run-audit-suite.js \
|
|
164
|
-
--audits audit-security,audit-privacy \
|
|
165
|
-
--ticket [EPIC_ID] \
|
|
166
|
-
--base-branch [BASE_BRANCH] \
|
|
167
|
-
--substitution changedFiles="[substitutionsPayload]" \
|
|
168
|
-
--run-id epic-[EPIC_ID]
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
CLI shape notes:
|
|
172
|
-
|
|
173
|
-
- `--audits` is **comma-separated**, not space-separated. Passing each
|
|
174
|
-
lens as a separate positional arg only captures the first one.
|
|
175
|
-
- `--substitution` is **repeatable** (`key=value` per occurrence); the
|
|
176
|
-
legacy `--substitutions '<json>'` flag is not supported.
|
|
177
|
-
- `--run-id` is the per-lens artifact prefix (the legacy
|
|
178
|
-
`--artifact-prefix` flag is not supported). When omitted, no
|
|
179
|
-
artifact is written and the host LLM must walk the workflow body in
|
|
180
|
-
memory.
|
|
181
|
-
|
|
182
|
-
After the runner returns:
|
|
183
|
-
|
|
184
|
-
1. **Read the descriptor stream** — confirm every requested lens
|
|
185
|
-
appears in `metadata.auditsRun`, then walk each entry in
|
|
186
|
-
`workflows[]` (or each on-disk artifact when `--run-id` was set).
|
|
187
|
-
2. **Execute the lens inline at the run's `depth`.** Open the lens
|
|
188
|
-
workflow at `path` (or the per-lens artifact file when `--run-id`
|
|
189
|
-
produced one) and follow its procedure verbatim against the
|
|
190
|
-
substituted change set, scoping the sweep to the envelope's `depth`
|
|
191
|
-
(see "The `depth` field" above): `light` walks the changed surface and
|
|
192
|
-
reports only 🔴/🟠 findings, `standard` walks the full procedure at
|
|
193
|
-
every severity, and `deep` extends the sweep to the directly-touched
|
|
194
|
-
modules. Depth scopes the sweep only — never skip a selected lens.
|
|
195
|
-
Each lens declares its own pillars, severity rubric, and remediation
|
|
196
|
-
prose; treat its body as the canonical execution contract for that
|
|
197
|
-
pass.
|
|
198
|
-
3. **Aggregate** by severity (🔴 Critical Blocker / 🟠 High /
|
|
199
|
-
🟡 Medium / 🟢 Suggestion). Hold the aggregate for Step 3
|
|
200
|
-
(auto-fix) and Step 4 (the `audit-results` structured comment).
|
|
201
|
-
|
|
202
|
-
### Optional: delegate the roster walk to an audit-orchestrator sub-agent
|
|
203
|
-
|
|
204
|
-
The Step 2 loop above walks the `selectedAudits` roster **serially in the
|
|
205
|
-
host's own context**. When the roster carries more than one lens, `/deliver`
|
|
206
|
-
Phase 4 MAY instead delegate the whole walk to a **single audit-orchestrator
|
|
207
|
-
sub-agent** — one level-1 `Agent` call (`subagent_type: general-purpose`) — that:
|
|
208
|
-
|
|
209
|
-
1. Receives the **already-selected** `selectedAudits` roster, the run's
|
|
210
|
-
`depth`, and the prepare envelope's substitution payload. It does **not**
|
|
211
|
-
re-run `selectAudits` and does **not** widen the roster — the roster is
|
|
212
|
-
fixed upstream by Step 1 (see the Constraints below).
|
|
213
|
-
2. Fans the roster out as **parallel level-2 agents, one per lens** (nested
|
|
214
|
-
`Agent` dispatch — verified depth 2, announced max depth 5, per
|
|
215
|
-
[#2870](https://github.com/dsj1984/mandrel/issues/2870) and the
|
|
216
|
-
"Flat Story dispatch by design" note in
|
|
217
|
-
[`deliver-epic.md`](deliver-epic.md)). Each level-2 agent executes exactly
|
|
218
|
-
one lens's workflow procedure at the run's `depth`, isolated from the main
|
|
219
|
-
context.
|
|
220
|
-
3. Collects the per-lens findings, **aggregates them by severity** (🔴 / 🟠 /
|
|
221
|
-
🟡 / 🟢), and returns **only the aggregated audit-results** to the host —
|
|
222
|
-
the per-lens reasoning transcripts stay in the level-2 leaves and never
|
|
223
|
-
enter the main context. The host resumes at Step 3 (remediation routing)
|
|
224
|
-
with the aggregate exactly as if it had walked the roster itself, and Step 4
|
|
225
|
-
posts the identical `audit-results` comment.
|
|
226
|
-
|
|
227
|
-
This delegation is a **cross-lens parallelization of the roster walk only**. It
|
|
228
|
-
is orthogonal to — and MUST NOT be conflated with — the *per-lens execution
|
|
229
|
-
strategy*:
|
|
230
|
-
|
|
231
|
-
- **The per-lens cost/precision gate is preserved.** Each level-2 lens agent
|
|
232
|
-
still runs its own lens at whatever strategy that lens's cost/precision gate
|
|
233
|
-
dictates (`docs/roadmap.md` § "The per-lens cost / precision gate"): an
|
|
234
|
-
orchestrated lens fans its own analysis dimensions out under
|
|
235
|
-
`runAuditOrchestration`, a sequential-only lens runs turn-by-turn. Fanning
|
|
236
|
-
the *roster* out in parallel changes **which context** runs a lens, never
|
|
237
|
-
**how** that lens runs internally, so no per-lens cost gate is bypassed or
|
|
238
|
-
altered.
|
|
239
|
-
- **The "do not batch-convert the sequential-only lenses" rule is preserved.**
|
|
240
|
-
The seven sequential-only lenses (`audit-dependencies`, `audit-devops`,
|
|
241
|
-
`audit-sre`, `audit-privacy`, `audit-seo`, `audit-ux-ui`,
|
|
242
|
-
`audit-lighthouse`) stay sequential **inside** their level-2 agent.
|
|
243
|
-
Dispatching them as parallel level-2 agents is **not** a batch-conversion of
|
|
244
|
-
their internal execution — a sequential-only lens remains sequential-only
|
|
245
|
-
(`docs/roadmap.md` § "Remaining orchestration surface"). Generalizing any of
|
|
246
|
-
those lenses to orchestrated is still a separate, gated, lens-by-lens
|
|
247
|
-
decision that this roster fan-out neither performs nor pre-empts.
|
|
248
|
-
|
|
249
|
-
Weigh the whole subtree's token cost before delegating
|
|
250
|
-
([`.agents/instructions.md` § 4](../../instructions.md) — cost compounds with
|
|
251
|
-
nesting depth): the level-1 orchestrator plus one level-2 agent per lens
|
|
252
|
-
re-pays the always-loaded context at each level. For a single-lens roster the
|
|
253
|
-
serial host walk is cheaper; the delegation pays off when several lenses fan
|
|
254
|
-
out at once. Either path produces the identical Step 4 `audit-results` comment,
|
|
255
|
-
so the delegation is a performance/context-isolation choice, never a change to
|
|
256
|
-
what gets audited or reported.
|
|
257
|
-
|
|
258
|
-
If a future Story lifts per-lens execution out of the host-LLM walk
|
|
259
|
-
into the CLI itself, the runner will populate `findings[]` and this
|
|
260
|
-
section will collapse to a "read the structured findings off the
|
|
261
|
-
envelope" bullet. Until then, the host LLM is the gate.
|
|
262
|
-
|
|
263
|
-
## Step 3 — Remediation Routing (host LLM, no automated loop)
|
|
264
|
-
|
|
265
|
-
There is **no runtime auto-fix function** at this phase. The host LLM is
|
|
266
|
-
the executor: it inspects the aggregated 🔴 / 🟠 findings from Step 2 and
|
|
267
|
-
either applies a focused fix on the Epic branch or escalates the finding
|
|
268
|
-
to the operator via the `audit-results` comment in Step 4.
|
|
269
|
-
|
|
270
|
-
For each 🔴 / 🟠 finding, the host LLM MUST decide between two paths:
|
|
271
|
-
|
|
272
|
-
1. **Apply a focused fix on `[EPIC_BRANCH]`.** Permitted only when the
|
|
273
|
-
finding is unambiguously *fixable* (clean remediation, no scope creep,
|
|
274
|
-
no spec deviation, no secret exposure):
|
|
275
|
-
- Call [`assert-branch.js`](../../scripts/assert-branch.js) with
|
|
276
|
-
`--expected [EPIC_BRANCH]` before touching the working tree.
|
|
277
|
-
- Stage explicit paths only (never `git add .`).
|
|
278
|
-
- Make one focused conventional commit per finding
|
|
279
|
-
(`fix(<scope>): <description> (audit finding)`).
|
|
280
|
-
- Re-run the owning lens (re-invoke `run-audit-suite.js` for that
|
|
281
|
-
single lens) and confirm the finding is gone before moving on.
|
|
282
|
-
- Run the lens-appropriate validation subset (`npm run lint` plus the
|
|
283
|
-
relevant `npm test` slice) to confirm the fix did not regress
|
|
284
|
-
anything.
|
|
285
|
-
- If the rescan still surfaces the same finding, or validation
|
|
286
|
-
regresses, **stop fixing** — route the finding to escalation
|
|
287
|
-
(path 2) and record the attempt context in Step 4.
|
|
288
|
-
2. **Escalate to the operator via Step 4.** Required when the finding
|
|
289
|
-
falls into any of the following classes:
|
|
290
|
-
- `spec-deviation` — the change diverges from the Epic/Tech Spec.
|
|
291
|
-
- `secrets` — credentials, tokens, or PII surfaced in the diff.
|
|
292
|
-
- `test-deletion` — coverage was removed without an explicit
|
|
293
|
-
decision in the spec.
|
|
294
|
-
- `scope-exceeded` — the remediation would touch more files than the
|
|
295
|
-
change set warrants.
|
|
296
|
-
- Any finding the host LLM cannot remediate after one focused
|
|
297
|
-
attempt (the equivalent of the prior loop's
|
|
298
|
-
`validation-regression` / `thrash-detected` exits).
|
|
299
|
-
|
|
300
|
-
Do not invent a programmatic retry budget. The host LLM applies *at most
|
|
301
|
-
one* focused-fix attempt per finding before escalating; any further
|
|
302
|
-
remediation is the operator's call after reading the `audit-results`
|
|
303
|
-
comment.
|
|
304
|
-
|
|
305
|
-
Escalated findings flow through to Step 4 unchanged with their
|
|
306
|
-
escalation reason recorded — the audit pass does not delete them, it
|
|
307
|
-
just stops trying to fix them automatically. Surface the escalation
|
|
308
|
-
reason for each in the `audit-results` comment so the operator sees
|
|
309
|
-
exactly why the finding was not auto-remediated.
|
|
310
|
-
|
|
311
|
-
## Step 4 — Post `audit-results` Structured Comment
|
|
312
|
-
|
|
313
|
-
Persist the findings as an `audit-results` structured comment on the Epic
|
|
314
|
-
issue. The comment is idempotent — re-runs replace the prior one. Build the
|
|
315
|
-
body in a temp file under `[TEMP_ROOT]/epic-[EPIC_ID]/audit-results.md`,
|
|
316
|
-
then upsert via [`post-structured-comment.js`](../../scripts/post-structured-comment.js):
|
|
317
|
-
|
|
318
|
-
```bash
|
|
319
|
-
node .agents/scripts/post-structured-comment.js \
|
|
320
|
-
--ticket [EPIC_ID] \
|
|
321
|
-
--marker audit-results \
|
|
322
|
-
--body-file [TEMP_ROOT]/epic-[EPIC_ID]/audit-results.md
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
The body MUST include:
|
|
326
|
-
|
|
327
|
-
- the `selectedAudits` roster (or `Lenses applied: none (docs-only)` when
|
|
328
|
-
the prepare envelope returned an empty list),
|
|
329
|
-
- the per-severity counts (🔴 critical / 🟠 high / 🟡 medium / 🟢 suggestion),
|
|
330
|
-
- the per-lens findings grouped under the lens name, each carrying file
|
|
331
|
-
path + line range + pillar + recommended fix,
|
|
332
|
-
- a link to the per-lens artifact files under `<auditOutputDir>` so the
|
|
333
|
-
operator (and downstream retro) can re-read the full prompt body.
|
|
334
|
-
|
|
335
|
-
### Severity gating
|
|
336
|
-
|
|
337
|
-
- **Any 🔴 Critical Blocker** → STOP. Relay to the operator and let
|
|
338
|
-
`/deliver` Phase 4 record a manual intervention.
|
|
339
|
-
- **Only 🟠/🟡/🟢** → log as non-blocking and return to `/deliver`
|
|
340
|
-
Phase 5 (code-review).
|
|
145
|
+
## Step 2 — Hand the roster to the Phase 5 code-review pass
|
|
146
|
+
|
|
147
|
+
The cumulative Epic diff is walked **once** at Epic close. The
|
|
148
|
+
`epicCloseLenses` roster is executed as **dimensions of the Phase 5
|
|
149
|
+
code-review pass** ([`code-review.md`](code-review.md) with `scope: epic`),
|
|
150
|
+
not as a standalone walk here. The Phase 5 pass:
|
|
151
|
+
|
|
152
|
+
1. Loads each rostered lens's `.agents/workflows/audit-<lens>.md` via
|
|
153
|
+
[`runAuditSuite`](../../scripts/lib/audit-suite/index.js) (the
|
|
154
|
+
prompt-assembly runner), applying the `{{changedFiles}}` / `{{ticketId}}` /
|
|
155
|
+
`{{baseBranch}}` substitutions from this envelope.
|
|
156
|
+
2. Executes each lens inline at the run's `depth` over the cumulative diff,
|
|
157
|
+
folding its findings into the pass's severity aggregate alongside the review
|
|
158
|
+
pillars — one walk of `main..epic/<id>`, one aggregate.
|
|
159
|
+
3. Posts the single `verification-results` structured comment (there is **no**
|
|
160
|
+
separate `audit-results` comment; that producer was retired in Story #4412).
|
|
161
|
+
|
|
162
|
+
Remediation of the aggregate is **tier-aware** (Story #4412): the Epic-close
|
|
163
|
+
tier reads `delivery.epicAudit.autoFixSeverity` (default **`high`** — see
|
|
164
|
+
[`config/runners.js`](../../scripts/lib/config/runners.js)) and routes only
|
|
165
|
+
🔴 Critical + 🟠 High findings into on-branch remediation; 🟡 Medium and
|
|
166
|
+
🟢 Suggestion findings graduate to follow-up issues, because 🟡 Medium concerns
|
|
167
|
+
are already remediated shift-left at the write-time and Story-scope tiers.
|
|
168
|
+
Setting `medium` opts back into routing 🔴/🟠/🟡 on-branch. The severity gate
|
|
169
|
+
is **unchanged** — a surviving 🔴 Critical Blocker halts the run.
|
|
341
170
|
|
|
342
171
|
## Constraints
|
|
343
172
|
|
|
344
173
|
- **Always** diff against `[BASE_BRANCH]`, not against individual Story
|
|
345
|
-
branches. The
|
|
346
|
-
|
|
174
|
+
branches. The Epic-close pass examines the cumulative effect of the entire
|
|
175
|
+
Epic.
|
|
176
|
+
- **Always** read the Epic body and Tech Spec before the Phase 5 walk. Findings
|
|
347
177
|
without spec context are noise.
|
|
348
|
-
- **
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
- **Never** widen the
|
|
353
|
-
|
|
354
|
-
|
|
178
|
+
- **Never** walk `selectedAudits`. The roster the Phase 5 pass executes is
|
|
179
|
+
`epicCloseLenses` — the slim cumulative + global + risk-routed set. Walking
|
|
180
|
+
the pre-slim union re-verifies local-tier concerns already covered
|
|
181
|
+
shift-left, defeating the three-tier model.
|
|
182
|
+
- **Never** widen the roster past `epicCloseLenses`. The whole point of the
|
|
183
|
+
change-set selector plus the tier filter is to avoid re-running irrelevant or
|
|
184
|
+
already-verified lenses on a scoped Epic.
|
|
185
|
+
- **Never** post an `audit-results` structured comment. The Epic-close lens
|
|
186
|
+
findings are folded into the Phase 5 `verification-results` comment — the
|
|
187
|
+
single findings surface on the Epic.
|
|
355
188
|
- **Always** propagate `degraded` envelopes verbatim. Do not paper over a
|
|
356
189
|
selector failure with a full-roster fallback.
|
|
@@ -180,6 +180,20 @@ Run a single Story-implementation phase against the inline `acceptance[]`
|
|
|
180
180
|
Story's own context points you at one. See
|
|
181
181
|
[`.agents/instructions.md` § 3](../../instructions.md).
|
|
182
182
|
|
|
183
|
+
**Write-time audit checklists — read the threaded `checklistPath`.**
|
|
184
|
+
When the parent prompt passes a `checklistPath` (Story #4410 — the
|
|
185
|
+
repo-relative path to this Story's footprint-matched **local**-lens
|
|
186
|
+
authoring checklists at
|
|
187
|
+
`temp/epic-<epicId>/checklists/story-<storyId>.md`), read it before you
|
|
188
|
+
write and self-check your change against each listed concern as you
|
|
189
|
+
author it. These are the local audit lenses whose `filePatterns` matched
|
|
190
|
+
the Story's predicted footprint, distilled to a short checklist and
|
|
191
|
+
capped at a hard token budget by `epic-deliver-prepare.js` (matched via
|
|
192
|
+
`resolveLensTier(lens) === 'local'` + `matchesAnyFilePattern`, never
|
|
193
|
+
`selectAudits` — no provider or git diff runs on that path). When
|
|
194
|
+
`checklistPath` is null or absent, the Story's footprint matched no local
|
|
195
|
+
lens and there is nothing extra to read.
|
|
196
|
+
|
|
183
197
|
3. Implement the work as one or more commits on `story-<storyId>`.
|
|
184
198
|
Author commits directly with the project's editor / `git commit`,
|
|
185
199
|
following
|