Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions .github/workflows/backend-uptime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,17 @@ jobs:
exit 0
fi
# Hidden database or a monitor account that is not set up: neither raise nor close a
# backend-down issue. A hidden database check must not look green (A7-01). A rate-limited
# or unset workspace check stays a warning only; the monitor-not-set-up issue covers it.
# backend-down issue. A hidden database check must not look green (A7-01), but it is
# reported after any sign-in or workspace failure has raised its issue. A rate-limited or
# unset workspace check stays a warning only; the monitor-not-set-up issue covers it.
hidden=""
if [ "$HEALTH" = "unknown" ]; then
echo "::error::Uptime check did not see the database: WARD_FLOW_UPTIME_TOKEN is missing or does not match the backend's value."
exit 1
hidden="::error::Uptime check did not see the database: WARD_FLOW_UPTIME_TOKEN is missing or does not match the backend's value."
fi
if [ "$state" = "unknown" ]; then
if [ -n "$hidden" ]; then echo "$hidden"; exit 1; fi
exit 0
fi
if [ "$state" = "unknown" ]; then exit 0; fi
if [ -z "$open" ]; then
gh label create "$LABEL" --color B60205 --description "Hosted backend not answering" --force
case "$state" in
Expand All @@ -264,4 +268,5 @@ jobs:
gh issue create --label "$LABEL" --title "Shared backend is not answering" --body "@$OWNER The hosted Ward Flow backend ($BACKEND_URL/healthz) did not answer three times in a row ($run). Shared mode will not load or save until it is back. Check the ward-flow-backend service in Railway. This issue closes itself when the backend answers again." ;;
esac
fi
if [ -n "$hidden" ]; then echo "$hidden"; fi
exit 1
8 changes: 7 additions & 1 deletion backend/ward-flow/healthz-uptime-token.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,13 @@ test("P177: the uptime workflow sends the token and warns, not alarms, when the
assert.match(workflow, /::warning::Database not checked: WARD_FLOW_UPTIME_TOKEN/);
// Hidden is unknown, not up: it must not close a real open incident.
assert.match(workflow, /WARD_FLOW_UPTIME_TOKEN is missing[^\n]*\n\s*state=unknown/);
assert.match(workflow, /= "unknown" \]; then exit 0; fi/);
// An unknown state stops before any issue; a hidden database fails the run only after a
// sign-in or workspace failure has raised its issue (D-159).
assert.match(
workflow,
/if \[ "\$state" = "unknown" \]; then\n\s*if \[ -n "\$hidden" \]; then echo "\$hidden"; exit 1; fi\n\s*exit 0\n\s*fi/,
);
assert.match(workflow, /esac\n\s*fi\n\s*if \[ -n "\$hidden" \]; then echo "\$hidden"; fi\n\s*exit 1/);
// A failed curl or malformed JSON counts as down, never as hidden.
assert.doesNotMatch(workflow, /\|\| true\)/);
assert.doesNotMatch(workflow, /\|\| echo hidden/);
Expand Down
4 changes: 2 additions & 2 deletions docs/FACTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ green. Quote a fact instead of restating it, and it updates itself when the sour
| `migration-count` | 18 | Numbered database migrations | `backend/ward-flow/migrations/` |
| `ward-route-count` | 61 | `page.tsx` routes under `/ward-flow` | `src/app/ward-flow/` |
| `app-route-count` | 65 | Pages and route handlers: the Ward Flow routes plus sign-in and the `/mockups` digest | `src/app/ward-flow/, src/app/ward-flow-sign-in/, src/app/mockups/` |
| `latest-decision` | D-158 | Newest entry in the decision log | `docs/ward-flow/decisions.md` |
| `next-decision` | D-159 | Number to use for the next decision | `docs/ward-flow/decisions.md` |
| `latest-decision` | D-159 | Newest entry in the decision log | `docs/ward-flow/decisions.md` |
| `next-decision` | D-160 | Number to use for the next decision | `docs/ward-flow/decisions.md` |
| `node-engine` | >=24.22.1 <25 | Supported Node.js range | `package.json` |
| `backend-env-vars` | 33 names, [listed below](#backend-env-vars) | Environment variables the shared backend reads | `backend/ward-flow/*.mjs` |

Expand Down
42 changes: 21 additions & 21 deletions docs/design/DESIGN-SYSTEM.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,25 +116,25 @@ The shell is the same on every page. Copy it from the master's newest screens (t

Build with `src/components/wf`. Never copy a primitive into a screen, and never write one-off `.tag`, `.chip` or `.pill` CSS. The master's Components tab shows each part in each state.

| Need | Use | Rules |
| --------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Page header | `Hero` (band), `CheckingFoot` | Title is the answer, five words at most. One strip of figures. At most one on-hero action; on phone the rest go in "…" (Q153). Eyebrow hidden on phone unless it adds facts. |
| Figures | `Stat` strip | Mono, tabular. Keep a strip on one row where it fits; let a title column shrink first (Q290, Q293). |
| A labelled state | `Badge`, `StatusGlyph` | Small tinted tag or glyph. Counts use the count badge. |
| A group of content | `Card` | Only where it is a separate object. Kit card heads keep their title whole (Q237). |
| Actions | `Button` | One filled button per row or panel; the rest are quiet. Unavailable for now: `aria-disabled` with `disabledReason`. Never usable by this desk: not shown. Unwired: "Not wired in this prototype." |
| Choosing one of a few | `choice` (segments, radio group) | Never the browser's own drop-down for a kit choice (Q319). |
| Search | `SearchField` | "/" jumps to it where a page has one search. |
| Dates and times | `DateField` (DD/MM/YYYY), `TimePresets` | Never the browser's date picker. Never default a written time to now (Q120). |
| Long lists | `ShowMoreRow` | About eight rows, then "Show 8 more" / "Show fewer". Never a small scrolling box. |
| Pop-ups and panels | `Sheet`, `Dialog`, `requestConfirm` | See section 5. Leaving with unsaved work: "Leave this page?", "Leave without saving", "Keep editing" (focus on Keep editing). Never `confirm`, `alert` or `prompt`. |
| Activity lists | `Feed`, `SinceYouLookedFold` | One timeline per record. |
| Charts | `Chart` | To scale, from existing figures only, data tokens, Geist axes. |
| Names | `FormalName` | Patients surname first as recorded ("Jenkinwood, Sarah"); staff as written ("Dr S. Chen", Q226). Always in full, wrapping. |
| Missing facts | `MissingValue` | "Not recorded" in ink-3; amber only where the gap blocks the next step. |
| Phone folds and rows | `PhoneFold`, `phoneRows` | Chip rows put the count first and slide with an edge fade. |
| Live changes | `LiveAnnouncer`, `live` | One polite region per page, batched, act-now changes only. |
| Formatting | `format.ts` (`clk`, `dur`, `durMinutes`) | Never re-implement a formatter. |
| Need | Use | Rules |
| --------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Page header | `Hero` (band), `CheckingFoot` | Title is the answer, five words at most. One strip of figures. At most one on-hero button, the next step's light button; page tools sit in one row of quick-link chips under it, which scrolls sideways on a phone (page tops v6, D-116, D-159). Anything past that goes in "…" (Q153). Eyebrow hidden on phone unless it adds facts. |
| Figures | `Stat` strip | Mono, tabular. Keep a strip on one row where it fits; let a title column shrink first (Q290, Q293). |
| A labelled state | `Badge`, `StatusGlyph` | Small tinted tag or glyph. Counts use the count badge. |
| A group of content | `Card` | Only where it is a separate object. Kit card heads keep their title whole (Q237). |
| Actions | `Button` | One filled button per row or panel; the rest are quiet. Unavailable for now: `aria-disabled` with `disabledReason`. Never usable by this desk: not shown. Unwired: "Not wired in this prototype." |
| Choosing one of a few | `choice` (segments, radio group) | Never the browser's own drop-down for a kit choice (Q319). |
| Search | `SearchField` | "/" jumps to it where a page has one search. |
| Dates and times | `DateField` (DD/MM/YYYY), `TimePresets` | Never the browser's date picker. Never default a written time to now (Q120). |
| Long lists | `ShowMoreRow` | About eight rows, then "Show 8 more" / "Show fewer". Never a small scrolling box. |
| Pop-ups and panels | `Sheet`, `Dialog`, `requestConfirm` | See section 5. Leaving with unsaved work: "Leave this page?", "Leave without saving", "Keep editing" (focus on Keep editing). Never `confirm`, `alert` or `prompt`. |
| Activity lists | `Feed`, `SinceYouLookedFold` | One timeline per record. |
| Charts | `Chart` | To scale, from existing figures only, data tokens, Geist axes. |
| Names | `FormalName` | Patients surname first as recorded ("Jenkinwood, Sarah"); staff as written ("Dr S. Chen", Q226). Always in full, wrapping. |
| Missing facts | `MissingValue` | "Not recorded" in ink-3; amber only where the gap blocks the next step. |
| Phone folds and rows | `PhoneFold`, `phoneRows` | Chip rows put the count first and slide with an edge fade. |
| Live changes | `LiveAnnouncer`, `live` | One polite region per page, batched, act-now changes only. |
| Formatting | `format.ts` (`clk`, `dur`, `durMinutes`) | Never re-implement a formatter. |

### Icons and status marks

Expand Down Expand Up @@ -249,7 +249,7 @@ The shell, tokens and kit keep Ward Flow feeling like one product. The variation
- The shell: sidebar, app bar, band hero frame, phone dock, toasts, footer.
- Tokens: no new colours, sizes, radii or fonts. Tone semantics (red is act now).
- Kit primitives: buttons, badges, choices, fields, sheets, dialogs, Show more.
- House rules: 12px floor, 40px phone controls with a 48px cover, 30px desktop tabs, no coloured side edges, one filled button per panel, one on-hero action.
- House rules: 12px floor, 40px phone controls with a 48px cover, 30px desktop tabs, no coloured side edges, one filled button per panel, at most one on-hero button plus one quick-link chip row (D-159).
- Words, names, times, safety wording and synthetic data.
- The five-second answer in the hero title.

Expand Down Expand Up @@ -282,7 +282,7 @@ Each page may take **one signature part**: a bespoke visual that shows its own d
- [ ] Tokens only; kit parts only; no one-off pills.
- [ ] Icons from the table in section 4 at 1.75 stroke; status marks from `StatusGlyph`, no typed symbols, and only where they change the next action.
- [ ] No coloured side edges; no text under 12px; phone controls 40px; desktop tabs 30px.
- [ ] One on-hero action, one filled button per panel, eight rows then Show more.
- [ ] At most one on-hero button plus one quick-link chip row (D-159), one filled button per panel, eight rows then Show more.
- [ ] Words from section 6; patient names surname first, staff names as written, both in full; times as typed.
- [ ] At most one signature part, inside the limits in section 8.
- [ ] Synthetic data only; no names or typed text in URLs, screenshots or logs.
Expand Down
Loading
Loading