JavaZone · September 2026

Fear-Driven Development

Thor Henning Hetland · eXOReaction

We'll begin shortly.

The Hook

Most developers won't admit this.

$ whoami --honest
"I'm scared of AI."
01Scared the AI is hallucinating and I can't tell
02Scared something will break in production
03Scared I'll ship hallucinated code
04Scared costs will spiral out of control
05Scared of losing control to the AI
06Scared of silent failures nobody notices

Those fears built the system.

Before We Start

Who's talking.

40 years building software
Co-founder of JavaZone, 2001
Founder, eXOReaction · Ægis · Quadim · Sunstone Tech · Cantara · former president, javaBin
Java Champion since 2005
Totto at the console, running a fleet of AI agents

These days: shipping production code with AI agents at speeds that shouldn't be possible.

The Experiment

January 16, 2026. I wanted to see how far I could push Claude Code in a weekend.

The domain: PCB manufacturing file formats — binary parsers, validators, industry specs. I chose it because I knew almost nothing about it. Not a prototype. Production code, handling real manufacturing data for actual fabricators.

197,831
Lines of Java (day 11)
7,461
Tests, day 11 (99.8% pass rate)
445
Commits, day 11, all via PR
25–66×
vs. a 9–24 month industry estimate

8 file-format parsers · 28 validators · 17 auto-fix types · a domain I didn't know — still a week of hardening left; final numbers land on the Proof slide.

Where We're Going

Six fears. Six systems. Then what happened next.

01
The Framework — every fear becomes a system
02
Fear → System — one fear at a time, six times
03
The Proof — the numbers, the zero bugs
04
Down the Rabbit Hole — what came after
05
Welcome to the Dark Side — where we are today
06
The Lesson
The Framework
Fear Without Systems = Just Anxiety
Fear With Systems = 10× Productivity

Every fear in this talk became a system.
Every system made things faster. Watch how.

Fear #1 · AI Hallucinations

Day 4, midnight. A 500KB file wanted to be 1.1 gigabytes.

"The format needed 11 primitive fields — ints, bools, floats — before any strings. The parser read a string first."
"One misplaced field type. The whole byte stream silently misaligned."
The crash:"Requested 1174405120 bytes (1.1GB) for string length exceeds buffer size."
// Spec: 11 primitives BEFORE strings. String name = reader.readString(); // ← reads garbage int type = reader.readInt8(); // 575KB later: misalignment explodes → 1.1GB requested

I can't trust my ability to spot hallucinations by reading code.

System #1 · Round-Trip Testing

If You Can't Trust What You Read, Prove What It Does

Round-trip test
byte[] original = Files.readAllBytes(testFile); PCBDesign design = parser.parse(testFile); byte[] written = writer.write(design); assertArrayEquals(original, written); // If this fails → AI lied somewhere
Property-based test
@Property void boundingBoxContainsAllFeatures(Layer layer) { BoundBox box = layer.getBoundBox(); for (Feature f : layer.getFeatures()) { assertTrue(box.contains(f.getBoundBox())); } } // AI can't hallucinate away invariants
23 tests → 10,035 tests. Zero false confidence.
Fear #2 · Production Bugs

Tests passed. Production broke. Next day.

"I implemented filtering of embedded documentation from German PCB manufacturer files. Tests pass. Looks great."
User reports:"The drill holes are 2× too large."
"Coordinate scaling in DrillListing.java was calibrated against inflated dimensions (400mm). After filtering, actual PCB is 216mm — but drill holes still scale to 432mm."

The code looked fine. But there was a lurking interaction between two features I'd never tested together.

System #2 · Battle Testing

Test Against the Chaos of the Real World

Collected 191 real PCB files from the wild — KiCad, Altium, Eagle, German manufacturers, ancient legacy formats
Every change runs against ALL 191. If ANYTHING breaks, build fails.
Not synthetic examples. Real-world chaos you'd never invent.
terminal

$ mvn test

Running com.exoreaction.pcb.BattleTestSuite

Tests run: 10,035, Failures: 0, Errors: 0, Skipped: 30

[INFO] BUILD SUCCESS

Fear #3 · Shipping Bad Code

main was broken for 23 minutes.

$ git log --oneline 7c8d9e4 Fix bounding box (for real this time) 2e5f6a3 Revert "Actually fix bounding box" 8b9c4d2 Actually fix bounding box calculation 3a7f2e1 Fix bounding box calculation
Working directly on main, accepting AI suggestions, committing fast.
The 'fix' introduced a bug that broke 47 tests. For 23 minutes, main was broken.

Direct commits to main with AI-generated code is playing Russian roulette.

System #3 · CI as Final Arbiter

CI is the Truth. Not My Code Review.

#!/bin/bash if [ "$(git rev-parse --abbrev-ref HEAD)" = "main" ]; then echo "ERROR: Direct commits to main are forbidden" echo "Use: git checkout -b feature/your-branch" exit 1 fi
Branch
AI generates
Local tests
PR · CI · 10,035 tests
Merge

CI is the final gate. AI can convince me. It cannot convince CI.

695 commits. Zero broken builds on main.

Fear #4 · Cost Spiral

$80,000–$120,000. For one 2.5-week project.

$80K–$120K

Not per year. For this one project, at heavy usage, metered.

Heavy AI usage. Multiple sessions per day. Long context windows. All the testing, verification, and measurement required for Fear-Driven Development.
What if I build my entire workflow around this and the pricing changes?
System #4 · Sustainable Economics

Make the Economics Non-Negotiable

Claude MAXFlat-rate usage makes FDD economically possible. Without it, testing everything, verifying everything can run $80K–$120K per project.

Why optimize even on flat-rate? Latency + discipline + future-proofing.

Model selection
ComplexityModelUse
Simple queriesHaikuFile ops, searches
Standard codingSonnetMost work (60–70%)
ArchitectureOpusComplex reasoning
Fear #5 · Losing Control

47 changed files. Understood maybe 60%.

"I gave Claude a high-level description. It came back with a plan."
"I said 'looks good, do it.' One hour later: 47 changed files."
"I merged it. Tests passed."
"But I had this nagging feeling: I just shipped code I don't understand."
Am I still a developer if the AI is doing the thinking?
System #5 · Directed Synthesis

Don't Grade Your Own Homework

When something needs spot-checking — a deep-dive report, 10+ pages — I don't just re-read it. I ask ExoCortex to write it, then pick whichever of these actually answers the question I have — rarely all three.

Is the science real?
ChatGPT deep-research — peer-review it against actual published research.
Does it match my mental model?
NotebookLM → infographic — a fast visual gut-check against what I expected.
Do I actually understand it?
NotebookLM → slide deck, 10–20 slides — forces me to learn it, not just skim it.
Different product areas need different lenses. The point isn't running all three — it's never checking the AI's work with the same kind of AI that produced it.
Fear #6 · Silent Failures

Green tests. Wrong answer.

A user reports: "The PCB bounding box is wrong. The board should be 216mm wide, but your library says 425mm."
"Individual drill holes: correct position. Assembly components: correct position."
"Overall bounding box: including a documentation layer with inflated coordinates."
Tests were green. The code worked. But the result was wrong because I was measuring the wrong thing.

Green tests don't mean the system is correct. They mean it matches what you tested.

System #6 · Extreme Measurement

Don't Just Test. Measure.

System.out.printf("PCB boundBox: %.1fmm × %.1fmm%n", width / 1_000_000.0, height / 1_000_000.0); System.out.printf("Expected: ~216mm × 206mm%n"); System.out.printf("Alignment: %.1f%%%n", misalignment * 100); assertTrue(misalignment < 0.25, "BoundBox should be within 25% of copper dimensions"); if (Math.abs(x) > 3_000_000_000L) { // 3 meters logger.warn("Extreme coordinate: {}mm. Overflow?", x/1_000_000.0); }
Test countTracked ↑ over time
Pass rateMust stay >99%
Battle coverage191 real files, 100%
The System

Fear → System → Result

FearSystemResult
AI hallucinationsRound-trip + property tests10,035 tests, zero false confidence
Production bugsBattle testing (191 files)Zero AI bugs past the systems
Shipping bad codePR-only + CI gatesmain always green, 695 commits
Cost spiralClaude MAX subscription$80K–$120K exposure → $0 spent
Losing controlDirected synthesisBetter codebase understanding
Silent failuresExtreme measurementFast bug detection

Formula: FearDisciplineResults

The Proof

2.5 Weeks. Real Numbers.

10,035
Tests (99.8% pass rate)
695
Commits (278/week, ~40/day)
0
AI-induced bugs past the systems
$0
API costs (Claude MAX)
191 real-world PCB files in battle suite
main branch: always green  ·  lib-pcb: 2.5 weeks, Jan–Feb 2026
Down the Rabbit Hole

I'd solved the generation problem.
I'd created a comprehension problem.

8,934 files across the workspace by the time lib-pcb shipped — not just code, but skills, docs, tests, plans
Standard RAG (vector search) was categorically inadequate — it answers "find something like X," not "what breaks if I change this?"
Graph questions need graph answers, not semantic similarity

So I built the tool I needed: Synthesis — an open-source knowledge graph over the codebase.

The Shape of It

Explore lean → hit a wall → build deeper → explore again.

lib-pcb
SDD
Synthesis
KCP

KCP — Knowledge Context Protocol — is where I am now. Not a product. A proposal: what an AI agent should know before it acts, not just what it can do.

I don't know where the bottom of this rabbit hole is. I'm not sure there is one.

June – August 2026

A spec isn't a system. So I built the system.

KCP stopped being just a proposal. Four things made it real, each testing a different piece of the idea.

kcp-agent
The reference deterministic agent. The model proposes a plan, the planner disposes — fail-closed, every step audited before it runs.
kcp-harness
Governance from outside: an MCP proxy that checks every tool call against policy before it reaches the downstream server.
pi-kcp
Governance from inside: the same enforcement, but living inside the agent's own turn instead of in front of it.
Sunstone Atlas
The first real product built on top of it — a governed knowledge, skill, and playbook substrate for an actual organization.

Two different enforcement points, tested in parallel, on purpose. I still don't know which one wins.

Welcome to the Dark Side

This didn't stop. Here's today.

1,337
Skills in the library (548 in May)
21
Knowledge-graph workspaces live (10 in May)
90,050
Files indexed across them (66,350 in May)
252
KCP command manifests (152 in May)
The hard part now isn't writing more code — it's staying oriented inside what you've already built.

A harder confession: even measuring this got harder. Session counts fell 25× between February and July — not because the work stopped, but because sessions got longer: 61 turns per session in February, 1,737 by June. The naive metric would have told you the opposite of what actually happened.

The House Remembers
The Lesson

The developers who are scared of AI
get the most value from it.

The confident onesTrust the AI. Ship without tests. Wake up to production bugs.
The scared onesTest everything. Measure everything. Automate their paranoia.
The paranoid onesTrust nothing. Read every line by hand. No automation, no sleep, no shipping.
Only the ones who automate their fear sleep well at night.
Fear-Driven Development

Turn Your Anxiety Into Automation

Fear
Identify Risk
Design System
Automate Paranoia
Trust Process
10× Productivity
Think of your agent as a colleague, not a tool. When you see it struggle — a wrong turn, a missing detail, a shortcut taken under pressure — you don't just catch the mistake. You give it what it needs: a skill, a tool, the context it was missing. Fewer hallucinations aren't caught. They're prevented.

That's Fear-Driven Development.

Questions?  ·  Press 16 for deep-dives  ·  N for notes

Stay in Touch

Thanks. Come find me.

Thor Henning Hetland (Totto) · eXOReaction

wiki.totto.org

This talk, the source incidents, and the rest of what I write up are all there. And if you want to keep arguing about any of it over a beer — that's a standing weekly thing, not just tonight.

Agent Pilsen & Skill-Driven Development — Thursdays 17:00 at Eileff Landhandleri. Informal discussions, peer learning, cold beers.
Fear 1 · The Moment

The bounding box bug.

Week 1 of lib-pcb. I ask Claude to implement bounding box calculation for PCB layers — aggregate the spatial extent of all features in a layer.
Claude produces clean, readable Java. Union loop. Sensible initialization. Looks right. I review it, nod, merge it.
Tests pass. I write a few unit tests. Those pass too. Ship it.
Three days later:"The layer thumbnail is completely black."
// Claude's code — looks correct, isn't BoundBox result = features.get(0).getBoundBox(); // ← problem here for (Feature f : features) { result = result.union(f.getBoundBox()); } // features.get(0) often has empty bbox (0,0,0,0) — common for metadata features // union(0,0,0,0, real) expands to include origin → wrong dimensions → thumbnail all black

The fix was trivial. The lesson was not: I cannot trust code review for AI-generated code.

Fear 1 · The Fear

Visual code review is insufficient.

"If I couldn't catch that bug reading the code, what else am I missing?"
The problem with visual reviewAI code is stylistically convincing. Clean names. Sensible structure. It looks like it should work. Your brain pattern-matches to "correct" before you've actually verified it.
Off-by-one errorsAI consistently confuses inclusive vs exclusive bounds. Hard to spot reading code. A property-based test catches it instantly.
Edge case blindnessAI generates for the happy path. Features with empty bboxes, features with negative coordinates, features at the origin — AI doesn't think to guard against these.
Semantic correctnessThe code can be syntactically perfect and logically coherent while being semantically wrong for your domain.

Solution: stop reading for correctness. Prove correctness mechanically.

Fear 1 · Round-Trip Testing

Parse → Write → Compare bytes.

@Test void roundTripPreservesFile(Path testFile) throws Exception { byte[] original = Files.readAllBytes(testFile); byte[] written = writer.write(parser.parse(testFile)); assertArrayEquals(original, written, "Round-trip must preserve every byte"); // If ANY transformation is lossy → fails immediately. AI cannot hallucinate away byte-level identity. }
Why bytes?Not structural equality — byte equality. Every comment, every whitespace, every coordinate format. Nothing is lost.
Why it worksEven clever hallucinations can't survive a round-trip test. If the AI misunderstood the format, the bytes will differ. Period.
Scale itRun against all 191 real files. Every format, every quirk, every edge case the real world throws at you.
Fear 1 · Property-Based Testing

Mathematical invariants the AI can't violate.

// jqwik property-based test — runs with hundreds of random inputs @Property void boundingBoxContainsAllFeatures(@ForAll Layer layer) { BoundBox box = layer.getBoundBox(); for (Feature f : layer.getFeatures()) { assertTrue(box.contains(f.getBoundBox()), "Layer bbox must contain all feature bboxes"); } } // + a second invariant: adding a feature can only expand the bbox, never shrink it
What this catchesOff-by-one errors, wrong union logic, initialization bugs (the original bounding box bug!), coordinate overflow, sign errors.
Why it's powerfulYou don't define inputs. The framework generates hundreds of random valid inputs. Your paranoia is automated at scale.
Fear 1 · The Results

From 23 tests to 10,035.

23
Tests when I started (false confidence)
2,847
Tests after round-trip suite added
10,035
Final count (99.8% pass)
Zero AI-induced production bugsAfter implementing round-trip and property tests, not a single hallucination made it past CI.
Hallucinations caught in minutesAverage time from AI write to hallucination detection: the time to run tests locally. Not days. Not weeks.
FormulaRead code for comprehension. Test code for correctness. These are different activities. Separate them.
Fear 2 · The Moment

German PCB manufacturer. Drill holes 2× too large.

lib-pcb needed to handle files from a specific German PCB manufacturer that embeds extensive documentation inside the Gerber file. Comments, revision history, layer metadata — inflating the coordinate space to 400mm × 400mm.
I implement a filter that strips the documentation layers before processing. Tests pass. CI is green. The PCB now measures correctly at 216mm × 206mm.
But DrillListing.java had a coordinate scaling factor calibrated against the pre-filter 400mm coordinate space. After filtering: scale factor is now 2× too large.
Next day:"The drill holes are 2× too large. Every board we ordered is scrap."

This was not an AI hallucination. This was a correct change that broke a correct assumption in a different module. The bug was lurking in the interaction.

Fear 2 · The Fear

Bugs that hide for weeks.

"The code was correct. The tests were green. And yet the result was wrong."
Lurking interactionsModule A is correct. Module B is correct. Their interaction is wrong. Neither test suite covers the combined behavior.
AI reasoning opacityClaude doesn't have a global model of your codebase. When it changes DrillListing.java, it doesn't know that BoundBox.java relied on the 400mm coordinate space assumption.
Time delayThe bug was introduced week 1. Discovered week 3. Seven production boards printed with wrong drill holes before anyone noticed.
Synthetic test blindnessMy synthetic test files were clean, normalized, well-structured. The German manufacturer file was none of those things.
Fear 2 · Battle Testing Setup

Collect the chaos of the real world.

1
Start with your own project files

Whatever PCB designs you have in-house. These cover your primary use cases.

2
Mine open-source hardware projects

GitHub is full of KiCad, Altium, Eagle projects with real Gerber exports. Download and include.

3
Seek out the oddballs

Legacy formats. Non-standard tools. Manufacturer-specific variants. These are the bugs waiting to happen.

4
Run the full suite on every PR

Not a subset. Not a sample. All 191. If you're skipping files "because they're slow", the slow files are the ones that matter.

5
Add every reported bug as a fixture

Each production bug becomes a permanent test. It can never come back silently.

Fear 2 · Edge Cases in the Wild

The files you'd never invent.

File typeWhat it catches
German manufacturer exportsEmbedded documentation, inflated coordinate spaces, comment-only layers
KiCad legacy format (.brd)Coordinate system origin differences, unit variations, non-standard layer names
Altium Designer exportsMulti-layer pad stacks, blind/buried vias, non-integer drill sizes
Eagle 6.x exportsNegative coordinate origins, arc representation differences, metric vs imperial
Hand-authored GerberMinimal headers, missing optional fields, non-standard but valid syntax
Flex PCB designsNon-rectangular board outlines, unusual layer counts, overlay geometries
191 files. 10,035 tests. If something regresses on any of these, CI fails before it reaches production.
Fear 2 · The Results

Bugs caught in CI. Not in production.

0
Production bugs from AI-generated code
191
Real-world files in battle suite
14
Regressions caught by CI before merge
The drill hole bug, if caught by CI5 minutes to fix, zero scrap boards. Caught in production: 2 weeks delay + material cost.
The ruleEvery production bug that reaches a user becomes a permanent test fixture. The second occurrence is the system's fault, not the developer's.
Real-world files don't lieYou can construct any synthetic test you want. Real-world files contain surprises you'd never think to test for.
Fear 3 · The Moment

The 23-minute broken main.

git log --oneline

7c8d9e4 Fix bounding box (for real this time)

2e5f6a3 Revert "Actually fix bounding box"

8b9c4d2 Actually fix bounding box calculation

3a7f2e1 Fix bounding box calculation

...

Pattern: I'm working fast. Claude suggests a fix. I read it, it looks right, I commit directly to main. Repeat.
8b9c4d2 introduced a regression that broke 47 tests. I didn't run the full suite before committing — "it's a small change."
For 23 minutes, main was broken. Anyone who pulled during that window got a broken build.

The AI's confidence is contagious. Its mistakes are invisible until they aren't.

Fear 3 · The Fear

What could have happened during those 23 minutes.

A teammate pulls mainTheir local build is now broken. They spend 20 minutes debugging before realizing it's not their fault. Morale hit. Trust hit.
CI/CD deploys from mainIf main is the deploy branch and CI is fast, a broken build can reach staging in under 5 minutes. Users see errors.
Cascade of fixesLook at the git log. Three fix commits for one bug. Each "fix" creates risk of introducing another regression. This is the spiral.
Velocity illusionCommitting fast feels like moving fast. But the revert + re-fix costs 3× the time a proper branch workflow would have taken.
Direct commits to main with AI-generated code is playing Russian roulette. You win most of the time. Until you don't.
Fear 3 · The System

Four lines of bash. Never break main again.

#!/bin/bash # .git/hooks/pre-commit if [ "$(git rev-parse --abbrev-ref HEAD)" = "main" ]; then echo "❌ ERROR: Direct commits to main are forbidden" echo "🔑 Use: git checkout -b feature/your-branch" exit 1 fi
The PR workflow
1
Branch

git checkout -b feature/fix-bounding-box

2
AI generates & I review

Multiple commits, reverts, experiments — all safely on the branch

3
Full test suite locally

10,035 tests. If any fail, fix before pushing.

4
Push PR → CI gates → Merge

CI is the final arbiter. The AI can convince me. It cannot convince CI.

Fear 3 · The Results

695 commits. main always green.

695
Commits over 2.5 weeks
0
Broken builds on main
278
Commits per week (avg)
CI as final arbiterThe AI can produce convincing-looking code. But it cannot produce code that makes 10,035 tests pass when the logic is wrong. CI is the immune system.
Branch freedomOn a branch, you can commit dirty, revert, experiment. The mess stays contained. main sees only the final, tested result.
The paradoxAdding the PR step feels like it slows you down. It speeds you up by eliminating emergency recovery time, broken-main debugging, and the 3-fix spirals.
Fear 4 · The Math

Two ways to run this. Two different bills.

Disciplined (model selection + MAX)Tokens/dayCost/day (Sonnet)
Code generation (10 sessions)~2M output$30
Test generation (full suite)~800K output$12
Code review + analysis~500K input$1.50
Battle test analysis~300K output$4.50
Over 17.5 days (2.5 weeks)~$840
Undisciplined, heavy parallel usage: a real number, not a guessA burn rate I've actually hit since: $850 in 90 minutes on a heavy multi-session sprint — $566/hour. Run anything close to that pace for 8–12 hours a day across a 2.5-week project and you land at $80,000–$120,000. Extrapolated from something real, not assumed Opus pricing.

The $100k fear was never precise math. But the range it was pointing at turns out to be real — the gap between $840 and six figures is entirely which of these two ways you're running.

Fear 4 · The Fear

What if pricing changes?

"I'm building a methodology that depends on a specific pricing model. That's fragile."
Structural dependencyFDD generates more AI calls than non-FDD workflows. Every fear becomes a system that runs tests, measures things, verifies outputs. All of that costs tokens.
Switching costOnce you're doing 695 commits/week with 10,035 tests driven by AI, you can't easily step back if costs change. You're committed to the workflow.
The reinforcement loopThe more successful FDD is, the more you use it. The more you use it, the higher the token costs. Success increases exposure.
But waitThis fear shaped the entire cost discipline. Model selection. Batch processing. Caching context. Not just because of money — because of strategic resilience.
Fear 4 · The System

Claude MAX + disciplined model selection.

Claude MAX ($100/month)Flat-rate, not unlimited — there's a weekly quota. But it's a subscription, not per-token billing: every test, every verification, every measurement is already paid for, not a cost that accumulates toward $80K–$120K.
Strategic resilienceMAX pricing is stable. If token pricing changes, the subscription model is a hedge. The worst case is a price increase on the subscription itself — predictable, budgetable.
ModelUse caseWhy
HaikuFile ops, simple search, boilerplateFast. No reasoning needed.
SonnetMost coding (60–70% of work)Best quality/speed ratio
OpusArchitecture, complex debuggingWhen thinking matters most

Even on flat-rate: wrong model = slow feedback loops = less FDD discipline = closer to that weekly quota.

Fear 4 · The Results

$80K–$120K of exposure. $0 actual spend.

$0
API costs for the entire 2.5-week project
$100
Monthly MAX subscription (the only cost)
100%
FDD methodology executed without budget compromise
The fear became the systemWorrying about costs forced disciplined model selection. That discipline made FDD faster, not just cheaper.
Sustainable methodologyA methodology that risks $80K–$120K/project unmanaged is a demo, not a practice. MAX + discipline makes FDD repeatable across every project.
Future-proofingModel selection habits built now transfer to any pricing model, any provider. The discipline is portable even if the economics change.
Fear 5 · The Moment

47 changed files. 60% understood.

"I need to refactor the coordinate system to support both metric and imperial PCB units. I describe it to Claude at a high level."
"Claude comes back with a detailed plan. 7 steps. Sounds reasonable. I say: 'Go ahead.'"
"One hour later: 47 changed files. I review the PR. I understand the changes in about 28 of them clearly. The other 19, I can see what changed but I'm not fully sure why."
"I merge it. Tests pass. But for the next three days I have a nagging feeling: I shipped code I don't fully understand."
The question that wouldn't leave:"Am I still a developer if the AI is doing the thinking?"
The Existential Pivot
The Mechanism of Symbiosis
Fear 5 · The Existential Fear

Am I still a developer?

The identity questionSoftware development has always been: I write code. I understand the code I write. If an AI writes code I don't fully understand, what is my role exactly?
The competence questionIf I can't read 47 changed files and fully verify each one, am I being reckless? Or am I adapting to a new way of working that requires different verification skills?
The accountability questionWhen something breaks, who is responsible? "The AI did it" is not an answer. I merged the PR. I own the outcome.
"The developer who delegates everything to the AI has outsourced their judgment. The developer who directs the AI has amplified their judgment."
Fear 5 · Directed Synthesis

Directed, not delegated.

1
I identify the problem and the approach

Not just "fix this" — I define the architecture before Claude touches a file.

2
AI explores the codebase

Claude finds relevant files. I review the list and make decisions about what's in scope.

3
I review findings, decide what to change

Claude proposes. I approve, reject, or modify each finding.

4
AI implements to my specification

Not to its interpretation of my vague request. To a specification I have approved.

5
I review every changed file

Small tasks mean small diffs. 5–8 files per task, not 47.

6
AI runs tests, reports results

I see the test output. I make the call on what failures mean.

7
I make the merge decision

Not automatic. Not because CI passed. Because I have reviewed and understood.

Fear 5 · Task Breakdown

Break it down before you hand it over.

Black box (what I said before)
"Refactor the coordinate system to support both metric and imperial units."

Result: 47 changed files, 19 I don't fully understand, a nagging feeling for 3 days.

Directed synthesis (what I do now)
1
Find all files using coordinate scaling
2
Identify 2.5× vs 1.0× usage patterns
3
Create CoordinateMode enum + conditional logic
4
Update each converter separately (one PR each)
5
Add tests for both metric and imperial mode

Each task: 3–8 changed files. Each reviewable in minutes. Total understanding: 100%.

Fear 5 · The Results

AI amplifies agency. It doesn't replace it.

100%
Files reviewed and understood in final workflow
5–8
Files per task (vs 47 in the black-box approach)
7
Decision gates where I stay in control
The paradoxI understand this codebase better with AI assistance than I would have without it. Because Directed Synthesis forces me to articulate my decisions before Claude implements them.
The identity answerI'm not less of a developer. I'm a developer who has learned to direct an extremely capable collaborator. The architect who designs the building is still the architect, even when others pour the concrete.
The accountability answerWhen I understand every file in the PR, I own the outcome. When I don't, I don't. Fear of that accountability forces the discipline that makes understanding possible.
Fear 6 · The Moment

425mm. Should be 216mm. CI was green.

A user reports: "Your library says the PCB bounding box is 425mm wide. The board is clearly 216mm wide."
I investigate. Open the file. Individual drill holes: correct position. Copper traces: correct position. Board outline: correct at 216mm.
Overall bounding box: 425mm. Includes a documentation layer — frame, title block, revision table — that extends well outside the board boundary.
CI was green.All 2,847 tests at the time passed. The code worked correctly. My tests just didn't test what the user needed.

I was testing whether the code ran. Not whether the output was correct.

Fear 6 · The Fear

What you don't measure, you don't know.

"Green tests don't mean the system is correct. They mean it matches what you tested."
Testing the test, not the resultassertNotNull(boundingBox) passes when boundingBox is 425mm and when it's 216mm. The assertion is too weak to catch the semantic error.
Semantic driftAs AI adds features, the semantics of a return value can drift. The function still returns a BoundBox. It now returns a different BoundBox. Your tests pass. Your users are confused.
Long feedback loopsThe bug was in the code for weeks before a user noticed. During those weeks: CI green, no warnings, no alerts. Total silence.
The measurement gapYou know the code runs. You don't know if the output is physically reasonable. 425mm × 400mm for a 216mm board should have triggered an alarm.
Fear 6 · Extreme Measurement

Assert values, not just existence.

// Don't just assert non-null. Assert the value makes sense. double widthMm = design.getBoundBox().getWidth() / 1_000_000.0; double heightMm = design.getBoundBox().getHeight() / 1_000_000.0; // Print for audit trail — shows up in CI logs System.out.printf("PCB boundBox: %.1fmm × %.1fmm%n", widthMm, heightMm); System.out.printf("Expected: ~216mm × 206mm (copper layer extent)%n"); // Assert with domain knowledge double copperWidth = design.getCopperLayer().getBoundBox().getWidth() / 1_000_000.0; double misalignment = Math.abs(widthMm - copperWidth) / copperWidth; assertTrue(misalignment < 0.25, String.format("Board bbox (%.1fmm) should be within 25%% of copper (%.1fmm)", widthMm, copperWidth)); // Guard against coordinate overflow for (Feature f : design.getAllFeatures()) { if (Math.abs(f.getX()) > 3_000_000_000L) { // 3 meters logger.warn("Extreme coordinate: {}mm. Possible overflow.", f.getX()/1_000_000.0); } }

The printf output appears in CI logs. When something's wrong, you see the actual values, not just a pass/fail.

Fear 6 · The Results

Fast detection. Confidence through numbers.

minutes
Time to detect semantic bugs (was: weeks)
100%
Test output includes actual measured values
0
Silent failures since measurement system added
The shiftFrom: "Did it crash?" To: "Are the values physically reasonable?" That one-sentence shift in your testing mindset eliminates an entire category of bugs.
CI as measurement dashboardEvery CI run now prints actual PCB dimensions for 191 files. If any value looks wrong, you investigate immediately. The numbers don't lie.
The fear becomes the metric"I'm scared the output is semantically wrong" → assert that the output is semantically correct, with domain-specific bounds. Fear drives the assertion design.
Fear-Driven Development Infographic
Demo · The Numbers

lib-pcb: 2.5 weeks, Jan–Feb 2026.

Project metrics
Tests10,035 (99.8% pass rate)
Commits695 (278/week, ~40/day)
Production bugs (AI)0
Broken main builds0
API costs$0 (Claude MAX)
Battle test files191 real PCB files
Timeline
Week 1Core parser, 23 tests, first hallucination bug
Week 1.5Round-trip + property tests. 2,847 tests.
Week 2Battle suite (191 files). Pre-commit hook. PR workflow.
Week 2.5Extreme measurement. 10,035 tests. Main always green.
Each fear emerged as a real incident. Each system was built in response. No upfront planning. Pure reaction.
Demo · Round-Trip Test Output

Catching hallucinations in CI.

mvn test -pl lib-pcb -Dtest=RoundTripTestSuite

Running com.exoreaction.pcb.roundtrip.RoundTripTestSuite

[RoundTrip] Testing: kicad-nightly-sample.gbr ... PASS (bytes identical)

[RoundTrip] Testing: altium-flex-pcb.gbr ... PASS (bytes identical)

[RoundTrip] Testing: german-manufacturer-rs274x.gbr ... PASS (bytes identical)

[RoundTrip] Testing: eagle-legacy-6x.brd ... PASS (bytes identical)

... [187 more files] ...

Tests run: 2,847, Failures: 0, Errors: 0, Skipped: 12

All round-trips preserved byte identity.

Property tests: 1,200 random inputs, all invariants held.

[INFO] BUILD SUCCESS

Total time: 4:32 min

Every line with "bytes identical" is a hallucination that could not survive. 2,847 assertions that the AI told the truth about the file format.

Demo · Battle Test Run

191 real-world files. All green.

mvn test -pl lib-pcb

Running com.exoreaction.pcb.BattleTestSuite

[Battle] KiCad projects (47 files): ALL PASS

[Battle] Altium Designer (38 files): ALL PASS

[Battle] Eagle <=6.x (22 files): ALL PASS

[Battle] German manufacturers (18 files): ALL PASS

[Battle] Flex PCB designs (11 files): ALL PASS

[Battle] Hand-authored / legacy (31 files): ALL PASS

[Battle] Edge cases / bug fixtures (24 files): ALL PASS

Tests run: 10,035, Failures: 0, Errors: 0, Skipped: 30

[INFO] BUILD SUCCESS

Total time: 6:48 min

The 30 skipped: known format variants not yet implemented. Documented, tracked, not hidden.

Demo · Git Log Main

695 commits. Zero broken builds.

git log --oneline main | head -20

a9f3c21 Add coordinate overflow detection for extreme values

87e2b14 Implement imperial mode for DrillListing converter

6c4d8a9 Property test: bbox monotonicity under feature addition

5b1f7e3 Fix: filter documentation layers before bbox calculation

4a9c2d8 Battle test: add 18 German manufacturer fixtures

3e8b5f1 Add measurement assertions to BoundBox test suite

2d7a4c9 Round-trip tests for all KiCad legacy formats

1c6f3b8 Pre-commit hook: enforce feature-branch workflow

... [687 more commits, all green] ...

Every commit:Passed CI before merge. No exceptions.
Pattern:Fix, test, measurement, battle fixture, property. The 6 fears visible in the commit history.
Demo · The Paranoia Engine

Fear → System → Result → Trust

Fear System Result Metric
AI hallucinations Round-trip + property tests Hallucinations caught in CI 10,035 tests
Production bugs Battle testing (191 files) Zero AI bugs past the systems 191 real files
Shipping bad code Pre-commit hook + PR gates main always green 695 commits, 0 breaks
Cost spiral Claude MAX + model selection $80K–$120K exposure → $0 $0 API spend
Losing control Directed synthesis (7 steps) 100% files understood 5–8 files/task
Silent failures Extreme measurement Fast semantic detection Minutes, not weeks
Formula: FearDisciplineResultsSleep

Keyboard Shortcuts

Previous slide
Next slide
Space
Main threadM
Fear 1 — AI Hallucinations1
Fear 2 — Production Bugs2
Fear 3 — Shipping Bad Code3
Fear 4 — Cost Spiral4
Fear 5 — Losing Control5
Fear 6 — Silent Failures6
Demo7
Toggle narratorN
FullscreenF
Bigger / smaller
+ -
Reset size0
Show shortcuts?
Return to mainEsc