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
+217 -1
View File
@@ -19,6 +19,9 @@ from devplacepy.services.nodes.scheduler import MEGABYTE, NodeScheduler
from devplacepy.services.nodes.session import NodeSession
from devplacepy.services.nodes.spec import SPEC
from devplacepy.utils import generate_uid
import asyncio
from concurrent.futures import ThreadPoolExecutor
from tests.conftest import run_async
from tests.unit.services.nodes.scheduler import Clock, node, settings
@@ -26,6 +29,11 @@ LIMITS = SPEC.limits
TARGET_URL = "https://www.reddit.com/r/python.json"
def run_in_thread(coro):
with ThreadPoolExecutor(max_workers=1) as pool:
return pool.submit(asyncio.run, coro).result()
class Rig:
def __init__(self):
self.clock = Clock()
@@ -38,12 +46,13 @@ class Rig:
self.registry, self.scheduler, self.broker, self.breaker, UsageLedger(), self.counters,
clock=self.clock,
)
self.dispatcher.redundancy_percent = staticmethod(lambda: 0)
def connect(self, **overrides):
owner = generate_uid()
device, _ = store.create_device(owner, "d", "native")
session = NodeSession(
node().websocket, {"uid": device["uid"], "user_uid": owner, "kind": "native"}
node().websocket, {"uid": device["uid"], "user_uid": owner, "kind": "native", "asn_class": "residential"}
)
session.hello = {"modes": ["fetch"]}
session.settings = settings(**overrides)
@@ -413,3 +422,210 @@ def test_the_owner_exclusion_does_not_saturate_the_destination(rig):
other.host_started.clear()
rig.tick()
assert second in mine.inflight
def test_the_claim_records_the_donor_address_class(rig):
session = rig.connect()
session.asn_class = "mobile"
uid = rig.enqueue()
rig.tick()
assert store.get_request(uid)["device_asn_class"] == "mobile"
def test_outcomes_are_observed_per_class(rig):
session = rig.connect()
uid = rig.enqueue()
rig.tick()
rig.answer(session, uid)
other = rig.enqueue(url="https://www.reddit.com/r/two.json")
rig.clock.now += 100
rig.tick()
rig.answer(session, other, status=403)
third = rig.enqueue(url="https://www.reddit.com/r/three.json")
rig.clock.now += 100
rig.tick()
rig.answer(session, third, status=404)
seen = rig.counters.outcomes()
assert seen["outcome:reddit:residential:ok"] == 2 and seen["outcome:reddit:residential:blocked"] == 1
def test_a_node_failure_is_observed_but_a_donor_limit_is_not(rig):
session = rig.connect()
uid = rig.enqueue()
rig.tick()
run_async(session._handle({"type": "job_error", "job_id": uid, "code": "fetch_failed"}))
assert rig.counters.outcomes().get("outcome:reddit:residential:failed") == 1
rig.clock.now += 100
session.paused_until = 0
second = rig.enqueue(url="https://www.reddit.com/r/two.json")
rig.tick()
run_async(session._handle({"type": "job_error", "job_id": second, "code": "outside_hours"}))
assert rig.counters.outcomes().get("outcome:reddit:residential:failed") == 1
def test_on_battery_pauses_the_donor_without_blaming_it(rig):
session = rig.connect()
uid = rig.enqueue()
rig.tick()
run_async(session._handle({"type": "job_error", "job_id": uid, "code": "on_battery"}))
assert session.paused_until > rig.clock()
assert not rig.breaker.failures or rig.breaker.allows(("node", session.device_uid))
assert store.get_request(uid)["error"] == "on_battery"
class SampleAll:
def __init__(self, rig):
rig.dispatcher.redundancy_percent = staticmethod(lambda: 100)
def mismatch_flags(device_uid=None):
return [
flag
for flag in store.list_flags()
if flag["kind"] == "redundancy_mismatch" and (device_uid is None or flag["device_uid"] == device_uid)
]
def sent_to(session):
return [frame["job_id"] for frame in session.websocket.sent if frame["type"] == "job"]
def test_a_sampled_fetch_result_is_cross_checked_on_a_different_donor(rig):
SampleAll(rig)
first, second = rig.connect(), rig.connect()
uid = rig.enqueue()
rig.tick()
holder = first if uid in sent_to(first) else second
other = second if holder is first else first
rig.answer(holder, uid, headers={"content-type": "application/json"}, body_b64=base64.b64encode(b'{"kind":"Listing","data":{}}').decode())
shadows = list(get_table("node_requests").find(shadow_of=uid))
assert len(shadows) == 1 and shadows[0]["exclude_device"] == holder.device_uid
assert shadows[0]["caller_kind"] == "shadow"
rig.clock.now += 100
assert rig.tick() == 1
assert sent_to(other) and shadows[0]["uid"] in sent_to(other)
rig.answer(other, shadows[0]["uid"], headers={"content-type": "application/json"}, body_b64=base64.b64encode(b'{"kind":"Listing","data":{}}').decode())
counts = rig.counters.snapshot()
assert counts["redundancy_checked"] == 1 and counts["redundancy_matched"] == 1
assert not mismatch_flags(other.device_uid)
def test_a_forged_second_opinion_raises_a_flag_and_no_ban(rig):
SampleAll(rig)
first, second = rig.connect(), rig.connect()
uid = rig.enqueue()
rig.tick()
holder = first if uid in sent_to(first) else second
other = second if holder is first else first
rig.answer(holder, uid, headers={"content-type": "application/json"}, body_b64=base64.b64encode(b'{"kind":"Listing","data":{}}').decode())
shadow = list(get_table("node_requests").find(shadow_of=uid))[0]["uid"]
rig.clock.now += 100
rig.tick()
rig.answer(other, shadow, headers={"content-type": "application/json"}, body_b64=base64.b64encode(b'{"buy":"now"}').decode())
assert rig.counters.snapshot()["redundancy_mismatches"] == 1
flags = mismatch_flags(other.device_uid)
assert len(flags) == 1
assert effective_status_of(other) == "active"
def effective_status_of(session):
return store.effective_status(store.get_device(session.device_uid))
def test_a_shadow_never_spends_the_caller_quota_and_is_not_cross_checked_again(rig):
SampleAll(rig)
first, second = rig.connect(), rig.connect()
uid = rig.enqueue()
rig.tick()
holder = first if uid in sent_to(first) else second
other = second if holder is first else first
rig.answer(holder, uid)
shadow = list(get_table("node_requests").find(shadow_of=uid))[0]["uid"]
rig.clock.now += 100
rig.tick()
rig.answer(other, shadow)
assert get_table("node_requests").count(shadow_of={"!=": ""}) == 1
def test_sampling_is_deterministic_and_close_to_the_requested_rate():
uids = [generate_uid() for _ in range(10000)]
chosen = [uid for uid in uids if NodeDispatcher.sampled(uid, 5)]
assert chosen == [uid for uid in uids if NodeDispatcher.sampled(uid, 5)]
assert 350 <= len(chosen) <= 650
assert not any(NodeDispatcher.sampled(uid, 0) for uid in uids[:500])
assert all(NodeDispatcher.sampled(uid, 100) for uid in uids[:500])
def test_the_percent_is_clamped_to_the_spec_ceiling(local_db):
from devplacepy.database import set_setting
set_setting("nodes_redundancy_percent", "99")
try:
assert NodeDispatcher.redundancy_percent() == LIMITS.redundancy_max_percent
set_setting("nodes_redundancy_percent", "-4")
assert NodeDispatcher.redundancy_percent() == 0
finally:
set_setting("nodes_redundancy_percent", str(LIMITS.redundancy_percent))
def test_a_missing_original_is_inconclusive_not_a_flag(rig):
session = rig.connect()
rig.dispatcher._compare_shadow(session, type("J", (), {"shadow_of": "gone", "destination": "reddit.com"})(), 200, {}, b"x")
assert rig.counters.snapshot()["redundancy_inconclusive"] == 1
assert not mismatch_flags(session.device_uid)
def test_a_waiter_in_the_dispatcher_process_wakes_without_polling(rig):
import asyncio
from devplacepy.services.nodes.wake import HUB
async def scenario():
HUB.attach()
target = DestinationPolicy().check(TARGET_URL)
uid = rig.broker.enqueue("user", "c1", target, "any")
store.claim_request(uid, "d1")
loop = asyncio.get_running_loop()
loop.call_later(0.02, lambda: rig.broker.complete(uid, 200, {}, b"ok", False))
started = time.monotonic()
result = await rig.broker.wait(uid, 5)
return result, time.monotonic() - started
try:
result, elapsed = run_in_thread(scenario())
finally:
HUB.enabled = True
assert result.ok and result.body == b"ok"
assert elapsed < LIMITS.poll_interval_ms / 1000
def test_a_waiter_without_the_hub_still_finishes_by_polling(rig):
import asyncio
from devplacepy.services.nodes.wake import HUB
async def scenario():
target = DestinationPolicy().check(TARGET_URL)
uid = rig.broker.enqueue("user", "c2", target, "any")
store.claim_request(uid, "d1")
asyncio.get_running_loop().call_later(0.02, lambda: rig.broker.complete(uid, 200, {}, b"ok", False))
return await rig.broker.wait(uid, 5)
HUB._loop = None
assert run_in_thread(scenario()).ok
def test_enqueue_signals_the_dispatcher(rig):
import asyncio
from devplacepy.services.nodes.wake import HUB
async def scenario():
HUB.attach()
target = DestinationPolicy().check(TARGET_URL)
woke = asyncio.ensure_future(HUB.wait_queued(5))
await asyncio.sleep(0)
rig.broker.enqueue("user", "c3", target, "any")
return await asyncio.wait_for(woke, 1)
assert run_in_thread(scenario()) is True