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_reasonnames it andyield_sincesays 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_blockis 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_frontiercarries 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
| Class | Surfaces | Typical age (median) | Promise | Target |
|---|---|---|---|---|
| On-chain ingestion | chain.trades | 6 min | ≤ 15 min | 99.5% of the time |
| Realtime P&L | pnl.realized, pnl.resolved, pnl.skill, pnl.unrealized | 39 s – 44 min | ≤ 5 h outside the nightly recompute | 99.5% of the time |
| Internal pipeline | chain.resolutions, markets.tokenmap | 5 min – 31 min | ≤ 2 h outside the nightly recompute | 75.0% of the time · provisional |
| Batch metrics | pnl.baseline, metrics.lifetime, metrics.24h, metrics.7d, metrics.30d, metrics.90d | 12 h – 16 h | ≤ 36 h | 99.0% of the time · provisional |
| Exchange observations | mids, markets.meta | 12 s – 5 min | ≤ 45 min | 99.0% of the time |
| Prediction slots | predictions | 10 min | ≤ 45 min | 99.5% of the time |
| Ranks and percentiles | ranks.lifetime, ranks.24h, ranks.7d, ranks.30d, ranks.90d | 3 h – 4 h | ≤ 16 h | 99.0% of the time · provisional |
Every surface
Measured 2026-09-01 → 2026-09-15 (5-minute samples).
| Surface | Anchor | What it is | Stamped by | Budget | Nightly pause (reason; at most) | Target | Measured |
|---|---|---|---|---|---|---|---|
chain.trades | block | Raw on-chain trades | exchange_trades_backfill, indexer_catchup_monitor | 15 min | — | 99.5% | 99.7% (p50 6 min) |
pnl.realized | block | Realized P&L (per-wallet) | pnl_trade_handler, position_ledger_batch, wallet_token_agg_build | 5 h | the position ledger recompute, the nightly metrics chain; up to 7 h | 99.5% | 99.9% (p50 4 min) |
chain.resolutions | block | On-chain resolution completeness (attested) | resolution_reconcile | 2 h | — | 99.5% | 100.0% (p50 31 min) |
pnl.resolved | block | Resolution re-marks in P&L | pnl_resolution_handler | 30 min | the position ledger recompute; up to 6 h | 99.5% | 99.8% (p50 39 s) |
pnl.skill | block | Skill counts (brier / resolved tallies) | pnl_skill_handler | 5 h | the position ledger recompute, the nightly metrics recompute; up to 13 h | 99.5% | 99.9% (p50 44 min) |
pnl.baseline | block | P&L baseline (wallet_token_agg + trade cursor) | position_ledger_batch, wallet_token_agg_build | 30 h | — | 99.0% | 100.0% (p50 12 h) · provisional |
pnl.unrealized | time | Unrealized P&L re-mark (mids applied) | pnl_mid_remark | 1 h | the position ledger recompute; up to 6 h | 99.5% | 99.8% (p50 10 min) |
mids | time | CLOB midpoints | open_position_mids, clob_market_subscriber | 10 min | — | 99.0% | 99.2% (p50 12 s) |
markets.meta | time | Market metadata (gamma) | gamma_sync | 45 min | — | 99.5% | 100.0% (p50 5 min) |
markets.tokenmap | time | Derived token map | derived_token_map_load | 1 h | the nightly metrics chain, the position ledger recompute; up to 7 h | 75.0% | 78.5% (p50 5 min) · provisional |
predictions | slot | Market prediction ledger (15-min slots) | market_prediction_snapshot | 45 min | — | 99.5% | 100.0% (p50 10 min) |
metrics.lifetime | block | Lifetime wallet metrics (the board) | metrics_grid_chain | 34 h | — | 99.0% | 99.5% (p50 14 h) · provisional |
metrics.24h | block | Windowed metrics (24h) | windowed_metrics_batch | 36 h | — | 99.0% | 100.0% (p50 15 h) · provisional |
metrics.7d | block | Windowed metrics (7d) | windowed_metrics_batch | 36 h | — | 99.0% | 100.0% (p50 16 h) · provisional |
metrics.30d | block | Windowed metrics (30d) | windowed_metrics_batch | 36 h | — | 99.0% | 100.0% (p50 13 h) · provisional |
metrics.90d | block | Windowed metrics (90d) | windowed_metrics_batch | 36 h | — | 99.0% | 100.0% (p50 13 h) · provisional |
ranks.lifetime | cohort (of metrics.lifetime) | Percentile ranks (lifetime) | percentile_rank_recompute, metrics_grid_chain | 16 h | — | 99.0% | 100.0% (p50 3 h) · provisional |
ranks.24h | cohort (of metrics.24h) | Percentile ranks (24h) | percentile_rank_recompute, windowed_metrics_batch | 16 h | — | 99.0% | 99.5% (p50 4 h) · provisional |
ranks.7d | cohort (of metrics.7d) | Percentile ranks (7d) | percentile_rank_recompute, windowed_metrics_batch | 16 h | — | 99.0% | 99.3% (p50 4 h) · provisional |
ranks.30d | cohort (of metrics.30d) | Percentile ranks (30d) | percentile_rank_recompute, windowed_metrics_batch | 16 h | — | 99.0% | 100.0% (p50 3 h) · provisional |
ranks.90d | cohort (of metrics.90d) | Percentile ranks (90d) | percentile_rank_recompute, windowed_metrics_batch | 16 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.