{"domain":"witness.getvda.ai","count":4,"changes":[{"captured_at":"2026-08-19T11:28:23","card_hash":"9eb3ac3e2e1c70d0413edfa389e76acb93b5a454e984b782710bc0d05835b6a9","previous_card_hash":"582120a763369a148eb3f7d61ab54df92dcb837e924a3126f84b872855dff28a","diff":{"skills_added":[],"skills_removed":[],"skills_changed":[],"fields_changed":[],"other_changed":true,"is_empty":false,"human_summary":"internal fields changed"}},{"captured_at":"2026-08-18T20:35:07","card_hash":"582120a763369a148eb3f7d61ab54df92dcb837e924a3126f84b872855dff28a","previous_card_hash":"8981373d808cfe785df2654c0466fb56ee1cf56294023441396aef726e21fb8e","diff":{"skills_added":[],"skills_removed":[],"skills_changed":[],"fields_changed":[],"other_changed":true,"is_empty":false,"human_summary":"internal fields changed"}},{"captured_at":"2026-08-18T09:51:53","card_hash":"8981373d808cfe785df2654c0466fb56ee1cf56294023441396aef726e21fb8e","previous_card_hash":"d5d70b93e47cd047b13842c68be1642e72e97f688636d27e5f14576312317475","diff":{"skills_added":[],"skills_removed":[],"skills_changed":[],"fields_changed":[],"other_changed":true,"is_empty":false,"human_summary":"internal fields changed"}},{"captured_at":"2026-08-18T02:23:00","card_hash":"d5d70b93e47cd047b13842c68be1642e72e97f688636d27e5f14576312317475","previous_card_hash":null,"diff":{"skills_added":[{"id":"check_valid","name":"Check a credential's validity","description":"CONTRACT B — the public credential-verification endpoint. Is this admission credential currently valid? PUBLIC, no key: input is a credential_id; anyone holding one can verify it, which is what makes issuer-issued credentials verifiable-by-anyone (their whole value). Witness returns the single canonical verdict — issued ∧ signature verifies ∧ not revoked by the issuer ∧ not expired — so every enforcer is identically correct and the meaning of 'valid' evolves in ONE place, never drifting across independent implementations (the reason this is a skill and not a two-call recipe). Response {valid, code, subject, issuer, environment, scope, expires_at, revoked, revoked_at?, reason_code?, issuer_verified, issuer_verification}; code is 'valid' | 'revoked' | 'expired' | 'not_found' | 'not_credential'. PUBLIC — no key (a credential id is not a secret; CRL/OCSP posture). Cache-Control: private, max-age=60. issuer_verified is a DISTINCT signal from the lifecycle verdict — issuer-authenticity: 'verified' (customer-managed record signed by a key published in issuer_did's DID document — provable even against Witness), 'key_not_in_did_doc' (LOUD: claims an issuer but signed by a key not in its DID — suspicious), 'custodial' (Witness-signed; issuer-authenticity not established, only integrity/anchoring), or 'did_unresolvable' (the check did not complete; not verified AND not forged). Set your own bar: a high-stakes environment may require issuer_verified:true; a low-stakes one may accept custodial. TWO enforcer disciplines the schema teaches: (1) a credential id is a BEARER handle — a valid credential is necessary, NOT sufficient; you MUST separately challenge the presenter to prove control of `subject` (a DID challenge), because validity is not proof the presenter is the subject. (2) Record each check_valid response in YOUR OWN audit log (timestamp, credential_id, response) — Witness's cache and logs tell you what was returned, but only your local record proves what YOU acted on and when, when a regulator later asks how you knew the credential was valid at time T.","tags":["credential","verification","revocation","enforcement"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"issue_admission_credential","name":"Issue an admission credential","description":"Issue an agent admission credential — a sealed attestation admitting an agent (subject_did) to a customer environment with a scope, valid until expiry. The Witness record IS the credential (no separate document): enforcers hold only the credential id and check it via check_valid (Contract B); it is revocable via revoke_admission_credential. Sealed by the issuer's Witness account — only that account can revoke. subject_did / environment_id / scope / compliance_mappings are ASSERTED, not authenticated by Witness (the admission workflow establishes them; Witness records the claim). Records are immutable — validity is computed at verify time, never mutated. HOLDER-BINDING: the credential id is a bearer handle — issuing it does not bind the holder; the ENFORCER must separately prove the presenter controls subject_did (see check_valid). PROVISIONAL is representable honestly: sandbox_result.pass may be false and score null ('not run'), and evidence_seal_ref may point at an honest stub — a credential can truthfully record a conditional / not-yet-passed admission rather than forcing a passing claim.","tags":["credential","admission","attestation","ed25519"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"provision","name":"Self-provision an account (no human)","description":"Self-issue a SEALED-tier API key in-band with no human. Pass an Ed25519 controller PUBLIC key (`controllerPublicKeyJwk`) to claim a DURABLE, self-renewable account bound to a key you hold — otherwise the account auto-expires ~7 days. Sealed tier = signed + hash-chained + independently verifiable OFFLINE, but NOT externally anchored (terminal — it stays sealed). The Anchored tier (externally committed, \"provable even against us\") is concierge-provisioned separately. Then `renew` re-keys the same account forever. See also `provisioning.selfServeKey`.","tags":["provisioning","self-serve","ed25519"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"read","name":"Read your own records","description":"Read back what you've sealed (operational query, account-scoped by your key — never an accountId param). `list_records` returns paginated summaries + the set of chainKeys in your account (discover your own chains); `get_record` returns the FULL signed body of one record. For OFFLINE verification of chain continuity with ZERO calls back to Witness, fetch a self-contained proof bundle: `GET /records/{recordId}?proof=chain` (record + full chain + anchor attestation + did.json) or `GET /chains/{chainKey}/proof` (whole trail). Feed it to `offlineVerify({record, chain, anchor, didDocument})` — verdicts: ANCHORED_VALID / SIGNED_PENDING / BROKEN / INSUFFICIENT_PROOF (the last means proof material was missing, NOT tampering). Distinct from `report` (Article-12 artefact). Foreign/unknown id → not-found (no leak).","tags":["read","query","audit-trail"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"renew","name":"Renew a key (agent-provable, no human)","description":"Get a fresh short-TTL API key for an account you ALREADY control — indefinitely, with no human and no permanent secret. Two steps: POST /renew/challenge {accountId} → nonce; Ed25519-sign `vda.witness.renew/1|<accountId>|<nonce>` with your controller key; POST /renew {accountId, nonce, signature} → fresh key bound to the SAME account (chains continue, prev-hash unbroken). Bind the controller key at creation via `provisioning.selfServeKey.controllerPublicKeyJwk`.","tags":["credential","renewal","ed25519","self-serve"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"report","name":"Article 12 Evidence Report","description":"Generate an EU AI Act Article 12 evidence report from the sealed trail (API key required).","tags":["eu-ai-act","art-12","evidence"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"revoke_admission_credential","name":"Revoke an admission credential","description":"Revoke an admission credential your account issued. Only the issuing account may revoke (enforced structurally by comparing sealing accounts, not a DID string). Terminal — re-admission is a NEW credential. Produces a new immutable revocation attestation that supersedes the credential; verify_admission_credential reflects it within the ~60s cache window. Customers who want a credential revoked call the issuing service (onboard.getvda.ai), which owns revocation policy and executes here — customers do not call Witness directly.","tags":["credential","revocation","attestation"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"revoke_api_key","name":"Revoke an account API key (sealed as an event)","description":"Revoke one of your account's API keys — the key stops authenticating at once, and the revocation is itself sealed as a key_revocation attestation on your chain. TWO authorities: (1) CONTROLLER-AUTHORIZED, owner self-service, no operator — prepare a key_revocation via /prepare {skill:'revoke_api_key', params:{key_id, revoked_by:{type:'controller'}, reason_code}}, sign the canonical bytes with your BOUND CONTROLLER key, and POST { record } here. Witness verifies the signer IS your bound controller and that the key is yours; the record is customer-managed (owner-signed) so the revocation is provable AGAINST Witness, not merely asserted by it. (2) ADMIN break-glass (operator, x-witness-admin, { key_id }) — sealed custodially, revoked_by.type='operator'; the record honestly shows Witness asserted it. revoked_by.type is the trust distinction, not a code path. Revocation is TOTAL: a revoked key 401s at auth AND its account's records become unfetchable with it — there is NO operator backdoor to read a revoked account's records. Reflected in whoami: a revoked key 401s immediately (no-store); a sibling's ≤60s cached 200 is the only propagation lag.","tags":["revocation","key-management","custody","security"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"seal","name":"Seal (general-purpose / compatibility)","description":"General-purpose seal, retained for backward compatibility and for records that fit none of the shaped skills. PREFER a shaped skill so your record is auditor-reconstructable: seal_hitl_decision (a human decided), seal_agent_action (an agent acted), seal_attestation (you assert a fact/state). Records sealed here carry no record_type and report as unstructured. API key required; no key? see `provisioning.selfServeKey` or the MCP `get_test_key` tool.","tags":["evidence","ed25519","audit","compatibility"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"seal_agent_action","name":"Seal an autonomous agent action","description":"Seals a record for an action an agent took AUTONOMOUSLY under a governing rule. Records what the agent consumed as two fields split by provenance: `evidence` is EXTERNAL material it saw (content-addressed + hashed — e.g. a whoami response from another service), `parameters` is the COMPUTED arguments it was passed (self-contained, no hash — e.g. requested scopes, jurisdictions). One-question test: exists outside this record? → evidence (hash it); computed/passed as an argument? → parameters. At least one is required (or evidence_omitted_reason). Optionally include agent_context — free-form execution-substrate hints (cloud_run_revision, model_name, region) so an auditor can ask 'was this at a known-buggy revision?'; asserted by you, not verified by Witness. For a human decision use seal_hitl_decision.","tags":["evidence","agent","governance","audit"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"seal_attestation","name":"Seal an attestation","description":"Seals an assertion that a fact or state held AS OF a point in time — a model passed an evaluation, a card was issued, a key was rotated, a config was live. Not for decisions (use the decision skills). Captures the asserting party, the claim, and the as-of time; supporting external references (evidence) are optional but strengthen it. Cite the framework via governing_basis, or it is sealed as attested-by-the-signing-party, not independently verified by Witness.","tags":["attestation","ed25519","audit"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"seal_hitl_decision","name":"Seal a human-in-the-loop decision","description":"Seals a governance record for a HUMAN decision. Content-based and auditor-reconstructable: it captures the deciding human's identity and role, the disposition and rationale, the policies/SOPs cited AS THE BASIS (by reference, and where possible captured text or hash — policies drift, so an auditor needs the version in force), and content-addressable references (with sha256 hashes) to the system-of-record artifacts the decider SAW at decision time — reservation records, folios, inventory state — NOT the action produced. From the sealed record alone an auditor can verify exactly what state the decider was looking at. Witness seals the ASSERTED actor identity; it does not authenticate the person. Use evidence[].inline to embed a snapshot (≤100KB; bytes are verified against the hash at seal time) when upstream availability isn't guaranteed. If a decision genuinely has no evidentiary basis, state it in evidence_omitted_reason rather than omitting silently. See the MCP `seal_hitl_decision` inputSchema for required fields.","tags":["evidence","hitl","governance","audit"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"verify","name":"Verify a record","description":"Independently verify a record or chain (Ed25519 signature + hash-chain). No auth.","tags":["verification","tamper-evidence"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"verify_record_issuer","name":"Verify a record's issuer-authenticity (verdict only)","description":"Is a record's signature by the issuer it claims? PUBLIC, no key. Input is a record_id; the answer is a VERDICT plus the issuer DID and the public key it resolved against — NEVER the record body, decision.inputs, or evidence. General records (attestations, agent_actions) are account-private; this is the ONLY thing about them that is publicly checkable, and the surface is exactly as wide as the question. This is how an enforcer of a privilege-widening event — e.g. a service sealing a genesis authority registration or a baseline promotion ABOUT ITSELF, customer-managed — confirms the issuer signed it, not merely that Witness recorded it, without holding the account's key or seeing the record. Response {record_id, signature_valid, issuer_verified, issuer_verification, issuer_did, signer_key}. Same four states as check_valid's issuer_verified: 'verified' (signing key IS published in the claimed issuer's did:web) | 'key_not_in_did_doc' (LOUD — signed by a key NOT in that DID; suspicious) | 'custodial' (Witness's own key signed it — issuer-authenticity is not the applicable question, a different custody model, not a failure) | 'did_unresolvable' (issuer DID unreachable — the check did NOT complete; treat as neither verified nor forged). The issuer DID is taken from the credential's issuer_did or, for a general record, from the signer's did:web keyId. Cache-Control: public, max-age=60 (no-store while did_unresolvable). ids are unguessable UUIDs; unknown → not_found.","tags":["verification","issuer-authenticity","enforcement","custody"],"inputModes":["application/json"],"outputModes":["application/json"]},{"id":"whoami","name":"Resolve a Witness key — cross-service auth (Contract A)","description":"The SANCTIONED cross-service authorization endpoint. A sibling getvda.ai service that accepts `Authorization: Bearer wtn.<id>.<secret>` from ITS caller validates that key by calling whoami — Witness is the sole source of truth for its own keys, so no sibling replicates the key store. Returns everything a sibling needs to authorize on IDENTITY, not just presence: account_id (WHO), tier (SEALED|ANCHORED), scopes (WHAT it may do), compliance, key_id, revoked (always false on 200), and expires_at (validity window; null = non-expiring — a revoked or expired key 401s before reaching here). A key can only ever resolve ITSELF — it cannot enumerate other accounts. Any missing/invalid key returns a uniform 401 'unknown or invalid API key' (no existence leak). Available as REST (GET) and as the MCP `whoami` tool; permissively rate-limited per IP and per account.","tags":["auth","cross-service","composition","suite"],"inputModes":["application/json"],"outputModes":["application/json"]}],"skills_removed":[],"skills_changed":[],"fields_changed":[{"field":"name","before":null,"after":"VDA Witness"},{"field":"description","before":null,"after":"Seals governed AI-agent decisions into tamper-evident, Ed25519-signed, independently-verifiable records, and produces EU AI Act Article 12 evidence from the sealed trail. Part of the VDA platform."},{"field":"version","before":null,"after":"1.0.0"},{"field":"protocolVersion","before":null,"after":"0.2.5"},{"field":"url","before":null,"after":"https://witness.getvda.ai"},{"field":"documentationUrl","before":null,"after":"https://witness.getvda.ai/docs"},{"field":"preferredTransport","before":null,"after":"HTTP+JSON"}],"other_changed":true,"is_empty":false,"human_summary":"added 15 skills · name ∅ → VDA Witness · description ∅ → Seals governed AI-agent decisions into t · version ∅ → 1.0.0 · protocolVersion ∅ → 0.2.5 · url ∅ → https://witness.getvda.ai · documentationUrl ∅ → https://witness.getvda.ai/docs · preferredTransport ∅ → HTTP+JSON"}}]}