Capability evidence ledger
SRB records system capability claims in
docs/data/capabilities.toml. The ledger is deliberately conservative:
source code proves only that a capability is present. Higher claims require
current execution evidence.
Promotion ladder
Every lane uses the same contiguous ladder:
presentunit_verifiedsimulator_verifiedreal_data_verifiedhardware_verified
A lane cannot skip a level. An unearned level carries a reason, owner, requested evidence, and expiry date. Expired blockers remain visible and do not become evidence.
The ledger has twelve lanes. All twelve are currently present, and none
has reached its target. Historical reports are useful context, but they do not
promote the current tree.
Evidence identity
All source records include the SHA-256 digest of a repository-relative file. Changing or removing that file invalidates the record.
Execution and benchmark records bind to two identities:
code_shaidentifies the repository commit.scopeplussource_sha256identifies the exact owner-defined input set, including relevant configuration, submodules, data, or dirty-tree state.
The orchestrator computes each current scope digest and passes it to the evaluator. This keeps Git, CI, simulator, data, and hardware orchestration outside the ledger module while preventing results from being combined across different inputs.
Benchmarks additionally record the command, exit code, environment, configuration and artifact digests, failure class, and resource metrics.
Local producer policy
Executable authority is separate from capability status:
docs/data/capabilities.tomlowns lane metadata, target levels, blockers, and non-executable producer IDs.docs/data/capability_producers.tomlowns exact argv, working directory, evidence kind, source roots, benchmark configuration roots, timeout, and maximum evidence age.
The collector accepts a producer ID, not a caller-selected command, level,
scope, source list, or exit code. It derives the checked-out Git HEAD,
hashes the policy-declared scope, executes argv without a shell, captures the
real result and logs, then re-hashes the scope. A source mutation, launch
failure, timeout, nonzero exit, policy mismatch, future date, or expired record
cannot promote a lane.
Producer kind is required and digest-bound. Execution producers cannot declare benchmark configuration inputs. Benchmark producers must declare a sorted, unique configuration-source subset of their source scope, and external record kind must exactly match that policy.
Each record binds the selected producer digest and the complete policy-file
digest. Each report binds those digests again alongside the ledger digest.
Every retained execution record has the exact attestation
local-unattested. Its digests detect mutation and identity mismatch; they do
not authenticate who ran it or authorize CI, merge, release, or readiness
acceptance.
Local evidence runs
The executable scripts/capability_gates/run_local.bash runner invokes the
three approved local end-to-end producers: python-unit-build,
terrain-minimal, and python-packaging. It keeps each lane’s logs and
record, runs later lanes after an earlier lane fails, and generates one report
from the records that exist. A nonzero gate or report result makes the runner
nonzero. Each producer retains its behavior gate and then:
- loads its local producer policy and computes the declared source scope;
- executes the exact gate argv and captures stdout, stderr, timing, and the actual return code;
- writes a content-addressed,
local-unattestedunit_verifiedexecution record even when the gate fails; - re-hashes that scope and evaluates the canonical ledger with the record;
- requires the lane to reach
unit_verified; - retains logs, evidence, and the report locally before propagating gate or report failure.
The Python record covers its audit, strict typing, unit, terrain-unit, and
ownership gates. The terrain-minimal record covers the explicit no-SciPy
assertion and core-only face-budget bake. The packaging record covers uv build --offline --no-python-downloads --wheel --sdist --python <selected-host-python>, producing the wheel and source-distribution gate
without sync or download. SRB_PYTHON, when set, selects that interpreter;
otherwise the gate resolves python3. The explicit build interpreter prevents
implicit selection of an inaccessible project .venv, and the same host
interpreter creates the disposable validation venv. Artifacts are written
beside the evidence under ignored outputs/ storage, never dist/. The record
carries a canonical environment string, a configuration digest over
pyproject.toml, uv.lock, and the packaging gate, and an artifact digest over
a sorted path/size/SHA-256 manifest. It also records finite, nonnegative wall
seconds and artifact bytes. After requiring exactly one wheel and one sdist,
the gate creates a trap-cleaned disposable venv outside the artifact directory,
installs that wheel with offline/no-dependency controls and an explicit venv
interpreter, then verifies the installed srb distribution metadata and
import srb. The venv is never part of the artifact manifest. Their evidence
is retained per lane, then evaluated together by the local report; local
records cannot promote another lane or any higher level.
A nominally successful packaging command with missing, empty, unreadable, or
non-regular artifacts is retained as a failed benchmark with stable exit code
87 and an artifact-specific failure class. Command failures, timeouts, and
source changes also retain schema-valid benchmark records without promotion.
A passing schema-v3, local-unattested packaging benchmark has been retained
after the interpreter-selection repair. It is scoped local evidence only: the
aggregate evaluator still enforces source freshness and every higher-level
blocker. A passing standalone report can promote only this local capability;
it is not P2, CI, merge, release, or readiness acceptance by itself.
If a scoped source is mutated during a gate, the record uses exit code 86.
If a source is deleted or becomes unreadable before the post-run scope can be
recomputed, the collector still writes the schema-valid pre-run record with
source_changed_during_gate, exit code 86, and concise scope-error metadata.
Pre-run scope failures remain fail-closed and produce no evidence record.
The checked-in ledger remains conservative without that external record. Local records cannot promote a different commit or changed source scope. They remain unattested and cannot represent hosted acceptance. GitHub, scheduled, self-hosted, Rust/ROS, network, Isaac/GPU, SPICE, selected-real-data, and hardware attestation is deferred until the repository is public and an authenticated producer contract is approved.
Evaluation seam
srb.core.capability_ledger.evaluate_capability_ledger is the only public
evaluation seam:
from srb.core.capability_ledger import evaluate_capability_ledger
report = evaluate_capability_ledger(
current_code_sha=commit_sha,
current_source_digests={
"python-ci": python_ci_scope_sha256,
"terrain-data": terrain_data_scope_sha256,
},
evidence_paths=[python_ci_evidence_path],
)
The evaluator performs no tests or benchmarks. It validates the ledger, checks source hashes, rejects stale or expired execution evidence, enforces contiguous promotion, and returns frozen dataclasses.
Each report carries:
- the exact ledger SHA-256 digest;
- the local producer-policy path and SHA-256 digest;
- the exact
local-unattestedattestation; - the current commit and sorted source-scope digests;
- the canonical digests of all external evidence records;
- the exact required capability levels asserted by the report producer;
- per-lane effective levels, blockers, and machine-readable issues;
- a deterministic
report_sha256over the complete report payload.
Persist the JSON from report.to_json() as local engineering evidence. Its
checksum provides integrity, not authentication. A report with zero issues is
not CI, merge, release, or readiness acceptance, and it cannot by itself
authorize any of those decisions.