From 5bc7b78984ff20f4e938b7813d6aaa7222e25ae4 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Thu, 16 Jul 2026 06:38:59 -0400 Subject: [PATCH] Fix preflight --ledger-facts: pass the artifact's fact rows to the compiler _load_ledger_target_specs handed the LedgerConsumerArtifact wrapper itself to compile_us_fiscal_target_registry, so every --ledger-facts preflight crashed with "'LedgerConsumerArtifact' object is not iterable" before the zero-support preview could run (the flag's happy path had no test). The builder's own call site passes ledger_artifact.facts; the preflight now does the same. Regression test pins the seam: the compiler receives the artifact's fact ROWS (and the facts-sha pin reaches the loader), failing with the pre-fix wrapper-object behavior. Co-Authored-By: Claude Fable 5 --- .../us_runtime/release_gate_preflight.py | 6 ++- .../tests/test_us_release_gate_preflight.py | 51 +++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/packages/populace-build/src/populace/build/us_runtime/release_gate_preflight.py b/packages/populace-build/src/populace/build/us_runtime/release_gate_preflight.py index 97ad66a7..134d7551 100644 --- a/packages/populace-build/src/populace/build/us_runtime/release_gate_preflight.py +++ b/packages/populace-build/src/populace/build/us_runtime/release_gate_preflight.py @@ -760,10 +760,12 @@ def _load_ledger_target_specs( compile_us_fiscal_target_registry, ) - facts = load_ledger_consumer_artifact( + artifact = load_ledger_consumer_artifact( ledger_facts, expected_facts_sha256=ledger_facts_sha256 ) - registry = compile_us_fiscal_target_registry(facts, target_period=target_period) + registry = compile_us_fiscal_target_registry( + artifact.facts, target_period=target_period + ) return registry.specs diff --git a/packages/populace-build/tests/test_us_release_gate_preflight.py b/packages/populace-build/tests/test_us_release_gate_preflight.py index 5014c88c..16165e20 100644 --- a/packages/populace-build/tests/test_us_release_gate_preflight.py +++ b/packages/populace-build/tests/test_us_release_gate_preflight.py @@ -534,3 +534,54 @@ def test__report__to_dict_is_json_ready() -> None: payload = report.to_dict() assert json.loads(json.dumps(payload))["exit_code"] == 1 assert payload["checks"][0]["rows"] == [{"k": 1}] + + +def test__load_ledger_target_specs__hands_fact_rows_to_the_compiler( + monkeypatch, tmp_path +) -> None: + """Regression: the loader passed the LedgerConsumerArtifact wrapper itself + to the registry compiler, so every ``--ledger-facts`` preflight crashed + with "'LedgerConsumerArtifact' object is not iterable" before the + zero-support preview could run. The compiler must receive the artifact's + fact ROWS, and the facts-sha pin must reach the artifact loader.""" + import hashlib + import json + from types import SimpleNamespace + + import populace.build.us_runtime.fiscal_targets as fiscal_targets + from populace.build.us_runtime.release_gate_preflight import ( + _load_ledger_target_specs, + ) + + fact_row = {"aggregate_fact_key": "ledger.aggregate_fact.v2:abc123"} + feed = tmp_path / "consumer_facts.jsonl" + feed.write_text(json.dumps(fact_row) + "\n") + feed_sha = hashlib.sha256(feed.read_bytes()).hexdigest() + + expected_specs = ( + TargetSpec( + name="ledger.aggregate_fact.v2:abc123", + entity="household", + value=1.0, + measure="income", + source="ledger", + ), + ) + captured: dict[str, object] = {} + + def fake_compile(facts, *, target_period): + captured["facts"] = facts + captured["target_period"] = target_period + return SimpleNamespace(specs=expected_specs) + + monkeypatch.setattr( + fiscal_targets, "compile_us_fiscal_target_registry", fake_compile + ) + + specs = _load_ledger_target_specs( + feed, target_period=2024, ledger_facts_sha256=feed_sha + ) + + assert captured["facts"] == (fact_row,) + assert captured["target_period"] == 2024 + assert specs == expected_specs