Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@terwey
Copy link
Collaborator

@terwey terwey commented Nov 3, 2025

Summary

  • add recomma.OrderIdentifier and plumb venue-aware dispatch through the queue emitter, engine, and runtime wiring
  • rekey fill tracker state and API cancel handling on venue-aware identifiers and expose storage helpers for venue lookups
  • update Hyperliquid websocket/status refreshers and tests to emit and consume venue-scoped identifiers

Reviewing

Read specs/multi_venue_emission.adoc before reviewing


https://chatgpt.com/codex/tasks/task_e_6907f529e9788326a5b7d93ea277ce5a

@terwey terwey marked this pull request as ready for review November 3, 2025 01:07
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.

ℹ️ 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 685 to 695
idents, err := h.store.ListSubmissionIdentifiersForOrder(ctx, *oid)
if err != nil {
if h.logger != nil {
h.logger.Error("CancelOrderByOrderId load submission failed", slog.String("orderid", oid.Hex()), slog.String("error", err.Error()))
h.logger.Warn("CancelOrderByOrderId list identifiers failed", slog.String("orderid", oid.Hex()), slog.String("error", err.Error()))
}
return CancelOrderByOrderId500Response{}, nil
}
if !found || (action.Create == nil && action.Modify == nil) {
if len(idents) == 0 {
if h.logger != nil {
h.logger.Info("CancelOrderByOrderId submission not found", slog.String("orderid", oid.Hex()))
}
return CancelOrderByOrderId404Response{}, nil

Choose a reason for hiding this comment

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

P1 Badge Return 500 when identifier lookup fails

The cancel endpoint now calls ListSubmissionIdentifiersForOrder and logs any error, but it falls through and returns a 404 when the slice is empty. A storage failure (e.g. database unavailable) will therefore be reported to clients as “not found” instead of a server error, which makes retry logic and alerting unreliable. The previous implementation returned a 500 on the same failure path. Consider propagating the error after logging so transient storage issues aren’t silently treated as missing orders.

Useful? React with 👍 / 👎.

Comment on lines 159 to 175
// ListVenuesForBot returns the configured venue assignments for the given bot.
// If no explicit assignments exist, the default Hyperliquid venue is returned.
func (s *Storage) ListVenuesForBot(ctx context.Context, botID uint32) ([]VenueAssignment, error) {
s.mu.Lock()
defer s.mu.Unlock()

assignments, err := s.queries.ListBotVenueAssignments(ctx, int64(botID))
if err != nil {
return nil, err
}

if len(assignments) == 0 {
return []VenueAssignment{{
VenueID: defaultHyperliquidVenueID,
Wallet: defaultHyperliquidWallet,
IsPrimary: true,
}}, nil

Choose a reason for hiding this comment

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

P1 Badge Default venue uses placeholder wallet causing mismatched identifiers

When no venue assignments exist for a bot, ListVenuesForBot returns an assignment with Wallet: default (the defaultHyperliquidWallet constant). The engine uses this value when emitting order work, so submissions and fill‑tracker entries are keyed by VenueID=hyperliquid:default and wallet default. However the websocket client is constructed with the actual Hyperliquid wallet from secrets and records status updates using that real wallet string (hl/ws/ws.go around the New constructor). The same order therefore appears under two different OrderIdentifiers (one with wallet default, one with the real wallet) and reloadDeal iterates over both, creating duplicate order state with missing status data. This corrupts snapshots and downstream reconciliation. The default path should use the runtime wallet or persist the secret to the venues table so identifiers match across subsystems.

Useful? React with 👍 / 👎.

@terwey
Copy link
Collaborator Author

terwey commented Nov 3, 2025

@codex review with specs/multi_venue_emission.adoc in mind

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.

ℹ️ 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 +266 to 269
hasLocalOrder := len(storedIdents) > 0

action, latestEvent, shouldEmit, err := e.reduceOrderEvents(ctx, currency, oid, hasLocalOrder, orderLogger)
if err != nil {

Choose a reason for hiding this comment

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

P1 Badge Skip fan-out when one venue already has a submission

The loop treats hasLocalOrder := len(storedIdents) > 0 as a global flag for the order and immediately bails out when reduceOrderEvents returns shouldEmit=false. When a bot is assigned to multiple venues and one venue already recorded a submission, hasLocalOrder is true even for venues that never saw a create. With no new 3Commas snapshot, reduceOrderEvents returns ActionNone, the loop continues, and resolveOrderTargets is never called, so missing venues never receive their initial create. A transient failure during fan-out therefore leaves additional venues permanently unsynchronized until a new bot event happens. Consider evaluating hasLocalOrder per target or emitting create work for assignments that still lack a submission.

Useful? React with 👍 / 👎.

@terwey
Copy link
Collaborator Author

terwey commented Nov 3, 2025

@codex please fix the following

💡 Codex Review

recomma/storage/storage.go L125-L133

P1 Badge Update default wallet without migrating existing submissions
Startup now calls EnsureDefaultVenueWallet to rewrite the default venue’s wallet to the runtime secret, but the implementation only updates the venues row and does not touch already persisted records in hyperliquid_submissions or hyperliquid_status_history. Those rows remain keyed by the old wallet string, while new websocket/status updates and venue assignments use the new wallet. Because the fill tracker and engine cache orders by OrderIdentifier (venue + wallet), an upgrade will rebuild state with the old identifier and subsequently create a second, different identifier for the same order when fresh statuses arrive, causing previously active orders to be ignored or re‑emitted as “missing”. Consider migrating existing submission/status rows (or aliasing both wallets) when the default wallet changes so prior orders remain discoverable and aren’t replayed or dropped.

@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits. You can see your limits in the Codex usage dashboard.

@terwey
Copy link
Collaborator Author

terwey commented Nov 3, 2025

@codex please fix the following

recomma/storage/storage.go L125-L133

Update default wallet without migrating existing submissions
Startup now calls EnsureDefaultVenueWallet to rewrite the default venue’s wallet to the runtime secret, but the implementation only updates the venues row and does not touch already persisted records in hyperliquid_submissions or hyperliquid_status_history. Those rows remain keyed by the old wallet string, while new websocket/status updates and venue assignments use the new wallet. Because the fill tracker and engine cache orders by OrderIdentifier (venue + wallet), an upgrade will rebuild state with the old identifier and subsequently create a second, different identifier for the same order when fresh statuses arrive, causing previously active orders to be ignored or re‑emitted as “missing”. Consider migrating existing submission/status rows (or aliasing both wallets) when the default wallet changes so prior orders remain discoverable and aren’t replayed or dropped.

@chatgpt-codex-connector
Copy link

Summary

  • Migrated default Hyperliquid venue updates to clone and re-key existing submissions and status history when the wallet changes so historical orders continue to resolve under the runtime identifier. storage/storage.goL178-L310

Testing

  • ⚠️ go test ./... (terminated manually after prolonged runtime)

View task →

@terwey
Copy link
Collaborator Author

terwey commented Nov 3, 2025

@codex review with specs/multi_venue_emission.adoc in mind

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.

ℹ️ 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 199 to 206
}

work := recomma.OrderWork{
OrderId: oid,
Identifier: ident,
OrderId: oid,
Action: recomma.Action{
Type: recomma.ActionCancel,
Cancel: &cancel,

Choose a reason for hiding this comment

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

P1 Badge ReconcileTakeProfits ignores venue-specific emitters

The fill tracker still accepts a single recomma.Emitter and cmd/recomma/main.go wires it up with the default HyperLiquidEmitter. When ReconcileTakeProfits emits cancellations or recreate orders it calls that emitter directly, even though each OrderWork now carries a venue-scoped identifier. For take profits that belong to a non‑default venue, those emissions will be executed with the default wallet/client and recorded under the foreign venue, so the wrong account is modified and the intended venue never receives the cancel/create. The multi‑venue spec expects take‑profit reconciliation to dispatch per venue; this path should go through the venue dispatcher or resolve the correct emitter before emitting.

Useful? React with 👍 / 👎.

…tifier-and-refactor-queue' into codex/expand-openapi.yaml-for-venue-management

- Fix storage with duplicate UpsertVenue
…ue-management

feat: add venue management APIs and venue-aware identifiers
… into codex/extend-orderwork-with-identifier-and-refactor-queue
@terwey terwey merged commit c5393b1 into codex/investigate-multi-wallet-support-for-hyperliquid Nov 4, 2025
2 checks passed
@terwey terwey deleted the codex/extend-orderwork-with-identifier-and-refactor-queue branch November 4, 2025 02:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants