A lane is free when its body is gone, not when it is far away

The drill spawner measured its best-of-9 lane spacing only against bodies still
in the back half (drillNearZ 9 m). On a court where lanes are HELD for life and
speed is stamped at spawn, a body 12 m down still owns its lane — handing it to
a faster arrival books an overtake for ten seconds later, mid-court, as two
sprites walking through each other. That is what the seed-sensitive test failure
(SEED=1234) was reporting: the assertion was right, the stream was not.

Spacing now measures against every live drill body; drillNearZ is deleted (no
other reader). Still best-of-9, no retry loop, so the stream cannot stall.

60 seeds x 150 s of drill: before, 7 seeds overlapped with narrowest clearance
0.00 m; after, zero overlap frames, narrowest 0.46 m (the test asks > 0.3).
Suite green on 20260811/1234/777/99/424242/8 and on 299 of seeds 1..300; the
straggler (SEED=80, the slid-serve return rate) is unrelated and logged as open.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-08-16 08:45:31 +02:00
1 parent 86b8275f5d
commit bdc3f23f92
4 files changed
+35 -9

No files matched your search

+8 -4
View File
@@ -73,15 +73,19 @@ function pickType() {
return pool[Math.floor(Math.random() * pool.length)];
}
// ---- THE STREAM. One body at a time, spaced (best-of-9 lanes against the back half — a retry loop
// ---- THE STREAM. One body at a time, spaced (best-of-9 lanes against EVERY live body — a retry loop
// would stall the stream exactly when it should be getting harder), holding its lane all the way in.
// The measure used to ignore anything past the back half, which was wrong for a court where lanes are
// held for life and speeds are stamped per body: a lane 12 m down is still OWNED, and handing it to a
// faster body just books the overtake for ten seconds later, where it lands as two sprites walking
// through each other mid-court. A lane is free when its body is gone, not when it is far away.
function spawnDrillBody(d) {
if (zombies.filter(z => z.drill).length >= TUNE.drillMaxOnCourt) return null;
const near = zombies.filter(z => z.drill && z.z < TUNE.drillNearZ);
const live = zombies.filter(z => z.drill);
if (live.length >= TUNE.drillMaxOnCourt) return null;
let bx = 0, bs = -1;
for (let k = 0; k < 9; k++) {
const x = -TUNE.drillSpread + (2 * TUNE.drillSpread) * (k / 8) + (Math.random() - 0.5) * 0.5;
const s = near.length ? Math.min(...near.map(z => Math.abs(z.x - x))) : 1e9;
const s = live.length ? Math.min(...live.map(z => Math.abs(z.x - x))) : 1e9;
if (s > bs) { bs = s; bx = x; }
}
const t = pickType();