The scheduling problem at a funeral home is four problems wearing one coat. This explainer separates them and shows how they fit back together.
The cluster has four peer PRDs, not a parent and three children. Resources and Staff Availability are the data layer — what we own and who can work. Automatic Scheduling is the engine — it reads those two (plus case and custody state) and resolves slot proposals against conflicts. Calendar is the display layer — it surfaces everything to humans and is where manual edits happen.
The doctrinal rule that justifies the four-way split: people, resources, and the schedule are categorically different things. Folding any two of them into one entity produces the bugs the skeleton PRD was already producing.
Two data PRDs at the bottom. The engine in the middle, reading from both. The calendar on top, reading from all three. Workflows are the primary caller of the engine, but they live outside this cluster.
When this looked like one PRD, the model collapsed people into resources, folded availability into the calendar, and put conflict detection wherever it happened to land. Pulling the three things apart is the load-bearing rule for the whole cluster.
Margaret, David, Jessica, Rob, Sophie. They have working patterns and exceptions to them. They get tired, take leave, and go on-call. They have an HR layer behind them — not a booking layer.
Chapel A. Hearse 2. The prep room. They're owned things with operational properties — turnover times, custody-validity, out-of-service windows. They cannot be hard-deleted because custody records reference them forever.
A viewing at 2pm Thursday — claims a chapel and a director and a hearse. The event is the thing that intersects people and resources in time. It is not either of them.
Mash any two together and you get the bugs the skeleton PRD already had: resources.user_id linking a person into the resource table, cascading deletes that would have broken chain-of-custody, and a calendar that owned the data instead of just displaying it.
Each card answers four questions: what does it own, what does it explicitly not own, what does it read from, who reads from it. If you read nothing else in this explainer, read these four cards.
The catalog of physical things the home owns, and the rules that keep that catalog readable to chain-of-custody for years after a resource is retired.
What hangs off the staff entity: working patterns, exceptions, on-call rotations, time-off requests, and the rules around who sees whose schedule for what reason.
users table (read-only), branch list.The deterministic engine that finds feasible slots, surfaces structured conflicts, and never silently reassigns work. AI sits above it, never in place of it.
The surface staff live in alongside the case view. Shows everything that's scheduled, alongside the availability the events draw on, persona-shaped without becoming five separate products.
The four-way split only pays off when you watch a real flow cross between the documents. Each scenario is collapsed by default — open the one that maps to the work you're trying to understand.
K-2026-0143 advances past authorisation-signed. The cremation workflow module needs a slot on a cremator, with authorised staff, inside the BC regulatory window (≥48h after death, before the legislated outside bound). It calls into the engine in-process — no message bus.case_id, event type cremation, resource requirement cremator, staff requirement cremation_authorised_director, time window [2026-03-12, 2026-03-19], priority regulatory_window_bound.cremation_authorised_director attribute. David is off Friday. Sophie is on a course Tuesday morning.audited gem records a Layer 2 entry; the case's activity narrative gets a Layer 3 entry.Use this as a wayfinding reference when you're not sure which PRD owns a question. Bookmark this section.
| Question | Lives in | Why |
|---|---|---|
| "Does this chapel still exist?" | Resources | The catalog owns active / decommissioned state. |
| "Is Chapel A available Tuesday at 2pm?" | Calendar reads Resources | Availability display is the calendar's surface; the underlying state is the catalog's. |
| "Is David working Saturday?" | Staff Availability | Working patterns and exceptions live there. |
| "Can David also take Saturday at 3pm without violating BC employment standards?" | Engine reads Staff Availability | Employment-standards rules are warnings produced by the engine, against availability data. |
| "Find me a cremation slot next week." | Engine | Slot-finding is the engine's primary capability. |
| "Why couldn't the workflow find a slot?" | Engine | The conflict report — including path-to-yes alternatives — is the engine's output. |
| "How does the day view render an on-call window?" | Calendar | How availability data renders is the display surface's call. |
| "How does turnover time get composed into buffer?" | Resources declares · Engine composes | The catalog declares the constraint; the engine composes it into slot decisions. |
| "Can a viewing be scheduled in the prep room?" | Resources (custody-location flag) · Engine (enforces) | The flag is on the resource; the engine enforces it as a custody-state conflict. |
| "What time-off requests are pending?" | Staff Availability | The request workflow is owned by the availability PRD. |
| "What's the printable schedule for Rob tomorrow?" | Calendar (the run-sheet view) | The run-sheet is owned by the calendar; the priority signals that order it come from the engine. |
| "Can Jessica drag an event to a new time on the calendar?" | Calendar (surface) · Engine (conflict check) | The calendar owns the affordance; the engine checks the modified slot. |
| "Did Sophie's reassignment get recorded?" | Calendar writes · audit per ADR-014 | Modifications happen at the calendar; auditing is cross-cutting per ADR-014. |
| "Who's on-call this weekend?" | Staff Availability | On-call rotations are a third availability state (working / off / on-call). |
| "What does the schema actually look like?" | docs/database/mvp-rails-schema.md | None of these PRDs own schema. Per the doctrine — PRDs describe intent, not DDL. |
Three other PRDs come up constantly in the four scheduling documents. They are not part of the cluster — they read from it or call into it. Knowing where they sit prevents reading the wrong PRD.
Workflow modules schedule the majority of case-scoped events. They ask the engine for slots and commit them. Module internals, the JSONB context envelope, the pipeline state machine — all live in the Workflows PRD, not here.
Custody records reference resources as the deceased's physical location. The no-hard-delete and decommissioned-resolvability rules in Resources exist for this consumer. The records themselves and the regulatory reporting on them are owned in a future PRD.
Case priority, deceased characteristics, family preferences, the assigned director — read by the engine when evaluating slots. The case reference itself is what makes case-scoped events case-scoped. Branches as tenant configuration also live here.