diff --git a/data/outstanding-issues-snapshot.json b/data/outstanding-issues-snapshot.json index b906fa6228..629415f458 100644 --- a/data/outstanding-issues-snapshot.json +++ b/data/outstanding-issues-snapshot.json @@ -2,7 +2,7 @@ "version": "outstanding-issues-snapshot-v1", "ledger_revision": { "sha": "6085a0a59aca4c1bb9e19fb4d490fd34dec950cd", - "committed_at": "2026-08-22T20:52:39Z" + "committed_at": "2026-08-22T20:52:39+00:00" }, "counts": { "open": 73, @@ -10,7 +10,7 @@ "p2": 40, "p3": 33, "queued": 10, - "pending": 15, + "pending": 16, "resolved": 376 }, "queue": [ @@ -845,6 +845,12 @@ "summary": "Caring Contacts Phase 2B — the screens", "created_at": "2026-08-22" }, + { + "request_id": "b5d6b1be-d1c9-4739-898a-33aec4a656a5", + "action": "add", + "summary": "Document /ward-management/constellation as an intentional unlinked compatibility redirect", + "created_at": "2026-08-22" + }, { "request_id": "ba2bdfba-b1e1-4e13-83b4-8cb0f3ddc092", "action": "add", diff --git a/docs/codebase-index.md b/docs/codebase-index.md index a1434fbd21..9c62974a6a 100644 --- a/docs/codebase-index.md +++ b/docs/codebase-index.md @@ -358,7 +358,8 @@ visible reasons and a human confirms or overrides. derivations) - **Surfaces:** `ward-management-console.tsx` (command), `ward-management-modes.tsx` (mode workspaces), `ward-management-network.tsx` (network diagram), `ward-management-navigation.tsx`, - `coordinator/coordinator-screen.tsx` (Phase 3 live coordinator screen — priority queue, statewide + `src/app/ward-management/constellation/page.tsx` (retired constellation; server redirect to + `/ward-management/network`), `coordinator/coordinator-screen.tsx` (Phase 3 live coordinator screen — priority queue, statewide flow diagram, explainable shortlist), `ward/ward-screen.tsx` (Task 8: one inpatient unit's own view — `/ward-management/ward/[unitId]`; capacity confirmation, incoming-referral accept/hold/ decline, restriction notices, withdrawn referrals), `officer/officer-screen.tsx` (Task 9: the diff --git a/docs/design-system/ADOPTION.md b/docs/design-system/ADOPTION.md index 180844b750..26ede1a62e 100644 --- a/docs/design-system/ADOPTION.md +++ b/docs/design-system/ADOPTION.md @@ -358,38 +358,39 @@ Escape, and return focus). This is follow-up evidence, not a visual-baseline com `generate-design-system-adoption.mjs` discovers every production `src/app/**/page.tsx` and requires each route to appear exactly once in `adoption-contract.json`. Undeclared, missing, or multiply-owned routes fail the check. `src/app/api/**` and `src/app/mockups/**` are non-page -product exclusions; the only route-only disposition is the documented legacy document-source -redirect. Shared shell/component roots carry their own explicit `shared-shell` disposition. +product exclusions; the only route-only dispositions are the documented legacy-redirect +surfaces. Shared shell/component roots carry their own explicit `shared-shell` disposition. Registered public components: 54 Declared product roots: 94 Roots with a literal `.ckb-v2` opt-in: 1 Roots inheriting `.ckb-v2` from the global ``: 93 -Production surfaces observed under v2: 16/16 +Production surfaces observed under v2: 17/17 Dynamic `ckb-v2` constructions: 0 -Declared production page routes: 78/78 +Declared production page routes: 79/79 Source observation and contract declaration are independent. A literal `ckb-v2` on the global `` makes every production surface inherit v2, but it does not approve that adoption. The Proof column summarizes each surface's dark, forced-colours, 320px, print and browser declarations; exact statuses and evidence paths live in the manifest. Observed v2 under a compatibility declaration fails closed. A declared v2 shell also fails closed unless every proof is passed with evidence and its visual baseline is committed or explicitly not-committed (pending Linux screenshot approval). -| Surface | Disposition | Routes | Roots | Declared shell | Observed shell (mount) | Proof | Baseline | -| ---------------------------------- | --------------- | -----: | ----: | -------------- | -------------------------- | -------------- | -------------- | -| `root-shell-and-settings` | shared-shell | 3 | 6 | v2 | v2 (inherited-global-root) | passed | not-committed | -| `catalogues-forms-and-info` | owned | 23 | 23 | v2 | v2 (inherited-global-root) | passed | not-committed | -| `differentials` | owned | 7 | 7 | v2 | v2 (inherited-global-root) | passed | not-committed | -| `formulation` | owned | 6 | 6 | v2 | v2 (inherited-global-root) | passed | not-committed | -| `specifiers` | owned | 6 | 6 | v2 | v2 (inherited-global-root) | passed | not-committed | -| `therapy-compass` | owned | 9 | 10 | v2 | v2 (inherited-global-root) | passed | not-committed | -| `documents-and-source-evidence` | owned | 3 | 4 | v2 | v2 (inherited-global-root) | passed | not-committed | -| `documents-source-legacy-redirect` | legacy-redirect | 1 | 0 | v2 | v2 (inherited-global-root) | not-applicable | not-applicable | -| `favourites` | owned | 1 | 1 | v2 | v2 (inherited-global-root) | passed | not-committed | -| `tools-and-calculators` | owned | 3 | 3 | v2 | v2 (inherited-global-root) | passed | not-committed | -| `caring-contacts-workspace` | owned | 1 | 1 | v2 | v2 (inherited-global-root) | passed | not-committed | -| `ward-management` | owned | 12 | 20 | v2 | v2 (inherited-global-root) | passed | not-committed | -| `privacy-safety-and-reference` | owned | 3 | 3 | v2 | v2 (inherited-global-root) | passed | not-committed | -| `search-results-shared` | shared-shell | 0 | 1 | v2 | v2 (inherited-global-root) | passed | not-committed | -| `answers-shared` | shared-shell | 0 | 2 | v2 | v2 (inherited-global-root) | passed | not-committed | -| `source-preview-shared` | shared-shell | 0 | 1 | v2 | v2 (inherited-global-root) | passed | not-committed | +| Surface | Disposition | Routes | Roots | Declared shell | Observed shell (mount) | Proof | Baseline | +| ----------------------------------------------- | --------------- | -----: | ----: | -------------- | -------------------------- | -------------- | -------------- | +| `root-shell-and-settings` | shared-shell | 3 | 6 | v2 | v2 (inherited-global-root) | passed | not-committed | +| `catalogues-forms-and-info` | owned | 23 | 23 | v2 | v2 (inherited-global-root) | passed | not-committed | +| `differentials` | owned | 7 | 7 | v2 | v2 (inherited-global-root) | passed | not-committed | +| `formulation` | owned | 6 | 6 | v2 | v2 (inherited-global-root) | passed | not-committed | +| `specifiers` | owned | 6 | 6 | v2 | v2 (inherited-global-root) | passed | not-committed | +| `therapy-compass` | owned | 9 | 10 | v2 | v2 (inherited-global-root) | passed | not-committed | +| `documents-and-source-evidence` | owned | 3 | 4 | v2 | v2 (inherited-global-root) | passed | not-committed | +| `documents-source-legacy-redirect` | legacy-redirect | 1 | 0 | v2 | v2 (inherited-global-root) | not-applicable | not-applicable | +| `ward-management-constellation-legacy-redirect` | legacy-redirect | 1 | 0 | v2 | v2 (inherited-global-root) | not-applicable | not-applicable | +| `favourites` | owned | 1 | 1 | v2 | v2 (inherited-global-root) | passed | not-committed | +| `tools-and-calculators` | owned | 3 | 3 | v2 | v2 (inherited-global-root) | passed | not-committed | +| `caring-contacts-workspace` | owned | 1 | 1 | v2 | v2 (inherited-global-root) | passed | not-committed | +| `ward-management` | owned | 12 | 20 | v2 | v2 (inherited-global-root) | passed | not-committed | +| `privacy-safety-and-reference` | owned | 3 | 3 | v2 | v2 (inherited-global-root) | passed | not-committed | +| `search-results-shared` | shared-shell | 0 | 1 | v2 | v2 (inherited-global-root) | passed | not-committed | +| `answers-shared` | shared-shell | 0 | 2 | v2 | v2 (inherited-global-root) | passed | not-committed | +| `source-preview-shared` | shared-shell | 0 | 1 | v2 | v2 (inherited-global-root) | passed | not-committed | diff --git a/docs/design-system/adoption-contract.json b/docs/design-system/adoption-contract.json index 67aaa49410..6e8e10f954 100644 --- a/docs/design-system/adoption-contract.json +++ b/docs/design-system/adoption-contract.json @@ -10,6 +10,10 @@ "documents-source-legacy-redirect": { "route": "src/app/(search-app)/documents/source/page.tsx", "kind": "next-redirect-only" + }, + "ward-management-constellation-legacy-redirect": { + "route": "src/app/ward-management/constellation/page.tsx", + "kind": "next-redirect-only" } }, "proofEvidencePolicy": { @@ -427,6 +431,43 @@ "sanctionedSpecialPatterns": [], "documentedDisposition": "Legacy source URLs validate the document id and redirect to the canonical /documents/[id] route; they do not own a visual surface." }, + { + "id": "ward-management-constellation-legacy-redirect", + "disposition": "legacy-redirect", + "routes": ["src/app/ward-management/constellation/page.tsx"], + "routeRoots": false, + "roots": [], + "permittedComponentFamilies": [], + "expectedShellState": "v2", + "proof": { + "dark": { + "status": "not-applicable", + "evidence": [] + }, + "forcedColours": { + "status": "not-applicable", + "evidence": [] + }, + "compact320": { + "status": "not-applicable", + "evidence": [] + }, + "print": { + "status": "not-applicable", + "evidence": [] + }, + "browser": { + "status": "not-applicable", + "evidence": [] + } + }, + "baseline": { + "status": "not-applicable", + "files": [] + }, + "sanctionedSpecialPatterns": [], + "documentedDisposition": "Retired Phase 1 constellation URLs redirect to /ward-management/network; they do not own a visual surface." + }, { "id": "favourites", "disposition": "owned", diff --git a/docs/design-system/adoption-manifest.json b/docs/design-system/adoption-manifest.json index 89e2658894..3cdb56ae8f 100644 --- a/docs/design-system/adoption-manifest.json +++ b/docs/design-system/adoption-manifest.json @@ -21,6 +21,10 @@ "documents-source-legacy-redirect": { "route": "src/app/(search-app)/documents/source/page.tsx", "kind": "next-redirect-only" + }, + "ward-management-constellation-legacy-redirect": { + "route": "src/app/ward-management/constellation/page.tsx", + "kind": "next-redirect-only" } }, "evidence": { @@ -3170,6 +3174,63 @@ "sanctionedSpecialPatterns": [], "roots": [] }, + { + "id": "ward-management-constellation-legacy-redirect", + "disposition": "legacy-redirect", + "documentedDisposition": "Retired Phase 1 constellation URLs redirect to /ward-management/network; they do not own a visual surface.", + "routes": ["src/app/ward-management/constellation/page.tsx"], + "routeRoots": false, + "proofApplicability": "not-applicable", + "nonVisualRoute": { + "contract": { + "route": "src/app/ward-management/constellation/page.tsx", + "kind": "next-redirect-only" + }, + "source": { + "importsNextRedirect": true, + "hasDefaultFunction": true, + "hasJsx": false, + "terminalOutcomes": ["redirect"], + "redirectOnly": true + }, + "topologyMatches": true + }, + "declaredShellState": "v2", + "observedShellState": "v2", + "v2ShellMounted": true, + "v2MountMode": "inherited-global-root", + "inheritedFrom": "src/app/layout.tsx", + "directV2MountFiles": [], + "proof": { + "browser": { + "status": "not-applicable", + "evidence": [] + }, + "compact320": { + "status": "not-applicable", + "evidence": [] + }, + "dark": { + "status": "not-applicable", + "evidence": [] + }, + "forcedColours": { + "status": "not-applicable", + "evidence": [] + }, + "print": { + "status": "not-applicable", + "evidence": [] + } + }, + "baseline": { + "status": "not-applicable", + "files": [] + }, + "permittedComponentFamilies": [], + "sanctionedSpecialPatterns": [], + "roots": [] + }, { "id": "favourites", "disposition": "owned", @@ -3948,6 +4009,7 @@ "src/app/reference/colour-coding/page.tsx", "src/app/safety-plan/page.tsx", "src/app/ward-management/capacity/page.tsx", + "src/app/ward-management/constellation/page.tsx", "src/app/ward-management/ed/[edId]/page.tsx", "src/app/ward-management/exceptions/page.tsx", "src/app/ward-management/governance/page.tsx", @@ -4028,6 +4090,7 @@ "src/app/reference/colour-coding/page.tsx", "src/app/safety-plan/page.tsx", "src/app/ward-management/capacity/page.tsx", + "src/app/ward-management/constellation/page.tsx", "src/app/ward-management/ed/[edId]/page.tsx", "src/app/ward-management/exceptions/page.tsx", "src/app/ward-management/governance/page.tsx", @@ -4048,15 +4111,15 @@ "literalCkbV2RootCount": 1, "inheritedCkbV2RootCount": 93, "dynamicCkbV2RootCount": 0, - "v2MountedSurfaceCount": 16, - "declaredV2SurfaceCount": 16 + "v2MountedSurfaceCount": 17, + "declaredV2SurfaceCount": 17 }, "summary": { "registeredComponentCount": 54, "previewCount": 54, "productImportedComponentCount": 34, "rootCount": 94, - "productionRouteCount": 78, - "nextUiEntryCount": 139 + "productionRouteCount": 79, + "nextUiEntryCount": 140 } } diff --git a/docs/outstanding-issues-inbox/b5d6b1be-d1c9-4739-898a-33aec4a656a5.json b/docs/outstanding-issues-inbox/b5d6b1be-d1c9-4739-898a-33aec4a656a5.json new file mode 100644 index 0000000000..5472d072a2 --- /dev/null +++ b/docs/outstanding-issues-inbox/b5d6b1be-d1c9-4739-898a-33aec4a656a5.json @@ -0,0 +1,14 @@ +{ + "version": 2, + "id": "b5d6b1be-d1c9-4739-898a-33aec4a656a5", + "createdOn": "2026-08-22", + "action": "add", + "payload": { + "pri": "P3", + "type": "issue", + "summary": "Document /ward-management/constellation as an intentional unlinked compatibility redirect", + "detail": "PR #2303 restored /ward-management/constellation as a server redirect to /ward-management/network so live-main bookmarks do not 404 after Phase 3 retired the constellation command view. The route is on the reachability allowlist because in-app navigation uses the remaining rail modes and must not send readers through the redirect. STOP: do not add inbound nav to this route, and do not treat it as a visual Ward Flow surface; it is a bookmark/deep-link backstop only. Related: tests/route-reachability.test.ts REACHABILITY_ALLOWLIST, src/app/ward-management/constellation/page.tsx, docs/design-system/adoption-contract.json ward-management-constellation-legacy-redirect.", + "source": "PR #2303 CodeRabbit review; AGENTS.md new-route checklist requiring an /issues note for allowlisted orphans", + "issueUlid": "01M0NKTEQJHXY7QJXR82WCBXBT" + } +} diff --git a/docs/site-map.md b/docs/site-map.md index 5d1abe1408..cd801c6cdb 100644 --- a/docs/site-map.md +++ b/docs/site-map.md @@ -59,15 +59,16 @@ This file is generated by `npm run docs:update` (or `npm run sitemap:update` dir - `/tools` - Clinical tools and applications launcher directory. Source: `src/app/(search-app)/tools/page.tsx`. - `/ward-management` - Statewide psychiatry ward demand, bed capacity, and patient flow console. Source: `src/app/ward-management/page.tsx`. - `/ward-management/capacity` - Ward bed availability, unit occupancy, and staffing capacity. Source: `src/app/ward-management/capacity/page.tsx`. -- `/ward-management/ed/[edId]` - Route discovered from app directory Source: `src/app/ward-management/ed/[edId]/page.tsx`. +- `/ward-management/constellation` - Compatibility redirect to `/ward-management/network`. Phase 2 retired the constellation command view. Source: `src/app/ward-management/constellation/page.tsx`. +- `/ward-management/ed/[edId]` - Synthetic emergency-department role screen for one origin department. Source: `src/app/ward-management/ed/[edId]/page.tsx`. - `/ward-management/exceptions` - Patient flow exceptions, delays, and escalation alerts. Source: `src/app/ward-management/exceptions/page.tsx`. - `/ward-management/governance` - Ward coordination governance, compliance, and audit log. Source: `src/app/ward-management/governance/page.tsx`. - `/ward-management/movements` - Scheduled and completed patient transfers and bed movements. Source: `src/app/ward-management/movements/page.tsx`. - `/ward-management/network` - Psychiatric bed network status and regional catchment map. Source: `src/app/ward-management/network/page.tsx`. - `/ward-management/queue` - Priority referral queue and triage waiting list. Source: `src/app/ward-management/queue/page.tsx`. - `/ward-management/transport` - Patient inter-hospital transfer and transport logistics. Source: `src/app/ward-management/transport/page.tsx`. -- `/ward-management/transport/officer` - Route discovered from app directory Source: `src/app/ward-management/transport/officer/page.tsx`. -- `/ward-management/ward/[unitId]` - Route discovered from app directory Source: `src/app/ward-management/ward/[unitId]/page.tsx`. +- `/ward-management/transport/officer` - Synthetic transport-officer phone screen for in-flight jobs. Source: `src/app/ward-management/transport/officer/page.tsx`. +- `/ward-management/ward/[unitId]` - Synthetic ward-manager screen for one inpatient unit. Source: `src/app/ward-management/ward/[unitId]/page.tsx`. ## Mode/query routes @@ -1347,6 +1348,7 @@ This file is generated by `npm run docs:update` (or `npm run sitemap:update` dir - `/services` - Redirects to `/?mode=services`. Source: `src/app/(search-app)/services/page.tsx`. - `/specifiers` - Redirects to `/?mode=specifiers`. Source: `src/app/(search-app)/specifiers/page.tsx`. - `/therapy-compass` - Redirects to `/?mode=therapy-compass`. Source: `src/app/(search-app)/therapy-compass/page.tsx`. +- `/ward-management/constellation` - Redirects to `/ward-management/network`. Source: `src/app/ward-management/constellation/page.tsx`. ## Known caveats and stale-path flags diff --git a/docs/ward-flow-phase-handoff.md b/docs/ward-flow-phase-handoff.md index b48cca5a8f..59c497fe88 100644 --- a/docs/ward-flow-phase-handoff.md +++ b/docs/ward-flow-phase-handoff.md @@ -13,15 +13,14 @@ then the plan for the phase being executed. ## Where the build is -Branch `codex/ward-management-design`, worktree -`C:/Users/joshs/.codex/worktrees/ward-management-design/Database`. Nothing pushed. No PR. - -| Phase | Plan | State | -| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -| 1 — the model | [`plans/2026-08-18-ward-flow-phase-1-model.md`](./superpowers/plans/2026-08-18-ward-flow-phase-1-model.md) | **Complete.** All 8 tasks reviewed; whole-branch review clean after one fix wave | -| 2 — coordinator screen | not written | Next to plan | -| 3 — ED, ward and transport officer screens | not written | | -| 4 — specialist boards and escalation | not written | | +Branch `codex/ward-management-design` (PR #2289). Phase 3 is the successor of the #2140 squash on main; constellation remains only as a redirect. + +| Phase | Plan | State | +| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- | +| 1 — the model | [`plans/2026-08-18-ward-flow-phase-1-model.md`](./superpowers/plans/2026-08-18-ward-flow-phase-1-model.md) | **Complete.** Landed on main via PR #2140; Phase 3 continues that lineage on PR #2289 | +| 2 — coordinator screen | [`plans/2026-08-18-ward-flow-phase-2-coordinator-screen.md`](./superpowers/plans/2026-08-18-ward-flow-phase-2-coordinator-screen.md) | **Complete.** Live coordinator plus retired constellation (redirect to network) | +| 3 — ED, ward and transport officer screens | [`plans/2026-08-19-ward-flow-phase-3-role-screens.md`](./superpowers/plans/2026-08-19-ward-flow-phase-3-role-screens.md) | **Complete on this branch.** Live reducer, Form 1A→3B, role screens | +| 4 — specialist boards and escalation | not written | Not started | Phase boundaries are in §18 of the spec. diff --git a/docs/ward-management-mode-map.md b/docs/ward-management-mode-map.md index d8779e5a17..41c15eb1ba 100644 --- a/docs/ward-management-mode-map.md +++ b/docs/ward-management-mode-map.md @@ -7,7 +7,9 @@ That design has not been built yet — Phase 2 is what actually retires these mo document still describes the routes as they exist today. Read the design spec for where the product is headed; read this document for what is currently live. -**Phase 2 update (Task 9):** Constellation (`/ward-management/constellation`) is retired. Command +**Phase 2 update (Task 9):** Constellation (`/ward-management/constellation`) is retired. The +route remains as a server `redirect()` to `/ward-management/network` so live-main bookmarks do +not 404. Command is rebuilt as the coordinator screen (`CoordinatorScreen`) — priority queue, statewide flow diagram and explainable shortlist in one view — and absorbs the working-surface role Constellation used to carry; the table below is corrected to drop the Constellation row. The eight remaining diff --git a/scripts/generate-design-system-adoption.mjs b/scripts/generate-design-system-adoption.mjs index 188d78eb76..45ac325f06 100644 --- a/scripts/generate-design-system-adoption.mjs +++ b/scripts/generate-design-system-adoption.mjs @@ -81,6 +81,10 @@ const CANONICAL_NON_VISUAL_ROUTES = Object.freeze({ route: "src/app/(search-app)/documents/source/page.tsx", kind: "next-redirect-only", }, + "ward-management-constellation-legacy-redirect": { + route: "src/app/ward-management/constellation/page.tsx", + kind: "next-redirect-only", + }, }); const toPosix = (value) => value.split(path.sep).join("/"); @@ -1331,8 +1335,8 @@ export function manifestSections(manifest) { "`generate-design-system-adoption.mjs` discovers every production `src/app/**/page.tsx` and", "requires each route to appear exactly once in `adoption-contract.json`. Undeclared, missing, or", "multiply-owned routes fail the check. `src/app/api/**` and `src/app/mockups/**` are non-page", - "product exclusions; the only route-only disposition is the documented legacy document-source", - "redirect. Shared shell/component roots carry their own explicit `shared-shell` disposition.", + "product exclusions; the only route-only dispositions are the documented legacy-redirect", + "surfaces. Shared shell/component roots carry their own explicit `shared-shell` disposition.", "", `Registered public components: ${manifest.summary.registeredComponentCount}`, `Declared product roots: ${manifest.summary.rootCount}`, @@ -1626,7 +1630,7 @@ export function checkAdoptionManifest(manifest, { root = ROOT, trackedFiles = tr if (contract.defaultProofApplicability !== CANONICAL_DEFAULT_PROOF_APPLICABILITY) failures.push("default proof applicability must remain required"); if (JSON.stringify(contract.nonVisualRouteContracts) !== JSON.stringify(CANONICAL_NON_VISUAL_ROUTES)) - failures.push("non-visual route contracts drifted from the canonical redirect-only route"); + failures.push("non-visual route contracts drifted from the canonical redirect-only routes"); if (JSON.stringify(contract.proofEvidencePolicy) !== JSON.stringify(CANONICAL_PROOF_EVIDENCE_POLICY)) failures.push("proof evidence path policy drifted from the canonical contract"); if (JSON.stringify(contract.visualBaselinePolicy) !== JSON.stringify(CANONICAL_VISUAL_BASELINE_POLICY)) diff --git a/scripts/generate-site-map.ts b/scripts/generate-site-map.ts index f388af7966..ef97f97113 100644 --- a/scripts/generate-site-map.ts +++ b/scripts/generate-site-map.ts @@ -80,6 +80,7 @@ const documentedRedirectTargets: Record = { // Pinned because the page forwards the incoming query string, so its // `redirect()` argument is a template literal the regex above cannot read. "/dictionary/browse": "/dictionary/search", + "/ward-management/constellation": "/ward-management/network", }; const routeDescriptions: Record = { @@ -150,7 +151,9 @@ const routeDescriptions: Record = { "/tools": "Clinical tools and applications launcher directory.", "/ward-management": "Statewide psychiatry ward demand, bed capacity, and patient flow console.", "/ward-management/capacity": "Ward bed availability, unit occupancy, and staffing capacity.", - "/ward-management/constellation": "Statewide psychiatric hospital network constellation view.", + "/ward-management/constellation": + "Compatibility redirect to `/ward-management/network`. Phase 2 retired the constellation command view.", + "/ward-management/ed/[edId]": "Synthetic emergency-department role screen for one origin department.", "/ward-management/exceptions": "Patient flow exceptions, delays, and escalation alerts.", "/ward-management/governance": "Ward coordination governance, compliance, and audit log.", "/ward-management/movements": "Scheduled and completed patient transfers and bed movements.", @@ -158,6 +161,8 @@ const routeDescriptions: Record = { "/ward-management/patients/[patientId]": "Synthetic patient placement and transfer trajectory detail.", "/ward-management/queue": "Priority referral queue and triage waiting list.", "/ward-management/transport": "Patient inter-hospital transfer and transport logistics.", + "/ward-management/transport/officer": "Synthetic transport-officer phone screen for in-flight jobs.", + "/ward-management/ward/[unitId]": "Synthetic ward-manager screen for one inpatient unit.", }; const publicRouteHandlerDescriptions: Record = { diff --git a/src/app/ward-management/constellation/page.tsx b/src/app/ward-management/constellation/page.tsx new file mode 100644 index 0000000000..5e22b91530 --- /dev/null +++ b/src/app/ward-management/constellation/page.tsx @@ -0,0 +1,10 @@ +import { redirect } from "next/navigation"; + +/** + * Phase 2 retired the constellation command view into the coordinator screen and + * the network diagram. The route stays as a bookmark/deep-link backstop so the + * live main URL does not 404 after Phase 3 lands. + */ +export default function WardConstellationRedirect() { + redirect("/ward-management/network"); +} diff --git a/src/components/ward-management/coordinator/coordinator.module.css b/src/components/ward-management/coordinator/coordinator.module.css index 1c0f70f827..d4df141a41 100644 --- a/src/components/ward-management/coordinator/coordinator.module.css +++ b/src/components/ward-management/coordinator/coordinator.module.css @@ -6,7 +6,7 @@ --co-space-12: 0.75rem; --co-space-14: 0.875rem; --co-space-20: 1.25rem; - --co-space-48: 3rem; + --co-space-48: var(--spacing-tap); /* * Task 7: the phone-pinned referral bar's own vertical footprint, computed rather than * measured — one `--co-space-48` button row, `--co-shortlist-bar-pad-y` above it, at least the diff --git a/src/components/ward-management/ed/ed.module.css b/src/components/ward-management/ed/ed.module.css index e392248f8b..d0e3e2ab8c 100644 --- a/src/components/ward-management/ed/ed.module.css +++ b/src/components/ward-management/ed/ed.module.css @@ -13,7 +13,7 @@ --ed-space-14: 0.875rem; --ed-space-16: 1rem; --ed-space-20: 1.25rem; - --ed-space-48: 3rem; + --ed-space-48: var(--spacing-tap); --ed-leading-body: 1.4; --ed-leading-prose: 1.5; display: grid; diff --git a/src/components/ward-management/officer/officer.module.css b/src/components/ward-management/officer/officer.module.css index 00b5cff781..5348332307 100644 --- a/src/components/ward-management/officer/officer.module.css +++ b/src/components/ward-management/officer/officer.module.css @@ -12,7 +12,7 @@ --of-space-14: 0.875rem; --of-space-16: 1rem; --of-space-20: 1.25rem; - --of-space-48: 3rem; + --of-space-48: var(--spacing-tap); --of-leading-body: 1.4; --of-leading-prose: 1.5; /* diff --git a/src/components/ward-management/tracker/live-tracker.module.css b/src/components/ward-management/tracker/live-tracker.module.css index 633eea0499..439224bea3 100644 --- a/src/components/ward-management/tracker/live-tracker.module.css +++ b/src/components/ward-management/tracker/live-tracker.module.css @@ -12,7 +12,7 @@ --tr-space-14: 0.875rem; --tr-space-16: 1rem; --tr-space-20: 1.25rem; - --tr-space-48: 3rem; + --tr-space-48: var(--spacing-tap); --tr-leading-body: 1.4; --tr-leading-prose: 1.5; display: grid; diff --git a/src/components/ward-management/ward-management-modes.module.css b/src/components/ward-management/ward-management-modes.module.css index 7bef625e38..31efd948b9 100644 --- a/src/components/ward-management/ward-management-modes.module.css +++ b/src/components/ward-management/ward-management-modes.module.css @@ -109,7 +109,7 @@ .roleSelect { display: flex; - height: 2.5rem; + height: var(--spacing-tap); align-items: center; gap: var(--ward-space-8); border: 0.0625rem solid var(--ward-border); @@ -436,7 +436,7 @@ .primaryButton, .secondaryButton { display: inline-flex; - min-height: 2.75rem; + min-height: var(--spacing-tap); align-items: center; justify-content: center; gap: var(--ward-space-8); @@ -533,7 +533,7 @@ .bedStates span { display: grid; - min-height: 2.75rem; + min-height: var(--spacing-tap); place-items: center; border: 0.0625rem solid var(--ward-border); border-radius: var(--radius-sm); @@ -770,16 +770,16 @@ } .roleSelect { - width: 2.75rem; + width: var(--spacing-tap); padding: 0; justify-content: center; } .roleSelect select { position: absolute; - width: 2.75rem; + width: var(--spacing-tap); min-width: 0; - height: 2.75rem; + height: var(--spacing-tap); opacity: 0; } diff --git a/src/components/ward-management/ward-management-modes.tsx b/src/components/ward-management/ward-management-modes.tsx index a0f8978622..b63a12659a 100644 --- a/src/components/ward-management/ward-management-modes.tsx +++ b/src/components/ward-management/ward-management-modes.tsx @@ -298,13 +298,13 @@ function QueueView({ role }: { role: WardRole }) { - - - - - - - + + + + + + + @@ -383,11 +383,11 @@ function CapacityView() {
PatientPriorityWaitNeedHealth serviceBlockerTop candidatePatientPriorityWaitNeedHealth serviceBlockerTop candidate
- - - - - + + + + + diff --git a/src/components/ward-management/ward-management-network.module.css b/src/components/ward-management/ward-management-network.module.css index 7fc95818ec..2a61d6f063 100644 --- a/src/components/ward-management/ward-management-network.module.css +++ b/src/components/ward-management/ward-management-network.module.css @@ -376,7 +376,10 @@ box-shadow: var(--e1); } -.serviceCard[aria-pressed="true"] { +/* :not(:focus-visible) so the global focus ring still wins while selected - + `:where(...):focus-visible` contributes zero specificity, so an + unconditional selection outline would otherwise always beat it. */ +.serviceCard[aria-pressed="true"]:not(:focus-visible) { outline: 0.125rem solid var(--net-blue); outline-offset: 0.0625rem; } @@ -751,3 +754,15 @@ transition: none !important; } } + +/* High Contrast Mode. Selection and routing state on this screen is safety + information (which service a patient is routed to), and under forced-colors + the accent hues these states rely on are discarded. Mirrors the blocks the + three sibling ward stylesheets already carry. */ +@media (forced-colors: active) { + .serviceCard[data-routed="true"], + .serviceCard[aria-pressed="true"]:not(:focus-visible), + .queueRow[aria-pressed="true"] { + border: 0.125rem solid Highlight; + } +} diff --git a/src/components/ward-management/ward-management.module.css b/src/components/ward-management/ward-management.module.css index 2cd68a70b9..bf1b09cf2b 100644 --- a/src/components/ward-management/ward-management.module.css +++ b/src/components/ward-management/ward-management.module.css @@ -318,7 +318,7 @@ .confirmButton, .confirmedButton { display: inline-flex; - min-height: 2.75rem; + min-height: var(--spacing-tap); align-items: center; justify-content: center; gap: var(--ward-space-8); @@ -474,7 +474,7 @@ } .workspaceTabs button { - min-height: 2.75rem; + min-height: var(--spacing-tap); flex: 0 0 auto; border: 0.0625rem solid transparent; border-radius: var(--radius-md); diff --git a/src/components/ward-management/ward-role-switcher.module.css b/src/components/ward-management/ward-role-switcher.module.css index 08fa0abb84..0613056e7f 100644 --- a/src/components/ward-management/ward-role-switcher.module.css +++ b/src/components/ward-management/ward-role-switcher.module.css @@ -22,7 +22,7 @@ --rs-space-10: 0.625rem; --rs-space-12: 0.75rem; --rs-space-16: 1rem; - --rs-tap: 3rem; + --rs-tap: var(--spacing-tap); --rs-menu-width: 16rem; --rs-menu-gap: var(--rs-space-8); --rs-z-menu: var(--z-popover); diff --git a/src/components/ward-management/ward/ward.module.css b/src/components/ward-management/ward/ward.module.css index c84bc58d86..bf7716776e 100644 --- a/src/components/ward-management/ward/ward.module.css +++ b/src/components/ward-management/ward/ward.module.css @@ -15,7 +15,7 @@ --wd-space-14: 0.875rem; --wd-space-16: 1rem; --wd-space-20: 1.25rem; - --wd-space-48: 3rem; + --wd-space-48: var(--spacing-tap); --wd-leading-body: 1.4; --wd-leading-prose: 1.5; display: grid; diff --git a/tests/design-system-adoption.test.ts b/tests/design-system-adoption.test.ts index dd8bc2fef7..a2ab665dd7 100644 --- a/tests/design-system-adoption.test.ts +++ b/tests/design-system-adoption.test.ts @@ -33,6 +33,17 @@ function writeFixtureFile(fixtureRoot: string, relativePath: string, content: st fs.writeFileSync(absolutePath, content); } +const NON_VISUAL_REDIRECT_PAGES = [ + "src/app/(search-app)/documents/source/page.tsx", + "src/app/ward-management/constellation/page.tsx", +] as const; + +function writeNonVisualRedirectFixtures(fixtureRoot: string) { + for (const relativePath of NON_VISUAL_REDIRECT_PAGES) { + writeFixtureFile(fixtureRoot, relativePath, read(relativePath)); + } +} + function createCheckerFixture() { const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), "design-system-adoption-check-")); writeFixtureFile( @@ -396,6 +407,15 @@ describe("design-system adoption manifest", () => { ).toBe(true); }); + it("recognises the retired constellation route as redirect-only", () => { + expect( + analyzeNextRedirectOnlyRoute( + "src/app/ward-management/constellation/page.tsx", + read("src/app/ward-management/constellation/page.tsx"), + ).redirectOnly, + ).toBe(true); + }); + it("fails the adoption contract when a declared root constructs ckb-v2", () => { const current = JSON.parse(read("docs/design-system/adoption-manifest.json")); const manifest = { @@ -442,15 +462,35 @@ describe("design-system adoption manifest", () => { const manifest = { ...current, surfaces: current.surfaces.map((surface: { id: string }) => - surface.id === "documents-source-legacy-redirect" ? { ...surface, documentedDisposition: null } : surface, + surface.id === "documents-source-legacy-redirect" || + surface.id === "ward-management-constellation-legacy-redirect" + ? { ...surface, documentedDisposition: null } + : surface, ), }; - expect(checkAdoptionManifest(manifest)).toContain( - "documents-source-legacy-redirect legacy-redirect disposition is undocumented", + const failures = checkAdoptionManifest(manifest); + expect(failures).toContain("documents-source-legacy-redirect legacy-redirect disposition is undocumented"); + expect(failures).toContain( + "ward-management-constellation-legacy-redirect legacy-redirect disposition is undocumented", ); }); + it("models the retired constellation route as a non-visual legacy redirect", () => { + const manifest = JSON.parse(read("docs/design-system/adoption-manifest.json")); + const redirect = manifest.surfaces.find( + (surface: { id: string }) => surface.id === "ward-management-constellation-legacy-redirect", + ); + const owned = manifest.surfaces.find((surface: { id: string }) => surface.id === "ward-management"); + + expect(redirect).toMatchObject({ + disposition: "legacy-redirect", + proofApplicability: "not-applicable", + routes: ["src/app/ward-management/constellation/page.tsx"], + }); + expect(owned.routes).not.toContain("src/app/ward-management/constellation/page.tsx"); + }); + it("does not let a visual catalogue opt out by relabelling itself as a legacy redirect", () => { const current = JSON.parse(read("docs/design-system/adoption-manifest.json")); const catalogue = current.surfaces.find((surface: { id: string }) => surface.id === "catalogues-forms-and-info"); @@ -561,11 +601,7 @@ describe("design-system adoption manifest", () => { const fixtureRoot = createCheckerFixture(); try { writeFixtureFile(fixtureRoot, "tests/proof.test.ts"); - writeFixtureFile( - fixtureRoot, - "src/app/(search-app)/documents/source/page.tsx", - read("src/app/(search-app)/documents/source/page.tsx"), - ); + writeNonVisualRedirectFixtures(fixtureRoot); initialiseCandidateRepository(fixtureRoot); setCurrentAwaitingValues(fixtureRoot, ""); const baselineSet = writeBaselineSet(fixtureRoot); @@ -1238,10 +1274,15 @@ describe("design-system adoption manifest", () => { ["committed", "not-committed", "not-applicable"].includes(surface.baseline.status), ), ).toBe(true); - // 78 = 59 + 6 + 12 + 1: the base routes, the six mode-search routes, the - // twelve-route Ward Flow prototype, and the Caring Contacts workspace. This is - // a census, so a route nobody intended to add still fails the contract. - expect(manifest.routeCoverage.discovered).toHaveLength(78); + // 79 = 59 + 6 + 13 + 1: the 59 production pages that preceded both changes, + // the six `/search` routes home consolidation split out of the bare paths, + // the thirteen-route Ward Flow synthetic patient-flow prototype (mode home, + // eight remaining workspace routes, ED/ward/officer role screens, the per-patient + // detail route, and the retired constellation redirect), and the Caring Contacts + // workspace. Redirect stubs keep legacy deep links resolving and still count as + // declared routes. This is a census, so a route nobody intended to add still + // fails the contract. + expect(manifest.routeCoverage.discovered).toHaveLength(79); expect(manifest.routeCoverage.declared).toEqual(manifest.routeCoverage.discovered); expect(manifest.routeCoverage.undeclared).toEqual([]); expect(manifest.routeCoverage.missing).toEqual([]); diff --git a/tests/route-reachability.test.ts b/tests/route-reachability.test.ts index 4cd2dd3aca..ec517f6f8d 100644 --- a/tests/route-reachability.test.ts +++ b/tests/route-reachability.test.ts @@ -42,6 +42,10 @@ const REACHABILITY_ALLOWLIST = new Map([ "/dictionary/browse", "Retired half of the merged Dictionary catalogue. It redirects to /dictionary/search (proxy fast path plus a page backstop), so in-app navigation deliberately links the surviving route directly rather than routing readers through a redirect.", ], + [ + "/ward-management/constellation", + "Retired Phase 1 constellation view. It redirects to /ward-management/network so live-main bookmarks keep working; in-app navigation uses the eight remaining rail modes and does not send readers through the redirect.", + ], ]); function isMockupPath(relPosix: string) { diff --git a/tests/ward-management.test.ts b/tests/ward-management.test.ts index b8c34cf4ba..98c187fab1 100644 --- a/tests/ward-management.test.ts +++ b/tests/ward-management.test.ts @@ -7,6 +7,8 @@ import { movementById, wardMovements } from "../src/components/ward-management/w import { NOW_ANCHOR, allUnits } from "../src/components/ward-management/ward-sites"; import { toolCatalogRecordById } from "../src/lib/tools-catalog"; +const modesSource = readFileSync("src/components/ward-management/ward-management-modes.tsx", "utf8"); + /** * The mode strip renders one literal `` per view so * `tests/route-reachability.test.ts` can find the hrefs by static AST scan. Reading the @@ -23,6 +25,12 @@ function routeFileFor(href: string) { } describe("Ward Flow synthetic prototype", () => { + it("declares every queue and capacity header as a column header", () => { + const thTags = [...modesSource.matchAll(/]*)?>/g)].map((match) => match[0]); + expect(thTags).toHaveLength(12); + expect(thTags.every((tag) => tag.includes('scope="col"'))).toBe(true); + }); + it("keeps the production route reachable from the Tools catalogue", () => { expect(toolCatalogRecordById("ward-management").href).toBe("/ward-management"); });
UnitHealth serviceCapability cueFive bed statesFreshnessUnitHealth serviceCapability cueFive bed statesFreshness