From 37aef874fe99157b5fbf925110d6e6301a6e37ea Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Wed, 26 Aug 2026 09:01:00 +0800 Subject: [PATCH 01/12] Spec: Phase 5, bed availability becomes real The design for the phase that makes the capacity figure plannable: a lifecycle for a bed release, leave beds as a distinct thing from empty beds, a discharge and egress board, predicted capacity in four bands within today, and a freshness signal on every screen. Records eleven decisions, of which three are refusals worth naming: - Nothing predicted may ever be added into "available now". A coordinator has to be able to point at one number and say that is a bed I can fill this minute. - Releases expected beyond tonight are excluded AND counted as excluded. Silent truncation reads as having counted everything. - Neither a bed release nor a leave bed carries sex, even though sex is the one permitted patient attribute and carrying it would let the sex-mix column refresh an hour earlier. Phase 4 wrote a structural privacy test against the type's own field set; that test is worth more than the column. Also corrects the record: Phase 4 already built the bed-release concept, its fixed blocker list, its ward-only flag event and the ward's flagging panel. This phase extends that rather than starting over, and the spec says which single existing behaviour it changes - unitCapacity's raw "potential" count. Co-Authored-By: Claude Opus 5 --- ...rd-flow-phase-5-bed-availability-design.md | 255 ++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 docs/superpowers/specs/2026-08-26-ward-flow-phase-5-bed-availability-design.md diff --git a/docs/superpowers/specs/2026-08-26-ward-flow-phase-5-bed-availability-design.md b/docs/superpowers/specs/2026-08-26-ward-flow-phase-5-bed-availability-design.md new file mode 100644 index 000000000..8918a4031 --- /dev/null +++ b/docs/superpowers/specs/2026-08-26-ward-flow-phase-5-bed-availability-design.md @@ -0,0 +1,255 @@ +# Ward Flow Phase 5 — Bed availability becomes real + +**Status:** design, approved in chat 2026-08-26. Implementation plan follows separately. + +**One sentence:** wards say when beds are actually coming free, and the coordinator's capacity +figure becomes a number that can be planned against rather than a snapshot of the present moment. + +--- + +## Why this phase, and why first + +Ward Flow models one direction. Beds fill; nothing in the system ever releases one on a schedule. +The capacity board answers "how many beds exist right now", which is not the question a bed +coordinator asks. The question is "will there be a bed tonight", and that is a discharge question, +not an admission question. + +Every other item on the Phase 6–8 list — the morning page, escalation tiers, the closest-suitable- +bed measure, the retrospective — needs a trustworthy availability number underneath it. Building +any of those first means building them twice: once against guesses, then again once the guesses are +replaced. So this phase has no headline screen and is still the one that has to come first. + +## What already exists (do not rebuild it) + +Phase 4 built more of this than the Phase 5 discussion credited, and the plan must extend it rather +than introduce a parallel concept: + +- **`BedRelease`** (`ward-model.ts`) — `{ id, unitId, expectedAt, confidence, blocker, confirmedAt, +confirmedBy }`. Its doc comment records the privacy rule as non-negotiable: every field is about + the bed or the confirming ward, never about a person. `tests/ward-flow-reducer.test.ts` asserts + this **structurally against the type's own field set**, not merely against fixture content. +- **`BED_RELEASE_CONFIDENCE_LEVELS`** — `confirmed | likely | possible`. +- **`BED_RELEASE_BLOCKERS`** — `Awaiting clean | Awaiting pharmacy | Awaiting placement +confirmation | Awaiting service coordination`, chosen from a list and never typed. The list's own + doc comment records that "Pending case review outcome" was deliberately excluded because it reads + as being about the patient's case rather than about the bed. +- **`FLAG_BED_RELEASE`**, ward-only in `EVENT_ROLE`, with the acting-unit claim checked against the + target unit. +- **A flagging panel on the ward screen** already collecting confidence and blocker. +- **`unitCapacity().potential`** — a raw count of that unit's releases, rendered as a column. + +## Scope + +**In:** + +1. A lifecycle for a bed release, replacing the current single-shot flag. +2. Leave beds, as a distinct thing from an empty bed. +3. A discharge and egress board. +4. Predicted capacity for today, expressed in time bands. +5. A freshness signal on every screen. + +**Out, and deliberately so:** the community front door, geography and distance, the morning +state-of-the-state page, escalation tiers, the retrospective view, notifications, cohort and +bed-type matching, the navigation regrouping, the network diagram rework. Those are Phases 6–8. + +--- + +## Decisions + +### D1 — A bed release has a lifecycle, and `confidence` stops doing two jobs + +Add `state: "predicted" | "confirmed" | "blocked" | "released"` to `BedRelease`. + +`confidence` currently carries `confirmed | likely | possible`, which conflates a _lifecycle +position_ ("the ward has confirmed this is happening") with a _degree of belief_ ("we think it is +likely"). Narrow it to `likely | possible`, and make it meaningful only while `state` is +`predicted`. A confirmed release has no confidence: it is not a belief any more. + +Migration is mechanical: any existing release whose `confidence` is `confirmed` becomes +`state: "confirmed"` with `confidence: null`. + +- `predicted` — the ward expects this bed to come free today. Carries `confidence` and `expectedAt`. +- `confirmed` — the ward has confirmed it is happening today. No `confidence`. +- `blocked` — the bed would be free but something operational is holding it. Carries a `blocker`. +- `released` — terminal. The bed is now empty and counts as available. + +### D2 — Only the ward moves a release; the coordinator is read-only + +`FLAG_BED_RELEASE` is already ward-only. The three new transitions (`CONFIRM_BED_RELEASE`, +`BLOCK_BED_RELEASE`, `RELEASE_BED`) are ward-only too, with the same acting-unit claim check. + +A coordinator attempting any of them produces a `Rejection` — the codebase's existing first-class +refusal type, already surfaced on the coordinator screen rather than swallowed. The coordinator can +see every release and can escalate about one; they cannot change it. This is the point: the ward +owns its own beds, and a hub that lets a central coordinator edit a ward's bed state is a hub wards +will stop trusting. + +### D3 — `blocker` becomes state-dependent and typed + +Today `blocker` is `string` and always present. Tighten to `BedReleaseBlocker | null`: required when +`state` is `blocked`, and `null` in every other state. The reducer refuses a `blocked` transition +with no blocker, and refuses a blocker on any other state. + +Extend `BED_RELEASE_BLOCKERS` with three additions that are operational rather than clinical: + +- `Awaiting accommodation` +- `Awaiting transport` +- `Awaiting receiving-service acceptance` + +**Deliberately excluded: anything describing a person's own circumstances.** Guardianship, +financial arrangements and family availability are all real blockers in practice and all describe +the patient rather than the bed, so they follow "Pending case review outcome" out of the list. If +the product owner wants any of them, it is a one-line addition and a recorded decision — not +something an implementer adds because it seemed useful. + +### D4 — A leave bed is not an empty bed + +Add `LeaveBed`: `{ id, unitId, usable, expectedReturn, confirmedAt, confirmedBy }`. + +A patient on approved leave occupies a bed that may or may not be fillable while they are away, and +a coordinator needs to see which. `usable: true` means the ward says it can be filled; `usable: +false` means it cannot. Like `BedRelease`, it carries nothing about the person on leave — not an +identifier, not a reason, not a destination. + +**A usable leave bed is never merged into `available`.** It is its own count, rendered as its own +figure. Merging it would inflate the one number the whole hub depends on. + +### D5 — The horizon is today, in four bands + +`expectedAt` stays an instant. Bands are derived from it relative to the demo clock: + +- **Now** — already released. +- **By midday** +- **By 1600** +- **Tonight** — the rest of today. + +Anything expected beyond tonight is **excluded from every count and the board says how many were +excluded**. Silent truncation reads as "we counted everything" when we did not, and a bed +coordinator who discovers a hidden bucket stops trusting the visible ones. + +Beyond roughly 24 hours a psychiatric discharge prediction is a guess wearing a number's clothes. +The horizon is a deliberate refusal, not a limitation to be lifted later. + +### D6 — Predicted beds are never added to available + +The capacity headline becomes five separate figures, never a sum: + +> **Available now 25 · Confirmed today 9 · Predicted today 6 · Held 14 · Leave (usable) 3** + +`Available now` keeps its current meaning exactly. Nothing predicted or confirmed-but-not-yet- +released is permitted to change it. The render policy is explicit: a coordinator must be able to +point at one number and say "that is a bed I can fill this minute", and that number must never have +been softened by an expectation. + +`unitCapacity().potential` — today a raw count of every release regardless of state or timing — is +replaced by this breakdown. It is the one existing behaviour this phase changes rather than extends, +and the plan must say so where it does. + +### D7 — Every screen states when its data was last true + +One shared freshness component, rendered on every Ward Flow board: + +- Where a confirming role exists: **"Confirmed 10:22 · RPH Adult Secure"**. +- Where nothing has ever been confirmed: **"Never confirmed"** — never a blank, never a dash. +- Where the screen shows derived rather than confirmed data: **"As at 10:42"**, the clock time it + was computed. + +Today only the capacity board carries freshness. A board that looks authoritative and cannot say how +old it is invites the reader to assume it is current, and every other board in Ward Flow currently +does exactly that. + +### D8 — An owner is a role, never a person + +`confirmedBy` is tightened from `string` to a role identifier — a unit or a named service, never an +individual. This is the general rule for the whole hub (agreed for Phases 5–8): accountability +attaches to a role, which survives a shift change without reassignment and keeps staff names out of +the system entirely. + +### D9 — The discharge and egress board + +New route: `/mockups/ward-flow/discharges`, reached from the sidebar's Boards group and from the +capacity board's own figures. + +Grouped by state in the order a coordinator scans them — **Blocked** first (these are the ones +somebody must act on), then **Confirmed**, then **Predicted**, then **Released today**. Within a +group, ordered by expected band. + +Each row: unit, health service, expected band, blocker where there is one, confirming role, and its +freshness stamp. A count of releases excluded for falling beyond tonight sits at the foot of the +board, stated even when it is zero. + +**On a phone this board is cards, not a squeezed table** — one card per release, the blocker and the +band as the two prominent facts. Ward Flow's tables are right at a desk and wrong in a corridor, and +this is the first board built after that was noticed. + +### D10 — The ward screen owns the transitions + +The ward screen's existing flagging panel gains the rest of the lifecycle: confirm a predicted +release, mark one blocked with a reason from the fixed list, mark one released, and record a leave +bed with its usability. Every control is a real control with a real handler — no advisory buttons. + +The coordinator screen renders the same data read-only, with an escalation path but no edit path. + +### D11 — No new fact about any person, anywhere + +`BedRelease` and `LeaveBed` both stay free of anything describing the departing or absent patient. +Specifically, **neither carries sex**, even though sex is the one permitted patient attribute and +carrying it would let the sex-mix column update on a predicted release. + +The trade is deliberate: sex mix updates only when occupancy actually changes, which is already +modelled. Adding sex to a bed release for arithmetic convenience would break the structural privacy +test Phase 4 wrote against the type's own field set, and that test is worth more than a column that +refreshes an hour earlier. + +--- + +## Data flow + +A ward flags a release → it enters state `predicted` with a confidence and an expected time → the +ward later confirms, blocks, or releases it → every state change re-derives that unit's capacity +breakdown → the coordinator's capacity board, the new discharge board and the priority queue all +read the same derivation. No screen computes its own version of the number. + +Leave beds follow the same path with a two-state life: recorded, then ended on return. + +## Failure behaviour + +Consistent with the rest of Ward Flow, every failure degrades toward saying less rather than +guessing more: + +- A release with no valid state, an unknown blocker, or an expected time outside today is **not + counted and is reported as excluded**, never quietly dropped. +- A refused transition produces a visible `Rejection`, never a silent no-op. +- A unit with no confirmed capacity reads **"Never confirmed"**, never zero. Zero is a claim. +- If the derivation cannot produce a breakdown, the board shows `Available now` alone and states + that the prediction is unavailable — the conservative figure survives; the optimistic one does not. + +## Verification + +- Unit tests for the lifecycle, the role gate, the band derivation and the exclusion count — each + mutation-tested, with the surviving mutation reported rather than the test reshaped. +- Extension of the existing structural privacy test to `LeaveBed` and to the new fields. +- A contract test that no screen sums a predicted figure into `Available now`. +- A Chromium journey: a ward flags, confirms and blocks a release, and the coordinator's board + reflects each change without a reload. +- A phone-width check that the discharge board renders as cards and does not overflow. +- Screenshots at 390px, 820px and 1440px, looked at rather than assumed. Every defect found in the + Phase 4 sweep was invisible to structural checks. + +## Success criteria + +1. A coordinator can answer "how many beds will exist tonight" from one screen. +2. No predicted bed has ever been counted as an available one. +3. A ward can record everything it knows about its own beds in under a minute. +4. Every board says how old its data is. +5. Not one new fact about any patient has entered the system. + +## Risks + +- **The prediction is only as good as the ward's habit of updating it.** No software fixes that; the + design's answer is to make the ward screen fast and to make staleness visible everywhere rather + than to nag. +- **Replacing `potential` changes an existing rendered figure.** It is the one behavioural change in + this phase and must be called out where it happens, not folded in silently. +- **The four bands are a synthetic convenience.** They are the prototype's choice, not a clinical + standard, and the board should not imply otherwise. From 1608d3e49b7c2abd473ed0d83eb5a276d52cd915 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Wed, 26 Aug 2026 09:27:48 +0800 Subject: [PATCH 02/12] Spec: four more Phase 5 decisions, and the morning page moves to Phase 6 The coordinator gains exactly one thing it may do to a ward's bed data - mark it refresh requested, which the ward sees on its own screen. Nothing is sent and no number changes. It is the phone call that says is that still right, modelled as a mark rather than a message, so the hub is useful before notifications exist and without acquiring notification's governance weight. Tonight now ends at 22:00 rather than midnight, because midnight is a calendar boundary and nobody hands over at one. Recorded as this prototype's choice in one place, and named as a synthetic convenience rather than a claim about any real roster. The seeded scenario opens on its worst case: releases in every state, at least two blocked, at least one unusable leave bed. A discharge board that opens empty demonstrates nothing and one that opens all-confirmed demonstrates the wrong thing. And the four states are recorded as unvalidated. Predicted, confirmed, blocked, released is a software model of how a bed comes free; a ward charge nurse has not checked it, and it may be a tidy version of something messier. Built anyway, because a working model beats an unbuilt one and this one is cheap to change while it is synthetic - but named as the single most valuable thing to check with a clinician, and as the assumption most likely to be wrong. Co-Authored-By: Claude Opus 5 --- ...rd-flow-phase-5-bed-availability-design.md | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/docs/superpowers/specs/2026-08-26-ward-flow-phase-5-bed-availability-design.md b/docs/superpowers/specs/2026-08-26-ward-flow-phase-5-bed-availability-design.md index 8918a4031..426f09107 100644 --- a/docs/superpowers/specs/2026-08-26-ward-flow-phase-5-bed-availability-design.md +++ b/docs/superpowers/specs/2026-08-26-ward-flow-phase-5-bed-availability-design.md @@ -14,6 +14,11 @@ The capacity board answers "how many beds exist right now", which is not the que coordinator asks. The question is "will there be a bed tonight", and that is a discharge question, not an admission question. +The phase order after this one changed on 2026-08-26: the morning state-of-the-state page moves +from Phase 8 to **Phase 6**, ahead of the community front door. It is built entirely from the +numbers this phase produces, it is small, and it is the artefact that can be put in front of +colleagues. Finding out whether any of this is right is worth more than the next feature. + Every other item on the Phase 6–8 list — the morning page, escalation tiers, the closest-suitable- bed measure, the retrospective — needs a trustworthy availability number underneath it. Building any of those first means building them twice: once against guesses, then again once the guesses are @@ -121,7 +126,13 @@ figure. Merging it would inflate the one number the whole hub depends on. - **Now** — already released. - **By midday** - **By 1600** -- **Tonight** — the rest of today. +- **Tonight** — up to the end of the evening shift, taken as **22:00**. + +**Why 22:00 and not midnight.** Midnight is a calendar boundary; nobody hands over at midnight. The +band has to end where the working day ends, or "beds tonight" means something different to the +person reading it than to the ward that entered it. 22:00 is this prototype's choice, recorded here +so it can be changed in one place, and it is a synthetic convenience rather than a claim about how +any real service runs its shifts. Anything expected beyond tonight is **excluded from every count and the board says how many were excluded**. Silent truncation reads as "we counted everything" when we did not, and a bed @@ -201,6 +212,38 @@ modelled. Adding sex to a bed release for arithmetic convenience would break the test Phase 4 wrote against the type's own field set, and that test is worth more than a column that refreshes an hour earlier. +### D12 — A coordinator may ask a ward to refresh, and may do nothing else + +A coordinator can mark a unit's bed count as **refresh requested**. The ward sees that mark on its +own screen, next to its own capacity, with the time it was asked and by which role. + +Nothing leaves the sandbox and no message is sent. This is the most common real interaction in bed +management — the phone call that says "is that still right?" — and modelling it as a visible mark +rather than a message makes the hub useful before notifications exist (Phase 8), without acquiring +any of notification's governance weight. + +It remains the only thing a coordinator can do to a ward's bed data, and it changes no number. D2 +still holds: the ward owns its beds. + +### D13 — The seeded scenario opens on its worst case, not its best + +The default scenario seeds bed releases across **every** state, including at least two `blocked` +ones and at least one leave bed marked unusable. A discharge board that opens empty demonstrates +nothing, and a board that opens with everything confirmed demonstrates the wrong thing — the +screen's whole purpose is the awkward cases. + +### D14 — The four states are the prototype's model, and are not yet clinically validated + +`predicted → confirmed → blocked → released` is a software model of how a bed comes free. It has +not been checked against how a ward charge nurse actually thinks, and it may be a tidy version of +something messier — a bed can be simultaneously confirmed and blocked in reality, and "predicted" +may compress several distinct real states. + +It is built as specified because a working model beats an unbuilt one, and because the model is +cheap to change while it is synthetic. **This is recorded as the single most valuable thing to check +with a ward clinician**, not as a defect. If it turns out to be wrong, the states change; nothing +else in this phase depends on there being exactly four. + --- ## Data flow @@ -251,5 +294,7 @@ guessing more: than to nag. - **Replacing `potential` changes an existing rendered figure.** It is the one behavioural change in this phase and must be called out where it happens, not folded in silently. +- **The state model is unvalidated (D14).** A ward clinician has not yet checked it, and it is the + assumption most likely to be wrong. - **The four bands are a synthetic convenience.** They are the prototype's choice, not a clinical standard, and the board should not imply otherwise. From b280ace7d48a5a6daddcb2adf52a96a7db851876 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Wed, 26 Aug 2026 09:46:05 +0800 Subject: [PATCH 03/12] Phase 5 plan, the roadmap, a cold-start handover, and the project ledger brought current Four documents so the next session does not have to reconstruct any of this from a conversation that has ended. The plan is eight tasks. Task 1 is serial because every other task reads its types; then two fan-outs of three; then one verification sweep. Each implementer runs only its own focused test file - the heavyweight lock is machine-wide, so agents that each run the full suite queue behind one another and lose the parallelism the fan-out bought. The expensive gates run once, at the end. The roadmap records sixteen product decisions settled with the owner today, each with its reason, because a refusal with no reason attached gets reversed by the next person who finds it inconvenient. It also records the phase order, including the morning page moving ahead of the community work: it is small, built entirely from Phase 5's numbers, and it is the artefact that can be put in front of colleagues. Finding out whether any of this is right is worth more than the next feature. The handover is written for a session with no context at all, and it leads with the traps rather than the architecture - eight of them, every one already paid for. That a Playwright wrapper exits 0 on failure. That a busy lock is not a pass. That green tests are not proof the screen is right: four defects this month passed every structural check and were found by looking at a screenshot. The complete ledger now runs Phases 1 to 5 rather than 1 to 3, and includes the two Phase 4 figures that were corrected after the fact. Three outstanding-work inbox requests queued the merge-safe way: Phase 5 itself, the unvalidated state model, and the six agreed enhancements not yet assigned a phase. Co-Authored-By: Claude Opus 5 --- .../970bbb8b-4dbe-4e27-97a4-80142db94d7d.json | 14 + .../cfa44b9c-3d68-4030-b1e3-3d8f182ca3d4.json | 14 + .../ecabc51d-034a-4a68-91cd-280214aac6bf.json | 14 + ...8-26-ward-flow-phase-5-bed-availability.md | 865 ++++++++++++++++++ docs/ward-flow-complete-ledger.md | 118 ++- docs/ward-flow-phase-5-handover.md | 159 ++++ docs/ward-flow-roadmap.md | 172 ++++ 7 files changed, 1341 insertions(+), 15 deletions(-) create mode 100644 docs/outstanding-issues-inbox/970bbb8b-4dbe-4e27-97a4-80142db94d7d.json create mode 100644 docs/outstanding-issues-inbox/cfa44b9c-3d68-4030-b1e3-3d8f182ca3d4.json create mode 100644 docs/outstanding-issues-inbox/ecabc51d-034a-4a68-91cd-280214aac6bf.json create mode 100644 docs/superpowers/plans/2026-08-26-ward-flow-phase-5-bed-availability.md create mode 100644 docs/ward-flow-phase-5-handover.md create mode 100644 docs/ward-flow-roadmap.md diff --git a/docs/outstanding-issues-inbox/970bbb8b-4dbe-4e27-97a4-80142db94d7d.json b/docs/outstanding-issues-inbox/970bbb8b-4dbe-4e27-97a4-80142db94d7d.json new file mode 100644 index 000000000..57974d507 --- /dev/null +++ b/docs/outstanding-issues-inbox/970bbb8b-4dbe-4e27-97a4-80142db94d7d.json @@ -0,0 +1,14 @@ +{ + "version": 2, + "id": "970bbb8b-4dbe-4e27-97a4-80142db94d7d", + "createdOn": "2026-08-26", + "action": "add", + "payload": { + "pri": "P3", + "type": "rec", + "summary": "Ward Flow: six agreed enhancements not yet assigned to a phase", + "detail": "Ward prediction track record; 'why not here' across the whole state for one patient; a sixty-second self-driving guided tour; out-of-area ledger; 'waiting since' promoted in the priority queue; named moments on the demo clock. All accepted by the product owner 2026-08-26 and described in docs/ward-flow-roadmap.md.", + "source": "Product-owner direction, 2026-08-26", + "issueUlid": "01M0XVHQ3D875H6TZWM5JT85YW" + } +} diff --git a/docs/outstanding-issues-inbox/cfa44b9c-3d68-4030-b1e3-3d8f182ca3d4.json b/docs/outstanding-issues-inbox/cfa44b9c-3d68-4030-b1e3-3d8f182ca3d4.json new file mode 100644 index 000000000..cf667489f --- /dev/null +++ b/docs/outstanding-issues-inbox/cfa44b9c-3d68-4030-b1e3-3d8f182ca3d4.json @@ -0,0 +1,14 @@ +{ + "version": 2, + "id": "cfa44b9c-3d68-4030-b1e3-3d8f182ca3d4", + "createdOn": "2026-08-26", + "action": "add", + "payload": { + "pri": "P2", + "type": "issue", + "summary": "Ward Flow's bed-release state model is unvalidated by any ward clinician", + "detail": "predicted -> confirmed -> blocked -> released is a software model of how a bed comes free. A bed may be confirmed and blocked simultaneously in reality, and 'predicted' may compress several states a charge nurse would separate. Cheap to change while synthetic; recorded in the Phase 5 spec as D14 and as the assumption most likely to be wrong. Check before Phase 7 builds on it.", + "source": "Ward Flow Phase 5 design, 2026-08-26", + "issueUlid": "01M0XVHNB49GPWT3G522RG4YDC" + } +} diff --git a/docs/outstanding-issues-inbox/ecabc51d-034a-4a68-91cd-280214aac6bf.json b/docs/outstanding-issues-inbox/ecabc51d-034a-4a68-91cd-280214aac6bf.json new file mode 100644 index 000000000..b4b0ddf49 --- /dev/null +++ b/docs/outstanding-issues-inbox/ecabc51d-034a-4a68-91cd-280214aac6bf.json @@ -0,0 +1,14 @@ +{ + "version": 2, + "id": "ecabc51d-034a-4a68-91cd-280214aac6bf", + "createdOn": "2026-08-26", + "action": "add", + "payload": { + "pri": "P2", + "type": "task", + "summary": "Ward Flow Phase 5: bed availability becomes real - discharge lifecycle, egress board, predicted capacity, freshness everywhere", + "detail": "Binding spec: docs/superpowers/specs/2026-08-26-ward-flow-phase-5-bed-availability-design.md. Extends Phase 4's existing BedRelease concept rather than starting over. Settled direction and decisions: docs/ward-flow-roadmap.md.", + "source": "Product-owner direction, 2026-08-26", + "issueUlid": "01M0XVHM5H48HF8WJ52BHSR72A" + } +} diff --git a/docs/superpowers/plans/2026-08-26-ward-flow-phase-5-bed-availability.md b/docs/superpowers/plans/2026-08-26-ward-flow-phase-5-bed-availability.md new file mode 100644 index 000000000..3696d3b35 --- /dev/null +++ b/docs/superpowers/plans/2026-08-26-ward-flow-phase-5-bed-availability.md @@ -0,0 +1,865 @@ +# Ward Flow Phase 5 — Bed availability becomes real + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development +> (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use +> checkbox (`- [ ]`) syntax for tracking. + +**Goal:** wards record when their beds are actually coming free, and the coordinator's capacity +figure becomes a number that can be planned against for the rest of today. + +**Architecture:** extend the `BedRelease` concept Phase 4 already built — it has a unit, an expected +time, a confidence, a blocker chosen from a fixed list, and a ward-only flag event — with a state +machine, a sibling `LeaveBed` type, band derivations over today, and a discharge board that renders +them. Every number stays a pure derivation from `WardFlowState`; no screen computes its own version. + +**Tech Stack:** TypeScript 6 strict, React 19, Next.js 16 App Router, CSS modules with `@theme` +tokens, Vitest (`tests/**/*.test.ts`, `tests/**/*.dom.test.tsx`), Playwright (`tests/ui-ward-*.spec.ts`, +project `chromium-mockups`). + +**Spec:** `docs/superpowers/specs/2026-08-26-ward-flow-phase-5-bed-availability-design.md` +**Direction and settled decisions:** `docs/ward-flow-roadmap.md` + +## Global Constraints + +Every task's requirements implicitly include all of these. + +- **Never invent a legal figure.** No figure or requirement from the Mental Health Act may be cited, + paraphrased or inferred anywhere in code, copy, comment, test or fixture. +- **Synthetic data only.** No name, date of birth, medical record number, address, diagnosis, + narrative history or treatment. **Sex is the only permitted patient attribute**, and per spec D11 + neither `BedRelease` nor `LeaveBed` may carry even that. Free text counts as data. +- **Neither `BedRelease` nor `LeaveBed` may gain a field describing the departing or absent patient.** + `tests/ward-flow-reducer.test.ts`'s bed-release privacy suite asserts this against the type's own + field set. Do not weaken it; extend it. +- **`confirmedBy` is a role, never a person** — a unit or service label such as + `"NUM RPH Adult Secure"`. Never a personal name. +- **Blockers are chosen, never typed.** Every blocker value comes from `BED_RELEASE_BLOCKERS`. +- **Local and offline checks only.** Never run `verify:release`, `eval:*`, `check:supabase-project`, + `test:live`, or anything touching OpenAI, Supabase, hosted CI or a live database. +- **Read counts, never exit codes.** `node scripts/run-playwright.mjs` exits `0` on test failure and + on lock refusal alike. Quote the `N passed` line. On `DATABASE_HEAVY_RUN_ADMISSION_BUSY` or an + `EPERM … owner.json` stack trace the command did not run — retry, do not treat as a pass. +- **Every `