From b7f831e170ef25579366984b4604808f79864974 Mon Sep 17 00:00:00 2001 From: Tyler Date: Sat, 20 Jun 2026 00:11:01 -0600 Subject: [PATCH] docs: tick off completed boxes in sub-project 1 plan (housekeeping) --- ...2026-06-19-cyclone-production-readiness.md | 216 +++++++++--------- 1 file changed, 108 insertions(+), 108 deletions(-) diff --git a/docs/superpowers/plans/2026-06-19-cyclone-production-readiness.md b/docs/superpowers/plans/2026-06-19-cyclone-production-readiness.md index 2f8411f..ae797a5 100644 --- a/docs/superpowers/plans/2026-06-19-cyclone-production-readiness.md +++ b/docs/superpowers/plans/2026-06-19-cyclone-production-readiness.md @@ -1,6 +1,6 @@ # Cyclone Production-Readiness (local-only) Implementation Plan -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [x]`) syntax for tracking. **Goal:** Add a backend in-memory batch store + 6 GET endpoints (with filter/sort/pagination and NDJSON streaming) to the Cyclone EDI suite, wire the existing 4 React pages + Upload page to live data via `@tanstack/react-query` v5, ship 4 fresh reference notes + a root README rewrite, and lock the local-only deploy posture (`127.0.0.1:8000`, no auth, no internet exposure). All on a single branch, with frequent commits, fully testable at every checkpoint. @@ -84,7 +84,7 @@ - Create: `backend/src/cyclone/store.py` - Create: `backend/tests/test_store.py` -- [ ] **Step 1: Write the failing test for `BatchRecord` construction + module import** +- [x] **Step 1: Write the failing test for `BatchRecord` construction + module import** `backend/tests/test_store.py`: ```python @@ -172,12 +172,12 @@ def test_get_missing_returns_none(): > Note: if your `ClaimOutput` / `Envelope` / `ValidationReport` / `ParseResult` model fields differ, adjust the `_make_claim` / `_make_result` stubs to match the real field names. Run `python -c "from cyclone.parsers.models import ClaimOutput; help(ClaimOutput)"` to confirm. -- [ ] **Step 2: Run the test to verify it fails** +- [x] **Step 2: Run the test to verify it fails** Run: `cd backend && .venv/bin/pytest tests/test_store.py -v` Expected: `ModuleNotFoundError: No module named 'cyclone.store'` (or similar import error). -- [ ] **Step 3: Implement `BatchRecord` + empty `InMemoryStore` (no mappers yet)** +- [x] **Step 3: Implement `BatchRecord` + empty `InMemoryStore` (no mappers yet)** `backend/src/cyclone/store.py`: ```python @@ -254,12 +254,12 @@ def utcnow_iso() -> str: > Note: the imports `from cyclone.parsers.models import ParseResult` and `from cyclone.parsers.models_835 import ParseResult835` are correct based on the existing project layout. If the Pydantic v2 union complains about the discriminator, drop the `discriminator=None` and let Pydantic use the default behavior — the actual class is determined at runtime by the field type. -- [ ] **Step 4: Run the tests to verify they pass** +- [x] **Step 4: Run the tests to verify they pass** Run: `cd backend && .venv/bin/pytest tests/test_store.py -v` Expected: all 4 tests pass. -- [ ] **Step 5: Commit** +- [x] **Step 5: Commit** ```bash git add backend/src/cyclone/store.py backend/tests/test_store.py @@ -274,7 +274,7 @@ git commit -m "feat(backend): add cyclone.store with BatchRecord and InMemorySto - Modify: `backend/src/cyclone/store.py` - Modify: `backend/tests/test_store.py` -- [ ] **Step 1: Add failing tests for the mappers** +- [x] **Step 1: Add failing tests for the mappers** Append to `backend/tests/test_store.py`: ```python @@ -359,12 +359,12 @@ def test_to_activity_event_uses_iso_timestamp(): > Adjust stub values to match your actual Pydantic model field names. The important assertions are the `status` mapping rules (submitted/pending/denied) and that the mapper output is a dict with the right shape. -- [ ] **Step 2: Run the test to verify it fails** +- [x] **Step 2: Run the test to verify it fails** Run: `cd backend && .venv/bin/pytest tests/test_store.py -v` Expected: `ImportError: cannot import name 'to_ui_claim' from 'cyclone.store'`. -- [ ] **Step 3: Implement the mappers** +- [x] **Step 3: Implement the mappers** Add to `backend/src/cyclone/store.py` (after `utcnow_iso`): ```python @@ -509,12 +509,12 @@ def to_activity_event( > from cyclone.parsers.models_835 import ClaimPayment, ParseResult835 > ```) -- [ ] **Step 4: Run the tests to verify they pass** +- [x] **Step 4: Run the tests to verify they pass** Run: `cd backend && .venv/bin/pytest tests/test_store.py -v` Expected: all 10 tests pass. -- [ ] **Step 5: Commit** +- [x] **Step 5: Commit** ```bash git add backend/src/cyclone/store.py backend/tests/test_store.py @@ -529,7 +529,7 @@ git commit -m "feat(backend): add store mappers (claim, remittance, provider, ac - Modify: `backend/src/cyclone/store.py` - Modify: `backend/tests/test_store.py` -- [ ] **Step 1: Add failing tests for the iterators** +- [x] **Step 1: Add failing tests for the iterators** Append to `backend/tests/test_store.py`: ```python @@ -595,12 +595,12 @@ def test_recent_activity_returns_newest_first(): assert out[1]["timestamp"] == "2026-06-19T11:00:00Z" ``` -- [ ] **Step 2: Run tests to verify they fail** +- [x] **Step 2: Run tests to verify they fail** Run: `cd backend && .venv/bin/pytest tests/test_store.py -v -k "iter_ or distinct_ or recent_"` Expected: `AttributeError: 'InMemoryStore' object has no attribute 'iter_claims'`. -- [ ] **Step 3: Implement the iterators** +- [x] **Step 3: Implement the iterators** Add to `backend/src/cyclone/store.py` (as methods on `InMemoryStore`): ```python @@ -724,12 +724,12 @@ Add to `backend/src/cyclone/store.py` (as methods on `InMemoryStore`): return events[:limit] ``` -- [ ] **Step 4: Run tests to verify they pass** +- [x] **Step 4: Run tests to verify they pass** Run: `cd backend && .venv/bin/pytest tests/test_store.py -v` Expected: all tests pass (15 total now). -- [ ] **Step 5: Commit** +- [x] **Step 5: Commit** ```bash git add backend/src/cyclone/store.py backend/tests/test_store.py @@ -744,7 +744,7 @@ git commit -m "feat(backend): add store iterators (claims, remits, providers, ac - Modify: `backend/src/cyclone/api.py` - Create: `backend/tests/test_api_parse_persists.py` -- [ ] **Step 1: Add failing tests** +- [x] **Step 1: Add failing tests** `backend/tests/test_api_parse_persists.py`: ```python @@ -807,12 +807,12 @@ def test_failed_parse_837_does_not_create_batch(client: TestClient): assert len(global_store.list()) == 0 ``` -- [ ] **Step 2: Run tests to verify they fail** +- [x] **Step 2: Run tests to verify they fail** Run: `cd backend && .venv/bin/pytest tests/test_api_parse_persists.py -v` Expected: first test fails because `len(global_store.list()) == 1` is False (no batches added yet). -- [ ] **Step 3: Modify `cyclone.api` to call `store.add()` on success** +- [x] **Step 3: Modify `cyclone.api` to call `store.add()` on success** In `backend/src/cyclone/api.py`, add the import near the top: ```python @@ -853,12 +853,12 @@ import uuid > The exact location depends on your existing parse-route structure. The key invariant is: `store.add(record)` is called only after the parser successfully produces a result, and *before* the response is returned. -- [ ] **Step 4: Run tests to verify they pass** +- [x] **Step 4: Run tests to verify they pass** Run: `cd backend && .venv/bin/pytest tests/test_api_parse_persists.py -v` Expected: both tests pass. -- [ ] **Step 5: Commit** +- [x] **Step 5: Commit** ```bash git add backend/src/cyclone/api.py backend/tests/test_api_parse_persists.py @@ -873,7 +873,7 @@ git commit -m "feat(backend): wire parse-837/parse-835 to persist to InMemorySto - Modify: `backend/src/cyclone/api.py` - Modify: `backend/tests/test_api_gets.py` (new) -- [ ] **Step 1: Add failing tests for the batch endpoints** +- [x] **Step 1: Add failing tests for the batch endpoints** `backend/tests/test_api_gets.py`: ```python @@ -962,12 +962,12 @@ def test_get_batch_404_when_missing(client: TestClient): assert resp.status_code == 404 ``` -- [ ] **Step 2: Run tests to verify they fail** +- [x] **Step 2: Run tests to verify they fail** Run: `cd backend && .venv/bin/pytest tests/test_api_gets.py -v` Expected: all 4 tests fail with 404 (routes don't exist yet). -- [ ] **Step 3: Implement the routes** +- [x] **Step 3: Implement the routes** Add to `backend/src/cyclone/api.py`: ```python @@ -1008,12 +1008,12 @@ def get_batch(batch_id: str): return rec.result ``` -- [ ] **Step 4: Run tests to verify they pass** +- [x] **Step 4: Run tests to verify they pass** Run: `cd backend && .venv/bin/pytest tests/test_api_gets.py -v -k "batches"` Expected: 4 tests pass. -- [ ] **Step 5: Commit** +- [x] **Step 5: Commit** ```bash git add backend/src/cyclone/api.py backend/tests/test_api_gets.py @@ -1028,7 +1028,7 @@ git commit -m "feat(backend): add GET /api/batches and GET /api/batches/{id}" - Modify: `backend/src/cyclone/api.py` - Modify: `backend/tests/test_api_gets.py` -- [ ] **Step 1: Add failing tests** +- [x] **Step 1: Add failing tests** Append to `backend/tests/test_api_gets.py`: ```python @@ -1076,12 +1076,12 @@ def test_claims_pagination_limit_offset(seeded_store): assert body1["has_more"] is True ``` -- [ ] **Step 2: Run tests to verify they fail** +- [x] **Step 2: Run tests to verify they fail** Run: `cd backend && .venv/bin/pytest tests/test_api_gets.py -v -k "claims_"` Expected: 404 / Not Found for `/api/claims`. -- [ ] **Step 3: Implement the route** +- [x] **Step 3: Implement the route** Add to `backend/src/cyclone/api.py`: ```python @@ -1115,12 +1115,12 @@ def list_claims( } ``` -- [ ] **Step 4: Run tests to verify they pass** +- [x] **Step 4: Run tests to verify they pass** Run: `cd backend && .venv/bin/pytest tests/test_api_gets.py -v -k "claims_"` Expected: 5 tests pass. -- [ ] **Step 5: Commit** +- [x] **Step 5: Commit** ```bash git add backend/src/cyclone/api.py backend/tests/test_api_gets.py @@ -1135,7 +1135,7 @@ git commit -m "feat(backend): add GET /api/claims with filter/sort/pagination" - Modify: `backend/src/cyclone/api.py` - Modify: `backend/tests/test_api_gets.py` -- [ ] **Step 1: Add failing tests** +- [x] **Step 1: Add failing tests** Append to `backend/tests/test_api_gets.py`: ```python @@ -1198,12 +1198,12 @@ def test_activity_returns_one_event_per_claim(seeded_store): assert all(e["kind"] == "claim_submitted" for e in body["items"]) ``` -- [ ] **Step 2: Run tests to verify they fail** +- [x] **Step 2: Run tests to verify they fail** Run: `cd backend && .venv/bin/pytest tests/test_api_gets.py -v -k "remittances_ or providers_ or activity_"` Expected: 6 tests fail with 404. -- [ ] **Step 3: Implement the three routes** +- [x] **Step 3: Implement the three routes** Add to `backend/src/cyclone/api.py`: ```python @@ -1269,12 +1269,12 @@ def list_activity( } ``` -- [ ] **Step 4: Run tests to verify they pass** +- [x] **Step 4: Run tests to verify they pass** Run: `cd backend && .venv/bin/pytest tests/test_api_gets.py -v -k "remittances_ or providers_ or activity_"` Expected: 6 tests pass. -- [ ] **Step 5: Commit** +- [x] **Step 5: Commit** ```bash git add backend/src/cyclone/api.py backend/tests/test_api_gets.py @@ -1289,7 +1289,7 @@ git commit -m "feat(backend): add GET /api/{remittances,providers,activity}" - Modify: `backend/src/cyclone/api.py` - Create: `backend/tests/test_api_streaming.py` -- [ ] **Step 1: Add failing test** +- [x] **Step 1: Add failing test** `backend/tests/test_api_streaming.py`: ```python @@ -1346,12 +1346,12 @@ def test_claims_ndjson_returns_parseable_lines(seeded_client): assert summary["data"]["has_more"] is False ``` -- [ ] **Step 2: Run test to verify it fails** +- [x] **Step 2: Run test to verify it fails** Run: `cd backend && .venv/bin/pytest tests/test_api_streaming.py -v` Expected: response is JSON, not NDJSON — content-type assertion fails. -- [ ] **Step 3: Implement streaming on `/api/claims` (and apply the same pattern to remittances/providers/activity)** +- [x] **Step 3: Implement streaming on `/api/claims` (and apply the same pattern to remittances/providers/activity)** In `backend/src/cyclone/api.py`, refactor `list_claims` to content-negotiate: @@ -1405,12 +1405,12 @@ def list_claims( Apply the same pattern to `list_remittances`, `list_providers`, and `list_activity` (each branches on `request.headers.get("accept") == "application/x-ndjson"` and returns `StreamingResponse` when set). -- [ ] **Step 4: Run test to verify it passes** +- [x] **Step 4: Run test to verify it passes** Run: `cd backend && .venv/bin/pytest tests/test_api_streaming.py -v` Expected: test passes. -- [ ] **Step 5: Commit** +- [x] **Step 5: Commit** ```bash git add backend/src/cyclone/api.py backend/tests/test_api_streaming.py @@ -1424,7 +1424,7 @@ git commit -m "feat(backend): add NDJSON streaming on list endpoints" **Files:** - Modify: `backend/src/cyclone/__main__.py` -- [ ] **Step 1: Update `__main__.py` to bind loopback and honor env vars** +- [x] **Step 1: Update `__main__.py` to bind loopback and honor env vars** Replace `backend/src/cyclone/__main__.py` with: ```python @@ -1470,7 +1470,7 @@ if __name__ == "__main__": main() ``` -- [ ] **Step 2: Verify locally (manual)** +- [x] **Step 2: Verify locally (manual)** Run: `cd backend && .venv/bin/python -m cyclone serve &` Then: `curl -s http://127.0.0.1:8000/api/health | jq .` → should print `{"status": "ok", "version": "0.1.0"}`. @@ -1478,7 +1478,7 @@ Then: `curl -s http://0.0.0.0:8000/api/health` → should fail (refused; loopbac Kill the server: `kill %1` (or `pkill -f 'cyclone.api:app'`). -- [ ] **Step 3: Commit** +- [x] **Step 3: Commit** ```bash git add backend/src/cyclone/__main__.py @@ -1489,12 +1489,12 @@ git commit -m "feat(backend): bind serve to 127.0.0.1:8000, honor CYCLONE_PORT/C ### Task 10: Run the full backend test suite + manual smoke -- [ ] **Step 1: Run all backend tests** +- [x] **Step 1: Run all backend tests** Run: `cd backend && .venv/bin/pytest -v` Expected: all tests pass (existing 121 + new ~23 = 144+ total). -- [ ] **Step 2: Manual smoke (in two terminals)** +- [x] **Step 2: Manual smoke (in two terminals)** Terminal 1: `cd backend && .venv/bin/python -m cyclone serve` Terminal 2: `curl -s -X POST -F "file=@backend/tests/fixtures/co_medicaid_837p.txt" -H "Accept: application/json" http://127.0.0.1:8000/api/parse-837 | jq .summary` @@ -1502,7 +1502,7 @@ Then: `curl -s 'http://127.0.0.1:8000/api/claims?status=submitted' | jq '{total, Then: `curl -s 'http://127.0.0.1:8000/api/claims' -H 'Accept: application/x-ndjson' | head -4` Expected: parse succeeds; `/api/claims` returns 2 items; NDJSON returns 2 item lines + 1 summary line. -- [ ] **Step 3: Commit any leftover changes (likely none)** +- [x] **Step 3: Commit any leftover changes (likely none)** ```bash git status # should be clean @@ -1517,12 +1517,12 @@ git status # should be clean **Files:** - Modify: `package.json` -- [ ] **Step 1: Add the dep** +- [x] **Step 1: Add the dep** Run: `cd /Users/openclaw/dev/cyclone && npm install @tanstack/react-query@^5.59.0` Expected: `package.json` updated; `node_modules` grows. -- [ ] **Step 2: Commit** +- [x] **Step 2: Commit** ```bash git add package.json package-lock.json @@ -1536,7 +1536,7 @@ git commit -m "feat(frontend): add @tanstack/react-query ^5.59.0" **Files:** - Modify: `src/main.tsx` -- [ ] **Step 1: Update `main.tsx`** +- [x] **Step 1: Update `main.tsx`** Replace `src/main.tsx` with: ```tsx @@ -1567,12 +1567,12 @@ ReactDOM.createRoot(document.getElementById("root")!).render( ); ``` -- [ ] **Step 2: Verify build still passes** +- [x] **Step 2: Verify build still passes** Run: `npm run build` Expected: build succeeds with no TS errors. -- [ ] **Step 3: Commit** +- [x] **Step 3: Commit** ```bash git add src/main.tsx @@ -1586,7 +1586,7 @@ git commit -m "feat(frontend): wrap App in QueryClientProvider" **Files:** - Modify: `tailwind.config.js` -- [ ] **Step 1: Add the keyframes** +- [x] **Step 1: Add the keyframes** In `tailwind.config.js`, inside `theme.extend.keyframes`, add three new entries (next to the existing `fade-in`): ```js @@ -1605,7 +1605,7 @@ In `tailwind.config.js`, inside `theme.extend.keyframes`, add three new entries }, ``` -- [ ] **Step 2: Commit** +- [x] **Step 2: Commit** ```bash git add tailwind.config.js @@ -1619,7 +1619,7 @@ git commit -m "feat(frontend): add shimmer, scan, row-flash keyframes" **Files:** - Create: `src/components/ui/skeleton.tsx` -- [ ] **Step 1: Create the file** +- [x] **Step 1: Create the file** `src/components/ui/skeleton.tsx`: ```tsx @@ -1679,12 +1679,12 @@ export function Skeleton({ className, variant = "row" }: SkeletonProps) { } ``` -- [ ] **Step 2: Verify build** +- [x] **Step 2: Verify build** Run: `npm run build` Expected: passes. -- [ ] **Step 3: Commit** +- [x] **Step 3: Commit** ```bash git add src/components/ui/skeleton.tsx @@ -1698,7 +1698,7 @@ git commit -m "feat(frontend): add Skeleton UI primitive (hairline + scanline-sh **Files:** - Create: `src/components/ui/empty-state.tsx` -- [ ] **Step 1: Create the file** +- [x] **Step 1: Create the file** `src/components/ui/empty-state.tsx`: ```tsx @@ -1726,7 +1726,7 @@ export function EmptyState({ eyebrow, message }: EmptyStateProps) { } ``` -- [ ] **Step 2: Verify build + commit** +- [x] **Step 2: Verify build + commit** ```bash npm run build @@ -1741,7 +1741,7 @@ git commit -m "feat(frontend): add EmptyState primitive (instrument-label eyebro **Files:** - Create: `src/components/ui/error-state.tsx` -- [ ] **Step 1: Create the file** +- [x] **Step 1: Create the file** `src/components/ui/error-state.tsx`: ```tsx @@ -1776,7 +1776,7 @@ export function ErrorState({ error, onRetry }: ErrorStateProps) { } ``` -- [ ] **Step 2: Verify build + commit** +- [x] **Step 2: Verify build + commit** ```bash npm run build @@ -1791,7 +1791,7 @@ git commit -m "feat(frontend): add ErrorState primitive (destructive hairline + **Files:** - Create: `src/components/ui/filter-chips.tsx` -- [ ] **Step 1: Create the file** +- [x] **Step 1: Create the file** `src/components/ui/filter-chips.tsx`: ```tsx @@ -1847,7 +1847,7 @@ export function FilterChips({ } ``` -- [ ] **Step 2: Verify build + commit** +- [x] **Step 2: Verify build + commit** ```bash npm run build @@ -1862,7 +1862,7 @@ git commit -m "feat(frontend): add FilterChips primitive (read-only pill row)" **Files:** - Create: `src/components/ui/pagination.tsx` -- [ ] **Step 1: Create the file** +- [x] **Step 1: Create the file** `src/components/ui/pagination.tsx`: ```tsx @@ -1951,7 +1951,7 @@ export function Pagination({ page, pageSize, total, onChange }: PaginationProps) } ``` -- [ ] **Step 2: Verify build + commit** +- [x] **Step 2: Verify build + commit** ```bash npm run build @@ -1966,7 +1966,7 @@ git commit -m "feat(frontend): add Pagination primitive (nav-active echo, num pa **Files:** - Modify: `src/components/Layout.tsx` -- [ ] **Step 1: Update `Layout.tsx`** +- [x] **Step 1: Update `Layout.tsx`** Replace `src/components/Layout.tsx` with: ```tsx @@ -2000,7 +2000,7 @@ export function Layout() { } ``` -- [ ] **Step 2: Verify build + commit** +- [x] **Step 2: Verify build + commit** ```bash npm run build @@ -2016,7 +2016,7 @@ git commit -m "feat(frontend): add 1px scan-line refetch indicator to Layout" - Modify: `src/lib/api.ts` - Create: `src/lib/api.test.ts` (extend with 3 tests) -- [ ] **Step 1: Add GET methods + types** +- [x] **Step 1: Add GET methods + types** In `src/lib/api.ts`, before the `export const api = {` line, add: ```ts @@ -2174,7 +2174,7 @@ export const api = { }; ``` -- [ ] **Step 2: Add 3 unit tests in `src/lib/api.test.ts`** +- [x] **Step 2: Add 3 unit tests in `src/lib/api.test.ts`** Create `src/lib/api.test.ts`: ```ts @@ -2233,12 +2233,12 @@ describe("api GET helpers", () => { > If `vitest` is not already configured, add `"test": "vitest run"` to `package.json` `scripts` and `vitest` to devDependencies. Run `npm install -D vitest` if needed. -- [ ] **Step 3: Run the tests** +- [x] **Step 3: Run the tests** Run: `npm test -- src/lib/api.test.ts` Expected: 3 tests pass. -- [ ] **Step 4: Commit** +- [x] **Step 4: Commit** ```bash git add src/lib/api.ts src/lib/api.test.ts package.json package-lock.json @@ -2257,7 +2257,7 @@ git commit -m "feat(frontend): add listBatches/getBatch/listClaims/listRemittanc - Create: `src/hooks/useActivity.ts` - Create: `src/hooks/useParse.ts` -- [ ] **Step 1: `useBatches.ts`** +- [x] **Step 1: `useBatches.ts`** ```ts import { useQuery } from "@tanstack/react-query"; @@ -2272,7 +2272,7 @@ export function useBatches() { } ``` -- [ ] **Step 2: `useClaims.ts`** (with fallback to zustand when `!api.isConfigured`) +- [x] **Step 2: `useClaims.ts`** (with fallback to zustand when `!api.isConfigured`) ```ts import { useQuery } from "@tanstack/react-query"; @@ -2327,7 +2327,7 @@ export function useClaims(params: ListClaimsParams) { export { EMPTY as EMPTY_CLAIMS }; ``` -- [ ] **Step 3: `useRemittances.ts`** +- [x] **Step 3: `useRemittances.ts`** ```ts import { useQuery } from "@tanstack/react-query"; @@ -2367,7 +2367,7 @@ export function useRemittances(params: ListRemittancesParams) { } ``` -- [ ] **Step 4: `useProviders.ts`** +- [x] **Step 4: `useProviders.ts`** ```ts import { useQuery } from "@tanstack/react-query"; @@ -2400,7 +2400,7 @@ export function useProviders(params: ListProvidersParams = {}) { } ``` -- [ ] **Step 5: `useActivity.ts`** +- [x] **Step 5: `useActivity.ts`** ```ts import { useQuery } from "@tanstack/react-query"; @@ -2434,7 +2434,7 @@ export function useActivity(params: ListActivityParams = {}) { } ``` -- [ ] **Step 6: `useParse.ts`** +- [x] **Step 6: `useParse.ts`** ```ts import { useMutation, useQueryClient } from "@tanstack/react-query"; @@ -2458,7 +2458,7 @@ export function useParse(kind: "837p" | "835") { } ``` -- [ ] **Step 7: Verify build + commit** +- [x] **Step 7: Verify build + commit** ```bash npm run build @@ -2473,7 +2473,7 @@ git commit -m "feat(frontend): add 6 query/mutation hooks (batches, claims, remi **Files:** - Modify: `src/pages/Claims.tsx` -- [ ] **Step 1: Replace the file** +- [x] **Step 1: Replace the file** Replace `src/pages/Claims.tsx` with: ```tsx @@ -2779,7 +2779,7 @@ export function Claims() { } ``` -- [ ] **Step 2: Verify build + commit** +- [x] **Step 2: Verify build + commit** ```bash npm run build @@ -2794,7 +2794,7 @@ git commit -m "feat(frontend): refactor Claims page to useClaims + skeleton/empt **Files:** - Modify: `src/pages/Remittances.tsx` -- [ ] **Step 1: Replace the file** +- [x] **Step 1: Replace the file** Replace `src/pages/Remittances.tsx` with: ```tsx @@ -2945,7 +2945,7 @@ export function Remittances() { } ``` -- [ ] **Step 2: Verify build + commit** +- [x] **Step 2: Verify build + commit** ```bash npm run build @@ -2960,7 +2960,7 @@ git commit -m "feat(frontend): refactor Remittances page to useRemittances + UX **Files:** - Modify: `src/pages/Providers.tsx` -- [ ] **Step 1: Replace the file** +- [x] **Step 1: Replace the file** Replace `src/pages/Providers.tsx` with: ```tsx @@ -3068,7 +3068,7 @@ export function Providers() { } ``` -- [ ] **Step 2: Verify build + commit** +- [x] **Step 2: Verify build + commit** ```bash npm run build @@ -3083,7 +3083,7 @@ git commit -m "feat(frontend): refactor Providers page to useProviders + UX patt **Files:** - Modify: `src/pages/ActivityLog.tsx` -- [ ] **Step 1: Replace the file** +- [x] **Step 1: Replace the file** Replace `src/pages/ActivityLog.tsx` with: ```tsx @@ -3136,7 +3136,7 @@ export function ActivityLog() { } ``` -- [ ] **Step 2: Verify build + commit** +- [x] **Step 2: Verify build + commit** ```bash npm run build @@ -3151,7 +3151,7 @@ git commit -m "feat(frontend): refactor ActivityLog page to useActivity + UX pat **Files:** - Modify: `src/pages/Upload.tsx` -- [ ] **Step 1: Replace the file** +- [x] **Step 1: Replace the file** Replace `src/pages/Upload.tsx` with: ```tsx @@ -3592,7 +3592,7 @@ export function Upload() { } ``` -- [ ] **Step 2: Verify build + commit** +- [x] **Step 2: Verify build + commit** ```bash npm run build @@ -3604,17 +3604,17 @@ git commit -m "feat(frontend): refactor Upload page to use useParse mutation" ### Task 27: Run frontend smoke (build + dev server check) -- [ ] **Step 1: Build** +- [x] **Step 1: Build** Run: `npm run build` Expected: passes (no TS errors, no unused-import warnings). -- [ ] **Step 2: Type-check** +- [x] **Step 2: Type-check** Run: `npm run typecheck` Expected: passes. -- [ ] **Step 3: Commit any fixups (likely none)** +- [x] **Step 3: Commit any fixups (likely none)** ```bash git status # should be clean @@ -3629,7 +3629,7 @@ git status # should be clean **Files:** - Create: `docs/reference/837p.md` -- [ ] **Step 1: Create the file** +- [x] **Step 1: Create the file** ```markdown # 837P — Professional Claims (005010X222A1) @@ -3699,7 +3699,7 @@ full walker. | `R300_subscriber_present` | error | `NM1*IL` (subscriber) present | ``` -- [ ] **Step 2: Commit** +- [x] **Step 2: Commit** ```bash git add docs/reference/837p.md @@ -3713,7 +3713,7 @@ git commit -m "docs: add 837p reference note" **Files:** - Create: `docs/reference/835.md` -- [ ] **Step 1: Create the file** +- [x] **Step 1: Create the file** ```markdown # 835 — Electronic Remittance Advice (005010X221A1) @@ -3791,7 +3791,7 @@ date of service is deferred to sub-project 2. Cyclone currently stores the 835 output as-is. ``` -- [ ] **Step 2: Commit** +- [x] **Step 2: Commit** ```bash git add docs/reference/835.md @@ -3805,7 +3805,7 @@ git commit -m "docs: add 835 reference note" **Files:** - Create: `docs/reference/x12naming.md` -- [ ] **Step 1: Create the file** +- [x] **Step 1: Create the file** ```markdown # X12 naming conventions @@ -3876,7 +3876,7 @@ rest of the file by those characters. - `^` — repetition separator ``` -- [ ] **Step 2: Commit** +- [x] **Step 2: Commit** ```bash git add docs/reference/x12naming.md @@ -3890,7 +3890,7 @@ git commit -m "docs: add x12 naming reference note" **Files:** - Create: `docs/reference/co-medicaid.md` -- [ ] **Step 1: Create the file** +- [x] **Step 1: Create the file** ```markdown # Colorado Medicaid — payer specifics @@ -3966,7 +3966,7 @@ The pattern is: 4. Update this note + the 837p/835 notes with the new payer's specifics. ``` -- [ ] **Step 2: Commit** +- [x] **Step 2: Commit** ```bash git add docs/reference/co-medicaid.md @@ -3980,7 +3980,7 @@ git commit -m "docs: add CO Medicaid reference note" **Files:** - Modify: `README.md` -- [ ] **Step 1: Replace the file** +- [x] **Step 1: Replace the file** Replace `README.md` (root) with: ```markdown @@ -4103,7 +4103,7 @@ No license file yet; this is internal-use software. Add a `LICENSE` file when one is decided. ``` -- [ ] **Step 2: Commit** +- [x] **Step 2: Commit** ```bash git add README.md @@ -4116,22 +4116,22 @@ git commit -m "docs: rewrite root README for sub-project 1" ### Task 33: End-to-end smoke test (manual + documented) -- [ ] **Step 1: Start the backend** +- [x] **Step 1: Start the backend** Terminal 1: `cd backend && .venv/bin/python -m cyclone serve` Expected: log line "Uvicorn running on http://127.0.0.1:8000". -- [ ] **Step 2: Confirm loopback-only** +- [x] **Step 2: Confirm loopback-only** Terminal 2: `curl -s http://127.0.0.1:8000/api/health | jq .` → `{"status": "ok", "version": "0.1.0"}`. Then: `curl -s http://0.0.0.0:8000/api/health` → connection refused. -- [ ] **Step 3: Start the frontend** +- [x] **Step 3: Start the frontend** Terminal 3: `npm run dev` Expected: "Local: http://localhost:5173". -- [ ] **Step 4: Drop a fixture file and verify live data flow** +- [x] **Step 4: Drop a fixture file and verify live data flow** 1. Open `http://localhost:5173/upload` in a browser. 2. Drop `backend/tests/fixtures/co_medicaid_837p.txt` on the upload zone. @@ -4143,18 +4143,18 @@ Expected: "Local: http://localhost:5173". 8. Apply `Status: submitted` filter on `/claims`. Expect: the same 2 rows; the `FilterChips` row shows "Status: submitted ×". 9. Watch the top of `
` while navigating back to `/upload` and re-parsing — the 1px scan-line indicator should appear briefly. -- [ ] **Step 5: Verify NDJSON streaming** +- [x] **Step 5: Verify NDJSON streaming** Terminal 2: `curl -s -N -H 'Accept: application/x-ndjson' http://127.0.0.1:8000/api/claims | head -5` Expected: 2 lines of `{"type":"item",…}` + 1 line of `{"type":"summary",…}`. -- [ ] **Step 6: Stop the backend and verify the UI reverts to the fallback** +- [x] **Step 6: Stop the backend and verify the UI reverts to the fallback** Kill terminal 1 (`Ctrl+C`). Refresh the browser. Expect: the pages still render (using the zustand fallback via the existing `data` adapter), but the upload page shows "No backend configured". -- [ ] **Step 7: Final commit (likely none)** +- [x] **Step 7: Final commit (likely none)** ```bash git status # should be clean