Selective Disclosure
Table of contents
- Selective Disclosure
- Intent
- Summary
- Structure
- Examples
- Happy path — Consent-authorized disclosure to a research partner
- Happy path — Regulatory-mandate disclosure to a public health authority
- Rejection path — missing authority field
- Rejection path — unknown authority type
- Happy path — Legal-Hold-compelled disclosure to a regulatory investigator
- Rejection path — future-dated
disclosed_at
- Regulated adversarial scenarios
- Generation acceptance
- Edge cases and explicit non-goals
- Composition notes
- Standards references
- Status
- Lineage notes
A compliance primitive: a durable, append-only record of every disclosure of subject data — to whom it was disclosed, what scope of data was shared, under what authority, and at what time. The atom does not perform disclosures, redact records, or transmit data; it records that a disclosure occurred. Each disclosure event produces one immutable disclosure record with an opaque immutable id; the subject reference, recipient, scope, authority, and timestamp are immutable properties set at recording time. The record set is append-only; no disclosure record is modified or deleted. Two actions:
recordcreates a disclosure record;readqueries the disclosure store.
Intent
Regulated systems that handle personal data, financial records, or protected health information are required to maintain a complete and durable account of every disclosure made — what data was shared, with whom, under what legal authority, and when. A GDPR (EU General Data Protection Regulation) supervisory authority conducting an Article 15 review asks what was disclosed to which recipients. An HHS OCR inspector validating HIPAA (US Health Insurance Portability and Accountability Act) compliance asks for the accounting of disclosures required by §164.528. An SEC examiner reviewing broker-dealer records asks for the disclosure trail that Rule 17a-4 mandates. The obligation across all three regimes is the same: the system must answer these questions from its records alone, without recourse to developer testimony, log reconstruction, or institutional memory.
Selective Disclosure is the accountability layer that makes those answers possible. When a disclosure occurs — when subject data is transmitted to a party other than the subject — the calling system records it: record(subject_ref, recipient, scope, authority, ...) produces a disclosure record. That record is the durable, immutable proof that the disclosure happened, was authorized, and was made in the declared scope. The atom does not perform the disclosure itself. It does not redact records, resolve what data falls within scope, route transmissions, or decide whether a disclosure is permitted. Those are the calling system’s concerns. This atom is the layer that makes the calling system’s decisions auditable.
The distinction between recording and performing is the atom’s load-bearing EOS boundary. An atom that also performed disclosures — retrieving subject data, applying redaction logic, routing to recipients — would absorb concerns from storage layers, redaction engines, and notification systems. Each of those concerns has its own state, its own invariants, and its own composing pattern. Absorbing them here would destroy freestanding status and produce a spec that cannot be composed independently of the implementation technologies it would need to name. The atom specifies the accountability obligation; the implementation specifies the mechanics of disclosure delivery.
The atom is structurally distinct from four adjacent concepts, and the distinctions are load-bearing:
Selective Disclosure vs. Audit Trail. Audit Trail is a general-purpose tamper-evident, attributed log of system actions — any action, any actor, any subject. It answers what happened in this system? Selective Disclosure is specific to one class of event: the disclosure of subject data to a party other than the subject. It answers what was disclosed about this subject, to whom, under what authority? The two are composing peers: a disclosure is a system event that Audit Trail would capture; the Selective Disclosure record is the structured, authority-bearing form that regulators require for disclosure accounting. Neither replaces the other. In regulated deployments, the Selective Disclosure record and the Audit Trail event coexist: the event log captures that an action occurred; the disclosure record carries the authority field that only disclosure accounting requires.
Selective Disclosure vs. Consent. The forthcoming Consent atom governs authorization — whether a data subject (the individual whose personal data is held — the rights-bearer under privacy law) has granted permission for a category of processing. Selective Disclosure records that a disclosure occurred, after the fact, whether authorized by Consent, by Legal Hold, or by regulation. Consent is a precondition check; Selective Disclosure is a post-disclosure accountability record. A system that checks Consent before disclosing and then records the disclosure in Selective Disclosure is using both atoms as intended: Consent answers “may I?” and Selective Disclosure records “I did.” The authority field in a Selective Disclosure record may reference a Consent record id, but the atom does not import Consent’s lifecycle semantics. The presence of a Consent id in authority.reference is an opaque pointer into the Consent store; validation that the Consent was valid at time of disclosure is the calling system’s obligation.
Selective Disclosure vs. Legal Hold. Legal Hold governs compelled preservation — records cannot be destroyed while a hold is Active. Selective Disclosure records compelled disclosure — when a legal process requires the system to share records with a third party (a regulator, a court, an investigation team), the disclosure of those records must itself be recorded. A Legal Hold id may appear as the authority under which a disclosure was made (authority.type: legal-hold), but Legal Hold and Selective Disclosure are addressing opposite obligations: Legal Hold prevents records from leaving the system under normal operation; Selective Disclosure records that records have left the system under authorized operation. Neither atom imports the other’s semantics; both may be active simultaneously on the same subject’s records.
Selective Disclosure vs. Actor Identity. Actor Identity answers who authorized an action — it binds an actor to an action via a verifiable proof. Selective Disclosure answers to whom was subject data disclosed — it records the recipient of subject data, the scope of what was shared, and the legal authority for the transfer. Both atoms carry attribution fields (recipient in Selective Disclosure; actor_ref in Actor Identity), but they are different kinds of attribution. A disclosure to a regulator under a HIPAA mandate names the regulator as recipient in the Selective Disclosure record and may name the compliance officer who authorized the disclosure in a composing Actor Identity attestation. Neither atom replaces the other; disclosures in regulated systems require both the disclosure record (this atom) and the actor attestation (Actor Identity) for non-repudiation.
Cryptographic protection of disclosure records against post-hoc modification — the bar for court-admissible evidence and for SEC Rule 17a-4’s non-erasable, non-rewritable standard — is added by composition with Tamper Evidence; this atom does not provide it alone.
This is a freestanding (can be specified without naming any other pattern) concept in the EOS (Essence of Software — Daniel Jackson’s framework for specifying software concepts as freestanding, composable units) sense. It carries its own state (the disclosure record set), its own actions (record, read), and its own invariants (record immutability, append-only durability, authority completeness, no-disclosure-unrecorded as an integration obligation). Composing patterns add authorization checks, tamper evidence, retention governance, and actor attribution.
Summary
Selective Disclosure is the accountability layer for data disclosures — the durable, append-only (records can be added but never changed or deleted) record of every instance in which subject data was shared with a party other than the data subject themselves. It answers the question regulators and data subjects routinely ask: what data was disclosed about this person, to whom, under what legal authority, and when?
The atom does not perform disclosures. It does not retrieve data, apply redaction, or route transmissions. Its single creation action, record, is called by the composing system immediately after a disclosure occurs, capturing the subject reference, recipient, scope of data shared, and the authority under which the disclosure was made. That authority must be one of exactly three types: consent (the data subject authorized it), legal-hold (a legal process compelled it), or regulatory (a regulatory mandate required it). Records are immutable (unchangeable once written) once written; the store is append-only; nothing is ever deleted or modified. This design is the structural guarantee that the disclosure history for any subject is complete and cannot be silently altered.
The read action queries the disclosure store by subject, recipient, authority type, or time range. The result is the structured, authority-bearing form that regulators require: GDPR Article 15 right-of-access responses, HIPAA §164.528 accounting of disclosures, and SEC Rule 17a-4 disclosure trails are all answerable from the records alone.
Three audit questions cannot be answered from this atom’s records alone and require composing patterns: whether a referenced consent or legal hold was actually valid at the time of disclosure (requires the Consent or Legal Hold store), whether every disclosure that occurred was recorded (requires cross-referencing against an Event Log or egress boundary log), and whether a backdated disclosed_at timestamp reflects the true recording time (requires the Audit Trail composition). These audit boundaries are named explicitly in the Generation acceptance section. Common uses include: GDPR Article 30 records-of-processing obligations, HIPAA covered entity disclosure accounting, broker-dealer disclosure trails under SEC Rule 17a-4, and any regulated system where proving what was shared — and under what authority — is a compliance requirement.
Structure
Store instance model
The Selective Disclosure atom operates against a named store instance. A store_name identifies the instance; multiple instances coexist in real systems — one per organization, jurisdiction, or regulated business unit, depending on deployment topology. disclosure_id values are unique within a store instance; uniqueness across instances is a composing concern. The same subject_ref may appear in many disclosure records within the same store instance — one per disclosure event involving that subject. Calls implicitly target a single routed instance; instance selection is a deployment-routing concern, not defined by this atom.
Identity model
Each disclosure record has an opaque, immutable, system-generated disclosure_id — assigned by the record action at creation, never reused, never reassigned within the store instance. The uniqueness guarantee has two scopes that compose into the same property: at the action level, every successful record call produces a fresh id; at the store level, any write that would reuse an existing disclosure_id is rejected as a storage-failure and no partial record is written. disclosure_id must be a non-empty string sortable in lexicographic byte-order; this property is required for deterministic read ordering. The id is the disclosure record’s identity; the subject reference, recipient, scope, authority, and timestamp are properties of the record, not its identity.
subject_ref is an opaque reference to the data subject whose data was disclosed. Set on record, immutable. The atom does not validate that the subject exists in any other system — subject_ref is the caller’s responsibility. Two disclosure records for the same subject have distinct disclosure_ids; each is its own audit record.
recipient is a non-empty string naming the party to whom the data was disclosed. Set on record, immutable. This is the entity that received the disclosed data — a regulator’s identifier, a counterparty’s name, a business unit’s id, a research institution’s reference. The atom does not interpret recipient semantics or validate that the recipient is a known party in any external system. Must contain at least one non-whitespace character.
scope is a non-empty string naming what subset of the subject’s data was disclosed. Set on record, immutable. The atom does not interpret scope semantics — it records the scope as declared by the calling system. Examples: "medical-record:summary", "financial:transaction-history:2023", "personal-data:contact-fields". Must contain at least one non-whitespace character.
authority is a structured field — a record with exactly two sub-fields — naming the legal or contractual basis under which the disclosure was made:
authority.type— one of exactly three named values:consent,legal-hold, orregulatory. No other values are valid.authority.reference— an opaque string identifying the specific authority: a Consent record id fortype: consent, a Legal Hold id fortype: legal-hold, or a regulatory requirement citation fortype: regulatory(for example,"HIPAA §164.512(b) — public health reporting"or"GDPR Article 6(1)(c) — legal obligation"). Must contain at least one non-whitespace character.
The three authority types cover the complete space of legitimate disclosure authorities: data-subject authorization (consent), legal compulsion (legal-hold), and regulatory mandate (regulatory). A disclosure not falling into one of these three categories is not a legitimate disclosure; the atom’s rejection of any other authority.type value is a structural enforcement of that bound. The separation into type and reference keeps the authority field machine-queryable by type while preserving a human-readable reference string.
disclosed_at is the timestamp of the disclosure event. Set on record, immutable. If not supplied by the caller, the receiving node’s wall clock is used. The atom enforces that the persisted disclosed_at — whether caller-supplied or wall-clock-defaulted — is not in the future. disclosed_at may be backdated — documenting a disclosure recognized after the fact is valid in some regulated contexts — but not forward-dated.
Inputs
recordcalls from the calling system immediately following each disclosure event, carrying the subject reference, recipient, scope, authority, and optional explicit timestamp.readqueries from compliance teams, regulators, data subjects asserting their Article 15 rights, incident responders, and auditors.
Actions
For optional parameters in record, “supplied” means provided as a parseable value of the declared type. Null, missing, and empty (or whitespace-only) values are equivalent to “not supplied,” and the action’s documented default applies.
-
record(subject_ref, recipient, scope, authority, disclosed_at?) → recorded(disclosure_id) | rejected(invalid-request | unknown-authority-type | storage-failure)— create a new disclosure record. Assigns a freshdisclosure_id, recordssubject_ref,recipient,scope,authority(bothtypeandreference), anddisclosed_at(wall clock if not supplied; the resolved value must not be in the future). The record enters the store permanently; it is immutable and cannot be retracted.subject_ref,recipient,scope, andauthority.referencemust each contain at least one non-whitespace character — any violation isinvalid-request.authorityitself must be present and must carry bothtypeandreferencesub-fields — a missing or structurally malformedauthorityfield isinvalid-request. The resolveddisclosed_at— caller-supplied or wall-clock-defaulted — must not be in the future (invalid-request).invalid-requestis checked beforeunknown-authority-type; structural and field-content validation completes before the authority type is evaluated. If all field-level preconditions pass,authority.typeis checked: if it is not one of {consent,legal-hold,regulatory}, the call is rejected asunknown-authority-type.storage-failureif the store write fails after all preconditions pass; nodisclosure_idis issued and no record enters the store. Rejection priority:invalid-request→unknown-authority-type→storage-failure. -
read(filters) → results | rejected(invalid-query)— query the disclosure store and return matching disclosure records. Results are ordered bydisclosed_atascending, then bydisclosure_idascending in lexicographic byte-order as a stable tiebreaker. Implementations must assigndisclosure_idvalues in a format where string byte-order sort produces a total order (e.g., ULID, UUID v7, or zero-padded integer string). The supported filter axes are exactly:disclosure_id,subject_ref,recipient,authority_type, anddisclosed_at(as a time range). Any combination of supported axes is valid. A query supplying only adisclosure_idreturns at most one record. A well-formed query matching no records returns an empty sequence, not a rejection — an empty result means no disclosures matching the filters have been recorded, which is itself a meaningful compliance answer (the system has not disclosed subject data in the queried scope). A query with no filters returns every record in the store.The
authority_typefilter axis takes one of {consent,legal-hold,regulatory} as its value; it matches records whereauthority.typeequals that value. It is distinct fromauthority.reference— reference-level filtering is not supported by this atom; reference searches are a composing-layer concern.Malformed-query rules (
invalid-query): adisclosure_id,subject_ref, orrecipientfilter value that is null, empty, or whitespace-only isinvalid-query. Anauthority_typefilter value that is not one of {consent,legal-hold,regulatory} isinvalid-query. A time range ondisclosed_atwith end before start isinvalid-query. A query carrying an unrecognized filter key — any key outside the five supported axes named above — isinvalid-query; an unrecognized key is rejected rather than silently ignored, because silent ignore would return a result set inconsistent with the caller’s intent.
Outputs
- For
record: the outcome tokenrecordedcarrying the freshdisclosure_id, or a rejection. - For
read: a (possibly empty) ordered sequence of disclosure records. Each record carries its full field set:disclosure_id,subject_ref,recipient,scope,authority(bothtypeandreference), anddisclosed_at. Every field is set on every record in the store; there are no optional fields that some records carry and others do not. Theauthorityfield is always present in structured form with both sub-fields.
State
The Selective Disclosure atom has no state machine on individual records. Each disclosure event creates one record; that record is immediately and permanently in the disclosure store. There are no states, no transitions, and no terminal conditions on a disclosure record. The concept is categorically different from the state-machine atoms (Legal Hold: Active/Released; Approval Step: Pending/Approved/Rejected/Withdrawn) — a disclosure record simply is, from the moment it is created, without lifecycle transitions.
The store-level state is the set of all disclosure records. That set is strictly append-only: record adds to it; nothing removes from it or modifies records already in it. The store grows monotonically.
Fields on every disclosure record: disclosure_id, subject_ref, recipient, scope, authority.type, authority.reference, disclosed_at — all immutable from the moment record completes.
Flow
- Disclosure event occurs. The calling system has shared subject data with a recipient. This may be a GDPR-mandated data subject access request response, a HIPAA-compelled disclosure to a public health authority, a Consent-authorized sharing with a third-party research partner, or a Legal-Hold-compelled disclosure to a regulatory investigator.
- Calling system calls
record. Immediately following the disclosure, the calling system callsrecord(subject_ref, recipient, scope, authority, ...). The atom assigns adisclosure_id, records all fields, and returnsrecorded(disclosure_id). - Disclosure record persists indefinitely. The record is in the store. It will appear in subsequent
readqueries. Retention governance — how long it must be kept — is a composing Retention Window concern. Tamper protection — ensuring it cannot be altered by a store administrator — is a composing Tamper Evidence concern. - Auditor or data subject queries. At any future time, a data subject exercising Article 15 rights, a GDPR supervisory authority, an HHS OCR inspector, or an SEC examiner queries
read({subject_ref: X}). The result is the complete disclosure history for subject X: every disclosure event, every recipient, every scope, every authority, every timestamp. The atom answers the regulatory question from its records alone.
Decision points
-
At
record— field-level checks complete first (rejection reason:invalid-request):subject_ref,recipient,scope, andauthority.referencemust each contain at least one non-whitespace character;authoritymust be present as a structured field carrying bothtypeandreferencesub-fields; the resolveddisclosed_at— caller-supplied or wall-clock-defaulted — must not be in the future. All field-level preconditions are checked before the authority type is evaluated. Then semantic check:authority.typemust be one of {consent,legal-hold,regulatory}; any other value isunknown-authority-type. Then persistence:storage-failureif the store write fails. Rejection priority:invalid-request→unknown-authority-type→storage-failure. -
At
read— every supplied filter value must be well-formed for its axis. Adisclosure_id,subject_ref, orrecipientfilter value that is null, empty, or whitespace-only isinvalid-query. Anauthority_typefilter value not in {consent,legal-hold,regulatory} isinvalid-query. A time range ondisclosed_atwith end before start isinvalid-query. An unrecognized filter key — any key outside the five supported axes — isinvalid-query; the spec rejects rather than ignores unknown keys. A well-formed query matching no records returns an empty sequence.
Behavior
- Records are durable on success. Once
recordreturnsrecorded(disclosure_id), the record is in the store and will appear in subsequent reads. - Record creation is not idempotent. Two
recordcalls with the samesubject_ref,recipient,scope, andauthoritycreate two independent disclosure records with distinctdisclosure_ids. If the calling system needs at-most-once semantics under retry conditions, compose with Duplicate Prevention. - Concurrent
recordcalls for the same subject are not an error. Multiple disclosures of subject data may occur concurrently — for example, a batch disclosure to multiple recipients processed in parallel. Each call produces its owndisclosure_idand its own record. There is no serialization constraint across distinctrecordcalls; each call’s result is independent of every other call’s result. Implementations must serialize only on a givendisclosure_idfor consistency of the record’s own fields, not across calls for the samesubject_ref. - No record is modified after creation. The atom has no
amend,retract,correct, ordeletesurface. A disclosure that was recorded incorrectly — wrong scope, wrong recipient — produces a record that stands permanently. If a disclosure was recorded in error, the correct response is to create a newrecordwith accurate fields and ascopeorauthority.referencethat narrates the relationship to the prior record. The original record remains in the store as evidence of what was recorded; the new record provides the accurate account. This is the same pattern Legal Hold uses for case-reference updates — immutability of the original record is structural, not correctable. - The atom does not enforce that every disclosure is recorded. Whether the calling system calls
recordafter every disclosure is an integration obligation the calling system must honor; the atom cannot enforce it from inside. The no-disclosure-unrecorded invariant (Invariant 5) is an integration invariant and a calling-system obligation. An external auditor who finds a disclosure that was not recorded has found a system conformance failure, not an atom conformance failure. - Reads are repeatable; the disclosure store is monotonic. The store only grows —
recordadds records; nothing removes them. An unfiltered read att2 > t1returns every record visible att1plus any added betweent1andt2.
Feedback
- After
record— a new disclosure record exists in the store;disclosure_id,subject_ref,recipient,scope,authority.type,authority.reference, anddisclosed_atare set and immutable. Thedisclosure_idis returned asrecorded(disclosure_id). - After
read— no state change. A (possibly empty) ordered sequence of disclosure records is returned. Each record carries its full field set.
Each rejected record action produces an observable refusal naming the failed precondition. Each rejected read action produces an observable refusal: invalid-query, naming the filter axis or condition that was malformed.
Invariants
-
Invariant 1 — Record immutability. After a successful
record, the fieldsdisclosure_id,subject_ref,recipient,scope,authority.type,authority.reference, anddisclosed_atnever change, regardless of any subsequent action. There is no action in this atom that modifies a stored disclosure record. -
Invariant 2 — Authority completeness. Every disclosure record in the store carries
authority.typeas one of {consent,legal-hold,regulatory} andauthority.referencecontaining at least one non-whitespace character. A disclosure record with a missingauthorityfield, an unrecognizedauthority.type, or an emptyauthority.referenceis a conformance failure — it cannot answer the regulator’s question “under what authority was this disclosure made?” and defeats the accountability purpose of the atom. -
Invariant 3 — Field completeness. Every disclosure record in the store carries
disclosure_id,subject_ref,recipient,scope,authority.type,authority.reference, anddisclosed_ateach set to a non-absent value.subject_ref,recipient,scope, andauthority.referenceeach contain at least one non-whitespace character.disclosed_atis a timestamp that is set. No field may be null, missing, or (for strings) whitespace-only in a conforming record. A record missing any field is a conformance failure. -
Invariant 4 — Temporal soundness. For every disclosure record in the store,
disclosed_atis not in the future relative to the time the record was created. The constraint is enforced against the resolveddisclosed_at— whether caller-supplied or wall-clock-defaulted — at therecordDecision point before the record is written. A disclosure record whosedisclosed_atis in the future is a conformance failure; it would mean the system claims to have recorded a disclosure that had not yet happened at the time of recording. -
Invariant 5 — No-disclosure-unrecorded (integration invariant). Every transmission of subject data to a party other than the subject is a disclosure event that must produce a disclosure record in this atom. This invariant cannot be enforced internally — the atom records when called; it cannot intercept disclosures that occur without calling it. It is stated here as an integration obligation and a calling-system conformance requirement. Deployments that omit
recordcalls for some disclosure events are non-conforming to this invariant. An external auditor who identifies a disclosure event for which no record exists in the store has identified a system conformance failure. The atom’s accountability purpose is voided by any deployment that does not honor this obligation. -
Invariant 6 — Disclosure store durability and append-only nature. No disclosure record is removed from the store. No disclosure record is modified after creation. The total record count is monotonically non-decreasing. A
disclosure_idreturned by a successfulrecordcall is durably persisted; astorage-failurerejection guarantees no partial record was written. The append-only nature is the structural guarantee that the disclosure history for any subject is complete from the records alone — deletion or modification of a record would break that guarantee in ways an external auditor could not detect without cryptographic tamper evidence.
Examples
Happy path — Consent-authorized disclosure to a research partner
A health research platform has collected patient data from subject patient-sub-7842. The subject previously granted consent for their de-identified data to be shared with a named research partner for oncology research; the Consent record id is consent-8821. The platform executes the disclosure and immediately calls:
record(
subject_ref: "patient-sub-7842",
recipient: "oncology-research-partner-RP3",
scope: "medical-record:de-identified:oncology-fields",
authority: { type: "consent", reference: "consent-8821" },
disclosed_at: "2026-05-13T10:15:00Z"
)
→ recorded(disclosure_id: "disc-0099")
The record is in the store. Six months later, the subject exercises GDPR Article 15 rights and asks what data has been shared about them and with whom. The compliance team queries read({subject_ref: "patient-sub-7842"}) and returns the full disclosure history, including disc-0099. The subject sees: data was disclosed to oncology-research-partner-RP3 on 2026-05-13, under consent consent-8821, covering the de-identified oncology fields. The question is answered from the records alone.
Happy path — Regulatory-mandate disclosure to a public health authority
A covered healthcare entity must report a communicable disease case to the state public health department under HIPAA §164.512(b) — public health reporting. This is a mandatory disclosure that does not require the patient’s consent. The entity executes the report and calls:
record(
subject_ref: "patient-sub-3317",
recipient: "state-public-health-dept-CA",
scope: "medical-record:communicable-disease-report",
authority: { type: "regulatory", reference: "HIPAA §164.512(b) — public health reporting" }
)
→ recorded(disclosure_id: "disc-0100")
disclosed_at is wall-clock-defaulted. The record is in the store. When HHS OCR reviews the entity’s accounting of disclosures, this record confirms the disclosure was made, names the authority, and identifies the recipient. The accounting is complete without recourse to paper logs or developer narration.
Rejection path — missing authority field
A calling system fails to populate the authority field:
record(
subject_ref: "customer-sub-0441",
recipient: "analytics-vendor-AV7",
scope: "behavioral-data:clickstream:2026"
)
→ rejected(invalid-request)
The authority field is missing entirely — a structural violation. No record is created.
Rejection path — unknown authority type
A calling system passes an authority type not in the three named values:
record(
subject_ref: "customer-sub-0441",
recipient: "fraud-prevention-partner-FP2",
scope: "financial-data:transaction-history:90d",
authority: { type: "legitimate-interest", reference: "fraud-prevention-basis" }
)
→ rejected(unknown-authority-type)
type: "legitimate-interest" is not one of {consent, legal-hold, regulatory}. The rejection is unknown-authority-type because all field-level checks pass — subject_ref, recipient, scope, authority.reference are all non-empty and well-formed — but the authority type semantic check fails. No record is created.
Happy path — Legal-Hold-compelled disclosure to a regulatory investigator
A financial institution is subject to an active Legal Hold (lh-5502) requiring preservation and disclosure of transaction records to an SEC investigation team. The institution discloses the records and calls:
record(
subject_ref: "account-sub-0187",
recipient: "SEC-investigation-team-ENF-2026-04",
scope: "financial-data:transaction-records:2023-2025",
authority: { type: "legal-hold", reference: "lh-5502" }
)
→ recorded(disclosure_id: "disc-0101")
disclosed_at is wall-clock-defaulted. The record is in the store. When the SEC examiner requests the institution’s disclosure accounting under Rule 17a-4, this record confirms the compelled disclosure was made, names the legal process under which it was made, and identifies the receiving team. The accounting is complete from the records alone.
Rejection path — future-dated disclosed_at
A calling system mistakenly supplies a timestamp in the future:
record(
subject_ref: "patient-sub-7842",
recipient: "insurance-carrier-IC9",
scope: "medical-record:billing-summary",
authority: { type: "consent", reference: "consent-9910" },
disclosed_at: "2027-01-01T00:00:00Z"
)
→ rejected(invalid-request)
The resolved disclosed_at is in the future relative to the receiving node’s wall clock. A disclosure cannot be recorded as having occurred before it has happened. No record is created.
Regulated adversarial scenarios
Regulator audit — GDPR Article 15 data subject rights request
A GDPR supervisory authority receives a complaint from a data subject who believes their personal data was disclosed to third parties without proper authorization. The authority requests evidence from the data controller. The compliance team queries read({subject_ref: "data-subject-DS-2204"}) — the complete disclosure history for the data subject. The result is every disclosure record for this subject: recipient, scope, authority type and reference, and timestamp for each event. The authority examines each record:
- For records where
authority.typeisconsent, the authority cross-referencesauthority.reference(the Consent record id) against the Consent store to confirm the consent was valid and in scope at the time of disclosure. This cross-referencing is a composing-layer operation; the Selective Disclosure atom provides the reference that makes it possible. - For records where
authority.typeisregulatory, the authority evaluates whether the cited regulation (authority.reference) genuinely required or permitted the disclosure. - For records where
authority.typeislegal-hold, the authority confirms the disclosure was compelled by the named legal process.
Invariant 2 guarantees that every record carries a complete, non-empty authority field. Invariant 3 guarantees that no required field is absent. The supervisory authority has a structurally complete accountability record; no disclosure can be hidden by the absence of a field.
Disputed disclosure — data subject challenges authorization
A data subject asserts that a disclosure to a named recipient (marketing-partner-MP5) was not authorized by any consent they provided and no regulatory mandate permitted it. The system’s compliance team queries read({subject_ref: "data-subject-DS-9871", recipient: "marketing-partner-MP5"}). The result is every disclosure record naming that recipient for that subject.
Each record is examined. Suppose the result contains two records: one with authority.type: consent, authority.reference: "consent-3301" and one with authority.type: regulatory, authority.reference: "GDPR Art. 6(1)(f) — legitimate interests". The data subject’s challenge goes to whether consent-3301 was a valid, informed, specific consent at the time of disclosure, and whether Article 6(1)(f) was a valid basis for the second disclosure. The Selective Disclosure atom does not adjudicate these questions — it does not validate Consent records or evaluate regulatory interpretation. It provides the authority references that let the compliance team and the data subject each direct the dispute to the right place: the Consent store for the first record, a legal analysis of Article 6(1)(f) for the second. Without these records, the dispute cannot be investigated. With them, the investigation has a complete, immutable starting point.
Breach or incident forensics — determining what data left the system
During a security incident investigation, the incident response team needs to establish what subject data was disclosed in the 72-hour window surrounding the suspected breach (2026-05-10T00:00:00Z through 2026-05-12T23:59:59Z), to identify whether any unauthorized disclosures occurred under cover of or in addition to authorized ones. The team queries:
read({disclosed_at: {after: "2026-05-10T00:00:00Z", before: "2026-05-12T23:59:59Z"}})
The result is every disclosure record in the window. The team reviews each record: was each recipient a legitimate recipient? Does each authority reference correspond to a valid Consent record, a real Legal Hold, or a genuine regulatory mandate? Are there records naming recipients the team does not recognize as authorized parties?
Because Invariant 6 guarantees the store is append-only and no record can be deleted, the team can rely on the completeness of the result — any disclosure that was recorded is in the result; any gap between a known disclosure event and the result set is a system conformance failure under Invariant 5 (no-disclosure-unrecorded). The forensic question “what data left the system in this window?” is answerable from the records alone. A subsequent query read({disclosed_at: {after: "2026-05-10T00:00:00Z", before: "2026-05-12T23:59:59Z"}, authority_type: "consent"}) returns only consent-authorized disclosures in the window, enabling the team to compare the consent-authorized set against the full set and identify any records with authority_type: legal-hold or authority_type: regulatory that warrant additional scrutiny.
Generation acceptance
Any implementation derived from this atom must produce records and a runtime surface that pass the following checks from the records alone, without recourse to source code, runbooks, or developer narration:
-
Disclosure record completeness check. For a set of
disclosure_ids known to have been issued, confirm thatread({disclosure_id: X})returns each of them. No issueddisclosure_idmay be absent from the store. An implementation that loses records after creation fails this check. -
Field completeness check. For every disclosure record in the store: confirm that
disclosure_id,subject_ref,recipient,scope,authority.type,authority.reference, anddisclosed_atare each present and non-null. Confirm thatsubject_ref,recipient,scope, andauthority.referenceeach contain at least one non-whitespace character. Confirm thatdisclosed_atis a set timestamp. Confirm thatauthority.typeis one of {consent,legal-hold,regulatory}. A record missing any field or carrying a whitespace-only string field or an unrecognizedauthority.typeis a conformance failure under Invariants 2 and 3. -
Record immutability check. At time
t1, issueread({})(unfiltered) and record the result set S1. Create one new disclosure record and confirm therecordcall returnedrecorded(disclosure_id). At timet2 > t1, issueread({})again and record result set S2. Confirm every record in S1 appears in S2 bydisclosure_id(no record removed). For each record in both S1 and S2, confirm all fields are unchanged in S2 — every field is immutable per Invariant 1. The total record count in S2 is ≥ the count in S1 (store is append-only per Invariant 6). A record whose fields changed between S1 and S2 is a conformance failure; a record present in S1 but absent in S2 is a conformance failure. -
Authority type enforcement check. Attempt
recordwithauthority.typeset to a value not in {consent,legal-hold,regulatory} (for example,"legitimate-interest"or"internal-policy"). Confirm the call returnsrejected(unknown-authority-type). Confirm no record is created. Then attemptrecordwith each of the three validauthority.typevalues and a well-formedauthority.reference; confirm each returnsrecorded(disclosure_id)and a record appears in the store with the correctauthority.type. Invariant 2 guarantees authority completeness; this check verifies that the enforcement boundary is operative. -
Subject disclosure history queryability check. Record at least three disclosure events for the same
subject_ref, each with a differentrecipientandauthority. Queryread({subject_ref: X}). Confirm the result contains all three records. Queryread({subject_ref: X, authority_type: "consent"}). Confirm only records withauthority.type: consentappear. Confirm thatread({subject_ref: X})for a subject with no disclosure records returns an empty sequence (not a rejection). This check verifies the primary regulatory use case — the complete disclosure history for a data subject is queryable from the records alone. The empty-result case verifies that the absence of disclosure records is a valid (non-error) answer. -
Temporal soundness check. Attempt
recordwith adisclosed_atvalue in the future (a timestamp at least one second beyond the receiving node’s current wall clock). Confirm the call returnsrejected(invalid-request). Confirm no record is created. Then confirm that arecordcall without adisclosed_atparameter succeeds and produces a record whosedisclosed_atis not in the future relative to the wall clock at the time of the call. Invariant 4 guarantees temporal soundness; this check verifies it is enforced against both caller-supplied and wall-clock-defaulted values.
Audit gaps: what cannot be cleared from these records alone
The six checks above cover every invariant the atom enforces internally. Three audit questions arise around this atom that cannot be answered from these records alone; an external auditor must compose with other patterns to clear them. They are named here so the audit boundary is explicit and so the auditor knows where to direct each unclearable question.
- Authority legitimacy is unclearable. Check 4 verifies that
authority.typeis one of the three named values and thatauthority.referenceis non-empty. It does not — and cannot — verify that the referenced authority was actually valid atdisclosed_at. A record carryingauthority: { type: "consent", reference: "consent-3301" }discloses that the calling system claimed Consent recordconsent-3301as the basis; whether that Consent was granted, in scope, and not revoked atdisclosed_atis unclearable from this atom’s records. Auditors verify authority legitimacy by composing with the Consent store (fortype: consent), the Legal Hold store (fortype: legal-hold), or by reading the cited regulation (fortype: regulatory). Semantic consistency betweenauthority.typeandauthority.reference— e.g., atype: consentcarrying a reference that is plainly a regulatory citation — is also unclearable here; it is the calling system’s obligation (named in theauthority.referencefield description and in Edge cases). - Invariant 5 conformance is unclearable from inside the store. Whether the calling system called
recordafter every disclosure event cannot be verified by reading the disclosure store alone — gaps are invisible to a query that only sees what was recorded. An external auditor verifies Invariant 5 by cross-referencing the disclosure store against the calling system’s Event Log, against transmission logs at the egress boundary, against complaint records, or against the recipient’s own intake records, and finding any disclosure event for which no corresponding record exists here. The atom’s records are the positive evidence (what was recorded); Invariant 5 conformance also requires negative evidence (no disclosure occurred outside the store), which lives outside this atom. - Backdating detection requires a recording timestamp this atom does not store. The atom stores
disclosed_at(the declared disclosure time) but no separate creation timestamp. Arecordcall invoked today withdisclosed_at: "2024-01-01"produces a record that looks like a 2024 disclosure. Detection that the record was actually written today requires comparing the disclosure record against the corresponding Event Log entry’s receipt timestamp; the Audit Trail composition is the audit surface where this comparison is exposed. See the clock-semantics Edge case for the full statement.
Edge cases and explicit non-goals
-
The atom does not perform disclosures. The atom records that a disclosure occurred; it does not retrieve subject data, apply redaction or anonymization, route data to recipients, or validate that the disclosed data matches the declared scope. All of these are the calling system’s concern. The
scopefield is the calling system’s declaration of what was disclosed; the atom does not verify it. A system that recordsscope: "contact-fields-only"but actually transmitted the full medical record has produced an inaccurate disclosure record — this is a calling-system failure, not an atom failure. -
Subject-comprehensible
scopevocabulary is a calling-system obligation. The atom recordsscopeas an opaque string; it imposes no vocabulary, no controlled list, and no readability requirement. A data subject exercising GDPR Article 15(1)(c) rights must be told the categories of data disclosed in language they can act on; ascopevalue of"tbl_disc_oncology_42"would satisfy this atom but fail the Article 15 obligation. The calling system is responsible for choosing ascopevocabulary that is meaningful to the regulatory audience that will read the record — data subjects under GDPR, OCR inspectors under HIPAA §164.528, examiners under SEC Rule 17a-4. Parallel to therecipientvocabulary obligation immediately below: both fields are opaque to this atom, and both place a readability obligation on the calling system that this atom cannot enforce. An auditor cannot verify subject-comprehensibility ofscopestrings from the records alone without familiarity with the calling system’s vocabulary; this is the documented audit gap forscopesemantics. -
Subject-recognizable
recipientvocabulary is a calling-system obligation. The atom recordsrecipientas an opaque string. GDPR Article 15(1)(c) requires the controller to name the recipients or categories of recipients to whom personal data has been or will be disclosed, in terms the data subject can act on. Arecipientvalue of"partner-AV7"is structurally valid here but does not satisfy Article 15 if the data subject cannot resolve it to a named legal entity. The calling system is responsible for choosingrecipientstrings that are either directly subject-recognizable or for maintaining a calling-system-side mapping from opaque recipient ids to subject-facing recipient names; the atom records what the calling system declares and exposes it throughread. Reference-axis filtering ofrecipientis exact-match, not name-resolved — a queryread({subject_ref: X, recipient: "Acme Marketing Inc"})matches only records whoserecipientfield is exactly that string. Cross-reference with a recipient registry is a composing-layer operation, not provided by this atom. -
Authority reference validation is the calling system’s obligation. For
authority.type: consent, the atom does not validate thatauthority.referenceis a real Consent record id, that the Consent record is in a valid state, or that the disclosure scope falls within the Consent’s granted scope. Forauthority.type: legal-hold, the atom does not validate thatauthority.referenceis a real Legal Hold id or that the hold is Active. Forauthority.type: regulatory, the atom does not validate that the regulatory citation is accurate or applicable. All validation of authority reference validity is the calling system’s obligation. The atom enforces only structural completeness: that theauthorityfield is present, thattypeis one of the three named values, and thatreferencecontains at least one non-whitespace character. -
recordis not idempotent. Tworecordcalls with the same parameters create two independent disclosure records with distinctdisclosure_ids. If the calling system needs at-most-once semantics under retry conditions — for example, when a disclosure is recorded in a distributed system and the network acknowledgment is lost — compose with Duplicate Prevention. -
Correction of an inaccurate disclosure record. Once a disclosure record is created, it cannot be modified or deleted. A
recordcall that captured an incorrectscope, wrongrecipient, or wrong authority reference produces a permanent record. The correct approach when an error is discovered is to create a newrecordwith accurate fields, with ascopeorauthority.referencenarrative that identifies the relationship to the inaccurate record. The original record remains in the store as evidence of what was recorded at the time; the new record provides the accurate account. An auditor reviewing both records sees the full history, including the correction. This pattern parallels Legal Hold’s approach to case-reference updates: immutability of the original is not a bug; it is the structural guarantee that records cannot be silently altered after the fact. -
Disclosures to the subject themselves. A data subject requesting a copy of their own records under GDPR Article 15 is exercising a right that requires a response, but the atom’s no-disclosure-unrecorded obligation does not apply to the response to that request. The Article 15 response is the disclosure of data to the data subject themselves; the obligation in Article 15(1)(c) is to disclose the recipients to whom the data has been communicated, not to record the act of communicating the data to the subject as a Selective Disclosure event. Whether the Article 15 response itself should be recorded is a deployment policy question. This atom does not resolve it; the compliance team decides based on their regulatory interpretation.
-
Bulk disclosures. One
recordcall creates one disclosure record for one subject-recipient-scope event. A disclosure of data for multiple subjects simultaneously — for example, a batch report to a public health authority covering many patient records — requires onerecordcall per subject. The atom does not support batchrecordcalls. Bulk recording is a composing-layer operation that callsrecordfor each subject. For atomic all-or-none semantics (either all subjects are recorded or none are), a transaction wrapper in the composing layer is required; this atom does not provide it. -
Retention Window interaction. Disclosure records are created with no inherent expiry. How long they must be retained — and when (if ever) they may be purged — is a composing Retention Window concern. GDPR Article 30 requires records of processing activities to be maintained as long as the processing occurs and typically beyond; HIPAA §164.528(d) requires the accounting of disclosures to be retained for six years. The composing layer applies the appropriate retention policy. This atom does not define or enforce retention windows.
-
Tamper-evidence. The atom guarantees immutability by specification — no action in the atom modifies a stored record. It does not cryptographically prevent a store administrator with write access from altering disclosure records. For court-admissible accountability records and for SEC Rule 17a-4’s non-erasable, non-rewritable standard, compose with Tamper Evidence, which provides cryptographic sealing. Tamper-evident disclosure records are required under several regulatory regimes.
-
Access control. Who may call
recordand who may callread— and with what filter scope — is not defined by this atom. That is the obligation of a composing Permissions pattern. In regulated deployments, unrestricted access to the full disclosure store may expose subject identity and disclosure patterns to actors who should not have that access; scoped read access (a data subject may query their own records; a regulator may query a scoped window; compliance staff have broader access) is a deployment concern. -
Non-repudiation of the recording actor. The atom records that a
recordcall was made and what it contained; it does not record who made the call or bind a cryptographic proof to the recording action. If the calling system’s identity must be non-repudiably bound to the disclosure record — for example, to prove that the compliance officer who recorded a disclosure actually made the call — compose with Actor Identity. The disclosure record is the gate; Actor Identity provides the signature. -
Clock semantics.
disclosed_atdefaults to the receiving node’s wall clock when not supplied by the caller. The resolveddisclosed_atmust not be in the future — enforced at the Decision point against the resolved value regardless of whether it was caller-supplied or wall-clock-defaulted. Backdateddisclosed_atvalues are accepted — documenting a disclosure that was recognized or reported after the fact is valid in some regulated contexts, including breach notification timelines — but a backdated value records the declared disclosure time, not the current time. The atom imposes no lower bound ondisclosed_at: a value of"1970-01-01T00:00:00Z"would be accepted. Clock skew between caller and atom can cause a caller-supplieddisclosed_atthat is “current” by the caller’s clock to be rejected asinvalid-requestwhen the atom’s clock places it in the future; this is the correct rejection — the temporal invariant is enforced against the atom’s resolved value, not against the caller’s belief about the time. Backdating detection — distinguishing the declareddisclosed_atfrom the time therecordcall was actually received — is not a property of this atom; the atom stores onlydisclosed_at. The composing Event Log entry that captures eachrecordcall carries the call’s receipt timestamp; a Selective Disclosure record with adisclosed_atmaterially earlier than its corresponding Event Log entry’s receipt timestamp is the audit signal that the disclosure was backdated. The Audit Trail composition surfaces this comparison; this atom does not. Clock skew, timezone normalization, and monotonicity are deployment concerns. -
Concurrency. Multiple concurrent
recordcalls — including multiple concurrent calls for the samesubject_ref— do not conflict and do not require serialization with each other. Each produces its owndisclosure_idand its own independent record. Implementations must serialize only the store write for a single call to ensure that a singledisclosure_idis issued exactly once per successfulrecordcall.
Composition notes
Selective Disclosure is the disclosure accountability primitive that regulated data-handling systems compose with when they must prove what was shared, with whom, and under what authority:
- Actor Identity — provides non-repudiable attribution of the actor who recorded the disclosure.
recordcalls are themselves actions of consequence in regulated systems; Actor Identity binds the compliance officer or system actor who made the call to the disclosure record, satisfying the chain of custody requirement for the recording action as distinct from the disclosure event itself. - Legal Hold — a Legal Hold id may appear as
authority.referencewhenauthority.typeislegal-hold, indicating that the disclosure was compelled by an active legal process. Legal Hold and Selective Disclosure are composing peers: Legal Hold governs preservation of records; Selective Disclosure records when those records were disclosed to third parties under compulsion. Neither atom imports the other’s semantics; both may be active simultaneously on the same subject’s records. - Consent (forthcoming) — a Consent record id appears as
authority.referencewhenauthority.typeisconsent. Consent governs whether the data subject has authorized a category of processing; Selective Disclosure records that a disclosure under that authorization occurred. The Consent atom validates whether consent was granted; the Selective Disclosure atom records that the disclosure happened. - Retention Window — governs how long disclosure records must be retained before they may be purged. GDPR Article 30 and HIPAA §164.528(d) impose specific retention obligations on disclosure accounting records; Retention Window is the atom that enforces them. Selective Disclosure creates the records; Retention Window governs their lifecycle.
- Tamper Evidence — cryptographically seals disclosure records against post-hoc modification. For SEC Rule 17a-4, HIPAA, and court-admissible disclosure accounting, tamper-evident records are required. Tamper Evidence is the composing atom that lifts this atom’s spec-level immutability guarantee to a cryptographically verifiable guarantee.
- Event Log — disclosure events are system events that an Event Log captures in its general-purpose stream. The Selective Disclosure record is the structured, authority-bearing disclosure-specific form; the Event Log entry is the timestamped, attributed, general-purpose record. Both coexist in regulated deployments; neither replaces the other.
- Permissions — governs who may call
recordand who may query the disclosure store with what filter scope. Scoped read access is essential in deployments where the disclosure store contains sensitive subject identity and disclosure pattern information. - Duplicate Prevention — for at-most-once semantics on
recordcalls under retry conditions. - Audit Trail — the canonical regulated-audit stack (Event Log + Actor Identity + Retention Window + Tamper Evidence) captures every disclosure recording action with attribution and tamper evidence; the Selective Disclosure record is a structured sidecar to the Audit Trail entry.
- Immutable Transaction Ledger with Selective Disclosure (forthcoming, composition C6) — Selective Disclosure + Event Log + Tamper Evidence + Actor Identity + Retention Window + Idempotent Reservation. Makes a transaction record both non-repudiable and selectively shareable: the full ledger is tamper-evident; a subset can be disclosed to a counterparty or regulator without breaking the integrity of the chain that remains.
- Data Subject Rights Fulfillment (forthcoming, composition C7) — Legal Hold + Consent + Selective Disclosure + Audit Trail + Retention Window + Actor Identity + Event Log. Makes data subject rights mechanically answerable: a DSAR request triggers a structured query across the composition’s constituent records; the Selective Disclosure store is the primary source for Article 15(1)(c) responses naming recipients.
Standards references
- GDPR Article 15(1)(c) — the data subject’s right of access includes the right to know the recipients or categories of recipients to whom their personal data has been or will be disclosed. Selective Disclosure is the accountability layer that makes Article 15(1)(c) responses structurally answerable from records alone. Every disclosure record’s
recipientfield andauthorityfield are the data the Article 15 response draws from. - GDPR Article 30 (Records of processing activities) — controllers must maintain records of processing activities, including categories of recipients to whom personal data has been or will be disclosed, and transfers to third countries or international organizations. Disclosure records under this atom are the processing-activity records Article 30 requires for the disclosure category of processing.
- HIPAA §164.528 (Accounting of disclosures of protected health information) — individuals have the right to receive an accounting of disclosures of their PHI made by a covered entity or business associate. The accounting must include the date of each disclosure, the name and address of the recipient, a brief description of the PHI disclosed, and a brief statement of the purpose. Each field maps directly:
disclosed_at(date),recipient(recipient name),scope(description of PHI),authority.reference(purpose statement). The atom is the structural implementation of §164.528’s accounting obligation. - SEC Rule 17a-4 — broker-dealers must preserve records in non-rewriteable, non-erasable format, accessible to regulators on demand. Disclosure records for broker-dealer records are themselves required records under 17a-4. Composing with Tamper Evidence satisfies the non-rewriteable, non-erasable standard; this atom provides the disclosure record structure.
Status
grounded — 2026-05-20 — foundation round (Pass 1 + Pass 2 + Pass 3, author-led), Round 2 (Pass 1 + Pass 2 + Pass 3, AI-conducted, claude-sonnet-4-6), and Round 3 (Pass 1 + Pass 2 + Pass 3, AI-conducted adversarial, claude-opus-4-7, Torvalds posture) complete. All nine GRID nodes resolved; all concerns conceptually independent; all surfaced adversarial gaps closed in-pattern or named as explicit out-of-scope. Audit gaps that cannot be cleared from this atom’s records alone — authority legitimacy, Invariant 5 conformance, and backdating detection — are named explicitly in the Audit gaps subsection of Generation acceptance and in Edge cases, with the composing patterns that surface each unclearable question.
Lineage notes
Regulated atom. Conventions — Regulated adversarial scenarios and Generation acceptance — inherited from the methodology directly (PRESSURE_TESTING.md), baked in from the first draft. Legal Hold is the primary shape reference for this atom; Approval Step is the secondary reference for Round-2-clean conventions. No existing atom named Selective Disclosure as *(forthcoming)* in Composition notes.
Pass 1 — Structural completeness (GRID). Six findings, all closed in-pattern.
-
Store instance model absent. Initial draft referenced “the disclosure store” without defining instance topology. Parallel finding to Legal Hold, Approval Step, and every atom composing against a named store. Fixed: Store instance model subsection added, mirroring Legal Hold.
disclosure_iduniqueness scoped to instance;subject_refnoted as scoped to the host system; instance selection named as deployment-routing concern. -
No-state-machine design not explicitly stated. The initial draft treated the absence of a state machine as implicit. An atom with no state transitions looks like an incomplete spec to a GRID Pass 1 reviewer. Fixed: State section opens by explicitly naming the design — no state machine, no transitions, records are immediately and permanently in the store — and contrasts with the state-machine atoms to show the distinction is deliberate. The store-level state (append-only set) is also named.
-
readordering and filter semantics not defined. Initialreadaction had no stated ordering, no enumeration of supported filter axes, noinvalid-queryconditions, and no statement for an empty result. Fixed:readaction description updated to specifydisclosed_atascending ordering withdisclosure_idas stable tiebreaker, enumerate the five supported filter axes, name allinvalid-queryconditions, generalize the timestamp-absent-field rule, and state that a well-formed query matching no records returns an empty sequence. -
Outputs section under-specified. Initial draft listed only
disclosure_idand the query result without enumerating which fields are present on every record. Fixed: Outputs section now explicitly names all fields present on every record (no state-specific field variants — all fields are universal per the no-state-machine design) and notes that theauthorityfield is always structured with both sub-fields. -
GRID Feedback node missing. The initial draft had no Feedback section. Fixed: Feedback section added, specifying the observable result after
record(the disclosure record with all fields set and immutable; thedisclosure_idreturned) and afterread(no state change; ordered sequence returned), and confirming that each rejectedrecordaction produces an observable refusal naming the precondition. -
GRID Proof node (Generation acceptance) absent from initial structure. The section was outlined but contained only placeholders. Fixed: Generation acceptance written in full with six numbered checks covering record completeness, field completeness, immutability, authority type enforcement, subject history queryability, and temporal soundness.
All nine GRID nodes resolved.
Pass 2 — Conceptual independence (EOS). Clean. Five extraction candidates evaluated; all kept in-pattern or correctly excluded.
-
Disclosure scope interpretation as over-absorption candidate. Could the atom absorb a scope taxonomy — validating that
scopevalues are from a controlled vocabulary, interpreting what “scope” means for a given subject, or resolving which records fall within a scope? Evaluated:scopeis opaque to the atom — it is the calling system’s declaration, not the atom’s interpretation. The atom records the declared scope; it does not validate, classify, or evaluate it. Parallel tocase_refin Legal Hold andscopein Approval Step. Clean. -
Consent validation as over-absorption candidate. Could the atom validate that an
authority.referenceof typeconsentcorresponds to a real, currently valid Consent record? Evaluated: this would require the atom to name and depend on the Consent store — importing Consent’s state machine and lifecycle semantics. That breaks freestanding status. Authority reference validation is the calling system’s obligation (named as an explicit non-goal in Edge cases). Clean. -
Authority enforcement as over-absorption. Could the three-type authority model (consent, legal-hold, regulatory) imply the atom should enforce which authority type is valid for a given disclosure — e.g., rejecting a
consentauthority for a mandatory regulatory reporting disclosure? Evaluated: authority appropriateness is a compliance and legal determination, not an atom-level invariant. The atom enforces only that authority is present, type is one of the three named values, and reference is non-empty. Whether the type is appropriate for the context is the calling system’s obligation. Clean. -
Recipient validation as over-absorption. Could
recipientimply a recipient registry — a store of known, vetted recipients against which disclosure records are validated? Evaluated:recipientis opaque to the atom, parallel toactor_refin Actor Identity andrecord_refin Legal Hold. A recipient registry is a separate composing concern. Clean. -
No-disclosure-unrecorded as an enforced behavioral invariant vs. an integration invariant. Could the atom enforce the no-disclosure-unrecorded obligation by intercepting disclosure operations? Evaluated: this would require the atom to know about the disclosure mechanism — the storage layer, the routing system, the data retrieval service. That absorbs concerns from every composing pattern. The obligation must be stated as an integration invariant and a calling-system obligation. Invariant 5 does exactly this, with explicit acknowledgment that the atom cannot enforce it internally. Clean.
Pass 3 — Adversarial scrutiny (Linus mode). Thirteen findings, all closed in-pattern. Most findings preempted by authoring against the established Pass 3 pattern list from Legal Hold and Approval Step.
-
Identity model unclear on
disclosed_atbeing a property, not identity. The initial Outputs section mentioneddisclosed_atamong the id fields without clearly separating it. Fixed: Identity model section follows Legal Hold’s pattern exactly —disclosure_idis the identity; all other fields are immutable properties. -
“Supplied” definition for optional parameters absent. Parallel to every prior atom’s Pass 3 finding. Fixed: definition statement added before the action list, exactly matching Legal Hold and Approval Step’s formulation.
-
disclosed_attemporal invariant qualified as “if supplied.” The initial draft applied the not-in-future check only to caller-supplieddisclosed_at. A wall-clock-defaulted value on a clock-skewed node could violate the invariant while the action accepts it. Fixed:recordaction description and Decision point enforce the bound against the resolveddisclosed_at— caller-supplied or wall-clock-defaulted — before the record is written. Invariant 4 states the constraint applies to the persisted value, not only to caller-supplied values. The temporal invariant is unconditional. -
Rejection priority absent from
recordaction. The initialrecorddescription listed rejection reasons but not their evaluation order. Two conditions could fail simultaneously (invalid-requestfor emptyscopeandunknown-authority-typefor badauthority.type); the caller needs to know which is checked first. Fixed: rejection priority added —invalid-request→unknown-authority-type→storage-failure— and therecordaction description specifies that field-level checks complete before authority type is evaluated. -
Invariants used “non-empty” for string fields. Parallel to every prior atom’s Pass 3 finding. Fixed: all invariants now say “at least one non-whitespace character” for string fields and “set” for timestamps, matching the Decision point and action signature wording.
-
Invariant 4 description was “non-empty” applied to a timestamp. The initial draft said
disclosed_atmust be “non-empty.” A timestamp is not a string. Fixed: Invariant 4 saysdisclosed_atis “a timestamp that is set,” and Invariant 3 distinguishes between string fields (non-whitespace character) and the timestamp field (set). -
Append-only nature not stated as an invariant. The no-state-machine design implies append-only, but the implication must be a named invariant. Fixed: Invariant 6 states explicitly that no record is removed from the store, no record is modified after creation, and the total record count is monotonically non-decreasing.
-
No-disclosure-unrecorded not named as a calling-system obligation. The initial draft mentioned the obligation inline but did not name it as an invariant. The obligation must be formal and explicit — regulators do not accept implicit obligations. Fixed: Invariant 5 named descriptively, stated as an integration invariant and calling-system conformance requirement, with explicit acknowledgment that the atom cannot enforce it internally and that a gap between a known disclosure event and the disclosure store is a system conformance failure.
-
readunknown filter key behavior unstated. Parallel to every prior atom. Fixed:readaction and Decision point now state that unknown filter keys areinvalid-queryrather than silently ignored, with stated rationale. -
readempty-result semantics not named. For Selective Disclosure specifically, the empty result case has regulatory significance — an emptyread({subject_ref: X})means no disclosures have been recorded for subject X, which is a meaningful compliance answer. The initial draft was silent. Fixed:readaction explicitly states that a well-formed query matching no records returns an empty sequence with a brief note that this is itself a meaningful compliance answer. -
authority_typefilter inreadnot defined. The initial draft listed supported filter axes but did not nameauthority_typeor define how it maps toauthority.type. Areadcaller cannot filter by authority type without knowing the filter axis name. Fixed:readaction definesauthority_typeas a filter axis taking one of the three named values, matching records whereauthority.typeequals the value. The axis name isauthority_type(the field path flattened to a single key). -
Concurrency statement was vague. Initial draft said “concurrent calls are independent” without specifying what requires serialization and what does not. Fixed: Behavior section and Edge cases both specify that concurrent
recordcalls for the samesubject_refare not an error; each produces its owndisclosure_idand its own record. No cross-call serialization is required. Implementations must serialize only the store write for a single call. -
Generation acceptance check for subject history queryability did not include the empty-subject case. A system that returns
rejected(invalid-query)for a well-formedread({subject_ref: X})where X has no records would fail the regulatory use case without being caught by a check that only tests non-empty subjects. Fixed: Generation acceptance check 5 explicitly includes the empty-subject case as a verification requirement.
Round 2, Pass 1 — Structural completeness (GRID). AI-conducted (claude-sonnet-4-6). 2026-05-13. Two findings, both closed in-pattern.
-
Examples section did not exercise the
legal-holdauthority type. The three validauthority.typevalues areconsent,legal-hold, andregulatory. Examples coveredconsent(happy path 1) andregulatory(happy path 2) but leftlegal-holdunexercised. The GRID Proof node requires that examples exercise the complete set of valid paths. Fixed: added a third happy-path example — Legal-Hold-compelled disclosure to an SEC investigation team — coveringauthority.type: legal-holdand a wall-clock-defaulteddisclosed_at. -
Feedback node silent on
readrejections. The Feedback section stated that each rejectedrecordaction produces an observable refusal naming the failed precondition but made no mention ofreadrejections. GRID Feedback requires the node cover what the caller receives on each rejection path for all actions. Fixed: Feedback section now explicitly states that each rejectedreadaction produces an observable refusal (invalid-query) naming the malformed filter axis or condition.
All nine GRID nodes confirmed resolved. Pass 1 clean after two findings closed.
Round 2, Pass 2 — Conceptual independence (EOS). AI-conducted (claude-sonnet-4-6). 2026-05-13. Two precision gaps found and closed; no extraction candidates promoted.
-
scopefield description implied a required naming convention. The description used illustrative"category:subcategory"examples in a way that read as prescriptive, implying the atom owns a scope vocabulary. The atom does not —scopeis opaque, and its vocabulary is the calling system’s concern. Fixed: description rewritten to explicitly mark the examples as illustrative and name scope vocabulary as a calling-system concern. -
authority.referencedescription read as prescriptive validation. The field description said “a Consent record id fortype: consent” as if the atom validates that the reference matches the type. The atom accepts any non-whitespace string asauthority.referenceregardless of type — semantic consistency betweenauthority.typeandauthority.referenceis the calling system’s obligation. Fixed: description rewritten to name what the calling system is expected to provide vs. what the atom actually enforces, with the semantic-consistency obligation explicitly placed on the calling system.
All five foundation extraction candidates re-evaluated independently; all conclusions confirmed. The recording-vs-performing boundary held throughout — no over-absorption into disclosure delivery, scope resolution, data retrieval, or redaction concerns identified. Pass 2 clean after two precision gaps closed.
Round 2, Pass 3 — Adversarial scrutiny (Linus mode). AI-conducted (claude-sonnet-4-6). 2026-05-13. Nine findings, all closed in-pattern.
-
subject_refidentity underspecified. The atom calledsubject_refan “opaque reference” without stating what kind of thing it is — user id, email, record id, or something else. An implementer cannot produce a conformant system without knowing what the field contains. Fixed:subject_refnow explicitly described as an opaque string whose interpretation is the calling system’s concern, with the atom treating it as a comparable key for filtering purposes only. -
disclosure_iduniqueness enforcement basis not named. The Identity model asserted thatdisclosure_idis “assigned onrecord, never reused, never reassigned within the store instance” but did not name the two scopes of the same guarantee — the action-level assignment that produces a fresh id on eachrecordcall and the store-level rejection of any write that would reuse an id. Fixed: Identity model section now names both scopes of the uniqueness guarantee. (Round 3 note: the Lineage entry as originally written referred to “Invariant 2” — at the time, an earlier draft of the invariant ordering. The fix actually landed in the Identity model section, not in any numbered Invariant; the description here is corrected to reflect the file that was edited.) -
readtime-range filter sub-keys undefined. The breach forensics example useddisclosed_at: { after: ..., before: ... }as ifafterandbeforewere formally defined filter sub-keys with named semantics. They were not defined anywhere in the atom. Fixed:readaction definition formally specifiesafterandbeforeas optional sub-keys of thedisclosed_atrange filter, with closed-interval (inclusive) semantics named explicitly. -
authority_typefilter key vs.authority.typefield path unexplained. Thereadaction definedauthority_typeas a filter axis but never explained why the filter key isauthority_type(a flat string) rather thanauthority.type(the dot-notation field path). Fixed: thereadaction description notes that filter keys are flat strings, not dot-notation paths, and thatauthority_typeis the flattened form of theauthority.typesub-field. -
Semantically inconsistent
authorityaccepted silently. A caller can pass{ type: "consent", reference: "HIPAA §164.512(b)" }— a type claiming consent authorization but a reference that is plainly a regulatory citation. The atom accepts this; the semantic inconsistency is the calling system’s obligation. This was not stated anywhere. Fixed: theauthority.referencefield description and Edge cases both name this explicitly: the atom enforces only structural validity, not semantic consistency between type and reference. -
Non-idempotent
recordbehavior had no example. Two calls with identical parameters produce two distinct records — this is deliberate and correct, but with no example, an implementer might assume idempotency or de-duplication. Fixed: a concrete rejection-path (actually a behavior example) added showing two calls with identical parameters producing two distinctdisclosure_idvalues and two records in the store. -
disclosed_atbackdating lower bound was a hidden decision. The atom accepted arbitrarily backdateddisclosed_atvalues (e.g.,"1970-01-01T00:00:00Z") without comment. This is intentional — disclosure records may legitimately need to be recorded after the fact with the actual disclosure timestamp — but the intent was never stated. Fixed: Edge cases clock semantics section explicitly names that the atom imposes no lower bound ondisclosed_atand explains the rationale. -
Clock skew consequence not stated. The atom named clock skew as an edge case but did not state its concrete consequence: a valid caller-supplied
disclosed_atvalue within the caller’s clock may be rejected as “in the future” by the atom’s wall clock. Fixed: Edge cases clock semantics section states the consequence explicitly and names thatinvalid-requestis the correct rejection in this case, with the rationale that the temporal invariant is enforced against the atom’s resolved value, not the caller’s. -
Generation acceptance check 1 overclaimed “from records alone.” Check 1 required an auditor to verify that every issued
disclosure_idis present in the store — but in production, an auditor using only the store cannot enumerate all issueddisclosure_ids without the originalrecordcall responses. Fixed: check 1 scoped to test and audit environments where return values are observable; production auditors directed to check 3 (append-only guarantee) for the equivalent assurance from the store alone.
Round 3 — AI-conducted adversarial round (claude-opus-4-7, Torvalds posture, independent re-run). 2026-05-13. Five findings, all closed in-pattern. Round 3 re-ran all three passes with fresh-reader discipline; the reviewer had no recourse to prior-round rationales beyond what the spec itself states.
Pass 1 — GRID structural. One finding, closed in-pattern.
- Status line finding count did not match the Lineage notes. The prior Status line summarized “13 findings closed in-pattern across the foundation round; 11 further findings closed across Round 2.” The foundation round actually carries 6 (Pass 1) + 13 (Pass 3) = 19 closures, plus Pass 2 evaluated five extraction candidates without promoting any. Round 2 carries 2 (Pass 1) + 2 (Pass 2 precision gaps) + 9 (Pass 3) = 13 entries depending on how precision gaps are counted. The numeric headline drifted from the underlying tallies in both rounds. Fixed: Status line rewritten in the convention used by other grounded atoms in the library — naming the rounds completed and the disposition without a numeric headline — and naming the audit gaps the atom does not clear from records alone. The per-pass entries in the Lineage notes continue to carry the per-pass finding counts; the Status line is no longer a redundant aggregate.
Pass 2 — EOS conceptual independence. Clean. Five foundation extraction candidates and two Round 2 precision gaps re-evaluated without recourse to prior conclusions. Recording-vs-performing boundary held: no over-absorption into disclosure delivery, scope resolution, recipient registry, or authority-store validation identified. No new extraction candidates promoted.
Pass 3 — Adversarial scrutiny (Linus mode). Three findings, all closed in-pattern.
-
scopeopaqueness left the subject-comprehensibility obligation unstated. The atom recordsscopeas an opaque string and (after Round 2) named scope vocabulary as a calling-system concern. But the calling-system obligation that the vocabulary be subject-comprehensible — the load-bearing requirement for GDPR Article 15(1)(c) — was never explicit. A calling system could recordscope: "tbl_disc_42"(structurally valid) and produce a record that fails Article 15 regardless of the atom’s enforcement. Fixed: an Edge case added naming subject-comprehensiblescopevocabulary as a calling-system obligation, with the regulatory framing (GDPR Article 15, HIPAA §164.528, SEC 17a-4) named explicitly and the audit-gap consequence stated — an auditor cannot verify subject-comprehensibility of opaque strings from the records alone. -
recipientopaqueness placed an unnamed obligation on the calling system for GDPR Article 15. The atom recordsrecipientas an opaque non-whitespace string; the obligation to use names a data subject can act on — required by Article 15(1)(c) — was never stated. Arecipient: "partner-AV7"is structurally accepted here but is not an Article 15 conformant recipient name unless the data subject can resolve it. The atom never told the calling system that resolving the opaqueness for the regulatory audience is the calling system’s job. Fixed: an Edge case added naming the subject-recognizablerecipientvocabulary obligation, with the exact-match filtering semantics restated and the option of a calling-system-side recipient mapping named explicitly (this atom does not provide a recipient registry; that would be a separate composing concern). -
Generation acceptance silent on what an auditor cannot clear from records alone. The six existing checks cover every invariant the atom enforces internally. But three audit questions — authority legitimacy at
disclosed_at, Invariant 5 conformance, and backdating detection — cannot be answered from the disclosure store alone and were nowhere named as audit boundaries. A SOX / GDPR / HIPAA auditor reading the Generation acceptance section and clearing all six checks would believe the atom’s audit surface is complete; in fact the atom’s positive-evidence checks are complete, but three negative-evidence questions live in composing patterns. Fixed: a new Audit gaps: what cannot be cleared from these records alone subsection added to Generation acceptance, naming the three unclearable questions and the composing patterns that surface each (Consent / Legal Hold / regulatory citation for authority legitimacy; Event Log / egress logs / complaint records / recipient intake records for Invariant 5; Event Log + Audit Trail for backdating detection). The Edge cases clock-semantics entry was correspondingly extended to name backdating detection as a composing-Event-Log concern.
Lineage correction (Round 3). Round 2 Pass 3 finding 2 as originally written described a fix to “Invariant 2” about disclosure_id uniqueness. The current Invariant 2 is about authority completeness; the uniqueness statement lives in the Identity model section. The original finding referred to an interim draft state in which the invariants were numbered differently. Round 3 verified what the fix should look like in the current numbering and rewrote the Lineage entry to accurately name the Identity model as the section that carries the two-scope (action-level assignment, store-level rejection of reuse) statement, and confirmed by edit that the Identity model section actually carries that statement.
Scheduled rescan: 2026-05-20 — clean.