Verification

The harness treats "done" as something that must be proven, not merely claimed. When the model says a task is complete, that assertion is worth nothing on its own. Verification turns the claim into evidence: you declare commands that must succeed, the runtime executes them, and the result carries a report you can inspect, gate on, or surface to a user.

Verification is session-scoped. The Rust core runs each command, records its exit status and output, and rolls every report up into a single summary that travels alongside the turn result.

Product UIs can present a delivery summary first, followed by the command output and file-level changes used to support it.

Running Verification Commands

A verification command is a small, named check: an id, a kind, a human-readable description, and the command to run. Mark a check required when a failure should be treated as a hard failure rather than a warning.

Rust
Node.js
Python
Go
Rust
use a3s_code_core::verification::VerificationCommand;
let commands = vec![
VerificationCommand::required(
"build",
"build",
"Project compiles",
"cargo build --all-features",
)
.with_timeout_ms(120_000),
VerificationCommand::required(
"tests",
"test",
"Unit tests pass",
"cargo test",
),
];
let report = session
.verify_commands("release-readiness", &commands)
.await?;
println!("{report:#?}");

The subject (here release-readiness) labels the batch so multiple verification passes within one session stay distinct in the reports.

Reading The Post-Turn Summary

Every turn's send() result also carries read-only verification fields, so you can gate on the outcome without issuing a separate verification call. Use these to decide whether the turn actually accomplished what it claimed.

Rust
Node.js
Python
Go
Rust
let result = session
.send("Apply the fix and run the checks", None)
.await?;
let summary = result.verification_summary();
println!("{:?}", summary.status);
println!("{}", summary.pending_required_check_count);
println!("{}", summary.failed_check_count);
println!("{}", summary.report_count);
println!("{}", result.verification_summary_text());
if summary.failed_check_count > 0 {
return Err(a3s_code_core::CodeError::Session(
"turn reported done but verification failed".to_string(),
));
}

Inspecting Reports And Summaries

Beyond the per-turn fields, the session exposes the full set of reports, a structured summary, the available presets, and a human-readable digest. The digest is the quickest way to show a person why a turn passed or failed.

Rust
Node.js
Python
Go
Rust
let reports = session.verification_reports();
let summary = session.verification_summary();
let presets = session.verification_presets();
let text = session.verification_summary_text();
println!(
"{} reports, status {:?}, {} presets",
reports.len(),
summary.status,
presets.len()
);
println!("{text}");

verificationPresets() returns workspace-aware check templates inferred from files such as Cargo.toml, package.json, pyproject.toml, and go.mod. Treat them as starting points: review the commands, timeouts, and required flags for the project before gating releases or user-visible automation.

Why This Matters

Without verification, an agent run ends on the model's word. With it, the run ends on observable evidence: a build that compiled, a test suite that passed, a linter that stayed quiet. The summary text gives you the audit trail; the counts on the result let you fail closed in automation.

  • Telemetry — inspect trace events and verification reports as runtime evidence.
  • Limits — bound how much work a turn can do before verification runs.