Skip to content

Send the faded order hashes that caused a circuit breaker block in the blocking notification - #463

Draft
claude[bot] wants to merge 6 commits into
mainfrom
fix/cb-block-notification-order-id
Draft

Send the faded order hashes that caused a circuit breaker block in the blocking notification#463
claude[bot] wants to merge 6 commits into
mainfrom
fix/cb-block-notification-order-id

Conversation

@claude

@claude claude Bot commented Jul 13, 2026

Copy link
Copy Markdown

Requested by Christian Angelopoulos · Slack thread

Before / After

Before: when the circuit breaker blocks a filler, the blocking notification POSTed to their endpoint contains only { blockUntilTimestamp } — fillers cannot tell which order(s) triggered the block.

After: the notification names the faded order(s) that caused the block — the hashes of the posted orders the filler faded, which is what fired the circuit breaker in the first place. This works for both soft- and hard-quote requests, since the cause of a block is always a posted order:

{
  "blockUntilTimestamp": 1783970000,
  "orderHashes": ["0x9f2b...c41a", "0x77aa...01ce"],
  "quoteId": "b71e2a10-..." // current request's quoteId, when it carries one (hard quotes)
}

requestId is no longer sent. Block entries written before this change have no stored hashes; for those, orderHashes is simply omitted during the transition (entries refresh on every cron run, so this window is short).

How

The fade-rate-v2 cron is the block writer: it queries the latestRfqsV2 Redshift view for each filler's recent orders and whether each faded, computes per-filler Laplace-smoothed fade rates, and writes the block entry per filler to the Dynamo timestamps table. This change threads the faded orders' hashes along that same path (kept current with #454's rate-based trigger, #465/#473's cleanups, and #482's clean-run decay streak via merges):

  • lib/repositories/fades-repository.ts: the latestRfqsV2 view and V2_FADE_RATE_SQL now also select orderHash (column verified against posted_orders.yaml in data-eng-workflows, where it is also a dedupe key — present on every row); V2FadesRowType gains orderHash.
  • lib/cron/fade-rate-v2.ts: getFillersFadeStats() now also collects the faded orders' hashes per cohort (windowFadedOrderHashes for the post-block rate window, duringBlockFadedOrderHashes for the in-flight-during-block cohort). calculateNewTimestamps() persists on the block entry the hashes of whichever cohort(s) tripped or extended the block: set on a new block, appended (deduped, capped at MAX_FADED_ORDER_HASHES = 50, most recent kept) on extension, carried forward while the block is active, and cleared when the filler drops back under threshold.
  • lib/repositories/base.ts + lib/repositories/timestamp-repository.ts + lib/constants.ts: additive optional fadedOrderHashes list attribute on the timestamp row — written only when present, read back as undefined on legacy rows, no changes to existing attributes.
  • lib/providers/circuit-breaker/{index,dynamo,mock}.ts: EndpointStatuses.disabled entries surface fadedOrderHashes.
  • lib/quoters/WebhookQuoter.ts: notifyBlock() sends orderHashes from the block entry (omitted when the entry has none) plus the current request's quoteId when present; requestId removed.
  • lib/entities/{QuoteRequest,HardQuoteRequest}.ts: unchanged from main — the earlier threading of the current request's order hash is no longer needed.

Testing

  • jest unit suite on the merged result (base acce427): 31 suites passed, 300 tests passed. New coverage: per-cohort faded-hash collection in the cron, block/extend/carry-forward/clear/cap persistence semantics, Dynamo round-trip incl. legacy rows without the attribute, provider propagation, and exact notification payloads incl. the legacy-entry case.
  • tsc build clean; touched files pass prettier --check and eslint with no errors and no new warning patterns.

Context: reported by a filler (Thomas Retraint) — blocked fillers receive the notification but cannot identify the order that triggered the circuit breaker.

claude added 2 commits July 13, 2026 18:53
…otification

Fillers blocked by the circuit breaker receive a notification containing
only blockUntilTimestamp, so they cannot tell which order triggered it.
Thread the QuoteRequest into WebhookQuoter.notifyBlock and include the
order's requestId (and quoteId when present, e.g. hard quotes) in the
notification payload.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oU7bRX2dPnye7vC54t3Uz
…tion

Per review feedback, the block notification now identifies the triggering
order by its on-chain order hash: HardQuoteRequest.toQuoteRequest() threads
order.hash() onto the QuoteRequest (internal only; excluded from wire
payloads), and notifyBlock sends { orderHash, quoteId } for hard quotes.
Soft quotes have no signed order at quote time, so they fall back to
requestId to keep an identifier in the notification.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oU7bRX2dPnye7vC54t3Uz
@claude claude Bot changed the title Include triggering order requestId/quoteId in circuit breaker block notification Include triggering order hash and quoteId in circuit breaker block notification Jul 13, 2026
…e notification

Per review, the block notification should name the order(s) whose fades
caused the block, not the order currently being quoted. The fade-rate-v2
cron now selects orderHash from the latestRfqsV2 view (verified against
posted_orders.yaml in data-eng-workflows), collects the hashes of each
filler's new faded orders, and persists them on the block entry in Dynamo
(additive fadedOrderHashes list attribute; capped, deduped, carried
forward while the block is active, cleared when it expires). The circuit
breaker provider surfaces them on disabled endpoints and notifyBlock sends
{ blockUntilTimestamp, orderHashes, quoteId? }. requestId is gone from the
payload, and legacy block entries without stored hashes simply omit
orderHashes. The previous threading of the current request's order hash
through QuoteRequest is reverted as no longer needed.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oU7bRX2dPnye7vC54t3Uz
@claude claude Bot changed the title Include triggering order hash and quoteId in circuit breaker block notification Send the faded order hashes that caused a circuit breaker block in the blocking notification Jul 13, 2026
claude added 3 commits July 23, 2026 19:02
…rate)

Re-applies the fadedOrderHashes threading onto the rewritten cron:
getFillersFadeStats now also collects the faded order hashes per cohort
(post-block window and during-block), and calculateNewTimestamps persists
the hashes of whichever cohort(s) tripped or extended the block. Repository
and provider changes carried over onto the renamed row fields
(lastExaminedTimestamp/fadeWindowStart) and number-typed attributes; the
notification payload behavior is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oU7bRX2dPnye7vC54t3Uz
Keeps the orderHash selection in the V2 fade query; takes upstream's
removal of the legacy V1 FadesRepository and the un-exported
V2_FADE_RATE_SQL (no remaining importers).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oU7bRX2dPnye7vC54t3Uz
…tchlist

Re-applies the fadedOrderHashes threading onto the reworked cron:
getFillersFadeStats still collects the faded order hashes per cohort, and
calculateNewTimestamps persists them through the new consecutiveCleanRuns
branches (extend/new-block restart the streak and set hashes; blocked-clean
carries them; the under-threshold branch omits the attribute so the
full-item put clears it). Repository gains the list attribute alongside
consecutiveCleanRuns. Notification payload behavior is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018oU7bRX2dPnye7vC54t3Uz
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.

1 participant