Skip to content

Fix DATA-RECOVERY-001 review findings: risk-gate test coverage + honest source labeling - #61

Merged
jamalfrnk merged 1 commit into
mainfrom
fix/data-recovery-followup
Aug 3, 2026
Merged

Fix DATA-RECOVERY-001 review findings: risk-gate test coverage + honest source labeling#61
jamalfrnk merged 1 commit into
mainfrom
fix/data-recovery-followup

Conversation

@jamalfrnk

Copy link
Copy Markdown
Owner

Summary

Fast-follow to PR #59 (DATA-RECOVERY-001, issue #35), addressing the two Medium (non-blocking) findings from its independent review:

  • LA-QG-001: checkTrustworthySource's actual call sites in paperEngine.ts (processNewOrder/submitOrder, sweepLimitOrders) had zero automated regression coverage -- only the standalone risk-check function and evaluateTrade's dispatch of it were unit-tested. Added 4 tests to paperEngine.test.ts: a CoinGecko-fallback new order gets REJECTED, a Hyperliquid-sourced control still FILLEDs, a CoinGecko-fallback marketable resting limit order stays ACKNOWLEDGED, and a Hyperliquid-sourced control still fills via sweepLimitOrders.
  • LA-QG-002: the 1s WS-driven marketUpdate broadcast loop in server.ts always hardcoded source: 'hyperliquid', even though the change24h/volume fields merged into that same payload come from the last REST ingestion cycle's getLastKnownMarketMeta, which could itself be CoinGecko-sourced in a narrow window (WS healthy, REST degraded). Now reports meta.source -- the real provenance of those fields -- instead. Documented in docs/architecture/market-data.md.

Neither finding affected risk-gating correctness (the reviewer independently confirmed the gate itself works via direct DB manipulation) -- this is test-coverage and UI/labeling-accuracy hardening.

Verification

  • Full server suite: 195/195 passing (191 baseline + 4 new).
  • npm run build clean.
  • Checked for CRLF pollution (git diff --stat vs git diff -w --stat -- identical).

Test plan

  • Independent reviewer confirms the 4 new tests genuinely exercise the real call sites (not vacuously passing) and that meta.source is the correct fix for LA-QG-002

…st source labeling

Independent review of PR #59 (DATA-RECOVERY-001) verified the trustworthy-
source risk gate works correctly by hand but flagged two Medium,
non-blocking findings (LA-QG-001, LA-QG-002). Addressing both here.

- paperEngine.test.ts: adds regression coverage for checkTrustworthySource
  at its actual call sites -- processNewOrder (via submitOrder) and
  sweepLimitOrders -- which previously had zero automated coverage; only
  the standalone risk-check function and evaluateTrade's dispatch of it
  were tested. Each new describe block includes a positive control
  (a genuinely Hyperliquid-sourced order still fills) alongside the
  negative case, matching this file's existing ownership-test convention.
- server.ts: the 1s WS-driven marketUpdate broadcast loop always labeled
  its payload source: 'hyperliquid', even though change24h/volume in that
  same payload are only as fresh as the last REST ingestion cycle, which
  could itself have fallen back to CoinGecko while the WS stays healthy.
  Now reports meta.source (the REST cycle's actual source) instead of
  hardcoding a label the merged-in fields don't necessarily earn.
- docs/architecture/market-data.md: documents this source-attribution
  nuance in the broadcast loop.

Full server suite: 195/195 passing (191 baseline + 4 new). Build clean.

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

Copy link
Copy Markdown

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: adcc116cca

ℹ️ 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 thread server/src/server.ts
// trustworthiness of the change24h/volume figures being merged in
// alongside it (flagged by independent review of PR #59, LA-QG-002)
// -- meta.source truthfully reflects what those fields actually are.
source: meta.source,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve the provenance of the live price separately

When REST has fallen back to CoinGecko while the Hyperliquid WebSocket remains healthy, this payload contains a Hyperliquid mid-price but labels the entire update coingecko. The client copies that field into its market snapshot and explicitly renders the current price as Source: CoinGecko (fallback) in chartAccessibility.ts and AssetCandlestickCard.tsx, so the attempted provenance fix now misattributes the user-visible live price. Carry separate price and metadata source fields (or otherwise update the client contract) rather than assigning the metadata source to this mixed-provider row.

Useful? React with 👍 / 👎.

@jamalfrnk

Copy link
Copy Markdown
Owner Author

Independent review: PASS

Full server suite: 195/195 passing. Build clean. CI green (3/3 checks).

Non-vacuity of the new tests was empirically verified, not just inspected: the reviewer temporarily stripped checkTrustworthySource from both call sites (evaluateTrade's check array and sweepLimitOrders's gate) and reran paperEngine.test.ts -- both new negative-case tests (CoinGecko-sourced order should be REJECTED / should stay ACKNOWLEDGED) genuinely failed once the gate was removed, confirming they actually exercise the real protection rather than passing regardless. Reverted afterward; full suite reconfirmed clean.

LA-QG-002 fix confirmed correct: getLastKnownMarketMeta's source field is typed identically to the client's existing MarketSnapshotSource, and the client's WS consumption path (useMarketDataSocket.ts) and rendering (AssetCandlestickCard.tsx, chartAccessibility.ts) already branch correctly on both 'hyperliquid' and 'coingecko' -- a 'coingecko' value flowing through the fast WS path renders correctly, not just tolerably.

No findings. Ready to merge at your convenience.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Fast-follow hardening for DATA-RECOVERY-001 review findings from PR #59 by expanding regression coverage around the trustworthy-source gate at real paper-engine call sites, and by adjusting market-data WebSocket source labeling to better reflect provenance of merged REST metadata.

Changes:

  • Update the WS marketUpdate payload to report source: meta.source (REST-derived provenance) instead of hardcoding 'hyperliquid'.
  • Add 4 unit tests in paperEngine.test.ts to exercise checkTrustworthySource behavior through submitOrder and sweepLimitOrders integration paths.
  • Document the WS publish-loop provenance nuance in docs/architecture/market-data.md.

Reviewed changes

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

File Description
server/src/server.ts Changes WS payload source labeling to use REST meta provenance (meta.source).
server/src/execution/paperEngine.test.ts Adds integration-level tests for trustworthy-source gating at submitOrder / sweepLimitOrders call sites.
docs/architecture/market-data.md Documents the provenance semantics of fields merged into WS market updates.
Suppressed comments (2)

server/src/execution/paperEngine.test.ts:172

  • Same issue as the previous test: isUserHalted is mocked as if there is no riskLimits row, but getOrCreateRiskLimits then returns a row without any intervening insert. Keeping the mocked DB state consistent will make this test less brittle and more representative.
    selectMock
      .mockReturnValueOnce(dbChain([])) // isUserHalted
      .mockReturnValueOnce(dbChain([marketRow('hyperliquid')])) // getMarketSnapshot
      .mockReturnValueOnce(dbChain([RISK_LIMITS_ROW])) // getOrCreateRiskLimits
      .mockReturnValueOnce(dbChain([{ value: 0 }])) // countOpenPositions

server/src/execution/paperEngine.test.ts:216

  • Same as the prior test: the positive-control restingOrder should include at least quantity so fillOrder isn't operating on NaN in test. Otherwise this can pass while not actually exercising a realistic fill path.
  it('positive control: a genuinely Hyperliquid-sourced marketable resting limit order fills', async () => {
    const restingOrder = { id: 'order-2', userId: 'user-a', asset: 'BTC', side: 'LONG', orderType: 'LIMIT', limitPrice: '100', status: 'ACKNOWLEDGED' };
    selectMock

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

Comment thread server/src/server.ts
Comment on lines +179 to +187
// `price` here is always genuinely Hyperliquid-sourced (a live WS
// mid), but change24h/volume are only as fresh as the *last REST
// ingestion cycle*, which could itself have fallen back to
// CoinGecko even while this WS connection is healthy. Labeling the
// whole row "hyperliquid" in that window would overstate the
// trustworthiness of the change24h/volume figures being merged in
// alongside it (flagged by independent review of PR #59, LA-QG-002)
// -- meta.source truthfully reflects what those fields actually are.
source: meta.source,
Comment on lines +143 to +145
.mockReturnValueOnce(dbChain([])) // isUserHalted -- no risk_limits row, defaults to false
.mockReturnValueOnce(dbChain([marketRow('coingecko')])) // getMarketSnapshot
.mockReturnValueOnce(dbChain([RISK_LIMITS_ROW])) // getOrCreateRiskLimits
Comment on lines +199 to +201
it('leaves a marketable resting limit order ACKNOWLEDGED (not filled) when the market is CoinGecko-fallback-sourced', async () => {
const restingOrder = { id: 'order-2', userId: 'user-a', asset: 'BTC', side: 'LONG', orderType: 'LIMIT', limitPrice: '100', status: 'ACKNOWLEDGED' };
selectMock
@jamalfrnk
jamalfrnk merged commit 4c2fa04 into main Aug 3, 2026
4 checks passed
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.

2 participants