Release: dev → main (first public release) #258

Merged
bvandeusen merged 94 commits from dev into main 2026-09-25 10:02:40 -04:00
Showing only changes of commit 468ff71353 - Show all commits
+16 -28
View File
@@ -273,9 +273,14 @@ def test_one_lane_failing_does_not_stop_the_others(monkeypatch):
def test_a_lane_disabled_in_settings_but_still_consuming_is_stopped(monkeypatch):
"""The case that made `consuming` necessary: a lane turned off while its
worker was down comes back consuming, and must be stopped when it
returns."""
returns.
Its live pool is ONE — zero slots means zero WORK, not an empty pool.
billiard will not run one, and the process is what the enable switch lands
on.
"""
control = _stub_control(monkeypatch)
_stub_live(monkeypatch, "ml", pools={"host-a": 0}, consuming={"ml"})
_stub_live(monkeypatch, "ml", pools={"host-a": 1}, consuming={"ml"})
result = wc.reconcile_lanes_sync({"ml": (0, False)})
@@ -286,9 +291,16 @@ def test_a_lane_disabled_in_settings_but_still_consuming_is_stopped(monkeypatch)
def test_an_already_disabled_lane_is_not_cancelled_again(monkeypatch):
"""The other half of the fixed point. `cancel_consumer` on a queue that is
not being consumed succeeds and does nothing, so an unconditional
reconcile would churn here forever with no symptom."""
reconcile would churn here forever with no symptom.
The live pool is ONE, not zero. This fixture said zero until the floor
landed, and it was describing a container that cannot exist — billiard
will not run an empty pool, and the generator starts ml at one process for
exactly that reason. A fixture in an impossible state passes for the wrong
reason and then fails on the correct fix, which is what it did.
"""
control = _stub_control(monkeypatch)
_stub_live(monkeypatch, "ml", pools={"host-a": 0}, consuming=set())
_stub_live(monkeypatch, "ml", pools={"host-a": 1}, consuming=set())
result = wc.reconcile_lanes_sync({"ml": (0, False)})
@@ -692,30 +704,6 @@ def test_a_lane_at_zero_slots_is_never_shrunk_to_an_empty_pool(monkeypatch):
assert control.shrank == [], "tried to empty a pool billiard will not empty"
def test_that_lane_then_reports_nothing_to_do(monkeypatch):
"""The fixed point. It is not enough to stop sending the doomed message —
the reconcile must also stop CALLING the lane changed, or the log fills
with a correction that never corrects anything."""
_stub_control(monkeypatch)
_stub_live(monkeypatch, "ml", pools={"host-a": 1}, consuming=set())
result = wc.reconcile_lanes_sync({"ml": (0, False)})
assert result["changed"] == []
def test_zero_slots_still_means_zero_work(monkeypatch):
"""The floor is one PROCESS, not one consumer. A lane at zero keeps an
idle worker so the enable switch has something to reach, and stays off
because its queues are cancelled."""
control = _stub_control(monkeypatch)
_stub_live(monkeypatch, "ml", pools={"host-a": 1}, consuming={"ml"})
wc.reconcile_lanes_sync({"ml": (0, False)})
assert control.cancelled == [("ml", ["host-a"])]
def test_the_floor_applies_to_a_direct_resize_too(monkeypatch):
"""Not only the reconcile — the UI dial and the autoscaler go through the
same function, so the clamp belongs there rather than at each caller."""