fix(consume): a withheld concept carries the rule that actually decided it
The quota filters the WHOLE candidate list, so every over-quota candidate came back `source_quota_exceeded` -- including the ones the RANK had already put outside k, which the quota only reached because it ran first. `_fates_without_quota` asks the same cut what would have become of each candidate with no quota, and the drop keeps THAT rule; only a candidate the quota-off cut would have delivered is named as the quota's. The packer is lifted into `_pack` and used by both, so the quota-off fate is decided by the code the run itself uses and never by a second implementation. The retrieval gate's row 3 goes 2 of 5 RED to 5 of 5 GREEN. Row 7 is unchanged at 12 of 14; M01 and M02 lose their row-3 credit, which was the lying label moving and not the ranking. Suite: 2288 passed, 0 failed; no committed payload moves a byte. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
6b62ecea34
commit
f81683ea54
2 changed files with 141 additions and 46 deletions
|
|
@ -230,9 +230,22 @@ def test_a_miss_with_no_class_at_all_takes_the_whole_row_to_zero(tmp_path: Path)
|
|||
# --- row 3 --------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_row_three_is_red_because_the_payload_names_the_quota_for_a_rank(
|
||||
tmp_path: Path,
|
||||
def test_row_three_goes_red_again_the_moment_the_label_stops_being_true(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""The RED direction, driven by an input: the library's own behaviour.
|
||||
|
||||
This row was red on the shipped code until 2026-09-20 -- every over-quota
|
||||
candidate came back `source_quota_exceeded`, including the ones the RANK
|
||||
had already put outside k. Restoring exactly that naming puts the row back
|
||||
where it was, with the same three fixtures and the same detail line, so
|
||||
the green reading is not a green nobody can lose.
|
||||
"""
|
||||
|
||||
def every_drop_is_the_quotas(candidates: object, **_: object) -> dict[str, str]:
|
||||
return _AlwaysTheQuota()
|
||||
|
||||
monkeypatch.setattr(consume, "_fates_without_quota", every_drop_is_the_quotas)
|
||||
row = gate.row_three([_case(tmp_path, "set-classes.json")])
|
||||
assert row.status == gate.RED
|
||||
lying = [detail for detail in row.details if "source_quota_exceeded" in detail]
|
||||
|
|
@ -240,6 +253,23 @@ def test_row_three_is_red_because_the_payload_names_the_quota_for_a_rank(
|
|||
assert all("the quota-off run says `below_k`" in detail for detail in lying)
|
||||
|
||||
|
||||
class _AlwaysTheQuota(dict[str, str]):
|
||||
"""The pre-2026-09-20 naming: every drop the quota reached is the quota's."""
|
||||
|
||||
def __missing__(self, key: str) -> str:
|
||||
return "source_quota_exceeded"
|
||||
|
||||
|
||||
def test_row_three_is_green_on_the_shipped_code(tmp_path: Path) -> None:
|
||||
"""And the same three fixtures, unmutated, are the green direction.
|
||||
|
||||
Four judged units in this set alone; the fifth in the gate's own run comes
|
||||
from `set-miss.json`."""
|
||||
row = gate.row_three([_case(tmp_path, "set-classes.json")])
|
||||
assert (row.k, row.m, row.status) == (4, 4, gate.GREEN)
|
||||
assert not [detail for detail in row.details if "source_quota_exceeded" in detail]
|
||||
|
||||
|
||||
def test_row_three_is_green_when_the_printed_reason_is_the_true_one(tmp_path: Path) -> None:
|
||||
# The budget case: withheld by the pack in BOTH runs, so the label the
|
||||
# payload prints is the label the quota-off run confirms.
|
||||
|
|
@ -455,19 +485,28 @@ def test_row_seven_is_red_when_a_mutant_survives(tmp_path: Path) -> None:
|
|||
)
|
||||
|
||||
|
||||
def test_a_mutant_that_only_makes_a_red_row_greener_is_not_felled(tmp_path: Path) -> None:
|
||||
# The definition, held by a test: removing the quota makes row 3's label
|
||||
# honest, because there is then no quota to name. Calling that a kill
|
||||
# would credit this gate with a check it does not have.
|
||||
def test_a_mutant_is_felled_by_the_row_that_got_worse_and_never_by_one_that_did_not(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""PM's definition, held by a test: `worse`, never `different`.
|
||||
|
||||
Removing the quota costs row 1 deliveries -- that is the kill. It costs
|
||||
row 3 nothing, because a cut with no quota has no quota to name falsely,
|
||||
and crediting row 3 with the kill would give this gate a check it does not
|
||||
have. Before 2026-09-20 the same mutation made row 3 GREENER, which was
|
||||
the sharper form of the same point.
|
||||
"""
|
||||
cases, _ = gate.synthetic_cases(tmp_path / "bundles", FIXTURES)
|
||||
baseline = gate.deterministic_rows(cases)
|
||||
before = {row.number: (row.k, row.m) for row in baseline}
|
||||
before = {row.number: row.k for row in gate.deterministic_rows(cases)}
|
||||
with gate._wrap_cut(source_quota=None):
|
||||
rows = gate.deterministic_rows(
|
||||
[gate.measure_case(case.question_set, case.bundles) for case in cases]
|
||||
)
|
||||
after = {row.number: (row.k, row.m) for row in rows}
|
||||
assert after[3][0] - after[3][1] > before[3][0] - before[3][1]
|
||||
after = {row.number: row.k for row in rows}
|
||||
worse = [number for number in sorted(before) if after[number] < before[number]]
|
||||
assert 1 in worse, "row 1 is what fells this mutant"
|
||||
assert 3 not in worse, after
|
||||
assert after[3] >= before[3]
|
||||
|
||||
|
||||
# --- rows 8 and 9 -------------------------------------------------------------
|
||||
|
|
@ -600,12 +639,12 @@ def test_the_gate_is_red_today_and_says_which_rows(tmp_path: Path) -> None:
|
|||
rows = gate.evaluate(tmp_path / "bundles")
|
||||
by_number = {row.number: row for row in rows}
|
||||
assert sorted(by_number) == [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
assert [row.number for row in rows if row.fails] == [3, 4, 5, 7, 8, 9]
|
||||
assert [row.number for row in rows if row.fails] == [4, 5, 7, 8, 9]
|
||||
# 10, not 9: `set-quota.json` adds row 3's known-positive, one question the
|
||||
# source quota genuinely decides, and it is a hit.
|
||||
assert (by_number[1].k, by_number[1].m) == (10, 10)
|
||||
assert (by_number[2].k, by_number[2].m) == (7, 7)
|
||||
assert (by_number[3].k, by_number[3].m) == (2, 5)
|
||||
assert (by_number[3].k, by_number[3].m) == (5, 5)
|
||||
assert (by_number[6].k, by_number[6].m) == (10, 10)
|
||||
|
||||
|
||||
|
|
@ -622,7 +661,7 @@ def test_the_command_exits_one_and_prints_every_row(
|
|||
printed = capsys.readouterr().out
|
||||
for number in range(1, 10):
|
||||
assert f"\n{number} " in f"\n{printed}"
|
||||
assert "GATE RED: rows 3, 4, 5, 7, 8, 9" in printed
|
||||
assert "GATE RED: rows 4, 5, 7, 8, 9" in printed
|
||||
|
||||
|
||||
def test_the_json_form_carries_the_same_rows(capsys: pytest.CaptureFixture[str]) -> None:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue