Accepted - 2026-08-09
Phase 2 needs to demonstrate lakehouse decisions, data contracts, lineage, and cost signals while remaining runnable on a laptop. The streaming core stays standard-library-only under ADR 0002; hand-writing a Parquet encoder or query engine would add risk without strengthening that claim.
CMS hospital JSON v3 is nested at item, code, standard-charge, payer-rate, modifier-definition, modifier-payer, and charge-modifier grains. A single flattened table would duplicate source evidence, obscure ordinals, invent a primary code, lose modifier resolution failures, and invite aggregation of percentages with dollar amounts. The original source path can also change during or after a build, so a content digest alone is insufficient provenance unless the admitted bytes remain available. Modifier definitions can also be scoped to inpatient, outpatient, both, or no stated setting; canonical-code matching without that scope can select an inapplicable definition.
- Keep DuckDB in an optional
lakehouseextra. The base streaming and inspection layers remain dependency-free. - Hash the exact source bytes with SHA-256, copy and re-hash them into an immutable build snapshot, then promote that snapshot to a content-addressed archive. Inspection and normalization read the snapshot, not the mutable original path.
- Normalize the charge-information and optional modifier-information arrays one element at a time into bounded TSV spools, then let DuckDB bulk-load them under declared schemas. PyArrow is not required.
- Materialize and export 13 explicit models across raw, staging, intermediate, finding, and mart layers. Partition Parquet by publisher, source period, file version, and run identity.
- Define a run as the SHA-256 of pipeline version + publisher identifier + source-content identity
- inspection
as_of+ transformation fingerprint. The fingerprint covers the declared SQL, model/export DAG, spool shape, parser and normalization policy, manifest schema, inspection policy/finding catalog, and contracts. Identical tuples verify and reuse one run; a transformation or inspection-policy change produces disjoint artifacts even when publisher, input, and assessment date are unchanged.
- inspection
- Retain the exact admitted JSON element text and SHA-256 for every raw item and modifier. Use
DECIMAL(38,10)for typed numeric projections, leaving the raw lexeme authoritative when source precision exceeds that scale. Retain all item codes as orderedcodes_json; do not treat source code ordinal zero as a semantic primary code. - Preserve modifier definitions, charge references, and payer-plan mappings as separate grains.
Resolve with a documented NFKC/trim/case-folded key and only definitions applicable to the
charge-group setting; label a match
exactonly when original text also agrees. Include the selectedmodifier_settingand allcandidate_modifier_settings. Expose known-but-inapplicable definitions assetting_mismatch/modifier_setting_mismatch. Permit same-canonical inpatient and outpatient definitions, but reject pairs whose applicable settings overlap (including missing orbothsettings). - Preserve dollar, percentage, and algorithm representations as separate intermediate rows. Only
stated dollar observations enter
mart_segmented_dollar_rate; methodology remains a required comparison segment. - Enforce types, exact raw hashes, accepted code sets and methodologies, positive numeric values, uniqueness, source ordinals, reconciliation, and referential expectations as executable contracts. A violation rolls back model rows and promotes no completed snapshot.
- Write a schema-v4 manifest containing separate transformation and inspection fingerprints plus
the source archive and all 13 Parquet artifacts with relative path, byte size, and SHA-256.
Digest every immutable manifest field into
manifest_body_sha256, excluding onlystatusand the digest itself. Promote it inpreparedstate, commit the successful catalog row, then atomically replace it withsuccess. Reuse verifies the body digest, catalog/manifest identity, and every artifact before returning. If finalization was interrupted after commit, a validatedpreparedmanifest is finalized on the next reuse. - Configure DuckDB with an operator-visible memory limit, a warehouse-local spill directory, two
worker threads by default, and insertion-order preservation disabled. Source ordinals carry
order; physical insertion order does not. Record rows, bytes, wall time, DuckDB peak-buffer
signals, and requested/effective settings while stating that
memory_limitis not an RSS cap. - Run deterministic local inspection as part of each new run, persist one deduplicated
file_findingrow per code with occurrences and citations, and embed the full inspection in the manifest. Remote retrievability remains outside this local path.
- The streaming credibility claim remains attributable to standard-library code; DuckDB begins at the lakehouse boundary.
- The archived source makes a completed run independently auditable after the original is changed or removed, at the cost of one additional content-sized artifact per distinct source digest.
- Raw exact text plus typed projections make coercion visible.
DECIMAL(38,10)gives deterministic warehouse arithmetic but does not claim unlimited source precision. - The spool temporarily uses disk roughly in proportion to normalized content. The DuckDB file, source archive, and Parquet exports intentionally duplicate storage for different operational and publication roles; their sizes are recorded rather than hidden.
- Physical indexes are not created on high-volume model tables. Contracts enforce uniqueness transactionally, avoiding an index-memory cost that scales poorly.
- Insertion-order preservation is disabled. Stable keys, contracts, counts, archived input, and logical results are the cross-build reproducibility boundary; independent Parquet builds are not promised byte-identical.
- The manifest protocol closes the tested post-commit-finalization gap and reuse fails closed on corrupt inventories or immutable manifest-body tampering, including altered inspection, envelope, or metrics. Individual filesystem promotions are no-overwrite atomic operations, not a claim that a multi-file snapshot appears atomically under process death.
- Concurrent writers, historical warehouse migrations, and a full SIGKILL/fsync matrix across persistence boundaries are not implemented. Current deterministic fault tests cover partial promotion cleanup and interrupted post-commit manifest finalization.
- The final clean 64,828,148-byte acceptance completed in 46.66 seconds at 534,790,144 bytes
maximum process RSS and a 575,865,768-byte macOS peak memory footprint. DuckDB's retained
512,212,992-byte
system_peak_buffer_memory_bytesvalue is a profiler metric, not process RSS or a value to compare directly with the configured256MBbuffer-manager setting. Full evidence is indocs/PHASE-2-FINDINGS.md. - All 11 real-file modifier definitions omitted optional setting, so setting restriction behavior is established by synthetic regressions for mismatch reporting, disjoint definitions, and overlapping-setting rejection rather than by that one-file acceptance.
- Hospital CSV and payer-MRF shapes remain future adapters. This decision does not force them through the CMS v3 hospital normalizer.