Hospital Recovery
Live Recovery APIs, shared capacity, clinical evidence, retry safety and release gates.
Delivery Boundary
Programme U7 is governed by the focused Recovery plan. Local U1-U7 implement source protection, named resources, stays, observations, escalation, current readiness, secured HTTP APIs and the live workbench in both presets. See U6 API evidence, U7 UI evidence and U8 acceptance. Development mock mode remains separate; live failures do not return mock care. Programme U8 signed discharge and full ward operations remain later work. The ABDM discharge contract is a hard requirement for that signed-discharge phase, not a claim that this work exports a report. Production policy approval, explicit nursing grants, D4/D5, deployed QA and pilot acceptance remain separate gates. An empty production policy registry must keep policy-controlled assessment/handoff unavailable.
Use the manual QA guide and U1 execution record for evidence, limits, and the next implementation boundary. No green characterization test grants clinical release approval.
Current Source Evidence
| Test | Observed behavior | Required later action |
|---|---|---|
| RC01 | Case-linked MAR enrollment preserves a null encounter without creating an admission. The obligations query does not assert clearance. | Carry the same identity through the Recovery stay. Do not auto-create an encounter. |
| RC02 | The canonical assignable scope includes inactive/reserved beds and does not check parent activity. | Recovery must require an approved active resource chain and an available bed. |
| RC03 | U1 exposed occupied-bed deactivation/reparenting. U2 changes this test to prove database rejection. | Keep the guard through every supported writer. |
| RC04 | U1 exposed bed release without closing an active admission. U2 changes this test to prove commit rejection. | Release must coordinate the actual care owner in one transaction, not call this helper alone. |
| RC05 | The canonical state machine rejects occupied-to-available and requires cleaning. | Preserve this lifecycle in commands and UI. |
| RC06 | A second active admission for one bed fails at the database index. | Keep this protection and add cross-workflow ownership checks. It does not protect a future Recovery stay by itself. |
| RC07 | Canonical observations store structured values, units, observed time and optional practitioner without an encounter. | Reuse these records; add protected Recovery linkage and authenticated user/staff provenance. |
| RC08 | Encounter category replacement deletes old vital observation identities. | Exclude protected Recovery evidence or reject the managed mutation atomically. |
| RC09 | Generic observation update/delete has no Recovery correction lineage. | Protect linked records and route corrections through the managed command. |
The tests are in backend/domains/clinical/test/services/hospital/recovery_characterization_test.rb.
Tests named GAP capture a known unsafe source behavior, not a desired invariant.
When the relevant local U2-U5 fix lands, replace that gap expectation with a rejection/preservation regression in the same delivery.
Do not keep unsafe behavior to preserve a characterization assertion.
The isolated U1 source database reported, before the U2 forward repair:
| Table | RLS enabled | RLS forced | Owned foreign keys |
|---|---|---|---|
clinical.facility_beds | No | No | 0 |
clinical.facility_rooms | Yes | Yes | 3 |
clinical.facility_wards | Yes | Yes | 2 |
clinical.admissions | Yes | Yes | 8 |
This is metadata evidence from the isolated candidate database, not an audit of staging or production. The original bed migration declares protections that the SQL dump does not contain. U2 adds the forward repair. Actual-object checks, SQL/migration parity, enforced-role tests and facility acceptance remain required before Recovery intake.
Source And Writer Inventory
All paths in this table are under backend/domains/clinical/.
| Supported path | Current write and locking | Recovery obligation |
|---|---|---|
services/ipd/admit_service.rb, create | U4 creates canonical care and a bedless admission in one savepoint, then locks parents/beds and claims capacity. | One owner; losing intake leaves no orphan care. No Recovery dependency on the IPD gate. |
| Same service, assign | U4 reloads and locks admission before checking active/bedless state, then locks parents and bed. | Retain the admission recheck and cross-workflow owner guard. |
| Same service, transfer | U4 locks admission, all sorted parents and beds, then changes owner and releases source to cleaning. | Preserve one current owner and no partial release. |
services/discharges/create_service.rb | U4 locks related cases, current admission, stays and capacity. Active Recovery blocks discharge of the source encounter. | Receive after discharge must reject terminal source care. Never use this admission-only path as day-care discharge. |
controllers/facility_beds_controller.rb | Update permits room/active changes. Transition locks the bed and changes status. | Structure/state endpoints must not detach or release active care. A model validation alone does not protect raw writes. |
controllers/facility_rooms_controller.rb, facility_wards_controller.rb | Parent edits and ward deactivation affect child resources. | Reject an occupied parent's unsafe deactivation/reparenting and serialize against intake. |
models/facility_bed.rb | release!, transition_to! and direct updates are additional entry points. | Apply shared invariants below the controller. Preserve cleaning and occupant scope. |
services/hospital/surgical_cases/transition_service.rb | Locks case, then booking where applicable; readiness takes the Inventory source lock. | Ready/completed/cancelled changes cannot bypass or lose active Recovery care. |
services/medication_mar/order_command.rb | Case, registration for create, then request; nursing commands lock case, request, occurrence. | Keep case-first order and exact nullable encounter linkage. Recovery must not create a second medication writer. |
services/hospital/readiness/command.rb and services/hospital/case_stock/command.rb | Case lock precedes source changes/locks. | Keep source gates in the existing case-owned transaction and do not introduce reverse bed-to-case locking. |
controllers/observations_controller.rb | Generic create/update/delete and transactional bulk vital recording. | Add source-owner protection and retain ordinary unlinked observation behavior. |
services/encounters/save_clinical_data_service.rb | Replaces included categories with delete_all; patient-level history spans encounters. | Do not delete Recovery-owned evidence, unlink its history or silently recreate it under a new ID. |
Shared Occupancy And Lock Contract
This is the target protocol for local U2-U5, not a claim that existing writers follow it. Use one transaction for state, receipt, immutable events and required mutation audit.
- Resolve current membership, selected facility and action authority. Recheck current authorization before replaying a receipt.
- Lock applicable case rows in stable ID order, then existing admission rows, then stay rows. Re-read the current care owner and references under those locks.
- For operations that depend on parent activity or change structure, lock affected wards, then rooms, each in stable ID order. Lock all affected bed rows in stable ID order after the parents.
- When the action requires current clinical evidence, follow existing case-first source order. Lock medication requests and occurrences in stable ID order. Acquire any required Inventory source lock through its owning service. No source command may acquire a case or capacity lock in reverse order.
- Recheck expected versions, active resource chain, current owner, exact care identity and current source obligations. Commit one effect or return a conflict with no partial state.
A resource-only writer does not acquire a care-owner lock after a bed lock. It rejects an active-care mutation or enters the owner-first command path before taking bed locks. Database guards arbitrate on the same parent bed row and validate scope/owner agreement; they must not introduce bed-to-owner lock acquisition. U2/U4 must prove the full graph with independent connections. This protocol is not a runtime race-test receipt.
Required database invariants:
- One canonical physical identity per bed; purpose classification is separate from category.
- At most one active Recovery stay per case and one current physical owner across active admissions/stays.
- Bed, room, ward, case and registration references belong to the same tenant/facility.
- Bed pointers and active-owner references agree at transaction completion. A null encounter is valid for day care, not permission to omit the case/patient owner.
- Occupied resources and their parent chain cannot be deleted, deactivated, reclassified or moved out from under care.
- Immutable movement, observation-link, assessment and receipt history cannot be rewritten by generic CRUD.
Do not add a parallel physical-resource ledger. Do not infer a Recovery purpose or license count from a preset.
Proposed HTTP Contract
The original anchor is retained for existing links. Local U6 now implements
these routes and U7 uses them through the typed hospitalRecoveryApi.
Paths are relative to /clinical/facilities/:facility_id.
The facility ID is a selector, not authorization. A request does not supply a tenant as authority.
| Method and route | Meaning |
|---|---|
GET /recovery/capability | Read/write availability, source/policy status, supported actions and precise unavailable reasons. |
GET /recovery_board | Authorized resource totals, paginated active stays, awaiting-assignment cases and one evaluation time/timezone. |
GET/POST /recovery_resources | List or provision canonical named Recovery resources; return permitted parent-group choices. |
GET /recovery_resource_commands/:operation_key | Recover a provisioning receipt with current configuration authority, without knowing the created resource ID. |
POST /recovery_resources/:id/commands | Versioned structure, activation and cleaning/maintenance commands. |
GET /recovery_resources/:id/commands/:operation_key | Authorized resource-command receipt lookup. |
GET /surgical_cases/:case_id/recovery | Current stay, assessment/obligations and source-safe case projection. |
POST /surgical_cases/:case_id/recovery_commands | Stay, observation, escalation, assessment and continuing-care handoff commands. |
GET /surgical_cases/:case_id/recovery_commands | Paginated command history, or exact operation_key lookup. |
GET /recovery_stays/:id/history | Paginated protected clinical/movement history. |
GET /recovery_stays/:id/handoff_targets | Only currently eligible existing continuing-care destinations and acknowledgement actions. |
Use current Hospital response envelopes and structured errors.
Use runtime validation and snake-case mapping in hospitalRecoveryApi/recoveryTypes, not component HTTP calls.
Opaque versions are strings. Operation keys are UUIDs, scoped to tenant/facility and protected resource/action context.
Command history must not disclose another case's receipt through a matching key.
Command Matrix
Every command has action, operation_key, relevant expected versions and any required reason.
Reject unrecognized fields and actor/tenant/patient overrides.
Resolve resource and patient identities from authorized records, not text entered by the caller.
| Action group | Required preconditions/payload | Current result and effect |
|---|---|---|
| Provision resource | Existing authorized canonical group/room, unique local name/code, recovery purpose and current configuration version | One resource and receipt; no planning-count side effect. |
| Rename/activate/classify | Resource version and permitted new values | New version, or occupied-parent/owner conflict. No implicit move. |
| Clean/maintenance | Resource version and allowed state transition; reason where required | State/event change only. Cannot discharge or free occupied care. |
| Receive | Case version, available resource and its version; case is awaiting Recovery assignment | One active stay/occupant. An already-received case conflicts or replays its exact receipt. |
| Move | Stay version, target bed version and expected current resource/version | Same stay at target, source cleaning and immutable movement. |
| Record/correct observations | Stay version; structured coded values/units, observed time, note; correction target/current evidence version and reason | Canonical observations, protected links and author/time history. No client-ready flag. |
| Raise/acknowledge/resolve escalation | Stay/escalation version, reason and current evidence reference where required | Separate immutable lifecycle events. Acknowledgement is not resolution. |
| Assess readiness | Stay version, expected policy hash and current evidence revision preconditions | Server-evaluated result, current blockers and bound evidence snapshot. |
| Accept continuing-care handoff | Stay/current-target versions, server-eligible target and receiving actor's authenticated acknowledgement, reason | Explicit accepted context/obligations, closed stay and source cleaning once. No patient discharge. |
The accepting actor must have current authority for the target context and supply their own authenticated acknowledgement.
The producer cannot submit another actor's identity as proof of acceptance.
U1 does not assert that a supported receiving workflow exists for every facility.
If there is no eligible target, handoff is unavailable. Bed moves and ongoing care remain distinct.
The later U8 signed-discharge service calls the guarded release boundary inside its own transaction.
No public discharged flag, arbitrary destination, home label or browser-supplied proof can invoke it.
Read And Error Semantics
Base view requires view_hospital and view_surgical_cases, current facility scope and the relevant module/capability.
Clinical values require observation-source read authority. MAR data retains its own policy.
Structural resource changes use manage_hospital_configuration.
U1 did not seed manage_recovery. The U4 candidate pulls its migration and
catalog/default/snapshot/key-behavior coverage forward from U6, with no default
role grant. It checks real stay operations and current facility assignment.
The shell remains the role/permission administration surface.
Clinical writes additionally require canonical observation authority, current staff/practitioner assignment and the approved action policy. An admin role is not nursing authority.
| Condition | Required transport meaning |
|---|---|
| Missing authentication or denied current authority | Existing 401/403 contract; no receipt existence or restricted clinical data. |
| Foreign/missing selected resource | Existing non-disclosing 404 contract. |
| Invalid shape, unknown field or bad typed value | 422 validation details with field names; no write. |
| Stale resource/source version or changed payload under a used key | 409 conflict with a safe code and reload/recovery instruction. |
| Inactive bed or parent resource | 409 RESOURCE_UNAVAILABLE; no occupancy change or receipt. |
| Occupied resource, invalid state or current readiness blocker | Structured conflict/validation result, with authorized source links where applicable. |
| Missing capability, policy or required source | Explicit unavailable reason; never empty/ready success. |
| Required audit unavailable | 503; no clinical read result or committed clinical mutation. |
| Authorized exact lookup has no committed receipt | 200 with receipt: null; do not equate timeout/denial with absence. |
An exact-key replay is authorized before lookup and returns the committed receipt before testing the old versions again.
A replay does not assert that the present source state still equals the original result. Refetch current state.
After a lost response, look up the same key; never silently generate a new mutation intent.
For provisioning, use the facility-scoped /recovery_resource_commands/:operation_key lookup because the created ID may be unknown.
Require current configuration authority and return the created resource ID in the committed receipt, or receipt: null for authorized absence.
The instance-scoped lookup remains valid for commands against an already known resource.
Keep only private identity-scoped retry metadata, not observation notes, patient search or clinical payloads in browser storage.
Board counts cover the authorized filtered population, not only the current page. Active overnight stays remain visible across the facility-local date boundary. An observation/MAR reader without source authority sees unavailable/forbidden source state, not fabricated normal values. Query keys include tenant, facility, profile, authenticated user and filters. Cancel or isolate old responses and clear drafts/selectors on identity changes; preserve initial deep links during first identity hydration.
Resource drafts retain the version captured when selected. A refetch cannot replace that token under unsent fields. A changed version blocks save until the user explicitly loads the current resource. Readiness review also starts unchecked. It records the evidence the user reviewed, not merely the evidence that loaded. Changed evidence requires another explicit review.
A direct RESOURCE_UNAVAILABLE rejection permits a new target only after fresh
reads succeed. Failed refresh keeps the original key. Timeouts and 503 results
remain uncertain. A case with a closed Recovery stay cannot start another stay
through receive; exact-key replay still returns the original receipt.
Read-Only Capacity Audit Specification
Run the future audit against the selected facility with current read authority. Local U1 supplies this specification, not an executable production repair tool. Use aggregated, non-PHI output in the release record. Keep any authorized row-level reconciliation material private.
| Check | Report | Cutover rule |
|---|---|---|
| Actual schema | RLS/force/policy, scoped FKs, uniqueness, grants, schema path | Missing required protection blocks new Recovery intake. |
| Resource chain | Orphan or cross-tenant/facility room/ward/bed references | Resolve with approved forward corrections; no automatic reassignment. |
| Physical owner | Active admissions, bed pointers/status, duplicate or missing owner | Preserve active care and investigate discrepancies before validation. |
| Availability | Inactive occupied bed/parent, reserved/cleaning/maintenance resources | Never count as free because a planning field or preset says so. |
| Purpose/counting | Unclassified existing resources and deduplicated recovery/inpatient totals | D5 facility approval supplies the mapping; never infer from names or presets. |
| Care continuity | Exact nullable case/encounter/registration, MAR links, required document/source status | No fabricated admission/encounter, no silent resolution of obligations. |
The audit must be read-only and repeatable. Re-running it must not change rows, counters, classifications or migration state. Record selected facility, evaluated time, deployed commit, object-check outcome, aggregate counts and reviewer decision. An audit failure is not permission to reset or reseed a shared database.
Settings And Release
Planning capacity remains metadata. Real resource commands determine capacity. Disabling intake must preserve the authorized continuation/reconciliation path for active care and exact-key recovery. Code/schema delivery does not approve clinical policy or production resource classification. Use the release acceptance record for D4/D5 decisions and actual deployed QA.