mandrel 2.4.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.
Files changed (65) hide show
  1. package/.agents/audit-checklists/accessibility.md +29 -0
  2. package/.agents/audit-checklists/architecture.md +4 -5
  3. package/.agents/audit-checklists/clean-code.md +10 -0
  4. package/.agents/audit-checklists/data-model.md +22 -0
  5. package/.agents/audit-checklists/dependencies.md +11 -2
  6. package/.agents/audit-checklists/devops.md +4 -0
  7. package/.agents/audit-checklists/navigability.md +3 -0
  8. package/.agents/audit-checklists/performance.md +8 -11
  9. package/.agents/audit-checklists/privacy.md +3 -4
  10. package/.agents/audit-checklists/quality.md +2 -0
  11. package/.agents/audit-checklists/security.md +4 -5
  12. package/.agents/audit-checklists/seo.md +7 -1
  13. package/.agents/audit-checklists/sre.md +14 -12
  14. package/.agents/audit-checklists/ux-ui.md +4 -0
  15. package/.agents/docs/configuration.md +3 -0
  16. package/.agents/docs/workflows.md +4 -3
  17. package/.agents/schemas/agentrc.schema.json +17 -0
  18. package/.agents/schemas/audit-rules.json +134 -19
  19. package/.agents/schemas/audit-rules.schema.json +6 -2
  20. package/.agents/scripts/audit-labels-bootstrap.js +4 -4
  21. package/.agents/scripts/audit-to-stories.js +244 -19
  22. package/.agents/scripts/lib/audit-suite/checklist-threading.js +26 -3
  23. package/.agents/scripts/lib/audit-suite/dispatch-checklist.js +132 -0
  24. package/.agents/scripts/lib/audit-suite/index.js +1 -0
  25. package/.agents/scripts/lib/audit-suite/selector.js +290 -14
  26. package/.agents/scripts/lib/audit-to-stories/audit-lenses.js +2 -1
  27. package/.agents/scripts/lib/audit-to-stories/build-story-body.js +5 -1
  28. package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +23 -3
  29. package/.agents/scripts/lib/audit-to-stories/finding-adapter.js +38 -0
  30. package/.agents/scripts/lib/audit-to-stories/ledger.js +256 -0
  31. package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +41 -7
  32. package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +20 -2
  33. package/.agents/scripts/lib/command-header.js +1 -1
  34. package/.agents/scripts/lib/config-settings-schema-delivery.js +21 -0
  35. package/.agents/scripts/lib/dynamic-workflow/performance-report-contract.js +5 -3
  36. package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +56 -0
  37. package/.agents/scripts/lib/findings/route-finding.js +108 -10
  38. package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +81 -1
  39. package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +1 -0
  40. package/.agents/scripts/nav-registry-diff.js +449 -0
  41. package/.agents/workflows/audit-accessibility.md +243 -0
  42. package/.agents/workflows/audit-architecture.md +89 -71
  43. package/.agents/workflows/audit-clean-code.md +87 -53
  44. package/.agents/workflows/audit-data-model.md +198 -0
  45. package/.agents/workflows/audit-dependencies.md +143 -28
  46. package/.agents/workflows/audit-devops.md +109 -18
  47. package/.agents/workflows/audit-documentation.md +25 -53
  48. package/.agents/workflows/audit-navigability.md +78 -22
  49. package/.agents/workflows/audit-performance.md +207 -103
  50. package/.agents/workflows/audit-privacy.md +51 -13
  51. package/.agents/workflows/audit-quality.md +71 -61
  52. package/.agents/workflows/audit-security.md +94 -71
  53. package/.agents/workflows/audit-seo.md +80 -25
  54. package/.agents/workflows/audit-sre.md +99 -66
  55. package/.agents/workflows/audit-to-stories.md +44 -5
  56. package/.agents/workflows/audit-ux-ui.md +71 -17
  57. package/.agents/workflows/helpers/audit-dual-path.md +59 -0
  58. package/.agents/workflows/helpers/audit-self-check.md +70 -0
  59. package/.agents/workflows/helpers/audit-severity-scale.md +19 -0
  60. package/.agents/workflows/helpers/deliver-story.md +25 -0
  61. package/docs/CHANGELOG.md +16 -0
  62. package/package.json +1 -1
  63. package/.agents/audit-checklists/lighthouse.md +0 -15
  64. package/.agents/schemas/audit-results.schema.json +0 -69
  65. 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. Both emit the **identical**
22
- report contract (Step 3); downstream consumers (`audit-to-stories`) are agnostic to which path produced it.
23
-
24
- - **Orchestrated (dynamic-workflow) path.** When Claude Code's
25
- [dynamic workflows](https://code.claude.com/docs/en/workflows) are
26
- available, the saved project workflow
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
- Evaluate the gathered context against the following clean code dimensions:
140
-
141
- 1. **Over-Engineering & Abstractions:** Identify "dry-run" complexity, premature
142
- optimizations, or interfaces/classes that add boilerplate without clear value
143
- (e.g., interfaces with only one implementation).
144
- 2. **Cognitive Load & Nesting:** Pinpoint deeply nested logic (arrow code),
145
- massive functions violating the Single Responsibility Principle (SRP), or
146
- excessive cyclomatic complexity.
147
- 3. **Dead Code & Redundancy:** Locate unused exports, redundant utility
148
- functions that duplicate standard library features, or obsolete commented-out
149
- code blocks.
150
- 4. **Naming & Self-Documentation:** Find poorly named variables/functions,
151
- inconsistent naming conventions, or areas that rely heavily on comments to
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
- 7. **Automated Architecture Guardrails:** Assess whether the project encodes
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 Title of the Issue]
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. Both emit the **identical**
42
- report contract (Step 3); downstream consumers (`audit-to-stories`) are agnostic to which path produced it.
43
-
44
- - **Orchestrated (dynamic-workflow) path.** When Claude Code's
45
- [dynamic workflows](https://code.claude.com/docs/en/workflows) are
46
- available, the saved project workflow
47
- `.claude/workflows/audit-clean-code.workflow.js` fans the dimensions below
48
- out as parallel read-only subagents, runs an **adversarial cross-check**
49
- stage (an independent agent reviews each dimension's findings and drops
50
- false positives before they enter the report), then synthesises the Step 3
51
- report. The orchestrator derives its per-dimension prompts from *this*
52
- markdown at run time the lens stays the single source of truth; the
53
- script does not fork a second copy of the spec.
54
- - **Sequential (single-pass) path.** When dynamic workflows are unavailable,
55
- follow Steps 1–3 below turn-by-turn exactly as before. This is the default
56
- fallback and changes nothing about the existing behaviour.
57
-
58
- **Strategy selection** is computed by
59
- [`lib/dynamic-workflow/capability.js`](../scripts/lib/dynamic-workflow/capability.js)
60
- (`selectAuditStrategy`). The orchestrated path is chosen only when the runtime
61
- is Claude Code, `disableWorkflows` is not set (settings.json **or**
62
- `CLAUDE_CODE_DISABLE_WORKFLOWS`), and the Claude Code version meets the
63
- research-preview floor (`>= 2.1.154`). Any other runtime, a disabled setting,
64
- or an older version degrades gracefully to the sequential path.
65
-
66
- > **Capability degradation, not a contract shim.** This dual path is **not**
67
- > covered by the No-Shim / hard-cutover rule in
68
- > [`git-conventions.md`](../rules/git-conventions.md). That rule forbids
69
- > running two shapes of the *same contract* side by side. Here there is **one**
70
- > report contract; only the *execution strategy* is selected from a runtime
71
- > capability — the same pattern the protocol already endorses for live-docs
72
- > fallback in [`instructions.md` §1.C/§1.D](../instructions.md). The full
73
- > capability-degradation rationale lives in the
74
- > [`capability.js`](../scripts/lib/dynamic-workflow/capability.js) module
75
- > docstring; the orchestrated-run evidence and per-lens cost/precision gate
76
- > verdicts live in [`docs/roadmap.md`](../../docs/roadmap.md) (Part 3 —
77
- > Dynamic-Workflow Orchestration).
78
-
79
- **Forcing a path (for testing).** Set `MANDREL_AUDIT_STRATEGY=sequential` to
80
- verify the fallback path with the feature notionally disabled, or
81
- `MANDREL_AUDIT_STRATEGY=orchestrated` to pin the dynamic path. To exercise the
82
- real disable signals instead, set `CLAUDE_CODE_DISABLE_WORKFLOWS=1` (env) or
83
- `disableWorkflows: true` in `.claude/settings.json` and re-run the lens both
84
- degrade to the sequential path.
85
-
86
- > **Read-only on both paths.** The lens is read-only (see Constraint). The
87
- > orchestrated subagents run in `acceptEdits` and inherit the session tool
88
- > allowlist, but the workflow script grants the analysis agents only
89
- > read/search tools (`Read`, `Grep`, `Glob`) no write/edit/shell-mutation
90
- > tools. The single write in an orchestrated run is the final report artifact.
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 Title of the Issue]
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.