Code Farm: per-plot auto-replant pause and crop-lock check; community sync and node work

Continuous Delivery could never be turned off once a crop was planted. Add a
one-shot per-plot "stop after harvest" flag (POST /game/plot/stop, Devii tool
game_plot_stop, game_plots.stop_after_harvest), cleared by the next plant,
autoreplant claim or Refactor. Autoreplant now also respects crop locks through
the shared _crop_lock predicate. Plan and measurements in happyplanting.md.

Also includes the pending community sync, node network and related work in the
tree; the full suite passed (4999) with all of it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 02:23:43 +02:00
co-authored by Claude Sonnet 5.5
parent ce899fc5e1
commit 02ab747cd0
203 changed files with 11624 additions and 301 deletions
+54
View File
@@ -95,3 +95,57 @@ def test_a_zero_threshold_still_needs_one_failure():
assert breaker.allows("x")
breaker.failure("x")
assert not breaker.allows("x")
def test_snapshot_lists_open_circuits_with_time_left():
breaker, clock = make(failures=2, open_seconds=60)
breaker.failure(("destination", "reddit.com"))
breaker.failure(("destination", "reddit.com"))
clock.now = 20
rows = breaker.snapshot()
assert rows[0]["key"] == "destination:reddit.com" and rows[0]["state"] == "open"
assert 39 <= rows[0]["seconds_left"] <= 40 and rows[0]["failures"] == 2
def test_dirty_flag_follows_every_change():
breaker, _ = make(failures=2)
assert not breaker.dirty
breaker.failure("x")
assert breaker.dirty
breaker.dirty = False
breaker.success("x")
assert breaker.dirty
breaker.dirty = False
breaker.success("never-seen")
assert not breaker.dirty
def test_a_restart_keeps_an_open_circuit_open_until_its_time_is_up():
wall = {"now": 1_000_000.0}
clock = Clock()
first = CircuitBreaker(2, 60, clock, wall=lambda: wall["now"])
first.failure(("destination", "reddit.com"))
first.failure(("destination", "reddit.com"))
clock.now = 10
wall["now"] += 10
saved = first.snapshot()
second_clock = Clock()
second_clock.now = 5000
second = CircuitBreaker(2, 60, second_clock, wall=lambda: wall["now"] + 5)
assert second.restore(saved) == 1
assert second.state(("destination", "reddit.com")) == OPEN
second_clock.now += 60
assert second.state(("destination", "reddit.com")) == HALF_OPEN
def test_restore_ignores_closed_ancient_and_malformed_rows():
wall = {"now": 1_000_000.0}
breaker = CircuitBreaker(3, 60, Clock(), wall=lambda: wall["now"])
rows = [
{"key": "destination:a", "failures": 1, "opened_at": wall["now"]},
{"key": "destination:b", "failures": 3, "opened_at": wall["now"] - 10_000},
{"key": "nocolon", "failures": 9, "opened_at": wall["now"]},
{"key": "destination:c", "failures": 9, "opened_at": 0},
]
assert breaker.restore(rows) == 0
assert breaker.open_count() == 0