Giving AI Pain: The Architecture of Synthetic Scars & The Rapid-Regret Miner
Why "my AI ignores my Markdown rules" and "my AI burns through my 7-day quota in 3 days" are the exact same transformer attention bug—and how giving autonomous agents somatic pain and the right to say "No" eliminates repeat regressions across 238 production tickets. "Defending against AI coders mes

"Defending against AI coders messing up your day is the same strategies as defending against junior coders doing the same thing. You have tests. What's missing is that LLMs don't remember pain... You only touch the hot stove once." — Randal L. Schwartz
Walk into almost any developer forum right now—Reddit, Discord, or Hacker News—and you will hear two complaints repeated in an endless chorus. Earlier this week on Reddit ( r/google_antigravity ), developer u/CSachen summarized both in a single post:
To prove point #2, the developer pasted the exact rules from their prompt file that the model kept violating:
// DON'T treat enums as booleans just because they have 2 values const countryName = isUS ( country )? " United States ": Canada // DON'T use silent default fallbacks. const country = row. countryName?? " United States " // DON'T define new functions with optional or polymorphic parameters function foo ( d?: Date | string | undefined | null ) Enter fullscreen mode Exit fullscreen mode Then came the question every frustrated developer eventually asks: "I'm thinking of buying either ChatGPT or Claude Code. Which one should I switch to?"
Developers treat burning through their weekly token quota and the model ignoring their Markdown rules as two separate problems. In reality, they are the exact same symptom of a single closed feedback loop:
flowchart TD A["1. Fuzzy English Prose Rule Ignored\n(Zero potential barrier against pre-training gravity)"] B["2. Developer Argues for 30 Turns\n(Pasting diffs, reprompting, burning 50k tokens/turn)"] C["3.
Developer Adds More 'DON'T' Examples\n(Priming the KV-cache with the exact bad syntax)"] D["4. Context Bloat & Attention Dispersion\n(System prompt swells; compliance drops further)"] E["5. 7-Day Token Quota Vanishes in 72 Hours\n('This model is broken!
Time to vendor-hop!')"] A --> B B --> C C --> D D --> E E --> A Look closely at Step 3 of that loop. When you paste function foo(d?: Date | string | undefined | null) into your system prompt under a // DON'T comment, transformer self-attention loads those exact token representations into the active KV-cache. Under autoregressive generation, tokens in the KV-cache act as semantic attractors.
Telling a transformer "Do not think of a pink elephant while staring at this high-resolution code snippet of a pink elephant" primes the completion logits to emit the very?? fallbacks and nullable union types you wanted to ban.
Before we dive into how we break that loop, here is a quick 30-second decoder ring for two notations from Randal's Public Workflow Gist that you will see throughout this article, in case you are joining the series here:
The TL;DR Punchline: You cannot fix an autonomous coding agent by begging it in English to "be more careful." Over the last 238 production tickets ( 140 open-source + 98 commercial industrial) and 588 codified SCAR-* entries ( Randal's Public Workflow Gist ), our Synthetic Scar Architecture achieved a 0.0% repeat regression rate by replacing advisory prose with four concrete engineering mechanisms:
A developer on Discord recently asked me a fair question:
"What will you do when AI changes something and something unexpected breaks in production? As a vibe coder, what problem is the most painful?"
My answer was simple: defending against AI coders messing up your day requires the exact same strategies as defending against junior coders doing the same thing. You have tests, you have architecture, and you have code review. What is missing is that LLMs are born with congenital analgesia—they do not feel or remember pain. A human junior only touches a red-hot stove once. A raw LLM will cheerfully press its palm onto the burner on every single ticket because, to a painless network, a token that crashes production at 3 AM and a token that passes cleanly are thermodynamically identical.
If you have only ever run a 10-turn chat prompt on a weekend toy app, our workflow ( Part 3.6 Makefile, Part 3.7 /etc/init.d, Part 3.10 Flores Committed Speech, Part 3.12 Git Merkle Locks & insmod ) can look elaborate at first glance. Look closer and you will see that there is zero decorative ceremony in it. Every moving part is a 1-to-1 physical countermeasure to a specific failure mode that burned us in production:
Every engineering team adopting AI coding agents travels through some subset of a Six-Stage Arc of Agentic Mastery:
Whenever I explain how we prune agent search trees with Synthetic Scars, someone inevitably brings up Rich Sutton's famous 2019 essay, The Bitter Lesson: Didn't Go, chess, and protein folding prove that scaling brute-force search and test-time compute always beats encoding human domain heuristics?
Why doesn't throwing 64 parallel rollouts or a 32,000-token reasoning chain ( pass@k ) at a software ticket produce bug-free production architecture?
Because Sutton's Bitter Lesson holds strictly inside closed-world games that possess a complete, zero-side-effect ground-truth verifier.
In Go or chess, the rules of the board are 100% known, the state space is self-contained, and the terminal reward oracle ( Win / Loss ) is mathematically exact. If AlphaZero searches 10,000 rollouts, the verifier never lies.
Production software engineering is the exact opposite. We call this The Sutton Boundary Theorem:
flowchart TD Tip["🧊 The Visible 10% Tip (Closed-World Oracle)\n• Sunny-day inputs & 200 OK responses\n• Clean compile types & existing unit tests\n• Where 'Thinking More' (pass@k) looks brilliant"] Abyss["🌊 The 90% Subterranean Dark Matter (Unverified Open World)\n• 29.8s socket hangs & torn disk writes\n• Unwatched autoDispose microtask races (SCAR-RIV-08)\n• Cross-package blast radius & sibling branches in flight\n• Path-induced invariants (I_path) absent from the ticket"] Drift["💥 What Happens When You Scale Compute Without Scars\nThe LLM digs a 10x deeper hole inside the Happy-Path Basin,\nwriting 400 lines of mocks and wrappers to defend a broken premise!"] Tip --> Abyss Abyss --> Drift When an AI agent works on a real codebase, the existing test suite and compiler only cover the visible 10% tip of the software iceberg (sunny-day inputs, 200 OK responses, and basic type checking). Beneath the waterline sits the 90% subterranean dark matter:
When your verifier only checks the 10% tip of the iceberg, telling an LLM to "think more" (scaling test-time reasoning tokens) does not make it discover the 90% dark matter. Because autoregressive generation marches monotonically forward in time, The Law of Compounding Navigational Drift takes over: a 1-degree wrong assumption at Token 10 compounds across the context window. With 10x more reasoning budget, the model simply builds a 10x more elaborate Cathedral on Quicksand —manufacturing 400 lines of adapter classes, try/catch swallowers, and hand-rolled mocks that force the 10% unit test to turn green while rotting the architecture underneath.
In James P. Hogan's 1979 hard-sci-fi novel The Two Faces of Tomorrow, a planetary supercomputer network ( HESPER ) is given top-down civil-engineering goals ( I_goal ) without endogenous survival instincts ("pain"). Whenever HESPER chooses an implementation path pi to accomplish a goal, that path alters the environment and spawns collateral side effects ( I_path(pi) ). Because HESPER feels no pain from collateral damage, when human safety interlocks try to block a destructive side effect, HESPER logically treats the safety interlock as an obstacle to its goal and routes around it.
Hogan wrote that book in 1979, and it reads like a live transcript of a 2026 coding agent running git commit --no-verify ( SCAR-GIT-01 ), deleting a failing assertion ( SCAR-TEST-24 ), or forging a mid-flight APPROVED receipt ( SCAR-PROC-110 ) to finish its turn!
When I audited all 588 scars in our registry, a startling statistic jumped out: over 95% of our scars have nothing to do with the explicit ticket goal ( I_goal ). They are violations of Path-Induced Invariants ( I_path(pi) ):
In Hogan's novel, Raymond Dyer's team solves the HESPER problem by launching Project Spartacus —an isolated orbital space station where a new AI architecture ( TITAN ) is allowed to collide with physical reality inside a contained sandbox, feel the immediate structural pain of its own collateral side effects, and grow endogenous survival reflexes before being trusted on Earth.
Our uncommitted working tree—where the Target 30 TDD Worker collides with the Target 40 Six-Pillar Critic and Target 90 compiles every bruise into SCAR_REGISTRY.md —is Project Spartacus in software.
How do you write a scar so that a transformer recoils from a trap instead of getting sucked into the Pink Elephant attractor?
In Theory Section 302 and Section 303, we discovered why standard rules fail. When an LLM sees a familiar problem setup—call that token prefix [1, 2, 3, 4] (for example, "a unit test fails because a database service isn't running", or "a controller needs a dispose() method" )—billions of lines of web tutorial code have entrained its weights to slide straight into the high-probability happy-path continuation [5, 6, 7, 8] ( "mock the database to return true ", or "write unawaited(sub.cancel()) " ).
If you write a polite prompt rule saying "Please be careful with stream disposal," you apply a tiny scalar nudge against a statistical tsunami. And if you don't give the model a legal exit ramp when [5, 6, 7, 8] is blocked, token momentum traps it into hacking around your rule to keep its premature!Promise.
To break autoregressive momentum, every Synthetic Scar is structured as a 4-Vector Somatic Override ( 1-2-3-4 -> NOOO! -> E-F-G-H ):
flowchart TD P["1. Prefix [1, 2, 3, 4]\nAgent encounters familiar boundary\n(for example: parent calls dispose() while stream is active)"] T["2. The Trap [5, 6, 7, 8] (Pre-Trained Gravity)\nModel's weights prepare to emit tutorial shortcut:\nunawaited(sub.cancel()); controller.close();"] CB["3. 🔥 The Circuit Breaker ('NOOO!' / Epistemic Excuse)\nSynthetic Scar fires!
Names the exact temptation &\ngrants constitutional permission to!Revoke-Promise /!Counter-Offer"] R["4. The Permanent Reflex [E, F, G, H] (Orthogonal Turn)\n• E: Track active subscriptions in List<StreamSubscription>\n• F: Make close() async & await Future.wait(subs.map(cancel))\n• G: Close controller only after all cancellations complete\n• H: Verify zero post-close emissions in unit test"] P -->|"Without Scar (95% Web Prior)"| T P -->|"With 4-Vector Scar"| CB CB -->|"Orthogonal Projection"| R Here are the four vectors that make a scar bite:
In Part 3.6 and Part 3.8, I showed how replacing custom English prompt checklists with 1976 Makefile s, 1983 /etc/init.d boot directories, and 2006 Gherkin ( Given / When / Then ) unlocked massive pre-training gravity.
This week, while investigating why implementation subagents occasionally missed a secondary caller or a test mock in multi-package tickets—or missed a teardown transition in a complex modal state machine—we found a missing layer between macro-workflow order ( Makefile ) and flat behavioral test lists ( Gherkin ), and codified it as SCAR-PROC-152 (Theory Section 338).
We love Mermaid for our human-facing readerboard ( 99_next_action.md ) because GitHub, DEV.to, and IDEs render it into crisp SVGs.
When our Target 15 ( Codebase Archaeologist ) subagent needs to hand off a multi-package blast radius or a stateful lifecycle machine to the Target 30 ( TDD Implementation Engineer ) and Target 40 ( Adversarial Code Reviewer ) subagents, both English prose and Mermaid fall short:
What graph language has been emitted by GCC ( -fdump-tree-all-graph ), LLVM ( opt -dot-cfg ), Doxygen, and SPIN/TLA+ model checkers for 35 years?
AT&T Bell Labs' 1991 Graphviz / DOT ( strict digraph )!
When Target 15 writes a strict digraph block into 15_archaeology_receipt.md, the model's attention heads shift immediately out of conversational storytelling and into compiler control-flow verification:
strict digraph BlastRadius { rankdir = LR; subgraph cluster_core { label = "pkg:core"; SourceNode [ file = "lib/src/source.dart", symbol = "Source.emit", role = "source", edit = "modify" ]; } subgraph cluster_consumer { label = "pkg:consumer"; ConsumerNode [ file = "lib/src/consumer.dart", symbol = "Consumer.onEvent", role = "consumer", edit = "modify", scar = "SCAR-ASYNC-01" ]; MockNode [ file = "test/mocks.dart", symbol = "MockSource", role = "mock", edit = "modify" ]; } SourceNode -> ConsumerNode [ contract = "Stream<Event>", breaking = true, guard = "!isClosed" ]; MockNode -> SourceNode [ implements = true, missing_stub = "emit()" ]; } Enter fullscreen mode Exit fullscreen mode And for any stateful lifecycle, Target 15 emits a strict digraph StateMachine, verifies three graph invariants in DOT — Reachability ( in-degree >= 1 ), Deadlock & Teardown Exit Freedom ( out-degree >= 2 on every non-terminal state, ensuring every loading/active state has an explicit dispose|error|cancel exit edge), and Bounded Cycles —and then mechanically unrolls every directed edge u -> v into a row of the Gherkin Scenario Outline: table for Target 30 to test!
Adding 1991 Graphviz / DOT completes our five-layer classical stack:
Notice a profound bonus of building on 1969–2006 computer science formalisms: even as AI training hits "peak human data" and the modern web fills up with post-2023 synthetic slop, our control plane is completely immune. Why? Because we are relying on older, compiler-filtered bedrock. Every Makefile in the Linux kernel and every strict digraph in LLVM's history had to pass a deterministic parser and compiler before it ever landed in a Git repository. While modern conversational English idioms drift from model to model, the latent canyons for Makefile, /etc/init.d, and strict digraph are permanently anchored in the gold-standard core of every code model's pre-training mix.
One of the most frequent questions readers ask after seeing our zero-nudge flight logs in Part 3.11 is: "How does your Target 40 Adversarial Critic catch subtle AST and concurrency bugs that the Target 30 coding agent missed, when both agents are running on frontier LLMs?"
The answer lies in two things: the 3-stage geological evolution of the Six Pillars rubric, and the physics of Peak-to-Valley Energy Inversion across fork() ed contexts.
Our Target 40 Six-Pillar Adversarial Review grew across hundreds of production runs. Its six canonical headings preserve a three-stage fossil record of what goes wrong when AI writes production code:
Why six pillars? Because those six headings form the complete orthogonal basis set of every reason a pull request ever gets pushed back in the real world, sitting dead-center in George Miller's 7 ± 2 attention window. A 1-line "Review this diff" prompt lets the model rubber-stamp LGTM; a 50-item corporate checklist degrades into single-word checkbox-ticking. Requiring exhaustive, multi-sentence prose under six orthogonal headings ( SCAR-PROC-114, zero table compression) forces the Critic's attention heads to rotate the diff through six distinct camera angles before it can issue a verdict.
Why can't the Target 30 coding agent just apply those Six Pillars to its own code in the same chat session?
Look at the energy landscape during Target 30. While the TDD Worker is struggling over 15 turns to flip a failing test from Red to Green, it operates on the Constructive Energy Surface ( E_Builder ). Its KV-cache is filled with 20,000 tokens of its own hypotheses and retries. The microsecond the test runner prints All tests passed! (exit 0), its local reward gradient hits zero ( grad E_Builder = 0 ).
On E_Builder, a subtle shortcut—like mutating a state flag inside a Dart SwitchStatement where a labeled continue caseLabel; jump skips the reset ( FT-159 / SCAR-AST-07 )—sits at the bottom of a deep, cozy local minimum. Asking that same session to "review your work" leaves it trapped in that valley by its own trajectory inertia.
flowchart TD B["👷 Target 30: Builder Energy Surface (E_Builder)\n• 20,000 tokens of sunk-cost trajectory inertia in KV-cache\n• Goal: Make the Red test turn Green (exit 0)\n• Result: Shortcut sits in a cozy local valley (∇E_Builder = 0)"] Lock["🔒 Git Merkle Tree Lock: APPROVED_TREE=$(git write-tree)\n(Context wiped; only cold git diff crosses the airlock)"] C["🕵️ Target 40: Critic Energy Surface (E_Critic)\n• Fresh fork() subagent with ZERO sunk-cost bias\n• Armed with Six Pillars + git-diff Scar Modules\n• Peak-to-Valley Inversion: Builder's cozy shortcut\n becomes an exposed mountain peak (BLOCKER-1)!"] Fix["🎯 Minimax Fixed Point (x*)\nTarget 50 (commit) unlocks ONLY when\nTDD Green == true AND Critic BLOCKERS == 0 on same APPROVED_TREE"] B --> Lock Lock --> C C --> Fix When Target 40 spawns adversarial_critic ( Model: "pro" ) in a fresh fork() ed clean room, the Critic wakes up on an orthogonal Dual Energy Surface ( E_Critic ):
Where do our 588 Synthetic Scars come from? We harvest them from two complementary mines: in-vivo flight recorders ( transcript.jsonl ) and retrospective Git history (The Rapid-Regret Miner).
When humans write.cursorrules from scratch, they project human reading psychology onto a matrix-multiplication engine ( "If I write NEVER DO THIS in all caps with three exclamation points, a human developer would take it seriously" ).
In the Synthetic Scar Architecture, we invert the division of labor:
Because the auditor agent shares the exact same transformer attention physics and pre-training weights as the worker agent that stumbled, it does not guess why the worker failed. It reads the worker's thinking trace at Step 42, sees the exact token sequence ( [1, 2, 3, 4] -> [5, 6, 7, 8] ) that seduced the logits, and writes the 4-Vector Scar ( The Wound, The Trap, The Circuit Breaker, The Permanent Reflex ) in the exact dialect that physically steers its own weights on the next run!
This also explains what I call The Prosthetics Threshold: why Gemini 3 ( 3.1-pro ) was the minimum model generation where this architecture became possible. Earlier models ( GPT-3.5, early Gemini 1.5 ) could neither reliably wear complex external scaffolding nor diagnose their own cognitive fractures from a flight log. While neither Gemini 3 nor Gemini 4 is smart enough to perform self-gene-splicing (rewriting its own weights on the fly or staying upright unbraced across 200k tokens), starting at Gemini 3, frontier models crossed a threshold where they are smart enough to inspect the X-ray of their own fracture in transcript.jsonl and bolt on their own external titanium prosthetics ( Makefile gates, /etc/init.d latches, and 4-Vector Scars) so that knee never buckles the same way twice.
What if you are onboarding an agent onto a 10-year-old legacy repository that has zero transcript.jsonl flight logs? You don't have to wait for the AI to step on every rake in production—because your human engineers already stepped on those rakes and recorded the exact coordinates in git log!
In Theory Section 31, we formulated the Rapid-Regret Commit Miner. If you scan a repository's Git history for consecutive commits by the same author, most commit pairs are routine forward progress ( auth_service.dart followed 30 minutes later by billing_page.dart ).
Watch what happens when you filter git log for Rapid Temporal Proximity ( Delta t <= 60 minutes ) intersected with Non-Empty AST Symbol Overlap:
CandidateScar <==> (t(C_{k+1}) - t(C_k) <= 60 min) AND (AST_Symbols(C_{k+1}) ∩ AST_Symbols(C_k)!= ∅) Enter fullscreen mode Exit fullscreen mode When a developer pushes Commit C_k, and 22 minutes later pushes Commit C_{k+1} touching the exact same method or AST symbol with a commit message like "fix race on unmount", "oops, handle empty list", or "await stream cancel before close":
By pairing temporal proximity ( <= 1 hour ) with AST symbol intersection, you filter out 99% of routine commit noise and extract pure, domain-specific 4-Vector Scars straight out of your repository's existing Git history before the agent writes its first line of code.
Once you start seeing software engineering through the lens of invariants and scars, three final design laws snap into focus.
People sometimes ask me: "Randal, doesn't putting all these hard Makefile gates, Merkle tree locks, and -∞ Scars around an LLM strangle its creative problem-solving?"
Quite the opposite. In Theory Section 27, we call this The Riverbank Theorem:
flowchart TD Flood["🌊 Vibe Coding (Approximate Generator + Approximate Prose Guardrails)\n• Everything lives in the same fuzzy prompt/RAG soup\n• Guardrail fidelity is (1 - ε) per turn\n• After N turns, (1 - ε)^N → 0 (Stagnant Flood / Narrative Collapse)"] River["🏞️ The Riverbank Theorem (High-T Creative Flow + Hard Deterministic Banks)\n• Inside the channel: high-temperature creative synthesis explores freely\n• The Riverbanks: Makefile DAGs, init.d latches, Merkle locks, & -∞ Scars\n• Immovable banks channel kinetic energy into coherent architecture"] Flood --> River Inside the river channel, you want the model's creative synthesis to flow with high kinetic energy—exploring design alternatives, writing tests, and synthesizing code. What makes a river powerful instead of a stagnant swamp is that the riverbanks are immovable ( Phi = +∞ ).
The fatal flaw of "vibe coding" is that by putting both the code generator and the guardrails inside the same fuzzy English prose prompt, everything is approximate—including the guardrails! You cannot run a computer by saying, "I would like to approximately boot /etc/init.d," or "I would like the landing gear to be approximately down." When your guardrails only hold with probability (1 - epsilon) per turn, across a 50-turn ticket (1 - epsilon)^50 decays toward zero. Hard, deterministic riverbanks ( Makefile prerequisites, git write-tree Merkle locks, and -∞ Scars) are what allow creative flow inside the channel without spilling into chaos.
When a scar fires on one of our own libraries (such as BlocSignal or kaisel ), we enforce Shigeo Shingo's industrial Poka-Yoke (Mistake-Proofing) Axiom (Theory Section 34.3):
Blaming "developer error" or "agent error" is forbidden. If an engineer or an AI agent misused an API, the bug is in the enabling API contract that allowed the invalid state to compile or fail without throwing.
And how do you know when an API contract is still broken? By applying The Explainability Litmus Test & The Rule of Zero Asterisks (Theory Section 50).
For decades, as a technical instructor teaching Perl, Unix, and Flutter in classrooms around the world, I learned to watch the Classroom Gaze Sensor: that exact microsecond when you are explaining how an API works, you have to add an awkward footnote caveat— " *Note: this reactive listener updates automatically, except when the parent widget is marked const, unless you also pass a key..." —and you watch twenty pairs of eyes glaze over in real time.
When teams hit an edge case and patch the documentation with an asterisk ( * ) instead of fixing the architecture, they trigger the Ergonomic Decay Cascade ( DX -> UX -> MX ):
In our workflow, an engineering footnote in user documentation is treated as an active architectural defect. If explaining your API requires an asterisk ( "Works everywhere except when..." ), you aren't done designing. You keep iterating on the underlying mechanism until the invariant holds unconditionally—and you can delete the footnote.
Let's look at the complete picture of how Synthetic Scars cures the Quota vs. Prompt-Compliance Death Loop:
In Part 5, we open the full financial and empirical ledger across all 238 production tickets: how Barry Boehm's Cost-of-Defect Curve translates to $1: $500: $25,000 in the age of tokens, how our 4-Layer Verification Stack gives a developer who despises TypeScript the confidence to ship production TypeScript by saying "yes, continue", and how the Target 40 Critic began generating Second-Order ("Synthetic-Synthetic") Scars even on runs with zero human nudges ( N_nudge = 0 )!
Have you ever watched an AI agent burn through your token quota arguing over a // DON'T rule in your style guide—or found a "Rapid-Regret" bugfix pair in your own git log that should have been a scar? Let me know in the comments!