Released docs. You are viewing the documentation published with v0.25.0. Development docs are available at Latest.
Disclosure modes and computed answers
You are weighing whether Registry Stack actually keeps a sensitive registry record private while still answering questions about the subjects in it. The short answer is that a caller asks a question and receives a computed answer, not the record. This page explains how that works, what each kind of answer does and does not reveal, and where the privacy claim has edges. You will see one product term used throughout: a requirement, which is one predefined, reviewed question about one set of subject roles, together with the exact set of values its answer may carry. A requirement is deliberately narrow and reusable. A requirement that returned a whole record would over-collect, and a requirement that embedded one consumer’s eligibility or action rules could not be reused as neutral evidence.
Evidence Gateway has no caller-selectable disclosure modes
Section titled “Evidence Gateway has no caller-selectable disclosure modes”The most important difference is a subtraction.
An Evidence Gateway request carries four required members: a per-request nonce, the requirement identifier,
the purpose, and one selector per declared subject role. The only optional member is holderKeys,
an array of holder public keys, each echoed into the cnf claim of the credential issued for it.
Under a holder-bound requirement at least one key is required and each key’s RFC 7638 thumbprint
scopes that credential’s subject binding; the keys still never reach authorization, selectors,
scripts, source requests, or audit. The request schema is closed and rejects anything
else (products/evidence/contracts/request.schema.yaml). What the keys never do is select a
binding mode or a disclosure level: the requirement declares the mode, and no caller input changes
it.
There is no disclosure mode, no redaction field list, no allowed set, and no downgrade policy,
because there is nothing for a caller to choose.
Evidence Gateway answers a predefined requirement and returns that requirement’s answer. It does not run a disclosure policy engine over an arbitrary record, and it has no notion of “the same answer, revealed at three levels of detail.” How much a requirement reveals is fixed when the requirement is authored and reviewed, and it is identical for every caller and every purpose authorized to invoke it.
That is deliberately narrow. It moves the disclosure decision from request time, where a caller could argue for more, to authoring and review time, where an operator has to justify it once and can be held to it.
What actually controls disclosure
Section titled “What actually controls disclosure”A requirement declares one to sixteen concepts. Each concept names the fact being disclosed and
fixes the exact value form that fact takes. The answer carries a value for each declared
concept and nothing else; the assertion schema rejects additional properties, and subject selector
profiles and selector values never appear in it
(products/evidence/contracts/evidence.schema.yaml).
The value form is the minimization control, because the form decides what the number, code, or date
behind the answer is allowed to become before it leaves the service. There are eleven forms and the
set is closed (products/evidence/contracts/supported-value-forms.yaml).
| Value form | What the caller learns |
|---|---|
boolean | one true or false, and nothing about how it was reached |
controlled-code, controlled-code-list | exact membership in a reviewed codelist; labels and source codes are not disclosed |
controlled-category | exact membership in a reviewed closed category set |
bounded-integer, bounded-decimal | a number inside declared bounds, at a declared scale |
date-bucket, time-bucket | which reviewed bucket applies; the underlying date, instant, or duration is not disclosed |
audience-scoped-entity-reference, entity-reference-list | an opaque reference meaningful to the named audience and to no other; unavailable to a holder-bound requirement, which has no audience |
reviewed-structured-value | a small structure whose closed JSON Schema forbids arbitrary JSON; the widest form, and the one to justify hardest |
Two of these deserve emphasis. A controlled code answers with a reviewed disclosure code rather than the register’s own code, so the register’s internal coding never leaves. A date bucket answers with a bucket rather than the date, which is how a question about time can be answered without releasing a birth date or an expiry date.
The size ceilings are part of the control: at most sixteen concepts per requirement, and a total serialized value budget of 65536 bytes.
Four questions, four answer shapes
Section titled “Four questions, four answer shapes”Four acceptance definitions carry equal weight in the Evidence Gateway contract. None is privileged, none
is a built-in type, and none has a special route (AGENTS.md, products/evidence/CONCEPT.md).
They are worth reading together because they show the same mechanism producing four differently
shaped answers.
- Adult status declares one
booleanconcept, derived from a date the caller never sees, with the age threshold supplied as a reviewed derivation parameter rather than by the caller. The caller learns whether the threshold is met, not the date or the age. - Residence region declares one
controlled-codeconcept bound to a reviewed codelist at a pinned version. Several register codes map onto one disclosed region, so the answer is coarser than the register’s own value by construction. A register code with no reviewed mapping leaves the requirement unresolved rather than guessing. - Professional licence status declares two concepts: a
booleanfor whether the licence is active, and acontrolled-categoryfor an expiry bucket. The caller learns “active, expiring within 90 days” without learning the expiry date. - Legal-parent relationship declares one
booleanconcept over two subject roles, a child and a candidate parent that the caller already holds a reference to. It confirms or denies the relationship the caller asked about, and never enumerates the child’s parents.
The fixtures for all four are in products/evidence/fixtures/acceptance/.
Evidence Gateway is not a consumer decision
Section titled “Evidence Gateway is not a consumer decision”Registry Relay source-access and adaptation policy controls how an authoritative source is read and normalized. Evidence Gateway authorization and requirement policy control which requirement is evaluated, who can request it, for what purpose, and exactly which values leave the service. The evidence consumer determines how the evidence is used, while the decision owner remains accountable for requirements, decisions, and actions.
A derivation script can compute an evidence value, such as whether a threshold is met or which
reviewed bucket applies. It is not a general-purpose consumer eligibility or decision engine, and
Version 1 has no general policy engine (products/evidence/contracts/README.md). A public-health
programme, for example, can act as both evidence consumer and decision owner when it combines those
answers with its own thresholds, priorities, and case state to decide whether outreach or follow-up
is required.
There is no redacted answer
Section titled “There is no redacted answer”Evidence Gateway cannot return an answer that carries neither a value nor a satisfaction outcome, and this
is structural rather than an omission: an assertion must carry at least one
supported value, so an assertion with nothing in it cannot be produced
(products/evidence/contracts/evidence.schema.yaml).
An Evidence Gateway request that cannot be answered does not return an empty assertion. It returns an
application/problem+json document with a closed member set, and no assertion is produced at all
(products/evidence/contracts/problem-contract.yaml).
What used to be modelled as a redacted answer is modelled in Evidence Gateway as a different requirement, or as a coarser value form on the same requirement, and is reviewed as such.
A refusal is not an existence oracle
Section titled “A refusal is not an existence oracle”Collapsing an unresolved outcome is not optional and not a mode.
Every requirement declares existenceDisclosure: collapse-unresolved, and that enum has exactly
one permitted value (products/evidence/contracts/bundle.schema.yaml).
No match, ambiguity, a missing required fact, and an unresolved derivation input all collapse into
one public problem, evidence.unavailable with status 422, carrying the same title and the same
body shape. A caller cannot tell which of the four happened, so it cannot use the response to learn
whether a record exists (products/evidence/contracts/problem-contract.yaml, invariant V1-I16 in
products/evidence/contracts/security-invariant-matrix.yaml).
Existence may be disclosed only as a separately authorized declared concept, never as error detail.
Internally the outcomes stay distinct in the audit record. Collapsing is a property of what the caller sees, not of what the operator can review.
Preserve negative, unknown, and unavailable evidence
Section titled “Preserve negative, unknown, and unavailable evidence”Requirement authors must keep these source meanings distinct:
truemeans the reviewed source contract positively establishes the fact.falsemeans the reviewed source contract positively establishes its negative.- An absent value means a subject matched but the declared source value is unknown, absent, or not recorded.
- No match means the exact selector did not resolve a subject.
- Ambiguity means the selector resolved more than one admissible subject.
- A source failure means the source could not provide a reliable result.
A derivation must not silently coerce an absent value, no match, ambiguity, or source failure to
false. Missing evidence is not a negative fact. An explicitly named existence concept is the
narrow exception: a reviewed derivation can treat “no admissible match” as a negative only when the
concept means exactly that one admissible match exists, and ambiguity or source failure never
becomes false.
Subjects do not travel, and do not correlate
Section titled “Subjects do not travel, and do not correlate”A subject appears in an assertion only as a role-bound opaque binding, derived with a keyed function over a binding scope, the purpose, role, selector profile, binding-key version, operator trust domain, and the complete canonical selector bundle. The binding scope is the only part that varies, and the requirement declares which of two closed values it takes.
By default the scope is the audience. The same person asked about by two relying parties, or under
two purposes, yields two unrelated bindings, so assertions cannot be joined into a profile
(invariant V1-I17). That property is also why audience-scoped-entity-reference is a usable
value form: an assertion can identify a related entity to the audience that asked without minting
an identifier anyone else can match on.
A requirement can instead declare the holder-bound scope, where the derivation takes the RFC 7638 thumbprint of the holder key and no audience at all. That is a deliberate trade rather than a stronger guarantee. The credential becomes presentable to several verifiers, and the same holder key under the same purpose, role, selector profile, and selector values yields the same binding for every one of them, so a holder who reuses a key is correlatable across the verifiers that see it. The service cannot prevent or detect that reuse; what it does is refuse the two entity-reference value forms for such a requirement, because both project a seed through an HMAC that takes the audience as an input and would degenerate without one. Issuing a batch of members under distinct holder keys lets a holder hand each verifier a different binding, which removes the deterministic key-based link and not linkability in general: the members still share an issuance timestamp, purpose, requirement, Evidence Type, configuration revision, and disclosed values.
Response formats are not disclosure levels
Section titled “Response formats are not disclosure levels”Evidence Gateway can serialize the same assertion in up to four formats: a signed flattened JWS, an
SD-JWT VC under a frozen local profile, a separately typed unsigned envelope, and a batch envelope
carrying one holder-bound credential per presented holder key. signed-jws is
mandatory in every bundle and is the default (products/evidence/contracts/bundle.schema.yaml).
The formats a given request may select are the intersection of the bundle’s permission, the one
matched grant’s permission, and the requirement’s binding mode allowlist: a holder-bound
requirement serves only the SD-JWT VC serialization and the batch envelope, and the whole
intersection is enforced with one denial that never says which layer withheld the format.
These are integrity and encoding choices, not privacy choices. All of them carry the same declared
values.
The SD-JWT VC serialization emits one root disclosure per supported value by default. A governed
reviewed-structured-value can instead expose an always-visible object whose direct fields are
independent disclosures. Nested field values remain atomic. The issuer appends every disclosure,
so the response the caller receives reveals the same set as the JWS. Holder-side omission at
presentation time is outside Version 1
(products/evidence/contracts/sd-jwt-vc-profile.yaml). The service performs no presentation-side
verification in either binding mode: it appends no key-binding JWT, issues no challenge, and holds
no presentation state. Verifying a holder-bound presentation is the relying party’s act, done with
the portable verifier or the evidence verify-presentation command
(products/evidence/contracts/holder-bound-profile.yaml).
The unsigned envelope carries no integrity protection, is released only when both the reviewed
configuration and the caller’s matched grant permit it, and is never later-verifiable evidence.
One requirement is not the whole disclosure surface
Section titled “One requirement is not the whole disclosure surface”Each requirement declares a disclosureGuard naming the value families it touches, and two
requirements that are each defensible alone can reconstruct a protected value between them.
The complete enabled configuration is therefore reviewed as one disclosure surface rather than
requirement by requirement, and that review is an operator duty the runtime cannot perform
(invariant V1-I03, products/evidence/OPERATOR-CONTRACT.md).
Disclosure control is one safeguard among several
Section titled “Disclosure control is one safeguard among several”Value forms are one design-time safeguard within a broader posture that also includes authentication, a single authorization decision taken before any source is contacted, immutable startup configuration, and audit at two durable gates. They are not the whole privacy guarantee. A few protections are not the software’s to make at all: secret and key custody, audit retention, tenant isolation, transport, and rate limiting are your deployment’s job, not built-in guarantees.
Limits
Section titled “Limits”A few boundaries matter when you evaluate this design:
- Minimization is modelled, not automatic: a requirement reveals exactly what its concepts declare.
A requirement authored with
reviewed-structured-valuereturns that structure. Least disclosure is a choice the requirement makes, not a property the runtime imposes on every answer. - Purpose does not narrow the answer: a requirement returns the same concepts in the same forms for every purpose authorized to invoke it. Purpose gates whether a caller may ask; a purpose that justifies a coarser answer needs its own requirement.
- The caller cannot inject a value, but matching strictness is configured: the computed answer rests on Evidence Gateway deriving it from one reviewed source consultation. A lookup resolves to exactly one match, no match, or ambiguity, and matching is only as strict as that reviewed source contract.
- This is not zero-knowledge: a boolean answer is computed inside the service from data the service read, and SD-JWT selective disclosure is digest omission. Neither is a zero-knowledge proof.
- An audience-scoped assertion is not a general-purpose credential: its subject binding is scoped to the audience named in it, so it is meaningful to that relying party and to no other. A holder-bound credential is presentable to several verifiers, and pays for that with the correlation described in Subjects do not travel, and do not correlate.
- Verifying a presentation is not preventing replay: a key-binding JWT proves the presenter held the confirmation key’s private key when it was signed, over exactly those bytes. Comparing the challenge nonce is not consuming it, the same presentation verifies again, and retiring a nonce belongs to the relying party’s own challenge lifecycle.
These forms also sit inside boundaries that are not specific to disclosure design: how the source consultation is authorized and pinned, how subject selectors are scoped, and what “aligned with a standard” does and does not mean. Weigh those alongside the value forms; see the known limitations hub for the full inventory.
Related
Section titled “Related”- Security overview: the full posture this fits into
- Evidence Gateway security model: the invariants named on this page
- Known limitations and non-guarantees: where the edges are
- Records stay home: what stays inside the institution and what crosses out
- How a requirement and its disclosure are defined: RS-PR-EVIDENCE