Files
stack/notebooks/bcda_v3_sandbox.py
kert a05cc51916
Some checks failed
Infra CI / notebooks (push) Successful in 1m6s
CI / lint (push) Successful in 46s
CI / notebooks-smoke (push) Successful in 1m44s
CI / test (push) Failing after 2m36s
Infra CI / zotero (push) Successful in 21s
Infra CI / llm (push) Successful in 55s
Infra CI / bcda (push) Successful in 1m38s
Infra CI / docs (push) Successful in 1m46s
Infra CI / api (push) Successful in 1m8s
Infra CI / mc (push) Failing after 36s
CI / lint (pull_request) Successful in 43s
CI / test (pull_request) Failing after 2m30s
Infra CI / zotero (pull_request) Successful in 15s
Infra CI / llm (pull_request) Successful in 16s
CI / notebooks-smoke (pull_request) Successful in 1m52s
Infra CI / docs (pull_request) Successful in 15s
Infra CI / api (pull_request) Successful in 15s
Infra CI / notebooks (pull_request) Successful in 49s
Infra CI / bcda (pull_request) Successful in 18s
Infra CI / mc (pull_request) Failing after 35s
feat(bcda): incremental _since pulls — watermarks, temporality checks, reconciliation with tiebreakers, ledger and invariants
Design: docs/superpowers/specs/2026-10-25-bcda-since-reconciliation-design.md.

Until now a _since export was loaded like a full one: the loader took the
newest export directory per type, so a delta silently replaced the baseline
it was meant to extend. bcda.sync makes incremental pulls safe end to end.

First order — which row is current. A baseline (no _since) is the
authoritative snapshot for its types; deltas of the same population at or
after its cut-off extend it. Keys: Patient BENE_SK, Coverage id, EOB claim
control number (each claim *version* has a new FHIR id — migration guide).
Winner per key: newest meta.lastUpdated, then NCH/DDPS over SharedSystem
(the connector's rule), then later transactionTime, later applied sequence,
larger id. NotFinalAction winners stay as tombstones; only a baseline
retires rows (the API cannot express deletion). eob_item follows its header.

Second order — what a job did, per table, in the ledger: new / replaced /
unchanged / stale_ignored, backfill (lastUpdated < _since for an enrollee we
did not have — the API's promise for newly attributed enrollees on
Group/all) vs late (same shape for one we had — should not happen),
tombstoned, adjusted (clm_orig_cntl_num → bcda.eob_supersession), retired,
orphans (claims/coverage without a current Patient), scope drift.

Third order — invariants on every apply before anything is published:
unique keys, count conservation (|cur'| = |cur| + new − retired), watermark
monotone, every item has a header; replay determinism and idempotency are
tested (apply in either order → byte-identical tables; re-apply → no-op).
Current tables are re-derived from the applied partitions each time, so the
state is a function of the set of applied jobs, not their arrival order.

Temporality checks before a _since export starts (block/warn/ok): format,
future (server 400s), floor (no v3 lastUpdated before 2026-03-26),
no_baseline, gap (since > watermark: a window nobody would ever fetch),
overlap (free), endpoint_mix (runout vs current population),
backfill_scope (/Patient delta over a Group/all baseline), scope_filter
(_typeFilter drift), inflight, unapplied, attribution_newer,
stale_baseline. next_since() is the previous job's transactionTime, as
BCDA recommends; a combined job takes the earliest watermark of its types.

Store: job rows carry transaction_time and request, exports/<key>/
manifest.json keeps the completed-job body, resume() fills both in for
jobs completed before this; adopted jobs read _since from their request
line; a delta with nothing to deliver (200, empty output) still counts and
advances the watermark. flatten_export(out_dir=) writes per-job partitions
under flat/history/<key>/; current tables keep _job_key/_transaction_time/
_since/_kind/_applied_seq and the connector's _ensure() drops them before
the stage contracts. load_bcda(reconcile=True) applies pending jobs and
also loads bcda.sync_ledger, bcda.sync_watermark, bcda.eob_supersession;
an explicit ndjson_dir or a store without job rows keeps the legacy path.

Surfaces: `stack bcda sync status|check|apply|pull`, `stack bcda export
--since auto [--force]`, `stack bcda resume`; the manager's Exports page
gets a _since mode (off / watermark / date) with the checks shown and
blocks respected, and a Sync page (watermarks, pending, reconcile, ledger);
notebook section 8.

Verified on the real Large-entity store: applying the three baselines over
the legacy flat/ tables reported every row unchanged (0 new, 0 retired)
and loaded counts identical to the full load (221,021 medical lines,
11,968 pharmacy, 9,582 eligibility); a real /Patient-endpoint EOB delta
with a _typeFilter reconciled as 248 unchanged with the drift on record;
the sandbox's transactionTime is midnight UTC of the run day, so a
same-day zero-row delta is correctly ignored as predating its baseline.

refs #1139
2026-10-25 16:04:16 -04:00

1024 lines
40 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import marimo
__generated_with = "0.23.13"
app = marimo.App(width="full")
@app.cell(hide_code=True)
def _():
import marimo as mo
return (mo,)
@app.cell(hide_code=True)
def _(mo):
mo.md("""
# BCDA v3 — sandbox pull, flatten, load, prove
The Beneficiary Claims Data API moved to **v3** on 2026-07-01 (v1/v2 end on
2027-07-30). This notebook walks the whole path against CMS's public sandbox
for the **Large Model Entity** (10,000 synthetic enrollees) and checks each
step with a number rather than a feeling:
1. **Preflight** — `/_version`, `/_health`, `/api/v3/metadata` (no token).
2. **Auth + attribution** — client-credentials token, `attribution_status`,
the entity's job history.
3. **Pull** — one export job per resource type (a combined job takes 20–40
minutes and the shared sandbox credentials mean anyone can cancel it; the
EOB-only job finishes in ~6 minutes and 190 files / 2 GB). A completed job
younger than 24 h is **adopted** instead of re-run.
4. **Flatten + load** — `bcda.express.v3` (table-driven from the v3 Data
Dictionary's `fhirPath` / `sourceColumn` / `ccwMapping` columns) streams
the ndjson into Parquet and `aco.duckdb` `bcda.*`, runs the connector
pipeline (`bcda.pipe.cclf`: v3 routing on EOB-TYPE, Final-Action filter,
SharedSystem→NCH dedupe) into `input_layer.*`, then republishes the
read-only replica.
5. **Proof** — identity, coverage shape, claim provenance, line amounts,
referential integrity, and how many dictionary-mapped columns actually
carry data, each marked pass / fail.
6. **input_layer** — the connector's medical_claim / pharmacy_claim /
eligibility reconciled against the `bcda.*` tables they came from.
Network steps run only when **`BCDA_PULL=1`** is set or the buttons below are
pressed (`BCDA_LOAD=1` flattens and loads what is already in the store without
touching the network); otherwise the notebook validates whatever is already in
the replica, so the nightly notebooks-integration run never starts an export.
Sources: BCDA v3 Data Dictionary (`dev/vendor/bcda-site`), the migration
guide and July-2026 office-hours transition deck, `dev/seeds/bcda_v3_*.csv`
(CCLF ↔ BCDA v3 crosswalk), CMSgov/bcda-app (sparse vendor, `dev/vendor/bcda-app`).
""")
return
@app.cell(hide_code=True)
def _():
# ── 0. Setup ──
import os
import time
from datetime import datetime, timedelta, timezone
import altair as alt
import polars as pl
from bcda.client import SANDBOX, BcdaError, Client
from bcda.store import Store
from conf import ROOT, connect, path
connect.theme()
# Public sandbox credentials from https://bcda.cms.gov/api-documentation/get-a-bearer-token.html
# ("Large Model Entity", 10,000 synthetic enrollees). Real credentials come in
# through the environment and win.
LARGE_ENTITY = {
"name": "Large Model Entity (sandbox, synthetic)",
"client_id": "f5b6a686-0d7b-4080-873a-e60534fd2995",
"client_secret": "96ac1483449c652f363396737937f23cdae47a56a116c8a4405dbd54b31d2686f005df502c5c86ab",
"enrollees": 10_000,
}
CLIENT_ID = os.environ.get("BCDA_CLIENT_ID") or LARGE_ENTITY["client_id"]
CLIENT_SECRET = (
os.environ.get("BCDA_CLIENT_SECRET") or LARGE_ENTITY["client_secret"]
)
BASE_URL = os.environ.get("BCDA_BASE_URL") or SANDBOX
PULL = os.environ.get("BCDA_PULL") == "1"
LOAD = (
os.environ.get("BCDA_LOAD") == "1"
) # flatten + load what is on disk, no network
TYPES = ("Patient", "Coverage", "ExplanationOfBenefit")
STORE_PATH = path("storage.bcda")
def client() -> Client:
return Client(
CLIENT_ID, CLIENT_SECRET, base_url=BASE_URL, output_dir=STORE_PATH
)
NOTES: dict[str, str] = {}
return (
BASE_URL,
BcdaError,
LARGE_ENTITY,
LOAD,
NOTES,
PULL,
ROOT,
STORE_PATH,
Store,
TYPES,
alt,
client,
connect,
datetime,
pl,
time,
timedelta,
timezone,
)
@app.cell(hide_code=True)
def _(BASE_URL, LARGE_ENTITY, PULL, mo):
pull_btn = mo.ui.run_button(label="Pull from sandbox now")
load_btn = mo.ui.run_button(label="Flatten + load into DuckDB")
mo.vstack(
[
mo.md(f"""
**Target** `{BASE_URL}` · entity *{LARGE_ENTITY["name"]}* ·
`BCDA_PULL` {"set — network steps run headless" if PULL else "unset — press a button to pull or load"}
"""),
mo.hstack([pull_btn, load_btn], justify="start"),
]
)
return load_btn, pull_btn
@app.cell(hide_code=True)
def _(BcdaError, NOTES, client, mo):
# ── 1. Preflight (no token) ──
preflight = {}
try:
with client() as _c:
_md = _c.metadata()
preflight["fhirVersion"] = _md.get("fhirVersion")
preflight["software"] = (_md.get("software") or {}).get("version")
preflight["releaseDate"] = (_md.get("software") or {}).get("releaseDate")
preflight["resources"] = ", ".join(
r.get("type", "?")
for r in (_md.get("rest") or [{}])[0].get("resource", [])
)
try:
preflight["_version"] = _c.server_version().get("version")
except BcdaError as e: # noqa: BLE001 — informational endpoint
preflight["_version"] = (
f"unavailable ({e.status_code if hasattr(e, 'status_code') else e})"
)
try:
preflight["_health"] = _c.health().get("database")
except BcdaError as e: # noqa: BLE001
preflight["_health"] = f"unavailable ({e})"
ONLINE = True
except Exception as e: # noqa: BLE001 — no network: validate disk only
ONLINE = False
NOTES["preflight"] = f"sandbox unreachable: {e}"
def _tick(ok: bool) -> str:
return "✅" if ok else "❌"
if ONLINE:
_rows = [
(
_tick(preflight.get("fhirVersion") == "4.0.1"),
"FHIR R4 metadata",
f"fhirVersion {preflight.get('fhirVersion')}",
),
(
_tick(bool(preflight.get("software"))),
"bcda-app release",
f"{preflight.get('software')} ({preflight.get('releaseDate')})",
),
(
_tick("ExplanationOfBenefit" in (preflight.get("resources") or "")),
"v3 resources advertised",
preflight.get("resources"),
),
(
_tick(preflight.get("_health") == "ok"),
"`/_health` database",
str(preflight.get("_health")),
),
("ℹ️", "`/_version`", str(preflight.get("_version"))),
]
mo.output.replace(
mo.md(
"## 1 · Preflight\n\n"
+ "\n".join(f"- {t} **{n}** — {v}" for t, n, v in _rows)
)
)
else:
mo.output.replace(
mo.md(
f"## 1 · Preflight\n\n⚠️ {NOTES['preflight']} — continuing with data already on disk."
)
)
return (ONLINE,)
@app.cell(hide_code=True)
def _(ONLINE, TYPES, client, datetime, mo, pl, timedelta, timezone):
# ── 2. Auth, attribution, job history ──
attribution = {}
completed: list[dict] = []
reusable: dict[str, dict] = {}
if ONLINE:
with client() as _c:
_tok = _c.authenticate()
attribution = _c.attribution_status()
completed = _c.completed_jobs()
_cutoff = datetime.now(timezone.utc) - timedelta(hours=23)
for _j in completed: # newest first; keep the newest single-type job per type
if (
len(_j["types"]) == 1
and _j["types"][0] in TYPES
and _j["types"][0] not in reusable
):
try:
_end = datetime.fromisoformat(_j["end"].replace("Z", "+00:00"))
except ValueError:
continue
if _end >= _cutoff:
reusable[_j["types"][0]] = _j
_ing = {
d["type"]: d["timestamp"] for d in attribution.get("ingestion_dates", [])
}
_exp = {
d["type"]: d["timestamp"] for d in attribution.get("expiration_dates", [])
}
_hist = (
pl.DataFrame(
[
{
"job_id": j["job_id"],
"types": ",".join(j["types"]) or "(all)",
"completed": j["end"],
"reusable_24h": any(r is j for r in reusable.values()),
}
for j in completed[:15]
]
)
if completed
else pl.DataFrame({"job_id": []})
)
mo.output.replace(
mo.vstack(
[
mo.md(f"""
## 2 · Auth + attribution
- ✅ **token** issued ({len(_tok)} chars, 20-minute lifetime)
- ✅ **attribution** last updated `{_ing.get("last_attribution_update")}`, runout `{_ing.get("last_runout_update")}`; access expires `{_exp.get("attribution_access_expiration")}`
- {"✅" if completed else "ℹ️"} **{len(completed)} completed v3 job(s)** on this entity; reusable single-type jobs (<24 h): {", ".join(sorted(reusable)) or "none"}
"""),
mo.ui.table(
_hist,
label="Most recent completed v3 jobs (shared entity — other sandbox users' jobs appear here too)",
),
]
)
)
else:
mo.output.replace(mo.md("## 2 · Auth + attribution\n\n⚠️ skipped — offline."))
return (reusable,)
@app.cell(hide_code=True)
def _(ONLINE, PULL, STORE_PATH, Store, TYPES, client, mo, pl, pull_btn, reusable, time):
# ── 3. Pull (one job per type; adopt a fresh completed job when one exists) ──
store = Store(path=str(STORE_PATH))
pulled: dict[str, str] = {}
_do_pull = ONLINE and (PULL or pull_btn.value)
if _do_pull:
_log = []
with client() as _c:
for _t in TYPES:
_t0 = time.time()
if _t in reusable:
_key = store.adopt(
_c, reusable[_t]["job_url"], types=[_t], poll_interval=10
)
_how = f"adopted job {reusable[_t]['job_id']}"
else:
_key = store.export(
_c, types=[_t], poll_interval=15, cancel_retries=8
)
_how = "exported"
pulled[_t] = _key
_log.append(
f"- ✅ **{_t}** {_how} → `{_key}`, {len(store.get_files(_key))} file(s), {time.time() - _t0:.0f}s"
)
mo.output.replace(mo.md("## 3 · Pull\n\n" + "\n".join(_log)))
else:
_jobs = store.list_jobs()
_df = (
pl.DataFrame(
[
{
"key": j["key"],
"status": j["status"],
"types": j["types"],
"ts": j["ts"],
"files": len(store.get_files(j["key"])),
}
for j in _jobs
]
).sort("ts", descending=True)
if _jobs
else pl.DataFrame({"key": []})
)
mo.output.replace(
mo.vstack(
[
mo.md(
f"## 3 · Pull\n\nNo pull requested ({'offline' if not ONLINE else 'set `BCDA_PULL=1` or press *Pull from sandbox now*'}). Jobs already in the store at `{STORE_PATH}`:"
),
mo.ui.table(
_df,
label="Store job history (append-only; last row per key is current)",
),
]
)
)
return pulled, store
@app.cell(hide_code=True)
def _(LOAD, PULL, STORE_PATH, connect, load_btn, mo, pulled, store, time):
# ── 4. Flatten + load ──
from aco.load.bcda import _find_latest_export, load_bcda
_complete = [j for j in store.list_jobs(status="complete")]
_do_load = bool(_complete) and (PULL or LOAD or load_btn.value or bool(pulled))
load_stats: dict[str, int] = {}
if _do_load:
_dirs = _find_latest_export(STORE_PATH)
_t0 = time.time()
load_stats = load_bcda(
run_pipeline=True
) # newest export per resource type → bcda.* in aco.duckdb
_dt = time.time() - _t0
_replica = connect.publish_replica("aco")
mo.output.replace(
mo.md(
"## 4 · Flatten + load\n\n"
+ f"- ✅ flattened from {len(_dirs)} export dir(s): {', '.join(d.name for d in _dirs)}\n"
+ "\n".join(
f"- ✅ `{t}` — {n:,} rows" for t, n in sorted(load_stats.items())
)
+ f"\n- ✅ {_dt:.0f}s end to end; replica republished at `{_replica}`"
)
)
else:
mo.output.replace(
mo.md(
"## 4 · Flatten + load\n\n"
+ (
"No complete export in the store yet."
if not _complete
else "Not requested — reading the tables already in the replica."
)
)
)
return
@app.cell(hide_code=True)
def _(connect, mo, pl):
# ── 5. Proof — against the read-only replica ──
con = connect.duckdb("aco", read_only=True)
def q(sql: str) -> pl.DataFrame:
return con.execute(sql).pl()
_tables = q(
"select table_name from information_schema.tables where table_schema = 'bcda'"
)["table_name"].to_list()
HAVE = {"patient", "coverage", "explanation_of_benefit", "eob_item"} <= set(_tables)
mo.stop(
not HAVE,
mo.md(
f"## 5 · Proof\n\n⚠️ `bcda.*` tables not in the replica yet (found: {_tables or 'none'}). Run the pull and load above first."
),
)
return HAVE, con, q
@app.cell(hide_code=True)
def _(mo, q):
checks: list[tuple[bool, str, str]] = []
def check(ok: bool, name: str, detail: str) -> None:
checks.append((bool(ok), name, detail))
counts = {
r["t"]: r["n"]
for r in q("""
select 'patient' t, count(*) n from bcda.patient
union all select 'coverage', count(*) from bcda.coverage
union all select 'explanation_of_benefit', count(*) from bcda.explanation_of_benefit
union all select 'eob_item', count(*) from bcda.eob_item
""").to_dicts()
}
# Identity
_p = q("""
select count(*) n, count(bene_mbi_id) with_mbi, count(distinct bene_mbi_id) distinct_mbi,
count(distinct bene_id) distinct_sk, sum(case when bene_id = id then 1 else 0 end) sk_is_id,
count(cntct_lang_cd) with_lang, count(bene_death_dt) deceased,
sum(case when bene_race_cd is not null then 1 else 0 end) with_race
from bcda.patient
""").to_dicts()[0]
check(
_p["n"] > 0 and _p["with_mbi"] == _p["n"],
"Every Patient carries a current MBI",
f"{_p['with_mbi']:,} / {_p['n']:,}",
)
check(
_p["distinct_mbi"] == _p["n"],
"MBIs are unique",
f"{_p['distinct_mbi']:,} distinct",
)
check(
_p["sk_is_id"] == _p["n"],
"bene_id is the v3 Patient.id (BENE_SK)",
f"{_p['sk_is_id']:,} rows",
)
check(
_p["with_race"] == _p["n"],
"Race crosswalked from US Core OMB codes",
f"{_p['with_race']:,} rows; {_p['deceased']:,} deceased; {_p['with_lang']:,} with contact language",
)
# Coverage shape
plans = q(
"select class_plan, count(*) n, count(period_start) with_start, count(ms_cd) with_ms, count(dual_stus_cd) with_dual from bcda.coverage group by 1 order by 1"
)
_plan_names = set(plans["class_plan"].to_list())
check(
{"Part A", "Part B"} <= _plan_names,
"Coverage has one row per plan (Part A/B present)",
", ".join(f"{r['class_plan']}={r['n']:,}" for r in plans.to_dicts()),
)
check(
plans["with_start"].sum() == plans["n"].sum(),
"Every Coverage row has Coverage.period.start",
f"{plans['with_start'].sum():,} / {plans['n'].sum():,}",
)
_a = plans.filter(plans["class_plan"] == "Part A")
check(
len(_a) and _a["with_ms"][0] == _a["n"][0],
"Part A rows carry Medicare status (ms_cd)",
f"{_a['with_ms'][0] if len(_a) else 0:,} / {_a['n'][0] if len(_a) else 0:,}",
)
_d = plans.filter(plans["class_plan"] == "Dual Medicare/Medicaid")
check(
len(_d) == 0 or _d["with_dual"][0] == _d["n"][0],
"Dual rows carry dual_stus_cd",
f"{_d['with_dual'][0] if len(_d) else 0:,} dual rows",
)
_cov_ref = q(
"select count(*) n, sum(case when p.bene_id is null then 1 else 0 end) orphans from bcda.coverage c left join bcda.patient p on p.bene_id = c.beneficiary_reference"
).to_dicts()[0]
check(
_cov_ref["orphans"] == 0,
"Coverage.beneficiary resolves to a Patient",
f"{_cov_ref['orphans']:,} orphans of {_cov_ref['n']:,}",
)
# Claims provenance
prov = q(
"select system_type, eob_type, count(*) n, sum(clm_pmt_amt) paid from bcda.explanation_of_benefit group by 1, 2 order by 1, 2"
)
_e = q("""
select count(*) n, count(clm_id) with_id, count(clm_cntl_num) with_ccn, count(system_type) with_sys, count(eob_type) with_eob_type,
count(clm_type_cd) with_clm_type, count(final_action) with_fa, count(clm_from_dt) with_from,
min(clm_from_dt) first_dt, max(clm_thru_dt) last_dt
from bcda.explanation_of_benefit
""").to_dicts()[0]
check(
_e["with_id"] == _e["n"] and _e["with_ccn"] == _e["n"],
"Every EOB has a unique claim id and a claim control number",
f"{_e['n']:,} EOBs",
)
check(
_e["with_sys"] == _e["n"] and _e["with_fa"] == _e["n"],
"Every EOB is tagged System-Type and Final-Action",
f"{', '.join(sorted(set(prov['system_type'].to_list())))}",
)
check(
_e["with_eob_type"] == _e["n"] and _e["with_clm_type"] == _e["n"],
"EOB-TYPE and CLM-TYPE-CD present on every claim",
f"{', '.join(sorted(set(prov['eob_type'].to_list())))}",
)
check(
_e["with_from"] == _e["n"],
"Billable period present",
f"{_e['first_dt']} → {_e['last_dt']}",
)
_dupe = q("""
select count(*) dupes from (
select system_type, clm_cntl_num, count(*) c from bcda.explanation_of_benefit
group by 1, 2 having count(*) > 1)
""").to_dicts()[0]["dupes"]
check(
_dupe == 0,
"Claim control number unique within a source system (v3 dedupes claim versions)",
f"{_dupe:,} duplicated control numbers",
)
_pairs = q("""
select count(*) pairs from (
select clm_cntl_num from bcda.explanation_of_benefit
group by 1 having count(distinct system_type) > 1)
""").to_dicts()[0]["pairs"]
check(
True,
"SharedSystem ↔ NationalClaimsHistory pairs (same control number)",
f"{_pairs:,} claims seen in two sources",
)
_eob_ref = q(
"select count(*) n, sum(case when p.bene_id is null then 1 else 0 end) orphans from bcda.explanation_of_benefit e left join bcda.patient p on p.bene_id = e.bene_id"
).to_dicts()[0]
check(
_eob_ref["orphans"] == 0,
"EOB.patient resolves to a Patient",
f"{_eob_ref['orphans']:,} orphans of {_eob_ref['n']:,}",
)
# Lines
_i = q("""
select count(*) n, count(distinct clm_id) claims, count(clm_line_hcpcs_cd) hcpcs, count(clm_line_ndc_cd) ndc,
count(clm_line_cvrd_pd_amt) paid, count(clm_line_sbmtd_chrg_amt) submitted, count(clm_line_from_dt) dated
from bcda.eob_item
""").to_dicts()[0]
check(
_i["claims"] == _e["n"] or _i["claims"] > 0,
"Every claim has line items",
f"{_i['n']:,} lines on {_i['claims']:,} claims",
)
check(
_i["hcpcs"] + _i["ndc"] >= _i["n"] * 0.95,
"Lines carry a HCPCS or NDC code",
f"HCPCS {_i['hcpcs']:,}, NDC {_i['ndc']:,} of {_i['n']:,}",
)
check(
_i["paid"] >= _i["n"] * 0.9 and _i["dated"] == _i["n"],
"Line paid amount and service date populated",
f"paid {_i['paid']:,}, submitted {_i['submitted']:,}, dated {_i['dated']:,}",
)
_orph = q(
"select count(*) n from bcda.eob_item i left join bcda.explanation_of_benefit e on e.clm_id = i.clm_id where e.clm_id is null"
).to_dicts()[0]["n"]
check(
_orph == 0,
"Every line item belongs to a loaded claim",
f"{_orph:,} orphan lines",
)
_passed = sum(1 for ok, _, _ in checks if ok)
mo.vstack(
[
mo.md(
f"## 5 · Proof — {_passed} / {len(checks)} checks pass\n\n"
+ " · ".join(f"`{t}` {n:,}" for t, n in counts.items())
),
mo.md(
"\n".join(
f"- {'✅' if ok else '❌'} **{name}** — {detail}"
for ok, name, detail in checks
)
),
]
)
return checks, counts, plans, prov
@app.cell(hide_code=True)
def _(alt, mo, plans, prov, q):
# ── Charts: one measure each, single hue from the fhirworx theme ──
_by_type = q(
"select eob_type, count(*) n, sum(clm_pmt_amt) paid from bcda.explanation_of_benefit group by 1 order by 2 desc"
)
claims_chart = (
alt.Chart(_by_type)
.mark_bar(cornerRadiusEnd=4, size=18)
.encode(
y=alt.Y("eob_type:N", sort="-x", title=None),
x=alt.X("n:Q", title="claims", axis=alt.Axis(grid=True)),
tooltip=[
alt.Tooltip("eob_type:N", title="EOB type"),
alt.Tooltip("n:Q", title="claims", format=","),
alt.Tooltip("paid:Q", title="paid", format="$,.0f"),
],
)
.properties(title="Claims by EOB type", height=28 * len(_by_type), width=420)
)
_monthly = q("""
select date_trunc('month', clm_from_dt) as svc_month, count(*) n
from bcda.explanation_of_benefit where clm_from_dt >= date '2015-01-01'
group by 1 order by 1
""")
monthly_chart = (
alt.Chart(_monthly)
.mark_line(strokeWidth=2, point=alt.OverlayMarkDef(size=36))
.encode(
x=alt.X("svc_month:T", title=None),
y=alt.Y("n:Q", title="claims per month"),
tooltip=[
alt.Tooltip("svc_month:T", title="month", format="%b %Y"),
alt.Tooltip("n:Q", title="claims", format=","),
],
)
.properties(title="Claims by service month", height=220, width=620)
)
plan_chart = (
alt.Chart(plans)
.mark_bar(cornerRadiusEnd=4, size=18)
.encode(
y=alt.Y("class_plan:N", sort="-x", title=None),
x=alt.X("n:Q", title="coverage rows"),
tooltip=[
alt.Tooltip("class_plan:N", title="plan"),
alt.Tooltip("n:Q", title="rows", format=","),
],
)
.properties(title="Coverage rows by plan", height=28 * len(plans), width=420)
)
mo.vstack(
[
mo.hstack(
[mo.ui.altair_chart(claims_chart), mo.ui.altair_chart(plan_chart)],
justify="start",
),
mo.ui.altair_chart(monthly_chart),
mo.ui.table(prov, label="Claims and payments by System-Type × EOB-TYPE"),
]
)
return
@app.cell(hide_code=True)
def _(mo, q):
# ── 6. input_layer — the connector pipeline reconciled against bcda.* ──
_il = q(
"select table_name from information_schema.tables where table_schema = 'input_layer'"
)["table_name"].to_list()
mo.stop(
not {"medical_claim", "pharmacy_claim", "eligibility"} <= set(_il),
mo.md(
"## 6 · input_layer\n\n⚠️ `input_layer.*` not in the replica yet — run the "
"load above (it runs `bcda.pipe.cclf`) or `stack load bcda --skip-flatten --run-pipeline`."
),
)
il_checks: list[tuple[bool, str, str]] = []
def il(ok: bool, name: str, detail: str) -> None:
il_checks.append((bool(ok), name, detail))
_src = q("""
select
count(*) filter (where final_action = 'FinalAction' and eob_type <> 'PDE') final_medical,
count(*) filter (where final_action = 'FinalAction' and eob_type = 'PDE') final_pde,
count(*) filter (where final_action = 'NotFinalAction') not_final,
count(*) filter (where final_action = 'FinalAction' and eob_type in ('INPATIENT','OUTPATIENT','SNF','HHA','HOSPICE')) final_inst,
count(*) filter (where final_action = 'FinalAction' and eob_type in ('CARRIER','DME')) final_prof
from bcda.explanation_of_benefit
""").to_dicts()[0]
_mc = q("""
select claim_type, count(*) lines, count(distinct claim_id) claims,
count(person_id) with_person, count(paid_amount) with_paid, count(charge_amount) with_charge,
count(deductible_amount) with_ded, count(coinsurance_amount) with_coins,
count(hcpcs_code) with_hcpcs, count(rendering_npi) with_rendering, count(billing_npi) with_billing,
count(bill_type_code) with_tob, count(drg_code) with_drg, count(admission_date) with_adm,
count(place_of_service_code) with_pos, count(diagnosis_code_1) with_dx, count(paid_date) with_paid_dt
from input_layer.medical_claim group by 1 order by 1
""")
_by = {r["claim_type"]: r for r in _mc.to_dicts()}
_inst, _prof = _by.get("institutional", {}), _by.get("professional", {})
_claims = sum(r["claims"] for r in _mc.to_dicts())
il(
_claims == _src["final_medical"],
"Every final-action medical EOB is in medical_claim, once",
f"{_claims:,} claims = {_src['final_medical']:,} FinalAction non-PDE EOBs; {_src['not_final']:,} NotFinalAction excluded",
)
il(
_inst.get("claims") == _src["final_inst"]
and _prof.get("claims") == _src["final_prof"],
"Routed by EOB-TYPE: institutional vs professional",
f"institutional {_inst.get('claims', 0):,} / {_src['final_inst']:,} · professional {_prof.get('claims', 0):,} / {_src['final_prof']:,}",
)
_no_person = q(
"select count(*) n from input_layer.medical_claim where person_id is null"
).to_dicts()[0]["n"]
il(
_no_person == 0,
"Every line resolves to an MBI (person_id)",
f"{_no_person:,} lines without MBI",
)
il(
_inst.get("with_adm") == _inst.get("lines")
and _inst.get("with_tob", 0) >= 0.99 * _inst.get("lines", 1),
"Institutional lines carry admission date and NUBC type of bill",
f"TOB {_inst.get('with_tob', 0):,}, admission {_inst.get('with_adm', 0):,} of {_inst.get('lines', 0):,}",
)
_tob_len = q(
"select count(*) n from input_layer.medical_claim where claim_type='institutional' and length(bill_type_code) <> 4"
).to_dicts()[0]["n"]
il(
_tob_len == 0,
"Type of bill is the 4-character NUBC code (not fac+clsfctn+freq)",
f"{_tob_len:,} malformed",
)
il(
_inst.get("with_paid") == _inst.get("lines")
and _inst.get("with_charge") == _inst.get("lines")
and _inst.get("with_ded") == _inst.get("lines")
and _inst.get("with_coins") == _inst.get("lines"),
"Institutional paid / charge / deductible / coinsurance from v3 Adjudication",
f"paid {_inst.get('with_paid', 0):,} · charge {_inst.get('with_charge', 0):,} · ded {_inst.get('with_ded', 0):,} · coins {_inst.get('with_coins', 0):,}",
)
il(
_prof.get("with_paid") == _prof.get("lines")
and _prof.get("with_pos", 0) >= 0.95 * _prof.get("lines", 1)
and _prof.get("with_rendering") == _prof.get("lines"),
"Professional lines: paid, place of service, rendering NPI",
f"paid {_prof.get('with_paid', 0):,} · POS {_prof.get('with_pos', 0):,} · rendering {_prof.get('with_rendering', 0):,} of {_prof.get('lines', 0):,}",
)
il(
_inst.get("with_drg", 0) > 0 and _inst.get("with_dx", 0) == _inst.get("lines"),
"Institutional DRG and header diagnoses present",
f"DRG {_inst.get('with_drg', 0):,} · dx1 {_inst.get('with_dx', 0):,}",
)
il(
(_inst.get("with_paid_dt", 0) + _prof.get("with_paid_dt", 0))
== (_inst.get("lines", 0) + _prof.get("lines", 0)),
"Paid date resolved (clm_pd_dt → NCH weekly → CMS process)",
f"{_inst.get('with_paid_dt', 0) + _prof.get('with_paid_dt', 0):,} lines",
)
_rx = q("""
select count(*) n, count(distinct claim_id) claims, count(prescribing_provider_npi) prs, count(dispensing_provider_npi) dsp,
count(ndc_code) ndc, count(quantity) qty, count(days_supply) ds, count(refills) rf, count(charge_amount) chg,
count(copayment_amount) cop, count(paid_amount) paid, count(paid_date) pd
from input_layer.pharmacy_claim
""").to_dicts()[0]
il(
_rx["claims"] == _src["final_pde"],
"Every final-action PDE is in pharmacy_claim, once",
f"{_rx['claims']:,} = {_src['final_pde']:,}",
)
il(
_rx["prs"] == _rx["n"]
and _rx["dsp"] == _rx["n"]
and _rx["ndc"] == _rx["n"]
and _rx["qty"] == _rx["n"]
and _rx["ds"] == _rx["n"],
"Part D: prescriber, pharmacy, NDC, quantity, days supply populated",
f"{_rx['n']:,} rows",
)
il(
_rx["chg"] == _rx["n"] and _rx["cop"] == _rx["n"],
"Part D: total drug cost and paid-by-patient populated",
f"charge {_rx['chg']:,} · copay {_rx['cop']:,} · plan-paid {_rx['paid']:,} (sandbox emits none)",
)
_el = q("""
select count(*) n, count(distinct person_id) people, count(gender) g, count(enrollment_start_date) es,
count(medicare_status_code) ms, count(original_reason_entitlement_code) orec, count(dual_status_code) dual,
count(enrollment_status) st, count(*) filter (where gender = 'unknown') g_unk, count(*) filter (where race = 'unknown') r_unk
from input_layer.eligibility
""").to_dicts()[0]
_pat = q("select count(*) n from bcda.patient").to_dicts()[0]["n"]
_dual_rows = q(
"select count(distinct subscriber_id) n from bcda.coverage where class_plan = 'Dual Medicare/Medicaid'"
).to_dicts()[0]["n"]
_ab_rows = q(
"select count(distinct subscriber_id) n from bcda.coverage where class_plan in ('Part A', 'Part B')"
).to_dicts()[0]["n"]
il(
_el["n"] == _pat and _el["people"] == _pat,
"One eligibility row per Patient",
f"{_el['n']:,} = {_pat:,}",
)
il(
_el["g_unk"] == 0,
"Gender resolved for every row",
f"{_el['g_unk']:,} unknown; race unknown {_el['r_unk']:,} (OMB UNK)",
)
il(
_el["es"] == _el["ms"] == _el["st"] == _ab_rows,
"Enrollment period, Medicare status and status from the Part A/B Coverage row",
f"{_el['es']:,} rows = {_ab_rows:,} beneficiaries with a Part A/B row; {_el['n'] - _el['es']:,} patients have none in this pull",
)
il(
_el["dual"] == _dual_rows,
"Dual status from the Dual Medicare/Medicaid Coverage row",
f"{_el['dual']:,} = {_dual_rows:,} beneficiaries with a Dual row",
)
_passed = sum(1 for ok, _, _ in il_checks if ok)
mo.vstack(
[
mo.md(f"## 6 · input_layer — {_passed} / {len(il_checks)} checks pass"),
mo.md(
"\n".join(
f"- {'✅' if ok else '❌'} **{name}** — {detail}"
for ok, name, detail in il_checks
)
),
mo.ui.table(
_mc,
label="medical_claim by claim_type: lines, claims and populated fields",
),
]
)
return (il_checks,)
@app.cell(hide_code=True)
def _(ROOT, con, mo, pl, q):
# ── 7. Dictionary field population + CCLF crosswalk ──
_cols = q(
"select table_name, column_name from information_schema.columns where table_schema = 'bcda' order by 1, 2"
)
_pop_rows = []
for _t in ("patient", "coverage", "explanation_of_benefit", "eob_item"):
_names = _cols.filter(pl.col("table_name") == _t)["column_name"].to_list()
_expr = ", ".join(f'count("{c}") as "{c}"' for c in _names)
_r = con.execute(f"select count(*) as _n, {_expr} from bcda.{_t}").fetchone()
_n = _r[0]
for _c, _v in zip(_names, _r[1:], strict=True):
_pop_rows.append(
{
"table": _t,
"column": _c,
"non_null": _v,
"pct": round(100 * _v / _n, 1) if _n else 0.0,
}
)
population = pl.DataFrame(_pop_rows)
_summary = (
population.group_by("table")
.agg(
pl.len().alias("columns"),
(pl.col("non_null") > 0).sum().alias("populated"),
)
.with_columns(
(100 * pl.col("populated") / pl.col("columns"))
.round(1)
.alias("pct_populated")
)
.sort("table")
)
# Crosswalk: the dictionary row behind each populated column, by IDR source column
_seeds = ROOT / "dev" / "seeds"
_has_ref = (
con.execute(
"select count(*) from information_schema.tables where table_schema='reference_data' and table_name='bcda_v3_data_dictionary'"
).fetchone()[0]
> 0
)
if _has_ref:
dictionary = q(
"select fhir_resource, field_name, fhir_path, source_column, ccw_mapping, cclf_mapping from reference_data.bcda_v3_data_dictionary"
)
crosswalk = q(
"select cclf_file, element, field_name, field_label, bcda_v3_field, fhir_path from reference_data.bcda_v3_cclf_crosswalk"
)
absent = q(
"select cclf_file, element, field_name, field_description from reference_data.bcda_v3_cclf_absent"
)
_src = "reference_data (stack load seed)"
elif (_seeds / "bcda_v3_data_dictionary.csv").exists():
dictionary = pl.read_csv(
_seeds / "bcda_v3_data_dictionary.csv", infer_schema_length=10000
)
crosswalk = pl.read_csv(
_seeds / "bcda_v3_cclf_crosswalk.csv", infer_schema_length=10000
)
absent = pl.read_csv(
_seeds / "bcda_v3_cclf_absent.csv", infer_schema_length=10000
)
_src = "dev/seeds CSVs"
else:
dictionary = crosswalk = absent = None
_src = "unavailable"
_mapped = (
crosswalk.filter(
pl.col("bcda_v3_field").is_not_null() & (pl.col("bcda_v3_field") != "")
)
if crosswalk is not None
else None
)
mo.vstack(
[
mo.md(f"""
## 7 · Dictionary field population and the CCLF crosswalk
Columns are named after the v3 Data Dictionary's `ccwMapping` (legacy CCW names) or its IDR
`sourceColumn` (v3-only). A populated column means the v3 payload actually carried that element
for this entity; empty ones are either v2-only (monthly `dual_*`, `buyin*`, `rfrnc_yr`), Part D-only
when no Part D coverage exists, or not emitted by the sandbox generator. Crosswalk source: *{_src}*.
"""),
mo.ui.table(_summary, label="Populated columns per table"),
mo.ui.table(
population.sort(["table", "pct"], descending=[False, True]),
label="Non-null count per column",
),
]
+ (
[
mo.md(
f"**CCLF → BCDA v3**: {len(_mapped):,} of {len(crosswalk):,} CCLF elements have a v3 field; {len(absent):,} CCLF fields have no v3 equivalent (HICNs, FIPS county, address lines, BETOS, several CCLFA/B amounts)."
),
mo.ui.table(
dictionary,
label="BCDA v3 Data Dictionary (fhirPath · IDR sourceColumn · CCW · CCLF)",
),
mo.ui.table(_mapped, label="CCLF element → BCDA v3 field"),
mo.ui.table(absent, label="CCLF fields absent from BCDA v3"),
]
if dictionary is not None
else [
mo.md(
"Crosswalk seeds not found — run `uv run python dev/scripts/gen_bcda_v3_crosswalk.py` and `stack load seed`."
)
]
)
)
return
@app.cell(hide_code=True)
def _(STORE_PATH, mo, pl):
"""## 8 · Incremental pulls — watermarks, checks, ledger."""
from bcda import sync as _sync
from bcda.store import Store as _Store
_store = _Store(path=str(STORE_PATH))
_status = _sync.status(_store)
_next = _sync.next_since(_store)
_blocks = []
for _rtype, _since in _next.items():
if _since is None:
_blocks.append(
{
"type": _rtype,
"_since": "— no baseline —",
"level": "block",
"code": "no_baseline",
"message": "run an unfiltered pull first",
}
)
continue
for _c in _sync.check_since(_store, _since, types=[_rtype]):
_blocks.append({"type": _rtype, "_since": _since, **_c.__dict__})
_ledger_rows = [
{
"seq": _r["applied_seq"],
"job": _r["job_key"],
"kind": _r["kind"],
"ok": _r["ok"],
"since": _r["since"],
"transaction_time": _r["transaction_time"],
"table": _t,
**_c,
}
for _r in _status["ledger"]
for _t, _c in (_r["counts"] or {}).items()
]
mo.vstack(
[
mo.md(f"""
## 8 · Incremental pulls (`_since`)
BCDA filters `_since` on `meta.lastUpdated`, returns **all** resources for newly attributed
enrollees on `/Group/all`, and recommends the previous job's `transactionTime` as the next `_since`.
Each claim *version* has a new FHIR id, so claims are keyed by control number; the newest
`lastUpdated` wins, then NCH/DDPS over SharedSystem, then the later job. Only a baseline retires rows.
`bcda.sync` keeps a per-job ledger and re-derives the current tables from the applied set on every
apply, so the result is independent of arrival order (tested in `tests/bcda/test_sync.py`).
Store: `{STORE_PATH}` · {len(_status["jobs"])} complete job(s), {len(_status["pending"])} not yet reconciled.
Next `_since`: {", ".join(f"`{t}` → `{v or '—'}`" for t, v in _next.items())}
"""),
mo.ui.table(
pl.DataFrame(_status["watermarks"])
if _status["watermarks"]
else pl.DataFrame({"note": ["no complete jobs"]}),
label="Watermarks",
),
mo.ui.table(
pl.DataFrame(_blocks).select(
"type", "_since", "level", "code", "message"
)
if _blocks
else pl.DataFrame({"note": ["—"]}),
label="Checks for the watermark _since",
),
mo.ui.table(
pl.DataFrame(_ledger_rows)
if _ledger_rows
else pl.DataFrame(
{"note": ["nothing applied yet — `stack bcda sync apply`"]}
),
label="Sync ledger (per job × table)",
),
]
)
return
if __name__ == "__main__":
app.run()