Polyrankdocs

Data freshness

One machine-readable answer to "how fresh is this number?" for every served surface.

Every surface Polyrank serves is stamped with the exact chain block (or observation time) it reflects, in one registry. You never have to memorize per-widget staleness folklore: ask the endpoint, or read the X-Data-As-Of-Block / X-Data-As-Of-Time response headers on the leaderboard, trader, and market rails.

GET /v1/meta/freshness

Anonymous — no API key needed.

curl -s https://api.polyrank.app/v1/meta/freshness | jq '.surfaces[] | {surface, state, age_seconds, state_reason}'
{
  "surfaces": [
    {
      "surface": "pnl.resolved",
      "anchor": "block",
      "label": "Resolution re-marks in P&L",
      "status": "measured",
      "as_of_block": "93863361",
      "as_of_time": "2026-09-16T04:10:02.000Z",
      "age_seconds": 10800,
      "budget_seconds": 1800,
      "slo_class": "realtime",
      "slo_target": 0.995,
      "state": "paused",
      "state_reason": "paused for the position ledger recompute",
      "yield_since": "2026-09-16T04:05:00.000Z",
      "yield_ceiling_seconds": 28800,
      "provisional": null,
      "measured": { "within_slo": 0.9994997498749375, "within_budget": 0.8184092046023012, "p50_seconds": 39, "p99_seconds": 16997, "max_seconds": 22257, "method": "yield_proxy" }
    }
  ],
  "frontier_readable": true,
  "yields_readable": true,
  "slo_classes": [{ "slo_class": "realtime", "label": "Realtime P&L", "budget_seconds": 18000, "slo_target": 0.995, "has_yields": true, "provisional": false, "surfaces": ["pnl.realized", "pnl.resolved", "pnl.skill", "pnl.unrealized"] }],
  "slo_evidence": { "measured_from": "2026-09-01T19:00:00.000Z", "measured_through": "2026-09-15T19:00:00.000Z", "source": "…" },
  "as_of": "2026-09-16T07:10:02.000Z"
}

States

Every measured surface is in exactly one state. The age is always the real age — a state explains a number, it never replaces it.

  • fresh — within its budget.
  • paused — past its budget because its job is deliberately waiting behind a recompute (nightly, or a rare daytime repair: the position ledger, or the metrics chain) that needs the database to itself. state_reason names it and yield_since says when it began. Realtime P&L pauses most mornings (UTC) for a few hours; it resumes on its own the moment the recompute ends. Occasionally a repair run pauses P&L for about 40 minutes during the day; the freshness line keeps showing the real age, and affected wallets show “P&L under review” until it ends.
  • stale — past its budget with no pause to explain it. This is a stall, and it alerts.
  • overrun — paused for longer than any pause we have measured. Also alerts.
  • unmeasured — no stamp yet. Absence never means fresh.

How the promises are set

Budgets and targets come from measurement, never from aspiration: each target is at or below the attainment we actually measured over the evidence window, and every budget change is recorded with its evidence. Surfaces marked provisional are about to change cadence (for example when a nightly job becomes incremental) and will be re-measured after the change. The class promise is always the loosest of its members, so it never promises more than every surface keeps.

The four anchor classes

Not everything can be block-aligned, and pretending otherwise would be its own confusion:

  • block — truth lives on-chain (trades, P&L, positions, resolutions). as_of_block is the exact Polygon block the surface reflects.
  • time — observations that exist only at the moment of capture (CLOB midpoints, market metadata). A mid has no block; a missed observation is gone, not "behind".
  • slot — the prediction ledger's pre-registered 15-minute slots (a design property, not a staleness bug).
  • cohort — ranks and percentiles are anchored to the vintage of the inputs they ranked: input_frontier carries the block of the metric snapshot that was ranked. Recomputing a rank per block is neither possible nor meaningful.

A registered surface with no stamp yet is status: "unmeasured" — absence never means fresh.

The registry

Promises by class

ClassSurfacesTypical age (median)PromiseTarget
On-chain ingestionchain.trades6 min≤ 15 min99.5% of the time
Realtime P&Lpnl.realized, pnl.resolved, pnl.skill, pnl.unrealized39 s – 44 min≤ 5 h outside the nightly recompute99.5% of the time
Internal pipelinechain.resolutions, markets.tokenmap5 min – 31 min≤ 2 h outside the nightly recompute75.0% of the time · provisional
Batch metricspnl.baseline, metrics.lifetime, metrics.24h, metrics.7d, metrics.30d, metrics.90d12 h – 16 h≤ 36 h99.0% of the time · provisional
Exchange observationsmids, markets.meta12 s – 5 min≤ 45 min99.0% of the time
Prediction slotspredictions10 min≤ 45 min99.5% of the time
Ranks and percentilesranks.lifetime, ranks.24h, ranks.7d, ranks.30d, ranks.90d3 h – 4 h≤ 16 h99.0% of the time · provisional

Every surface

Measured 2026-09-01 → 2026-09-15 (5-minute samples).

SurfaceAnchorWhat it isStamped byBudgetNightly pause (reason; at most)TargetMeasured
chain.tradesblockRaw on-chain tradesexchange_trades_backfill, indexer_catchup_monitor15 min—99.5%99.7% (p50 6 min)
pnl.realizedblockRealized P&L (per-wallet)pnl_trade_handler, position_ledger_batch, wallet_token_agg_build5 hthe position ledger recompute, the nightly metrics chain; up to 7 h99.5%99.9% (p50 4 min)
chain.resolutionsblockOn-chain resolution completeness (attested)resolution_reconcile2 h—99.5%100.0% (p50 31 min)
pnl.resolvedblockResolution re-marks in P&Lpnl_resolution_handler30 minthe position ledger recompute; up to 6 h99.5%99.8% (p50 39 s)
pnl.skillblockSkill counts (brier / resolved tallies)pnl_skill_handler5 hthe position ledger recompute, the nightly metrics recompute; up to 13 h99.5%99.9% (p50 44 min)
pnl.baselineblockP&L baseline (wallet_token_agg + trade cursor)position_ledger_batch, wallet_token_agg_build30 h—99.0%100.0% (p50 12 h) · provisional
pnl.unrealizedtimeUnrealized P&L re-mark (mids applied)pnl_mid_remark1 hthe position ledger recompute; up to 6 h99.5%99.8% (p50 10 min)
midstimeCLOB midpointsopen_position_mids, clob_market_subscriber10 min—99.0%99.2% (p50 12 s)
markets.metatimeMarket metadata (gamma)gamma_sync45 min—99.5%100.0% (p50 5 min)
markets.tokenmaptimeDerived token mapderived_token_map_load1 hthe nightly metrics chain, the position ledger recompute; up to 7 h75.0%78.5% (p50 5 min) · provisional
predictionsslotMarket prediction ledger (15-min slots)market_prediction_snapshot45 min—99.5%100.0% (p50 10 min)
metrics.lifetimeblockLifetime wallet metrics (the board)metrics_grid_chain34 h—99.0%99.5% (p50 14 h) · provisional
metrics.24hblockWindowed metrics (24h)windowed_metrics_batch36 h—99.0%100.0% (p50 15 h) · provisional
metrics.7dblockWindowed metrics (7d)windowed_metrics_batch36 h—99.0%100.0% (p50 16 h) · provisional
metrics.30dblockWindowed metrics (30d)windowed_metrics_batch36 h—99.0%100.0% (p50 13 h) · provisional
metrics.90dblockWindowed metrics (90d)windowed_metrics_batch36 h—99.0%100.0% (p50 13 h) · provisional
ranks.lifetimecohort (of metrics.lifetime)Percentile ranks (lifetime)percentile_rank_recompute, metrics_grid_chain16 h—99.0%100.0% (p50 3 h) · provisional
ranks.24hcohort (of metrics.24h)Percentile ranks (24h)percentile_rank_recompute, windowed_metrics_batch16 h—99.0%99.5% (p50 4 h) · provisional
ranks.7dcohort (of metrics.7d)Percentile ranks (7d)percentile_rank_recompute, windowed_metrics_batch16 h—99.0%99.3% (p50 4 h) · provisional
ranks.30dcohort (of metrics.30d)Percentile ranks (30d)percentile_rank_recompute, windowed_metrics_batch16 h—99.0%100.0% (p50 3 h) · provisional
ranks.90dcohort (of metrics.90d)Percentile ranks (90d)percentile_rank_recompute, windowed_metrics_batch16 h—99.0%100.0% (p50 3 h) · provisional

Budgets tighten by measurement, never by aspiration

The tables above are generated from the same registry and measured evidence the API serves. As the incremental stages of the block-frontier plan land, provisional budgets are re-measured and tighten to the new reality — the endpoint is always the source of truth for what is promised today.

On this page