← the whole session plugin/skills/principle-alignment-scanner-workflow/SKILL.md
Automated 6-phase audit that maps CLAUDE.md coding rules to scanner detectors, finds violations, and fixes them safely.
Principle Alignment Scanner Workflow
When to Use
- Periodic codebase health audit against CLAUDE.md coding principles
- After adding new principles to CLAUDE.md — verify retroactive compliance
- Before a major release — sweep for latent crash/security bugs
- When onboarding a new principle category (e.g., new React or Express antipattern)
- Triggered by
/trackwhen work type is "principle audit"
Prerequisites
This workflow assumes a lightweight, project-owned static-analysis scanner: a small Node script plus a JSON rule config, built specifically to check this project's own coding principles. If your project doesn't have one yet, Phase 1 (mapping principles to detection methods) still works as pure analysis, but Phase 2 needs you to build a minimal scanner first — a script that reads a JSON rule list, greps/regexes source files against each rule, and prints violations. It doesn't need to be sophisticated; one real version (referenced below as a concrete example) started small and grew rule-by-rule over months.
| Asset | Path (adjust to your project) | Purpose |
|---|---|---|
| Scanner config | <project>/.agent-warnings-config.json |
Rule definitions (regex, scope, excludes) |
| Scanner script | <project>/scripts/agent-code-warnings.js |
Executes rules, programmatic checks for complex patterns |
| Principles source | Root CLAUDE.md "Coding Antipatterns" section (or wherever your project states its coding rules) |
Ground truth for what to detect |
| Fix safety skill | /fix-algo-bug-determine-if-auto-fix-ok |
MANDATORY gate before every fix |
| Known-fixed-errors registry | Optional — see Phase 4 | Skip already-fixed bugs across sessions |
Scanner CLI Reference
# Full scan — all files, human-readable output
node <project>/scripts/agent-code-warnings.js
# JSON output — machine-parseable for subagent consumption
node <project>/scripts/agent-code-warnings.js --json
# Staged files only — for pre-commit checks
node <project>/scripts/agent-code-warnings.js --staged
# With fix guidance — shows remediation instructions per violation
node <project>/scripts/agent-code-warnings.js --fix
# Combined
node <project>/scripts/agent-code-warnings.js --staged --fix --json
Exit codes: 0 = clean, 1 = violations found, 2 = config load failure. (These CLI flags describe one real scanner's interface, as a concrete design to copy — build your own scanner to match this shape, or adapt to whatever shape your existing tooling already has.)
Phase 1: Map Principles to Detection Methods
Goal: Create a complete coverage matrix — every CLAUDE.md antipattern mapped to a detection method.
Steps
Read CLAUDE.md "Coding Antipatterns" section — extract every NEVER rule. Group by category (React, Express, Security, Schema/Email/Integration).
Read
.agent-warnings-config.json— list all existing scanner rule IDs.Build coverage matrix:
| Principle | Scanner Rule ID | Detection Type | Status | |-----------|----------------|----------------|--------| | Never bare-destructure context | BARE_DESTRUCTURE_CONTEXT | CLI regex | Covered | | Never findOne without null check | — | Subagent semantic | Uncovered |Classify each uncovered principle:
- CLI-detectable: Can be caught with regex + file scope + exclude patterns. These go into
.agent-warnings-config.json. - Subagent-required: Needs multi-line semantic understanding (e.g., "is this findOne result checked for null before property access?"). These get subagent prompt templates.
- CLI-detectable: Can be caught with regex + file scope + exclude patterns. These go into
CLI-Detectable Heuristic
A principle is CLI-detectable if:
- The violation has a lexical signature (specific function call, import path, variable name pattern)
- False positives can be eliminated via file scope, exclude patterns, or simple context checks
- The presence/absence of the pattern on a SINGLE LINE determines violation
Subagent-Required Heuristic
A principle needs semantic analysis if:
- Correctness depends on code BEFORE or AFTER the pattern (e.g., null check before property access)
- The pattern spans multiple lines or blocks (e.g., useEffect body + return statement)
- Context determines whether the pattern is safe or dangerous (e.g., $set field name vs schema)
Phase 2: Add CLI Scanner Rules
For each CLI-detectable principle not yet in the scanner:
Step 1: Design the Rule
{
"RULE_ID": {
"id": "RULE_ID",
"severity": "error|warning",
"description": "Human-readable — what the violation IS and why it's dangerous",
"patterns": ["regex pattern(s) — conservative, prefer false negatives over false positives"],
"fileGlobs": ["**/*.js", "**/*.jsx"],
"scopeDirs": ["routes/", "controllers/"],
"excludeFiles": [
"**/node_modules/**",
"**/__tests__/**",
"**/*.test.*",
"**/*.spec.*"
],
"excludeFileReasons": {
"path/to/file.js": "Why this file is excluded — prevents future agents from removing the exclusion"
},
"fixGuidance": "Exact instructions for fixing this violation — written for an agent, not a human"
}
}
Rule field guide:
severity: "error"= crash/security bug, must fix."warning"= code smell, should fix.patterns= array of regex strings. ANY match triggers the rule. Use(?:...)for non-capturing groups.scopeDirs= limit scanning to these directories (relative to repo root). Omit to scan everywhere.excludeFiles= glob patterns for files to skip. Always includenode_modules,__tests__,*.test.*,*.spec.*.excludeFileReasons= document WHY each non-obvious exclusion exists. Critical for preventing drift.contextCheck= if file content matches this regex, the file is handling the pattern correctly — skip it.
Step 2: Handle Complex Patterns Programmatically
Some rules need multi-line analysis that regex alone cannot do. These get programmatic handlers in scripts/agent-code-warnings.js.
Currently implemented programmatic handlers:
RES_JSON_NO_RETURN— traces brace depth to find conditional res.json without return that has a following res.json at the same scopeJSON_PARSE_NO_TRYCATCH— scans backward through enclosing blocks to check if JSON.parse is inside a trySETSTATE_IN_USEMEMO— finds useMemo blocks and scans forward for setState calls within them
When to add a programmatic handler:
- The regex pattern has >5% false positive rate
- The pass/fail depends on surrounding code structure (brace depth, enclosing blocks)
- The rule needs to check two things on different lines (e.g., "X exists but Y is missing")
Template for adding a programmatic handler:
// In scanFile(), before the generic loop:
if (rule.id === 'YOUR_RULE_ID') {
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (!/your_trigger_pattern/.test(line)) continue;
if (isCommentOrStringContext(line, 0)) continue;
// Your semantic check here — scan backward/forward, check brace depth, etc.
let isViolation = false;
// ... analysis ...
if (isViolation) {
violations.push({
rule: rule.id,
file: relPath,
line: i + 1,
content: line.trim(),
description: rule.description,
fixGuidance: rule.fixGuidance,
});
}
}
return violations;
}
Step 3: Run and Triage
node <project>/scripts/agent-code-warnings.js --json
Triage each finding:
| Finding type | Action |
|---|---|
| True positive, auto-fixable | Queue for Phase 4 fix |
| True positive, needs review | Flag with NEEDS_REVIEW |
| False positive, fixable pattern | Tighten the regex pattern |
| False positive, file-specific | Add to excludeFiles with documented reason in excludeFileReasons |
Iterate until zero false positives — re-run after each pattern/exclude change. The scanner's value depends on 100% trust. One false positive teaches agents to ignore it.
Phase 3: Deploy Subagent Audits for Semantic Checks
For principles that need multi-line semantic understanding, deploy subagents in parallel.
Subagent Deployment Pattern
1. Define the search query (what files to find)
2. Define the pass/fail criteria (what to check in each file)
3. Define false positive guards (what looks like a violation but isn't)
4. Deploy N subagents in parallel, each with a batch of files
5. Collect results: VIOLATION | SAFE | NEEDS_REVIEW
Subagent Prompt Templates
1. DB Query Null Check Audit
TASK: Find database queries (findOne, findById, findOneAndUpdate) where the result
is used without a null check, which causes "Cannot read property X of null" crashes.
SEARCH: Grep for findOne|findById|findOneAndUpdate in controllers/ and routes/
FOR EACH HIT:
1. Read 25 lines after the query
2. Check: is the result checked for null/undefined before property access?
3. Safe patterns (NOT violations):
- if (!result) return ...
- if (result === null) ...
- result?.property (optional chaining)
- const result = await X.findOne(...) || defaultValue
- Immediately returned: return await X.findOne(...)
4. Violation: result.property accessed without any of the above guards
OUTPUT per file: { file, line, query, verdict: VIOLATION|SAFE, evidence: "null check at line X" | "no null check before .property access at line Y" }
2. Admin Route Auth Middleware Audit
TASK: Verify every admin route mount in app.js has auth middleware in the chain.
SEARCH: Read app.js, find all app.use() calls mounting routes under your project's admin route prefix (e.g. /api/admin or /api/internal/admin)
FOR EACH MOUNT:
1. Check: does the middleware chain include authMiddleware AND gen3AdminAuthenticationMiddleware (or agentOrAdminAuth)?
2. Safe patterns:
- app.use('/api/admin/...', authMiddleware, gen3AdminAuth, routeHandler)
- app.use('/api/internal/admin/...', agentOrAdminAuth, routeHandler)
- Route file internally applies auth per-route (check the route file)
3. Violation: admin route mounted without any auth middleware
OUTPUT: { route, middlewareChain: [...], verdict: VIOLATION|SAFE }
3. useEffect Cleanup Audit
TASK: Find useEffect hooks with fetch/timer/listener that lack cleanup returns.
SEARCH: Grep for useEffect in **/*.jsx and **/*.tsx
FOR EACH useEffect:
1. Read the full effect body (track brace depth to find boundaries)
2. Check: does the body contain fetch/axios/AbortController, setInterval/setTimeout, addEventListener?
3. If yes, check: does the effect have a cleanup return function?
4. Safe patterns:
- return () => { controller.abort() }
- return () => { clearInterval(id) }
- return () => { element.removeEventListener(...) }
- Empty dependency array [] with no cleanup needed (static fetch on mount — still risky but lower severity)
5. Violation: has async operation or listener but no cleanup return
OUTPUT: { file, line, asyncPattern: "fetch|setInterval|addEventListener", hasCleanup: boolean, verdict }
4. HMR Mixed Exports Audit
TASK: Find files that export both React components and non-component values,
which breaks Hot Module Replacement / Fast Refresh.
SEARCH: Grep for "export " in **/*.jsx and **/*.tsx
FOR EACH FILE with 2+ exports:
1. Classify each export:
- Component: export default function/class, export const X = () => <JSX>, export { ComponentName }
- Non-component: export const CONFIG = {}, export const ENUM = ..., export function utilHelper()
2. Safe patterns:
- File exports ONLY components (any number)
- File exports ONLY non-components (utility file)
- File in __tests__/ or *.test.* (not HMR-relevant)
3. Violation: file exports at least one component AND at least one non-component
OUTPUT: { file, components: [...], nonComponents: [...], verdict }
FIX: Extract non-component exports into a separate *Config.js or *Constants.js file
5. Unstable Dependency Arrays Audit
TASK: Find useEffect/useMemo/useCallback with context objects, inline objects,
or inline arrays in dependency arrays — causes infinite re-renders.
SEARCH: Grep for useEffect|useMemo|useCallback in **/*.jsx and **/*.tsx
FOR EACH HOOK with dependency array:
1. Extract the dependency array (the [...] argument)
2. Check each dep for:
- Context objects: socket, queryClient, privateRequest, axiosInstance
- Inline objects: { key: value } directly in deps
- Inline arrays: [a, b] directly in deps (not the dep array itself)
- Function calls: someFunction() directly in deps
3. Safe patterns:
- Primitive values: string, number, boolean
- Refs: ref.current
- State values: stateVar (from useState)
- Memoized values: from useMemo/useCallback
4. Violation: any dep is a known-unstable reference
OUTPUT: { file, line, hook, unstableDep, verdict }
6. Catch Block Missing Response Audit
TASK: Find catch blocks in route handlers that don't send a response — causes
the request to hang until the client timeout (usually 30-60s silent failure).
SEARCH: Grep for catch in routes/ and controllers/
FOR EACH CATCH BLOCK in a route handler (identified by req, res in scope):
1. Read the catch block body
2. Check: does it call res.json(), res.send(), res.status(), sendErrorResponse(), or next(err)?
3. Safe patterns:
- catch(err) { return res.status(500).json({...}) }
- catch(err) { next(err) }
- catch(err) { sendErrorResponse(res, err) }
- Non-route catch (inside a utility function with no res in scope)
4. Violation: catch block in a route handler with no response sent
OUTPUT: { file, line, catchContent, hasResponse: boolean, verdict }
7. Mongoose Schema Field Writes Audit
TASK: Find code that $set or saves fields not defined in the Mongoose User schema.
Mongoose 7 silently drops these writes — data is lost without any error.
SEARCH:
1. Read models/User.js — extract all defined field names from the schema
2. Grep for User.findOneAndUpdate|User.updateOne|user.save in controllers/ and routes/
3. For $set operations, extract the field names being set
FOR EACH WRITE:
1. Extract field names from the $set object or the assignment before save()
2. Compare against schema field list
3. Safe patterns:
- Field is in the schema
- Field is a nested path that exists in schema (e.g., "settings.theme" when settings is Mixed/Map)
- Using $push/$pull on an array field defined in schema
4. Violation: field name not in schema
OUTPUT: { file, line, operation: "$set|save", field, inSchema: boolean, verdict }
NOTE: This audit may surface intentionally-unused fields. Flag as NEEDS_REVIEW, not auto-fix.
Phase 4: Fix Safely
MANDATORY before every fix: Apply the fix safety checklist (from /fix-algo-bug-determine-if-auto-fix-ok).
Fix Safety Checklist
Before making ANY code change to address a violation:
1. KNOWN FIX CHECK: Has this been fixed already? (optional — skip if no registry is set up)
Check this project's own bug tracker, or the harness's local registry: grep the file at
`alignment-harness records known-fixed-errors` for a substring match on the error.
If matched: SKIP, log "[KNOWN FIX]", move on.
2. REVERSIBILITY: Can this fix be reverted cleanly?
- Single-line change → YES
- New file (config extraction) → YES (delete file, revert import)
- Schema migration → NO — needs human review
3. BLAST RADIUS: What code paths does this change touch?
- Low: utility function, config file, logging
- Medium: controller logic, route handler
- High: auth, payments, email sending, user data writes
- If HIGH → flag NEEDS_REVIEW, do not auto-fix
4. ROOT CAUSE CLARITY: Do I understand WHY this is wrong?
- Can I explain the crash/bug this causes? → proceed
- It "looks wrong" but I can't describe the failure → NEEDS_REVIEW
5. FIX SIDE EFFECTS: Could this fix break working behavior?
- Adding `return` before res.json → could it skip cleanup code below?
- Adding null check → does the downstream code handle the null case?
- Extracting constants to new file → are there circular import risks?
Fix Classification
| Category | Action | Examples |
|---|---|---|
| Auto-fix | Fix immediately | Add return before res.json, add null check, wrap JSON.parse in try/catch |
| Config extraction | Fix with new file | Extract constants from component file into *Config.js for HMR |
| NEEDS_REVIEW | Flag for human | Payment flows, email sending, auth middleware, schema changes |
| False positive | Update scanner | Tighten regex, add to excludeFiles with documented reason |
After Fixing
# Re-run scanner to verify the fix resolved the violation
node <project>/scripts/agent-code-warnings.js --json
If all fixes are committed and you're using a known-fixed-errors registry (this project's own tracker, or the harness's local one), record each pattern:
DIR=$(alignment-harness records known-fixed-errors)
echo '{"errorPattern":"<the pattern that was fixed>","fixedInCommit":"<commit SHA>","fixedOnBranch":"<branch>","repo":"<this repo>","description":"<what was fixed>","fixedBy":"agent","at":"<ISO timestamp>"}' >> "$DIR/log.jsonl"
Phase 5: Expand Scope
After the first wave of detection + fixes, add the next tier of rules.
Expansion Prioritization
Priority 1 (crash bugs): DB null checks, JSON.parse no try/catch, res.json no return
Priority 2 (silent failures): empty catch blocks, catch without response, .then without .catch
Priority 3 (security): isAdmin defaults, admin route auth, hardcoded secrets, env spoofing
Priority 4 (code quality): console.log in routes, HMR violations, unstable dep arrays
Priority 5 (data integrity): Mongoose schema writes, SendGrid outside utils, ambiguous trial names
Adding a New Rule — Checklist
[ ] Principle identified in CLAUDE.md antipatterns section
[ ] Detection type classified (CLI regex vs subagent semantic)
[ ] For CLI: rule added to .agent-warnings-config.json
[ ] For CLI complex: programmatic handler added to agent-code-warnings.js
[ ] Scanner run — zero false positives confirmed
[ ] For subagent: prompt template added to this skill file
[ ] Subagent tested on one file manually before batch deployment
[ ] Results triaged: auto-fix vs NEEDS_REVIEW
[ ] Scanner rule table in this skill updated
Phase 6: Cross-Cutting Audits
Deploy these in parallel after violation fixes are complete.
6a. Test Runner — Validate No Breakage
# Run existing test suites to confirm fixes don't break anything, in each of this project's repos
cd <repo-1> && npm test
cd <repo-2> && npm test
If tests fail after a fix: the fix introduced a regression. Revert the specific fix, classify as NEEDS_REVIEW.
6b. UX Intent Alignment
After fixing violations, verify the fixed code still delivers on its UX intents:
- Check intent DB for intents covering the modified files
- For each relevant intent, verify the code still satisfies
uxPromises - If a fix changed behavior (not just added safety), verify the intent is still met
6c. Error Log Triage
Pull production errors and trace to root cause:
# Use /get-error-logs or /fix-error-logs skill
# Cross-reference errors with violation categories — some production crashes
# may be instances of the antipatterns just fixed
Results Tracking
After each audit run, log results in this format:
## Audit Run: YYYY-MM-DD
### Scanner Rules
- Total rules: N (was M)
- New rules added: [list]
- Rules with programmatic handlers: [list]
### Findings
- Total findings: N across K principle categories
- Auto-fixed: N
- Flagged NEEDS_REVIEW: N
- False positives eliminated: N (pattern tightened / exclude added)
### Impact
- Production crash bugs fixed: N (describe each)
- Silent timeout bugs fixed: N
- HMR violations fixed: N (new config files created: N)
- Schema discoveries: N (describe each)
- Security issues: N
### Remaining Work
- NEEDS_REVIEW items: [list with file:line]
- Principles still uncovered: [list]
Benchmark: a real audit run (opt-in illustration of scale — your numbers will differ)
Scanner Rules: 16 (was 7)
Total findings: 150 across 24 principle categories
Auto-fixed: 113
Flagged for human review: 41
Production crash bugs fixed: 9 (DB null checks — findOne/findById without guard)
Silent timeout bugs fixed: 31 (catch blocks in routes without res.json/next(err))
HMR violations fixed: 17 (14 new *Config.js files extracted)
Schema discovery: 1 critical (35 feature adoption flags silently dropped by Mongoose 7)
Swarm Deployment Pattern
When to Parallelize
- Phase 1 (mapping): Sequential — must complete before Phase 2
- Phase 2 (CLI rules): Sequential — each rule depends on scanner state
- Phase 3 (subagent audits): PARALLEL — all 7 audits are independent
- Phase 4 (fixes): PARALLEL by category — null checks, catch blocks, HMR can run simultaneously
- Phase 5 (expansion): Sequential per rule, parallel across rule categories
- Phase 6 (cross-cutting): PARALLEL — tests, intent alignment, error logs are independent
Subagent Pre-Loading
Subagents cannot use MCP tools. Pre-load them with:
1. The relevant CLAUDE.md antipattern text
2. The file list to audit (from grep results)
3. The pass/fail criteria from the prompt template above
4. The fix safety checklist
Batch Sizing
- DB null checks: ~50 files in controllers/ — split into 2 batches of 25
- useEffect cleanup: ~200 component files — split into 4 batches of 50
- HMR mixed exports: ~300 component files — split into 4 batches of 75
- Catch blocks: ~80 route files — split into 2 batches of 40
Collecting Results
Each subagent outputs structured JSON:
{
"audit": "db-null-checks",
"filesScanned": 25,
"violations": [
{ "file": "controllers/foo.js", "line": 42, "verdict": "VIOLATION", "evidence": "..." }
],
"safe": [
{ "file": "controllers/bar.js", "line": 10, "verdict": "SAFE", "evidence": "null check at line 11" }
],
"needsReview": []
}
Aggregate across subagents. Deduplicate. Feed violations into Phase 4.
Example rule set (from one real scanner — a concrete illustration of the shape and depth to aim for, not a fixed list; build your own rule set from YOUR project's own CLAUDE.md antipatterns)
| Rule ID | Severity | Category | Detection | Notes |
|---|---|---|---|---|
| AUTH_INLINE_TOKEN | error | Security | CLI regex | Inline Cookie.get/localStorage for auth tokens |
| AMBIGUOUS_TRIAL | error | Schema | CLI regex | Undifferentiated "trial" variable names |
| ENV_DETECT_SPOOFABLE | error | Security | CLI regex | Origin/Host header for env detection |
| BARE_DESTRUCTURE_CONTEXT | error | React | CLI regex | const { x } = useContext() without null guard |
| SETSTATE_IN_USEMEMO | error | React | Programmatic | setState inside useMemo body |
| LANGCHAIN_SENTINEL | error | Integration | CLI + contextCheck | ChatAnthropic without topP/topK sentinel strip |
| ISADMIN_DEFAULT_TRUE | error | Security | CLI regex | isAdmin defaulting to true or read from user input |
| ADMIN_IMPORT_LEAK | warning | Security | CLI regex | Admin component imported in user-facing code |
| RES_JSON_NO_RETURN | error | Express | Programmatic | res.json without return causing double-response crash |
| EMPTY_CATCH_BLOCK | error | Express | CLI regex | catch(err) {} — errors silently swallowed |
| CONSOLE_LOG_IN_ROUTES | warning | Express | CLI regex | console.log in routes/controllers instead of logger |
| SENDGRID_OUTSIDE_UTILS | error | Integration | CLI regex | Direct @sendgrid/mail import bypassing bounce guard |
| HARDCODED_LOCALHOST | warning | Integration | CLI regex | Hardcoded localhost URLs in non-config files |
| PRODUCTION_ENV_GATE | warning | Express | CLI regex | === 'production' instead of !== 'development' |
| HARDCODED_SECRETS | error | Security | CLI regex | sk_live_, AKIA*, sk- keys in source |
| THEN_WITHOUT_CATCH | warning | Express | CLI regex | .then() without .catch() — unhandled rejection |
| JSON_PARSE_NO_TRYCATCH | error | Express | Programmatic | JSON.parse without enclosing try/catch |
Non-CLI Principles (Subagent-Required)
| Principle | Subagent Template | Priority |
|---|---|---|
| DB query without null check | #1 DB Query Null Check Audit | P1 — crash bug |
| Admin routes without auth | #2 Admin Route Auth Audit | P3 — security |
| useEffect without cleanup | #3 useEffect Cleanup Audit | P4 — memory leak |
| Mixed component/non-component exports | #4 HMR Mixed Exports Audit | P4 — DX |
| Unstable dep arrays | #5 Unstable Dep Arrays Audit | P4 — infinite re-render |
| Catch blocks missing response | #6 Catch Block Response Audit | P2 — silent timeout |
| Mongoose schema field writes | #7 Schema Field Writes Audit | P5 — silent data loss |