feat(0135): publish the latest priced close in current_prices - #228
Conversation
Both argMax sites in current.sql now skip un-enriched candles (argMaxIf close_usd > 0): price_usd trades up to one enrichment cycle of staleness for the previous permanent zero, and a source with an un-enriched tip stays in sources and the vwap weighting at its latest priced close. The src_price > 0 filter becomes an explicit no-priced- candle rule. Fixture 7 now asserts the contract instead of pinning the bug; docs state the semantics in 4.2.
Review of the first cut found the unbounded carry unsafe: a chronically unpriced venue kept voting in the 5.5 median (demonstrated case: the only live venue evicted by two stale ones) and price_usd could certify a 24h-old close while updated_at read fresh. Both sites now carry only while the newest priced candle is within 2h of the newest candle. ref_7d took the oldest close available, so a freshly-listed asset published a short move labelled 7-day - now the [7d, 5d] band. xlm_usd uses the same argMaxIf idiom. Coverage for the shapes that had none: over-bound asset (the only test of the load-bearing 7d numerator guard), single-source carry, mask arming over a carried price, market_cap against a seeded supply. New static lint enforces the contract in CI. views.sql sentinel table, the 0072 runbook, dto.rs OpenAPI descriptions and 4.2 all synced.
Review findingsReviewed the full diff, read Findings 1, 2 and 3 share a root: the docs assert a freshness guarantee in three places that the SQL does not actually provide. 🔴 1. HIGH —
|
Runbook: the post-deploy check is back to investigate-not-abort. Two benign causes of a zero survive 0135 - legs enrichment never reaches, and lag beyond the carry bound, measured at ~30h on the USDT leg (0204) with the pivot having priced zero rows to date (0212) - so gating on it would fail a healthy deploy, which this same file records happening three times before. ref_7d: the comment claimed the band removes the mislabelled span; it only bounds it to ~28%, and the narrowing is a deliberate scope addition - both now stated. New fixture 13 pins the recent edge: its only 1h baseline sits at 4d, and without the cutoff the row publishes a 4-day move as change_7d_pct (verified: +100 without, sentinel with). dto.rs and views.sql header: the carry bound limits how far valuation may lag the newest candle, NOT the age of the published close - an asset that stopped trading publishes its last priced close, and updated_at cannot see that.
…rice Settled with okarcz. price_usd goes back to a plain argMaxIf: a stale headline price for an asset that stopped trading was never this task's bug (pre-0135 argMax published the same close), and blanking it costs more than it buys - 1,091 of 4,444 prod assets (24.5%) already publish a hard zero, and a consumer cannot separate 'worthless' from 'unknown'. The bound survives in per_source, where the actual regression was: a dead venue voting in the unweighted 5.5 median can evict the one live venue. Its reference moves from max(timestamp) - which spans quote legs enrichment can never price, so it advances forever - to now(). The 2h comes from the enrichment schedule, not from an observed lag; the pipeline has been failing on every run for ~2 days (0215). Lint now pins the bound to exactly one site. Fixture 10 flips to asserting the asymmetry (price published, venue dropped); the change_7d numerator guard moves to asset 6, the only shape that still reaches it. Contracts and the runbook follow, and 0216 carries the age column.
Summary
argMaxIf(close_usd, timestamp, close_usd > 0)on both aggregation sites incurrent.sql—unfiltered.price_usdandper_source.src_price.price_usdbecomes the latest priced close: up to one enrichment cycle of staleness (~25 min avg) instead of a permanent zero — production publishes the"0"stub on 88 of the top-200 volume assets today, XLM and EURC included. A remaining0now means exactly "no USD-priceable trade in the 24 h window".price_xlmandmarket_cap_usdstop collapsing with it.sourcesand in thevwap_24hweighting at its latest priced close; thesrc_price > 0filter is now an explicit no-priced-candle-in-window rule instead of an enrichment-timing side effect.current_mv_it.rsfixture 7 rewritten from pinning the bug to asserting the contract (price 1.90, change −5%/+90%, vwap weighs both venues, price_xlm 3.8) — 3/3 green on the 26.3.10.60 pin, with the pre-guard −100% control kept so the fixture cannot pass vacuously. §4.2 documents the semantics.current.sql(self-DROPs, TO table keeps serving during the ~1-min gap); no backfill —current_pricesfully recomputes each minute. Post-deploy gate:zero_but_vwap_ok = 0and the 0120 conformance suite's price-sentinel checks going green (42 of its 55 failures are this defect family). The task's original outlier question (failure mode 1) stays open and is deliberately not touched here.