M1-04 part A (2026-10-11) - bot client + 60 s 1,000-bot run + loop profile. Mac: 8 cores (4P+4E), load average recorded per run. 1) 200-client load check re-run (pnpm zone:loadcheck, M1-03D harness) -> loadcheck-200.json - load 11.3: FAIL only loop p99 21.4 ms (p50 3.5, CPU 3.73 ms/tick) [logs/test-output/M1-04-01.log] - load 3.4: PASS loop p50 3.97 p99 5.53 max 5.78 ms, CPU 3.86 ms/tick, down mean 12.7 KB/s, 0 skipped [M1-04-02.log] => the M1-03D 84.7 ms p99 was machine load; at 200 clients the loop fits the 15 ms target. 2) pnpm zone:bots (services/bots, new crate zoen-bots, no external crates) - 1,000 bots on 4 poll(2) worker threads + 1 connector thread (linear ramp), in-process server (tick thread CPU clock, 1 s windows). - walk: waypoint wander (25% crowd the town within 50 m of the start centre, 75% walk to a random hunting zone and wander in it). - fight: hunters cast every 2-6 s inside their zone (stand still 800 ms); the cast is NOT sent: protocol v1 input has no action bits. - chat: NOT in protocol v1; bot-side timer every 15-45 s, counted only. -> protocol owner task: action bits + chat message. 3) 1,000 bots, 20 s ramp + 60 s hold, load 3.5 -> 24.9 during the run -> metrics.json [M1-04-03.log, FAIL on loop p99 only] - 1000/1000 joined, 0 disconnects, 1000 clean closes, 0 missed ticks, 0 skipped frames, 0 dropped ticks, 0 stale/dropped inputs - downstream per bot over the hold: mean 8.5 KB/s, p95 10.2, max 10.6 (target avg <= 12, cap 32) - PASS - RTT p50 39.3 ms, p99 52.5 ms (tick answers pings: ~1 tick period is server queueing) - loop wall p50 17.9, p99 32.0, max 61.9 ms (target p99 15) - FAIL; 1,237 of 1,602 loops over target - tick-thread CPU per loop: mean 15.1, p99 21.7 ms -> the loop is CPU-bound, not just machine load - phase means (wall): ingest 0.36, tick (sim+hash+interest) 2.74, snapshot build 11.74 (p99 20.8), hand-off 2.56 (p99 8.4) ms - slow loops: build 13.5 + hand-off 3.0 + tick 3.0 + ingest 0.4 ms mean - process RSS flat at ~305 MB during the hold (bots + server in one process) - only 12 hunters reached their zone in 80 s (zones are 400 m+ from the spawn at 6.2 m/s), so most bots were still walking out of town: a crowded scene; a 10-minute soak spreads them out. Next (M1-04B): build snapshots + hand-off on 4 cores (per-client work is independent; no per-tick allocation), re-measure, then the 10-minute soak with a stepped ramp and the Grafana-like PNG.