Overnight swarm runbook — 2026-07-16 (skilled AutoPlayer + balance-signal reporting)
Overnight swarm runbook — 2026-07-16
Section titled “Overnight swarm runbook — 2026-07-16”Mission (Chris, 2026-07-16 23:35, live in chat before going to bed): build and run the
skilled-AutoPlayer + balance-signal reporting tool end to end overnight — “see how far we can
take it.” Unlike prior runs, the work queue is NOT docs/RELEASE-0.1.md (still under feature
freeze, untouched by this run) — it is the 5-task implementation plan at
docs/superpowers/plans/2026-07-16-skilled-autoplayer-balance-signal.md, backed by the design at
docs/superpowers/specs/2026-07-16-skilled-autoplayer-balance-signal-design.md. Read both in
full before acting — the design doc’s Guardrails section is binding, not optional.
Power note — REAL RISK, not template boilerplate: at mission start (23:35) the Mac was on
BATTERY at 78%, discharging — Chris intended AC but this was not confirmed connected at
dispatch time. If it’s not actually plugged in, expect the Monitor’s BATTERY_CRITICAL (≤25%) to
fire an early wind-down well before any extended horizon — that is the correct, safe behavior,
not a bug. Note the true power state honestly in the morning handoff report.
Permission posture: .claude/settings.local.json was broadened at mission start with
wildcard allows for godot --headless *, git commit/push/status/log/diff *, bash scripts/*.sh,
pkill/pgrep — the actual commands the bh-dev-chunk ritual and this plan’s steps invoke. If a
worker still hits an unanswered permission prompt, treat it as the #1 stall cause (see
bh-overnight-swarm §0) — kill and reclaim rather than assuming it’s machine sleep.
Standing orders (every iteration)
Section titled “Standing orders (every iteration)”git pull --rebasebefore starting AND before every commit. On.git/index.lock— wait 5s and retry, never delete.- Work off the plan file’s 5 tasks, in dependency order: Task 1 and Task 2 are independent
(dispatch both immediately, disjoint files — Task 1 touches
sim/sim.gd+tools/soak/soak_stats.gd, Task 2 touches onlyai/skilled_auto_player.gd— no overlap). Task 3 depends on BOTH 1 and 2 completing (it touchestools/soak/soak_run.gd+tools/soak/soak_stats.gd— don’t start it until Task 1’ssoak_stats.gdchanges are merged, to avoid a two-worker collision on that file). Task 4 depends on Task 3. Task 5 depends on Task 4. Do not skip ahead — each task’s Interfaces block in the plan documents exactly what the next task consumes. - Every code task (1-4) runs the full
bh-dev-chunkritual: TDD (test first, watch it fail, implement, watch it pass) →scripts/check-test-count.sh→ boot smoke → the plan’s own Step-by-step determinism sanity checks (test_determinism_survivalafter Tasks 1-3; nothing in this plan should ever require a re-pin — if one seems to, STOP and treat it as a bug, not a re-pin candidate, per the plan’s Global Constraints) → commit → push. - Follow the plan’s code EXACTLY as written — it was hand-verified against the actual current files (field names, method signatures, line anchors) before being committed, not sketched from memory. If something in the plan doesn’t match what you find in the actual file (a field renamed, a line moved), that’s real signal the plan is stale — stop, note the mismatch, adapt correctly, and say so in your report; don’t silently paper over a mismatch.
- Concurrency: disjoint file scopes per live worker. Claim protocol: first commit is a short claim note appended to THIS runbook under “Progress log” below (not a separate punch list — this run doesn’t have one), staged by exact pathspec, then push. Serialize commits.
HARD DON’Ts overnight
Section titled “HARD DON’Ts overnight”- NO deploys, NO App Store/TestFlight actions, NO BUILD-number bumps.
- NO touching
platform/tvos/symlinks. - NO work on
docs/RELEASE-0.1.mditems — this run is scoped entirely to the skilled-AI plan; the v0.1 feature freeze is untouched by this mission (this mission itself qualifies as QA tooling under the freeze, per the design doc — but that’s the ONLY freeze exception, not a general license to also pick up RC items opportunistically). - NO re-pinning determinism on this plan — nothing in Tasks 1-4 should move the baseline by construction (see plan Global Constraints). A red determinism test here means investigate, not re-pin.
- NO merging any Phase 3 guarded auto-tune to
main— branch only, always, no exceptions. See the Guardrails section below, copied from the design doc so it’s binding without needing to cross-reference. - NO Apple Intelligence / native-bridge work — that idea (see
docs/ideas/apple-intelligence-support-pilot.md) is explicitly parked, not part of this run.
Guardrails for Task 5 / Phase 3 (guarded auto-tune) — copied verbatim from the design doc
Section titled “Guardrails for Task 5 / Phase 3 (guarded auto-tune) — copied verbatim from the design doc”Once Task 5’s large sweep produces fun_signals, auto-tweaks are allowed ONLY when ALL hold:
- Single named numeric constant, never structural.
- Magnitude-capped to roughly a 15% nudge from its current value.
- Triggered only by one of: a damage context at ~zero across (nearly) every run; an enemy type essentially never killed across (nearly) every run; an upgrade’s dud-rate or overpower-rate near-100% across (nearly) every run it appears in.
- One tweak per finding, then re-measure (re-run the relevant soak slice) before considering a second tweak to the SAME constant.
- Full
bh-dev-chunkritual, plusbh-determinism-repinif the tweak shifts the pinned baseline (routine per that skill, not risky, as long as followed properly). - Branch only, never
main. Each tweak its own commit, triggering evidence (numbers) quoted in the commit message. Name the branchsoak-auto-tune-2026-07-16. - Everything that doesn’t cleanly meet 1-3 (difficulty curve, build dominance, the anticlimax
ratio) stays report-only — a
"DECISION (Chris): ..."entry in the handoff report, with the supporting numbers. When in doubt, escalate, don’t guess.
Iteration shape
Section titled “Iteration shape”Each tick: pull → check worker states (completion notifications, git log --oneline, git status --short, pgrep -fl godot for orphans) → dispatch the next unclaimed, dependency-satisfied task
to a fresh worker (2 concurrent max — this plan’s tasks are mostly sequential, not a wide fan-out
like a punch-list burn-down) → append progress to this runbook’s log → push. Never leave a task
half-done at tick end — finish it, or note exactly what’s left.
Progress log
Section titled “Progress log”(Workers append one line per claim/completion here, oldest first.)
- W1 claimed Task 1 (stats hook), 2026-07-16 23:47
- W2 claimed Task 2 (SkilledAutoPlayer), 2026-07-16 23:58
- W1 DONE Task 1, commit e7eec0a, tests green (check-test-count.sh: 236/236 scripts, 0 failing), determinism unchanged (test_determinism_survival PASS). Note: the plan’s own test premise (“900 ticks takes SOME damage”) didn’t hold empirically for this fixed movement pattern at seed 1234 — verified via the pre-existing, unrelated
Sim.damage_taken_totalfield that the player takes exactly 0.0 damage at 900 ticks with this drift pattern, first damage lands ~tick 1000, pilot dies ~tick 1100. Adapted the new test to run 1000 ticks locally (not the shared TICKS=900 const, other tests untouched) with a comment explaining why. Hook itself verified correct via direct_hurt_playercall + a synthetic on_player_damage check before making this call. - W2 DONE Task 2, commit 60ff544, tests green (6/6 in test_skilled_auto_player.gd; check-test-count.sh: 236/236 scripts, 0 failing after re-running clean post-W1’s-push — an earlier run mid-race with W1’s in-flight commit showed 1 transient failure, gone once W1’s commit landed), determinism unchanged (test_determinism_survival PASS). Plan code matched the actual codebase exactly (AutoPlayer consts/methods,
sim.enemies.is_elite,enemies.addsignature) — no adaptation needed, ai/auto_player.gd left completely untouched. Note:ai/skilled_auto_player.gd’s newclass_namewasn’t picked up by GUT until agodot --headless --path . --importpass — same fresh-registration behavior documented elsewhere for worktrees, applies here too even in the main checkout. - W3 claimed Task 3 (pluggable player + impact scoring), 2026-07-17 00:12
- W3 DONE Task 3, commit 6d52449, tests green (15/15 in test_soak_run.gd; check-test-count.sh: 236/236 scripts, 0 failing), determinism unchanged (test_determinism_survival PASS), boot smoke clean (no SCRIPT ERROR). soak_stats.gd’s current shape matched the plan’s Interfaces block for Task 1’s output exactly (
damage_taken_by_phase,on_player_damage) — Steps 3-4 in soak_run.gd/soak_stats.gd applied with zero code deviation from the plan. One real empirical deviation, same class as W1’s: the plan’s Step 1 test premise (“1200 ticks -> already leveled up, so upgrade_impacts non-empty”) didn’t hold for SkilledAutoPlayer at seed 1234 — traced directly: first kill lands ~tick 687, each basic kill is worth only 2.0 XP against a 100.0 xp_to_next threshold, so 1200 ticks only reaches 64/100 XP (still level 1, zero upgrades). Bumped the test to 2000 ticks (verified 1800 is the minimal point a level-up + its 180-tick impact window both close; used 2000 for margin) with a comment explaining why — the ring-buffer/impact-scoring CODE itself needed no changes, only the test’s tick budget. - W4 claimed Task 4 (soak_runner.gd –player= flag + fun-signal analysis), 2026-07-17 00:35
- W4 DONE Task 4, commit 89bbd8b, no GUT tests for this file per plan (dev-only CLI, matching
tests/test_soak_run.gd’s own header convention) — verification was Step 4’s manual CLI run + Step 5’s count guard, both per the plan. Code matched the plan exactly, zero deviation:--player=flag threaded intoSoakRun.new({...})’s cfg dict,_analyze_fun_signalsadded verbatim after_find_anomalies, wired into both the written JSON (fun_signalstop-level key) and a[soak] fun signals: {...}stdout line.Sim.PHASE_BOSSresolved exactly as the plan assumed (enum {PHASE_WAVES, PHASE_WIND_DOWN, PHASE_BOSS_PREP, PHASE_BOSS, PHASE_REST}atsim/sim.gd:21, accessible as a class constantSim.PHASE_BOSS— no fallback needed). Manual run--runs=2 --ticks=1200 --player=skilled --seed0=1000: exit 0,fun_signals.skilled_runs=2, JSON report written with the key — butupgrade_impactswas empty at 1200 ticks (one run leveled up viasplitbut its 180-tick impact window hadn’t closed yet), consistent with W1/W3’s prior findings that this seed/AI combo needs more ticks. Went further per my own instructions: reran at--runs=3 --ticks=2000 --player=skilled --seed0=1000and confirmedupgrade_impactsDOES populate and flow all the way through tofun_signals—upgrade_dud_rate_ge_90pctshowed{"split":1.0,"weapon:chalice":1.0}(small-sample noise per the plan’s own caveat, but proves the dud/overpowered aggregation pipeline works end-to-end).bash scripts/check-test-count.sh: 236/236 scripts, 0 failing — unchanged from Task 3, exit 0, as expected since this file has no GUT tests. No plan/codebase mismatches found. Task 5 (large 80-run sweep + findings report) is next and unclaimed. - W5 claimed Task 5, 2026-07-16 22:51 UTC. Power confirmed AC attached, 80% (not the feared battery-only start). Starting the 80-run sweep now (
--runs=40 --ticks=36000 --ships=cobalt,obsidian --coop=solo --player=skilled --seed0=2000) — expect real wall-clock time, will report back when done. - W5 DONE Task 5, commit 6897b91, all 5 plan tasks now complete on
main. Sweep: 80/80 runs (40 seeds × 2 ships), exit 0, 0 invariant failures, 0 anomalies, wall-clock ~1h5m (22:51→23:56 UTC).fun_signals.skilled_runs == 80confirmed. No auto-tune candidates met the Guardrails bar —soak-auto-tune-2026-07-16branch was NOT created, there was nothing to branch: all 7 upgrade ids at ≥90% dud/overpowered rate turned out to be 1-2-occurrence sample-size noise on direct recount (verified against the raw JSON, not just the aggregate), while the actually-frequent upgrades (weapon:chalice/armor at 20 picks, leech at 18, etc.) all sit in the healthy band. Real finding, report-only per Guardrails: 0 of 80 skilled runs ever reached PHASE_BOSS — all died in the wave phase (2731-12070 ticks), which also makes the anticlimax-ratio number in this sweep a divide-by-floor artifact (boss_taken=0 for every run), not usable signal — needs re-measuring once runs survive to boss content. Full findings + a build-diversity caveat + a noted Task-4 coverage gap (no enemy-never-killed signal wired into fun_signals) are indocs/overnight-swarm-report-2026-07-16.md. State of main at handoff: clean tree, check-test-count.sh 236/236 0 failing, boot smoke 0 SCRIPT ERROR, determinism baseline unchanged (test_determinism_survival PASS). Power: stable AC 80% throughout, the runbook’s flagged battery risk did not materialize. Mission complete — all 5 tasks done, no Phase 3 branch to hand off (nothing qualified).
Handoff (morning window, or BATTERY_CRITICAL, or all 5 tasks + Phase 3 done)
Section titled “Handoff (morning window, or BATTERY_CRITICAL, or all 5 tasks + Phase 3 done)”Write docs/overnight-swarm-report-2026-07-16.md (or -night.md if past midnight when started —
match existing convention): which tasks completed (commit SHAs), Task 5’s actual fun_signals
findings summarized in plain language, any Phase 3 auto-tune branch + commits (name it explicitly,
remind Chris it needs his review/merge — it is NOT on main), DECISION entries for anything that
didn’t meet the narrow auto-tune bar, the true power/sleep state honestly, and the measured
suite/count-guard/boot-smoke state of main at handoff. Commit + push the report, TaskStop the
Monitor, summarize for Chris with the decision queue up top.