Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
2bac3fb
docs(caring-contacts): correct the retired-branch records, close the …
BigSimmo Aug 24, 2026
ac9dd3b
docs(caring-contacts): correct the self-contradicting handoff, and re…
BigSimmo Aug 24, 2026
d0b2880
docs(caring-contacts): both mutation proofs run, and the Phase 2B plan
BigSimmo Aug 24, 2026
816284a
docs(caring-contacts): record the owner's approval of all thirteen co…
BigSimmo Aug 24, 2026
875c8b6
docs(caring-contacts): remove the freeze line the approval banner con…
BigSimmo Aug 24, 2026
bcede03
plan(caring-contacts): open the Phase 2B ledger, run the pre-flight s…
BigSimmo Aug 24, 2026
e690ad4
plan(caring-contacts): Task C brief, and the two rulings its conflict…
BigSimmo Aug 24, 2026
ac87293
plan(caring-contacts): Task 1 brief -- the shared empty-state component
BigSimmo Aug 24, 2026
623fc38
fix(caring-contacts): drop the unverifiable storage claim from the au…
BigSimmo Aug 24, 2026
b7aee30
feat(caring-contacts): refuse an unacknowledged fictional contact det…
BigSimmo Aug 24, 2026
49ce35b
feat(caring-contacts): refuse loudly when a closing contact has no au…
BigSimmo Aug 24, 2026
a4e3e02
fix(caring-contacts): narrow "lead" to its commercial sense only (B2)
BigSimmo Aug 24, 2026
bfd8688
test(caring-contacts): scan interface string literals for prohibited …
BigSimmo Aug 24, 2026
d6780e1
test(caring-contacts): bound the B3 fixture cleanup's rmSync retries
BigSimmo Aug 24, 2026
9a4cf05
docs(caring-contacts): Task C report -- six copy/policy changes, muta…
BigSimmo Aug 24, 2026
92c510c
ledger(caring-contacts): Task C evidence, and the zero-caller finding
BigSimmo Aug 24, 2026
9b031de
ledger(caring-contacts): Task C review verdict and fix round 1
BigSimmo Aug 24, 2026
e3d658e
fix(caring-contacts): fix round 1 -- seven review findings (B2, A1, B…
BigSimmo Aug 24, 2026
a865d6a
docs(caring-contacts): Task C fix-round-1 report
BigSimmo Aug 24, 2026
8a8a5cb
ledger(caring-contacts): Task C fix round 1, with the B2 inversion ve…
BigSimmo Aug 24, 2026
5000b16
ledger(caring-contacts): Task C COMPLETE -- all seven findings addressed
BigSimmo Aug 24, 2026
ff79cb6
plan(caring-contacts): reading the API layer cut one task and correct…
BigSimmo Aug 24, 2026
c0f8411
feat(caring-contacts): add the shared EmptyState component (Phase 2B …
BigSimmo Aug 24, 2026
e0fc37f
plan(caring-contacts): Ruling 87 -- Task 3 cannot ship a trigger with…
BigSimmo Aug 24, 2026
6e81317
plan(caring-contacts): Task 3 brief -- trigger plus commit contract
BigSimmo Aug 24, 2026
97a7ff7
docs(caring-contacts): Task 1 report -- shared EmptyState component
BigSimmo Aug 24, 2026
227414b
ledger(caring-contacts): Task 1 built, and the lock incident that cor…
BigSimmo Aug 24, 2026
347b786
ledger(caring-contacts): Task 1 review -- Ruling 88 renames the compo…
BigSimmo Aug 24, 2026
191761f
fix(caring-contacts): Task 1 fix round 1 -- rename collision, accessi…
BigSimmo Aug 24, 2026
1cd1136
plan(caring-contacts): Ruling 89 merges Task 4 into Task 5
BigSimmo Aug 24, 2026
caef3c7
docs(caring-contacts): correct Task 1 report -- mutation proof, plus …
BigSimmo Aug 24, 2026
5d3f26a
plan(caring-contacts): Task 5 brief -- the Patients directory, absorb…
BigSimmo Aug 24, 2026
f65dd39
ledger(caring-contacts): Task 1 COMPLETE -- all three findings addressed
BigSimmo Aug 24, 2026
16d6660
feat(caring-contacts): Task 3 -- overlay trigger and the commit contr…
BigSimmo Aug 24, 2026
f518734
test(caring-contacts): Task 3 -- trigger and commit-contract proofs
BigSimmo Aug 24, 2026
9a36d29
docs(caring-contacts): Task 3 report -- the handoff decision, its rej…
BigSimmo Aug 24, 2026
da696e2
plan(caring-contacts): the owner's three answers, and formatting
BigSimmo Aug 24, 2026
4d41e2c
ledger(caring-contacts): Task 3 review -- Ruling 90 overrules the bla…
BigSimmo Aug 24, 2026
9cc7fa5
ledger(caring-contacts): browser gate green at Task 3 head -- 32 passed
BigSimmo Aug 24, 2026
00056d3
fix(caring-contacts): Task 3 fix round 1 -- Ruling 90, the confirm fl…
BigSimmo Aug 24, 2026
b1f9c73
docs(caring-contacts): Task 3 fix round 1 -- record the four fixes an…
BigSimmo Aug 24, 2026
b452084
docs(caring-contacts): Task 3 fix round 1 gates -- 9823 passed, typec…
BigSimmo Aug 24, 2026
1306c0b
docs(caring-contacts): Task 3 -- the browser green predates fix round…
BigSimmo Aug 24, 2026
744fb7a
ledger(caring-contacts): Task 3 fix round 1, and a fifth check that c…
BigSimmo Aug 24, 2026
ba107ce
ledger(caring-contacts): browser gate re-taken post-fix -- 32 passed …
BigSimmo Aug 24, 2026
bb03d00
ledger(caring-contacts): Task 3 COMPLETE -- Group 0 finished
BigSimmo Aug 24, 2026
efb84c5
feat(caring-contacts): Task 5 -- the Patients directory, and the nav …
BigSimmo Aug 24, 2026
a359bbb
test(caring-contacts): Task 5 -- keep the production/prototype separa…
BigSimmo Aug 24, 2026
d270304
docs(caring-contacts): Task 5 report -- gates, mutations, and the nam…
BigSimmo Aug 24, 2026
0bebd94
ledger(caring-contacts): Task 5 built, Ruling 91 -- the owner chose a…
BigSimmo Aug 24, 2026
ea02d0c
Merge branch 'main' into claude/browser-test-gate-handoff-d5c1db
BigSimmo Aug 24, 2026
0becc47
Merge branch 'main' into claude/browser-test-gate-handoff-d5c1db
BigSimmo Aug 24, 2026
00a710a
Merge branch 'main' into claude/browser-test-gate-handoff-d5c1db
BigSimmo Aug 24, 2026
143a23c
chore: regenerate stale outstanding-issues snapshot
claude Aug 24, 2026
d3f5edc
fix(docs): scope-allowlist historical caring-contacts path references
claude Aug 24, 2026
9ab5691
ledger(caring-contacts): Task 5 review -- Rulings 92 and 93
BigSimmo Aug 24, 2026
3195464
fix(caring-contacts): Task 5 fix round 1 -- real browser proof, and t…
BigSimmo Aug 24, 2026
462747a
test(caring-contacts): record what the browser mutation actually meas…
BigSimmo Aug 24, 2026
a976e3c
test(caring-contacts): close two gaps the fix-round mutations found
BigSimmo Aug 24, 2026
cf8cff5
docs(caring-contacts): Task 5 fix round 1 report
BigSimmo Aug 24, 2026
5436505
ledger(caring-contacts): Task 5 fix round 1, and Ruling 93's premise …
BigSimmo Aug 24, 2026
9d21109
ledger(caring-contacts): Task 5 re-review -- Ruling 94 drops the coun…
BigSimmo Aug 24, 2026
31f16cf
fix(caring-contacts): Task 5 fix round 2
BigSimmo Aug 24, 2026
5e0dba3
docs(caring-contacts): itemise the round-1 mutation ledger
BigSimmo Aug 24, 2026
6df257b
docs(caring-contacts): Task 5 fix round 2 report
BigSimmo Aug 24, 2026
2063dc4
Merge remote-tracking branch 'origin/claude/browser-test-gate-handoff…
BigSimmo Aug 24, 2026
a666ca6
chore(issues): regenerate the snapshot after merging origin
BigSimmo Aug 24, 2026
d395b5e
ledger(caring-contacts): Task 5 COMPLETE, and Ruling 95 for the names…
BigSimmo Aug 24, 2026
e3d1fa6
plan(caring-contacts): Task 5b brief -- the names-only patient projec…
BigSimmo Aug 24, 2026
85fb6db
feat(caring-contacts): a names-only patient projection on the storage…
BigSimmo Aug 24, 2026
3450ebc
feat(caring-contacts): name the people on the caseload, from the narr…
BigSimmo Aug 24, 2026
897a49f
test(caring-contacts): read the identifier line itself, not the row's…
BigSimmo Aug 24, 2026
c6cd1ed
docs(caring-contacts): Task 5b report -- the names-only patient proje…
BigSimmo Aug 24, 2026
ee19925
ledger(caring-contacts): Task 5b built, Ruling 95 refined by the impl…
BigSimmo Aug 24, 2026
97be623
chore(format): prettier the shared repository contract
BigSimmo Aug 24, 2026
8b3f370
merge: reconcile Caring Contacts patients work with main
BigSimmo Aug 24, 2026
cac8336
Merge remote-tracking branch 'origin/main' into codex/review-fix-pr-2354
BigSimmo Aug 24, 2026
7957122
test(caring-contacts): allowlist private local search
BigSimmo Aug 24, 2026
065843a
test(caring-contacts): avoid false client graph match
BigSimmo Aug 24, 2026
a8e8364
test(caring-contacts): inspect client graph syntax
BigSimmo Aug 24, 2026
01fe261
Merge remote-tracking branch 'origin/main' into codex/review-fix-pr-2354
BigSimmo Aug 24, 2026
882336c
chore(developer-hub): refresh PR merge snapshot
BigSimmo Aug 24, 2026
b38f337
test(caring-contacts): avoid reserved module binding
BigSimmo Aug 24, 2026
0d5749c
fix(caring-contacts): filter rows before client boundary
BigSimmo Aug 24, 2026
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
8 changes: 7 additions & 1 deletion data/outstanding-issues-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"p2": 40,
"p3": 33,
"queued": 10,
"pending": 138,
"pending": 139,
"resolved": 376
},
"queue": [
Expand Down Expand Up @@ -1205,6 +1205,12 @@
"summary": "Cancel request 608150d5-7aa4-4b98-b497-1a9f1feaf4b5: Outcome stored a local account identifier under a personal home path; replace with repository-relative worktree logs, transcript filenames, and redacted home placeholders while keeping timestamps, hashes, and Claude Code 2.1.237 provenance.",
"created_at": "2026-08-23"
},
{
"request_id": "801d50ab-adbb-48e7-90ab-f8e6ed7ca588",
"action": "add",
"summary": "Caring Contacts: nothing enforces that a new workspace screen joins the browser spec's WORKSPACE_SCREENS",
"created_at": "2026-08-24"
},
{
"request_id": "82838fb1-7ed2-4f37-bd50-191a603ecd0f",
"action": "add",
Expand Down
53 changes: 43 additions & 10 deletions data/repo-awareness-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"version": "repo-awareness-snapshot-v1",
"captured_revision": {
"sha": "c93dd40b99e84e0a445bb16fc36c82d3089f5674",
"committed_at": "2026-08-25T05:43:27+08:00"
"sha": "01fe261f36dd001734cfd52a0556193edfcbac15",
"committed_at": "2026-08-25T06:16:41+08:00"
},
"routes": {
"modes": [
Expand Down Expand Up @@ -113,6 +113,11 @@
"file": "src/app/caring-contacts/page.tsx",
"area": "product"
},
{
"path": "/caring-contacts/patients",
"file": "src/app/caring-contacts/patients/page.tsx",
"area": "product"
},
{
"path": "/dictionary/[slug]",
"file": "src/app/(search-app)/dictionary/[slug]/page.tsx",
Expand Down Expand Up @@ -1339,8 +1344,8 @@
],
"counts": {
"modes": 15,
"pages": 185,
"product_pages": 65,
"pages": 186,
"product_pages": 66,
"mockup_pages": 120,
"redirects": 17,
"api": 56
Expand Down Expand Up @@ -1958,6 +1963,26 @@
"section": "caring-contacts",
"catalogued": false
},
{
"path": "docs/caring-contacts/phase-2b-sdd-archive/task-5-brief.md",
"section": "caring-contacts",
"catalogued": false
},
{
"path": "docs/caring-contacts/phase-2b-sdd-archive/task-5-report.md",
"section": "caring-contacts",
"catalogued": false
},
{
"path": "docs/caring-contacts/phase-2b-sdd-archive/task-5b-brief.md",
"section": "caring-contacts",
"catalogued": false
},
{
"path": "docs/caring-contacts/phase-2b-sdd-archive/task-5b-report.md",
"section": "caring-contacts",
"catalogued": false
},
{
"path": "docs/caring-contacts/phase-2b-sdd-archive/task-c-brief.md",
"section": "caring-contacts",
Expand Down Expand Up @@ -3497,8 +3522,8 @@
},
{
"name": "caring-contacts",
"documents": 62,
"uncatalogued": 62
"documents": 66,
"uncatalogued": 66
},
{
"name": "codex",
Expand Down Expand Up @@ -3567,9 +3592,9 @@
}
],
"counts": {
"documents": 425,
"documents": 429,
"catalogued": 101,
"uncatalogued": 324,
"uncatalogued": 328,
"sections": 18
}
},
Expand All @@ -3582,6 +3607,14 @@
},
"review_state": {
"records": [
{
"date": "2026-08-24",
"ref": "2354",
"head": "97be623d5cd0d878130ff1eb6aa8ef9851d92d97",
"scope": "PR #2354 current changed scope",
"outcome": "P1 privacy URL leak and P2 inventory/data-boundary defects fixed; final staged re-review clean",
"checks": "diff check; sitemap; docs links/index; issue snapshot pass; focused DOM blocked by repository Playwright lease"
},
{
"date": "2026-08-24",
"ref": "2360",
Expand Down Expand Up @@ -24448,8 +24481,8 @@
}
],
"counts": {
"records": 2608,
"refs": 1590
"records": 2609,
"refs": 1591
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
| 2026-08-24 | 2354 | 97be623d5cd0d878130ff1eb6aa8ef9851d92d97 | PR #2354 current changed scope | P1 privacy URL leak and P2 inventory/data-boundary defects fixed; final staged re-review clean | diff check; sitemap; docs links/index; issue snapshot pass; focused DOM blocked by repository Playwright lease |
315 changes: 315 additions & 0 deletions docs/caring-contacts/phase-2b-build-record.md

Large diffs are not rendered by default.

137 changes: 137 additions & 0 deletions docs/caring-contacts/phase-2b-sdd-archive/task-5-brief.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Task 5 brief — the Patients directory (absorbing Task 4)

**Plan:** `docs/superpowers/plans/2026-08-24-caring-contact-phase-2b-screens.md`, Group 1, Task 5.
**These are your requirements.** Read Rulings 85 and 89 in `docs/caring-contacts/phase-2b-build-record.md`
first — they are why this task is shaped the way it is.

Caring Contacts is a suicide-prevention prototype: patients discharged from hospital receive a fixed
schedule of brief, non-demanding messages. Every patient is fictional and **nothing is ever sent to any
number**. This is the **first real screen of Phase 2B** and the owner's first priority.

## What you are building

`src/app/caring-contacts/patients/page.tsx` — the team's caseload, listing the plans this actor's team
may see, plus the navigation and documentation that make it a real destination.

**Task 4 was merged into this one (Ruling 89).** The plan originally lit up the navigation link with an
empty placeholder page first. That page would have said _"No patients yet"_ whether or not patients
existed — a false statement on a clinical caseload screen, and precisely the defect the component you
are about to use was built to prevent. So the link and the real screen land together, and the screen is
never reachable in a state where it can lie.

## Do NOT build a data source — it exists (Ruling 85)

`GET /api/caring-contacts/plans` already lists the team's plans through `readHandler`. More directly,
**your page is a Server Component and should read the store the same way the Today page does**, not
over HTTP.

**Read `src/app/caring-contacts/page.tsx` before writing anything.** It is heavily commented and is the
established pattern: `isCaringContactsDemoEnabled()` then `notFound()`; `resolveDemoActor()`;
`caringContactsStore()`; the read wrapped in `auditedRead`; fail closed on every bad outcome; then
render `<CaringContactsShell title description serviceState>`.

Your page needs **two** audited reads — the service state (so the safety banner can render, which is a
required prop on every screen) and the plans list. Use the same access identity the API route already
records for each, so the access trail does not grow a second vocabulary for the same read:

- service state — `{ kind: "administrative", objectType: "serviceState", objectId: "service" }`
- plans — `{ kind: "search", objectType: "plan", objectId: "all" }` and `store.listPlans({ actor })`

**Do NOT call `getEpisode`.** It is the only read that releases `patientDetail` — name, mobile number,
identifiers, cultural identity — and a directory does not need them. If the approved design appears to
show a patient's name in the list, **stop and report it** rather than reaching for `getEpisode`; that
is a question for me, not a decision for the implementer. Every other read returns `PlanRecord`, which
excludes patient detail by construction.

## The empty-list contract test — the one thing that survived the cut of Task 2

`auditedRead` maps a `null` or `undefined` release to `denied`, which `readHandler` turns into
`not-found`. **An empty array is neither**, and an empty caseload must never present as a missing
resource.

Write a test pinning that **an empty list renders the empty state on a 200-shaped success path, never a
404 / `notFound()`**. This is not obvious from reading the code, which is exactly why it needs a test
rather than a comment. The factory's own note says the trail cannot distinguish "you may not see these"
from "there are none" for a list — so the HTTP and render shapes must be pinned deliberately.

## Use `ListEmptyState`, and use both of its kinds honestly

`src/components/caring-contacts/workspace/list-empty-state.tsx` (Task 1). It has two kinds and they are
not interchangeable:

- `"no-data"` — the team genuinely has no plans.
- `"filtered"` — plans exist but the current filter or search hides all of them. **Requires** a
`because` and a `changedBy`.

A filtered-empty caseload that renders `"no-data"` tells a clinician their caseload is empty when it is
not. That is the defect this whole component exists to prevent — get it right here, because this is the
first screen to use it and every later screen will copy this one.

## Filtering

Provide at least one filter or search. Keep it **server-side** if you can do so without a client
boundary — Ruling 13 holds this workspace's client payload to a rounding error, and a URL-parameter
filter read by the Server Component costs none. If you conclude a client boundary is unavoidable,
**say so in your report with your reasoning** rather than adding one quietly.

## What makes it a real destination (the absorbed Task 4)

All four, or the route is an orphan and the build fails:

1. `href: CARING_CONTACTS_ROUTES.patients` added to `PRIMARY_DESTINATIONS` in
`src/components/caring-contacts/workspace/shell.tsx`. The file's own comment says this is the whole
of the change. Note `PHONE_DESTINATIONS` derives from it, so the phone dock follows automatically.
2. `npm run sitemap:update`.
3. An entry in `docs/codebase-index.md`.
4. A reachability assertion — see `tests/route-reachability.test.ts`.

Build hrefs from `src/lib/caring-contacts-routes.ts`, never from string literals. It already exports
`patientRoute(patientId)` and `planRoute(planId)` for the rows.

## Constraints

- **Internal navigation** uses `<Link>` / `router.push` / server `redirect()` — never a raw
`<a href="/…">`.
- Every `<button>` does something. A control unavailable for a stated reason uses `aria-disabled="true"`
- an inert handler + `title="… — coming soon"` + an `sr-only` note. **Never** native `disabled` and
`aria-disabled` together.
- Design tokens only, no hardcoded hex. Tap targets `min-h-12` (48px) — **never `min-h-11`**, which
reintroduces a known `ui-smoke` flake.
- The service-state incident `note` must never reach a Client Component.
- No import from `src/components/caring-contacts/mockups/**`. Read them as a specification only —
`PatientsDirectoryPage` in `mockups/product-pages.tsx` is the approved design for this screen.
- **Explained automation (spec §4.4) is a contract:** wherever the system has acted on its own —
paused, suppressed, blocked, escalated — the surface stating it must also state, in plain words and
in place, **why** and **what would change it**. No bare status chip with an unreachable reason.
- **The closed transport vocabulary is frozen.** `Delivered` is a transport receipt and never a
patient-state label. Prohibited in any interface string: high risk, safe, engagement score, campaign,
lead, conversion, best match, inbox, conversation, clinical risk, risk score, wellbeing score, and
any claim that replies are monitored. A static scan enforces this — it caught a lucide icon named
`Inbox` in the previous task, on the identifier alone.
- **This is Next.js 16.** Read `node_modules/next/dist/docs/` before writing route or layout code;
it has breaking changes against most training data, and reading beats reasoning.

## Verification

- Test-first. Then deliberately break the implementation and confirm the covering test goes red —
**check FIRST that your mutation changes a value some assertion actually reads**, and prove the
mutation is in the tree before believing any result. Two mutation reports on this programme have
already turned out to describe something other than what was run.
- `npm run test:focused -- --files <paths>` while iterating; then the **full `npm run test`**; then
`npm run typecheck` and `npm run lint`.
- **Never report a gate as passing from an exit code — paste the `N passed` line.**
- **Known environmental noise, not yours:** exactly 2 failures in `tests/gate-receipts.test.ts` ("gate
receipts — file modes", failing in `chmodSync`) because this Windows drive cannot represent Unix file
modes. Report any others.
- **A lock-acquisition failure is neither a pass nor a failure.** If a gate cannot take the heavy-run
lease, retry a couple of times then report which gate did not run. No summary line means no run,
whatever the exit code says.

## Report

**Commit early — before waiting on any gate.** This machine has destroyed four working directories
mid-session and a commit is the only thing that has survived.

Write your full report to `docs/caring-contacts/phase-2b-sdd-archive/task-5-report.md`, then return
ONLY: status, commit SHAs, a one-line test summary, and your concerns. Do not paste the report into
your reply. Do not dispatch subagents. **Do not push and do not open a pull request.**
Loading
Loading