ts-reviewer 3.1.0 → 3.6.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 (57) hide show
  1. package/README.md +148 -43
  2. package/assets/skills/ts-reviewer/SKILL.md +525 -0
  3. package/{ts-reviewer → assets/skills/ts-reviewer}/references/architecture.md +1 -1
  4. package/{ts-reviewer → assets/skills/ts-reviewer}/references/async-patterns.md +11 -5
  5. package/{ts-reviewer → assets/skills/ts-reviewer}/references/boundary-validation.md +4 -1
  6. package/{ts-reviewer → assets/skills/ts-reviewer}/references/code-quality.md +15 -14
  7. package/{ts-reviewer → assets/skills/ts-reviewer}/references/error-handling.md +10 -3
  8. package/assets/skills/ts-reviewer/references/fix-design.md +50 -0
  9. package/{ts-reviewer → assets/skills/ts-reviewer}/references/fix-workflow.md +49 -27
  10. package/assets/skills/ts-reviewer/references/investigate.md +49 -0
  11. package/{ts-reviewer → assets/skills/ts-reviewer}/references/modernization.md +16 -13
  12. package/{ts-reviewer → assets/skills/ts-reviewer}/references/security.md +2 -2
  13. package/assets/skills/ts-reviewer/references/stack-cost.md +55 -0
  14. package/{ts-reviewer → assets/skills/ts-reviewer}/references/tsconfig.md +1 -1
  15. package/{ts-reviewer → assets/skills/ts-reviewer}/references/type-safety.md +11 -12
  16. package/assets/skills/ts-reviewer/tools/build-report.mjs +201 -0
  17. package/assets/skills/ts-reviewer/tools/check-passes.mjs +149 -0
  18. package/assets/skills/ts-reviewer/tools/eslint.config.mjs +21 -0
  19. package/assets/skills/ts-reviewer/tools/lint-pass.mjs +114 -0
  20. package/assets/skills/ts-reviewer/tools/lint-rules.mjs +91 -0
  21. package/assets/skills/ts-reviewer/tools/pass-prompts.mjs +81 -0
  22. package/{ts-reviewer → assets/skills/ts-reviewer}/tools/run-cruise.mjs +1 -1
  23. package/{ts-reviewer → assets/skills/ts-reviewer}/tools/validate-report.mjs +111 -13
  24. package/dist/cli.js +25 -45
  25. package/dist/cli.js.map +1 -1
  26. package/dist/installer/assets.js +53 -0
  27. package/dist/installer/assets.js.map +1 -0
  28. package/dist/installer/frontmatter.js +19 -0
  29. package/dist/installer/frontmatter.js.map +1 -0
  30. package/dist/installer/fsx.js +119 -0
  31. package/dist/installer/fsx.js.map +1 -0
  32. package/dist/installer/index.js +248 -0
  33. package/dist/installer/index.js.map +1 -0
  34. package/dist/installer/ops.js +213 -0
  35. package/dist/installer/ops.js.map +1 -0
  36. package/dist/installer/prompt.js +65 -0
  37. package/dist/installer/prompt.js.map +1 -0
  38. package/dist/installer/providers.js +130 -0
  39. package/dist/installer/providers.js.map +1 -0
  40. package/dist/installer/toml.js +37 -0
  41. package/dist/installer/toml.js.map +1 -0
  42. package/dist/tool.js +16 -0
  43. package/dist/tool.js.map +1 -0
  44. package/package.json +9 -10
  45. package/dist/index.js +0 -24
  46. package/dist/index.js.map +0 -1
  47. package/dist/io.js +0 -21
  48. package/dist/io.js.map +0 -1
  49. package/dist/paths.js +0 -50
  50. package/dist/paths.js.map +0 -1
  51. package/dist/prompt.js +0 -58
  52. package/dist/prompt.js.map +0 -1
  53. package/ts-reviewer/SKILL.md +0 -386
  54. /package/{ts-reviewer → assets/skills/ts-reviewer}/references/dependency-hygiene.md +0 -0
  55. /package/{ts-reviewer → assets/skills/ts-reviewer}/tools/classify-run.mjs +0 -0
  56. /package/{ts-reviewer → assets/skills/ts-reviewer}/tools/co-change.mjs +0 -0
  57. /package/{ts-reviewer → assets/skills/ts-reviewer}/tools/discover-projects.mjs +0 -0
package/README.md CHANGED
@@ -6,13 +6,28 @@ Built for one fixed stack — **TypeScript 5.9.x, ES2024, Node 24** — without
6
6
 
7
7
  ## What It Does
8
8
 
9
- Three modes, one skill:
9
+ Four modes, one skill:
10
10
 
11
11
  | Mode | What happens |
12
12
  |---|---|
13
13
  | **scan** | Analyzes the codebase and writes a prioritized report to `code-smells/report.md` |
14
+ | **investigate** | Reads the report and decides, from tests, git history, decision records, and callers, whether each finding is a real defect or deliberate. Changes no code |
14
15
  | **fix** | Reads the report and applies fixes file-by-file with tsc/lint/test verification |
15
- | **auto** | Runs scan, asks you to confirm, fixes everything, deletes the report if clean |
16
+ | **auto** | Runs scan, investigates, asks you to confirm, fixes everything, deletes the report if clean |
17
+
18
+ ## What's New
19
+
20
+ **3.6.0 — install once for every project.** `npx ts-reviewer@latest install` asks whether to install globally or into the project, and `update` brings every install to the latest version without questions. Antigravity is no longer a target.
21
+
22
+ **3.5.0 — pick what runs, and sturdier large runs.** `--domains security,boundary-validation` runs only those domains, and `--pick` asks you in a multi-select. The skill lint drops findings outside the pick, and skips itself when no picked domain owns a lint line. A new module, such as a future framework checklist, joins the menu through its `pass_groups` row. From a run on a 98-file monorepo: a database row typed by a generic and an untyped `JSON.parse` now grade High, a Next.js package is out of scope, `tools/check-passes.mjs` repairs and checks the pass files before the merge, every pass gets a fresh agent, and every Recurring Pattern row lists its sites. The main agent now writes 1 pass plan and its decisions, and 2 tools write the pass prompts and the report: on the recall corpus the main agent spends 35% less, on the monorepo 37% less, and every report validates on the first try.
23
+
24
+ **3.4.0 — a cheaper scan.** A pinned ESLint + typescript-eslint config now runs inside the scan (1 approval, through `npx`), and the 49 checklist lines it decides by rule leave the AI passes. A default scan runs 5 pass groups instead of 9 domain passes, the async and error group reads only the files that can hold its patterns, and the config and dependency group reads no `.ts` file. The pass model is yours to choose once per project. The report format is unchanged. Measured on a 98-file monorepo, the scan spent 8.6% less and finished 10 minutes sooner with the skill lint. On the recall corpus in `fixtures/recall-corpus/`, Sonnet passes halved what the passes cost and kept every High and Highest finding.
25
+
26
+ **3.3.0 — investigate mode.** Before a fix changes flagged code, the skill now checks whether the pattern is there on purpose: a test that pins it, a commit message that explains it, an ADR that decides it. Deliberate code is left alone and gets a `// Deliberate:` comment citing the evidence, so the next scan does not flag it again. See [Investigate](#investigate--why-is-this-code-this-way).
27
+
28
+ **3.2.0 — hot paths.** Mark performance-critical code with `/** @hotpath */`. A fix that would add an allocation, a validation, or an extra pass there is redesigned to pay that cost outside the hot path, or handed to you as a choice when it cannot be. See [Hot paths](#hot-paths--hotpath).
29
+
30
+ Both are optional: a project with no `@hotpath` markers, no tests, and no history gets today's behaviour plus 1 verdict line per finding.
16
31
 
17
32
  The review covers nine domains by default, each with its own detailed checklist. Add `--arch` or `--full` to include architecture analysis:
18
33
 
@@ -33,40 +48,58 @@ The review covers nine domains by default, each with its own detailed checklist.
33
48
 
34
49
  ### Install with npx
35
50
 
36
- From the root of the project where you want to install the skill:
37
-
38
51
  ```bash
39
- npx ts-reviewer
52
+ npx ts-reviewer@latest install
40
53
  ```
41
54
 
42
- The installer prints a short summary before installation:
55
+ It asks where to install and for which AI agents: Up/Down to move, Space to toggle, Enter to confirm. Pick **Global** once and the skill works in every project you open, with nothing added to the project.
56
+
57
+ | AI agent | Global | Project |
58
+ |---|---|---|
59
+ | Claude Code | `~/.claude/skills/ts-reviewer/` | `.claude/skills/ts-reviewer/` |
60
+ | Codex | `~/.agents/skills/ts-reviewer/` | `.agents/skills/ts-reviewer/` |
61
+
62
+ `CLAUDE_CONFIG_DIR` and `CODEX_HOME` move the global targets, as they do for the agents themselves.
43
63
 
44
- ```text
45
- TypeScript Code Reviewer
46
- Checks: type safety, security, async patterns, boundary validation, error handling, modernization, code quality, tsconfig, dependency hygiene
47
- Target stack: TypeScript 5.9.x, ES2024, Node 24
64
+ ```bash
65
+ npx ts-reviewer@latest update # every install, same place and agents, no questions
66
+ npx ts-reviewer@latest status # installed version, newer one on npm, changed files
67
+ npx ts-reviewer@latest uninstall
48
68
  ```
49
69
 
50
- Then it asks which AI agents to install for. Use Up/Down arrows to move, Space to toggle, and Enter to confirm.
70
+ Keep `@latest`: without it `npx` may run a copy it cached earlier. `update` refuses to replace a newer install with that older copy unless you pass `--force`.
51
71
 
52
- Supported targets:
72
+ Without a terminal (CI, an AI agent, Git Bash under MinTTY) nothing is asked and flags decide:
53
73
 
54
- | AI agent | Install path |
55
- |---|---|
56
- | Claude Code | `.claude/skills/ts-reviewer/` |
57
- | Codex | `.agents/skills/ts-reviewer/` |
58
- | Antigravity | `.agent/skills/ts-reviewer/` |
74
+ ```bash
75
+ npx ts-reviewer@latest install --global --agents claude-code,codex --yes
76
+ ```
59
77
 
60
- > **Note on Codex:** project-local skills belong in `.agents/` per the Codex docs; `~/.codex/` is the *global* per-user directory. Codex also reads a project-local `.codex/` implicitly, so installs from older versions of this installer keep working — but `.agents/` is the correct location going forward.
78
+ `--dry-run` prints the plan and changes nothing. Each install records what it wrote in `.ai-tools/ts-reviewer.json` (in the home directory or the project root): `update` uses it, removes files the new version no longer ships, and keeps a file you edited unless you pass `--force`.
61
79
 
62
- In non-interactive terminals, the installer selects all supported targets.
80
+ > **From 3.5.0 and earlier:** `npx ts-reviewer` with no command now prints help, and Antigravity is no longer a target. A copy an older version put in a project (`.claude/`, `.agents/` or `.agent/skills/ts-reviewer/`) is not tracked: delete it by hand.
63
81
 
64
82
  ### Manual Install
65
83
 
66
- You can still copy the `ts-reviewer/` folder directly into the skill directory for your AI agent.
84
+ You can still copy the `assets/skills/ts-reviewer/` folder directly into the skill directory for your AI agent.
67
85
 
68
86
  ## Usage
69
87
 
88
+ The usual workflow is 3 requests in 1 session, or 1 request in auto mode:
89
+
90
+ ```
91
+ Review my TypeScript code → code-smells/report.md
92
+ Investigate the report → 1 Verdict line per finding, no code change
93
+ Fix the report → fixes, comments on deliberate code, audit trail
94
+ ```
95
+ ```
96
+ Review and fix my TypeScript code → all of the above, with 1 confirmation before the fix
97
+ ```
98
+
99
+ Read the report between the steps: it is the work plan, and you can delete findings or edit a verdict before fix runs. Investigate is optional — `Fix the report` straight after a scan works as in earlier versions.
100
+
101
+ You do not start any sub-agents yourself. The scan launches its own analysis passes as sub-agents (`--agents N`, default 3); investigate and fix run in the main agent.
102
+
70
103
  ### Scan — find issues
71
104
 
72
105
  Just ask Claude to review your code:
@@ -86,6 +119,12 @@ With Architecture active, the same directory also holds project discovery, Knip,
86
119
 
87
120
  The analysis passes run in waves. `--agents N` sets how many run at once (default 3; `--agents 1` runs them one at a time in the main agent). Each pass writes its own findings file under `code-smells/passes/`, and the queue in `code-smells/passes/queue.md` tracks which passes are done, so an interrupted scan does not lose finished work.
88
121
 
122
+ The scan also runs a skill lint: a pinned ESLint + typescript-eslint config (`assets/skills/ts-reviewer/tools/eslint.config.mjs`), through `npx -y eslint@10 typescript-eslint@8 typescript@5.9`, after 1 approval. The checklist lines it decides by rule are marked `lint-owned` in the references, its findings land in the report like any pass, and the AI passes skip those lines. Declined or failed, the scan falls back to the passes for every line. Your project's own linter still runs as before.
123
+
124
+ The main agent writes its decisions, not the report: `tools/pass-prompts.mjs` fills the pass prompts from 1 plan, and `tools/build-report.mjs` applies the deduplication, merge, Recurring Pattern, and sorting steps to the pass files and renders the report, which `validate-report.mjs` then checks.
125
+
126
+ The passes run in groups: Type Safety with Boundary Validation, Async Patterns with Error Handling, Config with Dependency Hygiene, Modernization with Code Quality, and Security and Architecture alone.
127
+
89
128
  #### Domain flags
90
129
 
91
130
  By default, only the nine core domains run. Use flags to control which domains are active:
@@ -96,6 +135,8 @@ By default, only the nine core domains run. Use flags to control which domains a
96
135
  | `--arch` | Architecture only (shallow modules, coupling, dependency direction, seams) |
97
136
  | `--full` | All ten domains |
98
137
  | `--no-arch` | The nine core domains — overrides `--arch`, `--full`, and any phrase that would enable architecture |
138
+ | `--domains <slugs>` | Only the named domains, by slug (`security`, `type-safety`, `boundary-validation`, ...) or by pass group (`type-safety+boundary-validation`). `--no-arch` still removes Architecture |
139
+ | `--pick` | Asks which pass groups to run, in a multi-select (a numbered list on Codex). No answer runs the default set |
99
140
 
100
141
  Examples:
101
142
 
@@ -123,7 +164,7 @@ Apply fixes from code-smells/report.md
123
164
  The fix workflow:
124
165
  1. Parses the report as a work plan
125
166
  2. Runs existing tests to capture a baseline (knows what was already failing)
126
- 3. Fixes issues file-by-file, writes regression tests, runs `tsc` after each file
167
+ 3. Fixes issues file-by-file, writes regression tests, runs `tsc` after each file. A finding investigate called deliberate gets at most a comment; a fix on a hot path is redesigned first (see [Hot paths](#hot-paths--hotpath))
127
168
  4. Runs linter, fixes lint errors
128
169
  5. Runs full test suite, compares with baseline, fixes any regressions it caused
129
170
  6. Repeats verification up to 5 iterations
@@ -140,7 +181,43 @@ Review and fix my TypeScript code
140
181
  Auto-fix code smells
141
182
  ```
142
183
 
143
- Runs scan, shows you the summary, asks if you want to proceed with fixes, then runs the full fix cycle. If everything is clean afterward, the report is deleted.
184
+ Runs scan, investigates every finding, shows you the summary, asks if you want to proceed with fixes, then runs the full fix cycle. If everything is clean afterward, the report is deleted.
185
+
186
+ ### Investigate — why is this code this way?
187
+
188
+ ```
189
+ Investigate the report
190
+ ```
191
+ ```
192
+ Investigate the ts-reviewer report: which findings are deliberate?
193
+ ```
194
+
195
+ Run it after a scan, before fix. It needs `code-smells/report.md`, and it works best in a git repository with real commit messages and a test suite — those are its evidence.
196
+
197
+ Before a fix changes flagged code, investigate asks whether the pattern is there on purpose. For each finding in `code-smells/report.md` it reads 5 sources, cheapest first, and stops at the first that names the flagged behaviour: a comment at the site, a test that calls the function, the commit that introduced the exact lines (`git log -L`), a decision record (`docs/adr/`, `ARCHITECTURE.md`, ...), and the callers. It writes 1 `**Verdict:**` line per finding with a pointer to that source, and changes no code.
198
+
199
+ | Verdict | Decided by | What fix mode does |
200
+ |---|---|---|
201
+ | `defect` | a test, a record, or a caller shows the failure | fixes it as reported |
202
+ | `deliberate-recorded` | a decision record names the behaviour as wanted | no change, `[SKIPPED: deliberate, <pointer>]` |
203
+ | `deliberate-unrecorded` | a test or a commit message names it as wanted, and nothing at the site does | adds `// Deliberate: <behaviour>. Evidence: <pointer>.` above the line, no other change |
204
+ | `unreachable` | every caller is known, and none reaches the failure | fixes it when the fix is free; on a hot path a costly fix is skipped without asking |
205
+ | `unknown` | no source decides | fixes it as today; the verdict tells you the fix rests on no evidence |
206
+
207
+ A commit message counts only when it names the behaviour ("wip" does not), and a test is read before the history, so a test that asserts the opposite wins. The comment a `deliberate-unrecorded` verdict leaves is what makes the next scan drop the finding.
208
+
209
+ ### Hot paths — `@hotpath`
210
+
211
+ Some correct fixes are the wrong default in a frame loop or a message handler: `toSorted()` allocates on every call, a schema parse validates every message. Mark such code with a JSDoc tag:
212
+
213
+ ```typescript
214
+ /** @hotpath */
215
+ export function updateFrame(entities: Entity[], dt: number): void { /* ... */ }
216
+ ```
217
+
218
+ The tag is optional. `@hotpath` on a function, method, or class covers its body; in a file's leading comment it covers the whole file. Without any marker, only loop bodies and iteration callbacks (`map`, `forEach`, `sort`, ...) count as hot. A project running `eslint-plugin-jsdoc` with `check-tag-names` has to declare `hotpath` in `definedTags`.
219
+
220
+ A finding on a hot path whose fix adds a per-call cost carries a `**Hot path:**` line in the report. Fix mode does not apply such a fix as written: it walks a ladder of 7 rungs — remove the case through types, move the cost to the boundary, hoist it, reuse a module-owned buffer, check it in development builds only, split off the common case — and applies the first that closes the finding. When none does (rung 7), the code stays untouched and you are shown both variants: the reported fix with its cost, and the current code with its defect. You pick one; with no answer the entry is recorded as `[SKIPPED: rung 7 <kind>]`. A `bench` or `benchmark` script in `package.json` is run before and after, and both numbers go on every designed fix.
144
221
 
145
222
  ## Scope Modes
146
223
 
@@ -183,27 +260,31 @@ AGENTS.md # How to edit the review rules — read be
183
260
  CLAUDE.md # Pointer to AGENTS.md, picked up automatically by Claude Code
184
261
 
185
262
  src/ # npm/npx installer source
186
- ├── cli.ts # CLI entrypoint and provider prompt
187
- ├── prompt.ts # raw-mode keyboard multi-select
188
- └── paths.ts # target directories and skill asset loading
263
+ ├── cli.ts # CLI entrypoint: install, update, status, uninstall
264
+ ├── tool.ts # Tool name and version, read from package.json
265
+ └── installer/ # Copied from ts-ai-tool-template: fix it there, then copy the folder over
189
266
 
190
267
  cnlp/ # the CNL-P format the skill files are written in
191
268
  ├── cnlp-format.md # the standard: forms, line rules, lexicon
192
269
  ├── cnlp.js # the checker — Node builtins only, no dependencies
193
270
  ├── skill-format.test.js # the conformance test, run by `npm test`
194
271
  └── profiles/ # what each kind of document may contain
195
- ├── skill.md # → ts-reviewer/SKILL.md
196
- ├── reference.md # → ts-reviewer/references/*.md
272
+ ├── skill.md # → assets/skills/ts-reviewer/SKILL.md
273
+ ├── reference.md # → assets/skills/ts-reviewer/references/*.md
197
274
  ├── guide.md # → AGENTS.md
198
275
  └── profile.md # → the profiles themselves
199
276
 
200
- ts-reviewer/
277
+ assets/skills/ts-reviewer/ # What the installer copies
201
278
  ├── SKILL.md # Main skill file — mode routing, workflow orchestration
202
- ├── tools/ # Mechanical pre-pass and report validator — plain Node, no dependencies
279
+ ├── tools/ # Mechanical steps of the scan — plain Node, no dependencies
203
280
  │ ├── discover-projects.mjs # Finds the TypeScript projects and their source roots
204
281
  │ ├── co-change.mjs # Git co-change pairs across directory boundaries
205
282
  │ ├── run-cruise.mjs # dependency-cruiser graphs, metrics, and Mermaid diagrams per project
206
283
  │ ├── classify-run.mjs # Reads a tool run by its output, not its exit code
284
+ │ ├── eslint.config.mjs, lint-rules.mjs, lint-pass.mjs # The skill lint and its pass file
285
+ │ ├── pass-prompts.mjs # Writes the pass queue and 1 filled prompt per pass
286
+ │ ├── check-passes.mjs # Repairs and checks the pass files before the merge
287
+ │ ├── build-report.mjs # Applies the merge steps and renders code-smells/report.md
207
288
  │ └── validate-report.mjs # Checks code-smells/report.md against the report contract
208
289
  └── references/
209
290
  ├── type-safety.md # Checklist: any, unknown, casts, !, exhaustiveness, branded types
@@ -216,10 +297,18 @@ ts-reviewer/
216
297
  ├── tsconfig.md # Checklist: strict flags, target/lib, module resolution, deprecated
217
298
  ├── dependency-hygiene.md # Checklist: lockfiles, versions, npm audit, dependency choice
218
299
  ├── architecture.md # Checklist: shallow modules, coupling, dependency direction, seams
219
- └── fix-workflow.md # Complete fix protocol: tests, verification, rollback
300
+ ├── fix-workflow.md # Complete fix protocol: tests, verification, rollback
301
+ ├── fix-design.md # Stack-free ladder for designing a fix on a hot path
302
+ ├── stack-cost.md # The @hotpath marker, cost kinds, rung forms, bench command, evidence sources
303
+ └── investigate.md # Stack-free verdicts: why flagged code is the way it is
304
+
305
+ docs/ # design proposals behind each feature, with their decisions
306
+ fixtures/ # throwaway projects + answer keys the features were tested against (unpublished)
307
+ ├── cost-corpus/ # → hot paths, 3.2.0
308
+ └── intent-corpus/ # → investigate, 3.3.0
220
309
  ```
221
310
 
222
- **SKILL.md** is the orchestrator — it routes between scan/fix/auto modes, detects domain flags (`--arch`, `--full`), defines scope detection, severity scale, and report format.
311
+ **SKILL.md** is the orchestrator — it routes between scan/investigate/fix/auto modes, detects domain flags (`--arch`, `--full`), defines scope detection, severity scale, and report format.
223
312
 
224
313
  **Reference files** contain the detailed checklists and protocols. Each analysis agent reads only the reference file relevant to its domain, keeping context focused. Architecture analysis is opt-in and loaded only when the domain is active.
225
314
 
@@ -247,25 +336,34 @@ The test catches a check line that lost its severity, a block the profile does n
247
336
 
248
337
  ### Scan mode
249
338
 
250
- 1. **Discovery** — detects domain flags, maps the project, reads tsconfig.json, detects linter and test runner, and asks once before downloading a missing architecture tool.
251
- 2. **Diagnostics** — runs `tsc --noEmit`, linter, and LSP diagnostics (if available); compiler and linter output is cached under `code-smells/passes/` and reused on a resume of the same commit.
339
+ 1. **Discovery** — detects domain flags, maps the project, reads tsconfig.json, detects linter and test runner, asks the pass model once per project, and asks once before downloading the skill lint or a missing architecture tool.
340
+ 2. **Diagnostics** — runs `tsc --noEmit`, the project linter, the skill lint, and LSP diagnostics (if available). The skill lint's findings become the pass `lint-skill`; compiler and linter output is cached under `code-smells/passes/` and reused on a resume of the same commit.
252
341
  3. **Architecture pre-pass** — when active, writes bounded Knip, graph, metric, co-change, rule, and Mermaid artifacts under `code-smells/`, with project coverage and bounded failure diagnostics.
253
- 4. **Analysis** — specialized passes judge the candidates against the active checklists, running in waves of `--agents` at a time; each pass writes its own `code-smells/passes/<id>.jsonl`, and `passes/queue.md` marks which are done, so a stopped run resumes from the last checkpoint. Tool output is never a finding by itself.
342
+ 4. **Analysis** — specialized passes, 1 per group of domains, judge the candidates against the active checklists, skipping the lines the skill lint owns, running in waves of `--agents` at a time; each pass writes its own `code-smells/passes/<id>.jsonl`, and `passes/queue.md` marks which are done, so a stopped run resumes from the last checkpoint. Tool output is never a finding by itself.
254
343
  5. **Report** — deduplicates, applies severity boost (scoped modes), consolidates recurring patterns, enforces a noise budget, writes `code-smells/report.md`, and validates its contract before the scan succeeds. Architecture findings appear in a separate `## Architecture Opportunities` section at the end.
255
344
 
256
- Validate a report directly with `node ts-reviewer/tools/validate-report.mjs --repo . --report code-smells/report.md`. It checks headings, counts, finding anchors, architecture fields, and linked artifacts without adding a dependency. An **error** is a defect of the report that rewriting it fixes; a **warning** names an outcome of the mechanical pre-pass — a graph with no diagram, say — that the report cannot fix, and warnings do not fail the run.
345
+ Validate a report directly with `node ts-reviewer/tools/validate-report.mjs --repo . --report code-smells/report.md`. It checks headings, counts, finding anchors, architecture fields, and linked artifacts without adding a dependency, and it reads both the scan report and the audit trail a fix run leaves in its place. An **error** is a defect of the report that rewriting it fixes; a **warning** names an outcome of the mechanical pre-pass — a graph with no diagram, say — that the report cannot fix, and warnings do not fail the run.
346
+
347
+ ### Investigate mode
348
+
349
+ 1. Reads `references/investigate.md` and the evidence locations in `references/stack-cost.md`
350
+ 2. For each `###` finding, reads the sources in order — site comment, tests, `git log -L` on the exact lines, decision records, callers — and stops at the first that names the flagged behaviour
351
+ 3. Writes `**Verdict:** <verdict> | **Evidence:** <source> <pointer>` into the entry, and validates the report
352
+ 4. Changes no source file: `git diff` is the same before and after
257
353
 
258
354
  ### Fix mode
259
355
 
260
356
  1. Validates `code-smells/report.md` and stops before changing code when the report is invalid
261
357
  2. Parses the report as the work plan
262
- 3. Captures test baseline (runs tests before changes)
263
- 4. Applies fixes bottom-to-top within each file (so line numbers don't shift)
264
- 5. Writes regression tests for each testable fix
265
- 6. Runs `tsc --noEmit` after each file
266
- 7. Runs the full verification loop: tsc + linter + test suite (max 5 iterations)
267
- 8. Compares test results with baseline — only fixes regressions it caused
268
- 9. Updates or deletes the report, keeps the remaining `code-smells/` artifacts, and asks before removing them
358
+ 3. Captures test baseline (runs tests before changes), and the `bench` script when a finding is on a hot path
359
+ 4. Closes deliberate findings first: no change for `deliberate-recorded`, 1 `// Deliberate:` comment for `deliberate-unrecorded`
360
+ 5. Applies fixes bottom-to-top within each file (so line numbers don't shift); a fix on a hot path goes through the 7-rung design first
361
+ 6. Writes regression tests for each testable fix
362
+ 7. Runs `tsc --noEmit` after each file
363
+ 8. Runs the full verification loop: tsc + linter + test suite (max 5 iterations)
364
+ 9. Compares test results with baseline — only fixes regressions it caused
365
+ 10. Shows you the rung 7 choices, runs the `bench` script again, and writes both numbers on every designed fix
366
+ 11. Updates or deletes the report, keeps the remaining `code-smells/` artifacts, and asks before removing them
269
367
 
270
368
  ## Tips
271
369
 
@@ -275,9 +373,15 @@ Validate a report directly with `node ts-reviewer/tools/validate-report.mjs --re
275
373
 
276
374
  - **Claude Code users** — `CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS` in `settings.json` under `env` caps sub-agents for every session on the host. It is independent of `--agents`, which caps one review run and works in every supported agent.
277
375
 
376
+ - **Pick the pass model once** — the first scan asks which model and effort the analysis passes use, and writes the answer to `.claude/agents/ts-reviewer-scout.md` (Claude Code: `model`, `effort`) or `.codex/agents/ts-reviewer-scout.toml` (Codex: `model`, `model_reasoning_effort`). A smaller model there, for example Sonnet at `high`, costs less, while the main agent keeps verifying every finding. Delete the file to be asked again, or pass `--scout <model>` for 1 run. Architecture always runs on the main agent's model.
377
+
278
378
  - **Commit before running fix** — so you can `git diff` to review changes and `git checkout -- .` to revert if needed.
279
379
 
280
- - **Edit the report before fix** — since fix uses `code-smells/report.md` as its work plan, you can delete issues you don't want fixed, change severities, or add notes before running fix.
380
+ - **Edit the report before fix** — since fix uses `code-smells/report.md` as its work plan, you can delete issues you don't want fixed, change severities, change a `Verdict` line, or add notes before running fix.
381
+
382
+ - **Leave evidence of intent** — a test that asserts the behaviour, a commit message that names it, or an ADR in `docs/adr/` is what investigate reads. A code comment at the site is the strongest: the scan drops the finding outright.
383
+
384
+ - **Mark hot paths once** — `/** @hotpath */` on a frame loop, parser, or message handler keeps every future fix there allocation-aware. Unmarked loops are still treated as possibly hot.
281
385
 
282
386
  - **Scoped review for PRs** — `"review my branch against main"` is the most practical mode for day-to-day use. Full codebase audits are better suited for periodic health checks.
283
387
 
@@ -286,6 +390,7 @@ Validate a report directly with `node ts-reviewer/tools/validate-report.mjs --re
286
390
  - TypeScript 5.9.x project targeting ES2024 on Node 24
287
391
  - Git repository (for scoped modes and safe revert during fix)
288
392
  - Node 24 with `npx` available (for tsc, linter)
393
+ - Optional: a `bench` or `benchmark` script in `package.json`, for before/after numbers on hot-path fixes
289
394
  - Claude Code (recommended) or any Claude interface with skill support
290
395
 
291
396
  ## License