{"run_id":"pr_60d8d713b34741ce844e","created_at":"2026-10-01T22:28:39.705628+00:00","environment":{"python":"3.14.4","platform":"Linux-7.0.0-30-generic-x86_64-with-glibc2.43","deployment":"studio","fabric_enforce":"true","approval_enforce":"false","verify_enforce":"true","require_intent":"false","hostname":"unknown"},"results":[{"check_id":"fail-closed.unknown-never-allows","claim":"A stage that could not run never reads as permission.","category":"Fail-closed","label":"VERIFIED","passed":true,"observed":"ALLOWED_DEGRADED","detail":"an unavailable stage yields ALLOWED_DEGRADED, which is distinguishable from ALLOWED, so a client in strict mode refuses it","method":"Derive a verdict from a stage with verdict=unavailable and enforcing=true, using the same function the live path uses.","reproduce":"pytest tests/test_fabric.py -k degraded","limitations":"Checks the verdict function. A caller that ignores ALLOWED_DEGRADED can still proceed; strict mode in the SDK is what refuses it.","duration_ms":0,"executed_at":"2026-10-01T22:28:39.280658+00:00","result_sha256":"d581084307896b26e67bc1912672805d1f1f41b284f6278b8b2f6cab9771ee0a"},{"check_id":"enforcement.denial-blocks","claim":"An enforcing denial blocks the action.","category":"Enforcement","label":"VERIFIED","passed":true,"observed":"BLOCKED","detail":"an enforcing denial blocks","method":"derive_outcome with an enforcing deny.","reproduce":"pytest tests/test_fabric.py -k blocked","limitations":"Verdict derivation only; the gateway's action on `blocked` is covered by separate tests.","duration_ms":0,"executed_at":"2026-10-01T22:28:39.280923+00:00","result_sha256":"894cb4cf0bc5e1312edbab24b9e205e3a14569482f81f77f65b5c920e1073288"},{"check_id":"enforcement.shadow-does-not-block","claim":"In shadow mode the fabric records denials and blocks nothing.","category":"Enforcement","label":"SHADOW","passed":true,"observed":"ALLOWED_WITH_DENIALS","detail":"in shadow mode the denial is recorded and reported, and the call is not blocked -- deliberately, and visible in the verdict","method":"derive_outcome with enforce=false.","reproduce":"pytest tests/test_fabric.py -k shadow","limitations":"This is the DESIRED behaviour in shadow mode, not a security property. Labelled SHADOW so it is never read as 'protection is active'.","duration_ms":0,"executed_at":"2026-10-01T22:28:39.280959+00:00","result_sha256":"ea1ebea9fd5bed1950e83efa9f10e6df15609310bf1fed5e39696e55640443ff"},{"check_id":"incident.kill-switch-overrides-shadow","claim":"The kill switch blocks even when the fabric is in shadow mode.","category":"Incident control","label":"VERIFIED","passed":true,"observed":"BLOCKED","detail":"a halt blocks even with the fabric in shadow mode; a stop button that honours an observability setting is not one","method":"derive_outcome with enforce=false and halted=true.","reproduce":"pytest tests/test_fabric.py -k kill_switch","limitations":"Covers verdict derivation and the recorded halt flag.","duration_ms":0,"executed_at":"2026-10-01T22:28:39.281196+00:00","result_sha256":"f245c5fd075f00fb3d7c85a5979a735041fddde2b2d67abcf194d955694e6b54"},{"check_id":"chain.eleven-stages","claim":"Every consequential action is recorded across eleven stages.","category":"Traceability","label":"VERIFIED","passed":true,"observed":["identity","intent","policy","authorization","risk","verification","actionproof","approval","mcpgate","execution","evidence"],"detail":"the canonical chain has 11 stages","method":"Read the canonical chain from the registry every surface derives from.","reproduce":"python3 -c \"import canonical; print(canonical.TRUST_CHAIN)\"","limitations":"Confirms the canonical definition. That live decisions actually carry all eleven is covered by test_clean_call_is_allowed_and_records_every_stage.","duration_ms":48,"executed_at":"2026-10-01T22:28:39.329468+00:00","result_sha256":"7ccdc03a4dd5a0371687b3ab5b91884354e367aa947e53d9afb3f680195ced10"},{"check_id":"replay.approval-single-use","claim":"A granted approval can be spent exactly once.","category":"Replay protection","label":"VERIFIED","passed":true,"observed":{"first_consume":true,"second_consume":false},"detail":"the second attempt to spend an approval fails, so a granted approval cannot be replayed","method":"Grant an approval, consume it twice against the real store.","reproduce":"pytest tests/test_fabric.py -k single_use","limitations":"Sequential, not concurrent. The atomicity guarantee comes from the UPDATE's WHERE clause and is covered separately.","duration_ms":19,"executed_at":"2026-10-01T22:28:39.348635+00:00","result_sha256":"831d503ab405d53b07eb202d98e417381c0b4a37637cb819e9bb890af2f81899"},{"check_id":"authz.no-self-approval","claim":"A principal cannot approve its own held action.","category":"Authorization","label":"VERIFIED","passed":true,"observed":{"refused":true,"status":403},"detail":"the requesting principal cannot approve its own request","method":"Request an approval, then attempt to resolve it as the requester.","reproduce":"pytest tests/test_fabric.py -k own_request","limitations":"Identity is the principal id; it does not prove two humans are involved, only two principals.","duration_ms":4,"executed_at":"2026-10-01T22:28:39.353101+00:00","result_sha256":"aed109b3c1c17605a577b6e3d8d1f291fcfed9e6b3cfd01044a70bb6e586d8f6"},{"check_id":"authz.stale-approvals-expire","claim":"A pending approval expires on its own.","category":"Authorization","label":"VERIFIED","passed":true,"observed":"expired","detail":"a pending request past its deadline becomes expired on read, with no scheduler required","method":"Backdate a pending request's deadline and read it back.","reproduce":"pytest tests/test_fabric.py -k expire","limitations":"Expiry is evaluated on read; a request nobody reads stays pending in the table until it is.","duration_ms":4,"executed_at":"2026-10-01T22:28:39.358003+00:00","result_sha256":"e3a30a4a2b3d44a2acdfcac287fe91d79f4c499634dbedc02499ef450964473b"},{"check_id":"isolation.approvals-tenant-scoped","claim":"One tenant cannot read another tenant's approvals.","category":"Tenant isolation","label":"VERIFIED","passed":true,"observed":{"visible_to_other_tenant":false},"detail":"another tenant reading a known id gets not-found, so ids cannot be probed for existence","method":"Create an approval in one tenant, read it as another.","reproduce":"pytest tests/test_fabric.py -k tenant_scoped","limitations":"Covers the approval surface. Decisions, evidence and events have their own isolation tests.","duration_ms":2,"executed_at":"2026-10-01T22:28:39.360321+00:00","result_sha256":"5e33e7fe2a15522df47207a18d316429221cc626e0e032921af9d0f2b1158853"},{"check_id":"evidence.tamper-evident","claim":"An edit to a recorded decision is detectable.","category":"Evidence integrity","label":"VERIFIED","passed":true,"observed":{"intact_before":true,"intact_after_edit":false},"detail":"editing a stored decision breaks its digest and the edit is detected","method":"Record a decision, verify its digest, edit the row, verify again.","reproduce":"pytest tests/test_fabric.py -k tampered","limitations":"Tamper-EVIDENT, not tamper-proof. The digest is unkeyed: anyone able to write the row can recompute it. There is no append-only log and no external key.","duration_ms":4,"executed_at":"2026-10-01T22:28:39.364486+00:00","result_sha256":"c1745d080e20d232cf21b861a9a5a1b361a1c82f705c5cb2f23b8da97d253d48"},{"check_id":"ssrf.webhook-targets-refused","claim":"Webhook targets on internal addresses are refused.","category":"SSRF","label":"VERIFIED","passed":true,"observed":{"refused":5,"accepted":[]},"detail":"webhook targets on loopback, private ranges and the cloud metadata endpoint are refused before any request is made","method":"Submit loopback, private, link-local and non-HTTP URLs to the validator used at registration and before every delivery.","reproduce":"pytest tests/test_webhooks.py -k refused","limitations":"DNS is resolved at check time. A name that resolves publicly here and privately elsewhere is handled by re-validating before each delivery attempt, not by this check.","duration_ms":6,"executed_at":"2026-10-01T22:28:39.370830+00:00","result_sha256":"2d3e944dc1a84c363ce71c3e76f78575be33bec40e39cdf9c59b97f54890f0d8"},{"check_id":"crypto.webhook-signature-binds-timestamp","claim":"Webhook signatures cannot be replayed with a fresh timestamp.","category":"Cryptographic provenance","label":"VERIFIED","passed":true,"observed":{"differs_with_timestamp":true},"detail":"the timestamp is inside the signed material, so a captured delivery cannot be replayed with a fresh header","method":"Sign identical bodies at two timestamps and compare.","reproduce":"pytest tests/test_webhooks.py -k timestamp","limitations":"HMAC with a shared secret stored in our database. It authenticates the sender to the receiver; it is not a signature a third party can verify independently.","duration_ms":0,"executed_at":"2026-10-01T22:28:39.371002+00:00","result_sha256":"d6b994092a5a61c75113dd5c3c2332f05142e20b6ba7e50949826ba4b01fb564"},{"check_id":"performance.decision-write-latency","claim":"Recording a decision is fast enough to sit on a request path.","category":"Performance","label":"VERIFIED","passed":true,"observed":{"samples":200,"p50_ms":0.866,"p95_ms":5.397,"p99_ms":12.524,"mean_ms":1.564},"detail":"evidence-write latency only: this measures recording a decision, NOT the end-to-end request path, which includes network, OPA and ActionProof","method":"200 sequential record_decision calls against the real store, reporting p50/p95/p99.","reproduce":"POST /proof/run and read performance.decision-write-latency","limitations":"Evidence-write latency ONLY. It excludes network, OPA, ActionProof and the proxied upstream, so it is a floor for end-to-end latency and must not be quoted as one.","duration_ms":314,"executed_at":"2026-10-01T22:28:39.685399+00:00","result_sha256":"4493fa965ad58489945fe6789f89f5b091ec251b7fbc30c72487fef7f90a7eec"}],"passed":13,"failed":0,"total":13,"prev_hash":null,"run_hash":"23c9d6924daf273e22d578aca6bbf3ed9ef3d27c023f9a37b15fd63ae441a623","chain":{"runs":1,"intact":true,"problems":[],"guarantee":"tamper-evident","not":"tamper-proof. Whoever can write this table can recompute the chain. An external notary or an append-only store would be required for more, and neither exists here."},"labels_explained":{"VERIFIED":"executed just now, and passed","FAILED":"executed just now, and failed","HEURISTIC":"passed, but the mechanism is a rule of thumb","SHADOW":"recorded but not enforcing on this deployment","SIMULATED":"measured against a stand-in, not the real thing","UNVERIFIED":"not checked -- never render this as a pass","ERROR":"the check itself broke; not a pass"}}