Skip to content

Improve Notifications#3913

Draft
evanpelle wants to merge 1 commit into
mainfrom
notifs
Draft

Improve Notifications#3913
evanpelle wants to merge 1 commit into
mainfrom
notifs

Conversation

@evanpelle
Copy link
Copy Markdown
Collaborator

@evanpelle evanpelle commented May 12, 2026

Resolves #3910

Description:

Describe the PR.

Please complete the following:

  • I have added screenshots for all UI updates
  • I process any text displayed to the user through translateText() and I've added it to the en.json file
  • I have added relevant tests to the test directory
  • I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced

Please put your Discord username so you can be contacted if a bug or regression is found:

DISCORD_USERNAME

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 12, 2026

Review Change Stack

Walkthrough

PR introduces ActionableEvents, a new UI layer for actionable in-game notifications with alliance request/renewal prompts. The game's displayMessage infrastructure is extended to carry unitID and focusPlayerID context. EventsDisplay is simplified by removing action buttons and complex lifecycle logic. ControlPanel gains a gold-gain pop animation. All message emission sites are updated to use the new parameters.

Changes

ActionableEvents Layer & Message System Expansion

Layer / File(s) Summary
Display message contract expansion
src/core/game/Game.ts, src/core/game/GameImpl.ts, src/core/game/GameUpdates.ts, src/client/Utils.ts
Game interface and implementation now accept optional unitID and focusPlayerID in displayMessage calls. MessageType adds NUKE_DETONATED, mapped to failure severity colors and NUKE category.
ActionableEvents layer introduction
src/client/graphics/layers/ActionableEvents.ts
New LitElement-based layer manages timed, priority-sorted events. Handles alliance request prompts with focus/accept/reject actions, alliance-expiration renewal reminders, and cleanup on alliance breaks. Events expire per-tick based on duration. Wires eventBus, game, and uiState. Visibility toggles based on player spawn phase.
GameRenderer integration
src/client/graphics/GameRenderer.ts
GameRenderer queries and wires the actionable-events DOM element with dependencies and includes it in the render layers array.
UI element routing
index.html
HTML replaces <events-display> with <actionable-events> in the right-side HUD panel.
EventsDisplay simplification
src/client/graphics/layers/EventsDisplay.ts
Removes per-event action buttons, duration/shouldDelete logic, alliance renewal/extension handling, and gold animation. Event shape reduces to text, type, timestamp, and focus. Rendering splits into Tier 1 (critical) and Tier 2 (recent) containers. Alliance request validation simplified.
ControlPanel gold-gain animation
src/client/graphics/layers/ControlPanel.ts
Adds transient gold-gain pop animation via new internal state (_goldGain, _goldGainPulseId). tick() detects gold-earning updates and triggers 2-second animated overlay. Desktop and mobile gold displays conditionally render +<gold> with keyed animation.
Domain message parameter updates
src/core/game/UnitImpl.ts, src/core/game/PlayerImpl.ts, src/core/execution/NukeExecution.ts, src/core/execution/TradeShipExecution.ts
Unit captures, destructions, gold donations, and nuke detonations now include appropriate unitID or focusPlayerID when calling displayMessage. TradeShipExecution passes tile context to addGold.
Test migration
tests/client/graphics/layers/ActionableEventsAlliance.test.ts, tests/core/executions/NukeExecution.test.ts
Tests updated to construct and exercise ActionableEvents. NukeExecution tests assert NUKE_DETONATED displayMessage emissions for Atom/Hydrogen warheads and none for MIRV.
Localization
resources/lang/en.json
Adds events_display.atom_bomb_detonated and events_display.hydrogen_bomb_detonated translation entries.

Sequence Diagram(s)

sequenceDiagram
  participant GameRenderer
  participant GameView
  participant ActionableEvents
  participant EventBus

  GameRenderer->>ActionableEvents: wire eventBus, game, uiState
  GameView->>ActionableEvents: emit DisplayEvent / AllianceRequest / BrokeAlliance / AllianceExtension
  ActionableEvents->>ActionableEvents: onDisplayMessageEvent() / tick() expire/add prompts
  ActionableEvents->>EventBus: emit TransportIntentEvent (accept/reject/renew)
  ActionableEvents->>GameRenderer: render() sorted actionable cards
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

Feature - New

Suggested reviewers

  • scottanderson

Poem

🎯 New events unfold with purpose bright,
Alliance prompts now claim the light,
Old buttons fade, the UI refined,
Gold pops and dances, elegantly designed.
Actionable moments take center stage—

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Several changes appear outside the scope of issue #3910: nuke detonation messaging, trade ship gold attribution, and gold-gain animation in ControlPanel are not directly related to notification panel separation. Clarify whether nuke detonation messaging, trade ship gold handling, and ControlPanel gold-gain animation are required for this issue or should be moved to separate pull requests.
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Improve Notifications' is vague and generic; it does not clearly describe the specific changes made in the changeset. Consider a more descriptive title like 'Separate high-value and low-value notifications into distinct panels' to better reflect the implementation details.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed The description references issue #3910 and mentions the objective, but contains placeholder text and incomplete checklist items rather than actual implementation details.
Linked Issues check ✅ Passed The pull request successfully implements the core requirement from issue #3910: separating high-value and low-value notifications by creating a new ActionableEvents layer for actionable events and simplifying EventsDisplay for lower-priority notifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/client/graphics/GameRenderer.ts`:
- Around line 133-141: The code currently logs if
document.querySelector("actionable-events") is not an instance of
ActionableEvents but then continues to dereference actionableEvents (setting
actionableEvents.eventBus, .game, .uiState and later inserting layers), causing
a crash if missing; update the guard around actionableEvents in GameRenderer
(the variable actionableEvents and type ActionableEvents) to perform an early
return or throw after the console.error so no property writes or layer insertion
run when actionableEvents is falsy/incorrect, and apply the same guarded pattern
to the other occurrence around lines where layer insertion happens (the second
actionableEvents usage) to ensure eventBus, game and uiState are only assigned
when actionableEvents is a valid ActionableEvents instance.

In `@src/core/execution/TradeShipExecution.ts`:
- Around line 192-193: Add a core simulation unit test that asserts both source
and destination port gold-bonus events are emitted when TradeShipExecution runs:
locate where TradeShipExecution calls srcPort.owner().addGold(gold,
this.srcPort.tile()) and _dstPort.owner().addGold(gold, this._dstPort.tile())
and write a test in the core simulation test suite that (1) sets up a trade
between two ports, (2) spies or subscribes to the core event/bonus emitter for
the source owner and destination owner, (3) executes the TradeShipExecution, and
(4) asserts that each owner received a gold-add event including the correct gold
amount and that the source event includes the tile context (this.srcPort.tile())
while the destination event includes this._dstPort.tile().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 66197d95-9ab2-47fd-a2c2-0c1c0857e646

📥 Commits

Reviewing files that changed from the base of the PR and between 990eba6 and bb0c053.

📒 Files selected for processing (14)
  • index.html
  • src/client/Utils.ts
  • src/client/graphics/GameRenderer.ts
  • src/client/graphics/layers/ActionableEvents.ts
  • src/client/graphics/layers/ControlPanel.ts
  • src/client/graphics/layers/EventsDisplay.ts
  • src/core/execution/NukeExecution.ts
  • src/core/execution/TradeShipExecution.ts
  • src/core/game/Game.ts
  • src/core/game/GameImpl.ts
  • src/core/game/GameUpdates.ts
  • src/core/game/PlayerImpl.ts
  • src/core/game/UnitImpl.ts
  • tests/client/graphics/layers/ActionableEventsAlliance.test.ts

Comment on lines +133 to +141
const actionableEvents = document.querySelector(
"actionable-events",
) as ActionableEvents;
if (!(actionableEvents instanceof ActionableEvents)) {
console.error("actionable events not found");
}
actionableEvents.eventBus = eventBus;
actionableEvents.game = game;
actionableEvents.uiState = uiState;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard actionableEvents before property writes and layer insertion.

The null/type check only logs, then Line 139 still dereferences the value. If the element is missing, renderer init crashes.

Suggested fix
-  const actionableEvents = document.querySelector(
+  const actionableEvents = document.querySelector(
     "actionable-events",
-  ) as ActionableEvents;
-  if (!(actionableEvents instanceof ActionableEvents)) {
+  ) as ActionableEvents | null;
+  if (!(actionableEvents instanceof ActionableEvents)) {
     console.error("actionable events not found");
-  }
-  actionableEvents.eventBus = eventBus;
-  actionableEvents.game = game;
-  actionableEvents.uiState = uiState;
+  } else {
+    actionableEvents.eventBus = eventBus;
+    actionableEvents.game = game;
+    actionableEvents.uiState = uiState;
+  }
@@
-    actionableEvents,
+    ...(actionableEvents instanceof ActionableEvents
+      ? [actionableEvents]
+      : []),

Also applies to: 304-305

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/client/graphics/GameRenderer.ts` around lines 133 - 141, The code
currently logs if document.querySelector("actionable-events") is not an instance
of ActionableEvents but then continues to dereference actionableEvents (setting
actionableEvents.eventBus, .game, .uiState and later inserting layers), causing
a crash if missing; update the guard around actionableEvents in GameRenderer
(the variable actionableEvents and type ActionableEvents) to perform an early
return or throw after the console.error so no property writes or layer insertion
run when actionableEvents is falsy/incorrect, and apply the same guarded pattern
to the other occurrence around lines where layer insertion happens (the second
actionableEvents usage) to ensure eventBus, game and uiState are only assigned
when actionableEvents is a valid ActionableEvents instance.

Comment on lines +192 to 193
this.srcPort.owner().addGold(gold, this.srcPort.tile());
this._dstPort.owner().addGold(gold, this._dstPort.tile());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Add a core test for source-port gold bonus emission.

Line 192 changes core event output (source-side gold now includes a tile context). Please add a core simulation test that verifies bonus/event emission for both source and destination ports.

As per coding guidelines, "All changes to src/core/ must include tests."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/execution/TradeShipExecution.ts` around lines 192 - 193, Add a core
simulation unit test that asserts both source and destination port gold-bonus
events are emitted when TradeShipExecution runs: locate where TradeShipExecution
calls srcPort.owner().addGold(gold, this.srcPort.tile()) and
_dstPort.owner().addGold(gold, this._dstPort.tile()) and write a test in the
core simulation test suite that (1) sets up a trade between two ports, (2) spies
or subscribes to the core event/bonus emitter for the source owner and
destination owner, (3) executes the TradeShipExecution, and (4) asserts that
each owner received a gold-add event including the correct gold amount and that
the source event includes the tile context (this.srcPort.tile()) while the
destination event includes this._dstPort.tile().

@github-project-automation github-project-automation Bot moved this from Triage to Development in OpenFront Release Management May 12, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/core/game/UnitImpl.ts (1)

197-232: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add core tests for new unitID message payload fields.

UnitImpl behavior changed in core by adding this.id() to three displayMessage(...) paths, but no matching UnitImpl tests are included here to lock this contract. Please add tests that assert unitID is present for capture (both sender/receiver messages) and destroy notifications.

As per coding guidelines: “src/core/ ... All changes to src/core/ must include tests”.

Also applies to: 326-342

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/game/GameImpl.ts`:
- Around line 936-939: The code computes focusID by calling
this.player(focusPlayerID).smallID() without ensuring the player exists; use the
existing hasPlayer() guard to avoid the player() call when the ID is invalid.
Change the ternary to first check focusPlayerID !== undefined &&
this.hasPlayer(focusPlayerID) and only then call
this.player(focusPlayerID).smallID(); otherwise set focusID to undefined (or
handle per existing semantics), so GameImpl.player() cannot be invoked with a
missing PlayerID.
- Around line 929-930: Tests are missing for the new optional parameters on
GameImpl.displayMessage: add unit tests that call GameImpl.displayMessage (or
helper wrapper used in tests) and assert the produced GameUpdate with type
GameUpdateType.DisplayEvent contains the passed unitID as-is and the
focusPlayerID converted to smallID in the payload's DisplayEvent, and also
assert behavior when each optional parameter is undefined (i.e., absent from the
payload). Target the GameImpl.displayMessage invocation paths updated around
DisplayEvent and verify the update payload fields for unitID and focusPlayerID
(including conversion logic) in positive and undefined cases.

In `@tests/core/executions/NukeExecution.test.ts`:
- Around line 188-200: The test currently constructs a NukeExecution for
UnitType.MIRVWarhead with a null launch ref, so the detonation path isn't
exercised; update the test to create a valid missile silo (or other valid launch
unit) for 'player', obtain its reference (use game.ref(...) or the created
unit's ref) and pass that ref into new NukeExecution(UnitType.MIRVWarhead,
player, game.ref(50, 50), <siloRef>) so the MIRV launch code in NukeExecution is
executed, then run executeTicks(game, 200) and assert that game.displayMessage
was not called with NUKE_DETONATED. Ensure you reference NukeExecution,
UnitType.MIRVWarhead, and game.displayMessage when making these changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 89dee3df-72e9-4227-a64f-8adc37b0882a

📥 Commits

Reviewing files that changed from the base of the PR and between bb0c053 and db6b0cd.

📒 Files selected for processing (16)
  • index.html
  • resources/lang/en.json
  • src/client/Utils.ts
  • src/client/graphics/GameRenderer.ts
  • src/client/graphics/layers/ActionableEvents.ts
  • src/client/graphics/layers/ControlPanel.ts
  • src/client/graphics/layers/EventsDisplay.ts
  • src/core/execution/NukeExecution.ts
  • src/core/execution/TradeShipExecution.ts
  • src/core/game/Game.ts
  • src/core/game/GameImpl.ts
  • src/core/game/GameUpdates.ts
  • src/core/game/PlayerImpl.ts
  • src/core/game/UnitImpl.ts
  • tests/client/graphics/layers/ActionableEventsAlliance.test.ts
  • tests/core/executions/NukeExecution.test.ts
✅ Files skipped from review due to trivial changes (1)
  • resources/lang/en.json
🚧 Files skipped from review as they are similar to previous changes (12)
  • src/core/execution/TradeShipExecution.ts
  • src/core/game/GameUpdates.ts
  • src/client/Utils.ts
  • index.html
  • src/client/graphics/GameRenderer.ts
  • src/core/game/Game.ts
  • tests/client/graphics/layers/ActionableEventsAlliance.test.ts
  • src/core/execution/NukeExecution.ts
  • src/core/game/PlayerImpl.ts
  • src/client/graphics/layers/ControlPanel.ts
  • src/client/graphics/layers/ActionableEvents.ts
  • src/client/graphics/layers/EventsDisplay.ts

Comment thread src/core/game/GameImpl.ts
Comment on lines +929 to +930
unitID?: number,
focusPlayerID?: PlayerID,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Search for tests covering the new unitID and focusPlayerID parameters in displayMessage

# Search for tests that verify unitID in DisplayEvent updates
rg -n 'DisplayEvent.*unitID|unitID.*DisplayEvent' --type=ts --glob='*test*' -C3

# Search for tests that verify focusPlayerID in DisplayEvent updates  
rg -n 'DisplayEvent.*focusPlayerID|focusPlayerID.*DisplayEvent' --type=ts --glob='*test*' -C3

# Search for displayMessage calls with the new parameters
rg -n 'displayMessage\(' --type=ts --glob='*test*' -A5 | rg -C2 'unitID|focusPlayerID'

Repository: openfrontio/OpenFrontIO

Length of output: 49


🏁 Script executed:

cat -n src/core/game/GameImpl.ts | sed -n '920,950p'

Repository: openfrontio/OpenFrontIO

Length of output: 1027


🏁 Script executed:

fd -t f "test\|spec" src/core/game/ --type=f

Repository: openfrontio/OpenFrontIO

Length of output: 49


🏁 Script executed:

rg -l "displayMessage" src/core/ --type=ts --glob="*test*"

Repository: openfrontio/OpenFrontIO

Length of output: 49


🏁 Script executed:

rg -n "DisplayEvent" src/core/game/ --type=ts -A2 -B2 | head -50

Repository: openfrontio/OpenFrontIO

Length of output: 878


🏁 Script executed:

rg -n "interface DisplayMessageUpdate" src/core/game/GameUpdates.ts -A15

Repository: openfrontio/OpenFrontIO

Length of output: 544


🏁 Script executed:

fd "test\.ts" src/core/ --type f

Repository: openfrontio/OpenFrontIO

Length of output: 49


🏁 Script executed:

fd "NukeExecution" src/core/ --type f

Repository: openfrontio/OpenFrontIO

Length of output: 103


🏁 Script executed:

fd "NukeExecution.test" src/core/ --type f

Repository: openfrontio/OpenFrontIO

Length of output: 49


🏁 Script executed:

rg -l "displayMessage" src/core/ --type ts

Repository: openfrontio/OpenFrontIO

Length of output: 570


🏁 Script executed:

rg -n "displayMessage.*unitID|displayMessage.*focusPlayerID" src/core/ --type ts

Repository: openfrontio/OpenFrontIO

Length of output: 49


🏁 Script executed:

fd -e test.ts src/ --type f

Repository: openfrontio/OpenFrontIO

Length of output: 389


🏁 Script executed:

cat -n src/core/execution/NukeExecution.ts | grep -A5 -B5 "displayMessage"

Repository: openfrontio/OpenFrontIO

Length of output: 558


🏁 Script executed:

git log --oneline -n 20 -- src/core/game/GameImpl.ts

Repository: openfrontio/OpenFrontIO

Length of output: 1416


Add tests for the new unitID and focusPlayerID parameters in displayMessage.

The code correctly adds these parameters to the displayMessage method and passes them through to the DisplayEvent update. However, per the coding guidelines, all changes to src/core/ must include tests. Tests are missing to verify:

  1. The unitID parameter is included in the GameUpdateType.DisplayEvent update payload
  2. The focusPlayerID parameter is converted to smallID and included in the update payload
  3. These optional parameters work correctly when undefined

Also applies to: 936-939, 947-948

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/game/GameImpl.ts` around lines 929 - 930, Tests are missing for the
new optional parameters on GameImpl.displayMessage: add unit tests that call
GameImpl.displayMessage (or helper wrapper used in tests) and assert the
produced GameUpdate with type GameUpdateType.DisplayEvent contains the passed
unitID as-is and the focusPlayerID converted to smallID in the payload's
DisplayEvent, and also assert behavior when each optional parameter is undefined
(i.e., absent from the payload). Target the GameImpl.displayMessage invocation
paths updated around DisplayEvent and verify the update payload fields for
unitID and focusPlayerID (including conversion logic) in positive and undefined
cases.

Comment thread src/core/game/GameImpl.ts
Comment on lines +936 to +939
const focusID =
focusPlayerID !== undefined
? this.player(focusPlayerID).smallID()
: undefined;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add validation for focusPlayerID to prevent runtime errors.

The code calls this.player(focusPlayerID).smallID() without checking if the player exists. The player() method throws an error if the PlayerID is not found (lines 620-625), which would crash the game simulation if an invalid ID is passed.

Consider adding validation using the existing hasPlayer() method:

🛡️ Proposed validation
 const focusID =
   focusPlayerID !== undefined
-    ? this.player(focusPlayerID).smallID()
+    ? (this.hasPlayer(focusPlayerID) 
+        ? this.player(focusPlayerID).smallID() 
+        : undefined)
     : undefined;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const focusID =
focusPlayerID !== undefined
? this.player(focusPlayerID).smallID()
: undefined;
const focusID =
focusPlayerID !== undefined
? (this.hasPlayer(focusPlayerID)
? this.player(focusPlayerID).smallID()
: undefined)
: undefined;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/core/game/GameImpl.ts` around lines 936 - 939, The code computes focusID
by calling this.player(focusPlayerID).smallID() without ensuring the player
exists; use the existing hasPlayer() guard to avoid the player() call when the
ID is invalid. Change the ternary to first check focusPlayerID !== undefined &&
this.hasPlayer(focusPlayerID) and only then call
this.player(focusPlayerID).smallID(); otherwise set focusID to undefined (or
handle per existing semantics), so GameImpl.player() cannot be invoked with a
missing PlayerID.

Comment on lines +188 to +200
test("MIRVWarhead detonation does NOT emit NUKE_DETONATED", () => {
for (let x = 48; x < 53; x++) {
for (let y = 48; y < 53; y++) {
otherPlayer.conquer(game.ref(x, y));
}
}

const displayMessageSpy = vi.spyOn(game, "displayMessage");

game.addExecution(
new NukeExecution(UnitType.MIRVWarhead, player, game.ref(50, 50), null),
);
executeTicks(game, 200);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

MIRV negative case can pass without exercising detonation path

This test does not create a missile silo and passes null launch ref, so NUKE_DETONATED absence may be true even if MIRV logic is broken. Make MIRV launch under valid conditions, then assert no detonation message.

Suggested fix
 test("MIRVWarhead detonation does NOT emit NUKE_DETONATED", () => {
+  player.buildUnit(UnitType.MissileSilo, game.ref(1, 1), {});
   for (let x = 48; x < 53; x++) {
     for (let y = 48; y < 53; y++) {
       otherPlayer.conquer(game.ref(x, y));
     }
   }

   const displayMessageSpy = vi.spyOn(game, "displayMessage");

   game.addExecution(
-    new NukeExecution(UnitType.MIRVWarhead, player, game.ref(50, 50), null),
+    new NukeExecution(
+      UnitType.MIRVWarhead,
+      player,
+      game.ref(50, 50),
+      game.ref(1, 1),
+    ),
   );
   executeTicks(game, 200);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test("MIRVWarhead detonation does NOT emit NUKE_DETONATED", () => {
for (let x = 48; x < 53; x++) {
for (let y = 48; y < 53; y++) {
otherPlayer.conquer(game.ref(x, y));
}
}
const displayMessageSpy = vi.spyOn(game, "displayMessage");
game.addExecution(
new NukeExecution(UnitType.MIRVWarhead, player, game.ref(50, 50), null),
);
executeTicks(game, 200);
test("MIRVWarhead detonation does NOT emit NUKE_DETONATED", () => {
player.buildUnit(UnitType.MissileSilo, game.ref(1, 1), {});
for (let x = 48; x < 53; x++) {
for (let y = 48; y < 53; y++) {
otherPlayer.conquer(game.ref(x, y));
}
}
const displayMessageSpy = vi.spyOn(game, "displayMessage");
game.addExecution(
new NukeExecution(
UnitType.MIRVWarhead,
player,
game.ref(50, 50),
game.ref(1, 1),
),
);
executeTicks(game, 200);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/core/executions/NukeExecution.test.ts` around lines 188 - 200, The test
currently constructs a NukeExecution for UnitType.MIRVWarhead with a null launch
ref, so the detonation path isn't exercised; update the test to create a valid
missile silo (or other valid launch unit) for 'player', obtain its reference
(use game.ref(...) or the created unit's ref) and pass that ref into new
NukeExecution(UnitType.MIRVWarhead, player, game.ref(50, 50), <siloRef>) so the
MIRV launch code in NukeExecution is executed, then run executeTicks(game, 200)
and assert that game.displayMessage was not called with NUKE_DETONATED. Ensure
you reference NukeExecution, UnitType.MIRVWarhead, and game.displayMessage when
making these changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Development

Development

Successfully merging this pull request may close these issues.

Improve notification panel

1 participant