ADR-0053 — Per-write human authorship: the authoring signature, the authorship binding, and the authorship-confidence grade¶
- Status: Accepted
- Date: 2026-07-18
- Refines: ADR-0008 (implements its
session.user ≠ event.authorinvariant at the data/floor/CLI layer), ADR-0007 (the authorship half of the compositional contributor set), ADR-0051 (extends the contributor floor from responsibility to authorship; reuses the author-vs-admit asymmetry), ADR-0052 (the human signs the sealed body; the node keeps custody), ADR-0012 (grade-don't-refuse under version skew). - Resolves: #204 (2026-07-15 review finding C3).
Context¶
Every clinical event authored today mints exactly one contributor — {actor_id: node_key, role:
"recorded"}, the recording device. There is no human author on the event. The --attest-as path
(ADR-0049) adds a human's responsibility as a separate
clinical.medication-attestation.asserted event.
So the build has responsibility without authorship — the exact mirror image of the deployed-EHR
failure §3.9/§3.10
diagnoses. By §3.9's own rule — "an event is AI-generated iff its set contains a non-human author and no
human in a responsibility-bearing role" — every un-attested medication row reads as machine-generated
content, and the §5.10
informational floor would render the whole med list as un-vouched machine content. ADR-0051
ratified recorded precisely to make that interim reading honest (device-recorded, no human authorship
claimed) rather than illegal — while scheduling this slice to end the interim before the next clinical
stream.
The load-bearing invariant that closes the gap is ADR-0008's
session.user ≠ event.author: authorship binds by a per-write attribution act, not by whoever holds the
session. It has no implementation and, until this slice, no owning ROADMAP entry — while the second half
of the principle-10 split (attestation) shipped first. Each additional device-additive clinical stream
deepens the eventual retrofit; the window is cheapest to close now, on the one clinical stream that
exists.
Decision¶
Canonical home: spec §3.9 / §3.10. No new event type; no new envelope field; no schema migration (the contributor-set fields exist from day one — this fixes an authoring path and a floor binding).
Ship the authorship half of principle 10 onto the medication stream. A clinical event can carry an
authenticated human author — {human, "authored"} + {node, "recorded"}, signed by the human,
the node sealing the body and holding its DEK (custody) and staying recorded. Floor-enforced so the
authorship claim is unforgeable at the door that mints it, and graded, never refused, at the door
that receives it from the federation.
This realizes session.user ≠ event.author at the data / floor / CLI layer. ADR-0008's headline UX —
durable session-decoupled drafts and the sign-as stranded-work salvage — presumes a draft store
and a session/UI layer that do not exist yet (the reference UI is a Tauri shell, slice 1); those are the
implementation above the invariant and are explicitly deferred to the UI layer. The can't-retrofit
pieces — the wire shape and the floor binding — are what this slice lays down.
Authorship is a grade, not a gate (ADR-0008): the floor never requires a human author. The device-only path (batch / emergency / no enrolled human present) stays first-class and unchanged.
The seven ratified decisions¶
-
Cut. The node/floor/CLI realization of
session.user ≠ event.author. Draft-durability andsign-assalvage defer to the UI layer. -
Binding model — the human author signs; the node holds custody. Born-sealed already split signing from custody:
seal_and_sign(body, sk)signs the sealed bytes,ensure_unwrap_key(client, node_sk)grants the node the DEK. So the author (human) signs the sealed clinical event while the node seals it and holds the DEK —session ≠ authormade cryptographic, with no new token machinery. The pattern is already precedent:identity.link.assertedis signed by the accepting human (apply_proposal.rs;signer_key_id = human_kid). -
Wire shape — authorship only, this slice.
Theclinical.medication.asserted signer_key_id : <human> # session(node) ≠ author(human) contributors : [ {actor_id:<human>, role:"authored"}, # signs → authenticated {actor_id:<node>, role:"recorded"} ] # seals + holds DEK (no responsibility object)authoredrole is responsibility-bearing but carried without aresponsibilityobject — a legitimate "authored, not-yet-vouched" state (§3.9: absent = un-vouched, a legitimate state). Per-event or per-thread responsibility remains the separate ADR-0049 attestation event, unchanged. Device-only fallback is unchanged: node signs,[{node, "recorded"}]. -
Role — uniform
authored. All medication verbs (assert / cease / dose-change / dose-correction / reconcile / separate) carry the human asauthored: they record clinical statements about medications, not prescriptions.ordered/co-signedare reserved for a future prescribing/dispensing stream; clinical context makes finer distinctions implicit until then. -
Strict submit door (db/005) — enforce the authorship binding. Today's floor has a hole:
cairn_check_contributorschecks only role-in-vocab, andcairn_responsibility_boundchecks only entries that carryresponsibility. So a node could forge{human_X, "authored"}while signing with a different key and no token — recording "Dr X authored this" when Dr X never touched it (the #195 hazard, one field over). The binding, generalising #195 / ADR-0051 §2 from responsibility to authorship:
A contributor whose role is responsibility-bearing and whose
actor_idresolves to a human actor must be authenticated as the event's signer or a verified attester (signer_key_idor the verifiedattester_key).
recordedis contributory → exempt (the node need not sign); existing device events untouched.- Existing attestation /
identity.linkevents: human = signer = attester → satisfied. - New
{human, "authored"}: human = signer → satisfied. A forged{human_X, "authored"}signed by another key with no token → refused at strict submit.
This is the "attribution token" the issue names: for the human-signs case the signature itself is the attribution proof; a future token-backed author (an author who did not sign — verbal order, AI-scribe) is deferred, but the rule already accommodates it (verified attester arm).
-
Apply door (db/020) — admit and grade; no new refusal. The apply door already verifies signatures in-DB (
cairn_verify), runscairn_check_contributors(..., false)lenient, and already refuses the provably-false authorship shapes (a bad or contradictory attester token — "forged human author refused", #195). This slice adds nothing to the apply door's refusals. It refuses only what it can prove false; an unverifiable human-author claim (actor ≠ signer, no verifiable token) is admitted and graded, not refused. See the rationale below — this is the decisive, principle-anchored choice. -
Grading — one shared classifier, upgradable. A single pure predicate
classify_authorship_confidence(the ADR-0051classify_rolediscipline) grades an event's authorship: attested— a human author authenticated as the event's signer or a verified attester.unverified— a human-author claim this node cannot verify (actor ≠ signer, no verifiable credential; a forgery, or an author authenticated by a scheme this older node cannot parse — the two are indistinguishable at the door). Rendered "authorship claimed, not authenticated here", never attested, never dropped, and upgradable when a newer node re-grades it.device— recorded-only, no human author (the honest device-additive default, ADR-0051).
This slice ships attested + device; unverified is the apply-side grade. The middle asserted
rung (a named human author with no key present — verbal/telephone orders) defers with the UI and the
token-author path.
Why apply admits-and-grades¶
When a remote med event carries {human_X, "authored"}, signed by node_Y (signature verified), with no
verifiable token for human_X, the door cannot distinguish a forgery (node_Y fabricated it) from a
future-credential authorship (a later ADR authenticates authors by a scheme node_Y used but this older
node cannot parse — ADR-0012
guarantees such events arrive). This slice never mints that shape — we only ever mint author == signer,
which verifies cleanly and is admitted either way — so the ambiguous shape arises only from a hostile node
or a future node.
- Paper-parity (the governing argument, §1.2). On paper, a note initialled "Dr X" that you cannot verify is still in the chart, still readable; nobody shreds the folder because a signature is illegible — they read it and weigh the attribution with suspicion. Grading-not-refusing is the paper-parity move. Refusing a lawful-but-unverifiable future med event would make a real medication invisible to a clinician — interaction-checking, the med list, all silently missing it — which is inferior to paper (paper never makes a med vanish because provenance is doubtful). "A real medication never becomes invisible" is the harder patient-safety floor, and it wins.
- ADR-0012 (never refuse what you can't understand). The apply door must not refuse an event merely because it cannot verify a credential; that conflates forged with authored under a scheme I am too old to understand, and the latter is guaranteed by additive evolution.
- Consistency with ADR-0051's author-vs-admit asymmetry. Strict submit (local, understands its own schema) enforces — "author only what you can stand behind." Apply (remote, may see future schemas) admits and grades — "admit whatever verifiably-signed future the wire brings; refuse only the provably false." Same shape, one field over.
- The forgery is attributable, not silent. A forged remote claim is a signed act by node_Y — evidence for the ADR-0018 revocation cascade, and displayed honestly as unverified.
- The residual risk is bounded to one predicate. A forged row lands in the log, so consumers must
honour the grade; the mitigation is the standard Cairn move — one shared
classify_authorship_confidence— collapsing "every consumer must be disciplined" to "one predicate must be correct." The naive-external-reader risk (a FHIR façade ignoring the grade) is the universal graded-field risk (sensitivity, clock-confidence, trust-state), not unique here.
Consequences¶
- Easier: the authorship half of principle 10 now ships; every med row can read as human-authored, not machine content; the suppression owner-gate recognises the human author for free.
- Harder / trusted surface:
cairn_authorship_boundjoins the reviewed floor; the strict-enforce / apply-grade split must not be "simplified" into symmetry (the doc comment carries the warning, as ADR-0051's does). - The bet: that the human-signs case covers point-of-care authoring until the deferred token-author path (verbal orders, AI-scribe) is needed; the "verified attester" arm of the binding and the grade ladder already reserve room for it.
- Deferred (UI layer): durable session-decoupled drafts and
sign-assalvage; theassertedgrade (named-no-key); author+responsibility on one event.