feed-the-machine 1.5.0 → 1.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.
- package/LICENSE +21 -21
- package/README.md +170 -170
- package/bin/generate-manifest.mjs +463 -463
- package/bin/install.mjs +491 -491
- package/docs/HOOKS.md +243 -243
- package/docs/INBOX.md +233 -233
- package/ftm/SKILL.md +122 -122
- package/ftm-audit/SKILL.md +623 -541
- package/ftm-audit/references/protocols/PROJECT-PATTERNS.md +91 -91
- package/ftm-audit/references/protocols/RUNTIME-WIRING.md +66 -66
- package/ftm-audit/references/protocols/WIRING-CONTRACTS.md +135 -135
- package/ftm-audit/references/strategies/AUTO-FIX-STRATEGIES.md +69 -69
- package/ftm-audit/references/templates/REPORT-FORMAT.md +96 -96
- package/ftm-audit/scripts/run-knip.sh +23 -23
- package/ftm-audit.yml +2 -2
- package/ftm-brainstorm/SKILL.md +498 -498
- package/ftm-brainstorm/evals/evals.json +100 -100
- package/ftm-brainstorm/evals/promptfoo.yaml +109 -109
- package/ftm-brainstorm/references/agent-prompts.md +224 -224
- package/ftm-brainstorm/references/plan-template.md +121 -121
- package/ftm-brainstorm.yml +2 -2
- package/ftm-browse/SKILL.md +454 -454
- package/ftm-browse/daemon/browser-manager.ts +206 -206
- package/ftm-browse/daemon/bun.lock +30 -30
- package/ftm-browse/daemon/cli.ts +347 -347
- package/ftm-browse/daemon/commands.ts +410 -410
- package/ftm-browse/daemon/main.ts +357 -357
- package/ftm-browse/daemon/package.json +17 -17
- package/ftm-browse/daemon/server.ts +189 -189
- package/ftm-browse/daemon/snapshot.ts +519 -519
- package/ftm-browse/daemon/tsconfig.json +22 -22
- package/ftm-browse.yml +4 -4
- package/ftm-capture/SKILL.md +370 -370
- package/ftm-capture.yml +4 -4
- package/ftm-codex-gate/SKILL.md +361 -361
- package/ftm-codex-gate.yml +2 -2
- package/ftm-config/SKILL.md +345 -345
- package/ftm-config.default.yml +82 -80
- package/ftm-config.yml +2 -2
- package/ftm-council/SKILL.md +416 -416
- package/ftm-council/references/prompts/CLAUDE-INVESTIGATION.md +60 -60
- package/ftm-council/references/prompts/CODEX-INVESTIGATION.md +58 -58
- package/ftm-council/references/prompts/GEMINI-INVESTIGATION.md +58 -58
- package/ftm-council/references/prompts/REBUTTAL-TEMPLATE.md +57 -57
- package/ftm-council/references/protocols/PREREQUISITES.md +47 -47
- package/ftm-council/references/protocols/STEP-0-FRAMING.md +46 -46
- package/ftm-council.yml +2 -2
- package/ftm-dashboard/SKILL.md +163 -163
- package/ftm-dashboard.yml +4 -4
- package/ftm-debug/SKILL.md +1037 -1037
- package/ftm-debug/references/phases/PHASE-0-INTAKE.md +58 -58
- package/ftm-debug/references/phases/PHASE-1-TRIAGE.md +46 -46
- package/ftm-debug/references/phases/PHASE-2-WAR-ROOM-AGENTS.md +279 -279
- package/ftm-debug/references/phases/PHASE-3-TO-6-EXECUTION.md +436 -436
- package/ftm-debug/references/protocols/BLACKBOARD.md +86 -86
- package/ftm-debug/references/protocols/EDGE-CASES.md +103 -103
- package/ftm-debug.yml +2 -2
- package/ftm-diagram/SKILL.md +277 -277
- package/ftm-diagram.yml +2 -2
- package/ftm-executor/SKILL.md +777 -767
- package/ftm-executor/references/STYLE-TEMPLATE.md +73 -73
- package/ftm-executor/references/phases/PHASE-0-VERIFICATION.md +62 -62
- package/ftm-executor/references/phases/PHASE-2-AGENT-ASSEMBLY.md +34 -34
- package/ftm-executor/references/phases/PHASE-3-WORKTREES.md +38 -38
- package/ftm-executor/references/phases/PHASE-4-5-AUDIT.md +72 -72
- package/ftm-executor/references/phases/PHASE-4-DISPATCH.md +66 -66
- package/ftm-executor/references/phases/PHASE-5-5-CODEX-GATE.md +73 -73
- package/ftm-executor/references/protocols/DOCUMENTATION-BOOTSTRAP.md +36 -36
- package/ftm-executor/references/protocols/MODEL-PROFILE.md +59 -44
- package/ftm-executor/references/protocols/PROGRESS-TRACKING.md +66 -66
- package/ftm-executor/runtime/ftm-runtime.mjs +252 -252
- package/ftm-executor/runtime/package.json +8 -8
- package/ftm-executor.yml +2 -2
- package/ftm-git/SKILL.md +441 -441
- package/ftm-git/evals/evals.json +26 -26
- package/ftm-git/evals/promptfoo.yaml +75 -75
- package/ftm-git/hooks/post-commit-experience.sh +92 -92
- package/ftm-git/references/patterns/SECRET-PATTERNS.md +104 -104
- package/ftm-git/references/protocols/REMEDIATION.md +139 -139
- package/ftm-git/scripts/pre-commit-secrets.sh +110 -110
- package/ftm-git.yml +2 -2
- package/ftm-inbox/backend/adapters/_retry.py +64 -64
- package/ftm-inbox/backend/adapters/base.py +230 -230
- package/ftm-inbox/backend/adapters/freshservice.py +104 -104
- package/ftm-inbox/backend/adapters/gmail.py +125 -125
- package/ftm-inbox/backend/adapters/jira.py +136 -136
- package/ftm-inbox/backend/adapters/registry.py +192 -192
- package/ftm-inbox/backend/adapters/slack.py +110 -110
- package/ftm-inbox/backend/db/connection.py +54 -54
- package/ftm-inbox/backend/db/schema.py +78 -78
- package/ftm-inbox/backend/executor/__init__.py +7 -7
- package/ftm-inbox/backend/executor/engine.py +149 -149
- package/ftm-inbox/backend/executor/step_runner.py +98 -98
- package/ftm-inbox/backend/main.py +103 -103
- package/ftm-inbox/backend/models/__init__.py +1 -1
- package/ftm-inbox/backend/models/unified_task.py +36 -36
- package/ftm-inbox/backend/planner/__init__.py +6 -6
- package/ftm-inbox/backend/planner/generator.py +127 -127
- package/ftm-inbox/backend/planner/schema.py +34 -34
- package/ftm-inbox/backend/requirements.txt +5 -5
- package/ftm-inbox/backend/routes/execute.py +186 -186
- package/ftm-inbox/backend/routes/health.py +52 -52
- package/ftm-inbox/backend/routes/inbox.py +68 -68
- package/ftm-inbox/backend/routes/plan.py +271 -271
- package/ftm-inbox/bin/launchagent.mjs +91 -91
- package/ftm-inbox/bin/setup.mjs +188 -188
- package/ftm-inbox/bin/start.sh +10 -10
- package/ftm-inbox/bin/status.sh +17 -17
- package/ftm-inbox/bin/stop.sh +8 -8
- package/ftm-inbox/config.example.yml +55 -55
- package/ftm-inbox/package-lock.json +2898 -2898
- package/ftm-inbox/package.json +26 -26
- package/ftm-inbox/postcss.config.js +6 -6
- package/ftm-inbox/src/app.css +199 -199
- package/ftm-inbox/src/app.html +18 -18
- package/ftm-inbox/src/lib/api.ts +166 -166
- package/ftm-inbox/src/lib/components/ExecutionLog.svelte +81 -81
- package/ftm-inbox/src/lib/components/InboxFeed.svelte +143 -143
- package/ftm-inbox/src/lib/components/PlanStep.svelte +271 -271
- package/ftm-inbox/src/lib/components/PlanView.svelte +206 -206
- package/ftm-inbox/src/lib/components/StreamPanel.svelte +99 -99
- package/ftm-inbox/src/lib/components/TaskCard.svelte +190 -190
- package/ftm-inbox/src/lib/components/ui/EmptyState.svelte +63 -63
- package/ftm-inbox/src/lib/components/ui/KawaiiCard.svelte +86 -86
- package/ftm-inbox/src/lib/components/ui/PillButton.svelte +106 -106
- package/ftm-inbox/src/lib/components/ui/StatusBadge.svelte +67 -67
- package/ftm-inbox/src/lib/components/ui/StreamDrawer.svelte +149 -149
- package/ftm-inbox/src/lib/components/ui/ThemeToggle.svelte +80 -80
- package/ftm-inbox/src/lib/theme.ts +47 -47
- package/ftm-inbox/src/routes/+layout.svelte +76 -76
- package/ftm-inbox/src/routes/+page.svelte +401 -401
- package/ftm-inbox/svelte.config.js +12 -12
- package/ftm-inbox/tailwind.config.ts +63 -63
- package/ftm-inbox/tsconfig.json +13 -13
- package/ftm-inbox/vite.config.ts +6 -6
- package/ftm-intent/SKILL.md +241 -241
- package/ftm-intent.yml +2 -2
- package/ftm-manifest.json +3794 -3794
- package/ftm-map/SKILL.md +291 -291
- package/ftm-map/scripts/db.py +712 -712
- package/ftm-map/scripts/index.py +415 -415
- package/ftm-map/scripts/parser.py +224 -224
- package/ftm-map/scripts/queries/go-tags.scm +20 -20
- package/ftm-map/scripts/queries/javascript-tags.scm +35 -35
- package/ftm-map/scripts/queries/python-tags.scm +31 -31
- package/ftm-map/scripts/queries/ruby-tags.scm +19 -19
- package/ftm-map/scripts/queries/rust-tags.scm +37 -37
- package/ftm-map/scripts/queries/typescript-tags.scm +41 -41
- package/ftm-map/scripts/query.py +301 -301
- package/ftm-map/scripts/ranker.py +377 -377
- package/ftm-map/scripts/requirements.txt +5 -5
- package/ftm-map/scripts/setup-hooks.sh +27 -27
- package/ftm-map/scripts/setup.sh +56 -56
- package/ftm-map/scripts/test_db.py +364 -364
- package/ftm-map/scripts/test_parser.py +174 -174
- package/ftm-map/scripts/test_query.py +183 -183
- package/ftm-map/scripts/test_ranker.py +199 -199
- package/ftm-map/scripts/views.py +591 -591
- package/ftm-map.yml +2 -2
- package/ftm-mind/SKILL.md +1943 -1943
- package/ftm-mind/evals/promptfoo.yaml +142 -142
- package/ftm-mind/references/blackboard-schema.md +328 -328
- package/ftm-mind/references/complexity-guide.md +110 -110
- package/ftm-mind/references/event-registry.md +319 -319
- package/ftm-mind/references/mcp-inventory.md +296 -296
- package/ftm-mind/references/protocols/COMPLEXITY-SIZING.md +72 -72
- package/ftm-mind/references/protocols/MCP-HEURISTICS.md +32 -32
- package/ftm-mind/references/protocols/PLAN-APPROVAL.md +80 -80
- package/ftm-mind/references/reflexion-protocol.md +249 -249
- package/ftm-mind/references/routing/SCENARIOS.md +22 -22
- package/ftm-mind/references/routing-scenarios.md +35 -35
- package/ftm-mind.yml +2 -2
- package/ftm-pause/SKILL.md +395 -395
- package/ftm-pause/references/protocols/SKILL-RESTORE-PROTOCOLS.md +186 -186
- package/ftm-pause/references/protocols/VALIDATION.md +80 -80
- package/ftm-pause.yml +2 -2
- package/ftm-researcher/SKILL.md +275 -275
- package/ftm-researcher/evals/agent-diversity.yaml +17 -17
- package/ftm-researcher/evals/synthesis-quality.yaml +12 -12
- package/ftm-researcher/evals/trigger-accuracy.yaml +39 -39
- package/ftm-researcher/references/adaptive-search.md +116 -116
- package/ftm-researcher/references/agent-prompts.md +193 -193
- package/ftm-researcher/references/council-integration.md +193 -193
- package/ftm-researcher/references/output-format.md +203 -203
- package/ftm-researcher/references/synthesis-pipeline.md +165 -165
- package/ftm-researcher/scripts/score_credibility.py +234 -234
- package/ftm-researcher/scripts/validate_research.py +92 -92
- package/ftm-researcher.yml +2 -2
- package/ftm-resume/SKILL.md +518 -518
- package/ftm-resume/references/protocols/VALIDATION.md +172 -172
- package/ftm-resume.yml +2 -2
- package/ftm-retro/SKILL.md +380 -380
- package/ftm-retro/references/protocols/SCORING-RUBRICS.md +89 -89
- package/ftm-retro/references/templates/REPORT-FORMAT.md +109 -109
- package/ftm-retro.yml +2 -2
- package/ftm-routine/SKILL.md +170 -170
- package/ftm-routine.yml +4 -4
- package/ftm-state/blackboard/capabilities.json +5 -5
- package/ftm-state/blackboard/capabilities.schema.json +27 -27
- package/ftm-state/blackboard/context.json +23 -23
- package/ftm-state/blackboard/experiences/index.json +9 -9
- package/ftm-state/blackboard/patterns.json +6 -6
- package/ftm-state/schemas/context.schema.json +130 -130
- package/ftm-state/schemas/experience-index.schema.json +77 -77
- package/ftm-state/schemas/experience.schema.json +78 -78
- package/ftm-state/schemas/patterns.schema.json +44 -44
- package/ftm-upgrade/SKILL.md +194 -194
- package/ftm-upgrade/scripts/check-version.sh +76 -76
- package/ftm-upgrade/scripts/upgrade.sh +143 -143
- package/ftm-upgrade.yml +2 -2
- package/ftm-verify.yml +2 -2
- package/ftm.yml +2 -2
- package/hooks/ftm-blackboard-enforcer.sh +93 -93
- package/hooks/ftm-discovery-reminder.sh +90 -90
- package/hooks/ftm-drafts-gate.sh +61 -61
- package/hooks/ftm-event-logger.mjs +107 -107
- package/hooks/ftm-map-autodetect.sh +79 -79
- package/hooks/ftm-pending-sync-check.sh +22 -22
- package/hooks/ftm-plan-gate.sh +92 -92
- package/hooks/ftm-post-commit-trigger.sh +57 -57
- package/hooks/settings-template.json +81 -81
- package/install.sh +363 -363
- package/package.json +84 -84
- package/uninstall.sh +25 -25
package/ftm-audit/SKILL.md
CHANGED
|
@@ -1,541 +1,623 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: ftm-audit
|
|
3
|
-
description:
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
## Events
|
|
7
|
-
|
|
8
|
-
### Emits
|
|
9
|
-
- `audit_complete` — when all three audit layers finish and the final changelog is produced
|
|
10
|
-
- `issue_found` — when Layer 1 (knip) or Layer 2 (adversarial audit) identifies an unwired or dead-code problem
|
|
11
|
-
- `task_completed` — when an audit-initiated fix cycle finishes and the audited scope is verified clean
|
|
12
|
-
|
|
13
|
-
### Listens To
|
|
14
|
-
- `code_committed` — run post-commit verification: trigger Layer 1 and Layer 2 against the committed diff
|
|
15
|
-
- `review_complete` — validate that review findings align with static analysis results; flag discrepancies
|
|
16
|
-
|
|
17
|
-
## Blackboard Read
|
|
18
|
-
|
|
19
|
-
Before starting, load context from the blackboard:
|
|
20
|
-
|
|
21
|
-
1. Read `~/.claude/ftm-state/blackboard/context.json` — check current_task, recent_decisions, active_constraints
|
|
22
|
-
2. Read `~/.claude/ftm-state/blackboard/experiences/index.json` — filter entries by task_type="test" or tags matching "audit" or "wiring"
|
|
23
|
-
3. Load top 3-5 matching experience files for commonly found issues and effective fix strategies
|
|
24
|
-
4. Read `~/.claude/ftm-state/blackboard/patterns.json` — check recurring_issues for common wiring failures and execution_patterns for what types of code changes need more scrutiny
|
|
25
|
-
|
|
26
|
-
If index.json is empty or no matches found, proceed normally without experience-informed shortcuts.
|
|
27
|
-
|
|
28
|
-
# FTM Audit — Wiring Verification
|
|
29
|
-
|
|
30
|
-
Three-layer verification system: knip for import-graph dead code, LLM adversarial trace for semantic wiring, and auto-fix with changelog.
|
|
31
|
-
|
|
32
|
-
## Why This Exists
|
|
33
|
-
|
|
34
|
-
Code that compiles but isn't wired into the running application is worse than code that doesn't compile — it silently wastes space, confuses readers, and creates false confidence. This skill catches unwired code through two complementary lenses and fixes it automatically.
|
|
35
|
-
|
|
36
|
-
## Phase 0: Detect Project Patterns
|
|
37
|
-
|
|
38
|
-
Before running any checks, scan the project to calibrate which wiring dimensions apply and how to check them. This takes seconds and prevents false positives from applying React patterns to a Vue project (or Next.js App Router patterns to a Pages Router project).
|
|
39
|
-
|
|
40
|
-
**Read `package.json` and check for:**
|
|
41
|
-
|
|
42
|
-
| Signal | Detection | Impact on Audit |
|
|
43
|
-
|---|---|---|
|
|
44
|
-
| **Framework** | `react`, `next`, `vue`, `svelte`, `angular` in deps | Determines which dimensions are relevant |
|
|
45
|
-
| **Router** | `react-router-dom`, `@tanstack/react-router`, `next` (file-based), `vue-router` | Changes how Dimension 3 (Route Registration) works |
|
|
46
|
-
| **State management** | `zustand`, `@reduxjs/toolkit`, `pinia`, `jotai`, `recoil` | Changes how Dimension 4 (Store Consumption) works |
|
|
47
|
-
| **API layer** | `@tanstack/react-query`, `swr`, `trpc`, `@apollo/client`, `axios` | Changes how Dimension 5 (API Invocation) works |
|
|
48
|
-
| **Build tool** | `vite`, `next`, `webpack`, `turbopack` | Affects knip entry point detection |
|
|
49
|
-
|
|
50
|
-
**Quick file checks:**
|
|
51
|
-
|
|
52
|
-
- `next.config.*` exists → Next.js project. Check for `app/` directory (App Router) vs `pages/` (Pages Router). This completely changes route checking.
|
|
53
|
-
- `vite.config.*` exists → Vite project. Entry point is usually `index.html` → `src/main.tsx`.
|
|
54
|
-
- `app/layout.tsx` or `app/page.tsx` exists → Next.js App Router. Routes are file-based (`app/dashboard/page.tsx` = `/dashboard`). No router config file to check — Dimension 3 checks directory structure instead.
|
|
55
|
-
- `src/router.*` or `src/routes.*` exists → Explicit router config. Dimension 3 checks this file.
|
|
56
|
-
|
|
57
|
-
**Framework-specific dimension adjustments:**
|
|
58
|
-
|
|
59
|
-
| Framework | D1 (Import) | D2 (JSX) | D3 (Routes) | D4 (Store) | D5 (API) |
|
|
60
|
-
|---|---|---|---|---|---|
|
|
61
|
-
| React + react-router | Standard | Standard | Check router config file | Standard | Standard |
|
|
62
|
-
| Next.js App Router | Check `app/` tree | Standard | File-based: `page.tsx` in directory = route | Standard | Check for Server Actions too |
|
|
63
|
-
| Next.js Pages Router | Check `pages/` tree | Standard | File-based: `pages/foo.tsx` = `/foo` | Standard | Check `getServerSideProps`/`getStaticProps` |
|
|
64
|
-
| Remix | Check `app/routes/` | Standard | File-based + `remix.config` | Standard | Check `loader`/`action` exports |
|
|
65
|
-
| Vue + vue-router | Standard | `<template>` instead of JSX | Check router config | Pinia: `defineStore` | Standard |
|
|
66
|
-
| Svelte | Standard | Svelte components | SvelteKit: file-based routes | Svelte stores | Standard |
|
|
67
|
-
| No framework (Node.js) | Standard | Skip D2 | Skip D3 | Skip D4 | Standard |
|
|
68
|
-
|
|
69
|
-
**Output:** Store the detected pattern as context for all subsequent layers. Don't include it in the report unless something unusual was detected.
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
Project detected: React 18 + Vite + react-router v6 + Zustand + TanStack Query
|
|
73
|
-
Dimensions active: D1 ✓ D2 ✓ D3 (router config) D4 (Zustand) D5 (TanStack Query)
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## Layer 1: Static Analysis (knip)
|
|
77
|
-
|
|
78
|
-
**What it does:** Runs [knip](https://knip.dev/) against the target project to detect unused files, exports, dependencies, and unreachable modules from the import graph.
|
|
79
|
-
|
|
80
|
-
**Prerequisites check:**
|
|
81
|
-
1. Check if the project has a `package.json` — if not, skip Layer 1 entirely and note "No package.json found — knip layer skipped" in the report
|
|
82
|
-
2. Check if knip is installed (`node_modules/.bin/knip`) — if not, use `npx knip` (no install needed)
|
|
83
|
-
|
|
84
|
-
**Execution:**
|
|
85
|
-
|
|
86
|
-
Run knip with JSON output for machine parsing:
|
|
87
|
-
```bash
|
|
88
|
-
npx knip --reporter json 2>/dev/null
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
If the project has a `knip.json` or `knip.config.ts`, knip uses it automatically. If not, knip auto-detects entry points from the framework (Vite, Next.js, React Router, etc.).
|
|
92
|
-
|
|
93
|
-
**Parsing the JSON output:**
|
|
94
|
-
|
|
95
|
-
Knip's JSON output contains these categories:
|
|
96
|
-
- `files` — completely unused files (not imported by anything)
|
|
97
|
-
- `issues` — array of issues, each with:
|
|
98
|
-
- `type`: "exports", "types", "duplicates", "dependencies", "devDependencies", "optionalPeerDependencies", "unlisted", "binaries", "unresolved"
|
|
99
|
-
- `filePath`: the file containing the issue
|
|
100
|
-
- `symbol`: the unused export name (for export issues)
|
|
101
|
-
- `parentSymbol`: the re-exporting module (for re-export chains)
|
|
102
|
-
|
|
103
|
-
**Categorize findings:**
|
|
104
|
-
|
|
105
|
-
| Finding Type | Fix Action |
|
|
106
|
-
|---|---|
|
|
107
|
-
| Unused file | Remove file OR add import from appropriate parent |
|
|
108
|
-
| Unused export | Remove export OR wire it into consumer |
|
|
109
|
-
| Unused dependency | Remove from package.json OR add usage |
|
|
110
|
-
| Unlisted dependency | Add to package.json |
|
|
111
|
-
| Unresolved import | Fix import path OR install missing package |
|
|
112
|
-
|
|
113
|
-
**Output format for this layer:**
|
|
114
|
-
```
|
|
115
|
-
Layer 1 findings:
|
|
116
|
-
- [UNUSED_FILE] src/components/OldWidget.tsx — not imported anywhere
|
|
117
|
-
- [UNUSED_EXPORT] src/utils/helpers.ts:42 — export `formatDate` not used
|
|
118
|
-
- [UNUSED_DEP] package.json — `lodash` listed but never imported
|
|
119
|
-
- [UNLISTED_DEP] src/api/client.ts — imports `axios` but it's not in package.json
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
**Helper script:** `scripts/run-knip.sh` handles execution and returns structured JSON output.
|
|
123
|
-
|
|
124
|
-
## Layer
|
|
125
|
-
|
|
126
|
-
**
|
|
127
|
-
|
|
128
|
-
**
|
|
129
|
-
|
|
130
|
-
**
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
-
|
|
137
|
-
-
|
|
138
|
-
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
-
|
|
143
|
-
-
|
|
144
|
-
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
- [
|
|
172
|
-
- [
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
**
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
-
|
|
215
|
-
-
|
|
216
|
-
-
|
|
217
|
-
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
**
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
route_path: /
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
2.
|
|
449
|
-
3.
|
|
450
|
-
4.
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
-
|
|
477
|
-
-
|
|
478
|
-
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
-
|
|
482
|
-
-
|
|
483
|
-
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
-
|
|
502
|
-
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
-
|
|
524
|
-
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
-
|
|
541
|
-
-
|
|
1
|
+
---
|
|
2
|
+
name: ftm-audit
|
|
3
|
+
description: Triple-layer wiring audit that verifies all code is actually connected to the running application and documented in INTENT.md. Combines static analysis (knip), documentation coverage checking (INTENT.md entries for every changed function), and adversarial LLM audit — auto-fixes anything it finds. Use when user says "audit", "wiring check", "verify wiring", "dead code", "check imports", "unused code", "find dead code", "audit wiring", "check docs", or "documentation coverage". Also auto-invoked by ftm-executor after each task.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Events
|
|
7
|
+
|
|
8
|
+
### Emits
|
|
9
|
+
- `audit_complete` — when all three audit layers finish and the final changelog is produced
|
|
10
|
+
- `issue_found` — when Layer 1 (knip) or Layer 2 (adversarial audit) identifies an unwired or dead-code problem
|
|
11
|
+
- `task_completed` — when an audit-initiated fix cycle finishes and the audited scope is verified clean
|
|
12
|
+
|
|
13
|
+
### Listens To
|
|
14
|
+
- `code_committed` — run post-commit verification: trigger Layer 1 and Layer 2 against the committed diff
|
|
15
|
+
- `review_complete` — validate that review findings align with static analysis results; flag discrepancies
|
|
16
|
+
|
|
17
|
+
## Blackboard Read
|
|
18
|
+
|
|
19
|
+
Before starting, load context from the blackboard:
|
|
20
|
+
|
|
21
|
+
1. Read `~/.claude/ftm-state/blackboard/context.json` — check current_task, recent_decisions, active_constraints
|
|
22
|
+
2. Read `~/.claude/ftm-state/blackboard/experiences/index.json` — filter entries by task_type="test" or tags matching "audit" or "wiring"
|
|
23
|
+
3. Load top 3-5 matching experience files for commonly found issues and effective fix strategies
|
|
24
|
+
4. Read `~/.claude/ftm-state/blackboard/patterns.json` — check recurring_issues for common wiring failures and execution_patterns for what types of code changes need more scrutiny
|
|
25
|
+
|
|
26
|
+
If index.json is empty or no matches found, proceed normally without experience-informed shortcuts.
|
|
27
|
+
|
|
28
|
+
# FTM Audit — Wiring Verification
|
|
29
|
+
|
|
30
|
+
Three-layer verification system: knip for import-graph dead code, LLM adversarial trace for semantic wiring, and auto-fix with changelog.
|
|
31
|
+
|
|
32
|
+
## Why This Exists
|
|
33
|
+
|
|
34
|
+
Code that compiles but isn't wired into the running application is worse than code that doesn't compile — it silently wastes space, confuses readers, and creates false confidence. This skill catches unwired code through two complementary lenses and fixes it automatically.
|
|
35
|
+
|
|
36
|
+
## Phase 0: Detect Project Patterns
|
|
37
|
+
|
|
38
|
+
Before running any checks, scan the project to calibrate which wiring dimensions apply and how to check them. This takes seconds and prevents false positives from applying React patterns to a Vue project (or Next.js App Router patterns to a Pages Router project).
|
|
39
|
+
|
|
40
|
+
**Read `package.json` and check for:**
|
|
41
|
+
|
|
42
|
+
| Signal | Detection | Impact on Audit |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| **Framework** | `react`, `next`, `vue`, `svelte`, `angular` in deps | Determines which dimensions are relevant |
|
|
45
|
+
| **Router** | `react-router-dom`, `@tanstack/react-router`, `next` (file-based), `vue-router` | Changes how Dimension 3 (Route Registration) works |
|
|
46
|
+
| **State management** | `zustand`, `@reduxjs/toolkit`, `pinia`, `jotai`, `recoil` | Changes how Dimension 4 (Store Consumption) works |
|
|
47
|
+
| **API layer** | `@tanstack/react-query`, `swr`, `trpc`, `@apollo/client`, `axios` | Changes how Dimension 5 (API Invocation) works |
|
|
48
|
+
| **Build tool** | `vite`, `next`, `webpack`, `turbopack` | Affects knip entry point detection |
|
|
49
|
+
|
|
50
|
+
**Quick file checks:**
|
|
51
|
+
|
|
52
|
+
- `next.config.*` exists → Next.js project. Check for `app/` directory (App Router) vs `pages/` (Pages Router). This completely changes route checking.
|
|
53
|
+
- `vite.config.*` exists → Vite project. Entry point is usually `index.html` → `src/main.tsx`.
|
|
54
|
+
- `app/layout.tsx` or `app/page.tsx` exists → Next.js App Router. Routes are file-based (`app/dashboard/page.tsx` = `/dashboard`). No router config file to check — Dimension 3 checks directory structure instead.
|
|
55
|
+
- `src/router.*` or `src/routes.*` exists → Explicit router config. Dimension 3 checks this file.
|
|
56
|
+
|
|
57
|
+
**Framework-specific dimension adjustments:**
|
|
58
|
+
|
|
59
|
+
| Framework | D1 (Import) | D2 (JSX) | D3 (Routes) | D4 (Store) | D5 (API) |
|
|
60
|
+
|---|---|---|---|---|---|
|
|
61
|
+
| React + react-router | Standard | Standard | Check router config file | Standard | Standard |
|
|
62
|
+
| Next.js App Router | Check `app/` tree | Standard | File-based: `page.tsx` in directory = route | Standard | Check for Server Actions too |
|
|
63
|
+
| Next.js Pages Router | Check `pages/` tree | Standard | File-based: `pages/foo.tsx` = `/foo` | Standard | Check `getServerSideProps`/`getStaticProps` |
|
|
64
|
+
| Remix | Check `app/routes/` | Standard | File-based + `remix.config` | Standard | Check `loader`/`action` exports |
|
|
65
|
+
| Vue + vue-router | Standard | `<template>` instead of JSX | Check router config | Pinia: `defineStore` | Standard |
|
|
66
|
+
| Svelte | Standard | Svelte components | SvelteKit: file-based routes | Svelte stores | Standard |
|
|
67
|
+
| No framework (Node.js) | Standard | Skip D2 | Skip D3 | Skip D4 | Standard |
|
|
68
|
+
|
|
69
|
+
**Output:** Store the detected pattern as context for all subsequent layers. Don't include it in the report unless something unusual was detected.
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
Project detected: React 18 + Vite + react-router v6 + Zustand + TanStack Query
|
|
73
|
+
Dimensions active: D1 ✓ D2 ✓ D3 (router config) D4 (Zustand) D5 (TanStack Query)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Layer 1: Static Analysis (knip)
|
|
77
|
+
|
|
78
|
+
**What it does:** Runs [knip](https://knip.dev/) against the target project to detect unused files, exports, dependencies, and unreachable modules from the import graph.
|
|
79
|
+
|
|
80
|
+
**Prerequisites check:**
|
|
81
|
+
1. Check if the project has a `package.json` — if not, skip Layer 1 entirely and note "No package.json found — knip layer skipped" in the report
|
|
82
|
+
2. Check if knip is installed (`node_modules/.bin/knip`) — if not, use `npx knip` (no install needed)
|
|
83
|
+
|
|
84
|
+
**Execution:**
|
|
85
|
+
|
|
86
|
+
Run knip with JSON output for machine parsing:
|
|
87
|
+
```bash
|
|
88
|
+
npx knip --reporter json 2>/dev/null
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
If the project has a `knip.json` or `knip.config.ts`, knip uses it automatically. If not, knip auto-detects entry points from the framework (Vite, Next.js, React Router, etc.).
|
|
92
|
+
|
|
93
|
+
**Parsing the JSON output:**
|
|
94
|
+
|
|
95
|
+
Knip's JSON output contains these categories:
|
|
96
|
+
- `files` — completely unused files (not imported by anything)
|
|
97
|
+
- `issues` — array of issues, each with:
|
|
98
|
+
- `type`: "exports", "types", "duplicates", "dependencies", "devDependencies", "optionalPeerDependencies", "unlisted", "binaries", "unresolved"
|
|
99
|
+
- `filePath`: the file containing the issue
|
|
100
|
+
- `symbol`: the unused export name (for export issues)
|
|
101
|
+
- `parentSymbol`: the re-exporting module (for re-export chains)
|
|
102
|
+
|
|
103
|
+
**Categorize findings:**
|
|
104
|
+
|
|
105
|
+
| Finding Type | Fix Action |
|
|
106
|
+
|---|---|
|
|
107
|
+
| Unused file | Remove file OR add import from appropriate parent |
|
|
108
|
+
| Unused export | Remove export OR wire it into consumer |
|
|
109
|
+
| Unused dependency | Remove from package.json OR add usage |
|
|
110
|
+
| Unlisted dependency | Add to package.json |
|
|
111
|
+
| Unresolved import | Fix import path OR install missing package |
|
|
112
|
+
|
|
113
|
+
**Output format for this layer:**
|
|
114
|
+
```
|
|
115
|
+
Layer 1 findings:
|
|
116
|
+
- [UNUSED_FILE] src/components/OldWidget.tsx — not imported anywhere
|
|
117
|
+
- [UNUSED_EXPORT] src/utils/helpers.ts:42 — export `formatDate` not used
|
|
118
|
+
- [UNUSED_DEP] package.json — `lodash` listed but never imported
|
|
119
|
+
- [UNLISTED_DEP] src/api/client.ts — imports `axios` but it's not in package.json
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Helper script:** `scripts/run-knip.sh` handles execution and returns structured JSON output.
|
|
123
|
+
|
|
124
|
+
## Layer 1.5: Documentation Coverage Check
|
|
125
|
+
|
|
126
|
+
**Purpose:** Verify that every new or changed function has a corresponding INTENT.md entry. This catches the most common documentation skip — agents write code and tests but forget to update INTENT.md, leaving the documentation layer stale.
|
|
127
|
+
|
|
128
|
+
**When to run:** After Layer 1, before Layer 2. Only runs if the project has an INTENT.md documentation layer (root INTENT.md exists). If no INTENT.md exists anywhere in the project, skip this layer silently — it's not a documentation-first project.
|
|
129
|
+
|
|
130
|
+
**Scope:** Analyze the current git diff to find new or changed functions/classes/methods.
|
|
131
|
+
|
|
132
|
+
**Check protocol:**
|
|
133
|
+
|
|
134
|
+
1. **Find changed files:** `git diff HEAD~1 --name-only -- '*.py' '*.ts' '*.tsx' '*.js' '*.jsx'` (or equivalent for the project's language)
|
|
135
|
+
2. **For each changed source file:**
|
|
136
|
+
- Identify the module directory (e.g., `src/risk/` for `src/risk/position_sizer.py`)
|
|
137
|
+
- Check if `[module_dir]/INTENT.md` exists
|
|
138
|
+
- If it exists, read it and extract all documented function signatures
|
|
139
|
+
- Parse the changed file for public function/class/method definitions
|
|
140
|
+
- Compare: flag any public function that exists in code but has NO entry in INTENT.md
|
|
141
|
+
3. **For new module directories** (directories created in this diff):
|
|
142
|
+
- Check if `[new_module_dir]/INTENT.md` was created
|
|
143
|
+
- Check if root INTENT.md module map has a row for the new module
|
|
144
|
+
- Flag if either is missing
|
|
145
|
+
|
|
146
|
+
**Finding types:**
|
|
147
|
+
|
|
148
|
+
| Finding | Severity | Auto-fixable? |
|
|
149
|
+
|---------|----------|---------------|
|
|
150
|
+
| `MISSING_INTENT_ENTRY` — function exists in code but no INTENT.md entry | HARD FAIL | Yes — generate entry from code |
|
|
151
|
+
| `STALE_INTENT_ENTRY` — INTENT.md entry for a function that no longer exists | WARN | Yes — remove entry |
|
|
152
|
+
| `MISSING_MODULE_INTENT` — new module directory has no INTENT.md file | HARD FAIL | Yes — create from template |
|
|
153
|
+
| `MISSING_MODULE_MAP_ROW` — new module not in root INTENT.md module map | HARD FAIL | Yes — add row |
|
|
154
|
+
|
|
155
|
+
**Output format:**
|
|
156
|
+
```
|
|
157
|
+
Layer 1.5 findings:
|
|
158
|
+
- [MISSING_INTENT_ENTRY] src/risk/position_sizer.py:45 — `calculate_dynamic_size()` has no entry in src/risk/INTENT.md
|
|
159
|
+
- [STALE_INTENT_ENTRY] src/risk/INTENT.md — entry for `old_function()` but function no longer exists in code
|
|
160
|
+
- [MISSING_MODULE_INTENT] src/newmodule/ — directory created but no INTENT.md file
|
|
161
|
+
- [MISSING_MODULE_MAP_ROW] src/newmodule/ — not listed in root INTENT.md module map
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Auto-fix strategy for `MISSING_INTENT_ENTRY`:**
|
|
165
|
+
|
|
166
|
+
Generate the entry from the function's code. Read the function body and produce:
|
|
167
|
+
```markdown
|
|
168
|
+
### function_name(param1: Type, param2: Type) -> ReturnType
|
|
169
|
+
- **Does**: [infer from function body — one sentence]
|
|
170
|
+
- **Why**: [infer from context and callers — one sentence, or "Why unknown — inferred from usage: [inference]"]
|
|
171
|
+
- **Relationships**: [grep for callers/callees — one sentence]
|
|
172
|
+
- **Decisions**: [note any non-obvious choices, or "None"]
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Append the entry to the module's INTENT.md under the `## Functions` section.
|
|
176
|
+
|
|
177
|
+
**Auto-fix strategy for `MISSING_MODULE_INTENT`:**
|
|
178
|
+
|
|
179
|
+
Create `[module_dir]/INTENT.md` with:
|
|
180
|
+
```markdown
|
|
181
|
+
# [Module Name] — Intent
|
|
182
|
+
|
|
183
|
+
## Functions
|
|
184
|
+
|
|
185
|
+
[generate entries for all public functions in the module]
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Auto-fix strategy for `MISSING_MODULE_MAP_ROW`:**
|
|
189
|
+
|
|
190
|
+
Append a row to the root INTENT.md module map table:
|
|
191
|
+
```markdown
|
|
192
|
+
| [module_path] | [infer purpose from code] | [infer relationships from imports] |
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Layer 2: LLM Adversarial Audit
|
|
198
|
+
|
|
199
|
+
**Mindset:** You are an adversary trying to PROVE code is dead. Not "confirm it works" — PROVE it's dead. Every new/modified export is guilty until proven innocent. You must find a complete chain from app entry point to the code in question, or it's flagged.
|
|
200
|
+
|
|
201
|
+
**Scope:** Analyze the current git diff (`git diff HEAD~1` or the diff from the current task's changes). For each new or modified export:
|
|
202
|
+
|
|
203
|
+
**The 5 Wiring Dimensions:**
|
|
204
|
+
|
|
205
|
+
For each export, check ALL five. A component might be imported but never rendered. A function might be exported but never called. Check the full chain.
|
|
206
|
+
|
|
207
|
+
### Dimension 1: Import Chain
|
|
208
|
+
- Trace: `export` → `import` → ... → entry point (`main.tsx`, `App.tsx`, `index.ts`)
|
|
209
|
+
- Method: Use `grep -r "import.*{.*ExportName.*}.*from" src/` or equivalent
|
|
210
|
+
- **GUILTY if:** No file imports this export, OR the importing file itself is not imported (broken chain)
|
|
211
|
+
- Evidence required: Full import chain with file:line for each link
|
|
212
|
+
|
|
213
|
+
### Dimension 2: JSX Rendering (React/Vue/Svelte projects)
|
|
214
|
+
- Trace: Component → rendered in parent JSX → ... → root component
|
|
215
|
+
- Method: Search for `<ComponentName` in JSX/TSX files
|
|
216
|
+
- **GUILTY if:** Component is imported but never appears in any JSX return statement
|
|
217
|
+
- Evidence required: The parent component file:line where it's rendered (or "NOT FOUND")
|
|
218
|
+
- Special cases: Lazy imports (`React.lazy(() => import(...))`), conditional rendering (`{condition && <Component/>}`), render props, HOCs — all count as valid rendering
|
|
219
|
+
|
|
220
|
+
### Dimension 3: Route Registration
|
|
221
|
+
- Trace: View/page component → route config → router entry point
|
|
222
|
+
- Method: Search router config files (react-router `createBrowserRouter`, Next.js pages/, etc.)
|
|
223
|
+
- **GUILTY if:** A view/page component exists but no route points to it
|
|
224
|
+
- Evidence required: Route config file:line showing the route, or "NOT FOUND"
|
|
225
|
+
- Also check: Does the route have a navigation link (sidebar, navbar, menu)? A route with no nav link might be intentionally hidden (deep link) or might be orphaned
|
|
226
|
+
|
|
227
|
+
### Dimension 4: Store Field Consumption (Redux/Zustand/Pinia/etc.)
|
|
228
|
+
- Trace: Store field defined → selector/hook reads it → component uses the value
|
|
229
|
+
- Method: Search for store selectors, useSelector calls, useStore hooks that reference the field
|
|
230
|
+
- **GUILTY if:** Store field is written but never read anywhere
|
|
231
|
+
- Evidence required: Component file:line where the field is consumed, or "NOT FOUND"
|
|
232
|
+
|
|
233
|
+
### Dimension 5: API Function Invocation
|
|
234
|
+
- Trace: API function defined → called by hook/component/other function → used in app
|
|
235
|
+
- Method: Search for function call sites
|
|
236
|
+
- **GUILTY if:** API function is exported but never called anywhere
|
|
237
|
+
- Evidence required: Call site file:line, or "NOT FOUND"
|
|
238
|
+
|
|
239
|
+
**Non-React projects:** Skip Dimensions 2-3 if no JSX framework detected. Focus on import chain (D1), data flow (D4 adapted to the project's state management), and function invocation (D5).
|
|
240
|
+
|
|
241
|
+
**Output format for this layer:**
|
|
242
|
+
```
|
|
243
|
+
Layer 2 findings:
|
|
244
|
+
- [UNWIRED_COMPONENT] src/components/NewWidget.tsx — imported in Dashboard.tsx:5 but never rendered in JSX (Dimension 2 FAIL)
|
|
245
|
+
- [ORPHAN_ROUTE] src/views/SettingsView.tsx — no route in router config points to this view (Dimension 3 FAIL)
|
|
246
|
+
- [DEAD_STORE_FIELD] src/store/userSlice.ts:23 — `userPreferences` written in reducer but never read by any selector (Dimension 4 FAIL)
|
|
247
|
+
- [UNCALLED_API] src/api/billing.ts:15 — `fetchInvoices()` exported but never called (Dimension 5 FAIL)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
**Key principle:** File:line evidence for EVERY finding. "I think this might be unused" is NOT acceptable. Show the grep results, show the missing link in the chain.
|
|
251
|
+
|
|
252
|
+
## Layer 3: Auto-Fix and Changelog
|
|
253
|
+
|
|
254
|
+
**Purpose:** When Layer 1 or Layer 2 finds unwired code, this layer generates fixes, applies them, re-verifies, and produces a structured changelog.
|
|
255
|
+
|
|
256
|
+
**Fix Strategies by Finding Type:**
|
|
257
|
+
|
|
258
|
+
| Finding Type | Fix Strategy | Fallback |
|
|
259
|
+
|---|---|---|
|
|
260
|
+
| `UNUSED_FILE` | If the file was created by the current task, add import from the appropriate parent module. If it's pre-existing dead code, flag for removal. | Flag for manual review — might be intentionally standalone (config, script) |
|
|
261
|
+
| `UNUSED_EXPORT` | If another module should consume it (check wiring contract), add the import. If truly unnecessary, remove the export keyword. | Flag for manual review |
|
|
262
|
+
| `UNWIRED_COMPONENT` | Add `<ComponentName />` to the parent component's JSX return. Determine placement from component name and parent structure. | Flag — can't determine correct placement |
|
|
263
|
+
| `ORPHAN_ROUTE` | Add route entry to the router config. Infer path from component name (e.g., `SettingsView` → `/settings`). Add nav link to sidebar/navbar if one exists. | Flag — route path ambiguous |
|
|
264
|
+
| `DEAD_STORE_FIELD` | If a component should read this field (check wiring contract), add the selector/hook usage. If truly unused, remove the field. | Flag — store design decision needed |
|
|
265
|
+
| `UNCALLED_API` | If a hook or component should call this (check wiring contract), add the invocation. If truly unused, remove the function. | Flag — API integration decision needed |
|
|
266
|
+
| `UNUSED_DEP` | Remove from package.json `dependencies` or `devDependencies`. | Flag if it might be used in scripts, config files, or CLI |
|
|
267
|
+
| `UNLISTED_DEP` | Run `npm install <package>` (or appropriate package manager command). | Flag if the import might be wrong |
|
|
268
|
+
| `MISSING_INTENT_ENTRY` | Generate INTENT.md entry from function code (Does/Why/Relationships/Decisions). Append to module's INTENT.md. | Flag if function purpose is ambiguous |
|
|
269
|
+
| `STALE_INTENT_ENTRY` | Remove the entry from INTENT.md. | Flag if unsure whether function was renamed vs deleted |
|
|
270
|
+
| `MISSING_MODULE_INTENT` | Create module INTENT.md with entries for all public functions. | Flag if module has no clear public API |
|
|
271
|
+
| `MISSING_MODULE_MAP_ROW` | Add row to root INTENT.md module map table. | Flag if module purpose is unclear |
|
|
272
|
+
|
|
273
|
+
**Fix Protocol (for each finding):**
|
|
274
|
+
|
|
275
|
+
1. **Report** — Log the finding with type, file:line, and evidence
|
|
276
|
+
2. **Determine fix** — Match finding type to fix strategy above. Check wiring contract if available for guidance on WHERE to wire.
|
|
277
|
+
3. **Show proposed fix** — Display the exact code change before applying:
|
|
278
|
+
```
|
|
279
|
+
FIX: [UNWIRED_COMPONENT] NewWidget in Dashboard.tsx
|
|
280
|
+
Proposed: Add <NewWidget /> to Dashboard.tsx return JSX after line 45
|
|
281
|
+
```
|
|
282
|
+
4. **Apply fix** — Use Edit tool to make the change
|
|
283
|
+
5. **Re-verify** — Run the specific check that found the issue:
|
|
284
|
+
- For knip findings: re-run `npx knip --reporter json`
|
|
285
|
+
- For adversarial findings: re-trace the specific wiring dimension
|
|
286
|
+
6. **Log to changelog** — Record: timestamp, finding, fix applied, verification result
|
|
287
|
+
|
|
288
|
+
**When auto-fix is NOT possible:**
|
|
289
|
+
|
|
290
|
+
Some findings can't be auto-fixed safely:
|
|
291
|
+
- Ambiguous placement (where exactly should the component render?)
|
|
292
|
+
- Design decisions needed (should this store field exist at all?)
|
|
293
|
+
- Cross-cutting changes (fix requires modifying 5+ files)
|
|
294
|
+
- Test-only code (might be intentionally not wired into app)
|
|
295
|
+
|
|
296
|
+
For these, flag them clearly:
|
|
297
|
+
```
|
|
298
|
+
MANUAL_INTERVENTION_NEEDED:
|
|
299
|
+
- [ORPHAN_ROUTE] src/views/AdminPanel.tsx — cannot determine route path or nav placement
|
|
300
|
+
Suggested action: Add route to router config and nav link to sidebar
|
|
301
|
+
Reason auto-fix skipped: Multiple possible route paths (/admin, /settings/admin, /dashboard/admin)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Re-verification after all fixes:**
|
|
305
|
+
|
|
306
|
+
After all auto-fixes are applied:
|
|
307
|
+
1. Re-run Layer 1 (knip) — confirm no new unused code introduced by fixes
|
|
308
|
+
2. Re-run Layer 2 (adversarial audit on the fix diff) — confirm fixes actually wire correctly
|
|
309
|
+
3. If re-verification finds new issues, fix those too (max 3 iterations to prevent loops)
|
|
310
|
+
|
|
311
|
+
**Changelog format:**
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
### FTM Audit Changelog — [YYYY-MM-DD HH:MM]
|
|
315
|
+
|
|
316
|
+
#### Findings
|
|
317
|
+
| # | Type | Location | Description |
|
|
318
|
+
|---|------|----------|-------------|
|
|
319
|
+
| 1 | UNWIRED_COMPONENT | src/components/Widget.tsx | Imported but not rendered in Dashboard |
|
|
320
|
+
| 2 | ORPHAN_ROUTE | src/views/Settings.tsx | No route config entry |
|
|
321
|
+
|
|
322
|
+
#### Fixes Applied
|
|
323
|
+
| # | Finding | Fix | Verified |
|
|
324
|
+
|---|---------|-----|----------|
|
|
325
|
+
| 1 | UNWIRED_COMPONENT Widget | Added <Widget /> to Dashboard.tsx:47 | ✅ PASS |
|
|
326
|
+
| 2 | ORPHAN_ROUTE Settings | Added /settings route to router.tsx:23 | ✅ PASS |
|
|
327
|
+
|
|
328
|
+
#### Manual Intervention Required
|
|
329
|
+
| # | Finding | Reason | Suggested Action |
|
|
330
|
+
|---|---------|--------|-----------------|
|
|
331
|
+
| (none) | | | |
|
|
332
|
+
|
|
333
|
+
#### Final Status: PASS (0 remaining issues)
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Wiring Contracts
|
|
337
|
+
|
|
338
|
+
**What:** A wiring contract is a YAML block in a plan task that declares the expected wiring for code produced by that task. It tells ftm-audit exactly what to verify — instead of guessing, the audit checks specific expectations.
|
|
339
|
+
|
|
340
|
+
**Schema:**
|
|
341
|
+
|
|
342
|
+
```yaml
|
|
343
|
+
Wiring:
|
|
344
|
+
exports:
|
|
345
|
+
- symbol: ComponentName # What's being exported
|
|
346
|
+
from: src/components/Thing.tsx # From which file
|
|
347
|
+
|
|
348
|
+
imported_by:
|
|
349
|
+
- file: src/views/Dashboard.tsx # Which file should import it
|
|
350
|
+
line_hint: "import section" # Approximate location (optional)
|
|
351
|
+
|
|
352
|
+
rendered_in: # For React components
|
|
353
|
+
- parent: Dashboard # Parent component name
|
|
354
|
+
placement: "main content area" # Where in the JSX (descriptive)
|
|
355
|
+
|
|
356
|
+
route_path: /dashboard/thing # For routed views (optional)
|
|
357
|
+
|
|
358
|
+
nav_link: # For views that need navigation (optional)
|
|
359
|
+
- location: sidebar # Where the nav link goes
|
|
360
|
+
label: "Thing" # Display text
|
|
361
|
+
|
|
362
|
+
store_reads: # Store fields this code reads (optional)
|
|
363
|
+
- store: useAppStore
|
|
364
|
+
field: user.preferences
|
|
365
|
+
|
|
366
|
+
store_writes: # Store fields this code writes (optional)
|
|
367
|
+
- store: useAppStore
|
|
368
|
+
field: user.preferences
|
|
369
|
+
action: setPreferences
|
|
370
|
+
|
|
371
|
+
api_calls: # API functions this code invokes (optional)
|
|
372
|
+
- function: fetchUserPrefs
|
|
373
|
+
from: src/api/user.ts
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
**All fields are optional.** Graceful degradation:
|
|
377
|
+
- Full contract → audit checks every declared wire
|
|
378
|
+
- Partial contract → audit checks what's declared, uses heuristics for the rest
|
|
379
|
+
- No contract → audit falls back to pure Layer 1 + Layer 2 analysis
|
|
380
|
+
|
|
381
|
+
**Example: React Component Task**
|
|
382
|
+
|
|
383
|
+
```yaml
|
|
384
|
+
### Task 3: Build UserPreferences component
|
|
385
|
+
**Files:** Create src/components/UserPreferences.tsx
|
|
386
|
+
**Wiring:**
|
|
387
|
+
exports:
|
|
388
|
+
- symbol: UserPreferences
|
|
389
|
+
from: src/components/UserPreferences.tsx
|
|
390
|
+
imported_by:
|
|
391
|
+
- file: src/views/SettingsView.tsx
|
|
392
|
+
rendered_in:
|
|
393
|
+
- parent: SettingsView
|
|
394
|
+
placement: "below profile section"
|
|
395
|
+
store_reads:
|
|
396
|
+
- store: useAppStore
|
|
397
|
+
field: user.preferences
|
|
398
|
+
api_calls:
|
|
399
|
+
- function: updatePreferences
|
|
400
|
+
from: src/api/user.ts
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Example: API Client Function Task**
|
|
404
|
+
|
|
405
|
+
```yaml
|
|
406
|
+
### Task 5: Add billing API functions
|
|
407
|
+
**Files:** Create src/api/billing.ts
|
|
408
|
+
**Wiring:**
|
|
409
|
+
exports:
|
|
410
|
+
- symbol: fetchInvoices
|
|
411
|
+
from: src/api/billing.ts
|
|
412
|
+
- symbol: createSubscription
|
|
413
|
+
from: src/api/billing.ts
|
|
414
|
+
imported_by:
|
|
415
|
+
- file: src/hooks/useBilling.ts
|
|
416
|
+
api_calls: [] # These ARE the API functions — nothing to call downstream
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**Example: New Route/View Task**
|
|
420
|
+
|
|
421
|
+
```yaml
|
|
422
|
+
### Task 7: Build AnalyticsDashboard view
|
|
423
|
+
**Files:** Create src/views/AnalyticsDashboard.tsx
|
|
424
|
+
**Wiring:**
|
|
425
|
+
exports:
|
|
426
|
+
- symbol: AnalyticsDashboard
|
|
427
|
+
from: src/views/AnalyticsDashboard.tsx
|
|
428
|
+
imported_by:
|
|
429
|
+
- file: src/router.tsx
|
|
430
|
+
rendered_in:
|
|
431
|
+
- parent: RouterConfig
|
|
432
|
+
placement: "route element"
|
|
433
|
+
route_path: /analytics
|
|
434
|
+
nav_link:
|
|
435
|
+
- location: sidebar
|
|
436
|
+
label: "Analytics"
|
|
437
|
+
icon: BarChart
|
|
438
|
+
store_reads:
|
|
439
|
+
- store: useAppStore
|
|
440
|
+
field: analytics.dateRange
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
**How ftm-audit checks contracts:**
|
|
444
|
+
|
|
445
|
+
For each field in the wiring contract:
|
|
446
|
+
|
|
447
|
+
1. **exports** → Verify the symbol exists as a named export in the specified file. Use `grep "export.*ComponentName"` or AST-level check.
|
|
448
|
+
2. **imported_by** → Verify the importing file contains `import { Symbol } from './path'`. Check the actual import statement exists.
|
|
449
|
+
3. **rendered_in** → Verify the parent component's JSX contains `<Symbol`. If `placement` is specified, verify approximate location.
|
|
450
|
+
4. **route_path** → Verify the router config contains a route with this path pointing to this component.
|
|
451
|
+
5. **nav_link** → Verify the navigation component (sidebar/navbar) contains a link with matching label and path.
|
|
452
|
+
6. **store_reads** → Verify a selector/hook call reads this field in the component.
|
|
453
|
+
7. **store_writes** → Verify a dispatch/action call writes this field.
|
|
454
|
+
8. **api_calls** → Verify the function is imported and called somewhere in the component or its hooks.
|
|
455
|
+
|
|
456
|
+
Each check produces: `✅ VERIFIED file:line` or `❌ NOT FOUND — [what was expected] [where it was expected]`
|
|
457
|
+
|
|
458
|
+
## Phase 3: Runtime Wiring (Optional)
|
|
459
|
+
|
|
460
|
+
**Prerequisite**: This phase runs only when ALL of these conditions are met:
|
|
461
|
+
1. The ftm-browse binary exists at `$HOME/.claude/skills/ftm-browse/bin/ftm-browse`
|
|
462
|
+
2. A dev server is running (detected via `lsof -i :3000` or `lsof -i :5173` or `lsof -i :8080`)
|
|
463
|
+
3. The wiring contracts for the audited tasks include `route_path` entries
|
|
464
|
+
|
|
465
|
+
If any prerequisite is not met, skip this phase with a note explaining which condition failed.
|
|
466
|
+
|
|
467
|
+
**What it checks**: Components and routes that passed static analysis (Phases 1-2) actually render in the running application.
|
|
468
|
+
|
|
469
|
+
### Process
|
|
470
|
+
|
|
471
|
+
For each wiring contract that includes a `route_path`:
|
|
472
|
+
|
|
473
|
+
1. **Navigate**: `$PB goto <dev_server_url><route_path>`
|
|
474
|
+
2. **Snapshot**: `$PB snapshot -i` to get the ARIA tree of interactive elements
|
|
475
|
+
3. **Verify components render**: Check that the expected components from the wiring contract appear in the ARIA tree. Look for:
|
|
476
|
+
- Expected buttons, links, inputs by their labels/roles
|
|
477
|
+
- Expected headings and landmarks
|
|
478
|
+
- Expected form fields
|
|
479
|
+
4. **Screenshot**: `$PB screenshot` as evidence of the render state
|
|
480
|
+
5. **Report findings**:
|
|
481
|
+
- PASS: All expected components found in ARIA tree
|
|
482
|
+
- WARN: Page renders but some expected components are missing
|
|
483
|
+
- FAIL: Page doesn't render (blank, error page, 404)
|
|
484
|
+
|
|
485
|
+
Where `$PB` is `$HOME/.claude/skills/ftm-browse/bin/ftm-browse`.
|
|
486
|
+
|
|
487
|
+
### Integration with Phases 1-2
|
|
488
|
+
|
|
489
|
+
Runtime wiring catches a category of bugs that static analysis cannot:
|
|
490
|
+
- Component is imported and used in JSX but conditionally rendered (and the condition is false)
|
|
491
|
+
- Route is registered but the page component crashes on mount
|
|
492
|
+
- Component renders but is hidden via CSS (visibility: hidden, display: none)
|
|
493
|
+
- Server-side data dependency fails, leaving the component in an error state
|
|
494
|
+
|
|
495
|
+
If Phase 3 finds issues that Phases 1-2 missed, flag them as **runtime-only findings** in the audit report.
|
|
496
|
+
|
|
497
|
+
### Graceful Degradation
|
|
498
|
+
|
|
499
|
+
If ftm-browse is not installed or the dev server is not running:
|
|
500
|
+
- Log: "Phase 3 (Runtime Wiring) skipped — [reason: no browse binary | no dev server | no route_path in contracts]"
|
|
501
|
+
- Do NOT fail the overall audit
|
|
502
|
+
- Phases 1-2 results stand on their own
|
|
503
|
+
|
|
504
|
+
## Execution Protocol
|
|
505
|
+
|
|
506
|
+
When invoked (manually via `/ftm-audit` or automatically post-task):
|
|
507
|
+
|
|
508
|
+
1. Run Phase 0 (detect project patterns — framework, router, state, API layer)
|
|
509
|
+
2. Run Layer 1 (knip static analysis)
|
|
510
|
+
3. Run Layer 1.5 (documentation coverage check — INTENT.md entries for changed functions)
|
|
511
|
+
4. Run Layer 2 (LLM adversarial audit, calibrated to detected patterns)
|
|
512
|
+
5. Combine findings, deduplicate
|
|
513
|
+
6. Run Layer 3 (auto-fix) for each finding (including missing INTENT.md entries)
|
|
514
|
+
7. Re-verify (re-run Layers 1+1.5+2)
|
|
515
|
+
8. Run Phase 3 (runtime wiring via ftm-browse, if prerequisites met)
|
|
516
|
+
9. Produce final changelog report
|
|
517
|
+
|
|
518
|
+
## Blackboard Write
|
|
519
|
+
|
|
520
|
+
After completing, update the blackboard:
|
|
521
|
+
|
|
522
|
+
1. Update `~/.claude/ftm-state/blackboard/context.json`:
|
|
523
|
+
- Set current_task status to "complete"
|
|
524
|
+
- Append decision summary to recent_decisions (cap at 10)
|
|
525
|
+
- Update session_metadata.skills_invoked and last_updated
|
|
526
|
+
2. Write an experience file to `~/.claude/ftm-state/blackboard/experiences/YYYY-MM-DD_task-slug.json` capturing findings count, fix count, which wiring dimensions fired, and any manual interventions required
|
|
527
|
+
3. Update `~/.claude/ftm-state/blackboard/experiences/index.json` with the new entry
|
|
528
|
+
4. Emit `audit_complete` event
|
|
529
|
+
|
|
530
|
+
## Report Format
|
|
531
|
+
|
|
532
|
+
```
|
|
533
|
+
## FTM Audit Report — [timestamp]
|
|
534
|
+
|
|
535
|
+
### Layer 1: Static Analysis (knip)
|
|
536
|
+
- Findings: [N]
|
|
537
|
+
- [list each finding with file:line]
|
|
538
|
+
|
|
539
|
+
### Layer 1.5: Documentation Coverage
|
|
540
|
+
- Findings: [N]
|
|
541
|
+
- [list each finding — missing entries, stale entries, missing module docs]
|
|
542
|
+
|
|
543
|
+
### Layer 2: Adversarial Audit
|
|
544
|
+
- Findings: [N]
|
|
545
|
+
- [list each finding with file:line and evidence]
|
|
546
|
+
|
|
547
|
+
### Layer 3: Auto-Fix Results
|
|
548
|
+
- Fixed: [N]
|
|
549
|
+
- Manual intervention needed: [N]
|
|
550
|
+
- [list each fix applied]
|
|
551
|
+
|
|
552
|
+
### Final Status: PASS / FAIL
|
|
553
|
+
- Remaining issues: [list if any]
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
## Requirements
|
|
557
|
+
|
|
558
|
+
- tool: `knip` | optional | static dead-code and unused-export analysis (Layer 1)
|
|
559
|
+
- tool: `node` | required | runtime for knip via npx
|
|
560
|
+
- config: `knip.config.ts` | optional | custom knip configuration at project root
|
|
561
|
+
- reference: `references/protocols/PROJECT-PATTERNS.md` | required | framework detection table and dimension activation matrix
|
|
562
|
+
- reference: `references/strategies/AUTO-FIX-STRATEGIES.md` | required | fix actions by finding type
|
|
563
|
+
- reference: `references/protocols/WIRING-CONTRACTS.md` | optional | wiring contract schema for plan-driven audits
|
|
564
|
+
- reference: `references/protocols/RUNTIME-WIRING.md` | optional | runtime verification protocol
|
|
565
|
+
- reference: `references/templates/REPORT-FORMAT.md` | required | structured report template
|
|
566
|
+
- tool: `$HOME/.claude/skills/ftm-browse/bin/ftm-browse` | optional | runtime wiring verification via browser (Phase 3)
|
|
567
|
+
|
|
568
|
+
## Risk
|
|
569
|
+
|
|
570
|
+
- level: medium_write
|
|
571
|
+
- scope: modifies source files to fix wiring issues (auto-fix layer); also adds/removes imports and route registrations; reads codebase broadly
|
|
572
|
+
- rollback: git checkout on auto-fixed files; all changes are tracked in the changelog report before being applied
|
|
573
|
+
|
|
574
|
+
## Approval Gates
|
|
575
|
+
|
|
576
|
+
- trigger: auto-fix proposed for a finding | action: report proposed change before applying (show "Proposed: ..." format)
|
|
577
|
+
- trigger: finding flagged MANUAL_INTERVENTION_NEEDED | action: surface to user with suggested action, do not auto-fix
|
|
578
|
+
- trigger: re-verification still fails after 3 iterations | action: stop and report remaining issues to user
|
|
579
|
+
- complexity_routing: micro → auto | small → auto | medium → plan_first | large → plan_first | xl → always_ask
|
|
580
|
+
|
|
581
|
+
## Fallbacks
|
|
582
|
+
|
|
583
|
+
- condition: knip not installed and npx unavailable | action: skip Layer 1, run Layer 2 adversarial audit only
|
|
584
|
+
- condition: no package.json found | action: skip knip entirely, run adversarial audit only
|
|
585
|
+
- condition: ftm-browse not installed | action: skip Phase 3 runtime wiring check, log reason and continue
|
|
586
|
+
- condition: dev server not running | action: skip Phase 3 runtime wiring check, log reason and continue
|
|
587
|
+
- condition: wiring contracts absent | action: run pure Layer 1 + Layer 2 analysis without contract checking
|
|
588
|
+
- condition: project has no identifiable entry point | action: skip knip, run adversarial audit only
|
|
589
|
+
|
|
590
|
+
## Capabilities
|
|
591
|
+
|
|
592
|
+
- cli: `knip` | optional | dead code detection via npx knip
|
|
593
|
+
- cli: `node` | required | JavaScript runtime for npx
|
|
594
|
+
- cli: `$HOME/.claude/skills/ftm-browse/bin/ftm-browse` | optional | headless browser for runtime wiring
|
|
595
|
+
- mcp: `git` | optional | diff scope for Layer 2 adversarial audit
|
|
596
|
+
|
|
597
|
+
## Event Payloads
|
|
598
|
+
|
|
599
|
+
### audit_complete
|
|
600
|
+
- skill: string — "ftm-audit"
|
|
601
|
+
- findings_count: number — total issues found across all layers
|
|
602
|
+
- auto_fixed_count: number — issues auto-remediated by Layer 3
|
|
603
|
+
- manual_count: number — issues requiring manual intervention
|
|
604
|
+
- scope: string[] — file paths audited
|
|
605
|
+
- duration_ms: number — total audit duration
|
|
606
|
+
- layers_run: string[] — which layers executed (e.g., ["layer1", "layer2", "layer3"])
|
|
607
|
+
|
|
608
|
+
### issue_found
|
|
609
|
+
- skill: string — "ftm-audit"
|
|
610
|
+
- layer: string — "layer1" | "layer2" | "layer3"
|
|
611
|
+
- dimension: string — D1 | D2 | D3 | D4 | D5 (for Layer 2 findings)
|
|
612
|
+
- finding_type: string — exports | types | duplicates | UNWIRED_COMPONENT | etc.
|
|
613
|
+
- file_path: string — affected file
|
|
614
|
+
- symbol: string — affected symbol name
|
|
615
|
+
- severity: string — CRITICAL | HIGH | MEDIUM | LOW
|
|
616
|
+
- auto_fixable: boolean — whether Layer 3 can fix this automatically
|
|
617
|
+
|
|
618
|
+
### task_completed
|
|
619
|
+
- skill: string — "ftm-audit"
|
|
620
|
+
- result: string — "pass" | "pass_with_fixes" | "fail"
|
|
621
|
+
- findings_count: number — total findings
|
|
622
|
+
- auto_fixed_count: number — auto-remediated count
|
|
623
|
+
- manual_count: number — manual intervention needed
|