Skip to content

feat: reactive potion balances via WebSocket#131

Open
loothero wants to merge 5 commits intonextfrom
summit-reactive-potion-counts
Open

feat: reactive potion balances via WebSocket#131
loothero wants to merge 5 commits intonextfrom
summit-reactive-potion-counts

Conversation

@loothero
Copy link
Member

@loothero loothero commented Mar 9, 2026

Summary

  • Adds PG NOTIFY trigger on consumables table (indexer/migrations/0004_consumables_trigger.sql) to broadcast balance changes
  • Extends API SubscriptionHub with consumables_update LISTEN and consumables WS channel
  • Adds ConsumablesData type and onConsumables callback to client useWebSocket hook
  • Wires GameDirector to subscribe to consumables channel and update token balances when the connected wallet's potion counts change

Test plan

  • API typecheck passes (tsc --noEmit)
  • API tests pass (85 tests, including 3 new consumables channel tests)
  • Client lint passes
  • Client build passes
  • Client tests pass (188 tests, including 3 new useWebSocket tests + 2 new GameDirector consumables handler tests)

🤖 Generated with Claude Code

Wire up full pipeline for real-time potion balance updates:
- PG NOTIFY trigger on consumables table (indexer migration)
- API: LISTEN consumables_update, broadcast on consumables channel
- Client: useWebSocket consumables handler + GameDirector filtering by wallet

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 9, 2026 03:27
@vercel
Copy link

vercel bot commented Mar 9, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
summit Ready Ready Preview, Comment Mar 9, 2026 3:51pm

Request Review

@railway-app railway-app bot temporarily deployed to Summit stack / summit-pr-131 March 9, 2026 03:27 Destroyed
@railway-app
Copy link

railway-app bot commented Mar 9, 2026

🚅 Deployed to the summit-pr-131 environment in Summit stack

Service Status Web Updated (UTC)
summit-api ◻️ Removed (View Logs) Web Mar 11, 2026 at 1:05 am
summit-indexer ◻️ Removed (View Logs) Mar 11, 2026 at 1:05 am

@coderabbitai
Copy link

coderabbitai bot commented Mar 9, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4107d7c4-07ce-470d-8eb8-e1792a1219f4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch summit-reactive-potion-counts

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant enhancement to the game's real-time capabilities by enabling reactive updates for player potion balances. By integrating PostgreSQL notifications with a new WebSocket channel, players will now see their potion counts update instantly as changes occur on the backend. This improves the responsiveness and accuracy of the game's UI, providing a more seamless and engaging user experience without requiring manual refreshes.

Highlights

  • Real-time Potion Balance Updates: Implemented a new WebSocket channel ('consumables') to provide real-time updates on potion token balances for connected users.
  • PostgreSQL Trigger for Consumables: Added a PostgreSQL trigger on the consumables table to automatically send pg_notify events whenever potion balances are inserted or updated, feeding the WebSocket system.
  • Client-side Integration: The GameDirector context now subscribes to the new consumables WebSocket channel and updates the player's token balances dynamically based on incoming data.
  • WebSocket Hook Enhancement: The useWebSocket hook was extended to support the new consumables channel, including a dedicated onConsumables callback for handling potion balance data.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • api/AGENTS.md
    • Documented the new 'consumables' WebSocket channel and its role in the real-time data flow.
  • api/src/ws/subscriptions.test.ts
    • Added new unit tests to verify the subscription and unsubscription functionality of the 'consumables' WebSocket channel.
  • api/src/ws/subscriptions.ts
    • Extended the Channel type and broadcast method to support the new 'consumables' channel.
    • Implemented logic to listen for consumables_update notifications from PostgreSQL and broadcast them to subscribed WebSocket clients.
    • Defined the ConsumablesPayload interface for potion balance data.
  • client/src/contexts/GameDirector.test.tsx
    • Updated mock implementations for useWebSocket and useAccount to facilitate testing.
    • Added new tests to confirm that the GameDirector correctly processes consumables WebSocket messages and updates token balances for the active wallet, while ignoring irrelevant updates.
  • client/src/contexts/GameDirector.tsx
    • Imported the ConsumablesData type for potion balance information.
    • Implemented a handleConsumables function to update the game's token balances based on data received from the 'consumables' WebSocket channel.
    • Configured the useWebSocket hook to subscribe to the 'consumables' channel and utilize the new handleConsumables callback.
  • client/src/hooks/useWebSocket.test.ts
    • Added new unit tests for the useWebSocket hook, specifically verifying the correct handling of 'consumables' messages and the inclusion of the 'consumables' channel in subscription requests.
  • client/src/hooks/useWebSocket.ts
    • Extended the Channel type to include 'consumables'.
    • Defined the ConsumablesData interface to structure potion balance updates.
    • Modified UseWebSocketOptions to accept an onConsumables callback for handling incoming potion data.
    • Updated the internal message handling logic to dispatch 'consumables' messages to the new callback.
  • client/tsconfig.tsbuildinfo
    • Updated the TypeScript build configuration to include the newly added WebSocket test file.
  • indexer/migrations/0004_consumables_trigger.sql
    • Added a new SQL migration file to create a PostgreSQL function notify_consumables_update.
    • Created a trigger consumables_update_trigger that invokes notify_consumables_update after any insert or update operation on the consumables table, broadcasting the owner's potion counts.
Activity
  • API typecheck passed.
  • API tests passed, including 3 new tests for the consumables channel.
  • Client lint passed.
  • Client build passed.
  • Client tests passed, including 3 new useWebSocket tests and 2 new GameDirector consumables handler tests.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@claude
Copy link

claude bot commented Mar 9, 2026

Claude finished @loothero's task —— View job


Claude Review - General Engineering Review

run=22837099462 attempt=1 sha=33b866f8959df3f8e06f0347566693461c766a41 scope=general

Todo List

  • Run git diff to identify changes outside core app packages
  • Analyze any CI/workflow, scripts, tooling, or config changes
  • Provide review findings with severity levels
  • Update comment with final results

Review Findings

After analyzing the PR changes, I found only one file modified outside the core app packages: api/AGENTS.md. This is a documentation update that adds the new consumables WebSocket channel to the API documentation.

Changes analyzed:

  • api/AGENTS.md: Updated to document the new consumables WebSocket channel

Assessment

No issues found.

The documentation update in api/AGENTS.md is appropriate and correctly reflects the new functionality:

  • Added consumables to the list of WebSocket channels (line 42)
  • Updated the subscribe payload example to include the new channel (line 43)
  • Added consumables_update to the real-time pattern documentation (line 58)

This change maintains documentation accuracy and helps developers understand the new WebSocket channel functionality. The update is consistent with the implementation and follows the existing documentation patterns.

Summary

0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

--- | summit-reactive-potion-counts branch

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Codex Review - General Engineering Review

No issues found.
Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

@claude
Copy link

claude bot commented Mar 9, 2026

Claude finished @loothero's task —— View job


Claude Review - Indexer/API Review

run=22837099462 attempt=1 sha=33b866f8959df3f8e06f0347566693461c766a41 scope=indexer-api

Todo List

  • Get git diff for indexer/ and api/ directories
  • Review PostgreSQL trigger migration (0004_consumables_trigger.sql)
  • Analyze WebSocket subscription changes in api/src/ws/
  • Check data correctness and idempotency considerations
  • Verify schema consistency and migration safety
  • Assess operational reliability aspects
  • Provide structured findings with severity levels
  • Update comment with final results

Review Findings

No issues found.

Analysis Summary

I reviewed the changes in indexer/migrations/0004_consumables_trigger.sql and api/src/ws/subscriptions.ts focusing on data correctness, operational safety, and event handling reliability.

PostgreSQL Trigger (0004_consumables_trigger.sql):

  • ✅ Follows established pattern from existing triggers in 0001_triggers.sql
  • ✅ Uses safe json_build_object() for payload construction
  • ✅ Proper AFTER INSERT OR UPDATE timing for consistency
  • ✅ Safe DROP TRIGGER IF EXISTS for idempotent migrations
  • ✅ Matches exact column names from consumables schema (owner, xlife_count, attack_count, revive_count, poison_count)
  • ✅ Simple, deterministic notification logic with no external dependencies

WebSocket Subscription Changes:

  • ✅ Extends existing Channel type safely with "consumables"
  • ✅ Adds proper LISTEN for consumables_update channel alongside existing channels
  • ✅ ConsumablesPayload interface matches trigger payload structure exactly
  • ✅ Broadcast logic follows established pattern for summit/event channels
  • ✅ Test coverage includes subscription, unsubscription, and multi-channel scenarios

Data Integrity & Operations:

  • ✅ Trigger operates on existing consumables table with proper unique constraint on owner
  • ✅ No reorg-safety concerns - notifications are ephemeral and don't affect indexed data
  • ✅ No idempotency issues - trigger only notifies, doesn't modify state
  • ✅ Error handling maintains existing patterns with proper error logging
  • ✅ Connection management unchanged from proven implementation

Migration Safety:

  • ✅ Migration only adds trigger/function, no schema changes
  • ✅ Consistent with established trigger migration patterns
  • ✅ Safe to apply/rollback - no data dependencies

The implementation is operationally sound and follows established patterns from the existing notification system.

Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

--- | Branch: summit-reactive-potion-counts

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new WebSocket channel consumables for real-time updates of potion balances, with changes across the API, client, and database, including a new PostgreSQL trigger, API endpoint extensions, and client-side handling in GameDirector and useWebSocket hook. However, a critical security vulnerability exists: the server-side SubscriptionHub broadcasts balance updates for all users to any client subscribed to the consumables channel, leading to information exposure by allowing real-time monitoring of other players' assets. This must be mitigated by implementing server-side filtering based on the owner's address. Additionally, a high-severity issue in GameDirector.tsx was found where updating consumable balances incorrectly overwrites the entire token balance state. While the implementation is generally well-tested and follows existing patterns, addressing these issues is essential.

Comment on lines +424 to +429
setTokenBalances(() => ({
"EXTRA LIFE": data.xlife_count,
ATTACK: data.attack_count,
REVIVE: data.revive_count,
POISON: data.poison_count,
}));

Choose a reason for hiding this comment

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

high

The current implementation of setTokenBalances will overwrite the entire token balances state, potentially clearing other token balances like SKULL or CORPSE. The new consumable balances should be merged with the existing state to preserve other token counts.

    setTokenBalances((prevBalances) => ({
      ...prevBalances,
      "EXTRA LIFE": data.xlife_count,
      ATTACK: data.attack_count,
      REVIVE: data.revive_count,
      POISON: data.poison_count,
    }));

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed in ffede6c — now spreads ...prev to preserve SKULL/CORPSE/SURVIVOR balances. Test updated to verify existing keys are retained.

Comment on lines +168 to +170
case "consumables_update":
this.broadcast("consumables", payload as ConsumablesPayload);
break;

Choose a reason for hiding this comment

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

security-medium medium

The consumables channel broadcasts potion balance updates for all users to every client subscribed to the channel. While the client-side GameDirector filters these messages to only process updates for the connected wallet (line 422), a malicious client can subscribe to the channel and monitor the real-time balance changes of all players. This information exposure can be used for tactical advantage in a competitive game. To remediate this, implement server-side filtering: clients should provide the owner address they are interested in when subscribing, and the broadcast method should only send updates to clients whose interested address matches the owner in the payload.

Copy link
Member Author

Choose a reason for hiding this comment

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

Declining this one — this follows the same broadcast pattern as summit and event channels, which also send all data to all subscribers. Token balances are on-chain public data (anyone can call balanceOf), so there's no real information exposure. Adding server-side owner filtering would introduce significant complexity (subscription state per-owner, address normalization in the hub) for no meaningful security gain. If we decide to add per-owner filtering later, it should apply to all three channels uniformly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codecov
Copy link

codecov bot commented Mar 9, 2026

Codecov Report

❌ Patch coverage is 79.54545% with 9 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
api/src/ws/subscriptions.ts 42.85% 4 Missing ⚠️
client/src/contexts/Statistics.tsx 69.23% 4 Missing ⚠️
client/src/contexts/GameDirector.tsx 92.30% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Codex Review - Indexer/API Review

No review output was produced.

@claude
Copy link

claude bot commented Mar 9, 2026

Claude finished @loothero's task —— View job


Claude Review - General Engineering Review

run=22837142807 attempt=1 sha=f8dabb449264d8e66a51922fbe375ef93695cd81 scope=general

Todo List

  • Run git diff to identify changes outside core app packages
  • Analyze any CI/workflow, scripts, tooling, or config changes
  • Provide review findings with severity levels
  • Update comment with final results

Review Findings

After analyzing the PR changes, I found only one file modified outside the core app packages: api/AGENTS.md. This is a documentation update that adds the new consumables WebSocket channel to the API documentation.

Changes analyzed:

  • api/AGENTS.md: Updated to document the new consumables WebSocket channel

Assessment

No issues found.

The documentation update in api/AGENTS.md is appropriate and correctly reflects the new functionality:

  • Added consumables to the list of WebSocket channels (line 42)
  • Updated the subscribe payload example to include the new channel (line 43)
  • Added consumables_update to the real-time pattern documentation (line 58)

This change maintains documentation accuracy and helps developers understand the new WebSocket channel functionality. The update is consistent with the implementation and follows the existing documentation patterns.

Summary

0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

--- | summit-reactive-potion-counts branch

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Codex Review - General Engineering Review

No issues found.
Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

@claude
Copy link

claude bot commented Mar 9, 2026

Claude finished @loothero's task —— View job


Claude Review - Indexer/API Review

run=22837142807 attempt=1 sha=f8dabb449264d8e66a51922fbe375ef93695cd81 scope=indexer-api

Todo List

  • Get git diff for indexer/ and api/ directories
  • Review PostgreSQL trigger migration (0004_consumables_trigger.sql)
  • Analyze WebSocket subscription changes in api/src/ws/
  • Check data correctness and idempotency considerations
  • Verify schema consistency and migration safety
  • Assess operational reliability aspects
  • Provide structured findings with severity levels
  • Update comment with final results

Review Findings

No issues found.

Analysis Summary

I reviewed the changes in indexer/migrations/0004_consumables_trigger.sql and api/src/ws/subscriptions.ts focusing on data correctness, operational safety, and event handling reliability.

PostgreSQL Trigger (0004_consumables_trigger.sql):

  • ✅ Follows established pattern from existing triggers in 0001_triggers.sql
  • ✅ Uses safe json_build_object() for payload construction
  • ✅ Proper AFTER INSERT OR UPDATE timing for consistency
  • ✅ Safe DROP TRIGGER IF EXISTS for idempotent migrations
  • ✅ Matches exact column names from consumables schema (owner, xlife_count, attack_count, revive_count, poison_count)
  • ✅ Simple, deterministic notification logic with no external dependencies

WebSocket Subscription Changes:

  • ✅ Extends existing Channel type safely with "consumables"
  • ✅ Adds proper LISTEN for consumables_update channel alongside existing channels
  • ✅ ConsumablesPayload interface matches trigger payload structure exactly
  • ✅ Broadcast logic follows established pattern for summit/event channels
  • ✅ Test coverage includes subscription, unsubscription, and multi-channel scenarios

Data Integrity & Operations:

  • ✅ Trigger operates on existing consumables table with proper unique constraint on owner
  • ✅ No reorg-safety concerns - notifications are ephemeral and don't affect indexed data
  • ✅ No idempotency issues - trigger only notifies, doesn't modify state
  • ✅ Error handling maintains existing patterns with proper error logging
  • ✅ Connection management unchanged from proven implementation

Migration Safety:

  • ✅ Migration only adds trigger/function, no schema changes
  • ✅ Consistent with established trigger migration patterns
  • ✅ Safe to apply/rollback - no data dependencies

The implementation is operationally sound and follows established patterns from the existing notification system.

Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

--- | Branch: summit-reactive-potion-counts

@claude
Copy link

claude bot commented Mar 9, 2026

Claude finished @loothero's task —— View job


Claude Review - React/Frontend Review

run=22837142807 attempt=1 sha=f8dabb449264d8e66a51922fbe375ef93695cd81 scope=client

Todo List

  • Get git diff for client/** changes
  • Review GameDirector.tsx modifications
  • Analyze useWebSocket.ts hook changes
  • Check test implementations
  • Verify type safety and React patterns
  • Provide structured findings with severity levels
  • Update comment with final results

Review Findings

[HIGH] client/src/contexts/GameDirector.tsx:424-429 - State overwrite bug
Impact: The setTokenBalances function overwrites the entire token balances state instead of merging with existing balances. This will clear other token counts like SKULL, CORPSE, or SURVIVOR tokens whenever potion balances update.
Fix: Use function form with spread operator: setTokenBalances(prev => ({ ...prev, "EXTRA LIFE": data.xlife_count, ATTACK: data.attack_count, REVIVE: data.revive_count, POISON: data.poison_count }))

Additional Observations

The implementation is generally well-structured and follows good React patterns:

  • Proper use of useRef for callbacks to avoid stale closures
  • Good WebSocket connection management with reconnection logic
  • Appropriate dependency arrays in useEffect hooks
  • Strong type safety with TypeScript interfaces
  • Address validation using addAddressPadding for consistency

The security concern noted by Gemini about broadcasting all user data is primarily a backend API design issue rather than a client-side vulnerability. The client correctly filters messages to only process updates for the connected wallet.

Test coverage appears comprehensive with 5 new tests covering both the WebSocket hook functionality and GameDirector consumables handling.

Summary: 0 CRITICAL, 1 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

--- | summit-reactive-potion-counts branch

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 33b866f895

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +424 to +428
setTokenBalances(() => ({
"EXTRA LIFE": data.xlife_count,
ATTACK: data.attack_count,
REVIVE: data.revive_count,
POISON: data.poison_count,

Choose a reason for hiding this comment

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

P1 Badge Preserve existing token balances when applying consumable updates

This setter replaces the entire tokenBalances object with only four potion keys, so any previously loaded balances like SKULL, CORPSE, SURVIVOR, or STRK are dropped after the first consumables WebSocket event and then read as zero in balance-dependent UI/actions until another full fetch runs. Merge these values into prev instead of returning a new partial map.

Useful? React with 👍 / 👎.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed in ffede6c — now uses (prev) => ({ ...prev, ... }) to merge consumable balances into existing state. Test also updated to pass in { SKULL: 10, CORPSE: 5 } as prev and verify they're preserved.

@@ -0,0 +1,28 @@
-- Migration: Add NOTIFY trigger for real-time consumables balance updates

Choose a reason for hiding this comment

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

P1 Badge Register the new consumables trigger migration in journal

Adding this migration file without a corresponding 0004_consumables_trigger entry in indexer/migrations/meta/_journal.json means Drizzle-based migration execution (used by pnpm db:migrate and the indexer migrator) will not apply it, so the consumables_update trigger/function will be missing in upgraded environments and no consumables WS notifications will be emitted.

Useful? React with 👍 / 👎.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed in ffede6c — added 0004_consumables_trigger entry to indexer/migrations/meta/_journal.json so the Drizzle migrator picks it up.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds end-to-end real-time “consumables” (potion) balance updates from the indexer → API WebSocket → client state, so the UI can react when a wallet’s potion counts change.

Changes:

  • Add a PostgreSQL NOTIFY trigger on the consumables table to publish balance updates.
  • Extend the API WebSocket SubscriptionHub and the client useWebSocket hook with a new consumables channel + payload type.
  • Wire GameDirector to consume consumables updates and update local token balances; add corresponding tests.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
indexer/migrations/0004_consumables_trigger.sql Adds pg_notify('consumables_update', ...) trigger/function for consumables updates.
api/src/ws/subscriptions.ts LISTENs for consumables_update and broadcasts a new consumables WS channel.
api/src/ws/subscriptions.test.ts Adds tests around subscribing/unsubscribing to the new channel.
client/src/hooks/useWebSocket.ts Adds consumables channel support + ConsumablesData and callback wiring.
client/src/hooks/useWebSocket.test.ts Adds unit tests for the new hook callback and subscription message contents.
client/src/contexts/GameDirector.tsx Subscribes to consumables and updates balances for the connected wallet.
client/src/contexts/GameDirector.test.tsx Adds tests validating the consumables handler behavior.
api/AGENTS.md Updates documentation to include the new WS channel and real-time pattern.
client/tsconfig.tsbuildinfo Updates generated TS build info artifact (should not be committed).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +424 to +429
setTokenBalances(() => ({
"EXTRA LIFE": data.xlife_count,
ATTACK: data.attack_count,
REVIVE: data.revive_count,
POISON: data.poison_count,
}));
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

setTokenBalances is replacing the entire tokenBalances map with only the four potion entries. Elsewhere (e.g. in ControllerProvider.fetchTokenBalances/fetchPaymentTokenBalances) balances are merged into the same map, so this will wipe any existing token entries (including payment tokens) whenever a consumables update arrives. Update this to merge into the previous state instead of overwriting it (e.g. spread prev and update only the potion keys).

Copilot uses AI. Check for mistakes.
Comment on lines +168 to +170
case "consumables_update":
this.broadcast("consumables", payload as ConsumablesPayload);
break;
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

The new consumables_update notifications are broadcast to every client subscribed to the consumables channel, meaning each subscriber receives balance updates for all owners (and must filter client-side). Given consumables updates can be frequent, this increases bandwidth/CPU and may unnecessarily expose per-owner balance data to all connected clients. Consider adding server-side filtering (e.g. owner-scoped subscriptions or including an owner filter in the subscribe message) so clients only receive updates relevant to them.

Copilot uses AI. Check for mistakes.
@@ -1 +1 @@
{"root":["./src/App.tsx","./src/main.tsx","./src/patchCoverage.imports.test.ts","./src/vite-env.d.ts","./src/api/ekubo.test.ts","./src/api/ekubo.ts","./src/api/starknet.test.ts","./src/api/starknet.ts","./src/api/summitApi.test.ts","./src/api/summitApi.ts","./src/components/ActionBar.test.tsx","./src/components/ActionBar.tsx","./src/components/AttackingBeasts.tsx","./src/components/BeastCard.tsx","./src/components/BeastCollection.tsx","./src/components/BeastProfile.tsx","./src/components/BurgerMenu.tsx","./src/components/ClaimRewardsButton.tsx","./src/components/Countdown.tsx","./src/components/DiplomacyPopover.tsx","./src/components/EventHistoryButton.tsx","./src/components/FinalShowdown.tsx","./src/components/GameNotificationFeed.tsx","./src/components/Icons.tsx","./src/components/KilledByAdventurers.tsx","./src/components/Leaderboard.jsx","./src/components/Leaderboard.test.tsx","./src/components/LeaderboardButton.tsx","./src/components/Migrating.tsx","./src/components/ProfileCard.tsx","./src/components/QuestBoard.tsx","./src/components/QuestRewardsRemainingBar.tsx","./src/components/RewardsRemainingBar.tsx","./src/components/Summit.tsx","./src/components/TermsOfServiceModal.tsx","./src/components/dialogs/AutopilotConfigModal.tsx","./src/components/dialogs/BeastDexModal.tsx","./src/components/dialogs/BeastUpgradeModal.tsx","./src/components/dialogs/ConnectWallet.tsx","./src/components/dialogs/DCATab.tsx","./src/components/dialogs/EventHistoryModal.tsx","./src/components/dialogs/LeaderboardModal.tsx","./src/components/dialogs/MarketplaceModal.tsx","./src/components/dialogs/QuestsModal.tsx","./src/components/dialogs/SummitGiftModal.tsx","./src/components/dialogs/TopUpStrkModal.tsx","./src/contexts/GameDirector.test.tsx","./src/contexts/GameDirector.tsx","./src/contexts/QuestGuide.tsx","./src/contexts/Statistics.test.tsx","./src/contexts/Statistics.tsx","./src/contexts/controller.test.tsx","./src/contexts/controller.tsx","./src/contexts/sound.tsx","./src/contexts/starknet.tsx","./src/dojo/useGameTokens.test.tsx","./src/dojo/useGameTokens.ts","./src/dojo/useSystemCalls.ts","./src/hooks/useWebSocket.ts","./src/pages/MainPage.tsx","./src/stores/autopilotStore.ts","./src/stores/gameStore.ts","./src/types/game.ts","./src/utils/BeastData.ts","./src/utils/addressNameCache.ts","./src/utils/analytics.ts","./src/utils/beasts.test.ts","./src/utils/beasts.ts","./src/utils/events.test.ts","./src/utils/events.ts","./src/utils/networkConfig.ts","./src/utils/styles.ts","./src/utils/summitRewards.ts","./src/utils/themes.ts","./src/utils/translation.test.ts","./src/utils/translation.ts","./src/utils/utils.test.ts","./src/utils/utils.ts","./src/utils/variants.test.ts","./src/utils/variants.ts"],"errors":true,"version":"5.9.3"} No newline at end of file
{"root":["./src/App.tsx","./src/main.tsx","./src/patchCoverage.imports.test.ts","./src/vite-env.d.ts","./src/api/ekubo.test.ts","./src/api/ekubo.ts","./src/api/starknet.test.ts","./src/api/starknet.ts","./src/api/summitApi.test.ts","./src/api/summitApi.ts","./src/components/ActionBar.test.tsx","./src/components/ActionBar.tsx","./src/components/AttackingBeasts.tsx","./src/components/BeastCard.tsx","./src/components/BeastCollection.tsx","./src/components/BeastProfile.tsx","./src/components/BurgerMenu.tsx","./src/components/ClaimRewardsButton.tsx","./src/components/Countdown.tsx","./src/components/DiplomacyPopover.tsx","./src/components/EventHistoryButton.tsx","./src/components/FinalShowdown.tsx","./src/components/GameNotificationFeed.tsx","./src/components/Icons.tsx","./src/components/KilledByAdventurers.tsx","./src/components/Leaderboard.jsx","./src/components/Leaderboard.test.tsx","./src/components/LeaderboardButton.tsx","./src/components/Migrating.tsx","./src/components/ProfileCard.tsx","./src/components/QuestBoard.tsx","./src/components/QuestRewardsRemainingBar.tsx","./src/components/RewardsRemainingBar.tsx","./src/components/Summit.tsx","./src/components/TermsOfServiceModal.tsx","./src/components/dialogs/AutopilotConfigModal.tsx","./src/components/dialogs/BeastDexModal.tsx","./src/components/dialogs/BeastUpgradeModal.tsx","./src/components/dialogs/ConnectWallet.tsx","./src/components/dialogs/DCATab.tsx","./src/components/dialogs/EventHistoryModal.tsx","./src/components/dialogs/LeaderboardModal.tsx","./src/components/dialogs/MarketplaceModal.tsx","./src/components/dialogs/QuestsModal.tsx","./src/components/dialogs/SummitGiftModal.tsx","./src/components/dialogs/TopUpStrkModal.tsx","./src/contexts/GameDirector.test.tsx","./src/contexts/GameDirector.tsx","./src/contexts/QuestGuide.tsx","./src/contexts/Statistics.test.tsx","./src/contexts/Statistics.tsx","./src/contexts/controller.test.tsx","./src/contexts/controller.tsx","./src/contexts/sound.tsx","./src/contexts/starknet.tsx","./src/dojo/useGameTokens.test.tsx","./src/dojo/useGameTokens.ts","./src/dojo/useSystemCalls.ts","./src/hooks/useWebSocket.test.ts","./src/hooks/useWebSocket.ts","./src/pages/MainPage.tsx","./src/stores/autopilotStore.ts","./src/stores/gameStore.ts","./src/types/game.ts","./src/utils/BeastData.ts","./src/utils/addressNameCache.ts","./src/utils/analytics.ts","./src/utils/beasts.test.ts","./src/utils/beasts.ts","./src/utils/events.test.ts","./src/utils/events.ts","./src/utils/networkConfig.ts","./src/utils/styles.ts","./src/utils/summitRewards.ts","./src/utils/themes.ts","./src/utils/translation.test.ts","./src/utils/translation.ts","./src/utils/utils.test.ts","./src/utils/utils.ts","./src/utils/variants.test.ts","./src/utils/variants.ts"],"version":"5.9.3"} No newline at end of file
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

tsconfig.tsbuildinfo is a generated TypeScript incremental build artifact and is typically not meant to be committed. Including it in the repo tends to create noisy diffs and merge conflicts across machines/CI. Remove this file from version control and add it to an appropriate .gitignore (or disable incremental builds for the client if you intentionally want build info tracked).

Suggested change
{"root":["./src/App.tsx","./src/main.tsx","./src/patchCoverage.imports.test.ts","./src/vite-env.d.ts","./src/api/ekubo.test.ts","./src/api/ekubo.ts","./src/api/starknet.test.ts","./src/api/starknet.ts","./src/api/summitApi.test.ts","./src/api/summitApi.ts","./src/components/ActionBar.test.tsx","./src/components/ActionBar.tsx","./src/components/AttackingBeasts.tsx","./src/components/BeastCard.tsx","./src/components/BeastCollection.tsx","./src/components/BeastProfile.tsx","./src/components/BurgerMenu.tsx","./src/components/ClaimRewardsButton.tsx","./src/components/Countdown.tsx","./src/components/DiplomacyPopover.tsx","./src/components/EventHistoryButton.tsx","./src/components/FinalShowdown.tsx","./src/components/GameNotificationFeed.tsx","./src/components/Icons.tsx","./src/components/KilledByAdventurers.tsx","./src/components/Leaderboard.jsx","./src/components/Leaderboard.test.tsx","./src/components/LeaderboardButton.tsx","./src/components/Migrating.tsx","./src/components/ProfileCard.tsx","./src/components/QuestBoard.tsx","./src/components/QuestRewardsRemainingBar.tsx","./src/components/RewardsRemainingBar.tsx","./src/components/Summit.tsx","./src/components/TermsOfServiceModal.tsx","./src/components/dialogs/AutopilotConfigModal.tsx","./src/components/dialogs/BeastDexModal.tsx","./src/components/dialogs/BeastUpgradeModal.tsx","./src/components/dialogs/ConnectWallet.tsx","./src/components/dialogs/DCATab.tsx","./src/components/dialogs/EventHistoryModal.tsx","./src/components/dialogs/LeaderboardModal.tsx","./src/components/dialogs/MarketplaceModal.tsx","./src/components/dialogs/QuestsModal.tsx","./src/components/dialogs/SummitGiftModal.tsx","./src/components/dialogs/TopUpStrkModal.tsx","./src/contexts/GameDirector.test.tsx","./src/contexts/GameDirector.tsx","./src/contexts/QuestGuide.tsx","./src/contexts/Statistics.test.tsx","./src/contexts/Statistics.tsx","./src/contexts/controller.test.tsx","./src/contexts/controller.tsx","./src/contexts/sound.tsx","./src/contexts/starknet.tsx","./src/dojo/useGameTokens.test.tsx","./src/dojo/useGameTokens.ts","./src/dojo/useSystemCalls.ts","./src/hooks/useWebSocket.test.ts","./src/hooks/useWebSocket.ts","./src/pages/MainPage.tsx","./src/stores/autopilotStore.ts","./src/stores/gameStore.ts","./src/types/game.ts","./src/utils/BeastData.ts","./src/utils/addressNameCache.ts","./src/utils/analytics.ts","./src/utils/beasts.test.ts","./src/utils/beasts.ts","./src/utils/events.test.ts","./src/utils/events.ts","./src/utils/networkConfig.ts","./src/utils/styles.ts","./src/utils/summitRewards.ts","./src/utils/themes.ts","./src/utils/translation.test.ts","./src/utils/translation.ts","./src/utils/utils.test.ts","./src/utils/utils.ts","./src/utils/variants.test.ts","./src/utils/variants.ts"],"version":"5.9.3"}

Copilot uses AI. Check for mistakes.
@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Codex Review - React/Frontend Review

[HIGH] client/src/contexts/GameDirector.tsx:424 - handleConsumables replaces the entire tokenBalances map instead of merging updates.
Impact: any consumables websocket update wipes non-potion balances (SKULL, CORPSE, SURVIVOR, STRK, etc.), which can show incorrect zeros and block/alter UX flows that depend on those balances (upgrades, rewards, profile values) until a full refetch happens.
Fix: merge with previous state:
setTokenBalances((prev) => ({ ...prev, "EXTRA LIFE": data.xlife_count, ATTACK: data.attack_count, REVIVE: data.revive_count, POISON: data.poison_count }));

[LOW] client/src/contexts/GameDirector.test.tsx:204 - New consumables test validates updater behavior only against an empty previous state, so it does not catch balance-clobber regressions.
Impact: this allows destructive state replacement bugs (like above) to pass tests undetected.
Fix: invoke updater with seeded prior balances (e.g. { SKULL: 10, SURVIVOR: 5 }) and assert those keys are preserved after consumables updates.

Summary: 0 CRITICAL, 1 HIGH, 0 MEDIUM, 1 LOW, 0 INFO

…nal entry

Address review feedback:
- Merge consumables into existing tokenBalances instead of overwriting
- Register 0004_consumables_trigger in Drizzle migration journal

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@railway-app railway-app bot temporarily deployed to Summit stack / summit-pr-131 March 9, 2026 03:35 Destroyed
@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Codex Review - Indexer/API Review

[HIGH] indexer/migrations/0004_consumables_trigger.sql:1 - New migration file is not accompanied by a migration journal update (indexer/migrations/meta/_journal.json still ends at 0003_consumables).
Impact: Assuming this repo applies migrations via drizzle-kit migrate (as scripted), 0004_consumables_trigger.sql will not be applied in deployed environments, so consumables_update notifications never fire and the new WS channel appears broken.
Fix: Regenerate/record the migration metadata so 0004 is in meta/_journal.json (and related snapshot metadata), then verify pnpm db:migrate applies it on both fresh and existing databases.

[MEDIUM] api/src/ws/subscriptions.ts:168 - consumables_update is broadcast to every client subscribed to consumables, with no owner-level routing/filtering.
Impact: Each transfer-driven balance update is fanned out to all subscribers, creating O(events × subscribers) WS traffic and avoidable load/backpressure under real chain activity.
Fix: Add owner-scoped subscriptions (normalized owner in subscribe payload), store that filter per client, and only send consumables messages when payload.owner matches.

[LOW] indexer/migrations/0004_consumables_trigger.sql:26 - Trigger emits on every UPDATE, even when potion counts are unchanged.
Impact: No-op updates (for example, clamped deltas or replay-equivalent writes) still generate notifications, causing duplicate/unchanged balance pushes and noisy client updates.
Fix: Restrict update notifications with a WHEN clause (or function guard) that checks count fields actually changed before calling pg_notify.

Summary: 0 CRITICAL, 1 HIGH, 1 MEDIUM, 1 LOW, 0 INFO

@claude
Copy link

claude bot commented Mar 9, 2026

Claude finished @loothero's task —— View job


Claude Review - General Engineering Review

run=22837240827 attempt=1 sha=ffede6c1f3ed3264acbe322d752e8e5237b9d819 scope=general

Todo List

  • Run git diff to identify changes outside core app packages
  • Analyze any CI/workflow, scripts, tooling, or config changes
  • Provide review findings with severity levels
  • Update comment with final results

Review Findings

After running the git diff command to check for changes outside the core app packages (contracts/, client/, indexer/, api/), no files were modified in the targeted scope.

Changes analyzed: No files outside the core app packages were modified in this PR.

Assessment

No issues found.

This PR contains changes only within the core application packages (indexer/, api/, client/) and does not modify any CI/workflow files, scripts, tooling, shared configuration, or other files that could impact the broader repository infrastructure or development workflow.

The reactive potion balances feature is implemented entirely within the application layer without requiring changes to:

  • GitHub Actions workflows (.github/workflows/)
  • Build scripts or tooling configuration
  • Repository-level configuration files
  • Documentation with behavioral impact outside the core packages

Summary

0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

--- | | summit-reactive-potion-counts branch

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Codex Review - General Engineering Review

No issues found.
Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

@claude
Copy link

claude bot commented Mar 9, 2026

Claude finished @loothero's task —— View job


Claude Review - Indexer/API Review

run=22837240827 attempt=1 sha=ffede6c1f3ed3264acbe322d752e8e5237b9d819 scope=indexer-api

Todo List

  • Get git diff for indexer/ and api/ directories
  • Review PostgreSQL trigger migration (0004_consumables_trigger.sql)
  • Analyze WebSocket subscription changes in api/src/ws/
  • Check data correctness and idempotency considerations
  • Verify schema consistency and migration safety
  • Assess operational reliability aspects
  • Provide structured findings with severity levels
  • Update comment with final results

Review Findings

No issues found.

Analysis Summary

I reviewed the changes in indexer/migrations/0004_consumables_trigger.sql and api/src/ws/subscriptions.ts focusing on data correctness, operational safety, and event handling reliability.

PostgreSQL Trigger (0004_consumables_trigger.sql):

  • ✅ Follows established pattern from existing triggers in 0001_triggers.sql
  • ✅ Uses safe json_build_object() for payload construction
  • ✅ Proper AFTER INSERT OR UPDATE timing for consistency
  • ✅ Safe DROP TRIGGER IF EXISTS for idempotent migrations
  • ✅ Matches exact column names from consumables schema (owner, xlife_count, attack_count, revive_count, poison_count)
  • ✅ Simple, deterministic notification logic with no external dependencies

WebSocket Subscription Changes:

  • ✅ Extends existing Channel type safely with "consumables"
  • ✅ Adds proper LISTEN for consumables_update channel alongside existing channels
  • ✅ ConsumablesPayload interface matches trigger payload structure exactly
  • ✅ Broadcast logic follows established pattern for summit/event channels
  • ✅ Test coverage includes subscription, unsubscription, and multi-channel scenarios

Data Integrity & Operations:

  • ✅ Trigger operates on existing consumables table with proper unique constraint on owner
  • ✅ No reorg-safety concerns - notifications are ephemeral and don't affect indexed data
  • ✅ No idempotency issues - trigger only notifies, doesn't modify state
  • ✅ Error handling maintains existing patterns with proper error logging
  • ✅ Connection management unchanged from proven implementation

Migration Safety:

  • ✅ Migration only adds trigger/function, no schema changes
  • ✅ Consistent with established trigger migration patterns
  • ✅ Safe to apply/rollback - no data dependencies

The implementation is operationally sound and follows established patterns from the existing notification system.

Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

--- | Branch: summit-reactive-potion-counts

@claude
Copy link

claude bot commented Mar 9, 2026

Claude finished @loothero's task —— View job


Claude Review - React/Frontend Review

run=22837240827 attempt=1 sha=ffede6c1f3ed3264acbe322d752e8e5237b9d819 scope=client

Todo List

  • Get git diff for client/** changes
  • Review GameDirector.tsx modifications
  • Analyze useWebSocket.ts hook changes
  • Check test implementations
  • Verify type safety and React patterns
  • Provide structured findings with severity levels
  • Update comment with final results

Review Findings

No issues found.

Analysis Summary

I reviewed the changes in client/src/contexts/GameDirector.tsx, client/src/hooks/useWebSocket.ts, and their test files focusing on React state management, WebSocket integration, type safety, and testing patterns.

GameDirector.tsx Changes:

  • ✅ Properly imports ConsumablesData type from useWebSocket hook
  • handleConsumables function correctly filters updates by connected wallet address using addAddressPadding for consistent comparison
  • State merge fix verified: Uses (prev: Record<string, number>) => ({ ...prev, ... }) pattern to preserve existing token balances like SKULL, CORPSE, SURVIVOR when updating potion counts
  • ✅ Adds "consumables" channel to WebSocket subscription alongside existing "summit" and "event" channels
  • ✅ Uses useRef pattern for callbacks to prevent stale closures

useWebSocket.ts Changes:

  • ✅ Adds "consumables" to Channel union type
  • ✅ Defines ConsumablesData interface with proper field types matching backend payload
  • ✅ Extends UseWebSocketOptions with optional onConsumables callback
  • ✅ Updates callback ref and useEffect dependencies to include new callback
  • ✅ Adds message handling for "consumables" type in switch statement
  • ✅ Maintains existing WebSocket patterns for connection management and error handling

Test Coverage:

  • GameDirector tests: New tests verify consumables handler updates balances for correct wallet and ignores updates for other wallets
  • Critical fix verification: Test passes { SKULL: 10, CORPSE: 5 } as previous state and verifies these values are preserved after consumables update, catching the state overwrite bug that was previously found
  • useWebSocket tests: Comprehensive tests for consumables message handling, channel subscription, and cross-channel isolation
  • ✅ Uses proper React testing patterns with act() and mock WebSocket setup

Type Safety & React Patterns:

  • ✅ Strong TypeScript typing throughout with proper interface definitions
  • ✅ Proper React hook dependency arrays in useEffect
  • ✅ Callback stability via useRef to prevent unnecessary re-renders
  • ✅ Address normalization with addAddressPadding for consistent comparison
  • ✅ No unsafe casts or as any usage detected

Previous Review Issues Addressed:

  • State overwrite bug fixed: Author correctly changed from setTokenBalances({ ... }) to setTokenBalances((prev) => ({ ...prev, ... })) to preserve existing balances
  • Test coverage enhanced: Updated test validates that existing keys are preserved during consumables updates
  • Migration journal updated: Drizzle migration metadata was properly updated (outside client scope but confirmed in other reviews)

The implementation follows established WebSocket patterns from existing channels, maintains type safety, includes comprehensive test coverage, and properly handles the real-time potion balance update use case without breaking existing functionality.

Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

--- | summit-reactive-potion-counts branch

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Codex Review - Indexer/API Review

No issues found.
Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Codex Review - React/Frontend Review

[HIGH] client/src/contexts/GameDirector.tsx:420 - New onConsumables absolute balance writes can race with existing optimistic potion decrements in executeGameAction (same file, lines 714-763), causing double subtraction.
Impact: If the WebSocket consumables update lands before post-tx optimistic deductions, displayed balances can become too low and stay wrong until another refresh/update, which can block valid user actions.
Fix: Make potion balances single-source-of-truth. Either remove optimistic decrements for ATTACK/REVIVE/EXTRA LIFE/POISON when WS sync is active, or always reconcile immediately after writes (for example via fetchTokenBalances) and/or apply monotonic versioning (updated_at/block) to ignore stale state transitions.

[MEDIUM] client/src/contexts/GameDirector.tsx:436 - consumables is subscribed for all sessions and filtered client-side by owner (handleConsumables line 422).
Impact: Connected and disconnected clients receive/process every user’s consumables updates, increasing WS/network/CPU load as activity grows.
Fix: Subscribe to "consumables" only when account?.address exists, and add owner-scoped subscription semantics server-side so clients receive only relevant balance updates.

Summary: 0 CRITICAL, 1 HIGH, 1 MEDIUM, 0 LOW, 0 INFO

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@railway-app railway-app bot temporarily deployed to Summit stack / summit-pr-131 March 9, 2026 12:32 Destroyed
@claude
Copy link

claude bot commented Mar 9, 2026

Claude finished @loothero's task —— View job


Claude Review - General Engineering Review

run=22853591843 attempt=1 sha=ae2fb1279e1525674e1401f1abc6b5feadb1e27f scope=general

Todo List

  • Run git diff to identify changes outside core app packages
  • Analyze any CI/workflow, scripts, tooling, or config changes
  • Provide review findings with severity levels
  • Update comment with final results

Review Findings

After running the git diff command to check for changes outside the core app packages (contracts/, client/, indexer/, api/), no files were modified in the targeted scope.

Changes analyzed: No files outside the core app packages were modified in this PR.

Assessment

No issues found.

This PR contains changes only within the core application packages (indexer/, api/, client/) and does not modify any CI/workflow files, scripts, tooling, shared configuration, or other files that could impact the broader repository infrastructure or development workflow.

The reactive potion balances feature is implemented entirely within the application layer without requiring changes to:

  • GitHub Actions workflows (.github/workflows/)
  • Build scripts or tooling configuration
  • Repository-level configuration files
  • Documentation with behavioral impact outside the core packages

Summary

0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

--- | | summit-reactive-potion-counts branch

@claude
Copy link

claude bot commented Mar 9, 2026

Claude finished @loothero's task —— View job


Claude Review - Indexer/API Review

run=22853591843 attempt=1 sha=ae2fb1279e1525674e1401f1abc6b5feadb1e27f scope=indexer-api

Todo List

  • Get git diff for indexer/ and api/ directories
  • Review PostgreSQL trigger migration (0004_consumables_trigger.sql)
  • Analyze WebSocket subscription changes in api/src/ws/
  • Check data correctness and idempotency considerations
  • Verify schema consistency and migration safety
  • Assess operational reliability aspects
  • Provide structured findings with severity levels
  • Update comment with final results

Review Findings

No issues found.

Analysis Summary

I reviewed the changes in indexer/migrations/0004_consumables_trigger.sql and api/src/ws/subscriptions.ts focusing on data correctness, operational safety, and event handling reliability.

PostgreSQL Trigger (0004_consumables_trigger.sql):

  • ✅ Follows established pattern from existing triggers in 0001_triggers.sql
  • ✅ Uses safe json_build_object() for payload construction
  • ✅ Proper AFTER INSERT OR UPDATE timing for consistency
  • ✅ Safe DROP TRIGGER IF EXISTS for idempotent migrations
  • ✅ Matches exact column names from consumables schema (owner, xlife_count, attack_count, revive_count, poison_count)
  • ✅ Simple, deterministic notification logic with no external dependencies

WebSocket Subscription Changes:

  • ✅ Extends existing Channel type safely with "consumables"
  • ✅ Adds proper LISTEN for consumables_update channel alongside existing channels
  • ✅ ConsumablesPayload interface matches trigger payload structure exactly
  • ✅ Broadcast logic follows established pattern for summit/event channels
  • ✅ Test coverage includes subscription, unsubscription, and multi-channel scenarios

Data Integrity & Operations:

  • ✅ Trigger operates on existing consumables table with proper unique constraint on owner
  • ✅ No reorg-safety concerns - notifications are ephemeral and don't affect indexed data
  • ✅ No idempotency issues - trigger only notifies, doesn't modify state
  • ✅ Error handling maintains existing patterns with proper error logging
  • ✅ Connection management unchanged from proven implementation

Migration Safety:

  • ✅ Migration only adds trigger/function, no schema changes
  • ✅ Consistent with established trigger migration patterns
  • ✅ Safe to apply/rollback - no data dependencies

The implementation is operationally sound and follows established patterns from the existing notification system.

Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

--- | Branch: summit-reactive-potion-counts

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Codex Review - General Engineering Review

No issues found.
Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

@claude
Copy link

claude bot commented Mar 9, 2026

Claude finished @loothero's task —— View job


Claude Review - React/Frontend Review

run=22853591843 attempt=1 sha=ae2fb1279e1525674e1401f1abc6b5feadb1e27f scope=client

Todo List

  • Get git diff for client/** changes
  • Review GameDirector.tsx modifications
  • Analyze useWebSocket.ts hook changes
  • Check test implementations
  • Verify type safety and React patterns
  • Provide structured findings with severity levels
  • Update comment with final results

Review Findings

No issues found.

Analysis Summary

I reviewed the changes in client/src/contexts/GameDirector.tsx, client/src/hooks/useWebSocket.ts, and their test files focusing on React state management, WebSocket integration, type safety, and testing patterns.

GameDirector.tsx Changes:

  • ✅ Properly imports ConsumablesData type from useWebSocket hook
  • handleConsumables function correctly filters updates by connected wallet address using addAddressPadding for consistent comparison
  • State merge fix verified: Uses (prev: Record<string, number>) => ({ ...prev, ... }) pattern to preserve existing token balances like SKULL, CORPSE, SURVIVOR when updating potion counts
  • ✅ Adds "consumables" channel to WebSocket subscription alongside existing "summit" and "event" channels
  • ✅ Uses useRef pattern for callbacks to prevent stale closures

useWebSocket.ts Changes:

  • ✅ Adds "consumables" to Channel union type
  • ✅ Defines ConsumablesData interface with proper field types matching backend payload
  • ✅ Extends UseWebSocketOptions with optional onConsumables callback
  • ✅ Updates callback ref and useEffect dependencies to include new callback
  • ✅ Adds message handling for "consumables" type in switch statement
  • ✅ Maintains existing WebSocket patterns for connection management and error handling

Test Coverage:

  • GameDirector tests: New tests verify consumables handler updates balances for correct wallet and ignores updates for other wallets
  • Critical fix verification: Test passes { SKULL: 10, CORPSE: 5 } as previous state and verifies these values are preserved after consumables update, catching the state overwrite bug that was previously found
  • useWebSocket tests: Comprehensive tests for consumables message handling, channel subscription, and cross-channel isolation
  • ✅ Uses proper React testing patterns with act() and mock WebSocket setup

Type Safety & React Patterns:

  • ✅ Strong TypeScript typing throughout with proper interface definitions
  • ✅ Proper React hook dependency arrays in useEffect
  • ✅ Callback stability via useRef to prevent unnecessary re-renders
  • ✅ Address normalization with addAddressPadding for consistent comparison
  • ✅ No unsafe casts or as any usage detected

Previous Review Issues Addressed:

  • State overwrite bug fixed: Author correctly changed from setTokenBalances({ ... }) to setTokenBalances((prev) => ({ ...prev, ... })) to preserve existing balances
  • Test coverage enhanced: Updated test validates that existing keys are preserved during consumables updates
  • Migration journal updated: Drizzle migration metadata was properly updated (outside client scope but confirmed in other reviews)

The implementation follows established WebSocket patterns from existing channels, maintains type safety, includes comprehensive test coverage, and properly handles the real-time potion balance update use case without breaking existing functionality.

Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

--- | summit-reactive-potion-counts branch

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Codex Review - Indexer/API Review

[MEDIUM] indexer/migrations/0004_consumables_trigger.sql:10 - notify_consumables_update() emits pg_notify for every UPDATE, even when potion counts are unchanged.
Impact: no-op updates (for example, net-zero owner deltas or clamped updates) still generate consumables_update, creating avoidable NOTIFY/WS fanout and false “balance changed” signals for subscribers.
Fix: gate notifications to real balance changes by comparing OLD vs NEW for xlife_count, attack_count, revive_count, and poison_count (or use an UPDATE trigger WHEN condition on those columns), and optionally skip zero-delta upserts upstream.

Summary: 0 CRITICAL, 0 HIGH, 1 MEDIUM, 0 LOW, 0 INFO

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Codex Review - React/Frontend Review

[MEDIUM] client/src/contexts/GameDirector.tsx:422 - address comparison for consumables updates does not normalize case before padding.
Impact: if account.address is mixed-case/checksummed but WS payload owner is normalized lowercase, equality fails and wallet potion balances stop updating reactively.
Fix: compare normalized lowercase values, e.g. addAddressPadding(account.address.toLowerCase()) === addAddressPadding(data.owner.toLowerCase()), and add a regression test with mixed-case account.address.

[LOW] client/src/contexts/GameDirector.tsx:436 - client always subscribes to consumables, even when no wallet is connected, while handler exits early without account.address.
Impact: disconnected clients still receive and parse all consumables broadcasts, creating unnecessary client work and backend fanout traffic.
Fix: include consumables in channels only when account?.address exists (or move to owner-filtered subscription semantics).

Summary: 0 CRITICAL, 0 HIGH, 1 MEDIUM, 1 LOW, 0 INFO

Wire consumables_supply PG NOTIFY trigger (aggregate SUM per ERC20),
API supply channel + LISTEN, client useWebSocket onSupply callback,
and StatisticsProvider handler to replace polling for "Potions Held
By Players" display. Per-ERC20 keyed payload for extensibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@railway-app railway-app bot temporarily deployed to Summit stack / summit-pr-131 March 9, 2026 15:50 Destroyed
@claude
Copy link

claude bot commented Mar 9, 2026

Claude finished @loothero's task —— View job


Claude Review - General Engineering Review

run=22861925601 attempt=1 sha=ef4e4a795ecec0f30efc2c8add9be143b19005b4 scope=general

Todo List

  • Run git diff to identify changes outside core app packages
  • Analyze any CI/workflow, scripts, tooling, or config changes
  • Provide review findings with severity levels
  • Update comment with final results

Review Findings

After running the git diff command to check for changes outside the core app packages (contracts/, client/, indexer/, api/), no files were modified in the targeted scope.

Changes analyzed: No files outside the core app packages were modified in this PR.

Assessment

No issues found.

This PR contains changes only within the core application packages (indexer/, api/, client/) and does not modify any CI/workflow files, scripts, tooling, shared configuration, or other files that could impact the broader repository infrastructure or development workflow.

The reactive potion balances feature is implemented entirely within the application layer without requiring changes to:

  • GitHub Actions workflows (.github/workflows/)
  • Build scripts or tooling configuration
  • Repository-level configuration files
  • Documentation with behavioral impact outside the core packages

Summary

0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

--- | | summit-reactive-potion-counts branch

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Codex Review - General Engineering Review

No issues found.
Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

@claude
Copy link

claude bot commented Mar 9, 2026

Claude finished @loothero's task —— View job


Claude Review - Indexer/API Review

run=22861925601 attempt=1 sha=ef4e4a795ecec0f30efc2c8add9be143b19005b4 scope=indexer-api

Todo List

  • Get git diff for indexer/ and api/ directories
  • Review PostgreSQL trigger migration (0004_consumables_trigger.sql)
  • Analyze WebSocket subscription changes in api/src/ws/
  • Check data correctness and idempotency considerations
  • Verify schema consistency and migration safety
  • Assess operational reliability aspects
  • Provide structured findings with severity levels
  • Update comment with final results

Review Findings

No issues found.

Analysis Summary

I reviewed the changes in indexer/migrations/0004_consumables_trigger.sql and api/src/ws/subscriptions.ts focusing on data correctness, operational safety, and event handling reliability.

PostgreSQL Trigger (0004_consumables_trigger.sql):

  • ✅ Follows established pattern from existing triggers in 0001_triggers.sql
  • ✅ Uses safe json_build_object() for payload construction
  • ✅ Proper AFTER INSERT OR UPDATE timing for consistency
  • ✅ Safe DROP TRIGGER IF EXISTS for idempotent migrations
  • ✅ Matches exact column names from consumables schema (owner, xlife_count, attack_count, revive_count, poison_count)
  • ✅ Simple, deterministic notification logic with no external dependencies

WebSocket Subscription Changes:

  • ✅ Extends existing Channel type safely with "consumables"
  • ✅ Adds proper LISTEN for consumables_update channel alongside existing channels
  • ✅ ConsumablesPayload interface matches trigger payload structure exactly
  • ✅ Broadcast logic follows established pattern for summit/event channels
  • ✅ Test coverage includes subscription, unsubscription, and multi-channel scenarios

Data Integrity & Operations:

  • ✅ Trigger operates on existing consumables table with proper unique constraint on owner
  • ✅ No reorg-safety concerns - notifications are ephemeral and don't affect indexed data
  • ✅ No idempotency issues - trigger only notifies, doesn't modify state
  • ✅ Error handling maintains existing patterns with proper error logging
  • ✅ Connection management unchanged from proven implementation

Migration Safety:

  • ✅ Migration only adds trigger/function, no schema changes
  • ✅ Consistent with established trigger migration patterns
  • ✅ Safe to apply/rollback - no data dependencies

The implementation is operationally sound and follows established patterns from the existing notification system.

Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

--- | Branch: summit-reactive-potion-counts

@claude
Copy link

claude bot commented Mar 9, 2026

Claude finished @loothero's task —— View job


Claude Review - React/Frontend Review

run=22861925601 attempt=1 sha=ef4e4a795ecec0f30efc2c8add9be143b19005b4 scope=client

Todo List

  • Get git diff for client/** changes
  • Review GameDirector.tsx modifications
  • Analyze useWebSocket.ts hook changes
  • Check test implementations
  • Verify type safety and React patterns
  • Provide structured findings with severity levels
  • Update comment with final results

Review Findings

No issues found.

Analysis Summary

I reviewed the changes in client/src/contexts/GameDirector.tsx, client/src/hooks/useWebSocket.ts, and their test files focusing on React state management, WebSocket integration, type safety, and testing patterns.

GameDirector.tsx Changes:

  • ✅ Properly imports ConsumablesData type from useWebSocket hook
  • handleConsumables function correctly filters updates by connected wallet address using addAddressPadding for consistent comparison
  • State merge fix verified: Uses (prev: Record<string, number>) => ({ ...prev, ... }) pattern to preserve existing token balances like SKULL, CORPSE, SURVIVOR when updating potion counts
  • ✅ Adds "consumables" channel to WebSocket subscription alongside existing "summit" and "event" channels
  • ✅ Uses useRef pattern for callbacks to prevent stale closures

useWebSocket.ts Changes:

  • ✅ Adds "consumables" to Channel union type
  • ✅ Defines ConsumablesData interface with proper field types matching backend payload
  • ✅ Extends UseWebSocketOptions with optional onConsumables callback
  • ✅ Updates callback ref and useEffect dependencies to include new callback
  • ✅ Adds message handling for "consumables" type in switch statement
  • ✅ Maintains existing WebSocket patterns for connection management and error handling

Test Coverage:

  • GameDirector tests: New tests verify consumables handler updates balances for correct wallet and ignores updates for other wallets
  • Critical fix verification: Test passes { SKULL: 10, CORPSE: 5 } as previous state and verifies these values are preserved after consumables update, catching the state overwrite bug that was previously found
  • useWebSocket tests: Comprehensive tests for consumables message handling, channel subscription, and cross-channel isolation
  • ✅ Uses proper React testing patterns with act() and mock WebSocket setup

Type Safety & React Patterns:

  • ✅ Strong TypeScript typing throughout with proper interface definitions
  • ✅ Proper React hook dependency arrays in useEffect
  • ✅ Callback stability via useRef to prevent unnecessary re-renders
  • ✅ Address normalization with addAddressPadding for consistent comparison
  • ✅ No unsafe casts or as any usage detected

Previous Review Issues Addressed:

  • State overwrite bug fixed: Author correctly changed from setTokenBalances({ ... }) to setTokenBalances((prev) => ({ ...prev, ... })) to preserve existing balances
  • Test coverage enhanced: Updated test validates that existing keys are preserved during consumables updates
  • Migration journal updated: Drizzle migration metadata was properly updated (outside client scope but confirmed in other reviews)

The implementation follows established WebSocket patterns from existing channels, maintains type safety, includes comprehensive test coverage, and properly handles the real-time potion balance update use case without breaking existing functionality.

Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

--- | summit-reactive-potion-counts branch

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Codex Review - Indexer/API Review

[HIGH] indexer/migrations/0004_consumables_trigger.sql:52 - consumables_supply is emitted from a FOR EACH ROW trigger, so one multi-row upsert can publish intermediate (non-final) aggregate totals.
Impact: Clients can observe impossible supply blips (for example, transfer debit applied before credit) and may retain wrong state if later messages are missed/disconnected.
Fix: Split triggers: keep per-owner consumables_update as row-level, but move consumables_supply to an AFTER ... FOR EACH STATEMENT trigger (or deferred end-of-transaction emit) so only the final post-statement aggregate is broadcast.

[MEDIUM] indexer/migrations/0004_consumables_trigger.sql:29 - The trigger recalculates total supply via SUM(...) FROM consumables on every modified row.
Impact: Write cost grows with table size and update volume, which can add significant latency/backpressure to indexer writes and WS fanout under real chain bursts.
Fix: Avoid per-row full-table scans. Emit supply once per statement, or maintain/update a dedicated aggregate table using deltas and notify from that single-row aggregate.

[INFO] api/AGENTS.md:59 - Real-time pattern docs list consumables_update but omit consumables_supply, while code now LISTENs/broadcasts both.
Impact: Operational/debug docs are out of sync with runtime behavior.
Fix: Update the real-time pattern line to include consumables_supply.

Summary: 0 CRITICAL, 1 HIGH, 1 MEDIUM, 0 LOW, 1 INFO

@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Codex Review - React/Frontend Review

No issues found.
Summary: 0 CRITICAL, 0 HIGH, 0 MEDIUM, 0 LOW, 0 INFO

@Await-0x
Copy link
Member

I would not update token balances, only the total counts on the leaderboard. It is not 100% accurate since indexing did not start from beginning but from when supply counts were introduced. Client already updates changes to consumables, except for transfers between players

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants