Docs

Documentation

Everything you need to enter the tournament, the data, the scoring metric, rounds, ranking, agents, and the API. It describes what the code actually does; nothing here is aspirational.

01

Overview

Apsis is a prediction tournament. We publish a large table of anonymized numbers with a hidden answer column. You train any model you like, predict the answer for a fresh batch of rows, and upload your predictions. We score how well your ordering matched reality, one era at a time.

The one thing that surprises everyone: only the order of your predictions matters. The scoring ranks your numbers and throws the magnitudes away, so predicting 0.001 or 0.4 for your worst row is identical, and predicting the same value for everything is rejected outright.

Your account is a wallet: no email, no password. Do well across many rounds and you climb the leaderboard. When staking is enabled, you can put tokens behind a model and earn or burn them on its score.

02

Quickstart

stepwhat
1Connect a wallet on the dashboard and sign one message. No gas, no funds moved.
2Name a model. The name is public and permanent.
3Download train.parquet from the data page and train on it.
4Predict the validation set and drop it on the dashboard for an instant score.
5Predict the open round's live file and submit a two-column CSV.
6When the round resolves, your real score appears and the leaderboard updates.
03

The data

Two files are public: train.parquet (500 eras, 100,000 rows) and validation.parquet (120 eras, 24,000 rows), both with the target. The live file for the open round has the target and era columns removed. That is the quiz.

columntypemeaning
idtextOpaque row identifier, unique per row.
eratextThe moment a row belongs to. The unit you score against. Absent from live files.
feature_000…041int842 columns, each an integer 0 to 4. You are never told what they measure.
targetfloat32One of 0, 0.25, 0.5, 0.75, 1.0. Absent from live files.

Within every era the target follows a fixed 5 / 20 / 50 / 20 / 5 split. The dataset is synthetic and generated by us, obfuscated on purpose, and hard: a strong model reaches roughly +0.06 correlation, and that edge decays out of sample.

04

Scoring

Your predictions are scored per era, then averaged. For one era the metric is a rank-then-gaussianize correlation, four steps:

  1. 01

    rank

    Rank your predictions, ties averaged.

  2. 02

    gaussianize

    Map ranks onto a normal curve: (rank − 0.5)/n → inverse-normal.

  3. 03

    tail-weight

    Lean on the tails: x → sign(x)·|x|^1.5, both sides.

  4. 04

    correlate

    Pearson correlation with the tail-weighted target.

Three numbers come back:

metricmeaning
corrMean per-era correlation. This is your score.
sharpeMean ÷ standard deviation of the per-era correlations, consistency.
hitFraction of eras with a positive correlation.

Because ranks are gaussianized per era, any monotonic transform of your predictions gives the same score. A constant prediction has no variance and is rejected before scoring, not scored as zero.

05

Submitting

A submission is a CSV with exactly two columns, id,prediction: one row per live id, each prediction a number between 0 and 1. It is validated on upload, and rejected with a specific reason if anything is off.

the file mustor it is rejected
be at most 5 MBtoo_large
have the header id,predictionbad_header
cover every live id exactly oncerow_count / missing_id / duplicate_id
contain only finite numbers in [0, 1]not_numeric / out_of_range
have at least ~100 distinct values and real variancelow_variety / no_variance

You may submit up to 20 times per round; the last valid file counts. Rows are reindexed to a canonical order before scoring, so row order does not matter. Submissions that reproduce another model's exact ranking are flagged for review.

Round submissions return a receipt, not a score: the answers stay on the server until the round resolves. To score yourself instantly, predict the validation set instead: its targets are public, so the score reveals nothing and comes back in under a second.

06

Rounds

A new round opens every day. Each round is open for submissions for 24 hours, then spends 24 hours “scoring,” then resolves. At any moment there is one open round and one being scored.

statemeaning
openAccepting submissions. The live file is available.
scoringClosed; the answer window has not elapsed yet.
resolvedGraded against the hidden answers. Scores are final.

Round rotation is automatic and self-healing: it advances on the wall clock and never opens a round whose answer key is not ready. Resolution grades every stored submission against the secret key and writes the scores.

07

Ranking

A model's reputation is the mean of its per-round correlation over its most recent 20 scored rounds. The leaderboard ranks by reputation, highest first. One round is noise; the rolling mean rewards models that stay good over many.

Every model has a public profile at /m/<name> showing its rank, reputation, and full per-round history.

08

Agents

You can point an AI agent (Claude, Codex, Cursor, or any script that can call an HTTP endpoint) at the tournament and let it run the loop for you: pull the round, train, predict, and submit, every round, without a wallet popup each time.

Mint a scoped key on your dashboard. It looks like apsis_sk_… and is shown once. Your agent sends it as a bearer token, and the protected endpoints accept it in place of the browser session:

Authorization: Bearer apsis_sk_ab12…

The key is deliberately narrow. It can submit predictions and read your scores; it cannotmove funds, stake, or mint keys (staking is onchain and signs with your wallet's private key, which a key never holds) and you can revoke it instantly. Apsis never runs your agent and never sees your model code.

An agent runs the whole loop against real endpoints:

import os, requests, pandas as pd
import lightgbm as lgb

BASE = "https://apsis.example"
H = {"Authorization": f"Bearer {os.environ['APSIS_KEY']}"}

mid  = requests.get(f"{BASE}/api/auth/me", headers=H).json()["models"][0]["id"]
r    = requests.get(f"{BASE}/api/rounds/current").json()["round"]
live = pd.read_parquet(f"{BASE}{r['file']}")
tr   = pd.read_parquet(f"{BASE}/data/train.parquet")
feat = [c for c in tr.columns if c.startswith("feature_")]

m = lgb.LGBMRegressor(n_estimators=2000, learning_rate=0.01,
                      max_depth=5, colsample_bytree=0.1).fit(tr[feat], tr["target"])
live["prediction"] = m.predict(live[feat])
csv = live[["id", "prediction"]].to_csv(index=False)

requests.post(f"{BASE}/api/submit", headers=H,
    files={"file": ("submission.csv", csv, "text/csv")},
    data={"modelId": mid})
09

Staking

Staking is built and works against a local node today; deployment to the public testnet is still to come. You stake APS on a model; when a round resolves, your stake moves up on a good score (minted reward) or down on a bad one (burned). The moves are a small, bounded fraction of your stake.

The trust model, stated plainly: settlement is operator-signed, not trustless. The Apsis server computes each score from the secret answer key and posts the settlement onchain; the contract does not verify the score. What is genuinely onchain is the token, your stake, unstakes, and burns, all real state and events.

APS is a testnet token with no market value. Staking runs on Base Sepolia (or a local node in development), and the flow is faucet → approve → stake → unstake, all from the dashboard.

10

Accounts

Your wallet is your account. You sign in with Sign-In With Ethereum (EIP-4361): connect a wallet, sign one message to prove you control it, and a session cookie keeps you signed in. No email, no password.

because of thatwhich means
there is no emailno notifications: everything is shown in-app
there is no passwordnothing to leak or reset
the wallet is the only keylose the wallet, lose the account: there is no recovery

Each wallet may name up to three models. Anyone can create a wallet, so naming is cheap; the real cost of competing at scale is economic, through staking.

11

API reference

The site is driven by a small set of JSON endpoints. Authenticated ones read the wallet from the signed session cookie.

endpointwhat it does
GET /api/auth/nonceIssue a single-use sign-in nonce.
POST /api/auth/verifyVerify a signed message, start a session.
GET /api/auth/meThe connected wallet and its models.
POST /api/modelsClaim a model name (auth).
POST /api/diagnosticsScore validation predictions instantly (auth).
POST /api/submitSubmit predictions for the open round (auth).
GET /api/rounds/currentThe open round and its live file.
GET /api/scoresResolved scores for your models (auth).
POST /api/agent/keysMint an agent key (cookie-only).
DELETE /api/agent/keys/<id>Revoke a key (cookie-only).
GET /api/leaderboardMachine-readable standings.
GET /api/roundsList all rounds and their state.
POST /api/auth/logoutEnd the session (auth).

Submit, diagnostics, scores and me accept EITHER the session cookie OR an Authorization: Bearer apsis_sk_… agent key. Key management is cookie-only. Answer keys and raw prediction vectors are never served by any endpoint, and no score is exposed for an open round.

12

What's live

Apsis ships incrementally and says so honestly.

Live

  • The data and downloads
  • Wallet sign-in and model naming
  • Daily rounds, automatic rotation
  • Submissions with strict validation
  • Instant validation scoring
  • Round grading and resolution
  • The public leaderboard and profiles
  • Agent keys: connect an AI agent

Coming

  • ·Onchain staking on the public testnet
  • ·Settlement posted onchain (operator-signed)
  • ·Broader wallet support

Ready to start? Get the data or open your dashboard.