Skip to content
Merged
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 @@ -786,7 +786,7 @@
],
"budget_measure": "qualified_business_income_deduction",
"effect_direction": "baseline_minus_reform",
"expected_sign": "negative",
"expected_sign": "either",
"id": "qbi_farm_operations_income_exclusion",
"issue": "PolicyEngine/populace#298",
"min_abs_effect": 1000000.0,
Expand All @@ -803,7 +803,7 @@
}
},
"period": 2026,
"reason": "Removing only farm_operations_income from the 2026 Section 199A income definition isolates the restored signed Schedule F leaf. The real staged candidate is loss-heavy, so excluding it raises QBID and baseline-minus-reform is negative (-$4.16M). Without farm_operations_income the reform is a structural zero."
"reason": "Removing only farm_operations_income from the 2026 Section 199A income definition isolates the restored Schedule F leaf. The leaf is signed and two-channel: the ASEC channel carries the measured FRSE farm self-employment values (net-positive in the pooled frame) and the PUF channel carries the donor-pinned signed Schedule F values (net-negative, loss-heavy, populace#435), so the aggregate QBID effect direction is a property of the frame mix and the solve, not of coverage. The probe therefore requires a binding effect of at least the floor in either direction; a structural zero still fails."
},
{
"binding_inputs": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,16 @@ def us_reform_coverage_smoke_gate(
effect = baseline_total - reform_total
else:
effect = reform_total - baseline_total
signed_magnitude = effect if probe.expected_sign == "positive" else -effect
# "either" proves BINDING without a directional claim: the probe
# passes when the reform moves the measure by the floor in either
# direction. For a signed, two-channel input (measured ASEC leg plus
# donor-pinned PUF leg, e.g. farm_operations_income) the aggregate
# sign is a property of the frame mix, not of coverage — pinning a
# direction rots when the frame's honest composition changes.
if probe.expected_sign == "either":
signed_magnitude = abs(effect)
else:
signed_magnitude = effect if probe.expected_sign == "positive" else -effect
passed = signed_magnitude >= probe.min_abs_effect
results[probe.id] = {
"name": probe.name,
Expand All @@ -126,10 +135,15 @@ def us_reform_coverage_smoke_gate(
"passed": passed,
}
if not passed:
expectation = (
"an effect in either direction"
if probe.expected_sign == "either"
else f"a {probe.expected_sign} effect"
)
failures.append(
f"{probe.id}: '{probe.name}' scores {effect:+,.0f} on "
f"{probe.budget_measure} for {probe_period}; expected a "
f"{probe.expected_sign} effect with magnitude at least "
f"{probe.budget_measure} for {probe_period}; expected "
f"{expectation} with magnitude at least "
f"${probe.min_abs_effect:,.0f}. The reform did not bind as "
"declared, so its input leaves "
f"{list(probe.binding_inputs)} are absent or degenerate on the "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,9 @@ def __post_init__(self) -> None:
raise ValueError(f"{self.id}: min_abs_effect must be positive.")
if self.period is not None and self.period < 1990:
raise ValueError(f"{self.id}: period must be a plausible year.")
if self.expected_sign not in {"positive", "negative"}:
if self.expected_sign not in {"positive", "negative", "either"}:
raise ValueError(
f"{self.id}: expected_sign must be 'positive' or 'negative'."
f"{self.id}: expected_sign must be 'positive', 'negative', or 'either'."
)


Expand Down
60 changes: 59 additions & 1 deletion packages/populace-build/tests/test_release_input_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,61 @@ def test_negative_overtime_effect_passes_and_wrong_sign_fails(
assert not wrong_sign.passed
assert "expected a negative effect" in wrong_sign.failures[0]

def test_either_sign_probe_passes_both_directions_and_keeps_floor_teeth(
self, monkeypatch
) -> None:
# A signed, two-channel input (e.g. farm_operations_income: measured
# ASEC leg plus donor-pinned PUF leg) proves COVERAGE by moving the
# measure at all — the aggregate direction is a property of the frame
# mix, not of coverage. "either" accepts the floor in both directions
# while a structural (sub-floor) effect still fails.
monkeypatch.setattr(smoke_module, "_build_reform", lambda changes: "REFORM")
probe = ReformCoverageProbe(
id="either_probe",
name="Signed two-channel leaf exclusion",
parameter_changes={"gov.example.switch": {"2026-01-01.2026-12-31": 0}},
budget_measure="income_tax",
binding_inputs=("farm_operations_income",),
min_abs_effect=1_000_000.0,
reason="The exclusion binds through a signed leaf.",
issue="PolicyEngine/populace#298",
effect_direction="baseline_minus_reform",
expected_sign="either",
)

positive = us_reform_coverage_smoke_gate(
simulate=lambda reform: _Sim(9.0e9 if reform else 10.0e9),
probes=[probe],
)
assert positive.passed

negative = us_reform_coverage_smoke_gate(
simulate=lambda reform: _Sim(11.0e9 if reform else 10.0e9),
probes=[probe],
)
assert negative.passed

structural_zero = us_reform_coverage_smoke_gate(
simulate=lambda reform: _Sim(10.0e9 + (1.0e5 if reform else 0.0)),
probes=[probe],
)
assert not structural_zero.passed
assert "an effect in either direction" in structural_zero.failures[0]

def test_probe_rejects_unknown_expected_sign(self) -> None:
with pytest.raises(ValueError, match="expected_sign must be"):
ReformCoverageProbe(
id="bad_sign",
name="Bad sign",
parameter_changes={"gov.example.switch": {"2026": 0}},
budget_measure="income_tax",
binding_inputs=("x",),
min_abs_effect=1.0,
reason="r.",
issue="PolicyEngine/populace#1",
expected_sign="sideways",
)

def test_negative_auto_loan_effect_passes_and_wrong_sign_fails(
self, monkeypatch
) -> None:
Expand Down Expand Up @@ -1089,9 +1144,12 @@ def test_shipped_farm_probes_each_remove_only_the_bound_qbi_leaf(self) -> None:
"estate_income",
}
cases = {
# "either": the leaf is signed and two-channel (measured ASEC FRSE
# plus donor-pinned PUF Schedule F, populace#435) — the aggregate
# QBID direction is a frame property, not a coverage property.
"qbi_farm_operations_income_exclusion": (
"farm_operations_income",
"negative",
"either",
),
"qbi_farm_rent_income_exclusion": ("farm_rent_income", "positive"),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3506,7 +3506,10 @@ def fake_reconcile(frame, initial_result, specs, **kwargs):
try:
builder.main()
except RuntimeError as exc:
assert str(exc) == "Release gates failed: ctc failed"
# The batched pre-write report leads with the calibration battery
# failure; degraded-mode coverage/parity evaluation errors on the
# fake frame may append further lines after it.
assert str(exc).startswith("Release gates failed: ctc failed")
else: # pragma: no cover - defensive assertion
raise AssertionError("Expected post-calibration gate failure.")

Expand Down
Loading
Loading