ui/phase-27: root-cause aggregation of duplicate (race, className) rows
Legacy reports list the same `(race, className)` pair across several roster rows; the engine likewise creates one ShipGroup per arrival. Both the legacy parser and `TransformBattle` were keyed on shipClass without summing — only the last row / group's counts survived, so a protocol's destroy count appeared to exceed the recorded initial roster. The UI worked around this with phantom-frame logic. Both parser and engine now SUM `Number`/`NumberLeft` across rows / groups sharing the same class; the phantom-frame workaround is gone. KNNTS041 turn 41 planet #7 reconciles: `Nails:pup` 1168 initial − 86 survivors = 1082 destroys. The engine's previously latent nil-map write on `bg.Tech` (would have paniced on any group with non-empty Tech) is fixed in the same patch — it blocked the aggregation regression test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -208,15 +208,6 @@ describe("buildFrames phantom-destroy clamp", () => {
|
||||
// the only active race for the remainder of the protocol.
|
||||
expect(frames[5].remaining.get(10)).toBe(0);
|
||||
expect(frames[5].activeRaceIds).toEqual([1]);
|
||||
// Phantom flags: first two destroys land on a non-empty
|
||||
// group → real shots; the remaining three are phantoms.
|
||||
expect(frames[1].phantom).toBe(false);
|
||||
expect(frames[2].phantom).toBe(false);
|
||||
expect(frames[3].phantom).toBe(true);
|
||||
expect(frames[4].phantom).toBe(true);
|
||||
expect(frames[5].phantom).toBe(true);
|
||||
// The initial frame is never a phantom.
|
||||
expect(frames[0].phantom).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps a race active while phantom destroys hit one of its empty groups", () => {
|
||||
|
||||
Reference in New Issue
Block a user