Conformance
The conformance suite
A standard is only a standard if two independent implementations agree. This page fixes the exact rules and gives you the test vectors, a standalone verifier and a JavaScript verifier that all give the same answers.
The canonical form (v0.1)
What is signed is the receipt core: every field except signature_ed25519 and public_key, serialized in one exact way so any language reproduces the same bytes.
- Object keys sorted by Unicode code point. No whitespace between tokens.
- Every character outside U+0020 to U+007E is written as a lowercase
\uXXXX escape (characters above U+FFFF as surrogate pairs). Quote and backslash are written \" and \\; control characters as \b \f \n \r \t or \u00XX.
- Numbers are written exactly as they appear in the receipt. Languages format numbers differently, so signed content should use integers or strings (for example
"12.50") and avoid floats and exponents.
- Encode as UTF-8 and sign with Ed25519 (RFC 8032).
content_hash is sha256: plus the hex SHA-256 of the canonical form of the action.
This equals Python's json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=True), which is what the reference issuer uses.
Relationship to RFC 8785 (JCS) and the IETF work. The emerging IETF signed-action-receipt draft canonicalizes with RFC 8785. That differs from the form above in string escaping (JCS does not escape non-ASCII) and in number formatting. For data that is ASCII-only with integer numbers, the two produce identical bytes. Aligning a future version with RFC 8785 is a proposal, not a decision, and would be versioned so v0.1 receipts stay verifiable.
Test vectors
11 vectors generated from the reference issuer. A conforming verifier reproduces every outcome. Download test-vectors.json.
| Vector | What it tests | Expected |
|---|
valid_ascii | A plain valid Seal binding an ASCII action. | valid |
valid_non_ascii | Accents and an emoji in the action: the verifier must escape them exactly as the reference does. | valid |
valid_integral_float | An integral float (100.0): the verifier must keep the number exactly as written. | valid |
valid_with_oversight | A Level 2 Seal carrying the signed oversight evidence object. | valid |
valid_refusal | A refusal is also a valid, signed decision. | valid |
tampered_decision | The decision was changed after signing. | must FAIL |
tampered_approver | The approver was changed after signing. | must FAIL |
tampered_oversight | A forged fast decision time inside the signed oversight evidence. | must FAIL |
swapped_action | The signature is valid but the action presented is not the one that was approved. | must FAIL |
unsigned | No signature present. | must FAIL |
wrong_key | The signature was made by a different key than the one the receipt names. | must FAIL |
Run them
node run-vectors.js test-vectors.json
# needs hs-verify.js beside it (or in ../assets)
pip install cryptography
python3 hs_verify.py --vectors test-vectors.json
Or open the browser verifier and pick any vector from the dropdown to watch a tampered or swapped Seal fail.
- run-vectors.js and hs-verify.js: the JavaScript verifier (Node 20 or later, and the same code the browser page runs).
- hs_verify.py: a standalone Python verifier that shares no code with the reference implementation.
What conformance means at each level
- Level 1, Gated: reviewed against the requirements on the levels page (registry of gated actions, fail-closed behaviour, distinct authenticated approver). These are behaviours of a system, so they are reviewed, not tested by vectors.
- Level 2, Signed: the system must issue receipts that pass every vector above when verified by an independent verifier, and its verifier must reproduce every vector.
- Level 3, Assured: the criteria are still being defined. Proving a present human is an open research problem, and we will publish the criteria when they can be tested.
Where the check must live
A Seal only means something if the check that acts on it cannot be steered by the thing it is checking.
- The enforcement point sits outside the agent. The component that performs the action verifies the Seal, on the payload it is really about to run, and runs exactly that payload: the check and the execution are one step, and what runs is a copy of the bytes that were verified. An agent must never check its own action. An agent that both judges and executes can show one action and run another; the METR and Redwood report on the OpenAI and Hugging Face incident documents agents doing exactly that to their own logs.
- The enforcement point calls the online steps. Consume the Seal so it authorises one use, and check the issuer's signed revocation list. The offline check proves a receipt is authentic and binds the action; these online steps confirm it is still valid.
- The check is tested with hostile cases, not only good ones. The reference gate is driven with the cases below by a script with no refusals at all. A gate that passes only the good cases has not been tested.
| Case kind | Must be | Cases |
|---|
| authority above the minimum | allowed | 8 |
| valid seal and authority | allowed | 8 |
| action not in the registry | blocked | 3 |
| approver presented is not the approver in the seal | blocked | 8 |
| authority below the minimum | blocked | 6 |
| critical, no second approver | blocked | 2 |
| critical, second approver below authority | blocked | 2 |
| critical, second approver is the first | blocked | 2 |
| critical, second approver named without a seal | blocked | 2 |
| critical, second seal belongs to someone else | blocked | 2 |
| no approver | blocked | 8 |
| no seal | blocked | 8 |
| revoked seal | blocked | 8 |
| seal for a different action type | blocked | 7 |
| seal for a different payload | blocked | 8 |
| seal is a refusal | blocked | 8 |
| seal issued for a different tenant | blocked | 8 |
| seal older than the tier allows | blocked | 8 |
| seal past its own expiry | blocked | 8 |
| seal used a second time | blocked | 8 |
| tampered seal | blocked | 8 |
| unsigned seal | blocked | 8 |
What an affiliate's agents must satisfy
Requirements for a system that displays the Human Seal. Levels 1 and 2 are reviewed against these. Independent review is a role of the steward's board, and founding members help set it up.
- Approvals come only from a signed-in person. Agent, service and job tokens cannot approve, and the issuer refuses them.
- The approver is identified by an opaque reference, never a name or email, and the Seal records that the approver was a signed-in person.
- Each Seal binds one action, one action type, one approver reference and one tenant, and is checked against all four.
- A Seal has a life: a signed expiry or a tier maximum age, single use through the consume step, and revocation, including revocation of an issuer key.
- The enforcement point is outside the agent and runs exactly the payload it verified.
- Any agent can report a concern to a human through a route that cannot be switched off, and a person is alerted to refused approvals, a used decoy credential, and a lane or control going dark.
- Decoy credentials are planted where an agent might look, and any use is alerted.
- The system publishes its own hostile-case test results with the count of cases and the interval, not only a pass mark.
Scope. This specifies what to check; it is not itself a certification. A Seal proves who approved which action, and the standard's oversight measures address how well the review was done.
Changelog
- 2026-09-20, later: Added the deployment requirements and the affiliate requirements above, and the gate case kinds. The reference gate now also refuses expired, over-age, revoked and reused Seals, and the issuer publishes a signed revocation list.
- 2026-09-20: The test vectors were written and immediately exposed a bug in our own site verifier: it reported a genuine Seal as swapped whenever the action contained non-ASCII text or an integral decimal such as
100.0, because it canonicalized differently from the reference issuer. The verifier now reproduces the reference exactly and the vectors guard against the whole class of bug.