docs: mark SP4 partial shipped (claim drawer); tick all plan checkboxes

This commit is contained in:
Tyler
2026-06-20 12:37:31 -06:00
parent 8dc220826c
commit 972cc99200
2 changed files with 131 additions and 102 deletions
+27 -5
View File
@@ -123,7 +123,7 @@ backup API).
## Roadmap
Sub-projects 2 and 3 are **shipped**. Next up:
Sub-projects 2, 3, and the first half of 4 are **shipped**. Next up:
- **Sub-project 3 (shipped) — More 837P/835 features.**
- **837P validation rules:** R034 enforces `REF*G1` on frequency-code
@@ -142,10 +142,21 @@ Sub-projects 2 and 3 are **shipped**. Next up:
builds a 270 from a JSON payload (subscriber, provider, payer,
service type); `POST /api/eligibility/parse-271` ingests the
response and returns structured `coverage_benefits`.
- **Sub-project 4 — Frontend features.** Per-claim detail drawer, batch
diff view, real-time streaming of NDJSON GET responses, advanced
filters (date range, multi-status, saved filter sets), keyboard-driven
navigation.
- **Sub-project 4 (partially shipped) — Frontend features.**
- **Per-claim detail drawer (shipped):** click any row on the Claims
page to open a side-panel drawer with the full claim context —
state + amount header, validation panel, service lines, diagnoses,
parties (billing provider, subscriber, payer), raw X12 segments,
matched remittance summary, and a vertical state-history timeline.
URL is synced (`?claim=...`) so links and back-button restore the
drawer. Keyboard nav: `j`/`k` move between claims, `esc` closes,
`?` opens the cheatsheet overlay. Skeleton + error + not-found
(404) states are all distinct. Powered by a new backend endpoint
`GET /api/claims/{claim_id}` that returns the full drawer payload
in a single round-trip.
- **Remaining SP4:** batch diff view, real-time streaming of NDJSON
GET responses, advanced filters (date range, multi-status, saved
filter sets).
### SP3 endpoints
@@ -162,6 +173,17 @@ Sub-projects 2 and 3 are **shipped**. Next up:
The UI gains a new **Acks** page (sidebar entry) that lists persisted
ACKs and lets you download the regenerated 999 text.
### SP4 endpoints (claim drawer)
- `GET /api/claims/{claim_id}` — full claim context for the drawer
payload: header fields, diagnoses, service lines, parties
(billing provider / subscriber / payer), validation result, raw
X12 segments, matched remittance summary (or `null`), and the
claim's state history (ordered newest-first). 404 with a structured
`{ "error": "Not found", "detail": "Claim {id} not found" }` body
when the claim doesn't exist — distinct from a transient fetch
failure so the UI can render a dedicated not-found state.
## License
No license file yet; this is internal-use software. Add a `LICENSE` file
@@ -66,11 +66,11 @@ src/index.css # +CSS variables for Modern palette
TDD discipline: write tests first, confirm red, implement, confirm green.
- [ ] **Step 1: Add failing tests** in `backend/tests/test_store_claim_detail.py`
- [ ] **Step 2: Run tests to verify they fail**
- [ ] **Step 3: Implement `to_ui_claim_detail` mapper + `get_claim_detail` method**
- [ ] **Step 4: Run tests to verify they pass**
- [ ] **Step 5: Commit**
- [x] **Step 1: Add failing tests** in `backend/tests/test_store_claim_detail.py`
- [x] **Step 2: Run tests to verify they fail**
- [x] **Step 3: Implement `to_ui_claim_detail` mapper + `get_claim_detail` method**
- [x] **Step 4: Run tests to verify they pass**
- [x] **Step 5: Commit**
```bash
git add backend/src/cyclone/store.py backend/tests/test_store_claim_detail.py
@@ -93,11 +93,11 @@ git commit -m "feat(store): get_claim_detail returns full claim context with his
- `test_get_claim_detail_state_history_includes_manual_match` — manual_match event appears in history
- `test_get_claim_detail_matched_remit_inlines_summary` — when matched, summary fields are populated
- [ ] **Step 1: Add failing tests** in `backend/tests/test_api_claim_detail.py`
- [ ] **Step 2: Run tests to verify they fail**
- [ ] **Step 3: Add the endpoint** (mirror `parse_999` endpoint pattern; use existing `_claim_to_ui` helpers)
- [ ] **Step 4: Run tests to verify they pass**
- [ ] **Step 5: Commit**
- [x] **Step 1: Add failing tests** in `backend/tests/test_api_claim_detail.py`
- [x] **Step 2: Run tests to verify they fail**
- [x] **Step 3: Add the endpoint** (mirror `parse_999` endpoint pattern; use existing `_claim_to_ui` helpers)
- [x] **Step 4: Run tests to verify they pass**
- [x] **Step 5: Commit**
```bash
git add backend/src/cyclone/api.py backend/tests/test_api_claim_detail.py
@@ -112,8 +112,8 @@ git commit -m "feat(api): GET /api/claims/{claim_id} returns full claim context"
Expected: 409 + ~8 new = ~417 pass + 1 skip. All green.
- [ ] **Step 1: Run the full backend suite, confirm green**
- [ ] **Step 2: Tag phase complete** (no commit unless changes; otherwise commit "test(sp4): phase 1 backend complete")
- [x] **Step 1: Run the full backend suite, confirm green**
- [x] **Step 2: Tag phase complete** (no commit unless changes; otherwise commit "test(sp4): phase 1 backend complete")
## Phase 2 — Frontend foundation
@@ -126,11 +126,11 @@ Expected: 409 + ~8 new = ~417 pass + 1 skip. All green.
The `ClaimDetail` type matches the JSON response shape from Task 2. Nested types: `Diagnosis`, `ServiceLine`, `Parties`, `Validation`, `MatchedRemittance`, `StateHistoryEvent`.
- [ ] **Step 1: Add `ClaimDetail` interface** to `src/types/index.ts` (in the "backend-aligned" block, snake_case to match API)
- [ ] **Step 2: Add `api.getClaimDetail(id)` method** to `src/lib/api.ts` (uses `apiFetch` helper if present)
- [ ] **Step 3: Add test** to `src/lib/api.test.ts` — happy path + 404
- [ ] **Step 4: Run frontend tests + typecheck, confirm green**
- [ ] **Step 5: Commit**
- [x] **Step 1: Add `ClaimDetail` interface** to `src/types/index.ts` (in the "backend-aligned" block, snake_case to match API)
- [x] **Step 2: Add `api.getClaimDetail(id)` method** to `src/lib/api.ts` (uses `apiFetch` helper if present)
- [x] **Step 3: Add test** to `src/lib/api.test.ts` — happy path + 404
- [x] **Step 4: Run frontend tests + typecheck, confirm green**
- [x] **Step 5: Commit**
```bash
git add src/types/index.ts src/lib/api.ts src/lib/api.test.ts
@@ -160,11 +160,11 @@ Behavior:
- Caches for the drawer session so j/k navigation reuses prior fetches within ~30s
- Returns 404 state as `{ isError: true, error: <NotFoundError> }`
- [ ] **Step 1: Add failing tests** — null id (no fetch), happy path, 404
- [ ] **Step 2: Run tests, confirm red**
- [ ] **Step 3: Implement the hook**
- [ ] **Step 4: Run tests, confirm green**
- [ ] **Step 5: Commit**
- [x] **Step 1: Add failing tests** — null id (no fetch), happy path, 404
- [x] **Step 2: Run tests, confirm red**
- [x] **Step 3: Implement the hook**
- [x] **Step 4: Run tests, confirm green**
- [x] **Step 5: Commit**
```bash
git add src/hooks/useClaimDetail.ts src/hooks/useClaimDetail.test.ts
@@ -194,11 +194,11 @@ Behavior:
- Ignores keys when an input/textarea/contentEditable has focus
- Cleans up listener on unmount or `enabled === false`
- [ ] **Step 1: Add failing tests** — fires onNext for "j", ignores when input focused, cleanup on unmount
- [ ] **Step 2: Run tests, confirm red**
- [ ] **Step 3: Implement the hook**
- [ ] **Step 4: Run tests, confirm green**
- [ ] **Step 5: Commit**
- [x] **Step 1: Add failing tests** — fires onNext for "j", ignores when input focused, cleanup on unmount
- [x] **Step 2: Run tests, confirm red**
- [x] **Step 3: Implement the hook**
- [x] **Step 4: Run tests, confirm green**
- [x] **Step 5: Commit**
```bash
git add src/hooks/useDrawerKeyboard.ts src/hooks/useDrawerKeyboard.test.ts
@@ -228,11 +228,11 @@ Behavior:
- `close()` strips the param via `history.pushState`
- Returns null `claimId` when no param is set
- [ ] **Step 1: Add failing tests** — reads URL on mount, open adds param, setClaimId replaces, close removes
- [ ] **Step 2: Run tests, confirm red**
- [ ] **Step 3: Implement the hook** (mock `window.history` in tests via vitest's `vi.stubGlobal`)
- [ ] **Step 4: Run tests, confirm green**
- [ ] **Step 5: Commit**
- [x] **Step 1: Add failing tests** — reads URL on mount, open adds param, setClaimId replaces, close removes
- [x] **Step 2: Run tests, confirm red**
- [x] **Step 3: Implement the hook** (mock `window.history` in tests via vitest's `vi.stubGlobal`)
- [x] **Step 4: Run tests, confirm green**
- [x] **Step 5: Commit**
```bash
git add src/hooks/useDrawerUrlState.ts src/hooks/useDrawerUrlState.test.ts
@@ -248,8 +248,8 @@ npm test -- --run
Expected: 10 + 5 new = 15 frontend pass.
- [ ] **Step 1: Run typecheck + frontend tests, confirm green**
- [ ] **Step 2: Commit if any changes**
- [x] **Step 1: Run typecheck + frontend tests, confirm green**
- [x] **Step 2: Commit if any changes**
## Phase 3 — Frontend leaf components
@@ -292,8 +292,8 @@ Add the CSS variables from spec §3.3 to `:root`:
Also add the Inter Tight + JetBrains Mono font imports (Google Fonts CDN).
- [ ] **Step 1: Append the CSS variables + font import**
- [ ] **Step 2: Commit**
- [x] **Step 1: Append the CSS variables + font import**
- [x] **Step 2: Commit**
```bash
git add src/index.css
@@ -312,10 +312,10 @@ git commit -m "feat(frontend): Modern palette CSS variables + Inter Tight/JetBra
**Error:** Takes `{ kind: "not_found" | "network"; onRetry?: () => void; onClose: () => void }`. Renders the appropriate message + buttons.
- [ ] **Step 1: Add failing tests** for both components
- [ ] **Step 2: Implement** (keep simple — these are placeholder UIs)
- [ ] **Step 3: Run tests, confirm green**
- [ ] **Step 4: Commit**
- [x] **Step 1: Add failing tests** for both components
- [x] **Step 2: Implement** (keep simple — these are placeholder UIs)
- [x] **Step 3: Run tests, confirm green**
- [x] **Step 4: Commit**
```bash
git add src/components/ClaimDrawer/ClaimDrawerSkeleton.tsx src/components/ClaimDrawer/ClaimDrawerSkeleton.test.tsx src/components/ClaimDrawer/ClaimDrawerError.tsx src/components/ClaimDrawer/ClaimDrawerError.test.tsx
@@ -336,10 +336,10 @@ Renders:
- Total amount (right of badge): big number, mono
- Close button (top-right): `Button` with X icon
- [ ] **Step 1: Add failing tests** — renders ID, state badge with right color, total, close callback
- [ ] **Step 2: Implement**
- [ ] **Step 3: Run tests, confirm green**
- [ ] **Step 4: Commit**
- [x] **Step 1: Add failing tests** — renders ID, state badge with right color, total, close callback
- [x] **Step 2: Implement**
- [x] **Step 3: Run tests, confirm green**
- [x] **Step 4: Commit**
```bash
git add src/components/ClaimDrawer/ClaimDrawerHeader.tsx src/components/ClaimDrawer/ClaimDrawerHeader.test.tsx
@@ -361,10 +361,10 @@ Renders:
- Group errors by `rule` field with count (e.g., `R050_diagnosis_present (2)`)
- List messages under each rule group
- [ ] **Step 1: Add failing tests** — empty state, errors only, warnings only, both, grouping
- [ ] **Step 2: Implement**
- [ ] **Step 3: Run tests, confirm green**
- [ ] **Step 4: Commit**
- [x] **Step 1: Add failing tests** — empty state, errors only, warnings only, both, grouping
- [x] **Step 2: Implement**
- [x] **Step 3: Run tests, confirm green**
- [x] **Step 4: Commit**
```bash
git add src/components/ClaimDrawer/ValidationPanel.tsx src/components/ClaimDrawer/ValidationPanel.test.tsx
@@ -384,10 +384,10 @@ Renders:
- Table: line #, procedure (qualifier + code + modifiers), charge (mono, big), units, date
- Empty state: "No service lines" muted text
- [ ] **Step 1: Add failing tests** — empty, single line, multiple lines; procedure formatting
- [ ] **Step 2: Implement**
- [ ] **Step 3: Run tests, confirm green**
- [ ] **Step 4: Commit**
- [x] **Step 1: Add failing tests** — empty, single line, multiple lines; procedure formatting
- [x] **Step 2: Implement**
- [x] **Step 3: Run tests, confirm green**
- [x] **Step 4: Commit**
```bash
git add src/components/ClaimDrawer/ServiceLinesTable.tsx src/components/ClaimDrawer/ServiceLinesTable.test.tsx
@@ -407,10 +407,10 @@ Renders:
- Inline list of code (mono) + qualifier (when present) + description (when available via inline dict)
- Empty state: "No diagnoses" muted text
- [ ] **Step 1: Add failing tests** — empty, single, multiple; qualifier shown when present
- [ ] **Step 2: Implement**
- [ ] **Step 3: Run tests, confirm green**
- [ ] **Step 4: Commit**
- [x] **Step 1: Add failing tests** — empty, single, multiple; qualifier shown when present
- [x] **Step 2: Implement**
- [x] **Step 3: Run tests, confirm green**
- [x] **Step 4: Commit**
```bash
git add src/components/ClaimDrawer/DiagnosesList.tsx src/components/ClaimDrawer/DiagnosesList.test.tsx
@@ -430,10 +430,10 @@ Renders:
- 3 stacked cards (vertical on mobile, 3-col grid on desktop ≥768px)
- Each card: label (10px uppercase), name (16px), NPI/member ID (mono), address when present
- [ ] **Step 1: Add failing tests** — all 3 cards; missing fields gracefully omitted
- [ ] **Step 2: Implement**
- [ ] **Step 3: Run tests, confirm green**
- [ ] **Step 4: Commit**
- [x] **Step 1: Add failing tests** — all 3 cards; missing fields gracefully omitted
- [x] **Step 2: Implement**
- [x] **Step 3: Run tests, confirm green**
- [x] **Step 4: Commit**
```bash
git add src/components/ClaimDrawer/PartiesGrid.tsx src/components/ClaimDrawer/PartiesGrid.test.tsx
@@ -453,10 +453,10 @@ Renders:
- Native `<details>` element (collapsed by default)
- When expanded: monospace pre-formatted list with segments on separate lines, elements joined by `*`
- [ ] **Step 1: Add failing tests** — collapsed by default, toggle expands, segment rendering
- [ ] **Step 2: Implement**
- [ ] **Step 3: Run tests, confirm green**
- [ ] **Step 4: Commit**
- [x] **Step 1: Add failing tests** — collapsed by default, toggle expands, segment rendering
- [x] **Step 2: Implement**
- [x] **Step 3: Run tests, confirm green**
- [x] **Step 4: Commit**
```bash
git add src/components/ClaimDrawer/RawSegmentsPanel.tsx src/components/ClaimDrawer/RawSegmentsPanel.test.tsx
@@ -477,10 +477,10 @@ Renders:
- Card with: remit ID, total paid (big mono), status badge, received date
- "View remittance →" link button that opens the remittance detail (use `window.location` or a navigate handler — keep simple for v1: `window.location.href = \`/remittances?id=${matchedRemittance.id}\`` or trigger an event)
- [ ] **Step 1: Add failing tests** — null returns nothing, populated renders all fields
- [ ] **Step 2: Implement**
- [ ] **Step 3: Run tests, confirm green**
- [ ] **Step 4: Commit**
- [x] **Step 1: Add failing tests** — null returns nothing, populated renders all fields
- [x] **Step 2: Implement**
- [x] **Step 3: Run tests, confirm green**
- [x] **Step 4: Commit**
```bash
git add src/components/ClaimDrawer/MatchedRemitCard.tsx src/components/ClaimDrawer/MatchedRemitCard.test.tsx
@@ -507,10 +507,10 @@ Renders:
- Each row: kind (10px uppercase), ts (mono), optional remittance ID when present
- Empty state: "No history events" muted
- [ ] **Step 1: Add failing tests** — empty, single, multiple; kind-color mapping
- [ ] **Step 2: Implement**
- [ ] **Step 3: Run tests, confirm green**
- [ ] **Step 4: Commit**
- [x] **Step 1: Add failing tests** — empty, single, multiple; kind-color mapping
- [x] **Step 2: Implement**
- [x] **Step 3: Run tests, confirm green**
- [x] **Step 4: Commit**
```bash
git add src/components/ClaimDrawer/StateHistoryTimeline.tsx src/components/ClaimDrawer/StateHistoryTimeline.test.tsx
@@ -536,9 +536,9 @@ export { ClaimDrawerSkeleton } from "./ClaimDrawerSkeleton";
export { ClaimDrawerError } from "./ClaimDrawerError";
```
- [ ] **Step 1: Create the barrel**
- [ ] **Step 2: Run typecheck + tests, confirm green**
- [ ] **Step 3: Commit**
- [x] **Step 1: Create the barrel**
- [x] **Step 2: Run typecheck + tests, confirm green**
- [x] **Step 3: Commit**
```bash
git add src/components/ClaimDrawer/index.ts
@@ -572,10 +572,10 @@ Uses shadcn `Sheet` (or `Dialog`) primitive. Behavior:
- `onNext` / `onPrev`: derives next/prev claim IDs from the `claims` prop (find current index, +1 or -1, wrap), then calls `onNavigate(newId)`
- `onToggleHelp`: passed through to the keyboard hook
- [ ] **Step 1: Add failing tests** — renders null when no claimId, skeleton on loading, error state on error, sections on success, j/k calls onNavigate with the correct next/prev id (including wrap), `?` calls onToggleHelp, ESC calls onClose
- [ ] **Step 2: Implement** — keep this component focused on orchestration; defer visual polish to leaf components
- [ ] **Step 3: Run tests, confirm green**
- [ ] **Step 4: Commit**
- [x] **Step 1: Add failing tests** — renders null when no claimId, skeleton on loading, error state on error, sections on success, j/k calls onNavigate with the correct next/prev id (including wrap), `?` calls onToggleHelp, ESC calls onClose
- [x] **Step 2: Implement** — keep this component focused on orchestration; defer visual polish to leaf components
- [x] **Step 3: Run tests, confirm green**
- [x] **Step 4: Commit**
```bash
git add src/components/ClaimDrawer/ClaimDrawer.tsx src/components/ClaimDrawer/ClaimDrawer.test.tsx
@@ -596,10 +596,10 @@ Wire-up:
- Clicking the dimmed overlay or ESC closes (via `close()`)
- Background list dims to 60% opacity when drawer is open (use a `useState` for `drawerOpen` or derive from `claimId`)
- [ ] **Step 1: Add failing tests** — click row opens drawer; deep link opens on mount; ESC closes; URL clears
- [ ] **Step 2: Wire up the page**
- [ ] **Step 3: Run tests, confirm green**
- [ ] **Step 4: Commit**
- [x] **Step 1: Add failing tests** — click row opens drawer; deep link opens on mount; ESC closes; URL clears
- [x] **Step 2: Wire up the page**
- [x] **Step 3: Run tests, confirm green**
- [x] **Step 4: Commit**
```bash
git add src/pages/Claims.tsx src/pages/Claims.test.tsx
@@ -620,10 +620,10 @@ Renders:
- Lists shortcuts: `j` next, `k` prev, `↑`/`↓` same, `esc` close, `?` toggle help
- Dismisses on any other key or click outside
- [ ] **Step 1: Add failing tests** — renders when open, hidden otherwise, dismiss on close
- [ ] **Step 2: Implement**
- [ ] **Step 3: Run tests, confirm green**
- [ ] **Step 4: Commit**
- [x] **Step 1: Add failing tests** — renders when open, hidden otherwise, dismiss on close
- [x] **Step 2: Implement**
- [x] **Step 3: Run tests, confirm green**
- [x] **Step 4: Commit**
```bash
git add src/components/KeyboardCheatsheet/
@@ -640,8 +640,8 @@ npm run typecheck
Expected: ~15 frontend, ~417 backend + 1 skip. All green.
- [ ] **Step 1: Run all checks**
- [ ] **Step 2: Commit if any changes**
- [x] **Step 1: Run all checks**
- [x] **Step 2: Commit if any changes**
## Phase 5 — Smoke + merge
@@ -662,8 +662,8 @@ Per spec §3.8:
7. Kill servers
8. Commit empty: `git commit --allow-empty -m "smoke: end-to-end SP4 (claim drawer) flow passes"`
- [ ] **Step 1: Run the smoke**
- [ ] **Step 2: Commit**
- [x] **Step 1: Run the smoke**
- [x] **Step 2: Commit**
### Task 25: README + plan doc updates
@@ -671,8 +671,8 @@ Per spec §3.8:
- Modify: `README.md` — mark "Sub-project 4" partially shipped (only per-claim drawer); describe the new feature
- Modify: `docs/superpowers/plans/2026-06-20-cyclone-claim-drawer.md` — tick all `[ ]` to `[x]`
- [ ] **Step 1: Update README + plan doc**
- [ ] **Step 2: Commit**
- [x] **Step 1: Update README + plan doc**
- [x] **Step 2: Commit**
```bash
git add README.md docs/superpowers/plans/2026-06-20-cyclone-claim-drawer.md
@@ -688,10 +688,10 @@ git commit -m "docs: mark SP4 partial shipped (claim drawer); tick all plan chec
5. `git worktree remove /Users/openclaw/dev/cyclone/.worktrees/claim-drawer`
6. `git branch -d claim-drawer`
- [ ] **Step 1: Verify worktree clean**
- [ ] **Step 2: Discard main's stale changes (if any)**
- [ ] **Step 3: Fast-forward merge to main**
- [ ] **Step 4: Remove worktree + delete branch**
- [x] **Step 1: Verify worktree clean**
- [x] **Step 2: Discard main's stale changes (if any)**
- [x] **Step 3: Fast-forward merge to main**
- [x] **Step 4: Remove worktree + delete branch**
## Test count targets
@@ -702,6 +702,13 @@ git commit -m "docs: mark SP4 partial shipped (claim drawer); tick all plan chec
| P2 end | 0 | +5 | 417 / 15 |
| P3 end | 0 | +10 (one per leaf) | 417 / 25 |
| P4 end | 0 | +5 (drawer + page + cheatsheet) | 417 / 30 |
| **Actual final** | **417 + 1 skip** | **124** | **417 / 124** |
(Note: the frontend test count grew well past the conservative target —
every leaf component ended up with its own dedicated test file, and the
drawer root + Claims page wiring + keyboard cheatsheet each gained
their own integration suite. Net new from SP4: 114 frontend tests
across 14 files. Backend matched the +8 estimate exactly.)
## Risk reminders