Decision record — verifier service contract
Why the verifier-service contract froze at v1: three operations, a closed reason-code vocabulary and invariants no client, in any language, can change.
What the freeze covers
Status: Accepted (2026-07-21) — contract v1 frozen at 1.0.0 · depends on the specification’s presentation rules, decision records, paid-verification permission and single-core rule
The OpenAPI document verifier-service.v1.yaml at contract version 1.0.0: three operations (getBuildInfo, createChallenge, validatePresentation), their schemas, and the closed ReasonCode vocabulary — byte-identical to the reason codes the embedded SDK emits.
Freezing means: after acceptance, a change of decision semantics, or removing, renaming or changing the meaning of a reason code, is a major contract version (the SDK’s semver policy, applied at the contract level); additive, non-semantic surface is minor, and so is adding a reason code that no request the deployment issued before can produce (as applied in 1.2.0–1.5.0, changelog below). Transport-only clients, in every language, build against the frozen contract.
Why freeze now
The multi-language strategy makes this contract the load-bearing artifact of the whole approach: it is the boundary that guarantees no client ever carries cryptography or policy. The nine acceptance conditions, the 10-second constant and the retention schema sit behind the contract and are deliberately unexpressible in it: no lifetime parameter, no skip flags, no per-request height-lag override.
A contract test enforces route-for-route and code-for-code agreement between the YAML and the running service, so the frozen document is checked against reality on every CI run.
Invariants the freeze locks in
- One decision path:
validatePresentationresponses are the embedded SDK’s decision verbatim; HTTP 400 exists only where no session identity can exist — nothing parseable means no retention record. - Closed reason vocabulary shared with the conformance vectors; removing, renaming or changing the meaning of a code is major and flows to every language at once.
- Challenge identity (verifier id, exact origin, request key) is deployment configuration bound to on-chain registrations — never caller input.
build-infoexposes exactly the release pins — enough for a client to verify what it talks to, never secrets.
Post-freeze changelog
| Version | Date | Change |
|---|---|---|
1.0.0 | 2026-07-21 | Contract frozen (this record). |
1.1.0 | 2026-07-21 | Additive minor: BuildInfo gains required conformance_suite_version. No decision-semantics or reason-code change. |
1.2.0 | 2026-09-23 | Additive minor: the agent profile — profile on the challenge (identity_v1 by default, agent_v1 for an agent answering for its principal), the HTTP 422 policy_refused answer when an agent policy is not one the service will issue, and three reason codes only agent challenges can produce. Identity requests and responses byte-unchanged. |
1.3.0 | 2026-09-23 | Additive minor: the agent’s pairwise pseudonym — one pairwise_pseudonym entry in an agent policy, verified.pairwise_pseudonym (and verified.recognition where the deployment recognises) on an accepted decision that asked for it; one more agent-only code, pseudonym_verifier_mismatch. |
1.4.0 | 2026-09-23 | Additive minor: the pairwise pseudonym is mandatory in every agent policy (pseudonym_required); /v1/build-info gains the recogniser’s public configuration (recognition). |
1.5.0 | 2026-09-24 | Additive minor: the service decides only its own requests (request_not_ours for a request naming another verifier or origin); unexpired mandatory in every agent policy (unexpired_required); a fourth operation, checkStatusRoot (POST /v1/status-root-checks): is a status root still the issuer’s current, unexpired one. |
1.6.0 | 2026-10-06 | Additive minor: /v1/build-info gains source_revision and release — build provenance, never pins. |
1.7.0 | 2026-10-10 | Additive minor: profile: agent_v2 — an agent carrying its principal’s age floor, whose policy may also ask age_over N; the verifier learns age_over_<N> and nothing else. No new reason code. Identity and agent_v1 bodies byte-unchanged. |
1.8.0 | 2026-11-03 | Additive minor: dispute reachability. Every agent presentation carries a dispute ciphertext (agent presentations version 3), checked under condition 5 — a missing or invalid one is proof_invalid. For an agent presentation it accepts, the service keeps a dispute retention record before the nonce is consumed; when it cannot, the presentation is refused with one more agent-only code, dispute_retention_unavailable (condition 9), never accepted. Identity bodies byte-unchanged; no field changes. |
The published document is the 1.8.0 edition. Production and the public testnet serve 1.8.0.
The freeze is what lets every client — in any language — treat the service surface as a stable fact: the conformance suite, the reason-code page and the service-mode guide in these docs all build on it.