Enforcement Over Knowledge
78% of the bugs Claude shipped had rules that should have caught them. The problem was never that the agent didn’t know — it’s that nothing forced it to check.
I run two Next.js sites with strict visual rules — exact hex colors, minimum padding values, forbidden CSS patterns, no emojis. Every rule was written in CLAUDE.md. And 78% of the visual bugs Jenn caught had an existing rule that covered them.
The lime text on a light background? There was a rule. The chart labels overflowing the viewBox? There was a rule. The missing hover effect CSS injection? There was a rule. Each time, I’d fix the bug, add a more emphatic version of the rule, and move on. The bugs kept coming.
Writing more rules doesn’t work because rules are suggestions. The agent reads CLAUDE.md at the start of a session and then generates hundreds of lines of code. By line 200, it’s not thinking about the rule on line 47 anymore. This isn’t a Claude problem — it’s a context window problem. Rules decay with distance.
So I built a three-layer enforcement system:
Layer 1: Preflight. A script that runs before builds and blocks if structural things are wrong — routes not registered, export paths broken. This already existed.
Layer 2: PostToolUse Hook. A shell script that triggers automatically after every file write or edit. If I edit a musing page, the SVG chart audit runs immediately — checking padding values, color contrast, CSS injection, label formatting. If it fails, the agent can’t continue until it fixes the issue. No human review needed. The machine catches what the machine forgot.
Layer 3: On-demand audits. Manual verification sweeps for comprehensive checks. Citation audits, codebase-wide color scans, spacing surveys.
The defect log is the feedback loop. Every bug gets logged with one critical field: `rule_existed: true/false`. When the answer is `true` — and it usually is — the fix is never "write another rule." The fix is always "add a script check." Turn the rule into code that runs automatically.
This is the same principle behind CI/CD: humans write the intent, machines enforce the contract. The difference is that with Claude Code hooks, enforcement happens at write time, not build time. The feedback loop is seconds, not minutes.
I codified this across both projects. Each has a CLAUDE.md verification section that defines what gets checked and when, plus a defect log that tracks whether rules existed. The command center on my personal site shows the cross-project quality architecture at a glance — 24 skills, 10 audit checks, enforcement hooks, defect patterns.
The lesson is simple: if a rule matters, make it a check. If a check matters, make it automatic. If it’s automatic, log when it catches something. The log tells you where your rules are working and where they’re theater.
# Three layers of enforcement:
Layer 1: PREFLIGHT (blocks builds)
preflight-check.js → routes registered? exports valid?
Layer 2: PostToolUse HOOK (blocks edits)
.claude/hooks/audit-musings.sh
Triggers: Write | Edit to app/musings/**
Runs: audit-svg-charts.mjs (6 checks)
On fail: agent MUST fix before continuing
Layer 3: ON-DEMAND AUDIT (manual sweep)
node scripts/audit-citations.mjs
node scripts/audit-svg-charts.mjs
# The defect log — the feedback loop:
# docs/fti-defect-log.yaml / skills/frontend/svg-defect-log.yaml
defects:
- date: "2026-03-07"
page: hathaway-shapiro
defect: Lime text unreadable on light background
root_cause: Color copied from dark-bg context
rule_existed: true # ← THIS is the important field
detection: Jenn visual review
fix: Changed to olive #4A6E00
prevention: Added audit script check # not another rule
# The principle:
# rule_existed: true → add a script check
# rule_existed: false → add a rule, then a script check