scoring: the type-0 arm must RETURN, not break -- it was clobbering scoreAward
Chasing the duplicate rows from 1324c81 (80 real awards + 80 reading
award=0.00). Not a double delivery -- Entity::Dispatch sends exactly once on a
replicant. It was the `break` I left in the delegating arm.
After delegating to ScoreInflictedMessageHandler, control fell into
ScoreMessageHandler's post-switch tail, where the LOCAL `award` is still 0:
message->scoreAward = award; // clobbered to 0
BTMatchLog("SCORE", ... award=0.00 ...); // the phantom row
Player::ScoreMessageHandler(message); // base: currentScore += 0
Harmless to the total only because the value added happened to be zero -- but
it mutated a message on a shared path and ran a base handler for nothing. A
later reader of scoreAward, or any side effect gained by that tail, would have
turned it into a real bug with no obvious cause.
ScoreInflictedMessageHandler is self-contained (accumulates, ForceUpdate()s,
logs its own receipt), so the arm returns.
Re-benched cross-node:
rows on shooter's master 100, ZERO phantom rows (was 80 + 80)
rows on victim's node 0
running total 417.85, climbing continuously, no resets
type-0 Verify rejects 0
kill path intact (kills=1)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NCJQkvq6G2JNrpVbA75tVZ
This commit is contained in:
co-authored by
Claude Opus 5
parent
1324c81719
commit
b2498ca39a
@@ -1019,8 +1019,15 @@ void
|
||||
// exactly as the binary does; wire deliveries land here and get the same
|
||||
// handler. One accumulator, on the machine that owns the score.
|
||||
//
|
||||
// RETURN, not break. The post-switch tail folds the local `award` into
|
||||
// message->scoreAward and hands it to the base handler -- and for this
|
||||
// arm `award` is still 0, so falling through clobbered scoreAward to
|
||||
// zero, added nothing, and emitted a second SCORE row reading
|
||||
// "type=0 award=0.00" (the 80 real + 80 zero rows in the bench).
|
||||
// ScoreInflictedMessageHandler is self-contained: it accumulates,
|
||||
// ForceUpdate()s and logs its own receipt.
|
||||
ScoreInflictedMessageHandler(message);
|
||||
break;
|
||||
return;
|
||||
|
||||
case BTPlayer::ScoreMessage::DamageReceivedScore: // 1
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user