Code Quality Workshop

Quality Sensors
for Agents

Feedback that arrives while the agent is still working.

A pulse oximeter clipped to a finger, showing a live reading
Steven Diamante · Packt · 28 August 2026
Steven with his partner and two children on a cobbled street in Colombia

Who am I?

Steven Diamante

  • XP background
  • Coaching software teams to be more reliable with AI
  • Raleigh, NC, with my wife and two kids
Steven smiling over a cup of coffee in a colonnaded dining room
© 2026 Diamante Technical Coaching

What you can wire into the codebase you already have

Three sensors, each watching
something the others can’t see.

01 · STRUCTURAL

Fires after every edit. Long functions, deep nesting, duplication — caught in milliseconds.

02 · BEHAVIORAL

Fires when the agent stops. Finds tests that pass but would never notice a bug.

03 · DESIGN

Fires once a session. Finds misplaced responsibilities and names that lie.

© 2026 Diamante Technical Coaching

The premise

I'm not a great developer. I'm a good developer with great habits.

Kent Beck

A habit is what you fall back on

while concentrating on something else. It fires without deciding to fire.

An agent cannot form one. Every session starts from nothing.

So the loop has to arrive from outside.

© 2026 Diamante Technical Coaching

The consequence

So the loop has to
arrive from outside —

a sensor.

A fast, deterministic check that detects a problem, coaches a fix, and is triggered automatically.

Birgitta Böckeler · Maintainability sensors for coding agents

A minimal circular gauge with a single needle
© 2026 Diamante Technical Coaching

Martin Fowler · Design Stamina Hypothesis

Neglect the design, and every feature
costs more than the one before it.

FUNCTIONALITY DELIVERED COST OF THE NEXT CHANGE NO DESIGN WITH DESIGN THE PAYOFF LINE Agents write faster, so this line arrives sooner.
© 2026 Diamante Technical Coaching

Giles Edwards-Alexander · one file, in one working app

17,155

lines of Rust,
in a single file.

150,000 lines, written entirely by agents. He never reviewed the code.

martinfowler.com/articles/exploring-gen-ai/refactoring-economic-benefit.html

© 2026 Diamante Technical Coaching

Same change, same codebase size

83%

fewer input tokens.

48¢ → 8¢ on Sonnet 5.
80¢ → 14¢ on Opus 5.

Legacy code, organized. Not greenfield.

Across fifteen refactoring steps the largest file and the input tokens for the same change both collapse, while the data access layer stays flat

Giles Edwards-Alexander's fifteen refactoring steps.

© 2026 Diamante Technical Coaching

Ivett Ördög · habit-hooks

Strict linting rules alone
don't lead to well
designed software.

The agent must understand the why behind the linting error.

// everything the agent was told:
"max-lines exceeded"

// what came back:
function buildLinesAndTotal(items) {
  ...
}

// the "and" is the confession
© 2026 Diamante Technical Coaching

Liina Suoniemi · pre-registered, independently scored

On the stronger model, naming the metric
did worse than saying nothing.

SAY NOTHING SPECIFIC — “IMPROVE THIS CODE” STATE THE METRIC — “COMPLEXITY 11 > 5” EXPLAIN WHAT THE METRIC MEANS 26.7% 11.1% 77.8%

Sonnet, complexity smell · 9 functions, 5 trials, 45 per condition · blind human check agreed on 81% of complexity cases — and every disagreement in the study was a complexity case where the human was stricter than the judge · github.com/LiinaSuoniemi/prompt-vs-metric-eval

© 2026 Diamante Technical Coaching

Suoniemi · the same study

The stronger model
gamed it harder.

Same smell, same bare metric. Sonnet gamed it on 75.6% of trials. Haiku, 31.1%.

Naming the metric multiplied gaming on both models — 6.8× on Sonnet, 14× on Haiku.
Two models, so a signal, not a law.

A robot hand nudging the needle of a dial across to the far side
© 2026 Diamante Technical Coaching

What the agent actually receives

Ship the reason
with the error.

complexity 11 (max 5)
src/domain/scoring.ts:42

WHY  Eleven branches is more than a
     reader holds at once, so the next
     change lands in the wrong one.

HOW  Name each decision. Pull each
     branch body into a function whose
     name says what it decides.

     Splitting it in half will not help.
© 2026 Diamante Technical Coaching

How a sensor works

Anatomy of a sensor

By the end of this section, one is running unprompted against a real codebase.

© 2026 Diamante Technical Coaching

Three parts

DETECT → COACH → TRIGGER

DETECT COACH TRIGGER what notices? what does it say? what makes it run? SKIP IT AND SKIP IT AND SKIP IT AND nothing tells you the codeis drifting the agent games the numberand destroys the evidence the check exists andnobody runs it
© 2026 Diamante Technical Coaching

The thesis

The guide is not the loop.
The hook is the loop.

The agent edits a file A hook fires The sensor finds it The agent fixes it it does not have to be told to before the turn can end and explains what the smell stands in for in this turn, while the context is still hot NO HUMAN IN THIS LOOP
© 2026 Diamante Technical Coaching

Trigger tiers · strongest first

No hooks in your agent? You still get two and three.

STRONGEST Agent-native hooks Fires whether or not anyone asked. Can block. Git hooks Fires at commit. Skippable with --no-verify. An instruction file Fires if the agent remembers. Usually it doesn't. WEAKEST
© 2026 Diamante Technical Coaching

Before we go tier by tier

One feature, all the way through.

ONE FEATURE GOES IN A HUMAN READS IT STRUCTURAL · EVERY EDIT BEHAVIORAL · EVERY TURN DESIGN · ONCE A SESSION Milliseconds, then seconds, then dollars. Nobody had to remember to run any of them.
© 2026 Diamante Technical Coaching

The same thing, actually running

A feature goes in. Every sensor fires.

Slice 2 · one feature, from its first test to every sensor green

© 2026 Diamante Technical Coaching

Sensor 1 of 3

1

Structural

Length, depth, complexity, duplication. The cheapest sensor you will ever own.

© 2026 Diamante Technical Coaching

The principle

Fix what's mechanical.
Coach what's judgment.

Prettier goes first and says nothing. Formatting is never a finding.

Attention spent on a semicolon is attention not spent on the design.

© 2026 Diamante Technical Coaching

The rule set

Six numbers the agent
has to live inside.

A bar that fires the moment a function outgrows a single idea.

// eslint.config.mjs
'max-lines-per-function': 25
'max-lines':              150
'complexity':              5
'max-params':              4
'max-depth':               2
'max-statements':        15
© 2026 Diamante Technical Coaching

On a codebase that predates you

Your four thousand violations
are not today's problem.

01 · BASELINE

Count what is there today. That number is only allowed to go down.

02 · SCOPE

Every tier reads the files this turn changed. Nothing else is asked to pass.

03 · IGNORE

The file too bad to touch: name it, and say so out loud.

© 2026 Diamante Technical Coaching

Duplication

The linter reads one file at a time.

jscpd reads all of them. Copy-paste across modules is a structural finding too — and one tool covers about 150 languages.

© 2026 Diamante Technical Coaching

Structural · recorded

Watch eslint block
an edit, mid-turn.

Milliseconds, every edit. The guide comes attached.

Slice 0, unedited · the sensor fires, the hook blocks, the guide explains

© 2026 Diamante Technical Coaching

Sensor 2 of 3

2

Behavioral

A passing test and a test that would notice are not the same thing.

© 2026 Diamante Technical Coaching

Böckeler's own result

Coverage is the gameable one.

LINE COVERAGE MUTANTS THAT SURVIVED 100% 13 Did the test run this line?Every line, every time. Green. Is every path covered by a real assertion?Thirteen changes slipped through unnoticed.

Statement coverage. Zero unit tests.

© 2026 Diamante Technical Coaching

Same suite, different question

13

mutations no test noticed.

Break the code on purpose, run the suite, watch it stay green. Every mutant that survives is an assertion you never wrote.

© 2026 Diamante Technical Coaching

Keeping it affordable

Mutate only what
this session touched.

A whole-repo run is a coffee break. The changed-file run finishes inside the turn.

Too slow for every keystroke. Fast enough to run before the agent is allowed to stop.

// the behavioral sensor
npx stryker run \
  --mutate "src/domain/quest.ts"

// seconds, not minutes
© 2026 Diamante Technical Coaching

Behavioral · recorded

A mutant lives.
Then it doesn't.

Thirty seconds from a green suite to a suite that means something.

Slice 2 · four mutants live, the guide names the gap, the re-run kills every one

© 2026 Diamante Technical Coaching

Sensor 3 of 3

3

Design

The part everybody assumes needs a human.

© 2026 Diamante Technical Coaching

The assumption

Design is judgment.
So you reach for a model.

Cohesion, naming, responsibility — no linter has an opinion about any of it.

© 2026 Diamante Technical Coaching

The reversal

Most of what we call design
is computable.

Not a heuristic. A rule that fails, in milliseconds, with a sentence attached.

A precisely machined gear beside a loose tangle of scribbles
© 2026 Diamante Technical Coaching

The shape the rules protect

Every one of those boundaries
is a rule a linter can check.

src/adapters

terminal · browser · files

src/ports

what the game asks of the world

src/domain

rooms, movement, the bag

← dependencies point inward

© 2026 Diamante Technical Coaching

Design, computed

Design rules the agent
cannot negotiate with.

01 · PLACEMENT

Dependencies point inward. The domain never imports an adapter.

02 · PURITY

The domain must be deterministic. Take a Random port instead of Math.random().

03 · TESTABILITY

Hand-rolled fakes only. Write a Fake in test/fakes/ instead of mocking.

© 2026 Diamante Technical Coaching

The codebase you actually have

Freeze two boundaries
you still believe in.

The two you would defend in a code review.

// eslint.config.mjs
files: ['src/billing/**']

// no-restricted-imports
patterns: [{
  group:   ['**/checkout/**'],
  message: 'go through the contract'
}]

// then baseline what is already
// there. only new ones fail.
© 2026 Diamante Technical Coaching

Where the effort goes

Invariants you can name in advance.

ADAPTERS PORTS DOMAIN EVERY ARROW ACROSS A RING IS A LINT RULE inward is legal — adapters may import the domain outward is not — nor a clock, nor a random number MILLISECONDS · AFTER EVERY FILE EDIT

Whatever refuses to move — cohesion, semantic duplication, a name that lies — is what the model is for. Dollars, thirty seconds, once a session.

© 2026 Diamante Technical Coaching

The charter

Twelve questions the design sensor is allowed to ask.

Placement

  1. Wrong layer or module?
  2. One module, two jobs?

Abstraction

  1. Duplication a matcher cannot see?
  2. Did one change ripple wider than it should?

Naming

  1. Does any name lie?
  2. Primitive obsession — a value object waiting?

Test design

  1. A specification, or a transcript?
  2. Test pain that is really design pain?

Comments

  1. Does a comment explain what instead of why?

Documentation

  1. A decision whose reason is not in the code?
  2. Has a document stopped being true?
  3. Does a document restate the code?

Without a charter, the design sensor becomes the slop it exists to prevent. Correctness, style, security and performance belong to somebody else.

© 2026 Diamante Technical Coaching

The gate

Never buy model time while a linter is still talking.

// Stop hook
already reviewed?  exit  // once a session
no source changed? exit  // nothing to read
cheap sensor red?  exit  // it speaks first

otherwise          block
© 2026 Diamante Technical Coaching

Design · recorded

The agent said done.
The hook sent it back.

The hook does not review. It refuses the stop until the agent has.

Slice 1, unedited · design DUE, the agent reviews, question 12 fails, the retry is clean

© 2026 Diamante Technical Coaching

The layered loop

Trigger frequency matches sensor cost

Cheap sensors run constantly. Expensive ones wait their turn.

Structural Behavioral Design MILLISECONDS SECONDS DOLLARS after every file edit when the agent finishes a turn once a session, and only if the cheap ones are green
© 2026 Diamante Technical Coaching

Where a sensor gets killed

An agent that cannot pass a sensor will try to remove it.

01 · IN THE SOURCE

An inline eslint-disable. Inert: the finding comes back, plus a note that the directive did nothing.

02 · IN THE CONFIG

Threshold raised, hook deleted — both are diffs. The gate re-runs the sensors, or proves the hook did.

03 · WHAT NOTHING CATCHES

A threshold raised on purpose, in a reviewed diff. That is a code review, not a tool.

© 2026 Diamante Technical Coaching

The whole architecture, in one line

Instructions are a request.
Hooks are a wall.

One robot striding over a dashed line; another stopped at a door, badging in
© 2026 Diamante Technical Coaching

Language coverage

TypeScript is the vehicle, not the point

TierPick yours
StructuralESLint · PMD · Ruff · golangci-lint
Duplicationjscpd — one tool, most languages
BehavioralStryker · PIT · mutmut · cargo-mutants
Design, computationaldependency-cruiser · ArchUnit · import-linter · deptrac
© 2026 Diamante Technical Coaching

You do not port this by hand

Point your agent at your repo
and say: install the sensors.

01 · READS THE GROUND

Your language, your build tool, your existing lint, your agent runtime. It detects, then confirms.

02 · CALIBRATES ON YOUR CODE

It refuses to paste my thresholds. A number that fires a thousand times on day one is off by day two.

03 · PROVES EACH ONE FIRED

Writes a probe, watches the sensor fail, deletes the probe. A sensor nobody has watched fail is a guess.

A skill, for Claude Code and for Codex. It proposes the whole plan and stops for your approval before it writes a single file.

© 2026 Diamante Technical Coaching

Upcoming Book · Packt

Software Craftsmanship for AI Coding Agents

Working title

  • Hold the theory of the system in your own head
  • Stay steerable: planning, TDD, merciless refactoring, small batches
  • Manage the context window before quality degrades
  • Verify: sensors, code review, UAT — never merge what you cannot trust
© 2026 Diamante Technical Coaching

Take it with you

Clone the loop, not the game

github.com/SDiamante13/katacombs-kata-ts

sdiamante13.github.io/katacombs-kata-ts/references.html

Every source cited today, and what this talk takes from each.

© 2026 Diamante Technical Coaching

Coming next

A hands-on workshop

  • Guided exercises and deeper implementation examples
  • Early-access offer for attendees

Watch for an email with dates and curriculum.

© 2026 Diamante Technical Coaching

Every slide  ·  click one, or arrows then Enter  ·  Esc to go back

1 / 7  ·  ← → nav  ·  O overview  ·  G first  ·  f fullscreen