fix(orderbook): re-fetch stale fulfilled cache entries missing executedFee - #123
Merged
Conversation
…res all three fields Ponder's context.db.sql maps raw-SQL result rows positionally via Object.values(row). The three unaliased coalesce(sum(...)) columns all came back named "coalesce", collapsed into one key in the row object, and the values shifted: the executedFee sum was stored under executedSellAmount and the other two fields were dropped from the JSON entirely (9,830 of 9,834 TWAP parents on the deployed DB show the one-key shape, and the stored value matches the children's fee sum exactly). Unique .as() aliases keep the column names distinct so the positional mapping is stable. Unit tests can't catch this (they mock the DB and vanilla drizzle drivers use array row mode, which is immune), hence the warning comment.
…edFee cow_cache rows written before the executed_fee column existed carry a null fee, and terminal entries are never re-fetched — so fulfilled orders served from those rows keep executedFee null forever (and the TWAP fee totals stay zero). The API does return the fee for these orders; the indexer just never asks again. - fetchOrderStatusByUids: a fulfilled cache hit with a null executedFee is now treated as a miss and re-fetched once; if the UID has aged out of /by_uids, the cached data is returned as a fallback instead of omitting the UID (which callers read as "not on API yet"). - reconcileOpenCachedRows: fulfilled durable-cache rows with a null fee join the re-fetch set, so owner drains heal them too. Expired and cancelled rows are left alone — nothing was executed. - upsertDiscreteOrders / OrderStatusTracker / CandidateConfirmer: executed columns in the conflict sets now coalesce with the existing value, so a cached null can never erase amounts written by an earlier fresh fetch. The drain's no-op filter compares post-coalesce values so unchanged rows don't bump updatedAtBlock.
This was referenced Jul 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Fulfilled discrete orders on the deployed indexer have
executedFee: nulleven though the CoW orderbook API returns a fee for them (checked:GET /orders/{uid}returnsexecutedFee: 277555925419363854for an order our DB stores with a null fee). As a result the TWAP fee totals inadditionalDatasum to zero.Root cause
executed_feewas added tocow_cache.order_uid_cacheandcow_cache.composable_orderviaADD COLUMN IF NOT EXISTS(setup.ts), so every row cached by earlier deployments has a null fee. Terminal entries are cached indefinitely and never re-fetched, so the null can never heal — every reindex re-serves it from cache.Fix
fetchOrderStatusByUids: a fulfilled cache hit with a nullexecutedFeeis treated as a miss and re-fetched once (the fresh result overwrites the cache row, so it's one extra fetch per stale UID, ever). If the UID has aged out of/by_uids, the cached data is returned as a fallback instead of omitting the UID — callers interpret a missing UID as "not on API yet".reconcileOpenCachedRows: fulfilled durable-cache rows with a null fee join the re-fetch set, so owner drains heal them too.upsertDiscreteOrders,OrderStatusTracker,CandidateConfirmer): executed columns nowcoalesce(excluded.x, existing.x)— a cached null can never erase amounts written by an earlier fresh fetch.uidPrecomputealready did this; these paths didn't. The drain's no-op filter now compares post-coalesce effective values so unchanged rows don't bumpupdatedAtBlock.Verification
pnpm typecheck,pnpm lint,pnpm testgreen (159 tests).