Skip to content

Co-op Determinism Coverage Implementation Plan

Co-op Determinism Coverage Implementation Plan

Section titled “Co-op Determinism Coverage Implementation Plan”

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Fold the drones pool into the determinism checksums (baseline-safe) and add a 2-pilot determinism test, so the co-op sim (2 pilots + a per-pilot deployed drone) is provably byte-identical across same-seed runs.

Architecture: state_checksum()/snapshot_string() already loop over all pilots but omit the drones pool. Append a for d in drones: loop to both (empty in the existing single-pilot run → byte-identical → no re-pin of the existing baseline), deliberately excluding the accruing per-pilot drone_charge scalar. Then add a new test_determinism_coop.gd that deploys a drone for P2 and pins a new, separate 2-pilot baseline.

Tech Stack: Godot 4.6.3, typed GDScript, GUT 9.6.0 (headless).

  • /sim-internal change only. sim/sim.gd (the two checksum functions) + sim/drone_director.gd (one comment) + a new test file. No render/UI/Node code.
  • The existing single-pilot baseline in tests/test_determinism_survival.gd (state_checksum()==3312602286, snapshot_string().hash()==4217109746) MUST remain unchanged — no re-pin. This is the explicit proof the enrichment is baseline-safe (the existing run deploys no drones → empty loop → byte-identical).
  • Exclude the per-pilot drone_charge scalar from the checksum. It accrues every tick (drone_director.gd:102), so including it would change the existing baseline. Its only observable effect (deploy timing) is already caught by the drones pool.
  • Include the DroneState pool fields, and pilots.find(d.owner) as the owner index.
  • snapshot_string() must NOT add a drone-count to the aggregate line (that changes the single-pilot format); only append per-drone segments in a loop (empty → no change).
  • Spec: docs/superpowers/specs/2026-07-14-coop-determinism-coverage-design.md.
  • Test verification note: GUT’s headless run SIGABRTs (exit 134) at teardown even on green — judge from the printed “Run Summary”/“All tests passed!”, not the exit code. Narrow to one script with -gselect=<script_name_without_.gd>. godot is at /opt/homebrew/bin/godot.
  • 2-pilot tick API: sim.tick(inputs: Array[InputState]) (e.g. sim.tick([inp1, inp2])). add_player2() appends pilots[1]. sim.drone_director.deploy_drones(sim, pilot, [spec]) deploys a drone owned by pilot.

  • sim/sim.gd — state_checksum() (~line 2564) and snapshot_string() (~line 2590): append the drones-pool loop to each.
  • sim/drone_director.gd:508 — update the stale “never affects determinism” comment.
  • tests/test_determinism_coop.gd — NEW: the 2-pilot determinism test + pinned baseline.
  • tests/test_determinism_survival.gd — UNCHANGED (regression proof it still passes).

Two tasks. Task 1 enriches the checksums (baseline-safe) with a red-first test proving drone state is now counted, plus the regression proof. Task 2 adds the 2-pilot test with a captured baseline; it depends on Task 1 (the deployed-drone coverage is only meaningful once drones are in the checksum).


Task 1: Fold the drones pool into state_checksum() and snapshot_string()

Section titled “Task 1: Fold the drones pool into state_checksum() and snapshot_string()”

Files:

  • Modify: sim/sim.gd — state_checksum() (~2564), snapshot_string() (~2590).
  • Modify: sim/drone_director.gd:508 (comment).
  • Test: tests/test_determinism_coop.gd (create with the Task-1 red test; Task 2 adds more to the same file).

Interfaces:

  • Consumes: drones: Array[DroneState] (field on Sim); DroneState fields pos, vel, hp, life, charge, pulse_timer, phase, owner; pilots: Array[PlayerState]; sim.drone_director.deploy_drones(sim, pilot, loadout).
  • Produces: state_checksum() and snapshot_string() that include drone-pool state.

Context: Both functions already loop for pilot in pilots (multi-pilot player state is covered). The gap is the drones pool. The existing single-pilot determinism run deploys no drones, so appending an empty-when-no-drones loop keeps it byte-identical.

  • Step 1: Write the failing test proving drone state is now in the checksum

Create tests/test_determinism_coop.gd:

extends GutTest
# Co-op determinism coverage (2026-07-14). Task 1 guard: two sims identical except for a
# deployed drone's position must now produce DIFFERENT state_checksum()/snapshot_string() —
# i.e. the drones pool is actually included. Before the enrichment, drones were ignored, so
# the two checksums were equal and this test failed.
const DRONE_SPEC := {"klass": "sentinel", "life": 1.0, "dmg": 1.0, "radius": 1.0, "heal": 0.0, "extras": 0}
func test_drone_pool_state_is_included_in_the_checksums() -> void:
var a := Sim.new(1234, SimContentFixture.db())
a.enable_survival()
var b := Sim.new(1234, SimContentFixture.db())
b.enable_survival()
# Both deploy one drone (owned by the sole pilot); then move B's drone so the ONLY
# difference between the two sims is drone position.
a.drone_director.deploy_drones(a, a.player, [DRONE_SPEC])
b.drone_director.deploy_drones(b, b.player, [DRONE_SPEC])
assert_eq(a.drones.size(), 1, "precondition: sim A has one drone")
assert_eq(b.drones.size(), 1, "precondition: sim B has one drone")
b.drones[0].pos += Vector2(50.0, 0.0) # the only difference
assert_ne(a.state_checksum(), b.state_checksum(),
"drone pool position must affect state_checksum()")
assert_ne(a.snapshot_string(), b.snapshot_string(),
"drone pool position must affect snapshot_string()")
  • Step 2: Run it to verify it fails

Run: godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gselect=test_determinism_coop -gexit 2>&1 | grep -iE "Passing|Failing|\[Failed\]"

Expected: FAILS — before the enrichment, drones are ignored, so a.state_checksum() == b.state_checksum() (and snapshots equal), so the assert_nes fail.

  • Step 3: Append the drones pool to state_checksum()

In sim/sim.gd, state_checksum(), immediately BEFORE return hash(parts):

for d in drones:
parts.append(d.pos)
parts.append(d.vel)
parts.append(d.hp)
parts.append(d.life)
parts.append(d.charge)
parts.append(d.pulse_timer)
parts.append(d.phase)
parts.append(pilots.find(d.owner)) # owner as a stable pilot index (co-op)

Do NOT append the per-pilot drone_charge scalar (it accrues every tick and would change the existing baseline; its effects surface via the pool).

  • Step 4: Append the drones pool to snapshot_string()

In sim/sim.gd, snapshot_string(), after the per-pilot xp=/lv= loop and BEFORE return s:

for d in drones:
s += " d=(%.3f,%.3f)" % [d.pos.x, d.pos.y]

Do NOT add a drone-count field to the aggregate e=… a=… pr=… g=… k=… line — that would change the single-pilot format and break byte-identical output.

  • Step 5: Update the stale comment in sim/drone_director.gd:508

Find the comment (near func decoy_positions() / the decoy-charge query returning {"active":…, "charge": sim.drone_charge, …}) that reads roughly: # NOT in snapshot_string()/state_checksum() (drones are opt-in, so this never affects determinism). Replace it with:

# Deployed drones (the sim.drones pool) ARE now in state_checksum()/snapshot_string()
# (2026-07-14) — they affect determinism once fielded. Only the per-pilot drone_charge
# recharge scalar stays excluded (it accrues every tick); its sole observable effect is
# deploy timing, which surfaces through the pool.

(Match the exact surrounding wording in the file; keep it a comment.)

  • Step 6: Run the coop test — the red test now passes

Run: godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gselect=test_determinism_coop -gexit 2>&1 | grep -iE "Passing|Failing|All tests passed|\[Failed\]"

Expected: test_drone_pool_state_is_included_in_the_checksums PASSES.

  • Step 7: Prove the existing single-pilot baseline is UNCHANGED (no re-pin)

Run: godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gselect=test_determinism_survival -gexit 2>&1 | grep -iE "Passing|Failing|All tests passed|\[Failed\]"

Expected: PASSES unchanged (the 3312602286 / 4217109746 baseline still holds — the existing run has no drones, so the new loop appended nothing). If this FAILS, the enrichment is not baseline-safe — STOP and report (do not re-pin; investigate whether a drone_charge scalar or an aggregate-line change leaked in).

  • Step 8: Regression — snapshot_string byte/relative comparison tests still pass

Run: godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gselect=test_pilots_query -gexit 2>&1 | grep -iE "Passing|Failing|All tests passed|\[Failed\]" Run: godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gselect=test_determinism -gexit 2>&1 | grep -iE "Passing|Failing|All tests passed|\[Failed\]"

Expected: both PASS unchanged (empty drones pool → snapshot_string byte-identical for their single-pilot / no-drone runs).

  • Step 9: Commit
Terminal window
git add sim/sim.gd sim/drone_director.gd tests/test_determinism_coop.gd
git commit -m "feat(sim): include the drones pool in determinism checksums
state_checksum()/snapshot_string() already covered all pilots but omitted the drones
pool (documented as safe only because no determinism test deployed a drone). Append a
drones-pool loop to both — baseline-safe: the existing single-pilot run deploys no drones,
so the loop is empty and the 3312602286/4217109746 baseline is unchanged (no re-pin). The
accruing per-pilot drone_charge scalar stays excluded (its effect surfaces via the pool).
Updates the stale drone_director comment."

Task 2: 2-pilot determinism test with a pinned baseline

Section titled “Task 2: 2-pilot determinism test with a pinned baseline”

Files:

  • Modify: tests/test_determinism_coop.gd (add the 2-pilot test to the file created in Task 1).

Interfaces:

  • Consumes: Sim.new(seed, db), enable_survival(), add_player2(), pilots[1], drone_director.deploy_drones(sim, pilot, [spec]), tick(inputs: Array[InputState]), state_checksum(), snapshot_string() (now drone-aware from Task 1).

Context: This proves the co-op sim (2 pilots + a per-pilot deployed drone) is byte-identical across two same-seed runs — the Phase-3 netcode guarantee — and pins a new, separate 2-pilot baseline. The baseline VALUES don’t exist until the code runs; you capture them from the first green run (standard determinism-baseline bootstrapping, Steps 2–4).

  • Step 1: Add the 2-pilot test with placeholder baselines that print the real values

Append to tests/test_determinism_coop.gd:

const COOP_SPEC := {"klass": "sentinel", "life": 1.0, "dmg": 1.0, "radius": 1.0, "heal": 0.0, "extras": 0}
# Two pilots, seed 1234, P2 owns a deployed Sentinel kept alive (life/hp forced high, identically
# in both runs, so it survives all 600 ticks and the final checksum genuinely includes drone state).
func _coop_run() -> Sim:
var s := Sim.new(1234, SimContentFixture.db())
s.enable_survival()
s.add_player2()
s.drone_director.deploy_drones(s, s.pilots[1], [COOP_SPEC])
s.drones[0].life = 9999.0 # keep it alive the whole run (deterministic: identical in both)
s.drones[0].hp = 9999.0
s.drones[0].max_hp = 9999.0
for i in range(600):
var d1 := Vector2(cos(float(i) * 0.05), sin(float(i) * 0.03))
if d1.length() > 0.0:
d1 = d1.normalized()
var d2 := Vector2(sin(float(i) * 0.04), cos(float(i) * 0.06))
if d2.length() > 0.0:
d2 = d2.normalized()
s.tick([InputState.new(d1), InputState.new(d2)])
return s
func test_coop_trace_is_deterministic_and_pinned() -> void:
var a := _coop_run()
var b := _coop_run()
assert_eq(a.pilots.size(), 2, "precondition: two pilots")
assert_gt(a.drones.size(), 0, "precondition: the drone is still deployed at run end")
# PRIMARY guarantee: identical inputs + seed -> byte-identical co-op trace.
assert_eq(a.state_checksum(), b.state_checksum(), "2-pilot + drone sim is deterministic (a==b)")
assert_eq(a.snapshot_string(), b.snapshot_string(), "2-pilot snapshot is deterministic (a==b)")
# TEMP: print the values to capture the baseline (remove in Step 3).
print("COOP_CHECKSUM=", a.state_checksum(), " COOP_HASH=", a.snapshot_string().hash())
  • Step 2: Run it and capture the printed baseline values

Run: godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gselect=test_determinism_coop -gexit 2>&1 | grep -E "COOP_CHECKSUM|Passing|Failing|\[Failed\]"

Expected: the test_coop_trace_is_deterministic_and_pinned test passes its a==b asserts, and a line like COOP_CHECKSUM=<N> COOP_HASH=<M> prints. Record <N> and <M>. (If a==b FAILS, the co-op sim is non-deterministic — STOP and report; do not pin a baseline over a real desync.)

  • Step 3: Replace the temp print with pinned baseline assertions

In test_coop_trace_is_deterministic_and_pinned, delete the print(...) line and append (substituting the captured <N>/<M>):

# 2-pilot baseline — seed 1234, 600 ticks, P2 owns a deployed Sentinel (life/hp forced high).
# SEPARATE from the single-pilot baseline in test_determinism_survival.gd. Captured 2026-07-14.
assert_eq(a.state_checksum(), <N>, "2-pilot state checksum baseline")
assert_eq(a.snapshot_string().hash(), <M>, "2-pilot snapshot hash baseline")
  • Step 4: Run the coop test to verify it passes with the pinned baseline

Run: godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gselect=test_determinism_coop -gexit 2>&1 | grep -iE "Passing|Failing|All tests passed|\[Failed\]"

Expected: all test_determinism_coop tests pass (the Task-1 red test + this pinned 2-pilot test).

  • Step 5: Full suite + confirm the existing baseline still holds

Run:

Terminal window
godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gselect=test_determinism_survival -gexit 2>&1 | grep -iE "All tests passed|\[Failed\]"
godot --headless --path . -s res://addons/gut/gut_cmdln.gd -gdir=res://tests -ginclude_subdirs -gexit 2>&1 | grep -A26 "= Run Summary" | grep -iE "^Scripts|^Tests|^Passing|^Failing|^Risky"

Expected: single-pilot baseline “All tests passed!”; full suite 0 failing (only the pre-existing 4 Risky/Pending), script/test counts up by the new file/tests.

  • Step 6: Commit
Terminal window
git add tests/test_determinism_coop.gd
git commit -m "test(sim): 2-pilot determinism trace + baseline
Two same-seed Sims, each with a P2 and a deployed per-pilot Sentinel, run 600 ticks
driving both pilots; asserts byte-identical state_checksum()/snapshot_string() across
runs (the Phase-3 co-op netcode guarantee) and pins a new, separate 2-pilot baseline.
The single-pilot baseline in test_determinism_survival.gd is untouched."

1. Spec coverage:

  • Component 1 (state_checksum drones pool, exclude drone_charge scalar) → Task 1 Step 3. ✓
  • Component 2 (snapshot_string per-drone segment, no count field) → Task 1 Step 4. ✓
  • Component 3 (update stale comment) → Task 1 Step 5. ✓
  • Component 4 (2-pilot test, deploy P2 drone, a==b + new baseline) → Task 2. ✓
  • Baseline impact (existing single-pilot baseline unchanged, no re-pin) → Task 1 Step 7 (explicit regression proof) + Task 2 Step 5. ✓
  • Testing (coop test is the test; survival/pilots_query/determinism regressions) → Task 1 Steps 7–8, Task 2 Step 5. ✓
  • Out-of-scope items (drone_charge scalar, forced level-ups, networked MP) → honored (not implemented). ✓

2. Placeholder scan: No “TBD/TODO/handle edge cases”. The <N>/<M> in Task 2 are deliberate captured-at-runtime determinism baselines with an explicit capture procedure (Steps 2–3) — this is the standard, unavoidable bootstrapping for a determinism pin, not a vague placeholder.

3. Type consistency: DRONE_SPEC/COOP_SPEC are the same dict shape used in tests/test_drones.gd. deploy_drones(sim, pilot, [spec]), tick([inp1, inp2]), add_player2(), pilots[1], and the DroneState field names (pos/vel/hp/life/charge/pulse_timer/phase/owner) all match the verified sources. state_checksum()/snapshot_string() signatures unchanged (still zero-arg).