Skip to content

Rates Engine v0.5.0-rc.56

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 19 May 10:42
· 718 commits to main since this release

[v0.5.0-rc.56] — 2026-05-19

Fixed

  • /v1/diagnostics/ingestion entries is no longer silently 0 for
    every source.
    The fxHistoryReader adapter
    (cmd/ratesengine-api) wraps *timescale.Store and forwards the
    coverage-reader methods (FXCoverageStats, CAGGCoverageStats)
    but was missing a SourceEntryCounts delegate. So the
    request-time type assertion s.fxHistory.(SourceEntryCountReader)
    in fillIngestionEntryCounts failed closed and returned silently,
    leaving entryCounts nil → entries: 0 for every source
    (sdex included) even though source_entry_counts (migration 0035,
    maintained live by the indexer and reconciled by
    seed-entry-counts) was fully populated (sdex 2.7 B, …). Shipped
    missing in rc.55, so the status page showed all protocols at 0
    entries. Added the one-line delegate (same precedent as the two
    sibling forwards, which document this exact "renders empty"
    failure mode) and made the !ok path Warn-log instead of failing
    invisibly so this wiring-regression class can't recur unnoticed.
  • extendWithLiveTail now bridges interior sub-tip coverage gaps,
    fixing the ~96% (Soroban) / 99.5% (SDEX) density cap.
    The
    live-ingest tail was credited only above the top of the merged
    backfill union. When a disjoint high gap-backfill island (e.g. the
    62,606,296–62,613,951 gap re-fill) fragmented the union, a
    ~309,700-ledger interior span [62,296,595→62,606,296] — fully
    populated by gap-free live ingest (22.8 M trades verified on r1) —
    got zero credit, capping density at ~96% Soroban / 99.5% SDEX
    (the same absolute hole over different genesis denominators).
    The tail now also fills any gap between two merged backfill
    intervals whose upper neighbour starts at/below the live cursor:
    bracketed by backfill coverage on both sides and wholly within the
    gap-free live span (ADR-0017 archivecompleteness), so live ingest
    provably walked it. The honest guards are retained — the
    [genesis, firstBackfillStart] lower boundary is never an
    adjacent-pair interior gap so it stays uncovered (a
    never-backfilled-low source still reads honestly, e.g. band's
    pre-deploy history under the new #10 genesis), a never-backfilled
    source stays 0%, and nothing is credited above the live cursor.
  • sourceGenesisLedger now holds exact first-WASM-deploy ledgers,
    not rounded deploy-era constants.
    The per-source genesis is the
    denominator of backfill_coverage[].density_pct, so a rounded
    value was a two-way correctness bug under the "every source to
    100%" invariant: rounded before the real deploy padded the
    denominator with pre-existence ledgers (100% mathematically
    unreachable), rounded after it silently hid genuine
    early-history gaps (e.g. band const 53_500_000 vs real first
    deploy 50_842_736 — ~2.66M ledgers of history structurally
    invisible to the metric; reflector-fx const 51_000_000 vs
    real 56_733_481 — ~5.7M phantom pre-existence ledgers). All
    on-chain sources now use the MIN create_contract ledger across
    every routed contract (factory + instances, upgrade-in-place
    aware), sourced from the per-source WASM-audit walk evidence
    (docs/operations/wasm-audits/, r1-walk-2026-05-01); the doc
    contract flips from "approx slack is fine" to "exact, zero
    slack". defindex stays explicitly provisional pending its
    per-WASM walk (BackfillSafe=false; audit in_progress).
  • Migration ownership invariant documented (migrations/README.md
    Rule 7).
    source_entry_counts (migration 0035) was applied
    manually as the postgres superuser on r1, leaving it
    superuser-owned; the rc.55 indexer's always-on entry tally and
    ratesengine-ops seed-entry-counts then hit permission denied for table source_entry_counts (42501). Root cause is operational,
    not schema: ratesengine-migrate runs as the ratesengine app
    role (RATESENGINE_POSTGRES_DSN), so on correctly-applied deploys
    (R2/R3/fresh) the table is app-owned by construction and needs no
    GRANT — only r1's manual-as-superuser application was the anomaly.
    Hot-fixed in place with ALTER TABLE source_entry_counts OWNER TO ratesengine (canonical shape, matches trades); a follow-up
    GRANT migration was deliberately not added (it would error when
    run as the app role against a superuser-owned object and is a
    no-op otherwise — the fix is "apply as the app role", now a
    documented Rule).