Design Reference · for Zareef (schema) & Matt (surface)
ADR-067 · one model, three scenarios · in-house morgue / internal coroner section / provincial coroner morgues
The firewall is the acts_as_tenant boundary, not a permission rule. The tenant is the coroner service, not the individual morgue: the province is one tenant with its morgues as branches under it; Kearney is the operating contractor, not the owner. Megan's internal coroner section is a separate tenant again. A human who works two sides (Megan) holds two logins — ADR-029, one user = one tenant.
graph TD
subgraph T1["TENANT · Kearney Funeral Home"]
K1["Funeral cases
(at-need)"]
K2["In-house morgue
cooler + slots"]
end
subgraph T2["TENANT · Kearney's internal coroner section (BTC)"]
C1["Coroner-held bodies
(caseless)"]
C2["Morgue cooler + slots"]
end
subgraph T3["TENANT · BC Coroner Service (provincial)"]
P0["Province = the tenant"]
P1["Morgue A — branch"]
P2["Morgue B — branch"]
P3["Morgue N — branch (Kearney operates, does not own)"]
end
MEGAN(["Megan · one human"]) -.->|login 1| T1
MEGAN -.->|login 2| T2
K1 -->|cross-tenant transfer
recorded independently| C1
classDef kearney fill:#b4530922,stroke:#b45309,stroke-width:1.5px;
classDef prov fill:#0f766e22,stroke:#0f766e,stroke-width:1.5px;
classDef human fill:#1e407822,stroke:#1e4078,stroke-width:2px;
class K1,K2 kearney;
class C1,C2,P0,P1,P2,P3 prov;
class MEGAN human;
Most of our confusion was collapsing these into one. They are distinct records answering distinct questions. Occupancy is not custody. The slot catalogue is not the occupancy record.
A cooler is a resources row (sub_type: cooler); each slot is a child resources row (cooler_slot, parent_resource_id → cooler). Already ships. Answers: what slots physically exist? Same in every morgue.
One stored row per stay — subject + slot + admitted_at/released_at. Answers: is this slot free; how long has this body been in it? (inventory + billing). Drives the availability view and Phase-3 coroner billing.
Layer-1, append-only, immutable (ADR-014). Answers: who possessed the body, when? Exists only on the Kearney funeral side (at-need cases). Not written on the coroner side.
Capture is not the same on both sides — this is the thing the earlier draft of this page got wrong. The scan-decedent + scan-slot flow lives only on the Kearney internal funeral morgue, where the QR / wristband infrastructure exists and the subject is an at-need case. On the coroner tenants (Megan's internal section and the provincial morgues) RequiemOS is a terminus storage facility: it takes the in/out event fed from the province's own system or entered manually — there is no RequiemOS scan there. What both paths share is only the destination: one storage_occupancies row, read back by one source-agnostic availability query.
graph TD
HK["KEARNEY INTERNAL FUNERAL MORGUE
subject is an at-need case"]
HC["CORONER TENANTS
caseless Person · terminus storage"]
HK --> SK["Capture: scan decedent + scan slot
any order · direction inferred · manual fallback"]
SK --> K["Write custody_event"]
K --> KO["storage_occupancies row
case_id SET · custody_event_id SET"]
HC --> SC["Capture: in/out fed from province system
or manual entry · NO RequiemOS scan"]
SC --> C["No custody_event written"]
C --> CO["storage_occupancies row
case_id NULL · custody_event_id NULL"]
KO --> AV["Availability view
slots WHERE released_at IS NULL"]
CO --> AV
classDef hdrK fill:#b45309,stroke:#b45309,color:#ffffff,stroke-width:0px;
classDef hdrC fill:#0f766e,stroke:#0f766e,color:#ffffff,stroke-width:0px;
classDef kearney fill:#b4530915,stroke:#b45309,stroke-width:1.5px;
classDef prov fill:#0f766e15,stroke:#0f766e,stroke-width:1.5px;
classDef shared fill:#15803d18,stroke:#15803d,stroke-width:2px;
class HK hdrK;
class HC hdrC;
class SK,K,KO kearney;
class SC,C,CO prov;
class AV shared;
storage_occupanciesIn-house and coroner morgues use the same table. The entire structural difference is which columns are populated on a given row. The highlighted row is the delta that carries the whole distinction.
| Column | In-house morgue | Coroner morgue (internal or provincial) |
|---|---|---|
| id · tenant_id | sametenant_id scopes to the funeral tenant | sametenant_id scopes to the coroner tenant |
| storage_slot_id | same→ a cooler_slot resource |
same→ a cooler_slot resource |
| person_id | SETsubject is always a Person | SETcaseless Person (zero cases, per ADR-016) |
| case_id | SETthe at-need case | NULLno Kearney case exists — resolves OQ-0263 |
| custody_event_id | SETrow is the event's projection | NULLterminus storage — no custody event (D6) |
| admitted_at · released_at | samecheck-in / check-out timestamps | samesame — and this is the billing signal |
| admitted_by · released_by · entry_method · notes | sameentry_method: scan | manual |
samemanual likely more common here |
case_id nullable is a soft invariant — "coroner-tenant rows must not carry a case_id" is enforced at the model/service layer + a spec, not the DB (same posture as ADR-053's category-vs-type check). custody_event_id is nullable purely to future-proof a hypothetical reversal of D6 at zero migration cost — it is not populated on the coroner side today.
Every one of these got muddled at least once while we worked the model. Fixing the words fixes most of the "wait, which thing?" moments.
storage_occupancies row).resources; it's the same for every morgue."case_id is NULL; the subject is a caseless Person."storage_locations table." — dropped; it duplicates cooler_slot.case_id is required." — that made caseless bodies impossible (the old defect).What ADR-067 commits to (review these), and the one thing still genuinely open. Ratify on the ADR.
Province = one tenant, morgues = branches; Kearney operates, doesn't own. Internal section = separate tenant. Firewall = acts_as_tenant. Two logins for Megan.
resourcesParent cooler + cooler_slot children, every morgue. "Not time-schedulable" was never the membership test — schedulable and custody-location are independent flags.
case_id nullableOne storage_occupancies table, always-Person subject. The single nullable column is the whole in-house-vs-coroner delta. Resolves OQ-0263.
Scan decedent + slot, direction inferred, manual fallback. In-house writes a custody event and an occupancy row from one action.
Building-boundary in/out only; we don't own the province's CoC. No caseless custody events → ADR-016 Rule 4 intact. (Was deferred; decided at the 2026-09-21 Ryan session.)
How province-side users are provisioned and how a coroner decedent's Person record is created. Doesn't affect this schema, but gates a usable coroner-tenant surface.