Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ def load_jsonl(path: Path) -> list[dict[str, Any]]:
"""Load a JSONL results file."""
if not path.exists():
return []
return [json.loads(line) for line in path.read_text(encoding="utf-8").splitlines() if line.strip()]
return [
json.loads(line) for line in path.read_text(encoding="utf-8").splitlines() if line.strip()
]


def _decimal(value: Any) -> Decimal | None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ def select_cases(
cases = [case for case in cases if case.get("domain") in domains]
if not include_blocked:
cases = [
case
for case in cases
if (case.get("rulespec") or {}).get("compileStatus") == "ok"
case for case in cases if (case.get("rulespec") or {}).get("compileStatus") == "ok"
]
return cases
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ def run_openfisca_live_case(case: dict[str, Any], system: Any) -> dict[str, Any]
earnings = _acc_earnings(case)
if earnings is None:
# self-employed cases may need different vars — mark partial
return _gap_row(case, "no standard acc earnings input (self-employed path not mapped)")
return _gap_row(
case, "no standard acc earnings input (self-employed path not mapped)"
)
person["acc__earnings_for_earners_levy"] = {year: float(earnings)}
sim = SimulationBuilder().build_from_entities(
system,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ def probe_openfisca_tree(repo_root: Path) -> dict[str, Any]:
if path.is_file()
)
income_tax_vars = [path for path in variable_files if "income_tax" in path]
acc_vars = [path for path in variable_files if "/acc/" in path or path.startswith("variables/acts/acc")]
acc_vars = [
path for path in variable_files if "/acc/" in path or path.startswith("variables/acts/acc")
]
kiwisaver_vars = [path for path in variable_files if "kiwi" in path.lower()]

has_progressive_tax_formula = any(
Expand All @@ -75,7 +77,9 @@ def probe_openfisca_tree(repo_root: Path) -> dict[str, Any]:
"rateInstantCount": len(latest_rate_instants),
"rateInstants": latest_rate_instants,
"latestRateInstant": latest_rate_instants[-1] if latest_rate_instants else None,
"coversTaxYear2026": any(instant.startswith("202") and instant >= "2024" for instant in latest_rate_instants),
"coversTaxYear2026": any(
instant.startswith("202") and instant >= "2024" for instant in latest_rate_instants
),
"incomeTaxVariableFiles": income_tax_vars,
"accVariableFiles": acc_vars,
"kiwisaverVariableFiles": kiwisaver_vars,
Expand Down Expand Up @@ -105,9 +109,7 @@ def materialise_openfisca_result(case: dict[str, Any], probe: dict[str, Any]) ->
"individual_income_tax_before_credits."
)
elif not probe.get("coversTaxYear2026"):
gap_reason = (
"parameter scale does not include 2026 tax-year instants required by inventory cases."
)
gap_reason = "parameter scale does not include 2026 tax-year instants required by inventory cases."
else:
gap_reason = "mapping incomplete"
status = "engine_gap"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,10 @@ def inventory_case_to_pic_case(
if derived_only:
allowed = DERIVED_OUTPUT_LOCAL_NAMES.get(str(case.get("domain")), frozenset())
expected_items = [
(key, value)
for key, value in expected_items
if key.rsplit("#", 1)[-1] in allowed
(key, value) for key, value in expected_items if key.rsplit("#", 1)[-1] in allowed
]
expected = {
_short_id(key, kind="output"): _value_object(value)
for key, value in expected_items
_short_id(key, kind="output"): _value_object(value) for key, value in expected_items
}
return {
"caseId": case["caseId"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,11 @@ def main(argv: list[str] | None = None) -> int:
summary = {key: value for key, value in report.items() if key != "rows"}
summary["rowCount"] = len(report["rows"])
args.json_out.write_text(json.dumps(summary, indent=2, sort_keys=True) + "\n", encoding="utf-8")
print(json.dumps({"ok": True, "markdown": str(args.markdown), "json": str(args.json_out)}, indent=2))
print(
json.dumps(
{"ok": True, "markdown": str(args.markdown), "json": str(args.json_out)}, indent=2
)
)
return 0


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,7 @@ def _import_axiom():
"build_rulespec_nz_individual_income_tax_adapter": (
build_rulespec_nz_individual_income_tax_adapter
),
"build_rulespec_nz_acc_earners_levy_adapter": (
build_rulespec_nz_acc_earners_levy_adapter
),
"build_rulespec_nz_acc_earners_levy_adapter": (build_rulespec_nz_acc_earners_levy_adapter),
"build_rulespec_nz_kiwisaver_contributions_adapter": (
build_rulespec_nz_kiwisaver_contributions_adapter
),
Expand Down Expand Up @@ -177,7 +175,7 @@ def run_rulespec_cases(
for pic_id, payload in outputs.items():
# Reverse through expected map when possible.
durable_id = None
for rulespec_id in (case.get("expectedRulespec") or {}):
for rulespec_id in case.get("expectedRulespec") or {}:
from nz_reconciliation.pic_cases import _short_id

if _short_id(rulespec_id, kind="output") == pic_id:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ def compare_live(
"primary": rs.get("outputs", {}).get("individual_income_tax_before_credits")
or next(iter(rs.get("outputs", {}).values()), None)
}
of_out = {
"primary": of.get("outputs", {}).get("individual_income_tax_before_credits")
}
of_out = {"primary": of.get("outputs", {}).get("individual_income_tax_before_credits")}
pair = compare_pair(
{**rs, "outputs": {k: v for k, v in rs_out.items() if v}},
{**of, "outputs": {k: v for k, v in of_out.items() if v}},
Expand Down Expand Up @@ -94,8 +92,8 @@ def build_report(
"",
f"Cases: **{len(comparison_rows)}**",
f"Numeric agreements (≤$0.02): **{len(agreed)}**",
f"RuleSpec oracle ok: **{sum(1 for r in rulespec_rows if r.get('status')=='ok')}**",
f"OpenFisca live ok: **{sum(1 for r in openfisca_rows if r.get('status')=='ok')}**",
f"RuleSpec oracle ok: **{len([1 for r in rulespec_rows if r.get('status') == 'ok'])}**",
f"OpenFisca live ok: **{len([1 for r in openfisca_rows if r.get('status') == 'ok'])}**",
"",
"## Agreements",
"",
Expand Down Expand Up @@ -161,9 +159,9 @@ def main(argv: list[str] | None = None) -> int:
summary = {
"ok": True,
"cases": len(comparison_rows),
"agreements": sum(1 for r in comparison_rows if r.get("agreement")),
"rulespec_ok": sum(1 for r in rulespec_rows if r.get("status") == "ok"),
"openfisca_live_ok": sum(1 for r in openfisca_rows if r.get("status") == "ok"),
"agreements": len([1 for r in comparison_rows if r.get("agreement")]),
"rulespec_ok": len([1 for r in rulespec_rows if r.get("status") == "ok"]),
"openfisca_live_ok": len([1 for r in openfisca_rows if r.get("status") == "ok"]),
"report": str(results_dir / "LIVE_DUAL_ENGINE_REPORT.md"),
}
print(json.dumps(summary, indent=2))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,22 @@ def build_divergence_report(
klass = "engine_gap_no_earners_levy_surface"
else:
klass = "engine_gap_no_kiwisaver_surface_plus_rulespec_compile_block"
lines.append(f"| `{domain}` | {rs_status} ({len(rs)}) | {of_status} ({len(of)}) | `{klass}` |")
lines.append(
f"| `{domain}` | {rs_status} ({len(rs)}) | {of_status} ({len(of)}) | `{klass}` |"
)

lines.extend(
[
"",
"## Case rollup",
"",
f"- RuleSpec oracle rows: {len(rulespec_rows)} "
f"(ok={sum(1 for r in rulespec_rows if r.get('status')=='ok')}, "
f"compile_blocked={sum(1 for r in rulespec_rows if r.get('status')=='compile_blocked')})",
f"(ok={len([1 for r in rulespec_rows if r.get('status') == 'ok'])}, "
f"compile_blocked={len([1 for r in rulespec_rows if r.get('status') == 'compile_blocked'])})",
f"- OpenFisca gap rows: {len(openfisca_rows)} "
f"(engine_gap={sum(1 for r in openfisca_rows if r.get('status')=='engine_gap')})",
f"(engine_gap={len([1 for r in openfisca_rows if r.get('status') == 'engine_gap'])})",
f"- Comparison agreements (numeric): "
f"{sum(1 for c in comparison_rows if c.get('agreement'))} / {len(comparison_rows)}",
f"{len([1 for c in comparison_rows if c.get('agreement')])} / {len(comparison_rows)}",
"",
"Numeric agreements are expected to be **zero** while OpenFisca outputs remain empty gaps.",
"",
Expand Down Expand Up @@ -137,10 +139,10 @@ def main(argv: list[str] | None = None) -> int:
summary = {
"ok": True,
"cases": len(comparison_rows),
"rulespec_ok": sum(1 for r in rulespec_rows if r["status"] == "ok"),
"rulespec_blocked": sum(1 for r in rulespec_rows if r["status"] == "compile_blocked"),
"openfisca_gaps": sum(1 for r in openfisca_rows if r["status"] == "engine_gap"),
"numeric_agreements": sum(1 for c in comparison_rows if c.get("agreement")),
"rulespec_ok": len([1 for r in rulespec_rows if r["status"] == "ok"]),
"rulespec_blocked": len([1 for r in rulespec_rows if r["status"] == "compile_blocked"]),
"openfisca_gaps": len([1 for r in openfisca_rows if r["status"] == "engine_gap"]),
"numeric_agreements": len([1 for c in comparison_rows if c.get("agreement")]),
"report": str(results_dir / "DIVERGENCE_REPORT.md"),
}
print(json.dumps(summary, indent=2))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from decimal import Decimal

import pytest

from nz_reconciliation.comparison import compare_pair, compare_result_sets


Expand Down
5 changes: 4 additions & 1 deletion studies/nz-reconciliation/runner/tests/test_inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ def test_inventory_covers_required_domains() -> None:
def test_select_cases_can_exclude_blocked_kiwisaver() -> None:
inventory = load_inventory(INVENTORY)
runnable = select_cases(inventory, include_blocked=False)
assert all(case["domain"] != "kiwisaver" or case["rulespec"]["compileStatus"] == "ok" for case in runnable)
assert all(
case["domain"] != "kiwisaver" or case["rulespec"]["compileStatus"] == "ok"
for case in runnable
)
assert all(case["rulespec"]["compileStatus"] == "ok" for case in runnable)
assert len(runnable) >= 14 # 5 income tax + 9 ACC

Expand Down
19 changes: 15 additions & 4 deletions studies/nz-reconciliation/runner/tests/test_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ def test_annotate_inventory_case_updates_openfisca_block() -> None:
case = {
"caseId": "nz-recon/income_tax.x",
"domain": "income_tax",
"openfiscaAotearoa": {"repo": "ServiceInnovationLab/openfisca-aotearoa", "status": "pending_mapping"},
"openfiscaAotearoa": {
"repo": "ServiceInnovationLab/openfisca-aotearoa",
"status": "pending_mapping",
},
}
annotated = annotate_inventory_case(case)
assert annotated["openfiscaAotearoa"]["status"] == "engine_gap"
assert "progressive" in annotated["openfiscaAotearoa"]["notes"].lower() or "tax" in annotated["openfiscaAotearoa"]["notes"].lower()
assert (
"progressive" in annotated["openfiscaAotearoa"]["notes"].lower()
or "tax" in annotated["openfiscaAotearoa"]["notes"].lower()
)


def test_inventory_case_to_pic_case_maps_income_tax_ids() -> None:
Expand All @@ -35,11 +41,16 @@ def test_inventory_case_to_pic_case_maps_income_tax_ids() -> None:
"nz:statutes/income_tax/schedule_1/individual_income_tax#individual_income_tax_before_credits": 1638,
},
"sourceRefs": ["https://example.test"],
"rulespec": {"testPath": "nz/statutes/income_tax/schedule_1/individual_income_tax.test.yaml"},
"rulespec": {
"testPath": "nz/statutes/income_tax/schedule_1/individual_income_tax.test.yaml"
},
}
pic = inventory_case_to_pic_case(case)
assert "nz-income-tax/variable.taxable_income" in pic["inputs"]
assert pic["inputs"]["nz-income-tax/variable.taxable_income"]["value"] == "15600"
assert "nz-income-tax/decision.individual_income_tax_before_credits" in pic["expected"]
assert "nz-income-tax/decision.individual_income_tax_bracket_thresholds" not in pic["expected"]
assert pic["expected"]["nz-income-tax/decision.individual_income_tax_before_credits"]["value"] == "1638"
assert (
pic["expected"]["nz-income-tax/decision.individual_income_tax_before_credits"]["value"]
== "1638"
)
Loading