Commit Graph

141 Commits

Author SHA1 Message Date
Tyler 436cbead11 feat(frontend): ClaimDrawer root orchestrator with skeleton/error/data states 2026-06-20 12:00:27 -06:00
Tyler 7117f75764 feat(frontend): ClaimDrawer barrel export 2026-06-20 11:50:44 -06:00
Tyler 3fec07ca4d style(frontend): tidy drawer review nits
- RawSegmentsPanel: summary now reads 'Show N raw segments' for
  non-empty (with singular pluralization). The previous identical
  ternary branches read as a bug.
- PartiesGrid: replace the verbose intersection cast on AddressBlock
  with a direct ClaimDetailAddress cast (the union's other arm is
  Record<string, never>, ruled out by isEmptyAddress above).
2026-06-20 11:49:18 -06:00
Tyler dc89244100 feat(frontend): StateHistoryTimeline with kind-colored dots 2026-06-20 11:43:49 -06:00
Tyler 1671e96a10 feat(frontend): MatchedRemitCard with view-remittance link 2026-06-20 11:41:30 -06:00
Tyler 7c7e724464 feat(frontend): RawSegmentsPanel collapsible debug aid 2026-06-20 11:39:59 -06:00
Tyler 94a39e9dd6 feat(frontend): PartiesGrid with billing provider/subscriber/payer cards 2026-06-20 11:38:51 -06:00
Tyler 042597217f feat(frontend): DiagnosesList with qualifier + code formatting 2026-06-20 11:34:00 -06:00
Tyler 7f389fe04b feat(frontend): ServiceLinesTable with procedure + charge columns 2026-06-20 11:29:10 -06:00
Tyler 19b2eb7eaa fix(frontend): announce blocking validation errors via role=alert
ClaimDrawerError.tsx already wraps its error surface with role=alert
(line 36). Apply the same pattern to the ValidationPanel errors
sub-section so assistive tech announces blocking validation failures
when the drawer opens, matching the established sibling pattern.

Warnings stay decorative (no role change) — they're advisories, not
blocks.
2026-06-20 11:25:28 -06:00
Tyler 88da603c9b feat(frontend): ValidationPanel with rule-grouped errors + warnings 2026-06-20 11:21:54 -06:00
Tyler 702104c26d test(frontend): cover all 6 states in ClaimDrawerHeader badge variant matrix
The parametrized variant test only exercised 4 of the 6 mapped states
(submitted/denied/paid/pending). Add accepted (-> default) and matched
(-> success) so the entire STATE_VARIANT map is verified, not just the
branches whose tokens happened to be easy to reach.
2026-06-20 11:18:50 -06:00
Tyler 8933596c77 feat(frontend): ClaimDrawerHeader with state badge + close button 2026-06-20 11:15:49 -06:00
Tyler 67653f0da8 feat(frontend): ClaimDrawer skeleton + error states 2026-06-20 11:09:41 -06:00
Tyler 7dbcba8fa3 feat(frontend): Modern palette CSS variables + Inter Tight/JetBrains Mono fonts 2026-06-20 10:57:46 -06:00
Tyler 24d13faca7 fix(frontend): type pushState mocks with real History.pushState signature
- npm run typecheck failed on the 0-arg vi.fn<() => void>() because
  mock.calls[0] became an empty tuple, so calls[0][2] (the URL arg)
  was typed as undefined.
- Constrain the mock to the real (state, unused, url?) signature so
  mock.calls[0] is a 3-tuple and [2] is string-or-URL-or-null. Drops
  the as-string cast at every callsite.
2026-06-20 10:55:03 -06:00
Tyler e7469d39ec fix(frontend): normalize empty ?claim= to null; preserve sibling params
- readClaimId: URLSearchParams.get returns '' for ?claim=, not null.
  Normalize to null so the contract matches the JSDoc and consumers
  can treat empty as absent.

- Tests: regression for ?claim= → null; open/close preserves other
  query params (?foo=bar survives open/close unchanged).

- Tighten pushStateMock/replaceStateMock typing to vi.fn<() => void>()
  per code-review nit (drops the verbose ReturnType<typeof vi.fn>).
2026-06-20 10:52:42 -06:00
Tyler 234cd8b28b feat(frontend): useDrawerUrlState hook for ?claim= sync 2026-06-20 10:39:53 -06:00
Tyler c737bd742d feat(frontend): useDrawerKeyboard hook for j/k/esc/? 2026-06-20 10:23:40 -06:00
Tyler 1dfd4b58c0 feat(frontend): useClaimDetail hook with null-id short-circuit 2026-06-20 10:12:10 -06:00
Tyler 44e1c4616d feat(frontend): ClaimDetail type + api.getClaimDetail 2026-06-20 10:01:40 -06:00
Tyler b984c01d9a test(sp4): phase 1 backend complete 2026-06-20 09:56:48 -06:00
Tyler 14d61f82b8 test(api)+docs: assert matchedRemittance=null; fail-loud on fixture drift; tighten docstring 2026-06-20 09:56:24 -06:00
Tyler 129599f0f4 feat(api): GET /api/claims/{claim_id} returns full claim context 2026-06-20 09:43:08 -06:00
Tyler 7d0e76150b fix(store): drop dead defensive guard in get_claim_detail (FK guarantees batch exists) 2026-06-20 09:30:42 -06:00
Tyler 423415ab64 feat(store): get_claim_detail returns full claim context with history + matched remit 2026-06-20 09:21:07 -06:00
Tyler bdc851f0f0 docs(sp4): per-claim detail drawer implementation plan (24 tasks, 5 phases) 2026-06-20 08:55:49 -06:00
Tyler 25cd785e62 docs(sp4): per-claim detail drawer design spec + gitignore superpowers dir 2026-06-20 08:44:20 -06:00
Tyler a1dc8a59f7 smoke: end-to-end SP3 flow passes 2026-06-20 08:27:36 -06:00
Tyler 446a02d0a2 docs: mark SP3 shipped; tick all plan checkboxes 2026-06-20 08:25:15 -06:00
Tyler a665881d24 feat(parsers+api): 270/271 eligibility request + response (SP3 P4)
Adds API-only 270/271 eligibility flow per spec section 3.4 (no UI, no
DB persistence). Operator pastes a 270 query, gets back raw 270 text,
submits manually, pastes the 271 back.

New models (270 + 271):
  - InformationSource, InformationReceiver, Subscriber, Patient
  - EligibilityBenefitInquiry (EQ) and CoverageBenefit (EB)
  - Inline SERVICE_TYPE_CODES dict (566 codes, snapshot 2026-06-20)
  - service_type_description() lookup helper

Parsers (single segment walker, defensive, mirrors 835 pattern):
  - parse_270: HL*20/21/22/23 loops + EQ, NM1, DMG, TRN
  - parse_271: HL*20/21/22/23 loops + EB, DTP, MSG, AAA

Serializer:
  - serialize_270: ISA/GS/ST/BHT/HL*20/21/22/patient/EQ/SE/GE/IEA
  - round-trips: serialize -> parse -> serialize == identical

API:
  - POST /api/eligibility/request (JSON body -> {raw_270_text, parsed})
  - POST /api/eligibility/parse-271 (file upload -> structured summary)
  - 400 on missing fields / garbage; never 500.

Tests: 365 -> 408 backend (+43 new), 10 frontend unchanged.
TypeScript clean.
2026-06-20 08:22:31 -06:00
Tyler f3002e4cbe fix(api): regenerate raw_999_text in /api/acks/{id} detail response (SP3 P3 follow-up)
The P3 subagent shipped a Download button on /acks that fell back to
'no raw text' because the detail endpoint returned raw_json (the parsed
model dump) but never the regenerated X12.

Fix: detail endpoint now re-serializes raw_json via serialize_999 and
returns it as raw_999_text, so the operator can actually download the
999 file. List endpoint unchanged (keeps payload small).
2026-06-20 08:06:21 -06:00
Tyler fb2a98fc7a feat(parsers+api+ui+db): 999 ACK transaction set end-to-end (SP3 P3) 2026-06-20 08:03:37 -06:00
Tyler 7a20f732f2 fix(api): include adjustments array in /api/remittances list response (SP3 P2 follow-up)
The P2 subagent shipped a UI chevron+expansion in Remittances.tsx that
read adjustments from the list payload, but iter_remittances() didn't
include the CasAdjustment rows. Result: the expansion was always empty
when a remittance was opened from the list (the detail endpoint worked).

Fix: bulk-fetch all CasAdjustment rows for the remittance_ids in one
query, then attach them as the 'adjustments' array. N+1-free.
2026-06-20 07:49:20 -06:00
Tyler 2a853857b1 feat(parsers+api+ui): expose CARC-labeled CAS adjustments (SP3 P2) 2026-06-20 07:44:41 -06:00
Tyler 76eb33e029 chore(backend): track uv.lock for reproducible installs 2026-06-20 07:26:27 -06:00
Tyler 716bfb0a26 feat(parsers): R034 REF*G1 enforcement + R035 BHT06 transaction type code (SP3 P1)
- R034 _r034_ref_g1_required: when payer opts in (require_ref_g1_for_adjustments),
  emit error if frequency_code is 7/8 and no REF*G1 segment appears in raw_segments.
  CO Medicaid stays lenient in v1 (gate is False by default).
- R035 _r035_bht06_allowed: BHT06 transaction type code must be in cfg.allowed_bht06.
  Skipped silently when transaction_type_code is None.
- Add transaction_type_code (str|None) to Envelope and ClaimOutput.
- parse_837: read BHT06 (seg[6]) in _build_envelope; mirror onto each ClaimOutput
  via the existing model_copy(update={...}) call site.
- 9 new tests in test_validator.py: 5 R034 (incl. lenient no-op) + 4 R035.
  213 passed, 1 skipped (prodfile corpus present-conditional).
2026-06-20 07:25:29 -06:00
Tyler 763ca3d758 docs(sp3): put transaction_type_code on ClaimOutput (mirrors envelope convention) 2026-06-20 07:18:16 -06:00
Tyler 467087d683 docs(sp3): fix rule IDs (R034/R035) and BHT06 naming in plan+spec 2026-06-20 07:18:03 -06:00
Tyler b47818883a docs: add EDI features spec + implementation plan (sub-project 3, 30 tasks) 2026-06-20 07:14:14 -06:00
Tyler 8a289b8e80 smoke: end-to-end DB + reconciliation flow passes (sub-project 2) 2026-06-20 00:11:52 -06:00
Tyler b7f831e170 docs: tick off completed boxes in sub-project 1 plan (housekeeping) 2026-06-20 00:11:01 -06:00
Tyler 6ffa5e8c72 docs: document CYCLONE_DB_URL, backup recipe, sub-project 2 completion 2026-06-20 00:10:27 -06:00
Tyler 1de6e2e60b feat(frontend): /reconciliation page with two-column matching UI 2026-06-20 00:08:39 -06:00
Tyler 5a5f611c2f chore(frontend): exclude .worktrees from vitest discovery 2026-06-20 00:04:44 -06:00
Tyler 8412bdc090 feat(frontend): sidebar Reconciliation nav entry with badge count 2026-06-20 00:04:30 -06:00
Tyler 99c8635178 feat(frontend): render real adjustmentAmount on Remittances page 2026-06-20 00:03:56 -06:00
Tyler 35ffe31447 refactor(frontend): StatusBadge delegates to ClaimStateBadge; Claims uses API state 2026-06-20 00:03:23 -06:00
Tyler 5ddbbcfc2a feat(frontend): ClaimStateBadge primitive (7 states, same palette) 2026-06-20 00:02:36 -06:00
Tyler e8c251f9ca feat(frontend): useReconciliation hook with react-query invalidation cascade 2026-06-19 23:58:00 -06:00