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
+70
View File
@@ -107,3 +107,73 @@ def test_clear_empties_everything():
cache.put("GET", "u", 200, {}, b"x", False)
cache.clear()
assert len(cache) == 0 and cache.size_bytes == 0
def test_age_moves_the_expiry_forward():
cache, clock = make(ttl_seconds=100)
cache.put("GET", "https://r/x", 200, {}, b"x", False, age_seconds=90)
clock.now = 105
assert cache.get("GET", "https://r/x") is not None
clock.now = 111
assert cache.get("GET", "https://r/x") is None
def shared(local_db, **kwargs):
from devplacepy.database import nodes as store
from devplacepy.services.nodes.cache import SharedResultCache
store.cache_clear()
clock = Clock()
return SharedResultCache(clock=clock, **kwargs), clock, store
def test_a_second_process_sees_what_the_first_stored(local_db):
first, _, store = shared(local_db, ttl_seconds=60)
assert first.put("GET", "https://r/a", 200, {"content-type": "text/plain"}, b"payload", False)
from devplacepy.services.nodes.cache import SharedResultCache
second = SharedResultCache(ttl_seconds=60)
hit = second.get("GET", "https://r/a")
assert hit is not None and hit.body == b"payload" and hit.headers == {"content-type": "text/plain"}
assert (second.hits, second.misses) == (1, 0)
again = second.get("GET", "https://r/a")
assert again is not None and second.hits == 2
store.cache_clear()
def test_the_shared_layer_honours_ttl_truncation_and_server_errors(local_db):
cache, _, store = shared(local_db, ttl_seconds=60)
assert not cache.put("GET", "https://r/b", 500, {}, b"x", False)
assert not cache.put("GET", "https://r/b", 200, {}, b"x", True)
assert store.cache_stats()["entries"] == 0
cache.put("GET", "https://r/c", 200, {}, b"x", False)
from datetime import datetime, timedelta, timezone
assert store.cache_get("k-not-there") is None
key = cache_key("GET", "https://r/c")
assert store.cache_get(key) is not None
assert store.cache_get(key, datetime.now(timezone.utc) + timedelta(seconds=120)) is None
store.cache_clear()
def test_clear_empties_both_layers(local_db):
cache, _, store = shared(local_db, ttl_seconds=60)
cache.put("GET", "https://r/d", 200, {}, b"x", False)
cache.clear()
assert len(cache) == 0 and store.cache_stats()["entries"] == 0
def test_the_shared_layer_prunes_expired_rows_and_evicts_oldest_over_the_cap(local_db):
from datetime import datetime, timedelta, timezone
cache, _, store = shared(local_db, ttl_seconds=60)
now = datetime.now(timezone.utc)
for index in range(4):
store.cache_put(f"k{index}", "GET", f"https://r/{index}", 200, "{}", "AAAA", 1000, 60, now + timedelta(seconds=index))
store.cache_put("old", "GET", "https://r/old", 200, "{}", "AAAA", 10, 60, now - timedelta(seconds=300))
removed = store.cache_prune(2500)
assert removed["expired"] == 1 and removed["evicted"] == 2 and removed["bytes"] == 2000
left = store.cache_stats()
assert left["entries"] == 2
assert store.cache_get("k0") is None and store.cache_get("k3") is not None
store.cache_clear()