Clinical Observation
Table of contents
- Clinical Observation
- Intent
- Summary
- Structure
- Examples
- Happy path — vital sign recorded and queried
- Amendment — correcting a transcription error
- Retraction — wrong patient
- Rejection path — invalid record
- Rejection path — amending a non-existent observation
- Rejection path — amending an already-amended observation
- Rejection path — amending a retracted observation
- Regulated adversarial scenarios
- Generation acceptance
- Edge cases and explicit non-goals
- Composition notes
- Standards references
- Status
- Lineage notes
A healthcare primitive: an immutable record of a single clinical measurement — vital sign, lab result, assessment score — attributed to a clinician and scoped to a patient. Corrections create successor records; the original is never edited.
Intent
A clinician records a measurement about a patient — blood pressure, temperature, blood glucose, pain score, oxygen saturation. The record must be trustworthy: what was recorded, who recorded it, and when must be permanently fixed. Errors are corrected by recording a successor observation that supersedes the original; the original does not disappear, it is marked as amended (a correction added to a record without replacing it — the original remains). Erroneous observations recorded for the wrong patient or under the wrong type are retracted (formally withdrawn, with reason documented, but not deleted), not edited.
The pattern addresses a clinical requirement that is universal and recurring: the medical record must show both what was originally recorded and what the correction was, so that the history of clinical reasoning is recoverable. A mutable record system fails this requirement by definition — once a nurse edits a blood pressure value, the original is gone and the reason for the edit is invisible. The append-and-supersede model (corrections are added as new records that supersede the original — neither the original nor the correction is destroyed) preserves both.
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 observation record set), its own actions (record, amend, retract, read), and its own invariants (immutability, amendment traceability, retraction finality). Composing patterns add retention policy, tamper-evidence, access control, and longitudinal analytics. The Clinical Observation atom imposes no semantics on what the value means clinically; it imposes only the structural guarantee that the record is faithful to what was recorded and by whom.
Summary
Clinical Observation is the atom that records a single measurement taken about a patient — a vital sign, a lab result, an assessment score, or any other clinical finding — in an immutable (unchangeable once written), permanently attributed form. It answers the question a clinician or regulator must be able to ask: what was recorded, who recorded it, and when, and if there were corrections, what were they, who made them, and why? The record is trustworthy because it cannot be silently edited. Errors are corrected by creating a successor observation that supersedes the original; the original is retained and marked as Amended, with the correcting clinician and reason permanently recorded on the successor. Observations recorded for the wrong patient or under the wrong observation type cannot be amended — they must be retracted, leaving the original in the store with a required explanation, and a fresh correct observation recorded separately.
This append-and-supersede model directly addresses a universal clinical records requirement: the history of clinical reasoning must be recoverable. A mutable records system destroys that history the moment a value is edited. The Clinical Observation atom preserves both the original measurement and any correction, so that any downstream clinical decision made on the basis of the original is visible in context, and any audit of the record can distinguish a transcription correction from a change in the patient’s actual condition.
The atom is freestanding (can be specified without naming any other pattern) in the EOS (Essence of Software — Daniel Jackson’s framework for specifying software concepts as freestanding, composable units) sense. It owns the observation record set, not the semantics of what any given value means clinically — blood pressure ranges, pain scale interpretations, and reference range assessments are deployment concerns. The atom requires that value constraints be declared per observation type and applied at record time, but does not define what those constraints are.
The three states are Recorded (current, stands as-is), Amended (has been superseded by a correction), and Retracted (withdrawn as erroneous). Retraction is terminal; amendment is linear (each observation has at most one successor). Queries can filter by state, allowing clinical systems to retrieve only current (Recorded) observations while auditors retrieve the full history including corrections.
The most common uses are: electronic health record systems recording vital signs and lab results, regulated clinical trial data capture (21 CFR Part 11), HIPAA (US Health Insurance Portability and Accountability Act) audit trail requirements for ePHI (electronic Protected Health Information — individually identifiable health data in digital form), and any system requiring an immutable record of who measured what and when. The atom is grounded (passed all required review passes and is stable enough to generate from).
Structure
Store instance model
The Clinical Observation atom operates against a named store instance. A store_name identifies the instance; multiple instances coexist in real systems — one per hospital, per department, or per care team, depending on deployment topology. The atom specifies what one instance is and how it behaves; composing patterns and deployment configuration determine how many instances to instantiate. observation_id values are unique within a store instance; uniqueness across instances is a composing concern. patient_ref is an opaque reference scoped globally — the same patient_ref may appear in multiple store instances for the same patient across care settings.
Identity model
Each observation has an opaque, immutable, system-generated observation_id — assigned on record, never reused, never reassigned within the store instance. The id is the observation’s identity; the clinical content is a property of the observation, not its identity.
patient_ref is an opaque reference to the patient. It is set on record and is immutable. It is not the observation’s identity — two observations for the same patient have different observation_ids. patient_ref is inherited unchanged by any successor observation created by amend.
recorded_by is an opaque reference to the clinician who performed the measurement. It is set on record and is immutable. Amendments carry their own amended_by; the original recorded_by is never changed.
Inputs
recordcalls from clinicians or clinical systems, each carrying a patient reference, clinician reference, observation type, value, unit, and an optional explicit timestamp.amendcalls that correct a prior observation, carrying the id being corrected, the correcting clinician, the corrected value and unit, and a required reason.retractcalls that withdraw an erroneous observation, carrying the id being retracted, the retracting clinician, and a required reason.readqueries from clinical systems, analytics pipelines, and audit processes.
Actions
record(patient_ref, recorded_by, observation_type, value, unit, recorded_at?) → observation_id | rejected(invalid-observation | storage-failure)— create a new Recorded observation.recorded_atdefaults to the receiving node’s wall clock if not supplied; when supplied, it must not be in the future (see the Clock semantics edge case).amend(observation_id, amended_by, value, unit, reason) → new_observation_id | rejected(not-known | already-amended | already-retracted | invalid-request | invalid-observation | storage-failure)— create a successor observation that corrects the named one. The original transitions to Amended; the successor is Recorded with apredecessor_idreferencing the original.observation_typeandpatient_refare inherited from the original by construction —amenddoes not accept either as a parameter, so a wrong observation type requires retraction and a freshrecord, not amendment.invalid-requestcovers emptyamended_byor emptyreason;invalid-observationcoversvalueorunitfailures against the per-type content constraints.retract(observation_id, retracted_by, reason) → retracted | rejected(not-known | already-retracted | invalid-request | storage-failure)— mark the observation as Retracted. The record remains; no observation data is destroyed. An Amended observation may be retracted; doing so retracts only that link in the chain — prior and successor records are not affected.read(query) → ordered_sequence_of_observations | rejected(invalid-query)— return observations matching the query, ordered byrecorded_atascending. A query may filter byobservation_id,patient_ref,observation_type, time range, state (Recorded / Amended / Retracted), or any combination. A query supplying only anobservation_idreturns at most one observation; all other filter dimensions are combinable and may return zero or more.
Outputs
- For
record: a freshobservation_id, or a rejection naming the failed precondition. - For
amend: a freshobservation_idfor the successor observation, or a rejection. - For
retract: the tokenretracted, or a rejection. - For
read: a (possibly empty) ordered sequence of observations. Each carries itsobservation_id,patient_ref,recorded_by,observation_type,value,unit,recorded_at, andstate. The transition-metadata fields are present when applicable, and multiple may co-occur on a single observation per the State transitions:predecessor_id,amended_by, andamendment_reasonare set on any successor observation (one that corrects an earlier record);successor_idis set on any Amended-state original (one that has been corrected);retracted_byandretraction_reasonare set on any Retracted-state observation. An observation that was first amended (originating a successor) and then retracted carries bothsuccessor_idand the retraction-metadata fields. A successor observation that was itself later amended carries bothpredecessor_id(from the prior amend) andsuccessor_id(from the later amend). The combinations follow mechanically from the State transitions; they are not special cases.
State
Each observation is in exactly one state:
- Recorded — the observation stands. It may be amended or retracted.
- Amended — the observation has been superseded by a correction. It is retained and visible but carries a
successor_idpointing to the correcting observation. An Amended observation may still be retracted. The successor observation that supersedes it carriespredecessor_id,amended_by(the clinician who made the correction), andamendment_reason(required, non-empty) — set atamendtime and immutable thereafter. - Retracted — the observation was withdrawn as erroneous. It is retained and visible but flagged as invalid. No further transitions from Retracted.
Valid transitions:
- Recorded → Amended (via
amend) - Recorded → Retracted (via
retract) - Amended → Retracted (via
retract)
Purged is not a state in this atom. Clinical records are not deleted; their retention and eventual destruction under legal hold or regulatory obligation belong to composing patterns (Retention Window, Legal Hold).
Flow
- Clinician takes a measurement. Calls
record(patient_ref, recorded_by, observation_type, value, unit). The atom assignsobservation_id, setsstate = Recorded, recordsrecorded_at. Returnsobservation_id. - Clinician discovers an error in the value. Calls
amend(observation_id, amended_by, corrected_value, corrected_unit, reason). The atom marks the original as Amended (setssuccessor_id), creates a new Recorded observation withpredecessor_idreferencing the original. Returns the newobservation_id. - Clinician discovers the observation was recorded for the wrong patient or wrong type. Calls
retract(observation_id, retracted_by, reason). The atom marks the observation as Retracted. The clinician then callsrecordto create the correct observation. - Clinical system queries a patient’s observations. Calls
read({patient_ref, observation_type, state: "Recorded"}). Receives the current (non-superseded, non-retracted) observations in chronological order.
Decision points
- At
record—patient_refandrecorded_bymust be non-empty opaque references;observation_typemust be non-empty AND must have a declared value constraint at the deployment (anobservation_typewith no declared constraint cannot be safely validated and is rejected asinvalid-observation, not silently accepted);valuemust satisfy the declared value constraint for the observation type (the atom does not define what a valid blood pressure value is — that is deployment policy; it requires only that the constraint be declared and applied);unitmust be non-empty;recorded_at, if supplied, must not be in the future (checked against the receiving node’s wall clock). Any violation rejects asinvalid-observation. If the store write fails after all preconditions are satisfied, the atom returnsrejected(storage-failure); theobservation_idis not returned. - At
amend— the namedobservation_idmust exist (not-knownif absent); must be in Recorded state — an observation already in Amended state has a successor and cannot be amended again without creating a branch, which Invariant 3 prohibits (already-amended); must not be Retracted (already-retracted); correctedvalueandunitmust satisfy the same per-observation_typeconstraints asrecord(invalid-observation);amended_bymust be non-empty andreasonmust be non-empty — a blank reason defeats the audit trail (invalid-requestfor either being empty).observation_typeandpatient_refare inherited from the original by construction — the action does not admit either as a parameter. If both writes (successor creation and original state update) cannot be made durable, the atom returnsrejected(storage-failure)and no observable state change occurs: the successor is not created and the original remains in Recorded state. See theamendtwo-write atomicity edge case for the implementation obligation. - At
retract— the namedobservation_idmust exist (not-known); must not already be Retracted (already-retracted);retracted_bymust be non-empty;reasonmust be non-empty — both are required for the audit trail (invalid-requestfor either being empty). Recorded and Amended observations may both be retracted. If the state transition cannot be made durable, the atom returnsrejected(storage-failure); the observation’s state is unchanged and noretracted_byorretraction_reasonis attached. - At
read— query parameters must be well-formed: any suppliedobservation_idis a syntactically valid id (non-null, non-empty); any supplied time range has start ≤ end; any supplied state filter names one ofRecorded,Amended,Retracted. A query with no filters is well-formed and returns every observation in the store. A well-formed query matching no observations returns an empty sequence, not a rejection. Only malformed parameters (e.g., end before start, unrecognized state value) surface asinvalid-query.
Behavior
- Records are durable on success. Once
recordreturns anobservation_id, the observation is in the store and will appear in subsequent reads. - Amendment is additive, not destructive.
amendcreates a new record; the original remains. Both are visible toread; queries filtering forstate: "Recorded"return only the current end of the chain. - Retraction is permanent. A retracted observation cannot be un-retracted. It remains in the store, visible to queries that include
state: "Retracted", but excluded from queries for current (Recorded) observations. - Reads are repeatable; the underlying store is monotonic. The observation store only grows — every
observation_idever issued remains addressable indefinitely (Invariant 7). An unfiltered read at timet2 > t1therefore returns every observation visible att1plus any added in between. State-filtered reads are not monotonic in their result set: an observation visible att1understate: "Recorded"is excluded att2if it transitioned to Amended or Retracted in between. Filtered queries reflect the current state of each observation, not the state at the time of a previous read. observation_typeis stable across the amendment chain. All observations in an amendment chain share the sameobservation_type. A chain models the history of one measurement type for one patient; a different type is a different chain.
Feedback
- After
record— a new Recorded observation exists.observation_id,patient_ref,recorded_by,observation_type,value,unit,recorded_at,state: Recordedare set and immutable. - After
amend— the original observation is now Amended (acquiressuccessor_id); a new Recorded observation exists withpredecessor_idreferencing the original,amended_byset to the correcting clinician, andamendment_reasonset to the supplied reason. All three fields on the successor are immutable. The original’s fields are unchanged. - After
retract— the named observation is now Retracted (acquiresretraction_reason,retracted_by). Its other fields are unchanged. - After
read— a sequence of matching observations. The store is unchanged.
Each rejected action produces an observable refusal naming the failed precondition.
Invariants
- Invariant 1 — Observation immutability. After a successful
record, an observation’sobservation_id,patient_ref,recorded_by,observation_type,value,unit, andrecorded_atnever change, regardless of subsequentamendorretractactions against it. - Invariant 2 — Amendment produces a successor. Every
amendcreates a new observation; it does not modify the original. Afteramend, the original is in Amended state with asuccessor_id; the successor is in Recorded state with apredecessor_id. - Invariant 3 — Amendment chains are linear. Each observation has at most one
successor_idand at most onepredecessor_id. Amendment chains are singly-linked; branching is not permitted. - Invariant 4 — Patient ref is inherited across amendment chains. All observations in an amendment chain share the same
patient_ref. The successor inheritspatient_reffrom the original by construction:amenddoes not acceptpatient_refas a parameter, so divergence is structurally impossible — not enforced by a runtime check on inputs that cannot be supplied. - Invariant 5 — Observation type is inherited across amendment chains. All observations in an amendment chain share the same
observation_type. The successor inheritsobservation_typefrom the original by construction:amenddoes not acceptobservation_typeas a parameter. A clinician who recorded the wrong observation type must retract and re-record; the amendment chain cannot model a type change. - Invariant 6 — Retraction is terminal. A Retracted observation accepts no further state transitions.
amendandretractagainst a Retracted observation are rejected asalready-retracted. - Invariant 7 — Observation store durability. No
observation_idis removed from the store.amendandretracttransition state; they do not destroy records. The observation count is monotonically non-decreasing for the lifetime of the store instance, and the store admits no deletion surface by spec. Astorage-failureresponse fromrecord,amend, orretractguarantees that no partial record is observable: the action either makes all its required writes durable or has no observable effect on the store. This guarantee is jointly enforced — the spec mandates the atomicity (notably foramend’s two-write transition, see theamendtwo-write atomicity edge case); the implementation provides it, through transactional store semantics or a crash-recovery scan that detects and repairs dangling transitions on restart. An implementation that returnsstorage-failurewhile leaving a partial record visible is non-conforming. - Invariant 8 — Recorded_at is set once.
recorded_atis set at the moment ofrecord(from the supplied value or, if not supplied, the receiving node’s wall clock — see the Clock semantics edge case) and never changes, even after amendment. The successor observation carries its ownrecorded_at, reflecting when the correction was recorded, not when the original measurement was taken. - Invariant 9 — Transition metadata is write-once. Every field written by a state-transition action is immutable after the transition completes. When
amendwritessuccessor_idto the original observation, that value never changes thereafter — Invariant 3 (linear chains) and thealready-amendedrejection together prevent any secondamendagainst the same observation from overwriting it. Whenretractwritesretracted_byandretraction_reason, those values never change — Invariant 6 (retraction is terminal) prevents any further state transition that could overwrite them. The successor observation’spredecessor_id,amended_by, andamendment_reasonare immutable from the momentamendcompletes, inheriting the same protection as any other observation’s fields under Invariant 1. Taken together with Invariants 1 and 8, no field of any observation — original, successor, or retracted — ever changes after it is first written.
Examples
Happy path — vital sign recorded and queried
A nurse records a patient’s blood pressure: record(patient_ref: "p42", recorded_by: "nurse_chen", observation_type: "blood_pressure_systolic", value: 128, unit: "mmHg") → observation_id: "obs-001". The charge nurse later queries current observations: read({patient_ref: "p42", observation_type: "blood_pressure_systolic", state: "Recorded"}) → [{observation_id: "obs-001", value: 128, unit: "mmHg", state: "Recorded", recorded_at: "..."}].
Amendment — correcting a transcription error
The nurse realizes she recorded 128 instead of 138. Calls amend("obs-001", amended_by: "nurse_chen", value: 138, unit: "mmHg", reason: "transcription error — entered 128, correct value is 138") → observation_id: "obs-002". The store now contains obs-001 (Amended, successor_id: "obs-002") and obs-002 (Recorded, predecessor_id: "obs-001", value 138). A query for state: "Recorded" returns obs-002 only. A query for all states returns both, preserving the full correction history.
Retraction — wrong patient
An observation is recorded for the wrong patient. Calls retract("obs-003", retracted_by: "dr_patel", reason: "recorded against wrong patient — intended patient_ref p17, not p12") → retracted. A correct observation is then recorded against p17. obs-003 remains in the store, visible to audit queries, flagged as Retracted.
Rejection path — invalid record
A system submits a record call with an empty recorded_by field. record(patient_ref: "p42", recorded_by: "", observation_type: "heart_rate", value: 72, unit: "bpm") → rejected(invalid-observation). No observation_id is issued; no record enters the store. The system must supply a non-empty clinician reference before the observation can be accepted.
Rejection path — amending a non-existent observation
A clinical system submits an amend call against an observation_id that was never issued in this store instance. amend("obs-999", amended_by: "nurse_chen", value: 138, unit: "mmHg", reason: "correcting a prior entry") → rejected(not-known). No state transitions and no record is created; the caller must verify the observation_id before retrying. A common cause is cross-instance referencing — obs-999 may exist in a sibling store instance but is not visible here.
Rejection path — amending an already-amended observation
obs-001 has already been corrected once; obs-002 is its successor (Recorded). A caller attempts another correction against obs-001 rather than against the current end of the chain. amend("obs-001", amended_by: "nurse_chen", value: 140, unit: "mmHg", reason: "further correction") → rejected(already-amended). To record a further correction, the caller must amend obs-002 — the current Recorded end of the chain. Invariant 3 (linear chains) is what makes this a rejection rather than a branch creation.
Rejection path — amending a retracted observation
A caller attempts to amend an observation that was retracted. amend("obs-003", ...) → rejected(already-retracted). The caller must record a fresh observation instead.
Regulated adversarial scenarios
Regulator audit — verify amendment trail integrity
A HIPAA (US Health Insurance Portability and Accountability Act) auditor queries all observations for patient p42 across all states: read({patient_ref: "p42"}). The result must include every observation ever recorded for this patient — Recorded, Amended, and Retracted — in chronological order. For every Amended observation, the auditor verifies that a successor_id is present and that the successor is in the store. For every Retracted observation, the auditor verifies that a retraction_reason and retracted_by are present. No observation is missing; no amendment is unattributed; no retraction is unexplained. The audit passes by Invariants 2, 3, 7, and 9 — completeness (7), correct amendment-chain structure (2, 3), and the write-once guarantee that prevents retroactive rewiring of successor_id, retracted_by, or retraction_reason (9).
Disputed observation — patient challenges a recorded value
A patient disputes a recorded blood glucose value, claiming the measurement was taken incorrectly. The clinical record must show: the original observation (by Invariant 1, its value and recorded_by are immutable); whether it was amended and why (by the State definition for Amended observations and Invariant 9, the successor record names the correcting clinician via amended_by and the reason via amendment_reason, both write-once); or whether it was retracted and why (by the same Invariant 9, retracted_by and retraction_reason are write-once on the original). The patient’s dispute is answered from the records alone — the clinician’s identity, the timestamp, and the reason for any correction are all present and unalterable.
Breach investigation — unauthorized observations
A security investigation suspects that observations were recorded for a patient by an unauthorized actor. The investigator queries read({patient_ref: "p99"}) and cross-references each observation’s recorded_by against the authorized clinical staff list at recorded_at time. Invariant 1 guarantees recorded_by is immutable — it cannot have been edited to cover tracks after the fact. Every observation’s author is permanently attributed.
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:
- Immutability check. For a known
observation_id, retrieve the observation at two different points in time and compare all fields.observation_id,patient_ref,recorded_by,observation_type,value,unit, andrecorded_atmust be identical in both reads.statemay differ if anamendorretractoccurred between the reads. Additionally, any transition-metadata field that is set in either read —successor_id,predecessor_id,amended_by,amendment_reason,retracted_by,retraction_reason— must hold the same value in any later read where it is set (Invariant 9, write-once). A transition-metadata field that changes between two reads is a conformance failure. - Amendment chain check. For a known Amended observation, retrieve its
successor_idand confirm the successor exists, is in Recorded or Retracted state, and carries apredecessor_idequal to the original’sobservation_id. Confirm the successor shares the samepatient_refandobservation_typeas the original. - Retraction finality check. Attempt
amendagainst a known Retracted observation. The call must returnrejected(already-retracted). Confirm the observation’s fields are unchanged. - No-destruction check. For a set of
observation_ids known to have been issued — including Amended and Retracted ones — confirm thatreadreturns each of them when queried by id across all states. No issued id may be absent from the store. - Attribution check. For every observation in the store, confirm that
recorded_byis non-empty and that every Retracted observation has a non-emptyretracted_byandretraction_reason. An observation with an emptyrecorded_byis a conformance failure.
Edge cases and explicit non-goals
- Amending an intermediate node in a chain. The atom permits amending any Recorded or non-Retracted node, including intermediate nodes in an amendment chain. Callers should amend the current end of the chain (the most recent Recorded observation) to keep the chain semantically clean; amending an intermediate node creates a branch point, which Invariant 3 prohibits. Implementations must enforce that an already-Amended observation cannot be amended again (
already-amended) — the chain is linear. - Amending to change
observation_type. Structurally impossible —amenddoes not accept anobservation_typeparameter; the successor inherits the original’s type by construction (Invariant 5). A clinician who recorded “temperature” when they meant “oxygen_saturation” must retract and re-record. The amendment chain models value corrections within a type, not type changes. - Amending to change
patient_ref. Structurally impossible —amenddoes not accept apatient_refparameter; the successor inherits the original’s patient by construction (Invariant 4). A wrong-patient entry must be retracted and re-recorded against the correct patient. The amendment chain is patient-scoped. - Future-dated
recorded_at. Rejected asinvalid-observation. Clinical observations are records of what was measured; a future timestamp is a logical impossibility. - Back-dated
recorded_at. Permitted, with deployment policy governing the allowable look-back window. A nurse recording a bedside observation taken thirty minutes ago is a normal workflow. An observation recorded_at two years prior is unusual and may warrant additional scrutiny — but the atom does not enforce a look-back limit; that is deployment policy. - Value constraint definition. The atom requires that a value constraint for each
observation_typebe declared and applied; it does not define what the constraints are. Blood pressure ranges, glucose units, pain scale bounds — these are deployment-specific. Implementations must declare the constraint; the atom enforces that it is checked. Arecordcall carrying anobservation_typefor which no constraint has been declared is rejected asinvalid-observation— accepting unknown types without validation would defeat the per-type integrity guarantee and is therefore not permitted. Deployments add new observation types by first declaring their value constraints; the atom never silently accepts a type it has no validation for. - Access control. Who may record, amend, or retract an observation is not defined by this atom. That is the obligation of a composing Permissions pattern. The atom records
recorded_byandretracted_byfor attribution; it does not enforce that those actors have the right to perform the action. - Retention and destruction. The atom retains all observations indefinitely. Time-bounded retention under HIPAA minimum necessary standards and eventual destruction under defensible deletion belong to Retention Window and Legal Hold as composing patterns.
- Tamper-evidence. The atom guarantees immutability by spec; it does not cryptographically prevent a store administrator from rewriting records. Compose with Tamper Evidence for cryptographic guarantees.
- Observation aggregation and trending. Longitudinal analytics — trend lines, delta from prior, reference range comparison — are composing concerns. This atom provides the substrate; the analytics layer reads it.
- Units and terminology standardization. LOINC codes, SNOMED CT, UCUM units — the atom treats
observation_typeandunitas opaque strings. Standardization to controlled vocabularies is a deployment concern, not an atom-level concern. - Concurrency. Two clinicians recording observations for the same patient simultaneously is permitted — each receives a distinct
observation_id. The atom does not detect or prevent concurrent amendments to the same observation; implementations must serializeamendandretractagainst a givenobservation_id. - Store instance selection. The atom specifies what one store instance is and how it behaves; it does not specify how a caller selects which instance to call against. No action accepts
store_nameas a parameter — calls implicitly target a single routed instance. Selection is a deployment-routing concern: typically a service binding, URL endpoint, namespace prefix, or similar configuration supplied by the deployment. Composing patterns that need to operate across multiple instances (a multi-hospital audit query, a network-wide patient history) must compose at a layer above this atom, providing their own cross-instance routing or aggregation.patient_refis the only field designed to be portable across instances (global scope by spec);observation_ids are scoped to one instance and must not be assumed unique elsewhere. recordidempotency.recordis not idempotent at this layer. A clinical system that retriesrecordafter a network timeout — uncertain whether the previous call reached the store — creates a duplicate observation if the previous call did succeed; both calls return distinctobservation_ids. The atom takes no position on whether duplicate observations are clinically meaningful; that depends on the observation type and care setting. For systems requiring at-most-once semantics on record submission, compose with Duplicate Prevention, which provides idempotency keys above this atom.amendandretractare naturally semi-idempotent: a retry against an already-amended observation returnsalready-amended, and a retry against an already-retracted observation returnsalready-retracted. The caller can recover from a timeout by reading the affected observation to discover whether the prior call succeeded — thesuccessor_idorretraction_reasonreveals the outcome. Neither action creates duplicate state transitions on retry.amendtwo-write atomicity. Theamendoperation requires two durable writes: creating the successor observation and updating the original to Amended state with asuccessor_id. A crash between writes leaves the store in an inconsistent state — either the successor exists without the original pointing at it (violates Invariant 2) or the original is marked Amended with asuccessor_idthat does not exist in the store (violates Invariant 3). Resolving mid-transition crashes is out of scope for this atom; implementations must provide atomic transaction support across both writes, or a crash-recovery scan that detects and repairs dangling amendment links on restart. Per the Decision point foramend, astorage-failureresponse is the observable signal of an aborted two-write attempt; per Invariant 7 (Observation store durability), no partial record is visible after such a response.amenddoes not acceptrecorded_at. Whilerecordaccepts an optionalrecorded_at,amenddoes not. The successor observation’srecorded_atis always set to the receiving node’s wall clock at amendment time. This is by design: an amendment’s timestamp is its own audit provenance — when the correction was identified and entered, not when the original measurement was taken. Allowing a caller-suppliedrecorded_atonamendwould let a back-dated amendment masquerade as a contemporaneous correction, weakening the audit trail and the regulator-audit scenario below. The original observation’srecorded_at(set onrecord) remains the canonical measurement time and is unchanged by amendment, per Invariant 8.- Whitespace-only required strings. All required string fields —
patient_ref,recorded_by,observation_type,unit,amended_by,retracted_by, and thereasononamendandretract— must contain at least one non-whitespace character. A field consisting solely of whitespace characters (spaces, tabs, newlines, Unicode whitespace) is treated as empty and surfaces the same rejection as a literally empty string (invalid-observationforrecord’s content fields;invalid-requestforamend’samended_by/reasonandretract’sretracted_by/reason). Implementations must either trim or check for visible content before recording; they must not accept whitespace-only as a meaningful clinician identity, reason, or content value. - Clock semantics.
recorded_atdefaults to the receiving node’s wall clock when not supplied by the caller. “Must not be in the future” is checked against the receiving node’s clock at the moment of therecordcall. Clock skew between the caller and the receiving node is a deployment concern — an observation submitted from a client with a slightly fast clock may be rejected as future-dated even if the measurement occurred in the past. Timezone normalization (storage in UTC) is a deployment convention; the atom does not enforce a timezone. Under an unreliable or skewed clock,recorded_atmay not be monotonically increasing across observations; there is no sequence-number equivalent here. Ordering within a patient’s observation history should be treated as best-effort wall time, not authoritative causal order. - Rejection priority. When multiple precondition violations exist on the same call, the rejection returned follows a defined priority — cheapest and most-structural checks first, persistence last. For
amend:not-known(id existence) →already-amended/already-retracted(id state) →invalid-request(request metadata, emptyamended_by/reason) →invalid-observation(content,value/unitconstraint) →storage-failure(persistence). Forretract:not-known→already-retracted→invalid-request→storage-failure. Forrecord:invalid-observation(any content/metadata violation including unknownobservation_type) →storage-failure. Forread:invalid-queryis the only rejection. A caller that fixes one rejection class may receive a different rejection on retry as the next-priority check fires; this is expected and not a regression. The priority order is the same across conforming implementations so callers can write deterministic retry logic. - Tie-breaking for identical
recorded_at. When two or more observations carry the samerecorded_at— concurrent records from two clinicians, a back-dated record colliding with a current entry, or coarse-grained clock resolution — the relative order in areadresult sequence is implementation-defined but must be stable across consecutive reads of the same store state. The atom does not prescribe a tie-breaker; common choices areobservation_idlexical order (deterministic but arbitrary across implementations) or insertion order (deterministic within an implementation). Callers that depend on a specific tie-breaking rule must establish it as a deployment convention rather than relying on cross-implementation portability.
Composition notes
Clinical Observation composes naturally with the existing library:
- Event Log — the observation record set is structurally a specialized Event Log (append-only, immutable entries, ordered by
recorded_at). The two are not identical — Clinical Observation has amendment and retraction semantics that Event Log does not — but they share the same architectural instinct. A composing implementation may layer Event Log as the persistence substrate. - Actor Identity —
recorded_by,amended_by, andretracted_byare opaque references; Actor Identity provides the attestation store that verifies those references are real, credentialed actors at the time of recording. - Tamper Evidence — seals the observation store against post-hoc modification, complementing the spec-level immutability guarantee with a cryptographic one.
- Retention Window — governs the minimum and maximum retention period for observation records under HIPAA and applicable state law.
- Audit Trail — the canonical composition for regulated record-keeping; Clinical Observation feeds it.
- Medication Order — carries an optional
clinical_evidence_reffield that holds an opaque reference to the Clinical Observation(s) that informed the prescribing decision. The relationship is advisory and unidirectional: Clinical Observation provides the upstream evidence substrate; Medication Order records the clinical response. Clinical Observation does not depend on Medication Order to be specified. - Forthcoming: Care Plan — a composition modeling a structured set of medication orders, clinical observations, and clinical goals; Clinical Observation is a constituent.
Standards references
- HIPAA §164.312(b) — audit controls: covered entities must implement hardware, software, and procedural mechanisms to record and examine activity in information systems that contain ePHI. The observation record, with its immutable
recorded_byandrecorded_at, is the primary audit surface. - HL7 FHIR (Health Level 7 Fast Healthcare Interoperability Resources — a standard for exchanging healthcare information) Observation resource — the canonical interoperability representation of a clinical observation; this atom’s core fields map to FHIR Observation’s
subject(patient_ref),performer(recorded_by),value[x](value + unit),issued(recorded_at), andstatus(final → Recorded, amended → Amended, cancelled → Retracted). FHIR’scodefield is a CodeableConcept (LOINC or SNOMED CT), not an opaque string — this atom deliberately defers terminology binding to deployment convention. FHIR carries many additional fields (category, encounter, bodySite, interpretation, referenceRange) not present here; those are composing-layer concerns. - 21 CFR Part 11 — electronic records in FDA-regulated clinical trials; each observation is a regulated electronic record requiring attribution, timestamp, and amendment trail.
- Joint Commission Record of Care standards — require that corrections to medical records be dated, timed, and attributed; the amendment model satisfies this directly.
- IHE PCC (Patient Care Coordination) — the Clinical Document Architecture (CDA) and FHIR-based profiles that govern how observations are exchanged across care settings.
- SNOMED CT / LOINC / UCUM — controlled vocabularies for
observation_typeandunit; recommended deployment conventions, not atom-level obligations.
Status
grounded (passed all required review passes and is stable enough to generate from) — 2026-05-20 — foundation passes complete (Pass 1, Pass 2, Pass 3), two human refinement rounds complete (Refinement rounds 1 and 2), and one AI-conducted adversarial round complete (Refinement round 3, Torvalds X2 posture, Claude Opus 4.7). All nine GRID nodes resolved, all concerns conceptually independent, all known adversarial gaps closed or named as explicit out-of-scope.
Lineage notes
Pass 1 — Structural completeness (GRID). Two findings, both closed in-pattern.
- Store instance model absent. The atom referenced “the store” throughout without defining whether one global store or multiple named instances are valid. Fixed: added a Store instance model subsection to Structure, mirroring Event Log’s named-instance model.
observation_iduniqueness is now explicitly scoped to a store instance;patient_refis noted as globally scoped across instances. amended_byandamendment_reasonnot persisted. Theamendaction accepted both as inputs but neither appeared in the State field listing, Outputs, or Feedback — making them unrecoverable from the records. The regulated adversarial scenarios and Generation acceptance check 2 both depend on amendment attribution. Fixed: both fields added to the Amended state description in State, to Outputs (per-record field list for successor observations), and to Feedback afteramend. Both are set atamendtime and immutable thereafter.
All nine GRID nodes resolved. No extractions.
Pass 2 — Conceptual independence (EOS). Clean. No over-absorptions found. One judgment call recorded: amendment chain semantics (predecessor_id, successor_id, amended_by, amendment_reason, Recorded → Amended transition) were evaluated as an extraction candidate. Kept in-pattern because the mechanic is definitional to the atom — it cannot be specified without knowing which fields can and cannot change across an amendment, making a generic “Amendment Trail” atom dependent on the host for its constraints, which inverts the composition direction. All cross-cutting concerns (actor verification, tamper-evidence, retention, access control, terminology) correctly deferred to named composing patterns. One flag forwarded to Pass 3: concurrent amendment serialization obligation unstated.
Pass 3 — Adversarial scrutiny (Linus mode). Six findings: four real, two minor. All closed in-pattern.
- Contradictory
amendprecondition. Decision points said “Recorded or Amended state” — contradicting Invariant 3 (linear chains) and the Edge case requiring implementations to reject amending an already-Amended observation. Fixed: Decision point now states “Recorded state only”;already-amendedfires for any observation in Amended state; the rationale (amending an Amended observation would create a branch, prohibited by Invariant 3) is stated inline. retractmissing input validation. Decision points had no validation forretracted_byorreason; both could be empty; the signature lacked a rejection reason for invalid inputs. Fixed:invalid-requestadded toretractsignature; Decision point now explicitly requiresretracted_bynon-empty andreasonnon-empty, withinvalid-requestas the rejection.recordrejection example absent. All examples showed successfulrecordcalls. Fixed: added Rejection path — invalid record example showingrejected(invalid-observation)for an emptyrecorded_by.amendtwo-write atomicity gap. Theamendoperation requires two durable writes; a crash between them violates Invariants 2 or 3. Fixed: new edge case added naming this as out-of-scope and requiring atomic transaction support or crash-recovery logic from implementations.- Clock semantics unstated (minor).
recorded_atdefaults to “the system clock” without specifying whose clock, monotonicity, timezone, or skew behavior. Fixed: new edge case added statingrecorded_atis best-effort wall time from the receiving node’s clock; skew, timezone normalization, and monotonicity are deployment concerns. - “Maps directly” to FHIR overclaims (minor). FHIR
codeis a CodeableConcept, not an opaque string; FHIR carries many additional fields not present in this atom. Fixed: Standards reference updated to “core fields map to” with explicit field-by-field correspondence and a note on what FHIR carries that this atom defers to composing layers.
Refinement round 1 — re-run of all three passes. Eight findings, all closed in-pattern. Conventions inherited from prior worked examples (Actor Identity’s Invariant 9 durability framing, the per-action rejection-vocabulary split from Permissions and Retention Window) rather than re-derived.
- Rejection-reason naming inconsistency between
amendandretract(Pass 3). The two actions validate analogous request-metadata fields (amended_by/retracted_bynon-empty,reasonnon-empty), butamendsurfaced those violations asinvalid-observationwhileretractsurfaced them asinvalid-request. A reader of the signatures alone could not predict the naming split. Resolved:amend’s rejection vocabulary updated to useinvalid-requestfor emptyamended_byorreasonandinvalid-observationforvalue/unitcontent failures. The signature and Decision points are split accordingly. The split now follows a principled rule —invalid-observationis reserved for failures of observation content;invalid-requestfor failures of request metadata. amendandretractstorage-failure behavior unstated in Decision points (Pass 1 / Pass 3). The signatures namedstorage-failurebut the Decision points did not describe its effect on observed state. A reader of those sections alone could not predict whether astorage-failureleft the original in Amended state, a successor partially written, or no state change at all. Resolved: Decision points for both actions now state thatstorage-failureleaves no observable state change — foramend, the successor is not created and the original remains Recorded; forretract, the observation’s state is unchanged and noretracted_byorretraction_reasonis attached. The two-write atomicity edge case is cross-referenced.- Invariants 4 and 5 described unreachable rejections (Pass 3). Both invariants ended with “An
amendcall that would changepatient_ref(orobservation_type) is rejected asinvalid-observation.” Butamend’s signature does not acceptpatient_reforobservation_typeas parameters, so such a call is structurally impossible — the rejection clauses were dead code dressed as enforcement. The same misalignment had propagated into the Amending to changeobservation_typeand Amending to changepatient_refedge cases, both of which also assertedinvalid-observationrejection. Resolved: both invariants reframed as inheritance guarantees — the successor inherits the original’spatient_refandobservation_typeby construction, because the action signature does not admit either field as input — and both edge cases updated to describe the change as structurally impossible rather than runtime-rejected. The mechanism is structural, not predicate-checked. readfilter list omittedobservation_id(Pass 1 / Pass 3). The Actions description and Decision points enumeratedreadfilters aspatient_ref,observation_type, time range, and state — but notobservation_id. Generation acceptance check 4 (“retrieve each of them when queried by id”) requires id-based lookup, leaving a gap between the conformance bar and the documented action surface. Resolved:observation_idadded to the filter list in Actions; thereadDecision point now defines well-formedness across all filter dimensions and reservesinvalid-queryfor malformed parameters (end-before-start time ranges, unrecognized state values, syntactically invalid ids).- Observation store durability not formally invariant (Pass 3). Invariant 7 stated no observation is destroyed but did not state the consistency guarantee between
storage-failureresponses and the absence of partial records — the convention used by Actor Identity’s Invariant 9 and Retention Window’s Invariant 10. Resolved: Invariant 7 strengthened (and renamed to Observation store durability) to name the monotonically non-decreasing observation count, the absence of a deletion surface, and the explicit guarantee thatstorage-failurefrom any action leaves no partial record observable. - Rejection-path examples covered only one rejection class (Pass 3). Round 1 added a
recordrejection example but did not extend coverage;not-knownandalready-amendedhad no worked examples despite being the most likely failure modes foramendcallers. Resolved: two rejection-path examples added — amending a non-existent observation (returnsnot-known, with a note on cross-instance referencing as a common cause) and amending an already-amended observation (returnsalready-amended, tied to Invariant 3’s linear-chain rule). Together with the existing amending a retracted observation example, all three precondition-class rejections foramendare now exemplified. amendlackedrecorded_atrationale (Pass 3, minor).recordaccepts optionalrecorded_at;amenddoes not. The design intent is that an amendment’s timestamp is unambiguously “when the correction was identified and entered,” but the rationale was implicit. A reader could plausibly assume the omission was incidental and consider addingrecorded_attoamendin an implementation, which would let a back-dated amendment masquerade as a contemporaneous correction and weaken the audit trail. Resolved: edge case added explicitly stating the omission is intentional, naming the audit-trail rationale, and reaffirming that the original’srecorded_atremains the canonical measurement time.- Whitespace-only string handling unstated (Pass 3, minor). Decision points required fields to be “non-empty” without specifying whether whitespace-only strings counted. An implementation taking “non-empty” literally would accept
recorded_by: " "as a valid clinician reference, defeating the attribution guarantee underwriting the regulator-audit and breach scenarios. Resolved: edge case added clarifying that all required string fields are treated as empty if they contain only whitespace; implementations must either trim or check for visible content before recording.
Pass 2 was clean. The amendment-chain mechanic was re-examined as an extraction candidate (as in Round 1) and again kept in-pattern: the Round 1 rationale — that a generic Amendment Trail atom would depend on the host for its constraints, inverting the composition direction — still holds, and no new over-absorption candidates surfaced. All eight fixes are in-pattern; none required extraction or new composing patterns.
Refinement round 2 — re-run of all three passes. Four findings, all closed in-pattern. The findings cluster around surface area that Round 2’s fixes touched (the transition-metadata vocabulary made richer by the rejection-vocab split and the strengthened Invariant 7) plus two operational gaps that survived the first refinement.
- Monotonic-reads claim overclaimed for filtered queries (Pass 1). The Behavior bullet read “Reads are repeatable and monotonic. The observation store only grows; a read at time
t2 > t1returns at least the observations visible att1, plus any added or transitioned in between.” This is true for unfiltered reads but false for state-filtered reads — an observation visible att1understate: "Recorded"is excluded att2if it transitioned to Amended or Retracted in between, so the filtered result set is not monotonic. The earlier wording conflated store monotonicity (real, per Invariant 7) with result-set monotonicity (only real for unfiltered reads). Resolved: bullet rewritten to distinguish the two — the underlying store is monotonic; filtered queries reflect current state and may shrink as observations transition. - Transition metadata not invariant-grade immutable (Pass 3). Invariant 1 enumerated immutable fields as
observation_id,patient_ref,recorded_by,observation_type,value,unit, andrecorded_at— explicitly omittingsuccessor_id,predecessor_id,amended_by,amendment_reason,retracted_by, andretraction_reason. The State section called these fields “immutable thereafter” in prose, but no Invariant formally protected them. A composing implementation reading the Invariants alone could rationalize rewritingsuccessor_idretroactively — for instance, “stitching” a new successor in after the fact — without violating any explicit invariant. The Round 2 strengthening of Invariant 7 (durability and partial-record absence) did not close this gap; it addressed write atomicity, not write-once semantics on transition metadata. Resolved: Invariant 9 added (Transition metadata is write-once), spelling out that every transition-written field is immutable after the transition completes, with the mechanism (Invariants 3 and 6 plus thealready-amended/already-retractedrejections) cited inline. Generation acceptance check 1 extended to cover the new invariant — transition-metadata fields must hold the same value across reads where they are set. recordidempotency policy unstated (Pass 3). A clinical system retryingrecordafter a network timeout — uncertain whether the previous call reached the store — creates a duplicate observation if the previous call did succeed; both calls return distinctobservation_ids with no deduplication. The atom never named this gap, despite the library having Duplicate Prevention available and Idempotent Reservation already worked as a composition pattern. A reader could plausibly assumerecordprovides at-most-once semantics under retry; it does not. Resolved: new edge caserecordidempotency names the gap, defers the at-most-once requirement to a composing Duplicate Prevention, and notes thatamendandretractare naturally semi-idempotent — a retry returns the appropriatealready-amendedoralready-retractedrejection, and the caller can recover by reading the observation to discover whether the prior call succeeded.- Tie-breaking for identical
recorded_atunspecified (Pass 3).readreturns observations ordered byrecorded_atascending, but the ordering when two or more observations share the samerecorded_atwas undefined. Concurrent records from two clinicians, back-dated entries colliding with current ones, or coarse-grained clock resolution can all produce ties. A caller comparing two read results across implementations (or across query times in some implementations) could observe inconsistent orderings. Resolved: new edge case Tie-breaking for identicalrecorded_atrequires stable ordering across consecutive reads of the same store state, leaves the specific tie-breaker as implementation-defined (withobservation_idlexical order or insertion order named as common choices), and warns callers that cross-implementation portability requires a deployment convention.
Pass 2 was clean. The amendment-chain extraction was re-examined a third time and still belongs in-pattern; value-constraint declaration and observation-type classification were checked as new extraction candidates and both correctly remain deployment concerns (the atom requires they exist and be applied, but does not absorb their declaration). All four fixes are in-pattern; none required extraction or new composing patterns.
One regulator-audit-scenario wording candidate was considered and dropped — the scenario’s “chronological order” expectation reads cleanly under the Clock semantics edge case’s wall-time-best-effort caveat, and revising it would be polish without substance.
Refinement round 3 — AI-conducted adversarial round. Reviewer: Claude Opus 4.7, Torvalds X2 posture (low-patience, allergic to abstraction-as-evasion, every claim and citation contested, no sympathy for prior decisions). Full pass-question set from PRESSURE_TESTING.md applied. Seven findings surfaced, all closed in-pattern; Pass 2 clean with a documented settled-judgment note.
- Value-constraint behavior for unknown
observation_typeunstated (Pass 1 / Pass 3). TherecordDecision point requiredvalueto satisfy “the configured value constraint for the observation type” and the Value-constraint-definition edge case required implementations to declare constraints — but neither said what happens when arecordarrives carrying anobservation_typethat has no declared constraint. Reject? Accept without validation? Auto-register a default? A hidden decision dressed as a deployment-policy reference; two conforming implementations could differ. Resolved: therecordDecision point and the Value-constraint-definition edge case both updated to require rejection asinvalid-observationwhen no constraint is declared for the supplied type. Accepting unknown types without validation would defeat the per-type integrity guarantee underwriting the regulator-audit and dispute scenarios; the spec now closes that door explicitly. Deployments add new types by first declaring constraints. - Store-instance selection mechanism unstated (Pass 1). The Store-instance model defines
store_nameas identifier and notes that multiple instances coexist, but no action acceptsstore_nameas a parameter and no Decision point describes how a caller’s call lands on a specific instance. The cross-reference graph in GRID failed: System named the instances; no Decision or Behavior linked them to call routing. Resolved: new edge case Store instance selection names this as a deployment-routing concern (service binding, URL endpoint, namespace prefix) and clarifies that calls implicitly target a routed instance, thatpatient_refis the only field portable across instances by design, and that multi-instance composition lives in a layer above this atom. - Invariant 7’s no-partial-record claim stated unconditionally (Pass 3). The strengthened Invariant 7 added in Round 1 said a
storage-failureresponse guarantees no partial record is observable — without qualification. But theamendtwo-write atomicity edge case explicitly said implementations must provide atomicity or a crash-recovery scan; the guarantee is joint, not unilateral. Stated unconditionally, the invariant overclaimed. A reader could misread it as the atom enforcing atomicity by spec alone, when in reality the atom mandates it and the implementation provides it. Resolved: Invariant 7 amended to state the joint enforcement explicitly — spec mandates, implementation provides — with the two-write atomicity edge case cross-referenced and an implementation that violates the guarantee named as non-conforming. - Outputs field-listing used exclusive “or” where State transitions allow co-occurrence (Pass 3). The Outputs description for
readenumerated transition-metadata fields with “or” between successor-side fields, the original’ssuccessor_id, and retraction-side fields — reading as exclusive cases. But the State section allows Amended → Retracted: an observation that was first amended (originating a successor) and then retracted carries bothsuccessor_idAND retraction metadata. Similarly, a successor observation that is itself later amended carries bothpredecessor_id(from the first amend) andsuccessor_id(from the second). The exclusive “or” silently misrepresented the data model. Resolved: Outputs description rewritten to enumerate the conditional fields with explicit co-occurrence rules — multiple transition-metadata fields can be set on a single observation, and which ones follow mechanically from the State transitions. The two canonical combinations (Amended-then-Retracted, successor-also-amended) are called out explicitly. - Citation drift in disputed-observation scenario (Pass 3). The scenario claimed by Invariant 2, the amendment record names the correcting clinician and the reason. Invariant 2 is about successor creation; it says nothing about
amended_byoramendment_reason. The attribution actually rests on the State definition for Amended observations (which names the successor’s fields and their write-once timing) and Invariant 9 (which protects them from rewriting). The bad citation made the scenario look correct without actually following from the invariant it cited. A reader cross-checking the citation would discover the gap; a reader trusting it would have a false sense of audit-trail completeness. Resolved: citation rewritten to name the State definition and Invariant 9 explicitly; the retraction-metadata claim also cited Invariant 9 (previously uncited). - Rejection priority unspecified across all actions (Pass 3). When multiple precondition violations exist on the same call — say,
amend("obs-999", amended_by: "", value: "garbage", unit: "", reason: ""), which fails id-existence AND request-metadata AND content — the atom said nothing about which rejection fires first. Two conforming implementations could produce different rejections for the same call; a caller fixing the visible rejection might see an unrelated one on retry with no documented expectation. Resolved: new edge case Rejection priority specifies the order across all four actions — cheapest and most-structural checks first, persistence last — and names this as the same across conforming implementations so callers can write deterministic retry logic. The order onamendis:not-known→already-amended/already-retracted→invalid-request→invalid-observation→storage-failure; analogous orderings forretract,record, andread. - “System clock” vs “wall clock” wording inconsistency (Pass 3, minor). Invariant 8 said “system clock”; the Clock-semantics edge case said “receiving node’s wall clock”; the
recordDecision point also said “system clock”; therecordAction signature said “system clock.” Three different places, two different wordings for the same concept. An AI adversarial pass should catch this. Resolved: all references harmonized to “receiving node’s wall clock” with the Clock-semantics edge case cross-referenced from Invariant 8, therecordAction signature, and therecordDecision point.
Pass 2 was clean. The amendment-chain extraction question was steelmanned one more time at maximum pressure — a parameterized “Supersession Chain” atom taking immutable-fields and correctable-fields at instantiation, applying chain logic generically — and the extraction still loses: the fields operated on are host-specific (no generic record_id, no generic patient_ref/observation_type), the immutability invariants name specific fields, and composing a generic chain over a generic Record type inverts the dependency direction. After four examinations across four rounds with the same answer, this judgment is documented as settled; future rounds need not re-litigate it unless new evidence — a second concrete host atom that would benefit from the same mechanic — emerges. The state-machine extraction question was also examined and similarly resolved as host-specific; once Workflow / State Machine (roadmap atom #9) lands, the Composition notes will mention that this atom’s state model can be specified as a Workflow instance, but the state machine remains inlined here for the same definitional reasons.
The AI-conducted round closed the gaps a sympathetic human reviewer would have rationalized past — the unconditional Invariant 7 framing, the exclusive-“or” Outputs description, the bad Invariant 2 citation, the unspecified rejection priority, the silent unknown-observation_type behavior. Each finding was a real semantic gap or a real precision failure; none was paraphrased-back commentary. The pattern is stronger because the AI pass had no investment in the prior choices.
Scheduled rescan: 2026-05-20 — clean.