DEV Community

Werner Kasselman
Werner Kasselman

Posted on

Compilation Is Not Assurance: What Agentic Rust Needs After the First Green Build

AI-assisted coding looks fastest when we stop the clock too early.

A model can scaffold a crate, implement a trait, generate tests, and reach a green cargo check before a human engineer has finished tracing the existing ownership model. That is a real capability. It is also a poor measure of completed engineering work.

Senior systems developers care about the rest of the path:

  • Is the ownership model intentional, or did the implementation clone its way out of a lifetime problem?
  • Is shared state necessary, and are lock scope and contention understood?
  • Can malformed input turn into a process-wide panic?
  • Does the change preserve latency and allocation budgets?
  • Do tests establish the intended property, or merely reproduce the new implementation?
  • Can another engineer reconstruct why the design was accepted?
  • How much review and remediation did the apparent acceleration consume?

On 5 August 2026, Rust engineer Erik-Jan van de Wal described exactly this gap. His post called out agents reaching for .clone(), Arc<Mutex<T>>, unsafe trait implementations, and unwrap() when the actual task required reasoning about ownership, concurrency, and production failure. He also reported that token spend and fifteen additional hours of cleanup made his AI-assisted path roughly twice as expensive as writing the code himself. Those are his reported results, not a general industry benchmark, and the conclusions in this article are mine rather than his. Read Erik-Jan van de Wal's post.

His larger point is difficult to dismiss: generated code is being counted as progress while verification, architectural repair, and operational risk remain off the productivity ledger.

One way we are trying to correct that accounting in our work is the Agent Assurance Profile, or AAP. Its premise is simple:

Code is not ready for operational trust merely because it compiles. It becomes reviewable when important claims are connected to evidence another process can inspect, and residual judgment is explicit.

AAP does not make a model understand Rust. It does not convert a prompt into a proof, and it does not replace senior review. It changes the protocol around agentic work so that plausible output is not accepted as its own evidence.

Three layers that must not be confused

Before describing the mechanics, it is important to separate three layers that are often collapsed in discussions about agent assurance.

The first is the DAG-TOML specification and its draft profiles. The public agent-assurance repository defines document kinds, profiles, invariants, and validators. The implementation DAG and traceability documents come from core specification, the cost record comes from cost profile, and AAP composes them for agent assurance.

The second is an emitter implementation. agent-assurance-dsrs is the Rust workspace where we execute and evaluate DSPy-style programs, then emit a concrete subset of those documents as sidecars. It shows that runtime results can be mapped into validator-compatible assurance artifacts without coupling runtime types to governance schemas.

The third is a team's assurance policy. Rules such as "no lock guard across an await", "no unreviewed unsafe trait implementation", or "p99 latency may not regress by more than five percent" are not automatically supplied by AAP. A team must define those claims, choose suitable evidence, protect the acceptance policy, and decide which residual risks require human approval.

The specification and profiles supply a language. The emitter supplies data in that language. The policy determines what the data must establish.

From instructions to claims

Repository instructions still matter. An agent should be told which modules are security-sensitive, which APIs are stable, where allocation matters, and what style the project expects.

But instructions exist inside a probabilistic context. A rule such as:

Do not introduce Arc<Mutex<T>> without architectural justification.
Enter fullscreen mode Exit fullscreen mode

does not establish whether the model noticed the rule, whether the edited path was covered by it, whether the lock survives an .await, or whether contention remains acceptable under load. A model can violate the constraint, apologize, revise the patch, and declare success without leaving durable evidence that the final result complies.

AAP treats the instruction as an input. Assurance begins when it becomes a precise claim with an enforcement or review path.

For example:

claim: no synchronous lock guard crosses an async suspension point
scope: crates/runtime/src/**
evidence:
  - clippy::await_holding_lock result
  - targeted async integration tests
  - reviewer approval for synchronization changes
Enter fullscreen mode Exit fullscreen mode

Even this claim needs qualification. The Clippy lint catches particular structural patterns; it is not a proof that every concurrency interaction is safe. The tests exercise recorded cases; they do not cover every schedule. The human review remains part of the evidence chain because architecture has not become a lint.

That is the discipline AAP encourages: say exactly what is claimed, identify what supports it, and leave the limits visible.

The assurance graph

An assurance package is useful when its documents form a connected graph rather than a folder of ceremonial files.

requirement
    |
    v
implementation unit
    |
    v
changed code
    |
    v
verification command
    |
    v
test, analysis, or benchmark result
    |
    v
assertion
    |
    v
gate decision
Enter fullscreen mode Exit fullscreen mode

A reviewer should be able to traverse the graph in both directions. Starting from a requirement, they can find the implementation and evidence that claim to satisfy it. Starting from a changed synchronization primitive, they can find the requirement that authorized it and the checks that exercise it.

Missing edges are useful information. A critical requirement without evidence is incomplete. A test attached to no claim may be irrelevant. A changed file mapped to no authorized unit may indicate scope expansion.

The implementation DAG: bounded work instead of open-ended agency

Agentic coding is most dangerous when the assignment is broad enough for the model to redefine success while working.

“Improve the runtime architecture” is not an executable contract. It permits nearly unlimited reinterpretation.

DAG-TOML represents implementation as a directed acyclic graph of bounded units. Each unit can carry:

  • an identifier;
  • a concrete objective;
  • dependency relationships;
  • files it may create or modify;
  • acceptance criteria;
  • required evidence;
  • status;
  • and outputs consumed by later units.

For example:

U01: establish provider-neutral error taxonomy
  └─ U02: implement retry classification
      └─ U03: add bounded retry wrapper
          └─ U04: verify retry accounting
              └─ U05: approve release gate
Enter fullscreen mode Exit fullscreen mode

The graph has several advantages over an ordinary checklist.

First, it makes ordering explicit. The agent cannot credibly validate retry accounting before retry behavior exists.

Second, it exposes parallel work without inventing independence. Two tasks may run concurrently only when their dependency edges permit it.

Third, it creates scope boundaries. If the unit authorizes changes to the provider adapter and tests, an unsolicited rewrite of the runtime state model becomes detectable scope expansion.

Fourth, it gives failure a location. A gate can fail because a particular unit lacks evidence rather than because an agent vaguely reports that “some tests still need attention.”

This does not prevent an agent from making a bad edit. It makes the edit easier to classify as unauthorized, unsupported, or incomplete.

That is the profile's intended use, not a claim that every current emitter produces a rich plan. The default agent-assurance-dsrs demo emits a single completed unit with no dependency edges and an empty file scope. Separately, we use a hand-authored 34-unit implementation DAG to record and partly govern its development. The former demonstrates runtime emission; the latter demonstrates multi-unit planning. They should not be presented as the same capability.

What agent-assurance-dsrs actually implements

agent-assurance-dsrs is an eight-crate Rust workspace:

  • dsrs-core supplies typed examples, predictions, signatures, module traits, run context, callbacks, batching, parameter traversal, and state persistence.
  • dsrs-lm supplies the LM boundary, structured adapters, provider-neutral errors, caching, usage records, retry handling, OpenAI and Anthropic clients, reasoning modules, tools, streaming, and optional native process sandboxing.
  • dsrs-evaluate runs sequential evaluation and records metric results.
  • dsrs-optimize implements few-shot, ensemble, COPRO, MIPROv2, GEPA, and SIMBA optimization surfaces.
  • dsrs-retrieve provides exact cosine, LSH, ColBERT-style, and HTTP vector-store retrieval.
  • dsrs-datasets provides dataset loading and parsers for HotPotQA, GSM8K, and MATH.
  • dsrs-assurance maps evaluation data and run events into assurance sidecars.
  • dsrs-cli wires the pieces together for hermetic and optional live-provider demonstrations.

Network, async, and native-sandbox behavior remain off by default. Dedicated CI lanes exercise them without making the ordinary workspace build depend on provider access, Tokio, or platform-specific sandbox libraries.

The default demo evaluates a fixed Predict program using a deterministic EchoLm and ExactMatchMetric, uses the same run context for MIPROv2 search and LSH retrieval, parses SSE separately, and records caller-declared capability labels rather than inferring them from run events. A separate credentialed workflow tests a real OpenAI call and, when configured, an Anthropic call, then runs the live demo and validates its sidecars.

The current emitter writes eight TOML documents:

  • implementation DAG;
  • traceability;
  • smoke validation;
  • evidence matrix;
  • adapter contract;
  • assertion bundle;
  • gate decision; and
  • cost record.

It also writes raw evaluation and run-event JSON. The adapter contract contains declared metadata (the sandbox, network, and clock fields are not observations from the demo). Threat models and rollback plans belong to the wider profile but are not emitted by this runtime path today.

This is a working emission substrate, not proof of the full assurance thesis. It shows that evaluation results can become structured, linked sidecars while runtime APIs remain independent of document serialization. It does not, by itself, prove ownership quality, unsafe soundness, concurrency architecture, or production readiness.

What independent validation means today

The repository's CI checks out agent-assurance at a pinned commit, builds its Rust and Go validators, generates the demo sidecars, and validates the TOML package with both implementations.

That is valuable. The emitter and validators are different codebases, the validation contract is version-pinned, and two implementations must agree on document conformance.

The boundary must still be stated precisely. Coverage varies by document kind; some receive dedicated semantic checks, whilst others receive shared schema and cross-document checks. The validators do not rerun the evaluation, decide whether a benchmark is representative, establish that an unsafe proof is sound, or determine that the cited test actually supports the engineering claim.

The current gate decision is also produced by dsrs-assurance. Its pass or fail value is derived from whether the recorded evaluation meets a threshold. External validators can reject a malformed or invariant-breaking gate document, but they do not independently recompute the semantic decision.

A production acceptance system therefore needs another boundary:

producer emits evidence and a proposed decision
              |
              v
protected CI reruns required checks
              |
              v
independent validators check package conformance
              |
              v
policy evaluates required claims and exceptions
              |
              v
human approval handles residual judgment where required
Enter fullscreen mode Exit fullscreen mode

The most important operational rule is that the implementation agent must not be able to weaken its own thresholds, replace the validation policy, and approve the result in the same trust domain.

Hashes provide integrity only when something trusted anchors them

agent-assurance-dsrs currently derives several hashes from emitted content:

  • raw_input_hash covers the serialized evaluation result;
  • bundle_hash covers the assertion records; and
  • evidence_root is derived from one labeled, prehashed assertion-bundle.bundle_hash record.

The implementation tests reproduce those values from the emitted file contents; the external validators check their form and invariants rather than recomputing a whole-package hash, and evidence_root is not a hash of every sidecar. Within those limits, the hashes help detect accidental mutation and bind references within the content they cover.

It does not make a self-generated package trustworthy. An agent that weakens the evidence and regenerates every document can produce a new, internally consistent set of hashes. Tamper evidence becomes meaningful only when an expected hash is stored somewhere the producer cannot rewrite, such as a protected CI record, signed attestation, transparency log, or independently controlled release gate.

Hashes answer "did these bytes change relative to an anchored value?" They do not answer "was this the right test?" or "is this design safe?"

Rust-specific claims worth making explicit

The most useful AAP policies will be local and specific. Rust projects should resist generic claims such as "thread-safe" or "production-ready" when narrower claims can be checked more honestly.

Ownership and cloning

A blanket ban on .clone() would be counterproductive, because cloning an Arc or a small configuration value may be exactly right while cloning a large payload in a hot loop may destroy the intended performance model, and the difference is precisely the kind of judgment that a green build cannot supply.

A project could require justification for new clones in designated hot paths, allocation measurements using a counting allocator, DHAT, or an equivalent tool, a benchmark comparison for payload duplication, confirmation that ownership changes preserve the public API contract, and explicit review when a clone avoids a deeper ownership redesign.

The compiler proves the clone is legal. The evidence should establish whether its cost and design consequences are acceptable.

Shared mutable state

Arc<Mutex<T>> is sometimes the right design. It should not be the silent default, and the moment it becomes the default the design has already traded ownership reasoning for a concurrency model that is harder to audit under load.

Relevant claims might cover why the state requires shared ownership, whether ownership transfer or channels were considered, whether lock scope is bounded, whether a synchronous guard can survive an .await, how poisoning is handled when using std::sync::Mutex, and what contention looks like under the target workload.

Static checks, Loom models, integration tests, and benchmarks each support different parts of that story; none of them should be described as proving all of it.

Unsafe boundaries

A manual unsafe impl Send or unsafe impl Sync is a proof obligation written in code.

A serious policy can require a documented invariant, links to every relevant field, Miri or model-checking results where applicable, a source scan showing the complete unsafe surface, and named human approval. The gate should fail when the required review or evidence is absent.

Panic behavior

unwrap() is not universally wrong. It may be reasonable in tests or in an initialization path whose precondition is statically controlled. In a provider parser, streaming loop, library boundary, or long-running service path, it can turn malformed input into an outage.

The useful rule is scoped:

  • tests may use unwrap();
  • immutable startup configuration may permit documented exceptions;
  • library and runtime paths require typed error propagation;
  • each exception identifies its location and precondition; and
  • a repository check records whether the policy holds.

These are examples of claims a team can express through AAP. They are not checks the current DSRs emitter automatically runs.

Cost belongs in the evidence package

The strongest challenge to AI productivity claims is economic. Token spend is only one component. A more useful accounting model includes:

cost to accepted outcome =
    inference and orchestration cost
  + CI and infrastructure cost
  + human review cost
  + remediation and retest cost
  + expected incident loss
Enter fullscreen mode Exit fullscreen mode

Expected incident loss needs an explicit probability and impact model if it is to be treated as a number rather than a reminder. The point is not that every team can calculate it precisely. The point is that omitting operational risk does not make it zero.

agent-assurance-dsrs already emits a cost-record sidecar, but its current content is modest: it records evidence run count and a zero-valued compute-time placeholder with a note that elapsed time is not yet measured. It does not currently capture token cost, reviewer hours, remediation loops, or incident exposure.

One internal data point from our work shows why those missing fields matter without supporting a broad productivity claim. In our 34-unit DSRs implementation DAG, 31 units reached done, U32 was deliberately deferred, and U33-U34 remained pending. The first 18-unit build-out passed a per-unit Codex and Grok review gate only after the reviews caught defects, including five concrete examples: NaN reward poisoning, a cache sentinel that could return one request's response for another, tool execution after invalid JSON, an incorrect ensemble tie-break, and an assurance claim that said more than its evidence established. Later sandbox reviews caught three more fail-open defects and fixed them to fail closed. Two of those fixes overlap with U31's five follow-up fix or disclosure commits. The U31 filesystem-scoping pull request also produced four failed CI workflow runs across two revisions before it went green.

The observable wall-clock windows were about 6.1 hours from the first U02 commit to merge for the initial batch and 3.2 hours from pull-request opening to merge for U31. Those are not reviewer-hours: they do not separate human attention from parallel agent execution, and they are not an ROI benchmark. They are a record of review and rework that would disappear if the measurement stopped at generated code or first compilation.

That makes cost accounting a clear extension point rather than a completed feature. The target metric should be cost to an accepted, evidenced outcome, not tokens per generated line or minutes to first compilation.

A practical adoption path

Teams do not need to model their entire development lifecycle on day one.

Start with one class of change that repeatedly creates review debt, such as concurrency, provider adapters, authorization, migrations, unsafe boundaries, or performance-sensitive code.

Define a small vocabulary of narrow claims:

no_unreviewed_unsafe
no_sync_lock_guard_across_await
panic_policy_satisfied
latency_budget_preserved
all_requirements_traced
rollback_path_verified
Enter fullscreen mode Exit fullscreen mode

Bind those claims to tools the team already trusts: cargo test, targeted Clippy lints, Miri, Loom, fuzzing, Criterion, dependency audits, integration tests, and repository-specific checks.

Run the checks in protected CI. Record exact commands, versions, inputs, outputs, and hashes. Validate the artifact package independently. Require an external decision for policy changes and high-risk overrides.

Finally, measure rework. Record failed gates, review time, remediation time, and the classes of task for which the agent helped or hurt. Some work will prove cheap to assure and genuinely faster with an agent. Other work will reveal that human-led implementation remains the better engineering decision.

Both results are useful because both replace intuition with evidence.

The standard after compilation

Rust developers already work in a culture of explicit proof obligations. The compiler checks what the type system can express. Tests, model checking, benchmarks, review, and operational experience cover different parts of what it cannot.

The DAG-TOML stack, used through AAP, extends that discipline above the language layer. It can connect a requirement to a bounded unit of work, the changed code, the verification result, the assertion, and the release decision. It can make missing evidence and unauthorized scope visible. It can record which policy and validator version accepted the package.

It cannot decide whether an architecture is elegant, whether a workload represents production, whether an unsafe proof is sound, or whether the requirement itself is correct. Those limits should remain prominent because assurance becomes marketing the moment its evidence is allowed to claim more than it establishes.

The goal is not to prove that AI-assisted development is always faster. It is to stop measuring speed at the first green build.

In agent-assurance-dsrs, we are building one concrete piece of that future: a Rust runtime that emits reviewable assurance sidecars without folding governance schemas into its core types. Together, DAG-TOML and the draft Agent Assurance Profile connect those sidecars to plans, evidence, costs, and gates. Teams still have to supply the policy, the protected execution boundary, and the engineering judgment.

That is a more credible standard than asking whether the agent sounded confident or whether the patch happened to compile.

The important question is whether its claims can survive contact with independently controlled evidence.

Top comments (0)