223 lines
13 KiB
Markdown
223 lines
13 KiB
Markdown
# Phase 4 — Backlog reconciliation
|
||
|
||
**Depends on:** Phase 0, Phase 3 (and consumes Phase 2's drift list) · **Blocks:** Phase 5 · **Size:** 1–2 sessions
|
||
|
||
## Goal
|
||
|
||
Turn **five unreconciled ledgers plus 50+ scattered "follow-ups" sections** into one triaged backlog
|
||
where every open item is real, deduplicated, and carries its origin.
|
||
|
||
This is the "remaining works from plans, dev, refine and ui phases should be well documented"
|
||
deliverable. Today the honest answer to "what's left?" is *nobody knows* — the hardening ledger has
|
||
18 items with **zero ticked**, written before three more chains ran on top of it.
|
||
|
||
---
|
||
|
||
## Inputs
|
||
|
||
| Source | Volume | Note |
|
||
| --- | --- | --- |
|
||
| [dev/post-phase/hardening/issues.md](../../dev/post-phase/hardening/issues.md) | 18 items, **all unticked** | Written 2026-07-16. UI phases 0–13 and the deploy commits ran after. **Every item must be re-verified against current code.** |
|
||
| [dev/shared-working-context/frontend/requests/for-backend.md](../../dev/shared-working-context/frontend/requests/for-backend.md) | 67 REQs, 1,115 lines | Most delivered in refinement-phase-3; some `partially delivered`; REQ-066/067 blocked on a privacy sign-off |
|
||
| `dev/shared-working-context/reports/*.md` | 50 files | Each has a "Follow-ups for later phases" / "Deferred" section |
|
||
| `dev/shared-working-context/backend/STATUS.md` + `frontend/STATUS.md` | 86 KB | Deferrals recorded with explicit **pull-triggers** (e.g. Elasticsearch `INurseSearch`, SMS/push dispatcher, analytics, holiday feed, 8 unbuilt product tables) |
|
||
| [dev/manual-testing/iteration-1/](../../dev/manual-testing/iteration-1/) + [iteration-2/](../../dev/manual-testing/iteration-2/) | 2 raw notes + screenshots | Your own most recent feedback. Some applied in `baa3cc6` / `e6a8f93`; **which parts landed is unknown** |
|
||
| [product/notes/open-questions.md](../../product/notes/open-questions.md) | build backlog + research questions | |
|
||
| Phase 2's output | drift list | `phantom` and `drifted` endpoints |
|
||
| Phase 3's output | gap list | everything found while verifying flows |
|
||
| Root [CLAUDE.md](../../CLAUDE.md) §6 | | credential rotation before real users — a real pre-launch item |
|
||
|
||
## Outputs
|
||
|
||
```
|
||
docs/status/
|
||
index.md where the project is, in one page
|
||
implemented.md the product/business overlay: 14 areas -> build state
|
||
backlog.md BL-### — every open item, triaged
|
||
backlog-closed.md items confirmed done, with what closed them
|
||
decisions.md the distilled decision log
|
||
```
|
||
|
||
---
|
||
|
||
## Steps
|
||
|
||
### 1. Harvest everything into one raw list
|
||
|
||
One row per candidate item, with its **origin id** (`H-01`, `REQ-042`, `ui-phase-9 follow-up`,
|
||
`iteration-2`, `deferral: elasticsearch`, `phase-3 finding`, `phase-2 drift`). Expect 150–250 raw
|
||
rows before dedup. Do not filter while harvesting.
|
||
|
||
### 2. Verify each item's current state
|
||
|
||
This is the phase's real work, and the reason it comes after Phase 3.
|
||
|
||
- **The 18 hardening items**: re-locate each in the code. The file itself warns that line numbers
|
||
drifted. Several are likely fixed by the UI chain — e.g. **H-01** (the auth gate never running,
|
||
traced to a stray `pnpm-lock.yaml` and the `middleware.ts` → `proxy.ts` question) overlaps directly
|
||
with what ui-phase-13 did to the root route and matcher. Verify; don't assume either way.
|
||
- **The 67 REQs**: classify `delivered` / `partially delivered — what's left` / `open` / `obsolete`.
|
||
The ones marked `partially delivered in refinement-phase-3` need the residue spelled out. Once
|
||
Phase 2 folded delivered REQs into the domain docs, a delivered REQ is *closed*, not an item.
|
||
- **Iterations 1 & 2**: walk each bullet against the code. The clearest testable one:
|
||
*"replace all forms with more than 1 field with react-hook-form"* — 28 files import it today;
|
||
find the forms that still use raw state and file the residue.
|
||
- **Deferrals**: these are not bugs; they are *decisions with pull-triggers*. Keep them as
|
||
`deferred`, carry the trigger, and hand them to Phase 5's `roadmap/deferred.md`.
|
||
|
||
### 3. Dedup and assign `BL-###`
|
||
|
||
Many items appear in three ledgers. Merge them into one `BL-###` carrying **all** origin ids.
|
||
Old ids stay greppable — never rewrite the archived sources.
|
||
|
||
### 4. Write `backlog.md`
|
||
|
||
```markdown
|
||
> Last verified: <date> against <commit>
|
||
|
||
| ID | Area | Sev | Item | Origin | Status | Blocks |
|
||
|----|------|-----|------|--------|--------|--------|
|
||
| BL-001 | client | blocker | … | H-01 | open | flow: auth-login-otp |
|
||
```
|
||
|
||
- **Area**: `client` · `server` · `contract` · `ops` · `product` · `docs`
|
||
- **Sev**: `blocker` (product is wrong or unusable) · `major` · `minor` · `deferred`
|
||
- **Status**: `open` · `in-progress` · `blocked (on what)` · `deferred (trigger)`
|
||
- **Blocks**: the flow(s) from `docs/flows/` it degrades — this is what connects the backlog to
|
||
something a user can feel
|
||
|
||
Sort by severity, then area. Anything closed goes to `backlog-closed.md` with *what* closed it
|
||
(commit or phase), so the count of open items is honest at a glance.
|
||
|
||
### 5. Write `implemented.md` — the product overlay
|
||
|
||
The agreed alternative to touching `product/`. One row per business area:
|
||
|
||
| Business area | Doc | State | Flows | Gaps |
|
||
| --- | --- | --- | --- | --- |
|
||
| 08 Payments & escrow | [product/business/08-…](../../product/business/08-payments-and-escrow.md) | built | checkout-and-payment, cancellation-and-refunds | BL-023 |
|
||
|
||
States: `built` · `partial` · `mocked` · `not started` · `deferred`. Add the reverse link from each
|
||
`docs/flows/*.md` back to its business area. This gives the two-way mapping without editing a single
|
||
`product/` file.
|
||
|
||
Do the same, briefly, for the data model: the STATUS logs mention **8 product tables that were never
|
||
built** — name them here rather than leaving them in a status log.
|
||
|
||
### 6. Write `decisions.md`
|
||
|
||
The distilled decision log — the highest-value thing buried in 3 MB of reports. Extract every
|
||
**non-obvious decision with a reason** and write it as a short ADR-style entry: *what was decided,
|
||
when, why, and where it binds*. Candidates already visible in the STATUS logs and memory:
|
||
|
||
- Commission 0.15 / VAT 0.10 **on commission only** (the canonical fee model, refinement-phase-3)
|
||
- `district_id = NULL` means whole-city — in both directions
|
||
- Verification `status` is the source of truth; `is_verified` is a guarded flip
|
||
- Booking status is forward-only; the three-amount split has a CHECK constraint
|
||
- The two-stage clinical-disclosure gate; EVV is **advisory**, never a block
|
||
- Webhook idempotency is upsert-first; ledger postings must balance
|
||
- Reviews recompute from source; nurse care records are append-only
|
||
- `is_internal` ticket messages never appear in user-facing types
|
||
- One payout per booking (UNIQUE); whole-clawback greedy netting
|
||
- Escrow released after a confirmed check-out; weekly payout generation automatic, processing manual
|
||
- Config in files, not a secret store — deliberate pre-launch trade
|
||
- Error state is never an empty state (the client convention)
|
||
- Root `/` forks by auth via middleware **rewrite**, never redirect
|
||
|
||
Each entry: 3–6 lines. Where a decision is already stated in `product/`, link rather than restate —
|
||
`product/` wins for business rules; `decisions.md` is for *engineering* decisions and for business
|
||
decisions that were made **during** the build and never made it back into `product/`. Anything in the
|
||
second category should also get a note in `product/notes/` so the business truth stays complete.
|
||
|
||
### 7. Write `index.md`
|
||
|
||
One page: how many flows are built/partial/mocked, how many backlog items are open by severity, the
|
||
top five things standing between here and a usable product, and links to everything. This is the page
|
||
you open when you come back after two weeks away.
|
||
|
||
---
|
||
|
||
## Verification
|
||
|
||
- [x] Every one of the 18 hardening items has a verdict backed by a code check — none carried over
|
||
unexamined. (3 fixed, 4 partially-fixed, 11 open, 0 obsolete — see `backlog-closed.md`/`backlog.md`.)
|
||
- [x] Every REQ-001…067 is classified; the count of `open` is explicit. (28 delivered, 1 obsolete, 6
|
||
deferred, 2 partially-delivered, 30 open.)
|
||
- [x] Every "Follow-ups for later phases" section across the 53 reports was read and harvested. (Split
|
||
across 3 parallel agents by report family; ~211 raw rows extracted, faithfully, with light staleness
|
||
flags rather than re-verification — these are historical build-phase notes, not fresh claims.)
|
||
- [x] Both iteration notes are fully accounted for, bullet by bullet. (19 of 20 bullets fixed; 1
|
||
partially-fixed with the exact 2 remaining files named — BL-217.)
|
||
- [x] No `BL-###` duplicates another; every one names its origin id(s). (Root-cause consolidation applied
|
||
throughout — e.g. the admin-RBAC finding alone carries 18 origin ids into one `BL-001`.)
|
||
- [x] Every `blocker` names the flow it blocks.
|
||
- [x] `implemented.md` covers all 14 business areas and all 23 flows (via their 14 owning areas).
|
||
|
||
## Definition of done
|
||
|
||
"What's left?" is answered by one file, and every number in it was checked rather than inherited. **Met** —
|
||
`docs/status/index.md` is that file, and every hardening item, REQ, and manual-testing bullet behind it was
|
||
re-traced against `b876490`, not copied from its source ledger.
|
||
|
||
## Handoff
|
||
|
||
**Done 2026-08-02 against `b876490`, in one session using 10 parallel Sonnet subagents for the harvest.**
|
||
|
||
### What was produced
|
||
|
||
`docs/status/` — `index.md`, `backlog.md` (262 open items), `backlog-closed.md` (88 closed items),
|
||
`implemented.md` (14-area product overlay), `decisions.md` (18 distilled ADR-style entries). ~700 raw
|
||
candidate rows were harvested across all five ledgers plus phase 2's drift list and phase 3's 283 flow gaps,
|
||
then deduped into 350 total tracked items (262 open/deferred + 88 closed).
|
||
|
||
**Severity spread: 18 blocker · 86 major · 115 minor · 43 deferred.**
|
||
|
||
### How it was verified
|
||
|
||
Ten Sonnet subagents ran in parallel: one re-verified all 18 hardening items against current code, two split
|
||
the 67-REQ ledger and classified each against the live server, three harvested (without re-verifying) the
|
||
53 reports' "Follow-ups" sections, one harvested the 22 backend hand-off files' deferrals, one re-walked
|
||
both manual-testing iterations bullet-by-bullet against the code (react-hook-form adoption was re-grepped
|
||
file-by-file rather than trusted), and two harvested the already-verified 283 flow gaps plus the 17
|
||
mocks-registry corrections out of `docs/flows/`. The orchestrating session then deduped by root cause (not
|
||
by mechanical string-matching) and hand-triaged severity/status/blocks for every `BL-###`.
|
||
|
||
Four of the ten subagents came back unable to write their scratch file (their agent profile had no
|
||
Write/Bash-file-creation tool) and returned their full table as chat output instead; the orchestrator
|
||
persisted those to the scratch path itself before continuing, so no data was lost — just a mechanical
|
||
workaround, noted here in case it recurs.
|
||
|
||
### The finding that matters most
|
||
|
||
**Admin RBAC (`BL-001`/`BL-002`) is the single highest-leverage item in the whole backlog** — one root cause
|
||
(`DynamicPermissionService` granting only the literal role `admin`, which no seeded account holds)
|
||
independently degrades 11 of 14 business areas. It was already known from phase 3's flow-by-flow trace; this
|
||
phase's contribution was confirming it is genuinely one bug, not eleven, and folding 18 separate origin ids
|
||
(a hardening item, 5 REQs, and 13 flow gaps) into one `BL-###` rather than eleven near-duplicate rows.
|
||
|
||
Second: five domains are 100% client-mocked while a **working, code-verified server sits behind them**
|
||
(verification, refunds, nurse payouts, patient/care records, partner-center) — and three of those five would
|
||
*break*, not just show stale data, on a naive flag flip, because the client and server DTO shapes have
|
||
independently drifted since the mock was written.
|
||
|
||
### What was left undone, and why
|
||
|
||
- **Report follow-ups (~211 rows) were harvested but not individually re-verified against code** — that
|
||
would have meant re-running phase 3's entire flow-gap sweep at 10x the scope for marginal new information,
|
||
since the overwhelming majority either (a) are already superseded by a later, more current phase report,
|
||
confirmed by cross-referencing the later report's own "What was built" section, or (b) restate a deferred
|
||
decision that the 22 backend hand-off files already state more precisely with a pull-trigger. Genuinely
|
||
new, still-open findings from this pool were promoted into `backlog.md`; the rest are either in
|
||
`backlog-closed.md` (confirmed done) or folded into the Deferred section (confirmed intentional).
|
||
- **The Deferred section (43 items) is consolidated, not 1:1 with its ~150 raw source rows** — the same
|
||
"Redis needed for >1 instance" or "Elasticsearch not MVP" statement recurs verbatim across 3-4 separate
|
||
hand-off files; each `BL-###` in that section carries every origin id it absorbed.
|
||
- **`product/notes/open-questions.md`'s remaining open items were checked directly** (not delegated) since
|
||
the file is 86 lines — rate limiting turned out already built for auth/OTP (only search lacks it, already
|
||
tracked as REQ-066/`BL-206`); the ToS/Privacy pages exist but are explicitly commented as placeholder
|
||
legal copy pending review (`BL-097`); PWA/Workbox caching is untouched and was marked "maybe" in the
|
||
original backlog, so it's carried as `BL-251`, deferred.
|
||
- **This phase did not touch `dev/`, `product/`, or any code** — pure reconciliation, as scoped. Phase 6
|
||
(archive) is what moves/banners the source ledgers; phase 5 (roadmap) is what turns the Deferred section
|
||
into a sequenced plan.
|