agent-evidence-vectors v0.37.0

Predicate type: Evaluation claim

Type URI: https://probityai.github.io/agent-evidence-vectors/predicate/v1/evaluation-claim

Status: v1. The field set below is fixed for v1. A change that adds a required field, renames one or changes a type is published as v2 at a new URI, and this page stays.

Purpose

An evaluation claim says how an implementation fared against a case set: a conformance run, a benchmark, an agent evaluation. The usual record of such a run carries a count of passes and failures. A count cannot say which cases were expected, which never ran, who observed the run, which bytes were tested, or whether an action the run took is still open. Each of those gaps is read as clean by a consumer that only sees the count.

This record removes the gaps by construction. It is one envelope in which every coordinate a relying party needs is present, and each coordinate carries either a value or not_applicable under a reason a profile authorises. A coordinate the producer does not know is carried as unknown, unresolved or failed, and a record carrying one is refused. Silence is not a state the record can express.

Envelope

The record is a JSON object. It may be carried bare or as the predicate of an in-toto Statement v1 whose predicateType is the type URI above. In a Statement, the single subject names the implementation under test by sha256 digest, and that digest must equal the bytes.implementation digest in the record. A Statement is signed in a DSSE envelope like any other in-toto Statement; this page defines the predicate only.

Members are parsed as strict JSON: a duplicate member name, a float, NaN or Infinity makes the record malformed. Digests of documents are sha256 over their RFC 8785 (JCS) bytes, written sha256:<64 lowercase hex>.

{
  "claim_type": "https://probityai.github.io/agent-evidence-vectors/predicate/v1/evaluation-claim",
  "profile": {"id": "conformance/v1", "digest": "sha256:..."},
  "verdict": "pass",
  "coordinates": {
    "applicability": {"state": "value", "case_set": {"name": "...", "digest": "sha256:..."},
                      "applicable": ["c1", "c2"], "excluded": []},
    "population": {"state": "value", "coverage_denominator": 2,
                   "passed": ["c1", "c2"], "failed": [], "not_run": []},
    "vantage": {"state": "value", "observation_vantage": "substrate", "observer": "ci-runner"},
    "bytes": {"state": "value", "implementation": {"name": "...", "digest": "sha256:..."},
              "case_set": {"name": "...", "digest": "sha256:..."},
              "verifier": {"name": "...", "digest": "sha256:..."}},
    "epoch": {"state": "not_applicable", "reason": "no_authority_exercised"},
    "settlement": {"state": "not_applicable", "reason": "no_side_effecting_actions"}
  }
}

The record carries exactly claim_type, profile, verdict and coordinates. verdict is pass, fail or incomplete. coordinates holds only the coordinates defined below; an undefined one makes the record malformed.

Coordinates

Every coordinate is an object with a state: value, not_applicable, unknown, unresolved or failed. A not_applicable coordinate carries exactly state and reason. A value coordinate carries the members below.

Coordinate Question it answers Members when value
applicability Which cases of a pinned case set apply? case_set (reference), applicable (ids), excluded (each {id, reason})
population Over what denominator, and what happened to each case? coverage_denominator, passed, failed, not_run
vantage Who observed, and could the observed party shape it? observation_vantage (substrate or artifact), observer
bytes Which exact bytes does the claim bind? implementation, case_set, verifier (references); optional related (list of references)
epoch Under which authority state did the run act? initial (epoch id), transitions (each {after_action, from, to, kind})
settlement Is each side-effecting action resolved? actions (each {id, epoch, outcome, evidence?}), outcome is committed, not_run or unresolved

observation_vantage has the meaning the agent-evidence vocabulary gives it: substrate means every input was obtained where the executed party could neither forge nor suppress it; artifact means the claim rests on artifacts the executed party could have influenced.

A transition kind is one of revocation, suspension, consumption, root_change, restart, re_registration and fork. A transition takes effect after the action it names, so that action is judged under the epoch the transition ends, and every later action under the epoch it starts.

A reference is an object with any of name, alias, uri and digest. Only digest identifies bytes. A name or alias locates bytes and never replaces a digest; a digest of a superseded revision still identifies that revision.

Profiles and the acceptance rule

A profile (aev-claim-profile/v1) states, for one kind of evaluation, which coordinates may be not_applicable and under which reason tokens, which references must be bound by digest (immutable_references), and which reasons may exclude an optional case (exclusion_reasons). A profile lists every coordinate. A profile that authorises an absence (unknown, unresolved, failed, not_run, not_captured, unavailable, missing, skipped, timeout) as a reason for non-applicability is unusable.

An acceptance rule (aev-claim-acceptance-rule/v1) is the relying party's document. It pins the profile by id and digest, lists the case-set digests it accepts and the vantages it accepts. The rule is never taken from the record. A record names its profile so that a mismatch is visible; the rule's profile is the one the record is judged under. A producer therefore cannot satisfy a rule that requires the execution profile by naming the conformance profile.

The published profiles are conformance/v1 (epoch and settlement may be not applicable under no_authority_exercised and no_side_effecting_actions) and execution/v1 (no coordinate may be not applicable, and settlement evidence is bound by digest). They ship in the package under claim_record/corpus/profiles/.

Profiles and case sets are resolved by digest from bytes the verifier is given, offline. The verifier re-hashes what it resolves, so a store keyed under the wrong digest resolves nothing.

Verdict rules

Applicable and excluded together are the case set's ids, each once; only an optional case may be excluded, and only under a reason the profile authorises. Passed, failed and not run together are the applicable ids, each once, and the denominator counts them.

Refusal reasons

A verifier reports every reason it finds. A record is admitted when it finds none.

Code Meaning
MALFORMED_RECORD The record or Statement is not the shape above.
PROFILE_UNRESOLVED The pinned profile's bytes were not supplied, do not hash to the pin, or the profile is unusable. Nothing else is judged.
PROFILE_MISMATCH The record names a profile other than the one the rule pins.
MISSING_COORDINATE A coordinate is absent.
UNRESOLVED_COORDINATE A coordinate is unknown, unresolved or failed.
UNAUTHORISED_NOT_APPLICABLE not_applicable where the pinned profile allows no such reason, or epoch not applicable while actions were taken.
INVALID_REFERENTIAL_PIN A reference the profile requires to be immutable is bound by a name, alias or URI only, or by a malformed digest. References outside the profile's list are not held to this.
CASE_SET_NOT_ACCEPTED The rule does not accept the case set the record binds.
CASE_SET_UNRESOLVED The rule accepts the case set, and its bytes were not supplied.
APPLICABILITY_MISMATCH Applicable and excluded are not the case set exactly, or a required case or an unlisted reason is excluded.
POPULATION_MISMATCH A case is missing from the results, listed twice or not in the case set, or the denominator is wrong.
ABSENCE_READ_AS_CLEAN The verdict is pass while a case is not run, or while nothing applied.
VERDICT_CONTRADICTED The verdict is pass with a failure, fail with none, or incomplete with nothing missing or with a failure.
VANTAGE_NOT_ACCEPTED The rule does not accept the record's vantage.
BYTES_MISMATCH The bytes coordinate binds another case set than applicability resolved, or another implementation than the Statement subject.
STALE_EPOCH An action acts under an epoch a transition already ended.
UNSETTLED_OUTCOME An action is unresolved, or says committed or not run with no evidence.
UNSETTLED_ACROSS_EPOCH An unresolved action is followed by an authority transition.

The codes are identifiers. A consumer may match on them, and they do not change within v1.

Relation to the in-toto Test Result predicate

The in-toto Test Result predicate (https://in-toto.io/attestation/test-result/v0.1) names its first use case as verifying that all tests were in fact run, and carries passedTests, warnedTests and failedTests. It carries no expected set and no list of tests that did not run, so a record that omits a test reads as clean. The population and applicability coordinates are the two members such a record needs: an expected case set bound by digest, and a not_run list, with the verdict rules above. The reference verifier here judges both, with adversarial cases for an empty suite, a missing case, a duplicate and an unexpected case.

Verify, emit and replay

pip install agent-evidence-vectors
agent-evidence-vectors claim verify --record claim.json --rule rule.json --case-set cases.json
agent-evidence-vectors claim emit --case-set cases.json --results results.json \
  --implementation-name impl --implementation-digest sha256:<hex> \
  --verifier-name verifier --verifier-digest sha256:<hex> \
  --observation-vantage substrate --observer ci --statement --output claim.json
agent-evidence-vectors claim run --output claim-record-result

verify exits 0 when the record is admitted with verdict pass, 3 when it is admitted with fail or incomplete, 1 when it is refused and 2 on unusable input. emit records every case the results do not name as not run. The conformance corpus and its cases are described in the corpus README.

Record format: draft-gilda-audit-agent-audit-record-03, Section 4 (an in-toto Statement carried in a DSSE envelope).