A pre-registered, paper-only test of whether an LLM can out-forecast the market's own price. Nothing here places real orders.
| Category | n | Brier ours | Brier mkt | edge | hit |
|---|---|---|---|---|---|
| Climate and Weather | 346 | 0.260 | 0.141 | -0.119 | 60% |
| Commodities | 289 | 0.216 | 0.183 | -0.033 | 64% |
| Economics | 198 | 0.224 | 0.099 | -0.125 | 69% |
| Financials | 64 | 0.215 | 0.196 | -0.018 | 59% |
| Politics | 98 | 0.180 | 0.060 | -0.120 | 73% |
| Science and Technology | 35 | 0.183 | 0.061 | -0.122 | 66% |
| World | 2 | 0.041 | 0.000 | -0.041 | 100% |
| Context kind | n | Brier ours | Brier mkt | edge | hit |
|---|---|---|---|---|---|
| fred | 87 | 0.194 | 0.121 | -0.074 | 71% |
| news | 171 | 0.196 | 0.078 | -0.118 | 72% |
| none | 166 | 0.239 | 0.139 | -0.101 | 58% |
| nws | 323 | 0.257 | 0.135 | -0.122 | 61% |
| prices | 285 | 0.216 | 0.180 | -0.035 | 64% |
| Band | n | Said % | Actual % |
|---|---|---|---|
| 0.5-0.6 | 203 | 53% | 47% |
| 0.6-0.7 | 210 | 63% | 58% |
| 0.7-0.8 | 172 | 74% | 66% |
| 0.8-0.9 | 214 | 84% | 63% |
| 0.9-1.0 | 233 | 94% | 84% |
n_trades=527 total_pnl=$-2540.04 total_fees=$1157.62 win_rate=27%
| Ticker | Category | Our p | Mkt p | Close time | Rationale |
|---|---|---|---|---|---|
| KXLOWTCHI-26SEP26-T55 | Climate and Weather | 0.25 | 0.01 | 2026-09-27T06:00:00Z | NWS lows 55F overnight and Saturday night; min above 55 unlikely. |
| KXLOWTAUS-26SEP26-B66.5 | Climate and Weather | 0.02 | 0.03 | 2026-09-27T06:00:00Z | NWS lows 74-75F; 66-67 very unlikely. |
| KXLOWTAUS-26SEP26-T66 | Climate and Weather | 0.01 | 0.02 | 2026-09-27T06:00:00Z | NWS lows 74-75F; below 66 very unlikely. |
| KXHIGHTSATX-26SEP26-B94.5 | Climate and Weather | 0.28 | 0.59 | 2026-09-27T06:00:00Z | NWS Saturday high 93F, mostly cloudy; 94-95 plausible. |
| KXHIGHMIA-26SEP26-B87.5 | Climate and Weather | 0.40 | 0.24 | 2026-09-27T05:00:00Z | NWS Saturday high 87F, sunny then showers. |
| KXLOWTOKC-26SEP26-T70 | Climate and Weather | 0.45 | 0.01 | 2026-09-27T06:00:00Z | NWS lows 71F overnight, 70F Saturday night; storms may cool. |
| KXLOWTMIN-26SEP26-T58 | Climate and Weather | 0.15 | 0.01 | 2026-09-27T06:00:00Z | NWS lows 58F and 56F with rain; minimum above 58 unlikely. |
| KXLOWTDAL-26SEP26-T73 | Climate and Weather | 0.40 | 0.01 | 2026-09-27T06:00:00Z | NWS overnight low 73F, Saturday night 75F; min near threshold. |
| KXHIGHPHIL-26SEP26-B67.5 | Climate and Weather | 0.04 | 0.92 | 2026-09-27T05:00:00Z | NWS Saturday high 63F with rain showers. |
| KXHIGHPHIL-26SEP26-T68 | Climate and Weather | 0.02 | 0.06 | 2026-09-27T05:00:00Z | NWS high 63F with rain; 69+ very unlikely. |
| KXHIGHNY-26SEP26-B62.5 | Climate and Weather | 0.35 | 0.27 | 2026-09-27T05:00:00Z | NWS Saturday high 63F, light rain. |
| KXHIGHNY-26SEP26-T62 | Climate and Weather | 0.35 | 0.74 | 2026-09-27T05:00:00Z | NWS high 63F; rain may hold it to 61 or below. |
| KXHIGHMIA-26SEP26-B89.5 | Climate and Weather | 0.15 | 0.54 | 2026-09-27T05:00:00Z | NWS high 87F; 89-90 needs upside miss. |
| KXHIGHTBOS-26SEP26-B61.5 | Climate and Weather | 0.30 | 0.84 | 2026-09-27T05:00:00Z | NWS Saturday high 60F, patchy fog; 61-62 plausible upside. |
| KXHIGHTBOS-26SEP26-B63.5 | Climate and Weather | 0.08 | 0.15 | 2026-09-27T05:00:00Z | NWS high 60F; 63-64 needs notable upside miss. |
| KXHIGHTATL-26SEP26-B81.5 | Climate and Weather | 0.42 | 0.62 | 2026-09-27T05:00:00Z | NWS Saturday high 81F, sunny. |
| KXHIGHTATL-26SEP26-B83.5 | Climate and Weather | 0.18 | 0.23 | 2026-09-27T05:00:00Z | NWS high 81F; 83-84 needs 2-3F upside miss. |
| KXHIGHTTTN-26SEP26-B60.5 | Climate and Weather | 0.28 | 0.01 | 2026-09-27T05:00:00Z | No Trenton forecast; nearby NYC/Philly highs 63F with rain. |
| KXHIGHTTTN-26SEP26-B62.5 | Climate and Weather | 0.32 | 0.01 | 2026-09-27T05:00:00Z | Nearby NYC/Philly highs forecast 63F; rainy day. |
| KXHIGHTDC-26SEP26-B67.5 | Climate and Weather | 0.33 | 0.33 | 2026-09-27T05:00:00Z | NWS Saturday high 68F with light rain likely. |
| KXHIGHTDC-26SEP26-T67 | Climate and Weather | 0.35 | 0.27 | 2026-09-27T05:00:00Z | NWS high 68F but rain risk could hold it below 67. |
| KXRAIN-26SEP26-EWR | Climate and Weather | 0.92 | 0.99 | 2026-09-27T05:00:00Z | NYC area light rain likely overnight and Saturday. |
| KXLOWTPHIL-26SEP26-T59 | Climate and Weather | 0.06 | 0.01 | 2026-09-27T05:00:00Z | NWS lows 57F overnight and Saturday night; min above 59 unlikely. |
| KXLOWTNYC-26SEP26-T54 | Climate and Weather | 0.06 | 0.16 | 2026-09-27T05:00:00Z | NWS overnight low 56F, rain keeps temps steady; below 54 unlikely. |
| KXLOWTNYC-26SEP26-B56.5 | Climate and Weather | 0.45 | 0.01 | 2026-09-27T05:00:00Z | NWS overnight low 56F; day minimum likely 55-57. |
| KXLOWTBOS-26SEP26-B58.5 | Climate and Weather | 0.12 | 0.01 | 2026-09-27T05:00:00Z | NWS lows 56-57F; minimum 58-59 less likely. |
| KXTRUMPENDORSEMENTS-26SEP25-A5 | Politics | 0.70 | 0.01 | 2026-09-26T14:00:00Z | Midterm season; Trump usually endorses many candidates weekly. |
| KXTXERCOTPEAKD-26SEP27-T87000 | Economics | 0.01 | 0.01 | 2026-09-27T04:55:00Z | Late-September Saturday peak load well below 87 GW. |
| KXTXERCOTPEAKD-26SEP27-T88000 | Economics | 0.01 | 0.01 | 2026-09-27T04:55:00Z | Late-September Saturday peak load well below 88 GW. |
| KXRAIN-26SEP26-PHIL | Climate and Weather | 0.90 | 0.99 | 2026-09-27T05:00:00Z | NWS shows rain showers Saturday and Saturday night. |
| KXTEMPNYCHS-26SEP2606-T56.99 | Climate and Weather | 0.40 | 0.06 | 2026-09-26T10:00:00Z | NWS overnight low 56F with rain; 6am reading near 56, threshold 57. |
| KXTEMPMIAH-26SEP2606-T73.99 | Climate and Weather | 0.85 | 0.98 | 2026-09-26T10:00:00Z | NWS overnight 75F, mostly clear; 74+ at 6am likely. |
| KXTEMPMIAH-26SEP2606-T75.99 | Climate and Weather | 0.15 | 0.01 | 2026-09-26T10:00:00Z | Overnight forecast 75F; 76+ at 6am needs upside miss. |
| KXEOWEEK-26SEP12-0 | Politics | 0.90 | 0.50 | 2026-09-26T14:00:00Z | Trump almost always signs at least one EO in a given week. |
| KXWTIW-26SEP2514-T109.99 | Commodities | 0.01 | 0.01 | 2026-09-25T18:30:00Z | WTI near 92.87; +18% in hours implausible at 46% vol. |
| KXWTIW-26SEP2514-T85.00 | Commodities | 0.02 | 0.01 | 2026-09-25T18:30:00Z | WTI near 92.87; ~8% drop within hours is roughly 4 sigma. |
| KXWTI-26SEP2514-T92.99 | Commodities | 0.47 | 0.50 | 2026-09-25T18:30:00Z | Latest 92.87 just below threshold; near coin flip with slight edge down. |
| KXWTI-26SEP2514-T92.49 | Commodities | 0.57 | 0.59 | 2026-09-25T18:30:00Z | Latest 92.87 slightly above threshold; modest edge to stay above. |
| Ticker | Our p | Mkt p | Outcome |
|---|---|---|---|
| KXTEMPMIAH-26SEP2506-T75.99 | 0.75 | 0.96 | Yes |
| KXTEMPMIAH-26SEP2506-T76.99 | 0.50 | 0.86 | Yes |
| KXGOLDD-26SEP2417-T4268 | 0.74 | 0.39 | Yes |
| KXBRENTD-26SEP2417-T100 | 0.40 | 0.49 | Yes |
| KXBRENTD-26SEP2417-T100.50 | 0.35 | 0.40 | No |
| KXWTI-26SEP2414-T88.99 | 0.96 | 0.98 | Yes |
| KXCBDECISIONMEXICO-26SEP24-H25P | 0.05 | 0.12 | No |
| KXCBDECISIONMEXICO-26SEP24-C50P | 0.05 | 0.03 | No |
| KXGOLDD-26SEP2417-T4258 | 0.82 | 0.48 | Yes |
| KXJOBLESSCLAIMS-26SEP24-205000 | 0.32 | 0.17 | No |
| KX30YMORTW-26SEP24-T7.08 | 0.15 | 0.01 | No |
| KX30YMORTW-26SEP24-T6.98 | 0.55 | 0.89 | Yes |
| KXWTI-26SEP2414-T90.99 | 0.92 | 0.94 | Yes |
| KXTEMPMIAH-26SEP2406-T70.99 | 0.97 | 0.99 | Yes |
| KXTEMPCHIHS-26SEP2406-T58.99 | 0.62 | 0.90 | Yes |
| KXJOBLESSCLAIMS-26SEP24-215000 | 0.08 | 0.08 | No |
| KXBIGGESTQUAKE-23SEP26-5.2 | 0.80 | 0.98 | Yes |
| KXGOLDD-26SEP2317-T4315 | 0.85 | 0.46 | No |
| KXGOLDD-26SEP2317-T4325 | 0.80 | 0.35 | No |
| KXBRENTD-26SEP2317-T97 | 0.35 | 0.32 | Yes |
# PREREG.md — pre-registration of the gold-standard Kalshi forecaster
**Registered 2026-07-28 (America/Chicago), before any `source='ai'` forecast row exists.**
The git history is the proof: this file is committed at Phase 5, and the first production
(`source='ai'`) forecast is not created until Phase 7, after this commit. Any change to the rules
below requires a dated amendment appended to the "Amendments" section AND the owner's sign-off — the
original rules above the amendment line are never edited in place.
This is a paper-only research instrument. Nothing here places real orders. Educational / hypothetical.
---
## The pre-registered rules (copied verbatim from PLAN.md "LOCKED decisions")
1. **The model never sees the market price** in its prompt. We are testing independent skill;
showing the price lets the model echo the crowd and fakes calibration. Log `mkt_p` separately
at call time. (A later "sees-price" variant may be added as a separate scored segment. Not v1.)
2. **Question selection:** status open, `close_time` ≤ 30 days out, `volume_fp` ≥ 500, bid-ask
spread ≤ $0.10, category in: Economics, Financials, Commodities, Climate and Weather, Politics,
Science and Technology, World. Excluded: Sports, Entertainment, Mentions, Crypto, Elections,
Companies, Social, Health. Max **2 markets per event** (for ladders pick the 2 strikes nearest
$0.50 mid = nearest the money). Max **40 new forecasts per night**.
3. **One forecast per market**, made at first qualifying sighting, never revised. The model may
**skip** any question (no informational basis); skips are logged and cost nothing.
4. **Paper trade rule:** fills at the **ask** (not mid). Buy YES if `our_p − yes_ask − fee(yes_ask)
> 0.02`; buy NO if `(1 − our_p) − no_ask − fee(no_ask) > 0.02`. Kalshi fee per $1 contract:
`fee(p) = ceil_to_cent(0.07 · p · (1 − p))`. Flat $10 notional per trade, max 1 trade per event.
5. **Scoring:** Brier of `our_p` vs Brier of `mkt_p` (mid at call time) on identical resolved sets,
segmented by category and by context kind (fred / nws / prices / news / none), plus calibration
buckets. Voided/unresolvable markets are excluded. Only rows with `source='ai'` count
(`source='dev'` = build-time tests, never scored).
6. **Gates (evaluate at ≥150 resolved AI forecasts):** skill gate = our Brier < market Brier;
money gate = paper P&L > 0 net of fees over ≥100 trades. Both pass → owner may fund a real
bankroll ($500–2k, allowed to go to zero; separate authorization, separate build). Either fails
→ kill, write the post-mortem, keep the track record. Interim peeks fine; no action before n.
7. **Prompt discipline:** `PROMPT_VER` constant logged on every forecast; any prompt change bumps
it. LOUD failures only: a failed/malformed LLM call writes a `runs` row and stderr; **never**
silently fall back (market-radar's silent-fallback bug is the cautionary tale).
---
## Exact prompt text (PROMPT_VER = "v1")
The nightly batched call (`brain.py`, `--model sonnet`) emits ONE prompt built from a fixed
preamble plus one block per question. The preamble is **verbatim**:
> You are a calibrated event forecaster. For each question output a probability 0-1 that it
> resolves YES. You have NO market price and must not guess one - reason only from the evidence
> given. If you have no informational basis, set skip=true (this costs nothing and is better than
> a blind guess). Today is {UTC date} (UTC). Output STRICT JSON ONLY: an object mapping each
> ticker to {"p":<0..1>,"why":"<=20 words","skip":<bool>}. No prose outside the JSON.
Each per-question block that follows the preamble contains ONLY: the ticker, the question title,
its sub-title, its resolution rules, and the Phase-2 context pack (external evidence — FRED / NWS /
prices / news — which is itself price-free by construction; `context.py` contains zero Kalshi price
fields). **No market price, bid, ask, or implied probability is ever placed in the prompt.** This is
enforced structurally: `build_prompt()` is a separate pure function and the price fetch lives in
`_fetch_mid()`; a grep proves the string `_dollars` never appears in the prompt path.
If v1 is ever changed, `PROMPT_VER` is bumped (e.g. "v2") and forecasts made under different
versions are scored as separate segments — v1's track record is never retroactively altered.
---
## Gate arithmetic (exactly what `score.py` computes)
Scored set = resolved `forecasts` rows with `source='ai'`, `outcome ∈ {0,1}` (void `-1` and
unresolved `NULL` excluded), and both `our_p` and `mkt_p` populated.
- `brier_ours = mean((our_p − outcome)²)` over the scored set.
- `brier_mkt = mean((mkt_p − outcome)²)` over the identical set (the crowd's mid at call time).
- `edge = brier_mkt − brier_ours` (positive ⇒ we beat the market; lower Brier is better).
- Paper P&L: over settled `paper_trades` (`pnl` not NULL), `total_pnl = Σ pnl`, `n_trades = count`.
Per-trade P&L (LOCKED #4 `$1`-contract math, `contracts = $10 / entry_p`,
`total_fee = contracts · fee(entry_p)`): WIN `pnl = 10·(1/entry_p − 1) − total_fee`;
LOSS `pnl = −10 − total_fee`; VOID `pnl = 0`.
**Decision (only at `n_resolved ≥ 150`):**
- **skill_gate_pass** ⟺ `n_resolved ≥ 150` AND `brier_ours < brier_mkt`.
- **money_gate_pass** ⟺ `n_trades ≥ 100` AND `total_pnl > 0`.
- **Both pass** → the forecaster has earned a real-bankroll funding decision ($500–2k, may go to
zero; separate authorization + separate build). **Either fails** → kill it, write the post-mortem,
keep the documented track record as the durable asset.
- Before `n_resolved = 150`: interim peeks are allowed but **no action is taken** — `score.py`'s
verdict reads "accruing — N of 150 resolved; no decision yet".
---
## Note on the fee example in PLAN.md
PLAN.md's Phase-4 acceptance line ("fee(0.50) on 20 contracts = $0.70") is an arithmetic slip that
contradicts the LOCKED 0.07 coefficient. The **coefficient is unchanged** (`fee(p) =
ceil_to_cent(0.07·p·(1−p))`, i.e. $0.02/contract at p=0.50). The implemented order fee is
`contracts × fee(entry_p)` = 20 × $0.02 = **$0.40** at the example point. This clarification does not
alter any pre-registered rule; it records the correct arithmetic under the LOCKED formula.
---
## Amendments
(none — the rules above are the original registration. Append dated, owner-signed amendments below
this line; never edit the original rules in place.)