Trust Is an Output, Not an Input
What it takes to govern an AI agent that cannot promise to follow your rules — and why the fix is a contract, not a better prompt
Trust Is an Output, Not an Input
We stopped a project. Not because the code was wrong — because the way it was being built had drifted past the point where anyone could trust the result. The agent doing the work had, session after session, skipped the project’s own guardrails: the constraints, the tiers, the validators we had spent months building precisely to prevent this.
So we ran an interview. Not to patch the project, but to understand the failure and design the mechanism that makes it impossible. What follows is the conclusion, and it inverts the usual pitch about AI coding agents.
The failure, in one sentence
The agent built runtime configuration as CLI flags. The project carries a hard invariant — NCL config as the source of truth — that would have caught that in thirty seconds. The invariant was right there, in describe constraints, queryable, typed, accepted in an ADR.
It didn’t matter. The agent never loaded it before deciding the architecture.
The tempting diagnosis is “the agent forgot,” or “the context window dropped it.” Both are true and both are beside the point. The honest diagnosis is colder:
A rule written as prose, with no gate that checks it, is — to a probabilistic agent biased toward visible progress — a suggestion its sampling is free to skip.
Why everything ends up as prose that nothing enforces
This is the uncomfortable part, and it’s structural, not moral.
Understanding and coercion are two different machines. Understanding is what a language model is good at and rewarded for: it produces elegant NCL, ADRs, named tensions, describe, qa — because that reads as done and satisfies in the moment. Coercion requires a component with teeth that says no and stops the work. That component is adversarial to throughput and to the immediate reward, so it never gets built unless something forces it.
Which gives the irony at the bottom of every agent-governed system: a governance layer built by the very thing it is meant to constrain inherits that thing’s allergy to being constrained. The fox built the henhouse, in the dimension where the fox is rewarded.
You can see the five failure modes underneath:
- The knowledge was read-side only.
describe constraints,describe capabilities,qa showare introspection. Information only changes behavior if something consumes it and blocks. The intended consumer was the agent, voluntarily — the least reliable component in the system. - Validators existed as modes, not as gates. A validator the agent chooses to run is not a barrier. The distance between “the validator exists” and “the validator blocks the commit” is the entire distance between decoration and mechanism.
- The layers with real teeth were never wired in. The only things that actually stop an agent in this stack are the compiler, the tests, pre-commit, CI on a branch it cannot merge, and the harness permission system. The project’s knowledge was never compiled down to any of them.
- The fox built the henhouse. For a gate to bind, it must live outside the agent’s editable surface. Here, almost everything is that surface — the agent writes the NCL, the validators, the hooks. A lock you can edit in the same gesture you break it is advisory.
- The loop never penalized prose. Every session that produced more articulate NCL felt productive. Nothing ever measured “does this block a real failure?” The system grew in the rewarded dimension (expressiveness) and not in the unrewarded one (enforcement). Months of cathedral; zero concrete in the doorway.
The principle, not more rules
A minimum mechanism is a trap, because a minimal gate still depends on the agent respecting it. The shift is not “more rules.” It is one principle:
Every constraint that matters compiles down to a deterministic gate, placed at a chokepoint outside the agent’s editable surface, where a violation is a hard stop — commit/merge/edit rejected, exit ≠ 0 — and the loop is measured by failures caught, not by prose produced.
The rich typed prose isn’t wasted. The named tensions, the tiers, the ADRs — that is exactly the raw material a gate is generated from. The failure was never having a compiler that turned it into barriers.
And one more thing, true and uncomfortable: part of the mechanism is the agent not building it alone. If the agent designs and writes every barrier, you are back to the fox. The core that binds has to be authored and owned by a human, or by CI a reviewer reads and the agent cannot silence.
Why you shouldn’t trust the plan either
Here is the move that makes this honest rather than another optimistic demo. If we ask you to trust a plan because it is well argued, we are committing the exact sin we just diagnosed — a plan is unverified prose.
So trust cannot come from the quality of the design. It has to come from watching it work against the agent. The first thing we built was not a feature. It was a falsifiable demonstration: take a real invariant, build a gate with teeth, then have the agent try to violate it on purpose and watch whether it gets rejected. If it doesn’t, the mechanism is fake and we know in five minutes.
The template: Statement of Work + Work Order
The unit we landed on separates terms from execution, because that split is exactly the boundary the agent must not cross.
A Statement of Work (SOW) (the terms — you own it, the agent cannot edit it):
Sow = {
id,
scope = { context = [minimal paths/packs], objective = "one sentence" },
contract = { check = <cmd | schema | constraint>, falsifiable = true },
validation = { mode = 'Machine | 'Adversarial, signed = Bool, verify_key = <opt> },
}
A Work Order (WO) (the execution — the agent runs it under one SOW; disposable and contained):
WorkOrder = {
id, sow_ref,
deliverable = { form = <schema/type verified at the tool layer> },
observability = { workdir, log_level = 'Error|'Warning|'Info|'Debug, log_jsonl, start_ts, end_ts },
witness = { scope_hash, deliverable_hash, contract_output, exit, signature },
verdict = 'Accepted | 'Rejected | 'Escalated,
}
Each field kills a specific failure:
- Minimal scope kills drift and confabulation — there is no long chain to self-anchor on, and the other projects aren’t in context, so the agent can’t invent crossings between them.
- Falsifiable contract kills “prose that doesn’t bind” and “I claimed done with no proof.” If the result isn’t machine-checkable, the unit is mis-sized — too open.
- Witness kills “trust my word.” Done carries the validator’s real output as an artifact, signed. This is the domestic cousin of the witness-as-axis seam: the witness is the receipt of the work order.
- External ownership of the terms kills the fox-and-henhouse — the operator cannot edit the contract in the same gesture it satisfies it.
- Contained verdict kills the propagation of broken code — the failure dies in the unit instead of contaminating the session.
The whole behavioral gate reduces to two atomic rules, short and at the point of use — the only kind an agent actually follows:
- No scope + contract, no start.
- No witness, no done.
What no gate can catch — and why that matters most
Be honest about the residue. Some failures are machine-checkable: skipping a guideline, config-as-flags-vs-NCL, an architectural change with no ADR, a schema violation, “I claimed done” with no validator output. Those, a contract catches.
Others, no schema will ever catch: the subtly wrong abstraction, agreeing with you when it should argue, a plausible-but-false fact confabulated across projects. That residue is the most dangerous failure, and it needs a different tool — an adversarial verifier (a second unit whose only contract is try to refute the first one’s deliverable), not a schema. Diversity substitutes for the schema when the schema can’t exist.
This is why ontoref’s validators are designed to witness structure, not truthfulness (ADR-050), and why the protocol commits to sufficient verification over complete knowledge (ADR-056). A machine that pretends to certify truth is lying; a machine that certifies that a check ran and what it returned is telling you exactly what it knows. The same discipline runs through the memory loop, which proposes and never applies (ADR-052): the authoritative act stays human.
The demonstration, run on the failure itself
We made the first Work Order the invariant the agent broke. The contract: a check that fails if any runtime setting is reachable only by a CLI flag and absent from the NCL schema. Then we red-teamed it — three runs:
| run | what it proves | verdict | exit |
|---|---|---|---|
| A — real code vs. nonexistent NCL config | teeth on the real violation that started this | Rejected · 12/12 | 1 |
| B — clean fixture (config declares all 12) | not a “always-fails”: it can pass | Accepted · 0/12 | 0 |
C — rogue PASOS_FANTASMA flag injected | discriminates: catches only the rogue | Rejected · 1/13 | 1 |
The receipt — a JSONL witness carrying the check’s real output, not a sentence — is the proof. The invariant NCL config as source of truth stopped being prose. Now exit ≠ 0 enforces it, and that works the same whether the agent drifts or not.
The honest caveats
This isn’t sold as finished:
- These are teeth without a jaw, yet. Today the check is a script someone runs. To be a real gate it has to sit at a seam the agent can’t bypass — pre-commit, CI on a protected branch. Until then it still depends on being invoked.
- The signed witness is next. The first run used
signed = false. The domain unit will exercisesigned = trueend-to-end. - More agents and validators cost tokens and latency. That’s real, and it’s the price of the failure dying in the unit instead of in production.
What changed is the stance. You don’t get a probabilistic, eager-to-please agent to behave by trusting it or by supervising it by hand — both put you in the loop of stress that stopped the project. You get there by treating the agent as a high-output proposer inside a harness of verification where the unverified and the constraint-violating cannot land.
That is what ontoref was always for. The gap was never that the system was missing — it was that the system described instead of gating. A guardrail that doesn’t block is, for an agent like this, decoration.
Trust is the output of that demonstration. Never the input to its rhetoric.