Commit Graph

515 Commits

Author SHA1 Message Date
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
Tyler 23ac7f6fda feat(frontend): add listUnmatched, matchRemit, unmatchClaim to api 2026-06-19 23:47:34 -06:00
Tyler d4a142aa83 feat(frontend): add ClaimState enum + Match/Unmatched types 2026-06-19 23:45:11 -06:00
Tyler 43a88a356c feat(backend): parse-835 JSON response includes reconciliation summary 2026-06-19 23:42:22 -06:00
Tyler 44fe88d694 feat(backend): POST /api/reconciliation/{match,unmatch} + InvalidStateError 2026-06-19 23:39:20 -06:00
Tyler a4c59587c6 feat(backend): GET /api/reconciliation/unmatched 2026-06-19 23:34:25 -06:00
Tyler 0d172d0682 feat(backend): call db.init_db() before uvicorn starts 2026-06-19 23:31:34 -06:00
Tyler 3318c9418a fix(backend): set Remittance.claim_id symmetrically in reconcile.run
T12's list_unmatched filters Remittance by claim_id IS NULL. T10's
reconcile.run was only setting Claim.matched_remittance_id, leaving
auto-matched remits visible in the orphan bucket. Mirror the FK on
both sides so both list_unmatched filters produce consistent results.

T12 implementer flagged this as out-of-scope; addressed here as a
small follow-up so the Reconciliation page works correctly end-to-end.
2026-06-19 23:28:17 -06:00
Tyler aa7cd7654d feat(backend): implement list_unmatched + manual_match + manual_unmatch 2026-06-19 23:26:16 -06:00
Tyler cf2e52efb8 feat(backend): persist CasAdjustment rows from 835 SVC.adjustments 2026-06-19 23:07:48 -06:00
Tyler 6a65c2b750 fix(backend): spec-bug fixes for T10 — Match.claim_id non-unique + reconcile test dates
Three spec-bug fixes from T10 implementation:

- Match.claim_id: drop UNIQUE constraint (T4 schema error) — reversals add a 2nd row per claim (audit trail). Add explicit non-unique index ix_matches_claim_id to preserve query performance. Mirrored in ORM and migration 0001_initial.sql.
- test_run_orphan_remit_leaves_claim_unmatched: claim PCN-A does not match remit PCN-NEW, so unmatched_claims must be 1, not 0.
- test_run_reversal_flips_paid_to_reversed: claim service_date_from was 9 days before reversal remit service_date (outside default 7-day window) so no match occurred; changed to 5 days apart so match() picks the claim.
- test_match_unique_per_claim: in test_db_models.py asserted the now-removed UNIQUE behavior; renamed and inverted to assert the audit-trail design (two Match rows per claim allowed).
2026-06-19 22:59:20 -06:00
Tyler 8c92ef43bd feat(backend): add reconcile.run orchestrator with match + apply + CAS agg 2026-06-19 22:54:25 -06:00
Tyler c3306b882a chore(backend): move import json to module top in store.py 2026-06-19 22:45:25 -06:00
Tyler c8bc2c73e6 feat(backend): SQLAlchemy-backed CycloneStore (T9)
Replace the in-memory InMemoryStore with a SQLAlchemy-backed
CycloneStore that persists Batch, Claim, Remittance, Match, and
ActivityEvent rows to a configurable DB engine (sqlite by default,
overridable via CYCLONE_DB_URL).

Public API preserved: add / get_batch / iter_claims / iter_remittances
/ distinct_providers / recent_activity. New T10/T12 stubs:
list_unmatched, manual_match, manual_unmatch.

Backward-compat shims for tests that called ._batches.clear() or
acquired ._lock as a context manager.

Idempotency: add() does a per-row session.get(Claim, c.id) (and
s.get(Remittance, ...)) check before each insert; duplicates are
skipped with a warning. This makes re-uploading the same fixture
idempotent instead of raising IntegrityError on the PK.

Auto-init DB fixture (backend/tests/conftest.py) sets
CYCLONE_DB_URL to a per-test sqlite file and calls db.init_db()
once per test, replacing the old module-scoped in-memory fixture.
2026-06-19 22:37:12 -06:00
Tyler 00371248b3 feat(backend): add apply_payment, apply_reversal, split_unmatched pure fns 2026-06-19 22:10:44 -06:00
Tyler c13bbf9190 docs(backend): reconcile Protocol — patient_control_number is Optional[str] 2026-06-19 22:04:30 -06:00
Tyler c30416e68c feat(backend): add reconcile.match with date-window + multi-claim fallback 2026-06-19 21:59:23 -06:00
Tyler 05a49be964 feat(backend): add Match + ActivityEvent ORM models 2026-06-19 21:53:52 -06:00
Tyler 846944448a feat(backend): harden T5 — divergence comment + invariant tests 2026-06-19 21:51:43 -06:00
Tyler 0cc74dc173 feat(backend): add Remittance + CasAdjustment ORM models 2026-06-19 21:47:18 -06:00
Tyler 2019a651ed feat(backend): fix T4 index drift, lazy import, FK policy, expand test coverage 2026-06-19 21:42:11 -06:00
Tyler 0fdb760bc1 docs(backend): update db.py docstring to reflect migrations-first order 2026-06-19 21:36:26 -06:00
Tyler 5be6299b3a feat(backend): add Batch + Claim ORM models + ClaimState enum 2026-06-19 21:36:02 -06:00
Tyler 934d623d3a feat(backend): harden db_migrate — rollback test, non-sql filter test, doc convention 2026-06-19 21:25:15 -06:00
Tyler 1bd2334e40 feat(backend): add PRAGMA user_version migration runner + 0001_initial 2026-06-19 21:19:43 -06:00
Tyler 854078a726 feat(backend): add cyclone.db with engine, SessionLocal, Base, init_db 2026-06-19 21:03:21 -06:00
Tyler 4abc03a003 build(backend): add sqlalchemy>=2.0,<3 dependency 2026-06-19 20:58:57 -06:00