diff --git a/docs/tutorials/verifying-the-audit-chain.md b/docs/tutorials/verifying-the-audit-chain.md index 5fe7ba29..95a7b4a4 100644 --- a/docs/tutorials/verifying-the-audit-chain.md +++ b/docs/tutorials/verifying-the-audit-chain.md @@ -144,7 +144,7 @@ if call_count is not None and len(calls) != call_count: For high-assurance scenarios, individual calls may carry external execution receipts: signed by a third-party (the caller, an orchestrator, or a notary) rather than the agent that produced the Trust Record. -The spec (§3.3.1) defines the receipt structure: +The spec (§3.3.2) defines the receipt structure: | Field | Description | |---|---| diff --git a/docs/verification-outcome-statements.md b/docs/verification-outcome-statements.md index 2898cfa7..de329d72 100644 --- a/docs/verification-outcome-statements.md +++ b/docs/verification-outcome-statements.md @@ -24,7 +24,7 @@ The rows are representative, not exhaustive. Each row reads: the outcome a verif | Verification outcome | Supported bounded statement | Required non-claim | Evidence to retain | Follow-up | |---|---|---|---|---| -| **Verified at the required floor.** Signature binding verified, record fresh, `appraisal.status` is `affirming` (or `warning`), and `appraisal.provenance_depth_verified` meets the deployment profile floor. | This record was not altered after issuance, and the checks the verifier ran passed at the recorded depth, under the appraisal policy named in `appraisal.policy_ref`. ([§3.2.2](../spec/trace-v0.2.md), [What verification proves](verification.md#what-verification-proves)) | Not current trust in the signing key unless revocation was actually consulted ([LIMITATIONS](../LIMITATIONS.md): pure offline verification cannot prove non-revocation). Not that the bound policy achieves its intended outcome ([LIMITATIONS](../LIMITATIONS.md): policy correctness is a separate control). Not soundness of the model's behavior ([§2.4](../spec/trace-v0.2.md)). Not success of any physical or business outcome ([§3.3.2](../spec/trace-v0.2.md)). Not a general trust score for the subject. | The record itself; the trusted-key thumbprint used; the freshness bounds applied; if revocation was checked, the bundle identity and `valid_until` - reported as "verified against revocation bundle valid at T" ([§3.2.3](../spec/trace-v0.2.md)); the complete `appraisal`. | Re-verify before material reliance on an aging record; consult current revocation status at decision time; keep the `policy_ref` target resolvable for whatever retention the published statement promises. | +| **Verified at the required floor.** Signature binding verified, record fresh, `appraisal.status` is `affirming` (or `warning`), and `appraisal.provenance_depth_verified` meets the deployment profile floor. | This record was not altered after issuance, and the checks the verifier ran passed at the recorded depth, under the appraisal policy named in `appraisal.policy_ref`. ([§3.2.2](../spec/trace-v0.2.md), [What verification proves](verification.md#what-verification-proves)) | Not current trust in the signing key unless revocation was actually consulted ([LIMITATIONS](../LIMITATIONS.md): pure offline verification cannot prove non-revocation). Not that the bound policy achieves its intended outcome ([LIMITATIONS](../LIMITATIONS.md): policy correctness is a separate control). Not soundness of the model's behavior ([§2.4](../spec/trace-v0.2.md)). Not success of any physical or business outcome ([§3.3.3](../spec/trace-v0.2.md)). Not a general trust score for the subject. | The record itself; the trusted-key thumbprint used; the freshness bounds applied; if revocation was checked, the bundle identity and `valid_until` - reported as "verified against revocation bundle valid at T" ([§3.2.3](../spec/trace-v0.2.md)); the complete `appraisal`. | Re-verify before material reliance on an aging record; consult current revocation status at decision time; keep the `policy_ref` target resolvable for whatever retention the published statement promises. | | **Honestly downgraded, floor still met.** Evidence the claimed depth needs did not resolve; the verifier stopped lower and recorded the achieved depth in `appraisal.provenance_depth_verified`; nothing contradicted; the achieved depth still meets the configured floor. | Verification reached `builder` (for example); the deeper claim was left unverified because named evidence did not resolve; the unresolved evidence is identified. ([§3.3.1](../spec/trace-v0.2.md), [downgrade column of the depth table](verification.md#verifying-build-provenance-depth)) | The downgrade is not a defect in the record: "a record is not defective because someone else's transparency log is unreachable" ([verification.md](verification.md#verifying-build-provenance-depth)). Equally, nothing is assured at the unexecuted depth - unverified is not silently true ([what each stopping point leaves unknown](build-provenance-depth.md)). | `appraisal.provenance_depth_verified`; the evidence locations attempted and why each did not resolve; the configured floor; the final `appraisal`. | Retry resolution or obtain the evidence out-of-band; where the gap matters to the reader, state it explicitly instead of letting the affirming status carry the weight. | | **Resolved and contradicted.** Named evidence resolves and refutes the record - attestation subject mismatch, dependency publisher outside the trusted set, digest mismatch. The appraisal fails and is not downgraded to escape the contradiction; `appraisal.status` is `contraindicated`. | The named artifact resolves and contradicts this record's claim at the named depth; the appraisal failed, and the record is treated as untrusted. ([§3.3.1](../spec/trace-v0.2.md), [Step 5 status meanings](verification.md#step-5--appraise-the-claims)) | The statement covers the specific contradiction observed and nothing else: it does not extend to other fields or axes, and appraisal output does not identify which adversary class from [§2.2](../spec/trace-v0.2.md) caused the contradiction. | The contradicting artifacts themselves (attestation bytes, publisher attestations, issuer identities outside the trusted set), the comparisons performed, the final `appraisal`. | Treat as incident input; contact the issuer or operator; corrected records need re-issue, not re-reading. | | **Unresolvable below the floor.** Achieved `appraisal.provenance_depth_verified` sits below the deployment profile floor, so `appraisal.status` is `contraindicated` by the floor rule. Nothing resolved-and-contradicted. | Verification reached `surface`; this deployment's floor is `transitive`; the record is refused by the floor, with no contradicting evidence found. ([floor rule in §3.3.1](../spec/trace-v0.2.md)) | Unverifiable is not incriminating: "the strictness lives in the floor, not in a finding against the record" ([build provenance depth](build-provenance-depth.md#choosing-a-depth)). Do not report this as though evidence had contradicted the record - the depth vectors encode the two outcomes separately ([verification.md](verification.md#verifying-build-provenance-depth)), and reporting should keep them apart. | The attempted evidence locations and errors; the floor configuration; `appraisal.provenance_depth_verified`; `appraisal.status`. | Obtain the missing evidence, or let the rejection stand; record which of the two happened. | diff --git a/docs/verification.md b/docs/verification.md index 6705a2f5..e3fccf2e 100644 --- a/docs/verification.md +++ b/docs/verification.md @@ -272,7 +272,7 @@ For action receipts, a verifier should distinguish five common outcomes: | `receipt_valid_rejected` | The receipt is well-formed, trusted, bound to the call, and reports controller or policy rejection. This is valid negative evidence. | | `receipt_missing_required` | The profile required a receipt, but none was present for the consequential action. | | `receipt_invalid` | The receipt is present but fails signature, digest, freshness, ordering, or call-binding checks against a key the verifier holds. | -| `receipt_unverified` | The receipt names an issuer key the verifier has not pinned, and nothing else failed. Per section 3.3.1 of the spec this is unverified, not invalid: the receipt confers no trust and proves no wrongdoing, surfaced with an advisory rather than a failure. | +| `receipt_unverified` | The receipt names an issuer key the verifier has not pinned, and nothing else failed. Per section 3.3.2 of the spec this is unverified, not invalid: the receipt confers no trust and proves no wrongdoing, surfaced with an advisory rather than a failure. | The key boundary is that a valid rejection is not malformed evidence. It is evidence that the downstream authority declined the action. A valid acceptance diff --git a/examples/action-receipts/README.md b/examples/action-receipts/README.md index 57d33aaa..5f77e6f2 100644 --- a/examples/action-receipts/README.md +++ b/examples/action-receipts/README.md @@ -6,7 +6,7 @@ only: the JSON snippets are not TRACE Trust Records and are not validated by `schema/trace-claim.json`. The examples exercise the boundary from -[spec section 3.3.2](../../spec/trace-v0.2.md#332-action-receipts-for-embodied-workflows-informative): +[spec section 3.3.3](../../spec/trace-v0.2.md#333-action-receipts-for-embodied-workflows-informative): 1. session evidence verifies the Trust Record and committed transcript; 2. action issuance evidence verifies that a consequential action request was @@ -93,7 +93,7 @@ three operations: | `11-call-id-mismatch.json` | `receipt_invalid` | unknown | An authentic receipt bound to a different call. | | `12-session-id-mismatch.json` | `receipt_invalid` | unknown | An authentic receipt from a different session. | | `13-evidence-hash-mismatch.json` | `receipt_invalid` | unknown | The receipt is authentic but the detached evidence was swapped after signing. | -| `14-receipt-issuer-key-unknown.json` | `receipt_unverified` with advisory | unknown | The issuer key is not in the verifier's pinned set. Unverifiable is not invalid (spec §3.3.1): no trust is conferred and no forgery is proven, surfaced as an `issuer_key_unknown` advisory. | +| `14-receipt-issuer-key-unknown.json` | `receipt_unverified` with advisory | unknown | The issuer key is not in the verifier's pinned set. Unverifiable is not invalid (spec §3.3.2): no trust is conferred and no forgery is proven, surfaced as an `issuer_key_unknown` advisory. | | `15-receipt-from-future.json` | `receipt_invalid` | unknown | Issued after the verification time, so an upper bound on age never rejects it. | | `16-decision-not-in-enum.json` | `receipt_invalid` | unknown | An unrecognised decision verb, which must not read as accept or reject. | | `17-missing-receipt-explicit-null.json` | `receipt_missing_required` | unknown | The receipt supplied as an explicit `null`: 03's absence through a different door, misread by presence-checking implementations. | @@ -116,7 +116,7 @@ previously exercised. Every one was a check a conforming implementation could ha omitted entirely while passing this set. Two matter beyond tidiness: without `issuer_key_unknown` a receipt authenticates itself — a signature verifies against whatever key it names, and only the pinned set decides which keys the verifier can -check at all; per spec §3.3.1 the outcome is `receipt_unverified`, not +check at all; per spec §3.3.2 the outcome is `receipt_unverified`, not `receipt_invalid`, but a verifier that never consults its pinned set would report such a receipt as fully valid, which is what the vector distinguishes. Without `evidence_hash_mismatch` the signature covers a digest whose document may have been diff --git a/examples/action-receipts/conformance/gen_rule_coverage_vectors.py b/examples/action-receipts/conformance/gen_rule_coverage_vectors.py index 3e0c9739..37df48f3 100644 --- a/examples/action-receipts/conformance/gen_rule_coverage_vectors.py +++ b/examples/action-receipts/conformance/gen_rule_coverage_vectors.py @@ -195,7 +195,7 @@ def main() -> None: f["evidence"]["terminal_state"] = "rejected" # after the hash was taken fixtures.append(("13-evidence-hash-mismatch.json", f)) - # issuer_key_unknown — the one non-failure in this set. Spec section 3.3.1: a + # issuer_key_unknown — the one non-failure in this set. Spec section 3.3.2: a # receipt whose issuer key is unknown to the verifier is unverified, not invalid. # An unpinned key means the signature cannot be checked, which confers no trust and # proves no forgery, so the expected block is written by hand rather than through diff --git a/spec/trace-v0.2.md b/spec/trace-v0.2.md index 1baaf2dc..28ef6947 100644 --- a/spec/trace-v0.2.md +++ b/spec/trace-v0.2.md @@ -401,7 +401,7 @@ requirement, such as `required`, `optional`, or `none`, without folding action evidence into the supply-chain provenance axis. An action receipt profile can build on the external execution evidence rules in -section 3.3.1 by requiring the verifier to: +section 3.3.2 by requiring the verifier to: 1. recompute the receipt's action or evidence digest from the canonical action preimage; diff --git a/tests/test_action_receipt_fixtures.py b/tests/test_action_receipt_fixtures.py index 69ae9c0c..a6b0ce4f 100644 --- a/tests/test_action_receipt_fixtures.py +++ b/tests/test_action_receipt_fixtures.py @@ -147,7 +147,7 @@ def _evidence_hash_mismatch(f: dict[str, Any]) -> bool: def _issuer_key_unknown(f: dict[str, Any]) -> bool: - # Spec section 3.3.1: a receipt whose issuer key is unknown to the verifier is + # Spec section 3.3.2: a receipt whose issuer key is unknown to the verifier is # unverified, not invalid. An unpinned key is an inability to check, not # evidence of forgery, so this is an advisory rather than a failure; the # structural checks still run, and any of them failing is positive evidence