The latch is stale-proof by construction, the cup divisor honest, the trail visible
Oliver's tournament freeze was the stale latch by a THIRD route: matchFallWillPlay kept the deathmatch /4 while cup matchPoint divides by 4*need, so it promised a fall on a no-crossing point — whose synchronous matchReady left the after-set latch scoping a dead rally. No more ordering arguments: the latch is set BEFORE the resolve, the swallow exempts the in-progress resolution via G.matchEarly, and every path that arms a rally clears it in matchReady. willFall now mirrors the cup divisor exactly and knows a mid-round game keeps its body. Regression test drives the full QF sequence (no-crossing points, the fall, the mid-round game, game two). And the two 'not really' reports: the trail's 0.26 alpha was tuned on the gore palette and vanished on the bright lawn — 0.38 now, gate at 13 m/s; oppBright 1.18 -> 1.3. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f9b26e5380
commit
129a001109
6 files changed
+67
-21
No files matched your search
@@ -836,6 +836,44 @@ test('THE TOURNAMENT: bands draw, bodies deepen, rounds hold their body, the cha
|
||||
assert.equal(G.match.felled, CUP_ROUNDS.length, 'four bodies felled, banked as a match run');
|
||||
});
|
||||
|
||||
test('cup rallies never strand the latch: no-crossing points, the fall, and the mid-round game', () => {
|
||||
// Oliver's second lock: in the quarter-final, matchFallWillPlay still divided by 4 while
|
||||
// matchPoint divided by 4*need — it promised a fall on a point that crossed nothing, the
|
||||
// no-fall path re-armed synchronously, and the after-set latch went stale ("basically like
|
||||
// freeze from before"). The latch is set BEFORE the resolve now (the swallow exempts the
|
||||
// resolution in progress via G.matchEarly), and willFall mirrors the cup divisor exactly.
|
||||
const { CUP_ROUNDS } = cfg;
|
||||
_startMatch(true); G.modal = null; G.modalQ.length = 0;
|
||||
G.mode = 'splatter';
|
||||
const d = G.match;
|
||||
G.interlude.introT = 0;
|
||||
for (let k = 0; k < 4; k++) resolveInterlude('P'); // round one falls to the ordinary path
|
||||
G.modal = null; G.modalQ.length = 0;
|
||||
passMopBeat();
|
||||
assert.equal(d.cup.round, 1, 'on the quarter-final');
|
||||
const zb = oppOf();
|
||||
const launch = () => {
|
||||
zb.x = -4; zb.z = 2;
|
||||
ball.active = true; ball.lastHit = 'P'; ball.bounces = 0; ball.wid = 'ball'; ball.collected = false;
|
||||
ball.x = 3.4; ball.z = 7; ball.y = 0.5; ball.vx = 0.5; ball.vy = -2; ball.vz = -6; ball.g = TUNE.gravity;
|
||||
G.phase = 'rally'; G.wasServe = false;
|
||||
const before = score.pts[0] + score.games[0] * 10;
|
||||
for (let i = 0; i < 8 * 60 && score.pts[0] + score.games[0] * 10 === before && !G.matchFall; i++) update(DT);
|
||||
for (let i = 0; i < 6 * 60 && (G.matchFall || G.modal); i++) { G.modal = null; G.modalQ.length = 0; update(DT); }
|
||||
};
|
||||
launch(); // 8 -> 7: crosses nothing (the old mispredict)
|
||||
assert.equal(zb.hp, 7, 'point one chipped the pool');
|
||||
assert.ok(!d.decided, 'no stale latch after a no-crossing point');
|
||||
launch(); // 7 -> 6: still nothing
|
||||
launch(); // 6 -> 5: the arm comes off, mid-flight
|
||||
assert.ok(!d.decided, 'the fall beat ended and released its latch');
|
||||
launch(); // the game point, mid-round: same body plays on
|
||||
assert.ok(zombies.includes(zb), 'game one banked, the quarter-final body stands');
|
||||
assert.equal(score.games[0], 2, 'the game went up');
|
||||
launch(); // game two opens: the match is ALIVE
|
||||
assert.equal(score.pts[0], 1, 'the next rally resolved — no freeze');
|
||||
});
|
||||
|
||||
test('service alternates by game, and the opponent actually serves', () => {
|
||||
// Until now the corpse only ever returned: score.server was pinned to 'P' because the match calls
|
||||
// advancePoint directly and the flip lives in tennis's pointTo, which the match bypasses. Return
|
||||
|
||||
Reference in new issue
Block a user