mandrel 2.3.0 → 2.5.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/audit-checklists/accessibility.md +29 -0
- package/.agents/audit-checklists/architecture.md +4 -5
- package/.agents/audit-checklists/clean-code.md +10 -0
- package/.agents/audit-checklists/data-model.md +22 -0
- package/.agents/audit-checklists/dependencies.md +11 -2
- package/.agents/audit-checklists/devops.md +4 -0
- package/.agents/audit-checklists/navigability.md +3 -0
- package/.agents/audit-checklists/performance.md +8 -11
- package/.agents/audit-checklists/privacy.md +3 -4
- package/.agents/audit-checklists/quality.md +2 -0
- package/.agents/audit-checklists/security.md +4 -5
- package/.agents/audit-checklists/seo.md +7 -1
- package/.agents/audit-checklists/sre.md +14 -12
- package/.agents/audit-checklists/ux-ui.md +4 -0
- package/.agents/docs/configuration.md +3 -0
- package/.agents/docs/workflows.md +4 -3
- package/.agents/schemas/agentrc.schema.json +17 -0
- package/.agents/schemas/audit-rules.json +134 -19
- package/.agents/schemas/audit-rules.schema.json +6 -2
- package/.agents/scripts/audit-labels-bootstrap.js +4 -4
- package/.agents/scripts/audit-to-stories.js +244 -19
- package/.agents/scripts/lib/audit-suite/checklist-threading.js +26 -3
- package/.agents/scripts/lib/audit-suite/dispatch-checklist.js +132 -0
- package/.agents/scripts/lib/audit-suite/index.js +1 -0
- package/.agents/scripts/lib/audit-suite/selector.js +290 -14
- package/.agents/scripts/lib/audit-to-stories/audit-lenses.js +2 -1
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +5 -1
- package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +23 -3
- package/.agents/scripts/lib/audit-to-stories/finding-adapter.js +38 -0
- package/.agents/scripts/lib/audit-to-stories/ledger.js +256 -0
- package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +41 -7
- package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +20 -2
- package/.agents/scripts/lib/command-header.js +1 -1
- package/.agents/scripts/lib/config-settings-schema-delivery.js +21 -0
- package/.agents/scripts/lib/dynamic-workflow/performance-report-contract.js +5 -3
- package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +56 -0
- package/.agents/scripts/lib/findings/route-finding.js +108 -10
- package/.agents/scripts/lib/observability/runtime-friction.js +62 -0
- package/.agents/scripts/lib/orchestration/resolve-stories.js +9 -1
- package/.agents/scripts/lib/orchestration/retro-proposals.js +49 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +73 -15
- package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +81 -1
- package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +1 -0
- package/.agents/scripts/lib/orchestration/ticket-lease.js +78 -10
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +68 -16
- package/.agents/scripts/lib/single-story-sweep/sweep-lock.js +73 -0
- package/.agents/scripts/lib/wave-runner/live-probe.js +93 -12
- package/.agents/scripts/nav-registry-diff.js +449 -0
- package/.agents/scripts/single-story-init.js +189 -51
- package/.agents/scripts/stories-wave-tick.js +39 -2
- package/.agents/workflows/audit-accessibility.md +243 -0
- package/.agents/workflows/audit-architecture.md +89 -71
- package/.agents/workflows/audit-clean-code.md +87 -53
- package/.agents/workflows/audit-data-model.md +198 -0
- package/.agents/workflows/audit-dependencies.md +143 -28
- package/.agents/workflows/audit-devops.md +109 -18
- package/.agents/workflows/audit-documentation.md +25 -53
- package/.agents/workflows/audit-navigability.md +78 -22
- package/.agents/workflows/audit-performance.md +207 -103
- package/.agents/workflows/audit-privacy.md +51 -13
- package/.agents/workflows/audit-quality.md +71 -61
- package/.agents/workflows/audit-security.md +94 -71
- package/.agents/workflows/audit-seo.md +80 -25
- package/.agents/workflows/audit-sre.md +99 -66
- package/.agents/workflows/audit-to-stories.md +44 -5
- package/.agents/workflows/audit-ux-ui.md +71 -17
- package/.agents/workflows/deliver.md +32 -8
- package/.agents/workflows/helpers/audit-dual-path.md +59 -0
- package/.agents/workflows/helpers/audit-self-check.md +70 -0
- package/.agents/workflows/helpers/audit-severity-scale.md +19 -0
- package/.agents/workflows/helpers/deliver-story.md +25 -0
- package/docs/CHANGELOG.md +29 -0
- package/package.json +1 -1
- package/.agents/audit-checklists/lighthouse.md +0 -15
- package/.agents/schemas/audit-results.schema.json +0 -69
- package/.agents/workflows/audit-lighthouse.md +0 -269
|
@@ -18,56 +18,12 @@ existing external APIs or business logic.
|
|
|
18
18
|
|
|
19
19
|
## Execution strategy (dual-path)
|
|
20
20
|
|
|
21
|
-
This lens runs along one of two execution paths
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
`.claude/workflows/audit-architecture.workflow.js` fans the dimensions below
|
|
28
|
-
out as parallel read-only subagents, runs an **adversarial cross-check**
|
|
29
|
-
stage (an independent agent reviews each dimension's findings and drops
|
|
30
|
-
false positives before they enter the report), then synthesises the Step 3
|
|
31
|
-
report. The orchestrator derives its per-dimension prompts from *this*
|
|
32
|
-
markdown at run time — the lens stays the single source of truth; the
|
|
33
|
-
script does not fork a second copy of the spec.
|
|
34
|
-
- **Sequential (single-pass) path.** When dynamic workflows are unavailable,
|
|
35
|
-
follow Steps 1–3 below turn-by-turn exactly as before. This is the default
|
|
36
|
-
fallback and changes nothing about the existing behaviour.
|
|
37
|
-
|
|
38
|
-
**Strategy selection** is computed by
|
|
39
|
-
[`lib/dynamic-workflow/capability.js`](../scripts/lib/dynamic-workflow/capability.js)
|
|
40
|
-
(`selectAuditStrategy`). The orchestrated path is chosen only when the runtime
|
|
41
|
-
is Claude Code, `disableWorkflows` is not set (settings.json **or**
|
|
42
|
-
`CLAUDE_CODE_DISABLE_WORKFLOWS`), and the Claude Code version meets the
|
|
43
|
-
research-preview floor (`>= 2.1.154`). Any other runtime, a disabled setting,
|
|
44
|
-
or an older version degrades gracefully to the sequential path.
|
|
45
|
-
|
|
46
|
-
> **Capability degradation, not a contract shim.** This dual path is **not**
|
|
47
|
-
> covered by the No-Shim / hard-cutover rule in
|
|
48
|
-
> [`git-conventions.md`](../rules/git-conventions.md). That rule forbids
|
|
49
|
-
> running two shapes of the *same contract* side by side. Here there is **one**
|
|
50
|
-
> report contract; only the *execution strategy* is selected from a runtime
|
|
51
|
-
> capability — the same pattern the protocol already endorses for live-docs
|
|
52
|
-
> fallback in [`instructions.md` §1.C/§1.D](../instructions.md). The full
|
|
53
|
-
> capability-degradation rationale lives in the
|
|
54
|
-
> [`capability.js`](../scripts/lib/dynamic-workflow/capability.js) module
|
|
55
|
-
> docstring; the orchestrated-run evidence and per-lens cost/precision gate
|
|
56
|
-
> verdicts live in [`docs/roadmap.md`](../../docs/roadmap.md) (Part 3 —
|
|
57
|
-
> Dynamic-Workflow Orchestration).
|
|
58
|
-
|
|
59
|
-
**Forcing a path (for testing).** Set `MANDREL_AUDIT_STRATEGY=sequential` to
|
|
60
|
-
verify the fallback path with the feature notionally disabled, or
|
|
61
|
-
`MANDREL_AUDIT_STRATEGY=orchestrated` to pin the dynamic path. To exercise the
|
|
62
|
-
real disable signals instead, set `CLAUDE_CODE_DISABLE_WORKFLOWS=1` (env) or
|
|
63
|
-
`disableWorkflows: true` in `.claude/settings.json` and re-run the lens — both
|
|
64
|
-
degrade to the sequential path.
|
|
65
|
-
|
|
66
|
-
> **Read-only on both paths.** The lens is read-only (see Constraint). The
|
|
67
|
-
> orchestrated subagents run in `acceptEdits` and inherit the session tool
|
|
68
|
-
> allowlist, but the workflow script grants the analysis agents only
|
|
69
|
-
> read/search tools (`Read`, `Grep`, `Glob`) — no write/edit/shell-mutation
|
|
70
|
-
> tools. The single write in an orchestrated run is the final report artifact.
|
|
21
|
+
This lens runs along one of two execution paths (orchestrated dynamic-workflow
|
|
22
|
+
or sequential single-pass). Both emit the **identical** Step 3 report contract;
|
|
23
|
+
downstream consumers (`audit-to-stories`) are agnostic to which path produced
|
|
24
|
+
it. See [`helpers/audit-dual-path.md`](helpers/audit-dual-path.md) for strategy
|
|
25
|
+
selection, the forcing flags, and the read-only guarantee — read `audit-<lens>`
|
|
26
|
+
there as this lens's name.
|
|
71
27
|
|
|
72
28
|
## Scope (Story / plan-run mode)
|
|
73
29
|
|
|
@@ -90,6 +46,56 @@ before this section existed.
|
|
|
90
46
|
proceed with the full codebase-wide scan defined in the remaining
|
|
91
47
|
steps.
|
|
92
48
|
|
|
49
|
+
## Step 0: Tool-first detection (mandatory — run before any LLM dimension)
|
|
50
|
+
|
|
51
|
+
Ground every structural finding in a measured instrument this repo already
|
|
52
|
+
ships rather than free-associating over the source. Run the shipped checkers
|
|
53
|
+
**first** and treat their output as the spine of the report; the LLM
|
|
54
|
+
dimensions in Step 2 only *interpret, rank, and phrase* what the tools
|
|
55
|
+
surface. Skipping this step and reasoning about boundaries from prose alone is
|
|
56
|
+
the failure mode this lens exists to prevent.
|
|
57
|
+
|
|
58
|
+
1. **Cycle detection.** Run the shipped circular-dependency checker:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
node .agents/scripts/check-arch-cycles.js
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Each reported cycle is a grounded finding under the **Automated
|
|
65
|
+
Architecture Guardrails** dimension. When the shipped checker is
|
|
66
|
+
unavailable in the consumer project, fall back to
|
|
67
|
+
`npx madge --circular <srcDir>` or
|
|
68
|
+
`npx depcruise --validate <config> <srcDir>` (dependency-cruiser).
|
|
69
|
+
|
|
70
|
+
2. **Dead-export detection.** Run the shipped dead-export checker:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
node .agents/scripts/check-dead-exports.js
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Each unreferenced export is a grounded candidate. **Cede it** to
|
|
77
|
+
audit-clean-code's Dead Code dimension rather than re-deriving it here (see
|
|
78
|
+
the deferral in Step 2). When the shipped checker is unavailable, fall back
|
|
79
|
+
to `npx knip --production` — and heed the `!`-suffix entry-pattern caveat
|
|
80
|
+
that [`audit-clean-code`](audit-clean-code.md) documents, since
|
|
81
|
+
`knip --production` is a silent no-op without it.
|
|
82
|
+
|
|
83
|
+
3. **Hotspot ranking.** Rank the modules the checkers implicate by
|
|
84
|
+
**fan-in / fan-out** (how many modules import a file versus how many it
|
|
85
|
+
imports) and by **churn** (e.g.
|
|
86
|
+
`git log --format= --name-only -n 200 | sort | uniq -c | sort -rn`). A file
|
|
87
|
+
that is both heavily depended upon and frequently churned is the
|
|
88
|
+
highest-priority structural hotspot; lead the Triage Summary with it.
|
|
89
|
+
|
|
90
|
+
4. **LLM triage on top.** Only after the tools have run do you apply the Step 2
|
|
91
|
+
dimensions to interpret, rank, and phrase the findings. A structural claim
|
|
92
|
+
that no tool grounds and no Step 2 dimension covers does not belong in this
|
|
93
|
+
report — route it to the ceded clean-code dimensions instead.
|
|
94
|
+
|
|
95
|
+
When a shipped checker exits non-zero or is genuinely absent, record that as an
|
|
96
|
+
**Automated Architecture Guardrails** finding (the guardrail is missing or
|
|
97
|
+
broken) rather than skipping the step silently.
|
|
98
|
+
|
|
93
99
|
## Step 1: Context Gathering (Read-Only Scan)
|
|
94
100
|
|
|
95
101
|
> Apply [`helpers/parallel-tooling.md`](helpers/parallel-tooling.md) when batching the scan below — independent reads belong in one turn, long shells run via `run_in_background` + `Monitor`.
|
|
@@ -136,23 +142,19 @@ Structural Change can be Medium. As a loose default, Quick Wins typically land
|
|
|
136
142
|
High (cheap to fix, real payoff) and Structural Changes Medium/High, but grade
|
|
137
143
|
Impact on the risk itself rather than deriving it mechanically from Category.
|
|
138
144
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
explain *what* the code does rather than *why*.
|
|
153
|
-
5. **Coupling & Cohesion:** Spot tight coupling between modules that should be
|
|
154
|
-
independent or god-objects handling too many concerns.
|
|
155
|
-
6. **Testable Surface (Humble-Object Boundary):** Flag modules that interleave
|
|
145
|
+
> **Ceded to audit-clean-code.** The five clean-code-overlapping dimensions
|
|
146
|
+
> this lens historically enumerated — Over-Engineering & Abstractions,
|
|
147
|
+
> Cognitive Load & Nesting, Dead Code & Redundancy, Naming &
|
|
148
|
+
> Self-Documentation, and Coupling & Cohesion — are now owned by
|
|
149
|
+
> [`audit-clean-code`](audit-clean-code.md). Do **not** duplicate them here: a
|
|
150
|
+
> smell in one of those five belongs in the clean-code report, and the
|
|
151
|
+
> dead-export candidates from Step 0 flow into audit-clean-code's Dead Code
|
|
152
|
+
> dimension. This lens keeps only the two structural dimensions no other lens
|
|
153
|
+
> owns — the testable-surface boundary and the automated-guardrail maturity.
|
|
154
|
+
|
|
155
|
+
Evaluate the gathered context against the following architecture dimensions:
|
|
156
|
+
|
|
157
|
+
1. **Testable Surface (Humble-Object Boundary):** Flag modules that interleave
|
|
156
158
|
hard-to-test I/O — filesystem (`fs`), process spawning (`child_process`,
|
|
157
159
|
`exec`, `spawn`), network calls, database access, or GUI/terminal
|
|
158
160
|
rendering — directly with business logic. The humble-object /
|
|
@@ -189,7 +191,7 @@ Evaluate the gathered context against the following clean code dimensions:
|
|
|
189
191
|
thin `runAsCli` shell — not the logic — owns the `process.exit` side effect,
|
|
190
192
|
keeping the wrapped logic exercisable under a stubbed `process.exit`. Cite
|
|
191
193
|
that precedent where it applies rather than restating it.
|
|
192
|
-
|
|
194
|
+
2. **Automated Architecture Guardrails:** Assess whether the project encodes
|
|
193
195
|
its architectural boundaries as **deterministic, automated checks** rather
|
|
194
196
|
than relying on convention or reviewer memory. When relevant to the
|
|
195
197
|
consumer project's shape, evaluate enforcement for:
|
|
@@ -245,6 +247,9 @@ Generate and save a highly structured Markdown audit report to
|
|
|
245
247
|
`{{auditOutputDir}}/audit-architecture-results.md`, using the exact template
|
|
246
248
|
below.
|
|
247
249
|
|
|
250
|
+
> Grade every finding's severity on the shared
|
|
251
|
+
> [`Critical | High | Medium | Low` scale](helpers/audit-severity-scale.md).
|
|
252
|
+
|
|
248
253
|
```markdown
|
|
249
254
|
# Architecture & Clean Code Review
|
|
250
255
|
|
|
@@ -297,16 +302,19 @@ marked `n/a`.]
|
|
|
297
302
|
|
|
298
303
|
## Detailed Findings
|
|
299
304
|
|
|
300
|
-
[For every gap identified, use the following strict structure
|
|
305
|
+
[For every gap identified, use the following strict structure. Lead each title
|
|
306
|
+
with the primary file the finding lives in:]
|
|
301
307
|
|
|
302
|
-
### [Short
|
|
308
|
+
### `path/to/primary-file.ext` — [Short title of the issue]
|
|
303
309
|
|
|
304
|
-
- **Impact:** [High | Medium | Low]
|
|
310
|
+
- **Impact:** [Critical | High | Medium | Low]
|
|
305
311
|
- **Category:** [Quick Win | Structural Change]
|
|
306
312
|
- **Dimension:** [e.g., Cognitive Load & Nesting | Testable Surface (Humble-Object Boundary) | Automated Architecture Guardrails]
|
|
313
|
+
- **Location:** `path/to/primary-file.ext:line`
|
|
307
314
|
- **Current State:** [The specific file/function and why it is problematic]
|
|
308
315
|
- **Recommendation & Rationale:** [The specific refactor strategy and how it
|
|
309
316
|
improves readability or maintainability]
|
|
317
|
+
- **Acceptance signal:** [the command or observable that proves this finding is remediated — e.g. a maintainability-index re-check, `npm test`, or a re-run of this lens]
|
|
310
318
|
- **Agent Prompt:**
|
|
311
319
|
`[A copy-pasteable, highly specific prompt to execute this refactor independently. Must explicitly state NOT to change external APIs.]`
|
|
312
320
|
```
|
|
@@ -318,3 +326,13 @@ marked `n/a`.]
|
|
|
318
326
|
Do NOT execute any code modifications, edit files, create branches, or implement
|
|
319
327
|
changes. This is strictly a read-only analysis. Ensure all recommendations
|
|
320
328
|
preserve existing functionality and external APIs. Output the report and stop.
|
|
329
|
+
|
|
330
|
+
## Self-cross-check (mandatory — filter false positives before you finalize)
|
|
331
|
+
|
|
332
|
+
Before you write the report artifact from the previous step, run the shared
|
|
333
|
+
adversarial self-cross-check over your Detailed Findings — see
|
|
334
|
+
[`helpers/audit-self-check.md`](helpers/audit-self-check.md). It defines the
|
|
335
|
+
per-finding evidence bar, the exclusion list, and the final re-open-and-drop
|
|
336
|
+
pass whose `kept <k> / dropped <d>` counts you record in the Executive
|
|
337
|
+
Summary, so the sequential single-pass path filters unverified findings just as
|
|
338
|
+
the orchestrated path's adversarial reviewer does.
|
|
@@ -38,56 +38,74 @@ before this section existed.
|
|
|
38
38
|
|
|
39
39
|
## Execution strategy (dual-path)
|
|
40
40
|
|
|
41
|
-
This lens runs along one of two execution paths
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
`
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
41
|
+
This lens runs along one of two execution paths (orchestrated dynamic-workflow
|
|
42
|
+
or sequential single-pass). Both emit the **identical** Step 3 report contract;
|
|
43
|
+
downstream consumers (`audit-to-stories`) are agnostic to which path produced
|
|
44
|
+
it. See [`helpers/audit-dual-path.md`](helpers/audit-dual-path.md) for strategy
|
|
45
|
+
selection, the forcing flags, and the read-only guarantee — read `audit-<lens>`
|
|
46
|
+
there as this lens's name.
|
|
47
|
+
|
|
48
|
+
## Step 0: Tool-first detection (mandatory — measure before you judge)
|
|
49
|
+
|
|
50
|
+
Ground the maintainability, duplication, and dead-code findings in the exact
|
|
51
|
+
instruments this repo ships, then let the LLM triage in Steps 1–2 interpret and
|
|
52
|
+
rank the numbers. Do **not** eyeball complexity or "spot" dead code from prose —
|
|
53
|
+
run the tools first.
|
|
54
|
+
|
|
55
|
+
1. **Complexity / maintainability (scoped mode).** When a change-set is in
|
|
56
|
+
scope, run the quality preview against the base:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
node .agents/scripts/quality-preview.js --changed-since <base>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
It reports the per-file maintainability-index and complexity deltas the
|
|
63
|
+
`check-baselines.js` gate enforces. Treat any per-file MI drop beyond
|
|
64
|
+
`delivery.quality.gates.maintainability.tolerance` (default 0.5pt) as a
|
|
65
|
+
grounded must-fix finding, and any cyclomatic reading over the
|
|
66
|
+
`codingGuardrails` ceilings (flag > 8, must-fix > 12) as measured, not
|
|
67
|
+
guessed.
|
|
68
|
+
|
|
69
|
+
2. **Committed baselines (codebase-wide mode).** Read the committed metric
|
|
70
|
+
baselines under `baselines/` — `baselines/maintainability.json`,
|
|
71
|
+
`baselines/duplication.json`, `baselines/crap.json`,
|
|
72
|
+
`baselines/dead-exports.json` — and cite the outlier rows as evidence
|
|
73
|
+
rather than re-deriving them. These are the same artifacts the delivery
|
|
74
|
+
gates read, so a finding that quotes a baseline row is reproducible.
|
|
75
|
+
|
|
76
|
+
3. **Duplication.** Run the shipped duplication checker
|
|
77
|
+
(`node .agents/scripts/check-baselines.js --gate duplication`, backed by
|
|
78
|
+
jscpd) and lift its clone clusters into the DRY dimension.
|
|
79
|
+
|
|
80
|
+
4. **Dead code.** Run the shipped dead-export checker
|
|
81
|
+
(`node .agents/scripts/check-dead-exports.js`); it is backed by `knip`.
|
|
82
|
+
**`knip --production` is a silent no-op unless entry points are declared
|
|
83
|
+
with `!`-suffixed patterns** — a run that reports `{"issues":[]}` without
|
|
84
|
+
`!`-suffixed entries has measured nothing, so verify the entry config before
|
|
85
|
+
trusting a clean result. Apply the **dead-code exclusion taxonomy** below so
|
|
86
|
+
the report does not drown real dead code in false positives:
|
|
87
|
+
|
|
88
|
+
- **Entry points** — CLI mains, `bin/` scripts, and files named in
|
|
89
|
+
`package.json` `main` / `exports` / `bin`: reachable by definition, never
|
|
90
|
+
dead.
|
|
91
|
+
- **Public API surface** — exports that are the package's declared
|
|
92
|
+
`exports` / barrel contract: consumed out-of-tree, so a zero in-repo
|
|
93
|
+
importer count is not death.
|
|
94
|
+
- **Dynamic imports** — symbols reached via `import()`,
|
|
95
|
+
`require(variable)`, or string-keyed dispatch tables: invisible to static
|
|
96
|
+
export-graph analysis, so exclude unless you confirm no dynamic reference.
|
|
97
|
+
- **Test-only seams** — exports consumed only by tests (the sanctioned
|
|
98
|
+
`test-seams` pattern): flag as test-only, not dead, and never as a
|
|
99
|
+
production-dead finding.
|
|
100
|
+
- **Framework/registration hooks** — decorators, lifecycle listeners, and
|
|
101
|
+
files auto-loaded by convention (globbed listener/plugin dirs): reachable
|
|
102
|
+
via the framework, not the import graph.
|
|
103
|
+
|
|
104
|
+
5. **Churn-by-complexity hotspot cap.** Rank candidate hotspots by
|
|
105
|
+
**churn × complexity** (frequently-changed files that also score poorly on
|
|
106
|
+
MI/CRAP) and **cap the Detailed Findings at the top ~15 hotspots** so the
|
|
107
|
+
report stays a ranked, actionable batch rather than an exhaustive dump. Note
|
|
108
|
+
the cap in the Executive Summary when it bites.
|
|
91
109
|
|
|
92
110
|
## Step 1: Quality Scan
|
|
93
111
|
|
|
@@ -139,6 +157,9 @@ Generate and save a highly structured Markdown audit report to
|
|
|
139
157
|
`{{auditOutputDir}}/audit-clean-code-results.md`, using the exact template
|
|
140
158
|
below.
|
|
141
159
|
|
|
160
|
+
> Grade every finding's severity on the shared
|
|
161
|
+
> [`Critical | High | Medium | Low` scale](helpers/audit-severity-scale.md).
|
|
162
|
+
|
|
142
163
|
```markdown
|
|
143
164
|
# Clean Code Audit Report
|
|
144
165
|
|
|
@@ -149,15 +170,18 @@ primary themes.]
|
|
|
149
170
|
|
|
150
171
|
## Detailed Findings
|
|
151
172
|
|
|
152
|
-
[For every gap identified, use the following strict structure
|
|
173
|
+
[For every gap identified, use the following strict structure. Lead each title
|
|
174
|
+
with the primary file the finding lives in:]
|
|
153
175
|
|
|
154
|
-
### [Short
|
|
176
|
+
### `path/to/primary-file.ext` — [Short title of the issue]
|
|
155
177
|
|
|
156
178
|
- **Dimension:** [e.g., SOLID Principles | DRY | KISS | Dead Code]
|
|
157
|
-
- **Impact:** [High | Medium | Low]
|
|
179
|
+
- **Impact:** [Critical | High | Medium | Low]
|
|
180
|
+
- **Location:** `path/to/primary-file.ext:line`
|
|
158
181
|
- **Current State:** [Problematic code snippet, file, or pattern description]
|
|
159
182
|
- **Recommendation & Rationale:** [The specific refactor strategy and how it
|
|
160
183
|
improves long-term velocity]
|
|
184
|
+
- **Acceptance signal:** [the command or observable that proves this finding is remediated — e.g. a duplication re-check, `npm test`, or a re-run of this lens]
|
|
161
185
|
- **Agent Prompt:**
|
|
162
186
|
`[A copy-pasteable, highly specific prompt to execute this refactor independently]`
|
|
163
187
|
|
|
@@ -177,3 +201,13 @@ standards.]
|
|
|
177
201
|
|
|
178
202
|
This workflow is **read-only**. Provide the analysis and the roadmap, but do not
|
|
179
203
|
apply changes.
|
|
204
|
+
|
|
205
|
+
## Self-cross-check (mandatory — filter false positives before you finalize)
|
|
206
|
+
|
|
207
|
+
Before you write the report artifact from the previous step, run the shared
|
|
208
|
+
adversarial self-cross-check over your Detailed Findings — see
|
|
209
|
+
[`helpers/audit-self-check.md`](helpers/audit-self-check.md). It defines the
|
|
210
|
+
per-finding evidence bar, the exclusion list, and the final re-open-and-drop
|
|
211
|
+
pass whose `kept <k> / dropped <d>` counts you record in the Executive
|
|
212
|
+
Summary, so the sequential single-pass path filters unverified findings just as
|
|
213
|
+
the orchestrated path's adversarial reviewer does.
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Audit the persistence layer as a first-class artifact — model↔migration↔seed drift, constraint completeness, migration hygiene, type fidelity, and access-pattern fit; gated by a persistence-layer applicability probe so DB-less repos skip cleanly.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Data Model & Persistence Audit
|
|
6
|
+
|
|
7
|
+
## Role
|
|
8
|
+
|
|
9
|
+
Data Modeler & Database Reliability Engineer
|
|
10
|
+
|
|
11
|
+
## Context & Objective
|
|
12
|
+
|
|
13
|
+
Analyze the project's persistence layer — its ORM model definitions, the schema
|
|
14
|
+
migrations those definitions are supposed to produce, and the seed data that
|
|
15
|
+
populates them — as a first-class artifact. Your goal is to find where the
|
|
16
|
+
model, the migrations, and the runtime schema silently disagree, where an
|
|
17
|
+
invariant the application assumes is not actually enforced by a constraint, and
|
|
18
|
+
where a migration is unsafe to run against a live database.
|
|
19
|
+
|
|
20
|
+
This lens is **only applicable to a project that has a persistence layer.** A
|
|
21
|
+
repository with no ORM dependency, no migrations directory, and no tracked
|
|
22
|
+
`.prisma` / `.sql` schema files has nothing for this lens to read: resolve
|
|
23
|
+
**not applicable** and emit the explicit not-applicable report (below) rather
|
|
24
|
+
than empty findings. The applicability probe (`hasPersistenceLayer` in
|
|
25
|
+
[`lib/audit-suite/selector.js`](../scripts/lib/audit-suite/selector.js), gated
|
|
26
|
+
by `target: "data-model"` in
|
|
27
|
+
[`schemas/audit-rules.json`](../schemas/audit-rules.json)) makes this decision
|
|
28
|
+
automatically in `/deliver` and plan-run modes; in a manual invocation you MUST
|
|
29
|
+
make the same determination yourself before reading anything else.
|
|
30
|
+
|
|
31
|
+
## Scope (Story / plan-run mode)
|
|
32
|
+
|
|
33
|
+
When this lens is invoked from `/deliver` close lenses (or a plan-run audit), the
|
|
34
|
+
following block is populated with the Story (or plan-run) change-set file list.
|
|
35
|
+
Otherwise — for any manual `/audit-<dimension>` invocation — the block
|
|
36
|
+
renders the literal substitution token and you MUST treat it as **no
|
|
37
|
+
scope filter — run the lens codebase-wide** exactly as you would have
|
|
38
|
+
before this section existed.
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
{{changedFiles}}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- If the block above contains a newline-delimited list of file paths,
|
|
45
|
+
restrict your analysis to those files (and their direct dependencies
|
|
46
|
+
when the lens explicitly calls for cross-file reasoning).
|
|
47
|
+
- If the block above renders as the literal string `{{changedFiles}}`
|
|
48
|
+
(i.e. no substitution was supplied), ignore this section entirely and
|
|
49
|
+
proceed with the full codebase-wide scan defined in the remaining
|
|
50
|
+
steps.
|
|
51
|
+
|
|
52
|
+
## Execution strategy (dual-path)
|
|
53
|
+
|
|
54
|
+
This lens runs along one of two execution paths (orchestrated dynamic-workflow
|
|
55
|
+
or sequential single-pass). Both emit the **identical** Step 3 report contract;
|
|
56
|
+
downstream consumers (`audit-to-stories`) are agnostic to which path produced
|
|
57
|
+
it. See [`helpers/audit-dual-path.md`](helpers/audit-dual-path.md) for strategy
|
|
58
|
+
selection, the forcing flags, and the read-only guarantee — read `audit-<lens>`
|
|
59
|
+
there as this lens's name.
|
|
60
|
+
|
|
61
|
+
In scoped mode, restrict analysis to the changed models and migrations plus
|
|
62
|
+
their **direct dependents** — a model related to a changed model, a migration
|
|
63
|
+
ordered after a changed one. A Story that adds a destructive migration is the
|
|
64
|
+
canonical routed case: the change set names the migration and the models it
|
|
65
|
+
rewrites, and this lens inspects exactly that surface.
|
|
66
|
+
|
|
67
|
+
## Step 1: Applicability & Persistence-Surface Discovery
|
|
68
|
+
|
|
69
|
+
> Apply [`helpers/parallel-tooling.md`](helpers/parallel-tooling.md) when batching the scan below — independent reads belong in one turn, long shells run via `run_in_background` + `Monitor`.
|
|
70
|
+
|
|
71
|
+
First confirm the project **has a persistence layer** (see Context above). If it
|
|
72
|
+
does not, stop and emit the not-applicable report. If it does, discover the
|
|
73
|
+
persistence surface, preferring **tool-first** detection over hand-reading where
|
|
74
|
+
the consumer ships the tooling:
|
|
75
|
+
|
|
76
|
+
- **ORM drift tooling (preferred):** When the consumer ships an ORM CLI, run its
|
|
77
|
+
read-only drift/status command and treat its output as primary evidence —
|
|
78
|
+
`prisma migrate diff` / `prisma migrate status`, `drizzle-kit check`, or
|
|
79
|
+
`typeorm schema:log`. These report exactly where the model definitions and the
|
|
80
|
+
migration history disagree without a live database.
|
|
81
|
+
- **Read-only file fallback:** When no ORM CLI is present (or it needs a live
|
|
82
|
+
database this audit must not touch), fall back to reading the model
|
|
83
|
+
definitions, the migration files, and the seed scripts directly. This
|
|
84
|
+
fallback is always available and never mutates state.
|
|
85
|
+
- **Model & schema inventory:** Enumerate the ORM model/entity definitions and
|
|
86
|
+
the schema files (`schema.prisma`, `*.sql`, entity classes) they map to.
|
|
87
|
+
- **Migration history:** Enumerate the ordered migration files and note which
|
|
88
|
+
are applied, pending, or manually edited after generation.
|
|
89
|
+
- **Seed & fixture data:** Locate seed scripts and fixtures that assume a
|
|
90
|
+
particular shape, so drift against them surfaces too.
|
|
91
|
+
|
|
92
|
+
## Step 2: Evaluation Dimensions
|
|
93
|
+
|
|
94
|
+
Evaluate the persistence layer along these five dimensions:
|
|
95
|
+
|
|
96
|
+
1. **Model↔migration↔seed drift:** Do the ORM model definitions match the schema
|
|
97
|
+
the migrations actually produce, and do the seeds/fixtures match both? Flag a
|
|
98
|
+
column, index, enum, or relation present in the model but never migrated (or
|
|
99
|
+
migrated but dropped from the model), and seed data that would violate the
|
|
100
|
+
current schema.
|
|
101
|
+
2. **Constraint completeness:** Is every invariant the application code silently
|
|
102
|
+
assumes actually enforced by a constraint? Flag missing foreign-key, unique,
|
|
103
|
+
not-null, and check constraints; stringly-typed columns that should be a
|
|
104
|
+
database enum; orphanable relations with no FK or cascade rule; and
|
|
105
|
+
cascade-delete behavior that is either missing (orphans) or too aggressive
|
|
106
|
+
(unintended wide deletes).
|
|
107
|
+
3. **Migration hygiene:** Is each migration safe to run against a live database?
|
|
108
|
+
Flag irreversible/destructive steps (a `DROP` / data-losing change with no
|
|
109
|
+
documented rollback), non-null columns added without a default or a backfill,
|
|
110
|
+
**expand-contract** violations (a single migration that both adds and removes
|
|
111
|
+
in a way that breaks a rolling deploy), and ordering/idempotency hazards that
|
|
112
|
+
make a migration unsafe to re-run or apply out of order.
|
|
113
|
+
4. **Type fidelity:** Do column types match the domain? Flag money stored as a
|
|
114
|
+
float (rounding loss), timezone-less timestamps, bare-string IDs where a
|
|
115
|
+
typed/UUID column belongs, and over-wide or under-wide numeric types.
|
|
116
|
+
5. **Access-pattern fit:** Does the schema fit how the code queries it? Flag
|
|
117
|
+
unindexed foreign keys and unindexed frequent filter columns, relations that
|
|
118
|
+
force N+1 access, and soft-delete rows that leak through default queries
|
|
119
|
+
because no default scope excludes them.
|
|
120
|
+
|
|
121
|
+
## Step 3: Output Requirements
|
|
122
|
+
|
|
123
|
+
Generate and save a highly structured Markdown audit report to
|
|
124
|
+
`{{auditOutputDir}}/audit-data-model-results.md`, using the exact template
|
|
125
|
+
below.
|
|
126
|
+
|
|
127
|
+
> Grade every finding's severity on the shared
|
|
128
|
+
> [`Critical | High | Medium | Low` scale](helpers/audit-severity-scale.md).
|
|
129
|
+
|
|
130
|
+
When the project **has a persistence layer**, use the findings template:
|
|
131
|
+
|
|
132
|
+
```markdown
|
|
133
|
+
# Data Model & Persistence Audit Report
|
|
134
|
+
|
|
135
|
+
## Executive Summary
|
|
136
|
+
|
|
137
|
+
[Overview of the persistence layer's health, plus the `kept <k> / dropped <d>`
|
|
138
|
+
self-cross-check counts from the mandatory step below.]
|
|
139
|
+
|
|
140
|
+
## Detailed Findings
|
|
141
|
+
|
|
142
|
+
[For every issue identified, use the following strict structure. Lead each
|
|
143
|
+
title with the primary file the issue lives in:]
|
|
144
|
+
|
|
145
|
+
### `path/to/migration-or-model.ext` — [Short title of the issue]
|
|
146
|
+
|
|
147
|
+
- **Dimension:** [e.g., Drift | Constraint Completeness | Migration Hygiene | Type Fidelity | Access-Pattern Fit]
|
|
148
|
+
- **Impact:** [Critical | High | Medium | Low]
|
|
149
|
+
- **Location:** `path/to/migration-or-model.ext:line`
|
|
150
|
+
- **Current State:** [Technical explanation of the drift, missing constraint,
|
|
151
|
+
or unsafe migration step — cite the model definition and the migration it
|
|
152
|
+
disagrees with]
|
|
153
|
+
- **Recommendation & Rationale:** [The specific corrective migration or
|
|
154
|
+
constraint, and the failure it prevents]
|
|
155
|
+
- **Acceptance signal:** [the command or observable that proves this finding is remediated — e.g. `prisma migrate status` clean, a constraint present in the schema, or a re-run of this lens]
|
|
156
|
+
- **Agent Prompt:**
|
|
157
|
+
`[A copy-pasteable, highly specific prompt to execute this fix independently]`
|
|
158
|
+
|
|
159
|
+
## Low-Hanging Fruit
|
|
160
|
+
|
|
161
|
+
- [List up to 3 low-risk schema/constraint fixes that provide immediate safety gains.]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
When the project has **no persistence layer**, emit the explicit
|
|
165
|
+
not-applicable report instead — never empty findings — and stop:
|
|
166
|
+
|
|
167
|
+
```text
|
|
168
|
+
# Data Model & Persistence Audit Report
|
|
169
|
+
|
|
170
|
+
## Executive Summary
|
|
171
|
+
|
|
172
|
+
**Not applicable** — this project has no persistence layer (no ORM dependency,
|
|
173
|
+
no migrations directory, and no tracked `.prisma` / `.sql` schema files), so the
|
|
174
|
+
data-model lens has nothing to inspect and was skipped.
|
|
175
|
+
|
|
176
|
+
## Detailed Findings
|
|
177
|
+
|
|
178
|
+
_None — lens not applicable._
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Constraint
|
|
182
|
+
|
|
183
|
+
This is a **read-only** audit over repo-observable state only — schema files,
|
|
184
|
+
migrations, ORM config, and read-only ORM drift/status commands. It MUST NOT
|
|
185
|
+
connect to, read from, or mutate a production database; it MUST NOT run a
|
|
186
|
+
migration or a destructive ORM command. API-contract/serialization coverage is
|
|
187
|
+
out of scope (deferred `audit-contract-compat` territory), and runtime query
|
|
188
|
+
profiling belongs to `audit-performance`, which owns measured behavior.
|
|
189
|
+
|
|
190
|
+
## Self-cross-check (mandatory — filter false positives before you finalize)
|
|
191
|
+
|
|
192
|
+
Before you write the report artifact from the previous step, run the shared
|
|
193
|
+
adversarial self-cross-check over your Detailed Findings — see
|
|
194
|
+
[`helpers/audit-self-check.md`](helpers/audit-self-check.md). It defines the
|
|
195
|
+
per-finding evidence bar, the exclusion list, and the final re-open-and-drop
|
|
196
|
+
pass whose `kept <k> / dropped <d>` counts you record in the Executive
|
|
197
|
+
Summary, so the sequential single-pass path filters unverified findings just as
|
|
198
|
+
the orchestrated path's adversarial reviewer does.
|