Skip to content

fix(0135): make the carry bound conditional on a fresh venue surviving - #241

Open
stkrolikiewicz wants to merge 1 commit into
developfrom
fix/0135_conditional-carry-bound
Open

fix(0135): make the carry bound conditional on a fresh venue surviving#241
stkrolikiewicz wants to merge 1 commit into
developfrom
fix/0135_conditional-carry-bound

Conversation

@stkrolikiewicz

Copy link
Copy Markdown
Collaborator

Summary

The unconditional bound shipped on 2026-08-21 and was rolled back within the hour: measured against the same data, it blanked sources on 2,284 of 4,365 assets (52%) while preventing zero evictions. The defect it guards — a stale venue outvoting a live one in the unweighted §5.5 median — needs a live venue to victimise, so the guard now fires only when one survives.

per_source derives two prices (latest priced close, and latest priced close within 2 h); a new level 1b drops a stale venue only if the asset still has a fresh one. If every venue is stale there is nothing to defend and dropping them all is pure loss.

Counterfactual, measured BEFORE applying

This is runbook step 1b — the step the previous attempt lacked. Both variants run over the same live data in one sitting, read-only, 4,152 assets:

Metric Current prod This PR
zero_but_vwap_ok 30 0
zero_price_usd 868 368
empty_sources 840 368
zero_vwap 840 368

Every metric improves; none regresses. The 472-asset gain on empty_sources comes from C2's carry rescuing venues whose tip is un-enriched — which the conditional guard does not take back.

Worth noting: empty_sources, zero_price_usd and zero_vwap land on 368 exactly. An asset now has a price, sources and a VWAP, or none of the three — the contradiction this task exists for is gone by construction rather than by luck.

Sizing: the guard currently prevents nothing, and is kept anyway

Measured the same session: 7 assets are at risk (≥3 sources, mixed fresh/stale) and on all 7 the fresh-only median sits within 1% of the all-source median, against a 20% threshold — so zero live evictions.

Kept regardless, because that zero is not evidence of future safety. The mixed population is small precisely because almost nothing is fresh while enrichment is down (0215); BE has confirmed that fix is imminent, so fresh venues multiply and the mixed population grows with them. The risk rises as the pipeline recovers, and the conditional form costs nothing by construction. Re-measure after 0215 and 0111 land.

Tests

Both arms are pinned and proven non-vacuous:

  • Asset 10 (STA) — every venue stale ⇒ the guard must NOT fire. Making the bound unconditional fails this with sources = {}: the production regression reproduced in miniature.
  • Asset 14 (MIX) — one fresh venue, one stale ⇒ the guard fires. Disabling the filter fails this with both venues present in sources.

Lint updated for the extra guarded aggregate, and it still pins the bound to exactly one site.

Task record and the two runbook steps this incident produced are in #239.

…viving

The unconditional form blanked sources on 52% of the table to prevent
zero evictions. The defect it guards - a stale venue outvoting a live one
in the unweighted 5.5 median - needs a live venue to victimise, so the
guard now fires only when one survives.

Measured before applying this time, both variants over the same live data
(4152 assets): zero_but_vwap_ok 30->0, zero_price_usd 868->368, and
empty_sources 840->368. Every metric improves. empty_sources,
zero_price_usd and zero_vwap all land on 368 exactly - an asset has a
price, sources and a vwap, or none of the three.

Both arms pinned by fixtures and proven non-vacuous: disabling the filter
fails MIX, making it unconditional fails STA with sources={}.
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