Coding agents need numeric gates, not vibes
Verify for coding agents is a stack of measurable contracts in the harness. Pick the gates that fit the job. Fail closed. Retry or escalate. Never ship on confidence theater.
We build production GenAI for operations, knowledge, and data. Coding agents sit inside that same demand. They write fast. Shipping still needs a definition of done a machine can fail. Numbers in the harness, not a tone of confidence in the completion.
A coding agent that can edit, commit, and open a pull request without a numeric verify step is a costume with a keyboard. Lint green is not shippable. A polite self-check in the prompt is not a gate. The verify step has to read like a contract: complexity on the functions that changed, coverage on the logic under edit, dead code on touched paths, honest types at the boundary. Pass ships. Fail retries with a changed gather, or escalates to a person. Silent ship is the defect.
Vibes fail in the same places every time
Teams keep mistaking fluency for quality. The model produces a clean-looking diff. The review comment says "looks good." CI is green because the suite never touched the new branch. Two weeks later the file is a nested forest, half the helpers are unreachable, and one any has turned the boundary into fog.
Confidence theater is the other failure. The agent prints "I verified the change" inside the chat, yet no score left the process and no threshold was consulted. The harness treated a sentence as a sensor. That is how AI-generated clutter lands in production apps: not as malice, but as a missing contract.
Green lint is a low bar. Formatters and style rules catch almost none of the agent failure modes that matter on a long-lived codebase: god files, cognitive nests, untested happy paths, leftover exports, type escapes that compile and then lie. You need numbers that disagree with the model when the model is wrong.
The gate stack sits in verify, before done
Gather pulls the ticket, the diff, the schema, the prior failing score. Act fires the named tools under a permission list. Verify is where the numeric stack lives, and done is not a mood. Done is a set of contracts that returned pass.
The figure is the product shape. The gateway still routes, caches, and hardens stop sequences. The gate stack is not the gateway; it is the definition of done for this coding job.
What each class of gate actually buys you
Complexity caps catch the nested forest before it becomes the file everyone fears. Cyclomatic and cognitive limits on methods are useful defaults. Example contracts a harness can enforce look like warn around 15 and fail around 20 on the function under edit. A public scorecard that says "under 22" is a starting illustration, not a sacred number; tighten or loosen for the language and the blast radius. Halstead difficulty can sit as a trend on changed functions. Treat a hard global "under 80" as a smell signal, not as merge law. Absolute Difficulty thresholds do not have strong industry consensus. Agents will game a number they can see.
Coverage floors buy you evidence that the new logic ran. Aim the floor at changed lines and domain logic under edit, often in the 80 to 90 percent band for production app work. Do not demand 100 percent of UI chrome, platform channels, or generated tables. Repo-wide 100 percent as a merge block trains agents to write useless tests that inflate a score and teach nothing.
Dead code gates buy compound cleanup: no new dead exports on touched paths, and delete orphans in the same PR when it is cheap. Zero dead code as a whole-repo religion is expensive theater. Zero "redundant" as an automated fail is worse, because the word is subjective and agents respond with bad renames.
Type honesty buys a boundary you can trust. Ban any in TypeScript on agent PRs. Allow unknown at JSON and API edges, then narrow; blind rules that also ban unknown punish the right pattern. Dart and other languages need their own analysis rules, not a TypeScript paste.
Mutation and CRAP-style gates buy pressure on tests that only assert the happy path. Keep them on crown-jewel modules (matcher cores, billing, quota), not on every pull request for every package. Full mutation at repo scale is slow and noisy. "No surviving mutants" everywhere is religion dressed as rigor.
Those thresholds are example contracts. They are not Sunrise product KPIs. The product move is knowing which subset fits this job, and wiring it so the agent cannot talk past it.
Gates live in the harness, not in a polite prompt
A system prompt that says "keep complexity low and write tests" is a lecture. Models negotiate with lectures. The same pattern shows up when teams paste long policy into the window and call it control. Slim packs and hard stops are control, and numeric verify is the coding-agent version of that stop.
Put the scores in CI and in the agent loop. The harness gathers the failing metric, the file path, and the prior attempt so the next act has to change something measurable. A retry that does not change the gather is a hang you are paying for.
This is the same gather, act, verify shape as the rest of the production loop. Incident intelligence only delivers 75% lower mean time to recovery when a ranked hypothesis arrives with evidence and a person on the last step. Coding agents only stay useful when the verify step can fail them with a number. The in-network gateway still holds the routing and cache shape that delivers 42% lower token spend, 2.4× useful completions per 1k tokens, and about 68% prompt-cache hit on repeated enterprise workflows. None of that replaces the gate. It makes the gate affordable, because the expensive model sees a slim pack and a failing score, not a memoir about quality.
Schema and mapping work already shows what mechanical verify does for throughput: up to 60% less time on schema and mapping, and 3× throughput on attribute mapping, when the model proposes inside a scored contract instead of narrating a standards document. Coding-agent verify is that idea applied to diffs.
Fail closed. Then retry or escalate.
When a gate fails, done stays shut. The loop may retry with a changed gather: the complexity report, the uncovered lines, the dead export list, the type error. Cap the retries. When the budget is spent, escalate. A person owns the write that can still hurt.
Never silent ship. Never print the template because verify was inconvenient. Leadership will see throughput while the floor sees clutter, and trust leaves quietly the same way it leaves when a harness falls back to a canned answer after eval fails.
Fail closed is not cruelty.
It is how you keep an operations floor, a knowledge desk, or a data review queue from inheriting AI-generated debt at agent speed.
Tradeoffs you actually have to make
Numeric gates add latency. Mutation on a crown module can add minutes. Threshold tuning takes judgment, and false fails will happen on generated assets, golden scripts, and theme dumps. Carve those out in the PR note. Do not invent a softer gate that always passes.
The expensive trade is religion. Enforce the full public scorecard on every line of every repo and you will spend product time on coverage theater, Halstead games, and mutation noise. Skip numeric contracts entirely and you will spend it later deleting god files. The useful middle is a tightened default for agent PRs on production apps: complexity, dead code on touched paths, ban any, meaningful coverage on logic under edit, selective mutation where the blast radius is real.
Another trade is language. A TypeScript rule set is not a Flutter rule set, so the harness should carry language-specific contracts rather than one meme pasted into every brief.
A third trade is where judgment lives. Cheap workers can compute scores. The expensive model should see the failing slice and the slim pack. The person should see the trace when the loop escalates. That split is harness design, not a bigger model card.
We still do not know the perfect default band for every stack we will ship next year. The contracts will move. The rule that does not move is mechanical verify before done.
What production demands
Production coding agents need a verify step that can say no with a number.
Name the contracts for the job. Wire them in the harness, not in a paragraph the model can summarize away. Prefer diff-scoped complexity, dead code, type honesty, and coverage that proves the new logic ran. Keep mutation and CRAP for modules that deserve the cost. Reject repo-wide 100 percent coverage, blind Halstead absolutes, and "no surviving mutants" on every PR as universal law.
Fail closed. Retry with a changed gather, escalate when the budget is spent, and keep a person on the last step when the write can take a service down.
That is the standard we build to at sunrisegenai.com. The model writes. The harness decides whether the run ships. If you cannot point to the numeric stack in front of done, you do not have a coding agent yet. You have a fast autocomplete with a pull-request costume.