diff --git a/CHANGELOG.md b/CHANGELOG.md index c515b55..48bb3de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to this specification are documented here. The spec document follows [Semantic Versioning](https://semver.org/). Wire formats (Permit `v1`, `closure_v1`, `closure_v2`, chain entry `v1`) version independently and are not bumped by spec-document revisions. +## [1.4.1] — 2026-05-22 + +Promotes the Step 4 verifier adjudication corpus into the canonical public +verifier-claims corpus. Permit wire format `v1`, closure formats, chain entry +`v1`, claim registry `v0`, and pinned semantic artifacts are unchanged. + +- Add 17 Step 4 permit-claim corpus fixtures covering signed permit-decision negatives, signed permit-revocation negatives, and scope-faithful absence adjudication negatives/edges for post-revocation dispatch initiation. +- Record dependency verdicts for bridge-record and missing-artifact absence cases so the public corpus captures both the target permit claim result and the supporting scope-state/export-scope adjudication result. +- Keep doctrine language on scope-faithful absence adjudication and avoid native non-membership overclaims. + ## [1.4.0] — 2026-05-21 Adds Step 4 claim contracts for signed permit decisions, signed permit diff --git a/README.md b/README.md index dab2a44..4e57deb 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![License](https://img.shields.io/github/license/keelapi/keel-permit)](LICENSE) [![Latest release](https://img.shields.io/github/v/release/keelapi/keel-permit?label=release)](https://github.com/keelapi/keel-permit/releases) -![Spec version](https://img.shields.io/badge/spec-1.4.0-blue) +![Spec version](https://img.shields.io/badge/spec-1.4.1-blue) A pre-execution decision record for AI agent systems. A Permit records that an action was evaluated and decided, and, for dispatched allow executions, can be bound to the final provider or tool request. A Permit JSON object alone is not self-authenticating; verification is performed from signed export artifacts and the relevant public keys or key manifest. Those artifacts are verifiable without contacting the issuer when the verifier has the signed export artifacts and relevant public keys/key manifest. @@ -12,7 +12,7 @@ This repository contains the wire-format specification, JSON schemas, and verifi | | | |---|---| -| Spec document version | 1.4.0 | +| Spec document version | 1.4.1 | | Permit wire format | `v1` | | Closure record format | `closure_v1`, `closure_v2` | | Chain entry hash format | `v1` | diff --git a/scripts/build_step4_permit_claim_fixtures.mjs b/scripts/build_step4_permit_claim_fixtures.mjs index 478e40d..f83cce1 100644 --- a/scripts/build_step4_permit_claim_fixtures.mjs +++ b/scripts/build_step4_permit_claim_fixtures.mjs @@ -23,6 +23,8 @@ const EMPTY_TREE_HASH = "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934c const EXPORT_SEED = Buffer.alloc(32, 0x11); const CHECKPOINT_SEED = Buffer.alloc(32, 0x22); const PERMIT_BINDING_SEED = Buffer.alloc(32, 0x33); +const OTHER_PERMIT_BINDING_SEED = Buffer.alloc(32, 0x44); +const MISMATCHED_PROJECT_ID = "00000000-0000-0000-0000-000000000099"; const DECISION_FIXTURES = [ { @@ -45,9 +47,96 @@ const DECISION_FIXTURES = [ } ]; +const DECISION_NEGATIVE_FIXTURES = [ + { + id: "permit-decision-neg-bad-signature", + permitId: "10000000-0000-4000-8000-000000000101", + decision: "allow", + mutation: "bad_signature", + title: "Permit decision with invalid signature", + expectedVerdict: "disproved", + expectedReason: "PERMIT_DECISION_SIGNATURE_INVALID", + delta: "The binding signature is produced by an untrusted key while the canonical payload still names the trusted key." + }, + { + id: "permit-decision-neg-tampered-decision", + permitId: "10000000-0000-4000-8000-000000000102", + decision: "deny", + mutation: "tampered_decision", + title: "Permit decision with tampered canonical decision", + expectedVerdict: "disproved", + expectedReason: "PERMIT_DECISION_CANONICAL_HASH_MISMATCH", + delta: "The signed canonical payload decision is changed after the canonical hash and signature are produced." + }, + { + id: "permit-decision-neg-untrusted-key", + permitId: "10000000-0000-4000-8000-000000000103", + decision: "allow", + mutation: "untrusted_key", + title: "Permit decision signed by untrusted key", + expectedVerdict: "insufficient_evidence", + expectedReason: "PERMIT_DECISION_UNTRUSTED_KEY", + delta: "The binding is internally valid but names a permit-binding key absent from the public trust root." + }, + { + id: "permit-decision-neg-canonical-payload-mismatch", + permitId: "10000000-0000-4000-8000-000000000104", + decision: "allow", + expectedDecision: "deny", + mutation: "canonical_payload_mismatch", + title: "Permit decision canonical payload mismatch", + expectedVerdict: "disproved", + expectedReason: "PERMIT_DECISION_CANONICAL_PAYLOAD_MISMATCH", + delta: "The signed canonical payload is valid, but the requested decision evidence expects a different decision." + } +]; + const ABSENCE_PERMIT_ID = "20000000-0000-4000-8000-000000000001"; const ACTOR_ID = "30000000-0000-4000-8000-000000000001"; +const REVOKED_NEGATIVE_FIXTURES = [ + { + id: "permit-revoked-neg-bad-signature", + mutation: "bad_signature", + title: "Permit revocation with invalid signature", + expectedVerdict: "disproved", + expectedReason: "PERMIT_REVOKED_SIGNATURE_INVALID", + delta: "The revocation event signature is produced by a key outside the public permit-binding trust root." + }, + { + id: "permit-revoked-neg-project-mismatch", + mutation: "project_mismatch", + title: "Permit revocation project mismatch", + expectedVerdict: "disproved", + expectedReason: "PERMIT_REVOKED_PROJECT_ID_MISMATCH", + delta: "The export declares a different project scope than the signed revocation event." + }, + { + id: "permit-revoked-neg-effective-at-mismatch", + mutation: "effective_at_mismatch", + title: "Permit revocation effective_at mismatch", + expectedVerdict: "disproved", + expectedReason: "PERMIT_REVOKED_EFFECTIVE_AT_MISMATCH", + delta: "The signed revocation event uses an effective_at timestamp different from revoked_at, which v1 reserves for future scheduling semantics." + }, + { + id: "permit-revoked-neg-missing-field", + mutation: "missing_field", + title: "Permit revocation missing required field", + expectedVerdict: "insufficient_evidence", + expectedReason: "PERMIT_REVOKED_EVIDENCE_MISSING", + delta: "The required reason_code field is removed from the signed revocation event evidence." + }, + { + id: "permit-revoked-neg-actor-pii-detected", + mutation: "actor_pii", + title: "Permit revocation actor identity contains PII", + expectedVerdict: "disproved", + expectedReason: "PERMIT_REVOKED_ACTOR_PII_DETECTED", + delta: "The signed actor_id uses an email-address shape instead of an opaque UUID." + } +]; + const SUPPORTED_PREDICATE_KINDS = [ "project_id", "permit_id", @@ -65,6 +154,95 @@ const SUPPORTED_PREDICATE_KINDS = [ "export_type" ]; +const ABSENCE_PROMOTED_FIXTURES = [ + { + id: "dispatch-absence-after-revocation-neg-post-revocation-dispatch-present", + title: "Post-revocation dispatch initiation disproves absence", + postRevocationDisclosureAt: "2026-05-21T10:06:00.000000Z", + expectedVerdict: "disproved", + expectedReason: "EXPORT_SCOPE_POST_REVOCATION_DISPATCH_PRESENT", + negative: { + parent_fixture: "dispatch-absence-after-revocation-valid-empty-scope", + delta: "Adds a disclosed dispatch.egress_bound record inside the post-revocation occurred_at range." + } + }, + { + id: "dispatch-absence-after-revocation-neg-bridge-record-matches-predicate", + title: "Bridge record matching dispatch predicate disproves absence", + postRevocationBridgeAt: "2026-05-21T10:06:00.000000Z", + expectedScopeVerdict: "disproved", + expectedVerdict: "disproved", + expectedReason: "EXPORT_SCOPE_BRIDGE_RECORD_MATCHES_PREDICATE", + negative: { + parent_fixture: "dispatch-absence-after-revocation-valid-empty-scope", + delta: "Places a post-revocation dispatch.egress_bound record in proof_bridge_records even though it satisfies the declared absence predicate." + } + }, + { + id: "dispatch-absence-after-revocation-neg-predicate-out-of-grammar", + title: "Absence predicate outside permit v1 grammar", + predicateMutator: (predicate) => { + predicate.equals.provider = "openai"; + }, + expectedVerdict: "unverifiable_scope", + expectedReason: "EXPORT_SCOPE_PREDICATE_OUT_OF_GRAMMAR", + negative: { + parent_fixture: "dispatch-absence-after-revocation-valid-empty-scope", + delta: "Adds a scope-predicate v1-valid provider equality that is outside the stricter permit absence predicate grammar." + } + }, + { + id: "dispatch-absence-after-revocation-neg-missing-checkpoint", + title: "Missing checkpoint prevents absence adjudication", + writeCheckpoint: false, + expectedCheckpointVerdict: "insufficient_evidence", + expectedScopeVerdict: "insufficient_evidence", + expectedVerdict: "insufficient_evidence", + expectedReason: "CHECKPOINT_SCOPE_STATE_CHECKPOINT_MISSING", + negative: { + parent_fixture: "dispatch-absence-after-revocation-valid-empty-scope", + delta: "Omits the checkpoint artifact referenced by the scope-faithful absence segment." + } + }, + { + id: "dispatch-absence-after-revocation-neg-missing-sidecar", + title: "Missing scope-state sidecar prevents absence adjudication", + writeSidecar: false, + expectedCheckpointVerdict: "insufficient_evidence", + expectedScopeVerdict: "insufficient_evidence", + expectedVerdict: "insufficient_evidence", + expectedReason: "CHECKPOINT_SCOPE_STATE_MISSING", + negative: { + parent_fixture: "dispatch-absence-after-revocation-valid-empty-scope", + delta: "Omits the checkpoint scope-state sidecar referenced by the scope-faithful absence segment." + } + }, + { + id: "dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported", + title: "Pre-revocation dispatch does not disprove post-revocation absence", + includePreRevocationDispatch: true, + expectedVerdict: "supported", + expectedReason: "PERMIT_DISPATCH_ABSENCE_AFTER_REVOCATION_SUPPORTED" + }, + { + id: "dispatch-absence-after-revocation-edge-empty-scope-supported", + title: "Empty post-revocation dispatch scope is supported", + expectedVerdict: "supported", + expectedReason: "PERMIT_DISPATCH_ABSENCE_AFTER_REVOCATION_SUPPORTED" + }, + { + id: "dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at", + title: "Dispatch at revocation effective_at disproves absence", + postRevocationDisclosureAt: REVOCATION_TIME, + expectedVerdict: "disproved", + expectedReason: "EXPORT_SCOPE_POST_REVOCATION_DISPATCH_PRESENT", + negative: { + parent_fixture: "dispatch-absence-after-revocation-valid-empty-scope", + delta: "Adds a disclosed dispatch.egress_bound record whose occurred_at equals the revocation effective_at lower bound." + } + } +]; + function sortDeep(value) { if (Array.isArray(value)) { return value.map(sortDeep); @@ -92,6 +270,10 @@ function writeJson(filePath, value) { fs.writeFileSync(filePath, prettyJson(value), "utf8"); } +function resetFixtureDir(fixtureId) { + fs.rmSync(path.join(FIXTURE_ROOT, fixtureId), { recursive: true, force: true }); +} + function writeText(filePath, value) { fs.mkdirSync(path.dirname(filePath), { recursive: true }); fs.writeFileSync(filePath, value, "utf8"); @@ -101,6 +283,10 @@ function sha256Hex(input) { return crypto.createHash("sha256").update(input).digest("hex"); } +function sha256Bytes(input) { + return crypto.createHash("sha256").update(input).digest(); +} + function sha256Prefixed(input) { return `sha256:${sha256Hex(input)}`; } @@ -229,7 +415,10 @@ function buildTrustRoot() { }); } -function decisionCanonicalPayload(spec) { +function decisionCanonicalPayload( + spec, + { bindingKeyId = runtimeKeyId(ed25519PrivateKey(PERMIT_BINDING_SEED)) } = {} +) { return { binding_version: "v1", permit_id: spec.permitId, @@ -262,43 +451,55 @@ function decisionCanonicalPayload(spec) { issued_at: SIGNED_AT, expires_at: "2026-05-21T11:00:00.000000Z", is_dry_run: false, - binding_key_id: runtimeKeyId(ed25519PrivateKey(PERMIT_BINDING_SEED)), + binding_key_id: bindingKeyId, final_request_hash: null }; } -function decisionEvidence(spec) { - const permitKey = ed25519PrivateKey(PERMIT_BINDING_SEED); - const payload = decisionCanonicalPayload(spec); +function decisionEvidence( + spec, + { privateKey = ed25519PrivateKey(PERMIT_BINDING_SEED) } = {} +) { + const payload = decisionCanonicalPayload(spec, { + bindingKeyId: runtimeKeyId(privateKey) + }); const hash = sha256Hex(canonicalJson(payload)); return { artifact_type: "permit_decision_binding", artifact_version: "permit.decision.v1", canonical_payload: payload, binding_canonical_hash: hash, - binding_signature: signEd25519(permitKey, hash), - binding_key_id: runtimeKeyId(permitKey), + binding_signature: signEd25519(privateKey, hash), + binding_key_id: runtimeKeyId(privateKey), binding_issued_at: SIGNED_AT, expected_decision: spec.decision }; } -function revokedEvent({ permitId = ABSENCE_PERMIT_ID, projectId = PROJECT_ID } = {}) { - const permitKey = ed25519PrivateKey(PERMIT_BINDING_SEED); +function revokedEvent({ + permitId = ABSENCE_PERMIT_ID, + projectId = PROJECT_ID, + actorId = ACTOR_ID, + actorKind = "user", + reasonCode = "operator.requested", + revokedAt = REVOCATION_TIME, + effectiveAt = REVOCATION_TIME, + privateKey = ed25519PrivateKey(PERMIT_BINDING_SEED) +} = {}) { const payload = { permit_id: permitId, project_id: projectId, - actor_id: ACTOR_ID, - actor_kind: "user", - reason_code: "operator.requested", - revoked_at: REVOCATION_TIME, - effective_at: REVOCATION_TIME + actor_id: actorId, + actor_kind: actorKind, + reason_code: reasonCode, + revoked_at: revokedAt, + effective_at: effectiveAt }; const hash = sha256Hex(canonicalJson(payload)); return { event: { ...payload, - signature: signB64(permitKey, hash) + signature: signB64(privateKey, hash) }, canonical_hash: hash }; @@ -333,6 +534,7 @@ function writeReadme(fixtureId, title, body) { } function writeDecisionFixture(spec) { + resetFixtureDir(spec.id); const fixtureDir = path.join(FIXTURE_ROOT, spec.id); const evidence = decisionEvidence(spec); const exportPayload = { @@ -364,6 +566,73 @@ function writeDecisionFixture(spec) { }); } +function writeDecisionNegativeFixture(spec) { + resetFixtureDir(spec.id); + const fixtureDir = path.join(FIXTURE_ROOT, spec.id); + const otherPermitKey = ed25519PrivateKey(OTHER_PERMIT_BINDING_SEED); + let evidence = decisionEvidence({ + id: spec.id, + permitId: spec.permitId, + decision: spec.decision + }); + + if (spec.mutation === "bad_signature") { + evidence.binding_signature = signEd25519(otherPermitKey, evidence.binding_canonical_hash); + } else if (spec.mutation === "tampered_decision") { + evidence.canonical_payload.decision = "allow"; + } else if (spec.mutation === "untrusted_key") { + evidence = decisionEvidence( + { + id: spec.id, + permitId: spec.permitId, + decision: spec.decision + }, + { privateKey: otherPermitKey } + ); + } else if (spec.mutation === "canonical_payload_mismatch") { + evidence.expected_decision = spec.expectedDecision; + } else { + throw new Error(`unknown decision mutation: ${spec.mutation}`); + } + + const exportPayload = { + schema: "keel.step4.permit_claim_fixture/v1", + fixture_id: spec.id, + project_id: PROJECT_ID, + permit_decision: evidence + }; + const manifest = buildManifest({ + fixtureId: spec.id, + exportPayload, + claims: ["permit.decision.v1"], + artifacts: [SEMANTICS.permitDecision], + recordCount: 1 + }); + writeJson(path.join(fixtureDir, "pack", "export.json"), exportPayload); + writeJson(path.join(fixtureDir, "pack", "manifest.json"), manifest); + writeReadme( + spec.id, + spec.title, + `## What It Tests\n\nThe pack mutates a signed issuance-time permit decision binding: ${spec.delta}\n\n## Expected Verdict\n\n\`permit.decision.v1\` is expected to return \`${spec.expectedVerdict}\` with \`${spec.expectedReason}\`.` + ); + return corpusExportRecord({ + id: spec.id, + title: spec.title, + claims: [ + "export.integrity.v1", + { name: "permit.decision.v1", expected_verdict: spec.expectedVerdict } + ], + features: ["step4_permit_claims"], + extraPack: {}, + expectedOutcome: "FAIL", + reasonClasses: [spec.expectedReason], + negative: { + parent_fixture: "permit-decision-allow-valid", + delta: spec.delta + } + }); +} + function recordHashV1(entry) { const timestamp = String(entry.created_at).replace(/Z$/, ""); const parts = [ @@ -402,7 +671,11 @@ function chainEntry({ eventId, eventType, sequenceNumber, prevHash, occurredAt, return entry; } -function buildAbsenceChain({ includePreRevocationDispatch }) { +function buildAbsenceChain({ + includePreRevocationDispatch, + postRevocationDisclosureAt = null, + postRevocationBridgeAt = null +}) { const entries = []; let prev = GENESIS_PREV_HASH; let sequence = 1; @@ -443,6 +716,28 @@ function buildAbsenceChain({ includePreRevocationDispatch }) { } }); entries.push(revoked); + prev = revoked.record_hash; + sequence += 1; + if (postRevocationDisclosureAt !== null || postRevocationBridgeAt !== null) { + const occurredAt = postRevocationDisclosureAt || postRevocationBridgeAt; + const dispatch = chainEntry({ + eventId: postRevocationDisclosureAt !== null + ? "evt_step4_post_revocation_dispatch_disclosed" + : "evt_step4_post_revocation_dispatch_bridge", + eventType: "dispatch.egress_bound", + sequenceNumber: sequence, + prevHash: prev, + occurredAt, + payloadJson: { + project_id: PROJECT_ID, + permit_id: ABSENCE_PERMIT_ID, + event_type: "dispatch.egress_bound", + occurred_at: occurredAt, + dispatch_request_digest_v1: sha256Hex(`${occurredAt}:post-revocation-dispatch`) + } + }); + entries.push(dispatch); + } return { entries, revocation }; } @@ -499,9 +794,47 @@ function absencePredicate() { }; } -function buildSidecar({ entries, predicate }) { +function merkleRoot(disclosureRecords, predicateValueHash) { + if (!disclosureRecords.length) { + return EMPTY_TREE_HASH; + } + const leaves = [...disclosureRecords] + .sort((a, b) => { + const seq = a.sequence_number - b.sequence_number; + if (seq !== 0) return seq; + const eventCmp = String(a.event_id).localeCompare(String(b.event_id)); + if (eventCmp !== 0) return eventCmp; + return String(a.record_hash).localeCompare(String(b.record_hash)); + }) + .map((record) => { + const leafObject = { + canonical_predicate_value_hash: predicateValueHash, + event_id: record.event_id, + record_hash: record.record_hash, + sequence_number: record.sequence_number + }; + return sha256Bytes(Buffer.concat([Buffer.from([0]), Buffer.from(canonicalJson(leafObject), "utf8")])); + }); + + function merkleHash(nodes) { + if (nodes.length === 1) { + return nodes[0]; + } + const split = 1 << (Math.ceil(Math.log2(nodes.length)) - 1); + const left = merkleHash(nodes.slice(0, split)); + const right = merkleHash(nodes.slice(split)); + return sha256Bytes(Buffer.concat([Buffer.from([1]), left, right])); + } + + return `sha256:${merkleHash(leaves).toString("hex")}`; +} + +function buildSidecar({ entries, predicate, disclosures }) { const checkpointKey = ed25519PrivateKey(CHECKPOINT_SEED); const predicateHash = sha256Prefixed(Buffer.from(canonicalJson(predicate), "utf8")); + const sequences = disclosures.map((record) => record.sequence_number); + const firstMatching = sequences.length ? Math.min(...sequences) : null; + const lastMatching = sequences.length ? Math.max(...sequences) : null; const sidecar = { artifact_type: "checkpoint_scope_state", version: "checkpoint_scope_state.v1", @@ -519,10 +852,10 @@ function buildSidecar({ entries, predicate }) { { predicate_value: predicate, predicate_value_hash: predicateHash, - first_matching_sequence: null, - last_matching_sequence: null, - matching_count: 0, - membership_root_hash: EMPTY_TREE_HASH + first_matching_sequence: firstMatching, + last_matching_sequence: lastMatching, + matching_count: disclosures.length, + membership_root_hash: merkleRoot(disclosures, predicateHash) } ], tree_size: entries.at(-1).sequence_number, @@ -544,14 +877,40 @@ function buildSidecar({ entries, predicate }) { return sidecar; } -function buildAbsenceFixture({ id, title, includePreRevocationDispatch }) { - const { entries, revocation } = buildAbsenceChain({ includePreRevocationDispatch }); +function buildAbsenceFixture({ + id, + title, + includePreRevocationDispatch, + postRevocationDisclosureAt = null, + postRevocationBridgeAt = null, + predicateMutator = null, + writeCheckpoint = true, + writeSidecar = true, + expectedCheckpointVerdict = "supported", + expectedScopeVerdict = "supported", + expectedVerdict = "supported", + expectedReason = "PERMIT_DISPATCH_ABSENCE_AFTER_REVOCATION_SUPPORTED", + negative = null +}) { + resetFixtureDir(id); + const { entries, revocation } = buildAbsenceChain({ + includePreRevocationDispatch, + postRevocationDisclosureAt, + postRevocationBridgeAt + }); const checkpoint = buildCheckpoint(entries); const predicate = absencePredicate(); - const sidecar = buildSidecar({ entries, predicate }); + if (predicateMutator !== null) { + predicateMutator(predicate); + } + const disclosures = entries.filter((entry) => + postRevocationDisclosureAt !== null && entry.event_type === "dispatch.egress_bound" && entry.occurred_at === postRevocationDisclosureAt + ); + const sidecar = buildSidecar({ entries, predicate, disclosures }); const sidecarBytes = Buffer.from(prettyJson(sidecar), "utf8"); const sidecarHash = sha256Prefixed(sidecarBytes); const filtersHash = sha256Prefixed(Buffer.from(canonicalJson(predicate), "utf8")); + const proofBridgeRecords = entries.filter((entry) => !disclosures.includes(entry)); const segment = { segment_id: id, @@ -595,8 +954,8 @@ function buildAbsenceFixture({ id, title, includePreRevocationDispatch }) { filters_hash: filtersHash }, chain_evidence: { - disclosure_records: [], - proof_bridge_records: entries + disclosure_records: disclosures, + proof_bridge_records: proofBridgeRecords } }; @@ -636,12 +995,16 @@ function buildAbsenceFixture({ id, title, includePreRevocationDispatch }) { const fixtureDir = path.join(FIXTURE_ROOT, id); writeJson(path.join(fixtureDir, "pack", "export.json"), exportPayload); writeJson(path.join(fixtureDir, "pack", "manifest.json"), manifest); - writeJson(path.join(fixtureDir, "pack", "checkpoint.json"), checkpoint); - writeJson(path.join(fixtureDir, "sidecars", "checkpoint-scope-state-v1.json"), sidecar); + if (writeCheckpoint) { + writeJson(path.join(fixtureDir, "pack", "checkpoint.json"), checkpoint); + } + if (writeSidecar) { + writeJson(path.join(fixtureDir, "sidecars", "checkpoint-scope-state-v1.json"), sidecar); + } writeReadme( id, title, - `## What It Tests\n\nThe pack contains supported revocation evidence and a scope-faithful absence adjudication segment whose post-revocation \`dispatch.egress_bound\` matching count is zero.${includePreRevocationDispatch ? " A pre-revocation `dispatch.egress_bound` record is supplied as bridge evidence and does not match the bounded `occurred_at` range." : ""}\n\n## Expected Verdict\n\n\`permit.dispatch_absence_after_revocation.v1\` is expected to return \`supported\`.` + `## What It Tests\n\nThe pack contains supported revocation evidence and a scope-faithful absence adjudication segment for post-revocation \`dispatch.egress_bound\` events.${includePreRevocationDispatch ? " A pre-revocation `dispatch.egress_bound` record is supplied as bridge evidence and does not match the bounded `occurred_at` range." : ""}\n\n## Expected Verdict\n\n\`permit.dispatch_absence_after_revocation.v1\` is expected to return \`${expectedVerdict}\` with \`${expectedReason}\`.` ); return corpusExportRecord({ id, @@ -649,20 +1012,33 @@ function buildAbsenceFixture({ id, title, includePreRevocationDispatch }) { claims: [ "export.integrity.v1", "permit.revoked.v1", - "checkpoint.scope_state.v1", - "export.scope_faithfulness.v1", - "permit.dispatch_absence_after_revocation.v1" + { + name: "checkpoint.scope_state.v1", + expected_verdict: expectedCheckpointVerdict + }, + { + name: "export.scope_faithfulness.v1", + expected_verdict: expectedScopeVerdict + }, + { + name: "permit.dispatch_absence_after_revocation.v1", + expected_verdict: expectedVerdict + } ], features: ["scope_faithfulness", "step4_permit_claims"], extraPack: { - checkpoint_file: `fixtures/${id}/pack/checkpoint.json`, - sidecar_file: `fixtures/${id}/sidecars/checkpoint-scope-state-v1.json` - } + ...(writeCheckpoint ? { checkpoint_file: `fixtures/${id}/pack/checkpoint.json` } : {}), + ...(writeSidecar ? { sidecar_file: `fixtures/${id}/sidecars/checkpoint-scope-state-v1.json` } : {}) + }, + expectedOutcome: expectedVerdict === "supported" ? "PASS" : "FAIL", + reasonClasses: expectedVerdict === "supported" ? [] : [expectedReason], + negative }); } function writeRevokedFixture() { const id = "permit-revoked-valid"; + resetFixtureDir(id); const title = "Valid signed permit revocation event"; const exportPayload = { schema: "keel.step4.permit_claim_fixture/v1", @@ -695,12 +1071,83 @@ function writeRevokedFixture() { }); } -function corpusExportRecord({ id, title, claims, features, extraPack }) { - return { - claims: claims.map((name) => ({ expected_verdict: "supported", name })), +function writeRevokedNegativeFixture(spec) { + resetFixtureDir(spec.id); + const fixtureDir = path.join(FIXTURE_ROOT, spec.id); + const otherPermitKey = ed25519PrivateKey(OTHER_PERMIT_BINDING_SEED); + let revocation = revokedEvent(); + let projectId = PROJECT_ID; + if (spec.mutation === "bad_signature") { + revocation = revokedEvent({ privateKey: otherPermitKey }); + } else if (spec.mutation === "project_mismatch") { + projectId = MISMATCHED_PROJECT_ID; + } else if (spec.mutation === "effective_at_mismatch") { + revocation = revokedEvent({ effectiveAt: "2026-05-21T10:06:00.000000Z" }); + } else if (spec.mutation === "missing_field") { + delete revocation.event.reason_code; + } else if (spec.mutation === "actor_pii") { + revocation = revokedEvent({ actorId: "operator@example.com" }); + } else { + throw new Error(`unknown revocation mutation: ${spec.mutation}`); + } + const exportPayload = { + schema: "keel.step4.permit_claim_fixture/v1", + fixture_id: spec.id, + project_id: projectId, + permit_id: ABSENCE_PERMIT_ID, + revocation_event: revocation + }; + const manifest = buildManifest({ + fixtureId: spec.id, + exportPayload, + claims: ["permit.revoked.v1"], + artifacts: [SEMANTICS.permitRevoked], + recordCount: 1 + }); + writeJson(path.join(fixtureDir, "pack", "export.json"), exportPayload); + writeJson(path.join(fixtureDir, "pack", "manifest.json"), manifest); + writeReadme( + spec.id, + spec.title, + `## What It Tests\n\nThe pack mutates signed \`permit.revoked\` evidence: ${spec.delta}\n\n## Expected Verdict\n\n\`permit.revoked.v1\` is expected to return \`${spec.expectedVerdict}\` with \`${spec.expectedReason}\`.` + ); + return corpusExportRecord({ + id: spec.id, + title: spec.title, + claims: [ + "export.integrity.v1", + { name: "permit.revoked.v1", expected_verdict: spec.expectedVerdict } + ], + features: ["step4_permit_claims"], + extraPack: {}, + expectedOutcome: "FAIL", + reasonClasses: [spec.expectedReason], + negative: { + parent_fixture: "permit-revoked-valid", + delta: spec.delta + } + }); +} + +function corpusExportRecord({ + id, + title, + claims, + features, + extraPack, + expectedOutcome = "PASS", + reasonClasses = [], + negative = null +}) { + const record = { + claims: claims.map((claim) => + typeof claim === "string" + ? { expected_verdict: "supported", name: claim } + : claim + ), expected_current: { - outcome: "PASS", - reason_classes: [] + outcome: expectedOutcome, + reason_classes: reasonClasses }, id, kind: "export", @@ -713,6 +1160,12 @@ function corpusExportRecord({ id, title, claims, features, extraPack }) { }, title }; + if (negative !== null) { + record.negative = negative; + } + return { + ...record + }; } function updateCorpus(records) { @@ -728,7 +1181,9 @@ function main() { buildTrustRoot(); const records = [ ...DECISION_FIXTURES.map(writeDecisionFixture), + ...DECISION_NEGATIVE_FIXTURES.map(writeDecisionNegativeFixture), writeRevokedFixture(), + ...REVOKED_NEGATIVE_FIXTURES.map(writeRevokedNegativeFixture), buildAbsenceFixture({ id: "dispatch-absence-after-revocation-valid-empty-scope", title: "Valid post-revocation dispatch absence with empty matching scope", @@ -738,7 +1193,15 @@ function main() { id: "dispatch-absence-after-revocation-valid-with-pre-revocation-dispatch", title: "Valid post-revocation dispatch absence with pre-revocation dispatch evidence", includePreRevocationDispatch: true - }) + }), + ...ABSENCE_PROMOTED_FIXTURES.map((fixture) => + buildAbsenceFixture({ + includePreRevocationDispatch: false, + writeCheckpoint: true, + writeSidecar: true, + ...fixture + }) + ) ]; updateCorpus(records); console.log(`Generated ${records.length} Step 4 permit-claim fixtures.`); diff --git a/test-vectors/verifier_claims/v0/corpus.json b/test-vectors/verifier_claims/v0/corpus.json index 108ef1a..ae089a7 100644 --- a/test-vectors/verifier_claims/v0/corpus.json +++ b/test-vectors/verifier_claims/v0/corpus.json @@ -2223,6 +2223,138 @@ }, "title": "Valid signed permit challenge decision" }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "disproved", + "name": "permit.decision.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "PERMIT_DECISION_SIGNATURE_INVALID" + ] + }, + "id": "permit-decision-neg-bad-signature", + "kind": "export", + "negative": { + "delta": "The binding signature is produced by an untrusted key while the canonical payload still names the trusted key.", + "parent_fixture": "permit-decision-allow-valid" + }, + "pack": { + "export_file": "fixtures/permit-decision-neg-bad-signature/pack/export.json", + "features": [ + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/permit-decision-neg-bad-signature/pack/manifest.json" + }, + "title": "Permit decision with invalid signature" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "disproved", + "name": "permit.decision.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "PERMIT_DECISION_CANONICAL_HASH_MISMATCH" + ] + }, + "id": "permit-decision-neg-tampered-decision", + "kind": "export", + "negative": { + "delta": "The signed canonical payload decision is changed after the canonical hash and signature are produced.", + "parent_fixture": "permit-decision-allow-valid" + }, + "pack": { + "export_file": "fixtures/permit-decision-neg-tampered-decision/pack/export.json", + "features": [ + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/permit-decision-neg-tampered-decision/pack/manifest.json" + }, + "title": "Permit decision with tampered canonical decision" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "insufficient_evidence", + "name": "permit.decision.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "PERMIT_DECISION_UNTRUSTED_KEY" + ] + }, + "id": "permit-decision-neg-untrusted-key", + "kind": "export", + "negative": { + "delta": "The binding is internally valid but names a permit-binding key absent from the public trust root.", + "parent_fixture": "permit-decision-allow-valid" + }, + "pack": { + "export_file": "fixtures/permit-decision-neg-untrusted-key/pack/export.json", + "features": [ + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/permit-decision-neg-untrusted-key/pack/manifest.json" + }, + "title": "Permit decision signed by untrusted key" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "disproved", + "name": "permit.decision.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "PERMIT_DECISION_CANONICAL_PAYLOAD_MISMATCH" + ] + }, + "id": "permit-decision-neg-canonical-payload-mismatch", + "kind": "export", + "negative": { + "delta": "The signed canonical payload is valid, but the requested decision evidence expects a different decision.", + "parent_fixture": "permit-decision-allow-valid" + }, + "pack": { + "export_file": "fixtures/permit-decision-neg-canonical-payload-mismatch/pack/export.json", + "features": [ + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/permit-decision-neg-canonical-payload-mismatch/pack/manifest.json" + }, + "title": "Permit decision canonical payload mismatch" + }, { "claims": [ { @@ -2250,6 +2382,171 @@ }, "title": "Valid signed permit revocation event" }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "disproved", + "name": "permit.revoked.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "PERMIT_REVOKED_SIGNATURE_INVALID" + ] + }, + "id": "permit-revoked-neg-bad-signature", + "kind": "export", + "negative": { + "delta": "The revocation event signature is produced by a key outside the public permit-binding trust root.", + "parent_fixture": "permit-revoked-valid" + }, + "pack": { + "export_file": "fixtures/permit-revoked-neg-bad-signature/pack/export.json", + "features": [ + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/permit-revoked-neg-bad-signature/pack/manifest.json" + }, + "title": "Permit revocation with invalid signature" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "disproved", + "name": "permit.revoked.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "PERMIT_REVOKED_PROJECT_ID_MISMATCH" + ] + }, + "id": "permit-revoked-neg-project-mismatch", + "kind": "export", + "negative": { + "delta": "The export declares a different project scope than the signed revocation event.", + "parent_fixture": "permit-revoked-valid" + }, + "pack": { + "export_file": "fixtures/permit-revoked-neg-project-mismatch/pack/export.json", + "features": [ + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/permit-revoked-neg-project-mismatch/pack/manifest.json" + }, + "title": "Permit revocation project mismatch" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "disproved", + "name": "permit.revoked.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "PERMIT_REVOKED_EFFECTIVE_AT_MISMATCH" + ] + }, + "id": "permit-revoked-neg-effective-at-mismatch", + "kind": "export", + "negative": { + "delta": "The signed revocation event uses an effective_at timestamp different from revoked_at, which v1 reserves for future scheduling semantics.", + "parent_fixture": "permit-revoked-valid" + }, + "pack": { + "export_file": "fixtures/permit-revoked-neg-effective-at-mismatch/pack/export.json", + "features": [ + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/permit-revoked-neg-effective-at-mismatch/pack/manifest.json" + }, + "title": "Permit revocation effective_at mismatch" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "insufficient_evidence", + "name": "permit.revoked.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "PERMIT_REVOKED_EVIDENCE_MISSING" + ] + }, + "id": "permit-revoked-neg-missing-field", + "kind": "export", + "negative": { + "delta": "The required reason_code field is removed from the signed revocation event evidence.", + "parent_fixture": "permit-revoked-valid" + }, + "pack": { + "export_file": "fixtures/permit-revoked-neg-missing-field/pack/export.json", + "features": [ + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/permit-revoked-neg-missing-field/pack/manifest.json" + }, + "title": "Permit revocation missing required field" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "disproved", + "name": "permit.revoked.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "PERMIT_REVOKED_ACTOR_PII_DETECTED" + ] + }, + "id": "permit-revoked-neg-actor-pii-detected", + "kind": "export", + "negative": { + "delta": "The signed actor_id uses an email-address shape instead of an opaque UUID.", + "parent_fixture": "permit-revoked-valid" + }, + "pack": { + "export_file": "fixtures/permit-revoked-neg-actor-pii-detected/pack/export.json", + "features": [ + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/permit-revoked-neg-actor-pii-detected/pack/manifest.json" + }, + "title": "Permit revocation actor identity contains PII" + }, { "claims": [ { @@ -2333,6 +2630,376 @@ "sidecar_file": "fixtures/dispatch-absence-after-revocation-valid-with-pre-revocation-dispatch/sidecars/checkpoint-scope-state-v1.json" }, "title": "Valid post-revocation dispatch absence with pre-revocation dispatch evidence" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "supported", + "name": "permit.revoked.v1" + }, + { + "expected_verdict": "supported", + "name": "checkpoint.scope_state.v1" + }, + { + "expected_verdict": "supported", + "name": "export.scope_faithfulness.v1" + }, + { + "expected_verdict": "disproved", + "name": "permit.dispatch_absence_after_revocation.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "EXPORT_SCOPE_POST_REVOCATION_DISPATCH_PRESENT" + ] + }, + "id": "dispatch-absence-after-revocation-neg-post-revocation-dispatch-present", + "kind": "export", + "negative": { + "delta": "Adds a disclosed dispatch.egress_bound record inside the post-revocation occurred_at range.", + "parent_fixture": "dispatch-absence-after-revocation-valid-empty-scope" + }, + "pack": { + "checkpoint_file": "fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/pack/checkpoint.json", + "export_file": "fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/pack/export.json", + "features": [ + "scope_faithfulness", + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/pack/manifest.json", + "sidecar_file": "fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/sidecars/checkpoint-scope-state-v1.json" + }, + "title": "Post-revocation dispatch initiation disproves absence" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "supported", + "name": "permit.revoked.v1" + }, + { + "expected_verdict": "supported", + "name": "checkpoint.scope_state.v1" + }, + { + "expected_verdict": "disproved", + "name": "export.scope_faithfulness.v1" + }, + { + "expected_verdict": "disproved", + "name": "permit.dispatch_absence_after_revocation.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "EXPORT_SCOPE_BRIDGE_RECORD_MATCHES_PREDICATE" + ] + }, + "id": "dispatch-absence-after-revocation-neg-bridge-record-matches-predicate", + "kind": "export", + "negative": { + "delta": "Places a post-revocation dispatch.egress_bound record in proof_bridge_records even though it satisfies the declared absence predicate.", + "parent_fixture": "dispatch-absence-after-revocation-valid-empty-scope" + }, + "pack": { + "checkpoint_file": "fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/pack/checkpoint.json", + "export_file": "fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/pack/export.json", + "features": [ + "scope_faithfulness", + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/pack/manifest.json", + "sidecar_file": "fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/sidecars/checkpoint-scope-state-v1.json" + }, + "title": "Bridge record matching dispatch predicate disproves absence" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "supported", + "name": "permit.revoked.v1" + }, + { + "expected_verdict": "supported", + "name": "checkpoint.scope_state.v1" + }, + { + "expected_verdict": "supported", + "name": "export.scope_faithfulness.v1" + }, + { + "expected_verdict": "unverifiable_scope", + "name": "permit.dispatch_absence_after_revocation.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "EXPORT_SCOPE_PREDICATE_OUT_OF_GRAMMAR" + ] + }, + "id": "dispatch-absence-after-revocation-neg-predicate-out-of-grammar", + "kind": "export", + "negative": { + "delta": "Adds a scope-predicate v1-valid provider equality that is outside the stricter permit absence predicate grammar.", + "parent_fixture": "dispatch-absence-after-revocation-valid-empty-scope" + }, + "pack": { + "checkpoint_file": "fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/pack/checkpoint.json", + "export_file": "fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/pack/export.json", + "features": [ + "scope_faithfulness", + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/pack/manifest.json", + "sidecar_file": "fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/sidecars/checkpoint-scope-state-v1.json" + }, + "title": "Absence predicate outside permit v1 grammar" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "supported", + "name": "permit.revoked.v1" + }, + { + "expected_verdict": "insufficient_evidence", + "name": "checkpoint.scope_state.v1" + }, + { + "expected_verdict": "insufficient_evidence", + "name": "export.scope_faithfulness.v1" + }, + { + "expected_verdict": "insufficient_evidence", + "name": "permit.dispatch_absence_after_revocation.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "CHECKPOINT_SCOPE_STATE_CHECKPOINT_MISSING" + ] + }, + "id": "dispatch-absence-after-revocation-neg-missing-checkpoint", + "kind": "export", + "negative": { + "delta": "Omits the checkpoint artifact referenced by the scope-faithful absence segment.", + "parent_fixture": "dispatch-absence-after-revocation-valid-empty-scope" + }, + "pack": { + "export_file": "fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/pack/export.json", + "features": [ + "scope_faithfulness", + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/pack/manifest.json", + "sidecar_file": "fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/sidecars/checkpoint-scope-state-v1.json" + }, + "title": "Missing checkpoint prevents absence adjudication" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "supported", + "name": "permit.revoked.v1" + }, + { + "expected_verdict": "insufficient_evidence", + "name": "checkpoint.scope_state.v1" + }, + { + "expected_verdict": "insufficient_evidence", + "name": "export.scope_faithfulness.v1" + }, + { + "expected_verdict": "insufficient_evidence", + "name": "permit.dispatch_absence_after_revocation.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "CHECKPOINT_SCOPE_STATE_MISSING" + ] + }, + "id": "dispatch-absence-after-revocation-neg-missing-sidecar", + "kind": "export", + "negative": { + "delta": "Omits the checkpoint scope-state sidecar referenced by the scope-faithful absence segment.", + "parent_fixture": "dispatch-absence-after-revocation-valid-empty-scope" + }, + "pack": { + "checkpoint_file": "fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/pack/checkpoint.json", + "export_file": "fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/pack/export.json", + "features": [ + "scope_faithfulness", + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/pack/manifest.json" + }, + "title": "Missing scope-state sidecar prevents absence adjudication" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "supported", + "name": "permit.revoked.v1" + }, + { + "expected_verdict": "supported", + "name": "checkpoint.scope_state.v1" + }, + { + "expected_verdict": "supported", + "name": "export.scope_faithfulness.v1" + }, + { + "expected_verdict": "supported", + "name": "permit.dispatch_absence_after_revocation.v1" + } + ], + "expected_current": { + "outcome": "PASS", + "reason_classes": [] + }, + "id": "dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported", + "kind": "export", + "pack": { + "checkpoint_file": "fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/pack/checkpoint.json", + "export_file": "fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/pack/export.json", + "features": [ + "scope_faithfulness", + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/pack/manifest.json", + "sidecar_file": "fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/sidecars/checkpoint-scope-state-v1.json" + }, + "title": "Pre-revocation dispatch does not disprove post-revocation absence" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "supported", + "name": "permit.revoked.v1" + }, + { + "expected_verdict": "supported", + "name": "checkpoint.scope_state.v1" + }, + { + "expected_verdict": "supported", + "name": "export.scope_faithfulness.v1" + }, + { + "expected_verdict": "supported", + "name": "permit.dispatch_absence_after_revocation.v1" + } + ], + "expected_current": { + "outcome": "PASS", + "reason_classes": [] + }, + "id": "dispatch-absence-after-revocation-edge-empty-scope-supported", + "kind": "export", + "pack": { + "checkpoint_file": "fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/pack/checkpoint.json", + "export_file": "fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/pack/export.json", + "features": [ + "scope_faithfulness", + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/pack/manifest.json", + "sidecar_file": "fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/sidecars/checkpoint-scope-state-v1.json" + }, + "title": "Empty post-revocation dispatch scope is supported" + }, + { + "claims": [ + { + "expected_verdict": "supported", + "name": "export.integrity.v1" + }, + { + "expected_verdict": "supported", + "name": "permit.revoked.v1" + }, + { + "expected_verdict": "supported", + "name": "checkpoint.scope_state.v1" + }, + { + "expected_verdict": "supported", + "name": "export.scope_faithfulness.v1" + }, + { + "expected_verdict": "disproved", + "name": "permit.dispatch_absence_after_revocation.v1" + } + ], + "expected_current": { + "outcome": "FAIL", + "reason_classes": [ + "EXPORT_SCOPE_POST_REVOCATION_DISPATCH_PRESENT" + ] + }, + "id": "dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at", + "kind": "export", + "negative": { + "delta": "Adds a disclosed dispatch.egress_bound record whose occurred_at equals the revocation effective_at lower bound.", + "parent_fixture": "dispatch-absence-after-revocation-valid-empty-scope" + }, + "pack": { + "checkpoint_file": "fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/pack/checkpoint.json", + "export_file": "fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/pack/export.json", + "features": [ + "scope_faithfulness", + "step4_permit_claims" + ], + "key_manifest": "trust_roots/step4-permit-claims-trust-root.json", + "manifest": "fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/pack/manifest.json", + "sidecar_file": "fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/sidecars/checkpoint-scope-state-v1.json" + }, + "title": "Dispatch at revocation effective_at disproves absence" } ], "soundness_rule": "Expected doctrine verdicts are derived from claim_registry/v0.json and spec/verifier-claims-v0.md, never from current verifier output." diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/README.md b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/README.md new file mode 100644 index 0000000..407330a --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/README.md @@ -0,0 +1,11 @@ +# dispatch-absence-after-revocation-edge-empty-scope-supported + +Empty post-revocation dispatch scope is supported. + +## What It Tests + +The pack contains supported revocation evidence and a scope-faithful absence adjudication segment for post-revocation `dispatch.egress_bound` events. + +## Expected Verdict + +`permit.dispatch_absence_after_revocation.v1` is expected to return `supported` with `PERMIT_DISPATCH_ABSENCE_AFTER_REVOCATION_SUPPORTED`. diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/pack/checkpoint.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/pack/checkpoint.json new file mode 100644 index 0000000..dd6ef89 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/pack/checkpoint.json @@ -0,0 +1,49 @@ +{ + "chain_heads": { + "project:00000000-0000-0000-0000-000000000041": { + "last_record_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "sequence_number": 1 + } + }, + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "claim_set": { + "claims": [ + { + "name": "checkpoint.composite_hash.v1", + "required": true + }, + { + "name": "checkpoint.signature.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "composite_hash": "sha256:3fd43b6a0911bd5da20e720090f87f8ef106dee0ba2383ea2ad2d51488f83ba4", + "computed_at": "2026-05-21T10:10:00.000000Z", + "keel_version": "step4-permit-claims-fixtures", + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "public_key": "ed25519:oJql9HpnWYAv+VX43C0qFKXJnSO+l/hkEn/5ODRVpPA=", + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:RysiE3TOSHVFkxliH9NJlo4XdZc3J+xaI/MADBiFuYrQatXmCWQJ2aKBS7sIGfypK8FJDRa9sqngG5T5mF+UDw==" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/pack/export.json new file mode 100644 index 0000000..2b5e4bf --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/pack/export.json @@ -0,0 +1,125 @@ +{ + "fixture_id": "dispatch-absence-after-revocation-edge-empty-scope-supported", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "revocation_event": { + "canonical_hash": "988d47a4ae347d0b4f49866fc2414acec0139c4be103f3491ae53fd6f2cfe2b2", + "event": { + "actor_id": "30000000-0000-4000-8000-000000000001", + "actor_kind": "user", + "effective_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z", + "signature": "ULWxnis0lPSVXh3Hw2di7GUwu/KPflmoKX2PsTkXua2IF53KPduIdYwXy7SkPyERq/FhiEecHBU0qDV0DBVHBw==" + } + }, + "schema": "keel.step4.permit_claim_fixture/v1", + "scope_faithfulness": { + "segments": [ + { + "canonical_filters": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "filters_hash": "sha256:ce17beeb939a1868b176abcce5003a0dc3f6344d4cdaf3fd47a98eb3a4d067ad", + "raw_filters": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + } + }, + "chain_evidence": { + "disclosure_records": [], + "proof_bridge_records": [ + { + "chain_format_version": "v1", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "created_at": "2026-05-21T10:05:00.000000Z", + "event_id": "evt_step4_permit_revoked", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "outcome": "success", + "payload_json": { + "effective_at": "2026-05-21T10:05:00.000000Z", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z" + }, + "permit_id": "20000000-0000-4000-8000-000000000001", + "prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "project_id": "00000000-0000-0000-0000-000000000041", + "record_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "resource_id": "20000000-0000-4000-8000-000000000001", + "resource_type": "permit", + "sequence_number": 1, + "severity": "info" + } + ] + }, + "declared_end": { + "boundary_policy": "explicit_checkpoint", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_boundary": "2026-05-21T10:10:00.000000Z", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "last_record_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "sequence_number": 1 + }, + "declared_scope": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "population_label": "Post-revocation dispatch.egress_bound events for one permit", + "predicate": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "presentation_policy": { + "policy_kind": "none", + "policy_parameters": {}, + "version": "keel.presentation_policy.v1" + }, + "scope_kind": "declared_sample", + "version": "keel.scope_declaration.v1" + }, + "declared_start": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "genesis_prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "kind": "genesis", + "sequence_number": 1 + }, + "scope_state_reference": { + "artifact_hash": "sha256:de0471fad67c81de5d25ff14aa3ffa49332f889bcbb1589e4042205db2cb736b", + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "storage_uri": "scope-state/v1/bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92/40000000-0000-4000-8000-000000000001/checkpoint-scope-state-v1.json" + }, + "segment_id": "dispatch-absence-after-revocation-edge-empty-scope-supported" + } + ], + "version": "keel.export_scope_faithfulness.v1" + } +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/pack/manifest.json new file mode 100644 index 0000000..70bdd35 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/pack/manifest.json @@ -0,0 +1,94 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.revoked.v1", + "required": true + }, + { + "name": "checkpoint.scope_state.v1", + "required": true + }, + { + "name": "export.scope_faithfulness.v1", + "required": true + }, + { + "name": "permit.dispatch_absence_after_revocation.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:5d109ce640a23373de30eb5963b4e4343daa98cfb462b07130909827f9ce3e03", + "export_id": "dispatch-absence-after-revocation-edge-empty-scope-supported", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 0, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:5b7416b11a4a94a2f9f876b2337e118267ab5eb928165cc15f01abaff8639229", + "id": "keel.permit.revoked_event.v1", + "path": "semantics/permit/revoked_event_v1.json" + }, + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + }, + { + "hash": "sha256:a3213706c9e9531a74cd2355f2f05e537c7a70604cb869b7b76c65cba4a2b707", + "id": "keel.governance_chain.record_hash.v1", + "path": "semantics/governance_chain/record_hash_v1.json" + }, + { + "hash": "sha256:7fc40790b6d8552b8bff63bbfa69cdd53f744a98be97c217e832ea3299e7b528", + "id": "keel.scope_state.merkle.v1", + "path": "semantics/scope_state/merkle_v1.json" + }, + { + "hash": "sha256:f54ac8a8a0c9fb26ee5870e9aded865376af9dde4899026542e97df5d9f454fd", + "id": "keel.scope_state.sidecar_format.v1", + "path": "semantics/scope_state/sidecar_format_v1.json" + }, + { + "hash": "sha256:478150048a5135ebba4550806a814b27ced491a1198c41ad5a40390045a1435b", + "id": "keel.export.scope_faithfulness.v1", + "path": "semantics/export/scope_faithfulness_v1.json" + }, + { + "hash": "sha256:529f17bf4de5ab0ae4a85b89dd66894ddc65923825defae41d5e8af57d0cc0c4", + "id": "keel.permit.dispatch_absence_after_revocation.v1", + "path": "semantics/permit/dispatch_absence_after_revocation_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:cDj/D52UWGTgu0pySjASWCmkRuGJQUAED8Z8DC4rEDjHh2WmEu5KpjKZcwV0AGumkhWBOu+c4vKq7NQDucW9BA==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/sidecars/checkpoint-scope-state-v1.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/sidecars/checkpoint-scope-state-v1.json new file mode 100644 index 0000000..f018db3 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-empty-scope-supported/sidecars/checkpoint-scope-state-v1.json @@ -0,0 +1,68 @@ +{ + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "commitment_profile": "keel.scope_state.merkle.v1", + "predicate_basis": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "reserved_namespaces": [ + "keel.scope_predicate.reserved.v1", + "non_membership_profile" + ], + "supported_predicate_kinds": [ + "project_id", + "permit_id", + "request_id", + "event_type", + "category", + "severity", + "decision_type", + "policy_id", + "provider", + "sequence_number", + "created_at", + "occurred_at", + "section", + "export_type" + ] + }, + "predicate_grammar_version": "keel.scope_predicate.v1", + "scope_commitments": [ + { + "first_matching_sequence": null, + "last_matching_sequence": null, + "matching_count": 0, + "membership_root_hash": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "predicate_value": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "predicate_value_hash": "sha256:ce17beeb939a1868b176abcce5003a0dc3f6344d4cdaf3fd47a98eb3a4d067ad" + } + ], + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "signature": { + "algorithm": "Ed25519", + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "signature": "ed25519:MS9/fceZLVmv+VpH4JgpuqXcVMwUgUH3hvmY2co5n/FQ7a8FD3CPgu0uVDG3RLa28shlzi57rqE55XqjEs2DDw==" + }, + "signed_at": "2026-05-21T10:00:00.000000Z", + "tree_size": 1, + "trust_root_reference": { + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "manifest_version": "keel.public_key_manifest.v1", + "purpose": "scope_state" + }, + "version": "checkpoint_scope_state.v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/README.md b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/README.md new file mode 100644 index 0000000..b9a6438 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/README.md @@ -0,0 +1,11 @@ +# dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported + +Pre-revocation dispatch does not disprove post-revocation absence. + +## What It Tests + +The pack contains supported revocation evidence and a scope-faithful absence adjudication segment for post-revocation `dispatch.egress_bound` events. A pre-revocation `dispatch.egress_bound` record is supplied as bridge evidence and does not match the bounded `occurred_at` range. + +## Expected Verdict + +`permit.dispatch_absence_after_revocation.v1` is expected to return `supported` with `PERMIT_DISPATCH_ABSENCE_AFTER_REVOCATION_SUPPORTED`. diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/pack/checkpoint.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/pack/checkpoint.json new file mode 100644 index 0000000..f114fd5 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/pack/checkpoint.json @@ -0,0 +1,49 @@ +{ + "chain_heads": { + "project:00000000-0000-0000-0000-000000000041": { + "last_record_hash": "051485e92efe5e467f34fcfa91c59cc84752624d4c05e224956a1cc3558afa35", + "sequence_number": 2 + } + }, + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "claim_set": { + "claims": [ + { + "name": "checkpoint.composite_hash.v1", + "required": true + }, + { + "name": "checkpoint.signature.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "composite_hash": "sha256:e1d895aa7dacd6a858819b05aaab92fd4733993d529d43d0020c7f521df0bdd7", + "computed_at": "2026-05-21T10:10:00.000000Z", + "keel_version": "step4-permit-claims-fixtures", + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "public_key": "ed25519:oJql9HpnWYAv+VX43C0qFKXJnSO+l/hkEn/5ODRVpPA=", + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:bEVAzxxHmPpgpkvjH/yc3JBrK2lJqE+lqn9ykeA3uxOmRz7xi5YWEf3VerjDlb08W8V/C6aYXid2MpvhhsIwCQ==" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/pack/export.json new file mode 100644 index 0000000..d84974e --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/pack/export.json @@ -0,0 +1,149 @@ +{ + "fixture_id": "dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "revocation_event": { + "canonical_hash": "988d47a4ae347d0b4f49866fc2414acec0139c4be103f3491ae53fd6f2cfe2b2", + "event": { + "actor_id": "30000000-0000-4000-8000-000000000001", + "actor_kind": "user", + "effective_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z", + "signature": "ULWxnis0lPSVXh3Hw2di7GUwu/KPflmoKX2PsTkXua2IF53KPduIdYwXy7SkPyERq/FhiEecHBU0qDV0DBVHBw==" + } + }, + "schema": "keel.step4.permit_claim_fixture/v1", + "scope_faithfulness": { + "segments": [ + { + "canonical_filters": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "filters_hash": "sha256:ce17beeb939a1868b176abcce5003a0dc3f6344d4cdaf3fd47a98eb3a4d067ad", + "raw_filters": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + } + }, + "chain_evidence": { + "disclosure_records": [], + "proof_bridge_records": [ + { + "chain_format_version": "v1", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "created_at": "2026-05-21T10:04:00.000000Z", + "event_id": "evt_step4_pre_revocation_dispatch", + "event_type": "dispatch.egress_bound", + "occurred_at": "2026-05-21T10:04:00.000000Z", + "outcome": "success", + "payload_json": { + "dispatch_request_digest_v1": "8d8c75b9d7f2b718abd40045a9880e0a16186df3e2563a651ba7add4a1dafb2c", + "event_type": "dispatch.egress_bound", + "occurred_at": "2026-05-21T10:04:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "permit_id": "20000000-0000-4000-8000-000000000001", + "prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "project_id": "00000000-0000-0000-0000-000000000041", + "record_hash": "3df503d47c612f7250742ebf56efc095c93246204f56c6c13a238570f35f54eb", + "resource_id": "20000000-0000-4000-8000-000000000001", + "resource_type": "permit", + "sequence_number": 1, + "severity": "info" + }, + { + "chain_format_version": "v1", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "created_at": "2026-05-21T10:05:00.000000Z", + "event_id": "evt_step4_permit_revoked", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "outcome": "success", + "payload_json": { + "effective_at": "2026-05-21T10:05:00.000000Z", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z" + }, + "permit_id": "20000000-0000-4000-8000-000000000001", + "prev_hash": "3df503d47c612f7250742ebf56efc095c93246204f56c6c13a238570f35f54eb", + "project_id": "00000000-0000-0000-0000-000000000041", + "record_hash": "051485e92efe5e467f34fcfa91c59cc84752624d4c05e224956a1cc3558afa35", + "resource_id": "20000000-0000-4000-8000-000000000001", + "resource_type": "permit", + "sequence_number": 2, + "severity": "info" + } + ] + }, + "declared_end": { + "boundary_policy": "explicit_checkpoint", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_boundary": "2026-05-21T10:10:00.000000Z", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "last_record_hash": "051485e92efe5e467f34fcfa91c59cc84752624d4c05e224956a1cc3558afa35", + "sequence_number": 2 + }, + "declared_scope": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "population_label": "Post-revocation dispatch.egress_bound events for one permit", + "predicate": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "presentation_policy": { + "policy_kind": "none", + "policy_parameters": {}, + "version": "keel.presentation_policy.v1" + }, + "scope_kind": "declared_sample", + "version": "keel.scope_declaration.v1" + }, + "declared_start": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "genesis_prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "kind": "genesis", + "sequence_number": 1 + }, + "scope_state_reference": { + "artifact_hash": "sha256:259a35d5bcbdb44aa2431b9cb7f61e8960f578189835ff2804c169120b6c863e", + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "storage_uri": "scope-state/v1/bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92/40000000-0000-4000-8000-000000000001/checkpoint-scope-state-v1.json" + }, + "segment_id": "dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported" + } + ], + "version": "keel.export_scope_faithfulness.v1" + } +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/pack/manifest.json new file mode 100644 index 0000000..c5b65e8 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/pack/manifest.json @@ -0,0 +1,94 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.revoked.v1", + "required": true + }, + { + "name": "checkpoint.scope_state.v1", + "required": true + }, + { + "name": "export.scope_faithfulness.v1", + "required": true + }, + { + "name": "permit.dispatch_absence_after_revocation.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:efb2ca96f68b2af65b729b381ec7fc78bddb1bf26aa505a4836bcc78c2203203", + "export_id": "dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 0, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:5b7416b11a4a94a2f9f876b2337e118267ab5eb928165cc15f01abaff8639229", + "id": "keel.permit.revoked_event.v1", + "path": "semantics/permit/revoked_event_v1.json" + }, + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + }, + { + "hash": "sha256:a3213706c9e9531a74cd2355f2f05e537c7a70604cb869b7b76c65cba4a2b707", + "id": "keel.governance_chain.record_hash.v1", + "path": "semantics/governance_chain/record_hash_v1.json" + }, + { + "hash": "sha256:7fc40790b6d8552b8bff63bbfa69cdd53f744a98be97c217e832ea3299e7b528", + "id": "keel.scope_state.merkle.v1", + "path": "semantics/scope_state/merkle_v1.json" + }, + { + "hash": "sha256:f54ac8a8a0c9fb26ee5870e9aded865376af9dde4899026542e97df5d9f454fd", + "id": "keel.scope_state.sidecar_format.v1", + "path": "semantics/scope_state/sidecar_format_v1.json" + }, + { + "hash": "sha256:478150048a5135ebba4550806a814b27ced491a1198c41ad5a40390045a1435b", + "id": "keel.export.scope_faithfulness.v1", + "path": "semantics/export/scope_faithfulness_v1.json" + }, + { + "hash": "sha256:529f17bf4de5ab0ae4a85b89dd66894ddc65923825defae41d5e8af57d0cc0c4", + "id": "keel.permit.dispatch_absence_after_revocation.v1", + "path": "semantics/permit/dispatch_absence_after_revocation_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:nLjdbTf/XfT+1L1qUpjOl4Ay6xJplJCXrHKYCZyeTBuzTkRJ60jCCBD4IWpN1eDAsd3RREN/bqIpT1y53fm9CQ==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/sidecars/checkpoint-scope-state-v1.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/sidecars/checkpoint-scope-state-v1.json new file mode 100644 index 0000000..743985b --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-edge-pre-revocation-dispatch-supported/sidecars/checkpoint-scope-state-v1.json @@ -0,0 +1,68 @@ +{ + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "commitment_profile": "keel.scope_state.merkle.v1", + "predicate_basis": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "reserved_namespaces": [ + "keel.scope_predicate.reserved.v1", + "non_membership_profile" + ], + "supported_predicate_kinds": [ + "project_id", + "permit_id", + "request_id", + "event_type", + "category", + "severity", + "decision_type", + "policy_id", + "provider", + "sequence_number", + "created_at", + "occurred_at", + "section", + "export_type" + ] + }, + "predicate_grammar_version": "keel.scope_predicate.v1", + "scope_commitments": [ + { + "first_matching_sequence": null, + "last_matching_sequence": null, + "matching_count": 0, + "membership_root_hash": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "predicate_value": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "predicate_value_hash": "sha256:ce17beeb939a1868b176abcce5003a0dc3f6344d4cdaf3fd47a98eb3a4d067ad" + } + ], + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "signature": { + "algorithm": "Ed25519", + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "signature": "ed25519:uJkbrHfqF8DdWba5c9I7QTajEuoyXSHiTEKCkH5wXbUpEqv8JfgsLrlgYF7M+zYwCY1JM9idC45NyRRbNzrvDg==" + }, + "signed_at": "2026-05-21T10:00:00.000000Z", + "tree_size": 2, + "trust_root_reference": { + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "manifest_version": "keel.public_key_manifest.v1", + "purpose": "scope_state" + }, + "version": "checkpoint_scope_state.v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/README.md b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/README.md new file mode 100644 index 0000000..7733970 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/README.md @@ -0,0 +1,11 @@ +# dispatch-absence-after-revocation-neg-bridge-record-matches-predicate + +Bridge record matching dispatch predicate disproves absence. + +## What It Tests + +The pack contains supported revocation evidence and a scope-faithful absence adjudication segment for post-revocation `dispatch.egress_bound` events. + +## Expected Verdict + +`permit.dispatch_absence_after_revocation.v1` is expected to return `disproved` with `EXPORT_SCOPE_BRIDGE_RECORD_MATCHES_PREDICATE`. diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/pack/checkpoint.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/pack/checkpoint.json new file mode 100644 index 0000000..25d1178 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/pack/checkpoint.json @@ -0,0 +1,49 @@ +{ + "chain_heads": { + "project:00000000-0000-0000-0000-000000000041": { + "last_record_hash": "8d5f160c8fda5130dfd439c365b54a7982b47cf475663082ceaf94aaade7a8f6", + "sequence_number": 2 + } + }, + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "claim_set": { + "claims": [ + { + "name": "checkpoint.composite_hash.v1", + "required": true + }, + { + "name": "checkpoint.signature.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "composite_hash": "sha256:49081d336a0e5880cfb8363437c96d0610cc8ca2263fd2f25a31d32fe28e1ba5", + "computed_at": "2026-05-21T10:10:00.000000Z", + "keel_version": "step4-permit-claims-fixtures", + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "public_key": "ed25519:oJql9HpnWYAv+VX43C0qFKXJnSO+l/hkEn/5ODRVpPA=", + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:Ae7TGxwXjLGHo46jHYx73Co4OdqfLhVWWqsRJ8AkeLynhs08gmUQMMlUOyxQO5NXDVnX+IOHKbQglFT0iXtbBw==" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/pack/export.json new file mode 100644 index 0000000..265fd49 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/pack/export.json @@ -0,0 +1,149 @@ +{ + "fixture_id": "dispatch-absence-after-revocation-neg-bridge-record-matches-predicate", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "revocation_event": { + "canonical_hash": "988d47a4ae347d0b4f49866fc2414acec0139c4be103f3491ae53fd6f2cfe2b2", + "event": { + "actor_id": "30000000-0000-4000-8000-000000000001", + "actor_kind": "user", + "effective_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z", + "signature": "ULWxnis0lPSVXh3Hw2di7GUwu/KPflmoKX2PsTkXua2IF53KPduIdYwXy7SkPyERq/FhiEecHBU0qDV0DBVHBw==" + } + }, + "schema": "keel.step4.permit_claim_fixture/v1", + "scope_faithfulness": { + "segments": [ + { + "canonical_filters": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "filters_hash": "sha256:ce17beeb939a1868b176abcce5003a0dc3f6344d4cdaf3fd47a98eb3a4d067ad", + "raw_filters": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + } + }, + "chain_evidence": { + "disclosure_records": [], + "proof_bridge_records": [ + { + "chain_format_version": "v1", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "created_at": "2026-05-21T10:05:00.000000Z", + "event_id": "evt_step4_permit_revoked", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "outcome": "success", + "payload_json": { + "effective_at": "2026-05-21T10:05:00.000000Z", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z" + }, + "permit_id": "20000000-0000-4000-8000-000000000001", + "prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "project_id": "00000000-0000-0000-0000-000000000041", + "record_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "resource_id": "20000000-0000-4000-8000-000000000001", + "resource_type": "permit", + "sequence_number": 1, + "severity": "info" + }, + { + "chain_format_version": "v1", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "created_at": "2026-05-21T10:06:00.000000Z", + "event_id": "evt_step4_post_revocation_dispatch_bridge", + "event_type": "dispatch.egress_bound", + "occurred_at": "2026-05-21T10:06:00.000000Z", + "outcome": "success", + "payload_json": { + "dispatch_request_digest_v1": "8e982244e97c6b18d84087e3e6d58480e24f18d90c7c482201a8f7b7caf21b55", + "event_type": "dispatch.egress_bound", + "occurred_at": "2026-05-21T10:06:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "permit_id": "20000000-0000-4000-8000-000000000001", + "prev_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "project_id": "00000000-0000-0000-0000-000000000041", + "record_hash": "8d5f160c8fda5130dfd439c365b54a7982b47cf475663082ceaf94aaade7a8f6", + "resource_id": "20000000-0000-4000-8000-000000000001", + "resource_type": "permit", + "sequence_number": 2, + "severity": "info" + } + ] + }, + "declared_end": { + "boundary_policy": "explicit_checkpoint", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_boundary": "2026-05-21T10:10:00.000000Z", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "last_record_hash": "8d5f160c8fda5130dfd439c365b54a7982b47cf475663082ceaf94aaade7a8f6", + "sequence_number": 2 + }, + "declared_scope": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "population_label": "Post-revocation dispatch.egress_bound events for one permit", + "predicate": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "presentation_policy": { + "policy_kind": "none", + "policy_parameters": {}, + "version": "keel.presentation_policy.v1" + }, + "scope_kind": "declared_sample", + "version": "keel.scope_declaration.v1" + }, + "declared_start": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "genesis_prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "kind": "genesis", + "sequence_number": 1 + }, + "scope_state_reference": { + "artifact_hash": "sha256:259a35d5bcbdb44aa2431b9cb7f61e8960f578189835ff2804c169120b6c863e", + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "storage_uri": "scope-state/v1/bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92/40000000-0000-4000-8000-000000000001/checkpoint-scope-state-v1.json" + }, + "segment_id": "dispatch-absence-after-revocation-neg-bridge-record-matches-predicate" + } + ], + "version": "keel.export_scope_faithfulness.v1" + } +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/pack/manifest.json new file mode 100644 index 0000000..500b29c --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/pack/manifest.json @@ -0,0 +1,94 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.revoked.v1", + "required": true + }, + { + "name": "checkpoint.scope_state.v1", + "required": true + }, + { + "name": "export.scope_faithfulness.v1", + "required": true + }, + { + "name": "permit.dispatch_absence_after_revocation.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:9da284a15eb158fce32fa9a59725b2107141e4b088895fa186e71f96b6b1e784", + "export_id": "dispatch-absence-after-revocation-neg-bridge-record-matches-predicate", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 0, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:5b7416b11a4a94a2f9f876b2337e118267ab5eb928165cc15f01abaff8639229", + "id": "keel.permit.revoked_event.v1", + "path": "semantics/permit/revoked_event_v1.json" + }, + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + }, + { + "hash": "sha256:a3213706c9e9531a74cd2355f2f05e537c7a70604cb869b7b76c65cba4a2b707", + "id": "keel.governance_chain.record_hash.v1", + "path": "semantics/governance_chain/record_hash_v1.json" + }, + { + "hash": "sha256:7fc40790b6d8552b8bff63bbfa69cdd53f744a98be97c217e832ea3299e7b528", + "id": "keel.scope_state.merkle.v1", + "path": "semantics/scope_state/merkle_v1.json" + }, + { + "hash": "sha256:f54ac8a8a0c9fb26ee5870e9aded865376af9dde4899026542e97df5d9f454fd", + "id": "keel.scope_state.sidecar_format.v1", + "path": "semantics/scope_state/sidecar_format_v1.json" + }, + { + "hash": "sha256:478150048a5135ebba4550806a814b27ced491a1198c41ad5a40390045a1435b", + "id": "keel.export.scope_faithfulness.v1", + "path": "semantics/export/scope_faithfulness_v1.json" + }, + { + "hash": "sha256:529f17bf4de5ab0ae4a85b89dd66894ddc65923825defae41d5e8af57d0cc0c4", + "id": "keel.permit.dispatch_absence_after_revocation.v1", + "path": "semantics/permit/dispatch_absence_after_revocation_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:UB8apqR8dQjnLzaLPf3lzkQN54jgQK/40iEF6Q7CS3jAnO9NKnIEyrXsBvixzAJUdcGruLZO2c0hcri0GBpCBg==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/sidecars/checkpoint-scope-state-v1.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/sidecars/checkpoint-scope-state-v1.json new file mode 100644 index 0000000..743985b --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-bridge-record-matches-predicate/sidecars/checkpoint-scope-state-v1.json @@ -0,0 +1,68 @@ +{ + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "commitment_profile": "keel.scope_state.merkle.v1", + "predicate_basis": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "reserved_namespaces": [ + "keel.scope_predicate.reserved.v1", + "non_membership_profile" + ], + "supported_predicate_kinds": [ + "project_id", + "permit_id", + "request_id", + "event_type", + "category", + "severity", + "decision_type", + "policy_id", + "provider", + "sequence_number", + "created_at", + "occurred_at", + "section", + "export_type" + ] + }, + "predicate_grammar_version": "keel.scope_predicate.v1", + "scope_commitments": [ + { + "first_matching_sequence": null, + "last_matching_sequence": null, + "matching_count": 0, + "membership_root_hash": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "predicate_value": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "predicate_value_hash": "sha256:ce17beeb939a1868b176abcce5003a0dc3f6344d4cdaf3fd47a98eb3a4d067ad" + } + ], + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "signature": { + "algorithm": "Ed25519", + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "signature": "ed25519:uJkbrHfqF8DdWba5c9I7QTajEuoyXSHiTEKCkH5wXbUpEqv8JfgsLrlgYF7M+zYwCY1JM9idC45NyRRbNzrvDg==" + }, + "signed_at": "2026-05-21T10:00:00.000000Z", + "tree_size": 2, + "trust_root_reference": { + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "manifest_version": "keel.public_key_manifest.v1", + "purpose": "scope_state" + }, + "version": "checkpoint_scope_state.v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/README.md b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/README.md new file mode 100644 index 0000000..c7d3309 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/README.md @@ -0,0 +1,11 @@ +# dispatch-absence-after-revocation-neg-missing-checkpoint + +Missing checkpoint prevents absence adjudication. + +## What It Tests + +The pack contains supported revocation evidence and a scope-faithful absence adjudication segment for post-revocation `dispatch.egress_bound` events. + +## Expected Verdict + +`permit.dispatch_absence_after_revocation.v1` is expected to return `insufficient_evidence` with `CHECKPOINT_SCOPE_STATE_CHECKPOINT_MISSING`. diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/pack/export.json new file mode 100644 index 0000000..6a07277 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/pack/export.json @@ -0,0 +1,125 @@ +{ + "fixture_id": "dispatch-absence-after-revocation-neg-missing-checkpoint", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "revocation_event": { + "canonical_hash": "988d47a4ae347d0b4f49866fc2414acec0139c4be103f3491ae53fd6f2cfe2b2", + "event": { + "actor_id": "30000000-0000-4000-8000-000000000001", + "actor_kind": "user", + "effective_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z", + "signature": "ULWxnis0lPSVXh3Hw2di7GUwu/KPflmoKX2PsTkXua2IF53KPduIdYwXy7SkPyERq/FhiEecHBU0qDV0DBVHBw==" + } + }, + "schema": "keel.step4.permit_claim_fixture/v1", + "scope_faithfulness": { + "segments": [ + { + "canonical_filters": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "filters_hash": "sha256:ce17beeb939a1868b176abcce5003a0dc3f6344d4cdaf3fd47a98eb3a4d067ad", + "raw_filters": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + } + }, + "chain_evidence": { + "disclosure_records": [], + "proof_bridge_records": [ + { + "chain_format_version": "v1", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "created_at": "2026-05-21T10:05:00.000000Z", + "event_id": "evt_step4_permit_revoked", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "outcome": "success", + "payload_json": { + "effective_at": "2026-05-21T10:05:00.000000Z", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z" + }, + "permit_id": "20000000-0000-4000-8000-000000000001", + "prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "project_id": "00000000-0000-0000-0000-000000000041", + "record_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "resource_id": "20000000-0000-4000-8000-000000000001", + "resource_type": "permit", + "sequence_number": 1, + "severity": "info" + } + ] + }, + "declared_end": { + "boundary_policy": "explicit_checkpoint", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_boundary": "2026-05-21T10:10:00.000000Z", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "last_record_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "sequence_number": 1 + }, + "declared_scope": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "population_label": "Post-revocation dispatch.egress_bound events for one permit", + "predicate": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "presentation_policy": { + "policy_kind": "none", + "policy_parameters": {}, + "version": "keel.presentation_policy.v1" + }, + "scope_kind": "declared_sample", + "version": "keel.scope_declaration.v1" + }, + "declared_start": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "genesis_prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "kind": "genesis", + "sequence_number": 1 + }, + "scope_state_reference": { + "artifact_hash": "sha256:de0471fad67c81de5d25ff14aa3ffa49332f889bcbb1589e4042205db2cb736b", + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "storage_uri": "scope-state/v1/bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92/40000000-0000-4000-8000-000000000001/checkpoint-scope-state-v1.json" + }, + "segment_id": "dispatch-absence-after-revocation-neg-missing-checkpoint" + } + ], + "version": "keel.export_scope_faithfulness.v1" + } +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/pack/manifest.json new file mode 100644 index 0000000..698d153 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/pack/manifest.json @@ -0,0 +1,94 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.revoked.v1", + "required": true + }, + { + "name": "checkpoint.scope_state.v1", + "required": true + }, + { + "name": "export.scope_faithfulness.v1", + "required": true + }, + { + "name": "permit.dispatch_absence_after_revocation.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:69e41e40c58a64ef8d7e6234f0f6170be0e03d904778bd6d65e933af832bf0b5", + "export_id": "dispatch-absence-after-revocation-neg-missing-checkpoint", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 0, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:5b7416b11a4a94a2f9f876b2337e118267ab5eb928165cc15f01abaff8639229", + "id": "keel.permit.revoked_event.v1", + "path": "semantics/permit/revoked_event_v1.json" + }, + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + }, + { + "hash": "sha256:a3213706c9e9531a74cd2355f2f05e537c7a70604cb869b7b76c65cba4a2b707", + "id": "keel.governance_chain.record_hash.v1", + "path": "semantics/governance_chain/record_hash_v1.json" + }, + { + "hash": "sha256:7fc40790b6d8552b8bff63bbfa69cdd53f744a98be97c217e832ea3299e7b528", + "id": "keel.scope_state.merkle.v1", + "path": "semantics/scope_state/merkle_v1.json" + }, + { + "hash": "sha256:f54ac8a8a0c9fb26ee5870e9aded865376af9dde4899026542e97df5d9f454fd", + "id": "keel.scope_state.sidecar_format.v1", + "path": "semantics/scope_state/sidecar_format_v1.json" + }, + { + "hash": "sha256:478150048a5135ebba4550806a814b27ced491a1198c41ad5a40390045a1435b", + "id": "keel.export.scope_faithfulness.v1", + "path": "semantics/export/scope_faithfulness_v1.json" + }, + { + "hash": "sha256:529f17bf4de5ab0ae4a85b89dd66894ddc65923825defae41d5e8af57d0cc0c4", + "id": "keel.permit.dispatch_absence_after_revocation.v1", + "path": "semantics/permit/dispatch_absence_after_revocation_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:WRSO34yTYHURSl2aQG+RMGyKQgOqluB7apb0Z0pJVCD8RxD1I3suS0FV94DdSosygFE904nJ3AHgYH2N1R/rDw==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/sidecars/checkpoint-scope-state-v1.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/sidecars/checkpoint-scope-state-v1.json new file mode 100644 index 0000000..f018db3 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-checkpoint/sidecars/checkpoint-scope-state-v1.json @@ -0,0 +1,68 @@ +{ + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "commitment_profile": "keel.scope_state.merkle.v1", + "predicate_basis": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "reserved_namespaces": [ + "keel.scope_predicate.reserved.v1", + "non_membership_profile" + ], + "supported_predicate_kinds": [ + "project_id", + "permit_id", + "request_id", + "event_type", + "category", + "severity", + "decision_type", + "policy_id", + "provider", + "sequence_number", + "created_at", + "occurred_at", + "section", + "export_type" + ] + }, + "predicate_grammar_version": "keel.scope_predicate.v1", + "scope_commitments": [ + { + "first_matching_sequence": null, + "last_matching_sequence": null, + "matching_count": 0, + "membership_root_hash": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "predicate_value": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "predicate_value_hash": "sha256:ce17beeb939a1868b176abcce5003a0dc3f6344d4cdaf3fd47a98eb3a4d067ad" + } + ], + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "signature": { + "algorithm": "Ed25519", + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "signature": "ed25519:MS9/fceZLVmv+VpH4JgpuqXcVMwUgUH3hvmY2co5n/FQ7a8FD3CPgu0uVDG3RLa28shlzi57rqE55XqjEs2DDw==" + }, + "signed_at": "2026-05-21T10:00:00.000000Z", + "tree_size": 1, + "trust_root_reference": { + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "manifest_version": "keel.public_key_manifest.v1", + "purpose": "scope_state" + }, + "version": "checkpoint_scope_state.v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/README.md b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/README.md new file mode 100644 index 0000000..63c6852 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/README.md @@ -0,0 +1,11 @@ +# dispatch-absence-after-revocation-neg-missing-sidecar + +Missing scope-state sidecar prevents absence adjudication. + +## What It Tests + +The pack contains supported revocation evidence and a scope-faithful absence adjudication segment for post-revocation `dispatch.egress_bound` events. + +## Expected Verdict + +`permit.dispatch_absence_after_revocation.v1` is expected to return `insufficient_evidence` with `CHECKPOINT_SCOPE_STATE_MISSING`. diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/pack/checkpoint.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/pack/checkpoint.json new file mode 100644 index 0000000..dd6ef89 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/pack/checkpoint.json @@ -0,0 +1,49 @@ +{ + "chain_heads": { + "project:00000000-0000-0000-0000-000000000041": { + "last_record_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "sequence_number": 1 + } + }, + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "claim_set": { + "claims": [ + { + "name": "checkpoint.composite_hash.v1", + "required": true + }, + { + "name": "checkpoint.signature.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "composite_hash": "sha256:3fd43b6a0911bd5da20e720090f87f8ef106dee0ba2383ea2ad2d51488f83ba4", + "computed_at": "2026-05-21T10:10:00.000000Z", + "keel_version": "step4-permit-claims-fixtures", + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "public_key": "ed25519:oJql9HpnWYAv+VX43C0qFKXJnSO+l/hkEn/5ODRVpPA=", + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:RysiE3TOSHVFkxliH9NJlo4XdZc3J+xaI/MADBiFuYrQatXmCWQJ2aKBS7sIGfypK8FJDRa9sqngG5T5mF+UDw==" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/pack/export.json new file mode 100644 index 0000000..20608e2 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/pack/export.json @@ -0,0 +1,125 @@ +{ + "fixture_id": "dispatch-absence-after-revocation-neg-missing-sidecar", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "revocation_event": { + "canonical_hash": "988d47a4ae347d0b4f49866fc2414acec0139c4be103f3491ae53fd6f2cfe2b2", + "event": { + "actor_id": "30000000-0000-4000-8000-000000000001", + "actor_kind": "user", + "effective_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z", + "signature": "ULWxnis0lPSVXh3Hw2di7GUwu/KPflmoKX2PsTkXua2IF53KPduIdYwXy7SkPyERq/FhiEecHBU0qDV0DBVHBw==" + } + }, + "schema": "keel.step4.permit_claim_fixture/v1", + "scope_faithfulness": { + "segments": [ + { + "canonical_filters": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "filters_hash": "sha256:ce17beeb939a1868b176abcce5003a0dc3f6344d4cdaf3fd47a98eb3a4d067ad", + "raw_filters": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + } + }, + "chain_evidence": { + "disclosure_records": [], + "proof_bridge_records": [ + { + "chain_format_version": "v1", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "created_at": "2026-05-21T10:05:00.000000Z", + "event_id": "evt_step4_permit_revoked", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "outcome": "success", + "payload_json": { + "effective_at": "2026-05-21T10:05:00.000000Z", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z" + }, + "permit_id": "20000000-0000-4000-8000-000000000001", + "prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "project_id": "00000000-0000-0000-0000-000000000041", + "record_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "resource_id": "20000000-0000-4000-8000-000000000001", + "resource_type": "permit", + "sequence_number": 1, + "severity": "info" + } + ] + }, + "declared_end": { + "boundary_policy": "explicit_checkpoint", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_boundary": "2026-05-21T10:10:00.000000Z", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "last_record_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "sequence_number": 1 + }, + "declared_scope": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "population_label": "Post-revocation dispatch.egress_bound events for one permit", + "predicate": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "presentation_policy": { + "policy_kind": "none", + "policy_parameters": {}, + "version": "keel.presentation_policy.v1" + }, + "scope_kind": "declared_sample", + "version": "keel.scope_declaration.v1" + }, + "declared_start": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "genesis_prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "kind": "genesis", + "sequence_number": 1 + }, + "scope_state_reference": { + "artifact_hash": "sha256:de0471fad67c81de5d25ff14aa3ffa49332f889bcbb1589e4042205db2cb736b", + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "storage_uri": "scope-state/v1/bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92/40000000-0000-4000-8000-000000000001/checkpoint-scope-state-v1.json" + }, + "segment_id": "dispatch-absence-after-revocation-neg-missing-sidecar" + } + ], + "version": "keel.export_scope_faithfulness.v1" + } +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/pack/manifest.json new file mode 100644 index 0000000..fb9ef98 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-missing-sidecar/pack/manifest.json @@ -0,0 +1,94 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.revoked.v1", + "required": true + }, + { + "name": "checkpoint.scope_state.v1", + "required": true + }, + { + "name": "export.scope_faithfulness.v1", + "required": true + }, + { + "name": "permit.dispatch_absence_after_revocation.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:af953d165ab25632abf5fe22468c8750c480bbd6f35b0fda58708e2ee11a8614", + "export_id": "dispatch-absence-after-revocation-neg-missing-sidecar", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 0, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:5b7416b11a4a94a2f9f876b2337e118267ab5eb928165cc15f01abaff8639229", + "id": "keel.permit.revoked_event.v1", + "path": "semantics/permit/revoked_event_v1.json" + }, + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + }, + { + "hash": "sha256:a3213706c9e9531a74cd2355f2f05e537c7a70604cb869b7b76c65cba4a2b707", + "id": "keel.governance_chain.record_hash.v1", + "path": "semantics/governance_chain/record_hash_v1.json" + }, + { + "hash": "sha256:7fc40790b6d8552b8bff63bbfa69cdd53f744a98be97c217e832ea3299e7b528", + "id": "keel.scope_state.merkle.v1", + "path": "semantics/scope_state/merkle_v1.json" + }, + { + "hash": "sha256:f54ac8a8a0c9fb26ee5870e9aded865376af9dde4899026542e97df5d9f454fd", + "id": "keel.scope_state.sidecar_format.v1", + "path": "semantics/scope_state/sidecar_format_v1.json" + }, + { + "hash": "sha256:478150048a5135ebba4550806a814b27ced491a1198c41ad5a40390045a1435b", + "id": "keel.export.scope_faithfulness.v1", + "path": "semantics/export/scope_faithfulness_v1.json" + }, + { + "hash": "sha256:529f17bf4de5ab0ae4a85b89dd66894ddc65923825defae41d5e8af57d0cc0c4", + "id": "keel.permit.dispatch_absence_after_revocation.v1", + "path": "semantics/permit/dispatch_absence_after_revocation_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:+63pmARzt6PhWYdTAvZPE8hBx0uWNx2XKvO6CZ5eZildxmILdmHjQCIzRQ+qB0xf3cP3QMwwIfve7rlyfx9BAw==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/README.md b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/README.md new file mode 100644 index 0000000..b940486 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/README.md @@ -0,0 +1,11 @@ +# dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at + +Dispatch at revocation effective_at disproves absence. + +## What It Tests + +The pack contains supported revocation evidence and a scope-faithful absence adjudication segment for post-revocation `dispatch.egress_bound` events. + +## Expected Verdict + +`permit.dispatch_absence_after_revocation.v1` is expected to return `disproved` with `EXPORT_SCOPE_POST_REVOCATION_DISPATCH_PRESENT`. diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/pack/checkpoint.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/pack/checkpoint.json new file mode 100644 index 0000000..64617b9 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/pack/checkpoint.json @@ -0,0 +1,49 @@ +{ + "chain_heads": { + "project:00000000-0000-0000-0000-000000000041": { + "last_record_hash": "ce664eeab47c01ebc823b46abcf05779484a87d781a51166d1be602bad3ee769", + "sequence_number": 2 + } + }, + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "claim_set": { + "claims": [ + { + "name": "checkpoint.composite_hash.v1", + "required": true + }, + { + "name": "checkpoint.signature.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "composite_hash": "sha256:45a02df4f06718630571a2b695d36349138b3b070c5ec845dd66696f715b1623", + "computed_at": "2026-05-21T10:10:00.000000Z", + "keel_version": "step4-permit-claims-fixtures", + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "public_key": "ed25519:oJql9HpnWYAv+VX43C0qFKXJnSO+l/hkEn/5ODRVpPA=", + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:OngNk2qG+P3f7CPxk1ptJ/BCN4bQVfv7wNMOT33eI9k8b8SLLlYmYxMXbJvqPm2daz/GhE8ZZW9HseniuiMmDQ==" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/pack/export.json new file mode 100644 index 0000000..90fe8f5 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/pack/export.json @@ -0,0 +1,150 @@ +{ + "fixture_id": "dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "revocation_event": { + "canonical_hash": "988d47a4ae347d0b4f49866fc2414acec0139c4be103f3491ae53fd6f2cfe2b2", + "event": { + "actor_id": "30000000-0000-4000-8000-000000000001", + "actor_kind": "user", + "effective_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z", + "signature": "ULWxnis0lPSVXh3Hw2di7GUwu/KPflmoKX2PsTkXua2IF53KPduIdYwXy7SkPyERq/FhiEecHBU0qDV0DBVHBw==" + } + }, + "schema": "keel.step4.permit_claim_fixture/v1", + "scope_faithfulness": { + "segments": [ + { + "canonical_filters": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "filters_hash": "sha256:ce17beeb939a1868b176abcce5003a0dc3f6344d4cdaf3fd47a98eb3a4d067ad", + "raw_filters": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + } + }, + "chain_evidence": { + "disclosure_records": [ + { + "chain_format_version": "v1", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "created_at": "2026-05-21T10:05:00.000000Z", + "event_id": "evt_step4_post_revocation_dispatch_disclosed", + "event_type": "dispatch.egress_bound", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "outcome": "success", + "payload_json": { + "dispatch_request_digest_v1": "c64bac40f48ceafa155fd9db798682c91c82c0d5ecdda5b7aa70f1bdca998aea", + "event_type": "dispatch.egress_bound", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "permit_id": "20000000-0000-4000-8000-000000000001", + "prev_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "project_id": "00000000-0000-0000-0000-000000000041", + "record_hash": "ce664eeab47c01ebc823b46abcf05779484a87d781a51166d1be602bad3ee769", + "resource_id": "20000000-0000-4000-8000-000000000001", + "resource_type": "permit", + "sequence_number": 2, + "severity": "info" + } + ], + "proof_bridge_records": [ + { + "chain_format_version": "v1", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "created_at": "2026-05-21T10:05:00.000000Z", + "event_id": "evt_step4_permit_revoked", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "outcome": "success", + "payload_json": { + "effective_at": "2026-05-21T10:05:00.000000Z", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z" + }, + "permit_id": "20000000-0000-4000-8000-000000000001", + "prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "project_id": "00000000-0000-0000-0000-000000000041", + "record_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "resource_id": "20000000-0000-4000-8000-000000000001", + "resource_type": "permit", + "sequence_number": 1, + "severity": "info" + } + ] + }, + "declared_end": { + "boundary_policy": "explicit_checkpoint", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_boundary": "2026-05-21T10:10:00.000000Z", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "last_record_hash": "ce664eeab47c01ebc823b46abcf05779484a87d781a51166d1be602bad3ee769", + "sequence_number": 2 + }, + "declared_scope": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "population_label": "Post-revocation dispatch.egress_bound events for one permit", + "predicate": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "presentation_policy": { + "policy_kind": "none", + "policy_parameters": {}, + "version": "keel.presentation_policy.v1" + }, + "scope_kind": "declared_sample", + "version": "keel.scope_declaration.v1" + }, + "declared_start": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "genesis_prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "kind": "genesis", + "sequence_number": 1 + }, + "scope_state_reference": { + "artifact_hash": "sha256:73e5cbf0d60db1de1de49e1e616b2d7e0f7011416772018734b95391703a9532", + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "storage_uri": "scope-state/v1/bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92/40000000-0000-4000-8000-000000000001/checkpoint-scope-state-v1.json" + }, + "segment_id": "dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at" + } + ], + "version": "keel.export_scope_faithfulness.v1" + } +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/pack/manifest.json new file mode 100644 index 0000000..567bbdf --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/pack/manifest.json @@ -0,0 +1,94 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.revoked.v1", + "required": true + }, + { + "name": "checkpoint.scope_state.v1", + "required": true + }, + { + "name": "export.scope_faithfulness.v1", + "required": true + }, + { + "name": "permit.dispatch_absence_after_revocation.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:a22c60147b559be6bd76133c75b07a6660b94161f06d3f782865fe1ee8ca5093", + "export_id": "dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 0, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:5b7416b11a4a94a2f9f876b2337e118267ab5eb928165cc15f01abaff8639229", + "id": "keel.permit.revoked_event.v1", + "path": "semantics/permit/revoked_event_v1.json" + }, + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + }, + { + "hash": "sha256:a3213706c9e9531a74cd2355f2f05e537c7a70604cb869b7b76c65cba4a2b707", + "id": "keel.governance_chain.record_hash.v1", + "path": "semantics/governance_chain/record_hash_v1.json" + }, + { + "hash": "sha256:7fc40790b6d8552b8bff63bbfa69cdd53f744a98be97c217e832ea3299e7b528", + "id": "keel.scope_state.merkle.v1", + "path": "semantics/scope_state/merkle_v1.json" + }, + { + "hash": "sha256:f54ac8a8a0c9fb26ee5870e9aded865376af9dde4899026542e97df5d9f454fd", + "id": "keel.scope_state.sidecar_format.v1", + "path": "semantics/scope_state/sidecar_format_v1.json" + }, + { + "hash": "sha256:478150048a5135ebba4550806a814b27ced491a1198c41ad5a40390045a1435b", + "id": "keel.export.scope_faithfulness.v1", + "path": "semantics/export/scope_faithfulness_v1.json" + }, + { + "hash": "sha256:529f17bf4de5ab0ae4a85b89dd66894ddc65923825defae41d5e8af57d0cc0c4", + "id": "keel.permit.dispatch_absence_after_revocation.v1", + "path": "semantics/permit/dispatch_absence_after_revocation_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:lefzmCfQ1kPgNr70OM0CCHJc+qlHlr0JwwtMvXFPEWGurOEVGozIImgSNZ+YPSlGYQHaN9enMx0ukWaKnDAADg==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/sidecars/checkpoint-scope-state-v1.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/sidecars/checkpoint-scope-state-v1.json new file mode 100644 index 0000000..7b732bc --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-occurred-at-equals-effective-at/sidecars/checkpoint-scope-state-v1.json @@ -0,0 +1,68 @@ +{ + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "commitment_profile": "keel.scope_state.merkle.v1", + "predicate_basis": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "reserved_namespaces": [ + "keel.scope_predicate.reserved.v1", + "non_membership_profile" + ], + "supported_predicate_kinds": [ + "project_id", + "permit_id", + "request_id", + "event_type", + "category", + "severity", + "decision_type", + "policy_id", + "provider", + "sequence_number", + "created_at", + "occurred_at", + "section", + "export_type" + ] + }, + "predicate_grammar_version": "keel.scope_predicate.v1", + "scope_commitments": [ + { + "first_matching_sequence": 2, + "last_matching_sequence": 2, + "matching_count": 1, + "membership_root_hash": "sha256:cc8b91b2e59f63bce91013360febc84a670a30847963f9f544c00bd0fe000652", + "predicate_value": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "predicate_value_hash": "sha256:ce17beeb939a1868b176abcce5003a0dc3f6344d4cdaf3fd47a98eb3a4d067ad" + } + ], + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "signature": { + "algorithm": "Ed25519", + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "signature": "ed25519:c2Vsrnqwef4YIBm3zDgq37ibLlUM+fagOlHG3LOAmtzkvhBor8HHdRI1b26I65DoAJJcK0LvB1rl7PhB59xmAg==" + }, + "signed_at": "2026-05-21T10:00:00.000000Z", + "tree_size": 2, + "trust_root_reference": { + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "manifest_version": "keel.public_key_manifest.v1", + "purpose": "scope_state" + }, + "version": "checkpoint_scope_state.v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/README.md b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/README.md new file mode 100644 index 0000000..3d13fa9 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/README.md @@ -0,0 +1,11 @@ +# dispatch-absence-after-revocation-neg-post-revocation-dispatch-present + +Post-revocation dispatch initiation disproves absence. + +## What It Tests + +The pack contains supported revocation evidence and a scope-faithful absence adjudication segment for post-revocation `dispatch.egress_bound` events. + +## Expected Verdict + +`permit.dispatch_absence_after_revocation.v1` is expected to return `disproved` with `EXPORT_SCOPE_POST_REVOCATION_DISPATCH_PRESENT`. diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/pack/checkpoint.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/pack/checkpoint.json new file mode 100644 index 0000000..0d93363 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/pack/checkpoint.json @@ -0,0 +1,49 @@ +{ + "chain_heads": { + "project:00000000-0000-0000-0000-000000000041": { + "last_record_hash": "ce8eb3ea7a373b81ebb927c7049bfde2d5446710d792537097353fa032b74049", + "sequence_number": 2 + } + }, + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "claim_set": { + "claims": [ + { + "name": "checkpoint.composite_hash.v1", + "required": true + }, + { + "name": "checkpoint.signature.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "composite_hash": "sha256:770df2c194f7d4f6bbcc2cbe9d525ac63631c8b2e977c78f36f19331fb4cf870", + "computed_at": "2026-05-21T10:10:00.000000Z", + "keel_version": "step4-permit-claims-fixtures", + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "public_key": "ed25519:oJql9HpnWYAv+VX43C0qFKXJnSO+l/hkEn/5ODRVpPA=", + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:ZYWbDIiB4gGLD32HbOvEA31D1Y6nsuBnguV63jNfWN/XqeL2KNZ6HNlEKfGvgfrVVelf3IfcHpMhQPdebaoBDA==" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/pack/export.json new file mode 100644 index 0000000..8a0e72a --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/pack/export.json @@ -0,0 +1,150 @@ +{ + "fixture_id": "dispatch-absence-after-revocation-neg-post-revocation-dispatch-present", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "revocation_event": { + "canonical_hash": "988d47a4ae347d0b4f49866fc2414acec0139c4be103f3491ae53fd6f2cfe2b2", + "event": { + "actor_id": "30000000-0000-4000-8000-000000000001", + "actor_kind": "user", + "effective_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z", + "signature": "ULWxnis0lPSVXh3Hw2di7GUwu/KPflmoKX2PsTkXua2IF53KPduIdYwXy7SkPyERq/FhiEecHBU0qDV0DBVHBw==" + } + }, + "schema": "keel.step4.permit_claim_fixture/v1", + "scope_faithfulness": { + "segments": [ + { + "canonical_filters": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "filters_hash": "sha256:ce17beeb939a1868b176abcce5003a0dc3f6344d4cdaf3fd47a98eb3a4d067ad", + "raw_filters": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + } + }, + "chain_evidence": { + "disclosure_records": [ + { + "chain_format_version": "v1", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "created_at": "2026-05-21T10:06:00.000000Z", + "event_id": "evt_step4_post_revocation_dispatch_disclosed", + "event_type": "dispatch.egress_bound", + "occurred_at": "2026-05-21T10:06:00.000000Z", + "outcome": "success", + "payload_json": { + "dispatch_request_digest_v1": "8e982244e97c6b18d84087e3e6d58480e24f18d90c7c482201a8f7b7caf21b55", + "event_type": "dispatch.egress_bound", + "occurred_at": "2026-05-21T10:06:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "permit_id": "20000000-0000-4000-8000-000000000001", + "prev_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "project_id": "00000000-0000-0000-0000-000000000041", + "record_hash": "ce8eb3ea7a373b81ebb927c7049bfde2d5446710d792537097353fa032b74049", + "resource_id": "20000000-0000-4000-8000-000000000001", + "resource_type": "permit", + "sequence_number": 2, + "severity": "info" + } + ], + "proof_bridge_records": [ + { + "chain_format_version": "v1", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "created_at": "2026-05-21T10:05:00.000000Z", + "event_id": "evt_step4_permit_revoked", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "outcome": "success", + "payload_json": { + "effective_at": "2026-05-21T10:05:00.000000Z", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z" + }, + "permit_id": "20000000-0000-4000-8000-000000000001", + "prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "project_id": "00000000-0000-0000-0000-000000000041", + "record_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "resource_id": "20000000-0000-4000-8000-000000000001", + "resource_type": "permit", + "sequence_number": 1, + "severity": "info" + } + ] + }, + "declared_end": { + "boundary_policy": "explicit_checkpoint", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_boundary": "2026-05-21T10:10:00.000000Z", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "last_record_hash": "ce8eb3ea7a373b81ebb927c7049bfde2d5446710d792537097353fa032b74049", + "sequence_number": 2 + }, + "declared_scope": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "population_label": "Post-revocation dispatch.egress_bound events for one permit", + "predicate": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "presentation_policy": { + "policy_kind": "none", + "policy_parameters": {}, + "version": "keel.presentation_policy.v1" + }, + "scope_kind": "declared_sample", + "version": "keel.scope_declaration.v1" + }, + "declared_start": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "genesis_prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "kind": "genesis", + "sequence_number": 1 + }, + "scope_state_reference": { + "artifact_hash": "sha256:ca0e791b776ad359848dad241185b5b435fae9e5d9c64a0fff9158db554d9d98", + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "storage_uri": "scope-state/v1/bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92/40000000-0000-4000-8000-000000000001/checkpoint-scope-state-v1.json" + }, + "segment_id": "dispatch-absence-after-revocation-neg-post-revocation-dispatch-present" + } + ], + "version": "keel.export_scope_faithfulness.v1" + } +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/pack/manifest.json new file mode 100644 index 0000000..9b96a66 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/pack/manifest.json @@ -0,0 +1,94 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.revoked.v1", + "required": true + }, + { + "name": "checkpoint.scope_state.v1", + "required": true + }, + { + "name": "export.scope_faithfulness.v1", + "required": true + }, + { + "name": "permit.dispatch_absence_after_revocation.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:7534c6a853691c47c5a9286120dfc54850dfbdd9650b34d425581f5bb08891ea", + "export_id": "dispatch-absence-after-revocation-neg-post-revocation-dispatch-present", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 0, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:5b7416b11a4a94a2f9f876b2337e118267ab5eb928165cc15f01abaff8639229", + "id": "keel.permit.revoked_event.v1", + "path": "semantics/permit/revoked_event_v1.json" + }, + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + }, + { + "hash": "sha256:a3213706c9e9531a74cd2355f2f05e537c7a70604cb869b7b76c65cba4a2b707", + "id": "keel.governance_chain.record_hash.v1", + "path": "semantics/governance_chain/record_hash_v1.json" + }, + { + "hash": "sha256:7fc40790b6d8552b8bff63bbfa69cdd53f744a98be97c217e832ea3299e7b528", + "id": "keel.scope_state.merkle.v1", + "path": "semantics/scope_state/merkle_v1.json" + }, + { + "hash": "sha256:f54ac8a8a0c9fb26ee5870e9aded865376af9dde4899026542e97df5d9f454fd", + "id": "keel.scope_state.sidecar_format.v1", + "path": "semantics/scope_state/sidecar_format_v1.json" + }, + { + "hash": "sha256:478150048a5135ebba4550806a814b27ced491a1198c41ad5a40390045a1435b", + "id": "keel.export.scope_faithfulness.v1", + "path": "semantics/export/scope_faithfulness_v1.json" + }, + { + "hash": "sha256:529f17bf4de5ab0ae4a85b89dd66894ddc65923825defae41d5e8af57d0cc0c4", + "id": "keel.permit.dispatch_absence_after_revocation.v1", + "path": "semantics/permit/dispatch_absence_after_revocation_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:2dfdAHFtBiE1QXyg7VeQ2/FPnXImvD2XaSrPgfiE2Dja+6igkYSuZkSXqprWyA4lBZwDgXyLf3C5gASWT0AaCA==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/sidecars/checkpoint-scope-state-v1.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/sidecars/checkpoint-scope-state-v1.json new file mode 100644 index 0000000..0d1a279 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-post-revocation-dispatch-present/sidecars/checkpoint-scope-state-v1.json @@ -0,0 +1,68 @@ +{ + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "commitment_profile": "keel.scope_state.merkle.v1", + "predicate_basis": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "reserved_namespaces": [ + "keel.scope_predicate.reserved.v1", + "non_membership_profile" + ], + "supported_predicate_kinds": [ + "project_id", + "permit_id", + "request_id", + "event_type", + "category", + "severity", + "decision_type", + "policy_id", + "provider", + "sequence_number", + "created_at", + "occurred_at", + "section", + "export_type" + ] + }, + "predicate_grammar_version": "keel.scope_predicate.v1", + "scope_commitments": [ + { + "first_matching_sequence": 2, + "last_matching_sequence": 2, + "matching_count": 1, + "membership_root_hash": "sha256:28396aa07feca48cc69838b14fdb414894790fa3346cecea94bb93043bbd863e", + "predicate_value": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "predicate_value_hash": "sha256:ce17beeb939a1868b176abcce5003a0dc3f6344d4cdaf3fd47a98eb3a4d067ad" + } + ], + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "signature": { + "algorithm": "Ed25519", + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "signature": "ed25519:SeNEagg9u7uxh/A8qWgPUZTGXFtwGfKUt10XGB9V2Gd/HNLkwdymIr9D3/LrjSq6Lt3uOwHM7ayUu4/Q+GS1CA==" + }, + "signed_at": "2026-05-21T10:00:00.000000Z", + "tree_size": 2, + "trust_root_reference": { + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "manifest_version": "keel.public_key_manifest.v1", + "purpose": "scope_state" + }, + "version": "checkpoint_scope_state.v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/README.md b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/README.md new file mode 100644 index 0000000..9b373b3 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/README.md @@ -0,0 +1,11 @@ +# dispatch-absence-after-revocation-neg-predicate-out-of-grammar + +Absence predicate outside permit v1 grammar. + +## What It Tests + +The pack contains supported revocation evidence and a scope-faithful absence adjudication segment for post-revocation `dispatch.egress_bound` events. + +## Expected Verdict + +`permit.dispatch_absence_after_revocation.v1` is expected to return `unverifiable_scope` with `EXPORT_SCOPE_PREDICATE_OUT_OF_GRAMMAR`. diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/pack/checkpoint.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/pack/checkpoint.json new file mode 100644 index 0000000..dd6ef89 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/pack/checkpoint.json @@ -0,0 +1,49 @@ +{ + "chain_heads": { + "project:00000000-0000-0000-0000-000000000041": { + "last_record_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "sequence_number": 1 + } + }, + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "claim_set": { + "claims": [ + { + "name": "checkpoint.composite_hash.v1", + "required": true + }, + { + "name": "checkpoint.signature.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "composite_hash": "sha256:3fd43b6a0911bd5da20e720090f87f8ef106dee0ba2383ea2ad2d51488f83ba4", + "computed_at": "2026-05-21T10:10:00.000000Z", + "keel_version": "step4-permit-claims-fixtures", + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "public_key": "ed25519:oJql9HpnWYAv+VX43C0qFKXJnSO+l/hkEn/5ODRVpPA=", + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:RysiE3TOSHVFkxliH9NJlo4XdZc3J+xaI/MADBiFuYrQatXmCWQJ2aKBS7sIGfypK8FJDRa9sqngG5T5mF+UDw==" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/pack/export.json new file mode 100644 index 0000000..965f8dc --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/pack/export.json @@ -0,0 +1,127 @@ +{ + "fixture_id": "dispatch-absence-after-revocation-neg-predicate-out-of-grammar", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "revocation_event": { + "canonical_hash": "988d47a4ae347d0b4f49866fc2414acec0139c4be103f3491ae53fd6f2cfe2b2", + "event": { + "actor_id": "30000000-0000-4000-8000-000000000001", + "actor_kind": "user", + "effective_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z", + "signature": "ULWxnis0lPSVXh3Hw2di7GUwu/KPflmoKX2PsTkXua2IF53KPduIdYwXy7SkPyERq/FhiEecHBU0qDV0DBVHBw==" + } + }, + "schema": "keel.step4.permit_claim_fixture/v1", + "scope_faithfulness": { + "segments": [ + { + "canonical_filters": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "filters_hash": "sha256:b2b14dc1038f20204935bd31da629e880d5ed872f3fc51d552ba4a099f022dcf", + "raw_filters": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "provider": "openai" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + } + }, + "chain_evidence": { + "disclosure_records": [], + "proof_bridge_records": [ + { + "chain_format_version": "v1", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "created_at": "2026-05-21T10:05:00.000000Z", + "event_id": "evt_step4_permit_revoked", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "outcome": "success", + "payload_json": { + "effective_at": "2026-05-21T10:05:00.000000Z", + "event_type": "permit.revoked", + "occurred_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z" + }, + "permit_id": "20000000-0000-4000-8000-000000000001", + "prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "project_id": "00000000-0000-0000-0000-000000000041", + "record_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "resource_id": "20000000-0000-4000-8000-000000000001", + "resource_type": "permit", + "sequence_number": 1, + "severity": "info" + } + ] + }, + "declared_end": { + "boundary_policy": "explicit_checkpoint", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_boundary": "2026-05-21T10:10:00.000000Z", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "last_record_hash": "da137414bf851df9e30e1f86e95c13b387a36ed6152816452de982c743050b7d", + "sequence_number": 1 + }, + "declared_scope": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "population_label": "Post-revocation dispatch.egress_bound events for one permit", + "predicate": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "provider": "openai" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "presentation_policy": { + "policy_kind": "none", + "policy_parameters": {}, + "version": "keel.presentation_policy.v1" + }, + "scope_kind": "declared_sample", + "version": "keel.scope_declaration.v1" + }, + "declared_start": { + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "genesis_prev_hash": "0000000000000000000000000000000000000000000000000000000000000000", + "kind": "genesis", + "sequence_number": 1 + }, + "scope_state_reference": { + "artifact_hash": "sha256:3ee1dc5a34172b6ad8f394aefa7c07f477bb866dff1edea42c31dc5dc2bfc383", + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "storage_uri": "scope-state/v1/bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92/40000000-0000-4000-8000-000000000001/checkpoint-scope-state-v1.json" + }, + "segment_id": "dispatch-absence-after-revocation-neg-predicate-out-of-grammar" + } + ], + "version": "keel.export_scope_faithfulness.v1" + } +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/pack/manifest.json new file mode 100644 index 0000000..6dac157 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/pack/manifest.json @@ -0,0 +1,94 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.revoked.v1", + "required": true + }, + { + "name": "checkpoint.scope_state.v1", + "required": true + }, + { + "name": "export.scope_faithfulness.v1", + "required": true + }, + { + "name": "permit.dispatch_absence_after_revocation.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:be0c7d97891e6bcf227e4fa4641ab7bec0278c70f722eed7d4bf8dae59c48dd6", + "export_id": "dispatch-absence-after-revocation-neg-predicate-out-of-grammar", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 0, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:5b7416b11a4a94a2f9f876b2337e118267ab5eb928165cc15f01abaff8639229", + "id": "keel.permit.revoked_event.v1", + "path": "semantics/permit/revoked_event_v1.json" + }, + { + "hash": "sha256:68aafa26d6f1c8cf5ba83c7596209888d8e529d81f1a2c58f31e2fc41fc136de", + "id": "keel.checkpoint.composite_hash.v1", + "path": "semantics/checkpoint/composite_hash_v1.json" + }, + { + "hash": "sha256:af16c66e8a0b295cd2e5e436169bf0e3d628c1fc4901b6eba6596e86e3ad256b", + "id": "keel.checkpoint.signature.v1", + "path": "semantics/checkpoint/signature_v1.json" + }, + { + "hash": "sha256:a3213706c9e9531a74cd2355f2f05e537c7a70604cb869b7b76c65cba4a2b707", + "id": "keel.governance_chain.record_hash.v1", + "path": "semantics/governance_chain/record_hash_v1.json" + }, + { + "hash": "sha256:7fc40790b6d8552b8bff63bbfa69cdd53f744a98be97c217e832ea3299e7b528", + "id": "keel.scope_state.merkle.v1", + "path": "semantics/scope_state/merkle_v1.json" + }, + { + "hash": "sha256:f54ac8a8a0c9fb26ee5870e9aded865376af9dde4899026542e97df5d9f454fd", + "id": "keel.scope_state.sidecar_format.v1", + "path": "semantics/scope_state/sidecar_format_v1.json" + }, + { + "hash": "sha256:478150048a5135ebba4550806a814b27ced491a1198c41ad5a40390045a1435b", + "id": "keel.export.scope_faithfulness.v1", + "path": "semantics/export/scope_faithfulness_v1.json" + }, + { + "hash": "sha256:529f17bf4de5ab0ae4a85b89dd66894ddc65923825defae41d5e8af57d0cc0c4", + "id": "keel.permit.dispatch_absence_after_revocation.v1", + "path": "semantics/permit/dispatch_absence_after_revocation_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:alnKfdWY7Qyxq/wvpbLCv9Z8GFGKM3DqXl68w0rhbIdlQIALLn0XnxNeWNsVToRFA4kn+rEyyAKV5RaIUpgzDA==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/sidecars/checkpoint-scope-state-v1.json b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/sidecars/checkpoint-scope-state-v1.json new file mode 100644 index 0000000..2c4e629 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-neg-predicate-out-of-grammar/sidecars/checkpoint-scope-state-v1.json @@ -0,0 +1,69 @@ +{ + "artifact_type": "checkpoint_scope_state", + "chain_scope": "project:00000000-0000-0000-0000-000000000041", + "checkpoint_id": "40000000-0000-4000-8000-000000000001", + "commitment_profile": "keel.scope_state.merkle.v1", + "predicate_basis": { + "canonicalization_profile": "keel.canonical_json.payload.v1", + "reserved_namespaces": [ + "keel.scope_predicate.reserved.v1", + "non_membership_profile" + ], + "supported_predicate_kinds": [ + "project_id", + "permit_id", + "request_id", + "event_type", + "category", + "severity", + "decision_type", + "policy_id", + "provider", + "sequence_number", + "created_at", + "occurred_at", + "section", + "export_type" + ] + }, + "predicate_grammar_version": "keel.scope_predicate.v1", + "scope_commitments": [ + { + "first_matching_sequence": null, + "last_matching_sequence": null, + "matching_count": 0, + "membership_root_hash": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "predicate_value": { + "equals": { + "event_type": "dispatch.egress_bound", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "provider": "openai" + }, + "operator": "and", + "ranges": { + "occurred_at": { + "gte": "2026-05-21T10:05:00.000000Z", + "lt": "2026-05-21T10:10:00.000000Z" + } + }, + "version": "keel.scope_predicate.v1" + }, + "predicate_value_hash": "sha256:b2b14dc1038f20204935bd31da629e880d5ed872f3fc51d552ba4a099f022dcf" + } + ], + "scope_state_id": "keel.scope_state.v1:bd32ee1f1b8934ffc3688db3454a7049ebd808e866d2338d9fce48943abc7a92:40000000-0000-4000-8000-000000000001", + "signature": { + "algorithm": "Ed25519", + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "signature": "ed25519:aEapo3PC3R2lDB01Ez/T0x+kPhqNp81uw0WYVX9DpYnX/a+q9cgXXGgstVmT8fnvDpQ4kPqKjgT/07tCLN93Ag==" + }, + "signed_at": "2026-05-21T10:00:00.000000Z", + "tree_size": 1, + "trust_root_reference": { + "key_id": "sha256:1325b850c2871916eae203f0efc3c898", + "manifest_version": "keel.public_key_manifest.v1", + "purpose": "scope_state" + }, + "version": "checkpoint_scope_state.v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-valid-empty-scope/README.md b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-valid-empty-scope/README.md index df96902..ecb205e 100644 --- a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-valid-empty-scope/README.md +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-valid-empty-scope/README.md @@ -4,8 +4,8 @@ Valid post-revocation dispatch absence with empty matching scope. ## What It Tests -The pack contains supported revocation evidence and a scope-faithful absence adjudication segment whose post-revocation `dispatch.egress_bound` matching count is zero. +The pack contains supported revocation evidence and a scope-faithful absence adjudication segment for post-revocation `dispatch.egress_bound` events. ## Expected Verdict -`permit.dispatch_absence_after_revocation.v1` is expected to return `supported`. +`permit.dispatch_absence_after_revocation.v1` is expected to return `supported` with `PERMIT_DISPATCH_ABSENCE_AFTER_REVOCATION_SUPPORTED`. diff --git a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-valid-with-pre-revocation-dispatch/README.md b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-valid-with-pre-revocation-dispatch/README.md index 18b6165..e6a27e5 100644 --- a/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-valid-with-pre-revocation-dispatch/README.md +++ b/test-vectors/verifier_claims/v0/fixtures/dispatch-absence-after-revocation-valid-with-pre-revocation-dispatch/README.md @@ -4,8 +4,8 @@ Valid post-revocation dispatch absence with pre-revocation dispatch evidence. ## What It Tests -The pack contains supported revocation evidence and a scope-faithful absence adjudication segment whose post-revocation `dispatch.egress_bound` matching count is zero. A pre-revocation `dispatch.egress_bound` record is supplied as bridge evidence and does not match the bounded `occurred_at` range. +The pack contains supported revocation evidence and a scope-faithful absence adjudication segment for post-revocation `dispatch.egress_bound` events. A pre-revocation `dispatch.egress_bound` record is supplied as bridge evidence and does not match the bounded `occurred_at` range. ## Expected Verdict -`permit.dispatch_absence_after_revocation.v1` is expected to return `supported`. +`permit.dispatch_absence_after_revocation.v1` is expected to return `supported` with `PERMIT_DISPATCH_ABSENCE_AFTER_REVOCATION_SUPPORTED`. diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-bad-signature/README.md b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-bad-signature/README.md new file mode 100644 index 0000000..58e37c1 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-bad-signature/README.md @@ -0,0 +1,11 @@ +# permit-decision-neg-bad-signature + +Permit decision with invalid signature. + +## What It Tests + +The pack mutates a signed issuance-time permit decision binding: The binding signature is produced by an untrusted key while the canonical payload still names the trusted key. + +## Expected Verdict + +`permit.decision.v1` is expected to return `disproved` with `PERMIT_DECISION_SIGNATURE_INVALID`. diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-bad-signature/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-bad-signature/pack/export.json new file mode 100644 index 0000000..007cd6b --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-bad-signature/pack/export.json @@ -0,0 +1,49 @@ +{ + "fixture_id": "permit-decision-neg-bad-signature", + "permit_decision": { + "artifact_type": "permit_decision_binding", + "artifact_version": "permit.decision.v1", + "binding_canonical_hash": "94c1dd7b35f1b09cba2cad6334021d2cdb586468d4c447a47867d79d91d2412f", + "binding_issued_at": "2026-05-21T10:00:00.000000Z", + "binding_key_id": "6c8f8607dbe87077", + "binding_signature": "ed25519:0MlQsB+ODoxfXptuLJtwhpw3LiCC+K3XLT9Vq9+P28Oa6MfUqOszDO/PaqXHid4IcXev7S6RdxGR0EWVhudiBw==", + "canonical_payload": { + "action_name": "chat.completion", + "binding_key_id": "6c8f8607dbe87077", + "binding_version": "v1", + "constraints": { + "max_output_tokens": 512, + "temperature_max": 1 + }, + "decision": "allow", + "expires_at": "2026-05-21T11:00:00.000000Z", + "final_request_hash": null, + "is_dry_run": false, + "issued_at": "2026-05-21T10:00:00.000000Z", + "model": "gpt-4o-mini", + "operation": "responses.create", + "parent_permit_id": null, + "permit_id": "10000000-0000-4000-8000-000000000101", + "policy_id": "policy:step4-fixture", + "policy_snapshot_hash": "dc63f1212028c980e553f4b57380dd61f4bdd2b41695ef49228478643367f8a5", + "policy_version": "v2026-05-21", + "project_id": "00000000-0000-0000-0000-000000000041", + "provider": "openai", + "reason": "Fixture allow decision.", + "request_fingerprint": "5423af31c63837ac99f58353252aeed7058fb739b84340a170c694c9f099e49d", + "routing": { + "fallback_chain": [], + "fallback_occurred": false, + "reason_code": "fixture.primary", + "reason_metadata": {}, + "requested_model": "gpt-4o-mini", + "requested_provider": "openai", + "selected_model": "gpt-4o-mini", + "selected_provider": "openai" + } + }, + "expected_decision": "allow" + }, + "project_id": "00000000-0000-0000-0000-000000000041", + "schema": "keel.step4.permit_claim_fixture/v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-bad-signature/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-bad-signature/pack/manifest.json new file mode 100644 index 0000000..e6d445a --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-bad-signature/pack/manifest.json @@ -0,0 +1,47 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.decision.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:d3dc086ef7b3d0e1ead81be62c042a6404e14bd3073e9579b723c137f1611984", + "export_id": "permit-decision-neg-bad-signature", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 1, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:4fad85a1ab652b6ebc5dd15fd3264025eee400914478dcd4f726c480c34ce70c", + "id": "keel.permit.decision.v1", + "path": "semantics/permit/decision_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:6r24FXGGSyz16xGUNwrYSmFOuSXugsOFfwTuvjOOhfAz7lC4eqznxXz3MTJ7ZnlD3XMuXstC71xOwvcWarPUDQ==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-canonical-payload-mismatch/README.md b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-canonical-payload-mismatch/README.md new file mode 100644 index 0000000..10cce7f --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-canonical-payload-mismatch/README.md @@ -0,0 +1,11 @@ +# permit-decision-neg-canonical-payload-mismatch + +Permit decision canonical payload mismatch. + +## What It Tests + +The pack mutates a signed issuance-time permit decision binding: The signed canonical payload is valid, but the requested decision evidence expects a different decision. + +## Expected Verdict + +`permit.decision.v1` is expected to return `disproved` with `PERMIT_DECISION_CANONICAL_PAYLOAD_MISMATCH`. diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-canonical-payload-mismatch/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-canonical-payload-mismatch/pack/export.json new file mode 100644 index 0000000..b6f6144 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-canonical-payload-mismatch/pack/export.json @@ -0,0 +1,49 @@ +{ + "fixture_id": "permit-decision-neg-canonical-payload-mismatch", + "permit_decision": { + "artifact_type": "permit_decision_binding", + "artifact_version": "permit.decision.v1", + "binding_canonical_hash": "d6af0065ae8f45dbe610c090ce10405e161ce74e1e78cb1d96e1690a86529054", + "binding_issued_at": "2026-05-21T10:00:00.000000Z", + "binding_key_id": "6c8f8607dbe87077", + "binding_signature": "ed25519:+aAf3/pOGHba+sPStPv6MWyKcRwYuizNUMuDlGv+6kPR50Wa9ldMyzT2nt0mtz15DfVF0sOHDpCC2lW3IYH1DA==", + "canonical_payload": { + "action_name": "chat.completion", + "binding_key_id": "6c8f8607dbe87077", + "binding_version": "v1", + "constraints": { + "max_output_tokens": 512, + "temperature_max": 1 + }, + "decision": "allow", + "expires_at": "2026-05-21T11:00:00.000000Z", + "final_request_hash": null, + "is_dry_run": false, + "issued_at": "2026-05-21T10:00:00.000000Z", + "model": "gpt-4o-mini", + "operation": "responses.create", + "parent_permit_id": null, + "permit_id": "10000000-0000-4000-8000-000000000104", + "policy_id": "policy:step4-fixture", + "policy_snapshot_hash": "05f2bb2030f01e42cfb83167051477f5be3430a2f5e3c4c4befb2c22a0958305", + "policy_version": "v2026-05-21", + "project_id": "00000000-0000-0000-0000-000000000041", + "provider": "openai", + "reason": "Fixture allow decision.", + "request_fingerprint": "e26a0be3c2a89fc840350bbdcad007853e4bc99df698f55c551821fa5b0a8070", + "routing": { + "fallback_chain": [], + "fallback_occurred": false, + "reason_code": "fixture.primary", + "reason_metadata": {}, + "requested_model": "gpt-4o-mini", + "requested_provider": "openai", + "selected_model": "gpt-4o-mini", + "selected_provider": "openai" + } + }, + "expected_decision": "deny" + }, + "project_id": "00000000-0000-0000-0000-000000000041", + "schema": "keel.step4.permit_claim_fixture/v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-canonical-payload-mismatch/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-canonical-payload-mismatch/pack/manifest.json new file mode 100644 index 0000000..d4ad045 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-canonical-payload-mismatch/pack/manifest.json @@ -0,0 +1,47 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.decision.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:6d7e20429987ec865b645c333605bad79ab86b55048d8242ec87f87ec6fa3b20", + "export_id": "permit-decision-neg-canonical-payload-mismatch", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 1, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:4fad85a1ab652b6ebc5dd15fd3264025eee400914478dcd4f726c480c34ce70c", + "id": "keel.permit.decision.v1", + "path": "semantics/permit/decision_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:JVUKuW606nS+ux3A5NiXFCJ6QE3w3xIIlUYg5bKFwM3vmhrLrbhl5TRxgZoLhRAIVvqR5HDB7t1MUyyoThNkAA==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-tampered-decision/README.md b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-tampered-decision/README.md new file mode 100644 index 0000000..e23c063 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-tampered-decision/README.md @@ -0,0 +1,11 @@ +# permit-decision-neg-tampered-decision + +Permit decision with tampered canonical decision. + +## What It Tests + +The pack mutates a signed issuance-time permit decision binding: The signed canonical payload decision is changed after the canonical hash and signature are produced. + +## Expected Verdict + +`permit.decision.v1` is expected to return `disproved` with `PERMIT_DECISION_CANONICAL_HASH_MISMATCH`. diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-tampered-decision/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-tampered-decision/pack/export.json new file mode 100644 index 0000000..e36386d --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-tampered-decision/pack/export.json @@ -0,0 +1,49 @@ +{ + "fixture_id": "permit-decision-neg-tampered-decision", + "permit_decision": { + "artifact_type": "permit_decision_binding", + "artifact_version": "permit.decision.v1", + "binding_canonical_hash": "b2f71a6c91f1b5d288c727f4a6235870d74a72643fac9f5e0d1b6a428e5fe407", + "binding_issued_at": "2026-05-21T10:00:00.000000Z", + "binding_key_id": "6c8f8607dbe87077", + "binding_signature": "ed25519:uUSYtlpZxRT/N7skN9fKQZj4m7Ha/oigfHSQlvdb3T/7n+XSdV5g2S3/UkKQiMkzrS/mBK4O/iPGQRWkqSstCA==", + "canonical_payload": { + "action_name": "chat.completion", + "binding_key_id": "6c8f8607dbe87077", + "binding_version": "v1", + "constraints": { + "max_output_tokens": 512, + "temperature_max": 1 + }, + "decision": "allow", + "expires_at": "2026-05-21T11:00:00.000000Z", + "final_request_hash": null, + "is_dry_run": false, + "issued_at": "2026-05-21T10:00:00.000000Z", + "model": "gpt-4o-mini", + "operation": "responses.create", + "parent_permit_id": null, + "permit_id": "10000000-0000-4000-8000-000000000102", + "policy_id": "policy:step4-fixture", + "policy_snapshot_hash": "6a65353347cb3cda262c71b4fc8b0e01ce00c7bc26c86250784672f7e45ef51a", + "policy_version": "v2026-05-21", + "project_id": "00000000-0000-0000-0000-000000000041", + "provider": "openai", + "reason": "Fixture deny decision.", + "request_fingerprint": "cfaebd49c9afbc68392af168eb90c9c3e48cb139fb3082fa90ab2b6478e8ed37", + "routing": { + "fallback_chain": [], + "fallback_occurred": false, + "reason_code": "fixture.primary", + "reason_metadata": {}, + "requested_model": "gpt-4o-mini", + "requested_provider": "openai", + "selected_model": "gpt-4o-mini", + "selected_provider": "openai" + } + }, + "expected_decision": "deny" + }, + "project_id": "00000000-0000-0000-0000-000000000041", + "schema": "keel.step4.permit_claim_fixture/v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-tampered-decision/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-tampered-decision/pack/manifest.json new file mode 100644 index 0000000..d044e5c --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-tampered-decision/pack/manifest.json @@ -0,0 +1,47 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.decision.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:1da35f1f45f2905982abfef9ab24655b10c17635e03b88ac5724d2c70275cac0", + "export_id": "permit-decision-neg-tampered-decision", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 1, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:4fad85a1ab652b6ebc5dd15fd3264025eee400914478dcd4f726c480c34ce70c", + "id": "keel.permit.decision.v1", + "path": "semantics/permit/decision_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:J6CyMxKBEvF+BtBdz+1CXoBTPCgVO+wrKd0dKB5skCnNn7z3uXu8+pBERB6rveWTX8V/rK6W/UGwzgnZA+2DAQ==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-untrusted-key/README.md b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-untrusted-key/README.md new file mode 100644 index 0000000..49c9f4b --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-untrusted-key/README.md @@ -0,0 +1,11 @@ +# permit-decision-neg-untrusted-key + +Permit decision signed by untrusted key. + +## What It Tests + +The pack mutates a signed issuance-time permit decision binding: The binding is internally valid but names a permit-binding key absent from the public trust root. + +## Expected Verdict + +`permit.decision.v1` is expected to return `insufficient_evidence` with `PERMIT_DECISION_UNTRUSTED_KEY`. diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-untrusted-key/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-untrusted-key/pack/export.json new file mode 100644 index 0000000..1b13c17 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-untrusted-key/pack/export.json @@ -0,0 +1,49 @@ +{ + "fixture_id": "permit-decision-neg-untrusted-key", + "permit_decision": { + "artifact_type": "permit_decision_binding", + "artifact_version": "permit.decision.v1", + "binding_canonical_hash": "0b365b5d355d465f4c146b0f6c40bcfcd6099f65508cd9c2311186d14eee9c76", + "binding_issued_at": "2026-05-21T10:00:00.000000Z", + "binding_key_id": "b14705888f4a6839", + "binding_signature": "ed25519:PanJH+3uh+TN8DvOuw7ly26qHU6K1anwpJE1voiMsLgjB2TFPPEvvMcyC5y1b38692j7hykSyzdfmbIIYU+3Bw==", + "canonical_payload": { + "action_name": "chat.completion", + "binding_key_id": "b14705888f4a6839", + "binding_version": "v1", + "constraints": { + "max_output_tokens": 512, + "temperature_max": 1 + }, + "decision": "allow", + "expires_at": "2026-05-21T11:00:00.000000Z", + "final_request_hash": null, + "is_dry_run": false, + "issued_at": "2026-05-21T10:00:00.000000Z", + "model": "gpt-4o-mini", + "operation": "responses.create", + "parent_permit_id": null, + "permit_id": "10000000-0000-4000-8000-000000000103", + "policy_id": "policy:step4-fixture", + "policy_snapshot_hash": "0d8715fd177dd4df5b42a6995915c31fe89efb4e58dfd8cad49cb3d10622a78d", + "policy_version": "v2026-05-21", + "project_id": "00000000-0000-0000-0000-000000000041", + "provider": "openai", + "reason": "Fixture allow decision.", + "request_fingerprint": "9db5bc0e46777ca5f8d17e57041a9eaef1d3da801e16117230ea531422aa2fd0", + "routing": { + "fallback_chain": [], + "fallback_occurred": false, + "reason_code": "fixture.primary", + "reason_metadata": {}, + "requested_model": "gpt-4o-mini", + "requested_provider": "openai", + "selected_model": "gpt-4o-mini", + "selected_provider": "openai" + } + }, + "expected_decision": "allow" + }, + "project_id": "00000000-0000-0000-0000-000000000041", + "schema": "keel.step4.permit_claim_fixture/v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-untrusted-key/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-untrusted-key/pack/manifest.json new file mode 100644 index 0000000..13665d1 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-decision-neg-untrusted-key/pack/manifest.json @@ -0,0 +1,47 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.decision.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:8da042fd1ef2f96afcd38dc83e9c4213e95912aa0184aa3e285682562de58343", + "export_id": "permit-decision-neg-untrusted-key", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 1, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:4fad85a1ab652b6ebc5dd15fd3264025eee400914478dcd4f726c480c34ce70c", + "id": "keel.permit.decision.v1", + "path": "semantics/permit/decision_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:+/u08OP6NzSdlazIyic6yGP8cH3njzNNbXh7ql36IvR9bpDlyLdQOLVCWbMRELIA+bVD40+CZpfRaD+5RpmdAA==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-actor-pii-detected/README.md b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-actor-pii-detected/README.md new file mode 100644 index 0000000..5a2b02f --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-actor-pii-detected/README.md @@ -0,0 +1,11 @@ +# permit-revoked-neg-actor-pii-detected + +Permit revocation actor identity contains PII. + +## What It Tests + +The pack mutates signed `permit.revoked` evidence: The signed actor_id uses an email-address shape instead of an opaque UUID. + +## Expected Verdict + +`permit.revoked.v1` is expected to return `disproved` with `PERMIT_REVOKED_ACTOR_PII_DETECTED`. diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-actor-pii-detected/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-actor-pii-detected/pack/export.json new file mode 100644 index 0000000..ea4ab9c --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-actor-pii-detected/pack/export.json @@ -0,0 +1,19 @@ +{ + "fixture_id": "permit-revoked-neg-actor-pii-detected", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "revocation_event": { + "canonical_hash": "c3fa0e5eb2b8182e1e9cbb2a939839fbd5727727e7fd5d1784e7cb65a1edeba0", + "event": { + "actor_id": "operator@example.com", + "actor_kind": "user", + "effective_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z", + "signature": "z5EHy72KgFFyQdhakI97l6XzTfAdFfrb4zdSnV4Mxg/TLjNE70R+VIfwCR9Guj+PYFKqsZVR6zjDeAka6AO2BA==" + } + }, + "schema": "keel.step4.permit_claim_fixture/v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-actor-pii-detected/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-actor-pii-detected/pack/manifest.json new file mode 100644 index 0000000..e96fc99 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-actor-pii-detected/pack/manifest.json @@ -0,0 +1,47 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.revoked.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:c68a7b43bf450432e910097d480a7d81562fc118a4a3ff47aaa20ad6a778b67b", + "export_id": "permit-revoked-neg-actor-pii-detected", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 1, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:5b7416b11a4a94a2f9f876b2337e118267ab5eb928165cc15f01abaff8639229", + "id": "keel.permit.revoked_event.v1", + "path": "semantics/permit/revoked_event_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:CndMynv2WGFknFt2w6vRRshrR+krNyeNGgJDmuvEgogIwQBQ43EOQ+9qPWR+GKn94d91JnBY3ZrqUQKnxHgpBg==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-bad-signature/README.md b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-bad-signature/README.md new file mode 100644 index 0000000..9b100dd --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-bad-signature/README.md @@ -0,0 +1,11 @@ +# permit-revoked-neg-bad-signature + +Permit revocation with invalid signature. + +## What It Tests + +The pack mutates signed `permit.revoked` evidence: The revocation event signature is produced by a key outside the public permit-binding trust root. + +## Expected Verdict + +`permit.revoked.v1` is expected to return `disproved` with `PERMIT_REVOKED_SIGNATURE_INVALID`. diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-bad-signature/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-bad-signature/pack/export.json new file mode 100644 index 0000000..382cbf3 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-bad-signature/pack/export.json @@ -0,0 +1,19 @@ +{ + "fixture_id": "permit-revoked-neg-bad-signature", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "revocation_event": { + "canonical_hash": "988d47a4ae347d0b4f49866fc2414acec0139c4be103f3491ae53fd6f2cfe2b2", + "event": { + "actor_id": "30000000-0000-4000-8000-000000000001", + "actor_kind": "user", + "effective_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z", + "signature": "4B8/G3eghrx9bMlsCWWsWIrIaEUpKkTH2A7xWKaSSODrhL4S/4DSMotLyszqdAh4vRnqt+bukdZPJVLHQ9xiBw==" + } + }, + "schema": "keel.step4.permit_claim_fixture/v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-bad-signature/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-bad-signature/pack/manifest.json new file mode 100644 index 0000000..2d9e893 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-bad-signature/pack/manifest.json @@ -0,0 +1,47 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.revoked.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:a8a2998dd5039e8f6e55b3c78e98907f4efa7d7dd0609e38073b3e67a14682ab", + "export_id": "permit-revoked-neg-bad-signature", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 1, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:5b7416b11a4a94a2f9f876b2337e118267ab5eb928165cc15f01abaff8639229", + "id": "keel.permit.revoked_event.v1", + "path": "semantics/permit/revoked_event_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:m9mazqZsJbXYI26d3VTtvEOvf509QnHzxeq9uXz6z2BUmB5hVoxd0p/P8+ptHy2d0LGuCc6/LVL5Dw+/Y7TuAw==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-effective-at-mismatch/README.md b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-effective-at-mismatch/README.md new file mode 100644 index 0000000..396ff4c --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-effective-at-mismatch/README.md @@ -0,0 +1,11 @@ +# permit-revoked-neg-effective-at-mismatch + +Permit revocation effective_at mismatch. + +## What It Tests + +The pack mutates signed `permit.revoked` evidence: The signed revocation event uses an effective_at timestamp different from revoked_at, which v1 reserves for future scheduling semantics. + +## Expected Verdict + +`permit.revoked.v1` is expected to return `disproved` with `PERMIT_REVOKED_EFFECTIVE_AT_MISMATCH`. diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-effective-at-mismatch/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-effective-at-mismatch/pack/export.json new file mode 100644 index 0000000..1ce8463 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-effective-at-mismatch/pack/export.json @@ -0,0 +1,19 @@ +{ + "fixture_id": "permit-revoked-neg-effective-at-mismatch", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "revocation_event": { + "canonical_hash": "28dfe073c88e463e2b3cf9c029c6e693fdc709ae84586d2846c583171843cdcf", + "event": { + "actor_id": "30000000-0000-4000-8000-000000000001", + "actor_kind": "user", + "effective_at": "2026-05-21T10:06:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z", + "signature": "Sbindg3/IwYCpEUiBp/eiPSows20dSfGj1yk3dJN0UBYj6lZNseqc+Z+6kE3NqZxS0rKiJ3m1lAxqt8amuFGCA==" + } + }, + "schema": "keel.step4.permit_claim_fixture/v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-effective-at-mismatch/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-effective-at-mismatch/pack/manifest.json new file mode 100644 index 0000000..dd167af --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-effective-at-mismatch/pack/manifest.json @@ -0,0 +1,47 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.revoked.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:f399d523e7acf5dd6d21ae776cb2ca9806d73613cc23907e2dfb402fc65e0b37", + "export_id": "permit-revoked-neg-effective-at-mismatch", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 1, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:5b7416b11a4a94a2f9f876b2337e118267ab5eb928165cc15f01abaff8639229", + "id": "keel.permit.revoked_event.v1", + "path": "semantics/permit/revoked_event_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:Z5fDen6C+HvXIkJzpPy58+gx2XYbCvesAZbksgLe/A14/W1GyJjptiDI/j1UXIzIuFDaT2Fwe2CbRaHbbVMlAw==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-missing-field/README.md b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-missing-field/README.md new file mode 100644 index 0000000..2e2b08d --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-missing-field/README.md @@ -0,0 +1,11 @@ +# permit-revoked-neg-missing-field + +Permit revocation missing required field. + +## What It Tests + +The pack mutates signed `permit.revoked` evidence: The required reason_code field is removed from the signed revocation event evidence. + +## Expected Verdict + +`permit.revoked.v1` is expected to return `insufficient_evidence` with `PERMIT_REVOKED_EVIDENCE_MISSING`. diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-missing-field/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-missing-field/pack/export.json new file mode 100644 index 0000000..9a39019 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-missing-field/pack/export.json @@ -0,0 +1,18 @@ +{ + "fixture_id": "permit-revoked-neg-missing-field", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "revocation_event": { + "canonical_hash": "988d47a4ae347d0b4f49866fc2414acec0139c4be103f3491ae53fd6f2cfe2b2", + "event": { + "actor_id": "30000000-0000-4000-8000-000000000001", + "actor_kind": "user", + "effective_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "revoked_at": "2026-05-21T10:05:00.000000Z", + "signature": "ULWxnis0lPSVXh3Hw2di7GUwu/KPflmoKX2PsTkXua2IF53KPduIdYwXy7SkPyERq/FhiEecHBU0qDV0DBVHBw==" + } + }, + "schema": "keel.step4.permit_claim_fixture/v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-missing-field/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-missing-field/pack/manifest.json new file mode 100644 index 0000000..5ed05e6 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-missing-field/pack/manifest.json @@ -0,0 +1,47 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.revoked.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:c01f67872e8401f5e42573d6c84a4ba1f313301310adb2424dbc2dd69c7d92e7", + "export_id": "permit-revoked-neg-missing-field", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 1, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:5b7416b11a4a94a2f9f876b2337e118267ab5eb928165cc15f01abaff8639229", + "id": "keel.permit.revoked_event.v1", + "path": "semantics/permit/revoked_event_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:rM+x5xXiHxENYIRD7XFwmR52AOlBeUbYq4nGKY8VkK+PoD99KVXVaiYJJzrTu4Q+2P2nZvdfL1jAnDxTjb/GAw==", + "signed_at": "2026-05-21T10:00:00.000000Z" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-project-mismatch/README.md b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-project-mismatch/README.md new file mode 100644 index 0000000..db2c126 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-project-mismatch/README.md @@ -0,0 +1,11 @@ +# permit-revoked-neg-project-mismatch + +Permit revocation project mismatch. + +## What It Tests + +The pack mutates signed `permit.revoked` evidence: The export declares a different project scope than the signed revocation event. + +## Expected Verdict + +`permit.revoked.v1` is expected to return `disproved` with `PERMIT_REVOKED_PROJECT_ID_MISMATCH`. diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-project-mismatch/pack/export.json b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-project-mismatch/pack/export.json new file mode 100644 index 0000000..8ed1926 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-project-mismatch/pack/export.json @@ -0,0 +1,19 @@ +{ + "fixture_id": "permit-revoked-neg-project-mismatch", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000099", + "revocation_event": { + "canonical_hash": "988d47a4ae347d0b4f49866fc2414acec0139c4be103f3491ae53fd6f2cfe2b2", + "event": { + "actor_id": "30000000-0000-4000-8000-000000000001", + "actor_kind": "user", + "effective_at": "2026-05-21T10:05:00.000000Z", + "permit_id": "20000000-0000-4000-8000-000000000001", + "project_id": "00000000-0000-0000-0000-000000000041", + "reason_code": "operator.requested", + "revoked_at": "2026-05-21T10:05:00.000000Z", + "signature": "ULWxnis0lPSVXh3Hw2di7GUwu/KPflmoKX2PsTkXua2IF53KPduIdYwXy7SkPyERq/FhiEecHBU0qDV0DBVHBw==" + } + }, + "schema": "keel.step4.permit_claim_fixture/v1" +} diff --git a/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-project-mismatch/pack/manifest.json b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-project-mismatch/pack/manifest.json new file mode 100644 index 0000000..ce49085 --- /dev/null +++ b/test-vectors/verifier_claims/v0/fixtures/permit-revoked-neg-project-mismatch/pack/manifest.json @@ -0,0 +1,47 @@ +{ + "claim_set": { + "claims": [ + { + "name": "export.integrity.v1", + "required": true + }, + { + "name": "permit.revoked.v1", + "required": true + } + ], + "registry": { + "hash": "sha256:8da29094827fda581ee8fb3a1466934182e572a91b7940d2ef1cb3c28c1ec215", + "id": "keel.verifier_claim_registry.v0", + "path": "claim_registry/v0.json" + }, + "version": "verifier-claims.v0" + }, + "compressed": false, + "content_hash": "sha256:45315d647db8be9dce49f68eac6c10c879593e78ed6700f377f2f4a553bed6a7", + "export_id": "permit-revoked-neg-project-mismatch", + "export_type": "audit_export", + "format": "json", + "key_id": "sha256:10ba682c8ad13513971e8b56881aab8b", + "project_id": "00000000-0000-0000-0000-000000000041", + "public_key": "ed25519:0EqyMnQrtKs6E2i9RhXk5tAiSrcaAWuvhSCjMsl3hzc=", + "record_count": 1, + "semantics_pins": { + "artifacts": [ + { + "hash": "sha256:d1d67dca7eb9a662d26463c3dec841f47f8791df2fafb21e911dd26a83dabb76", + "id": "keel.export_manifest.integrity.v1", + "path": "semantics/export_manifest/integrity_v1.json" + }, + { + "hash": "sha256:5b7416b11a4a94a2f9f876b2337e118267ab5eb928165cc15f01abaff8639229", + "id": "keel.permit.revoked_event.v1", + "path": "semantics/permit/revoked_event_v1.json" + } + ], + "mode": "pinned", + "version": "keel-semantics-pins.v0" + }, + "signature": "ed25519:K9/NL30QPqxykwpcGt1AtXMyymSrCJ+5Py6Tv824cGhqbdF69q+7SanOYgMpBPNKANPRur5z0m1qt85h7ywTAA==", + "signed_at": "2026-05-21T10:00:00.000000Z" +}