01Start Here

What NED is, in five lines — and how to use this guide.

NED in five lines:

  1. NED is a fleet of trading bots on Polymarket, a prediction market. Each bot must prove its edge on honest ledgers before any real money.
  2. Everything is PAPER: real_capital = NO fleet-wide until a bot's canonical gate is met AND the owner flips the switches.
  3. The repo is the shared brain. Your agent (Claude Code / Antigravity) reads AGENTS.md and already knows the project — you supply the owner's operating style.
  4. Your lane as a friend is Togi, the sports bot. One sport = one new file, found automatically, zero shared edits — two friends literally cannot merge-conflict.
  5. Every edge claim goes through the same loop: measure it first, judge it on the honest lower bound, and let the owner promote. The graveyard of killed ideas is half the moat.

How to use this guide

  • Read 02 Prompting first — the mindset, the shared vocabulary, and the phrase-book. That's how you talk to your agent like the owner does.
  • 04 The Edge Loop and 05 Case Studies teach how the owner actually works. The method behind every verdict, told through the real studies (real numbers, no invention).
  • 06 The Trap List — each trap has a body attached. Read it before testing any idea.
  • 07 The Two Seats and 08 Per-Sport Recipe are the operational how-to: how we ship without stepping on each other, and exactly what a sport file is.
  • 09 Ground Rules is the constitution recap — everyone inherits it automatically via AGENTS.md.
  • 03 Vocabulary is a searchable reference — come back to it whenever a term is unfamiliar.
  • 10 Owner's Data Points is the owner's map of what matters in each sport and where to look.

GitHub & the context files — if you've never collaborated on a repo

GitHub is where the project's shared copy lives. It holds the source code and nothing else. No money data ever goes there — the live ledgers, the bankroll, and every key stay on the owner's machines and are excluded from git. Your copy starts with empty ledgers. That's correct, not broken.

Three words cover almost everything you'll do:

  • CLONE — download your own full copy of the project to your machine.
  • BRANCH — a private working line inside your copy, so your changes touch nothing shared until they're ready.
  • PR (pull request) — "here's my change, please review it." The owner reviews and folds it into the main project.

The context files. The repo carries its own memory. These files teach your agent everything about the project:

FileWhat it is
AGENTS.mdthe rulebook every agent reads first — CLAUDE.md and GEMINI.md are the same file
BUILD_STATE.mdwhat's been built + the latest verdicts — read the top checkpoint
NED_CONTEXT.mdthe architecture — what each bot is and how the pieces fit
PROMPTING_GUIDE.md
EDGE_PLAYBOOK.md
FRIENDS_COLLAB.md
the three guides this page packages — prompting style, edge method, the collab model
docs/togi-onboarding.mdthe sport how-to — exactly how to add your one sport file
docs/SPORT_DATA_POINTS.mdthe owner's per-sport data-point map (rendered as section 10 here)
docs/FREE_DATA_SOURCES.mdevery free data source per sport, verified + point-in-time graded — read before wiring any feed

The point: you don't have to teach your agent the project — point it at these files and it knows.

First thing you ever tell your agent: "Read AGENTS.md, BUILD_STATE.md (the top checkpoint), and NEXT_SESSION_PLAN.md before you touch anything. Then [your task]." The agent absorbs the fleet, the rules, and where we are — then you prompt it in the style this guide teaches.

02Prompting — Talk Like the Owner

The repo teaches your agent the project. This page teaches you the owner's operating style: the mindset, the phrases, and the shape of a good prompt.

The one-paragraph version

Talk to the agent like a sharp, trusting boss who has zero tolerance for self-deception. Point it at one thing, hand it the wheel, name the guardrails, and demand proof. You don't need to be formal or write clean prose. Messy, conversational, even voice-to-text rambling is fine — as long as every prompt lands three things: the goal, the guardrails (what must never happen), and "verify it / prove it / tell me honestly." That's the whole game.

The mindset — six values in every prompt

  1. Honesty over hope. Never accept a pretty number. "Make sure it's exactly what would happen on Polymarket." "Small n is honest, not flattered." If tests fail, you want to hear it. A result you can't trust is worse than no result.
  2. Edge before scale. Prove the edge first. Don't add bots or size to paper over a weak one. One lane at a time — build it out fully, watch it, then move on. Scale = more proven lanes, not a bigger bet.
  3. Anti-overfit is religion. A locked strategy is never re-tuned ("just one more filter" is banned). You measure a signal before you wire it live, and everything faces an out-of-sample gate — a test on data the idea never saw. A loop that optimizes on its own data just finds "prettier noise faster."
  4. Delegate, then verify. "You've got the wheel — go." But in the same breath: test it, adversarially review it, don't tell me it's done until it's proven. Trust is high; the bar for "done" is higher.
  5. Gates, not vibes. Nothing goes real until it clears a gate — a big enough sample n, a Wilson lower bound above breakeven. real_capital = NO until the math says otherwise. Report the claim as the lower bound, not the point estimate.
  6. Speed is an edge. Get information as fast as possible — faster feeds, warmer connections, lower latency — across every bot.

The owner's phrase-book — real phrases, steal them

PhraseWhat it signalsWhen to use
"You've got the wheel — go."full delegation; make the calls, don't ask permission for every stepstarting a work block you trust the agent to run
"…but never re-tune, keep it paper, zero orders."the guardrails that ride along with delegationalways attach to a "go"
"Prove it out / test it, then tell me."don't report success until it's verifiedafter asking for any build or fix
"Look at our losses — how much did we miss by, are they clustered, are we accounting for X?"an honest post-mortem, not a reassurancewhen something underperforms
"Make sure it's exactly what would happen on Polymarket."match reality (fees, spread, fills) to the centany P&L / edge claim
"One lane at a time."finish and prove one thing before the nextwhen scope starts sprawling
"Measure it before we wire it live."study first, deploy behind the gateany new signal idea
"Don't relitigate — treat the concept as proven, validate our implementation."don't re-argue settled strategy; check the code does it rightwhen the agent second-guesses a proven idea
"Verify, don't auto-change it — flag it for me."surface, don't silently mutate configanything touching live settings/mappings
"Plan and update, then launch."write the plan + docs first, then buildbefore a big build
"Update everything to a T — compact but full, every detail and where we're going."persist state so the next session (or a friend) can pick upend of a work block
"Say the word / say when."a checkpoint before something irreversible or outward-facingbefore deploys, sends, spends
"Additional stuff you fill in or learn yourself too."go beyond the literal ask; bring back what you foundresearch / exploration tasks
"Learn off the losses — no full-stop."don't panic-halt a working system; learn from misseswhen a bot has a bad run

The anatomy of an owner-style prompt

Not every prompt has all five, but the good ones hit Goal → Wheel → Guardrails → Verify → Persist:

  1. Goal — one thing, concretely. "Add a signal that fades order-flow imbalance on my sport."
  2. Wheel — hand over the how. "You've got the wheel — figure out the cleanest way."
  3. Guardrails — what must never happen. "Paper only, zero orders, don't touch the engine files, don't re-tune anything locked."
  4. Verify — the proof you want. "Run the test suite, keep it green, and show me the honest read — Wilson LB, not the point estimate."
  5. Persist — capture it. "Then update the docs so the next session and my friends can follow."

Template you can copy:

"Working on [one lane / one question]. You've got the wheel — [do the thing], but [guardrails: paper, zero orders, no re-tune, don't touch engine files]. Prove it — run the tests, and give me the honest read (small n is fine, just say so). Then update the docs to a T."

Worked example — adding a sport to Togi

Weak prompt (what NOT to do):

"make my sport bot win more, tune it until the win rate is good"

That asks the agent to overfit (banned), has no guardrails, and no proof standard. The agent that follows this project's rules will push back on it.

Owner-style prompt (do this):

"New lane: add [my sport] to Togi. You've got the wheel — one new file in the sports package, follow the existing sport as the template so it auto-discovers. Keep it paper, zero orders, don't touch the frozen engine files, and don't re-tune anything that's locked. Wire the staleness edge the same way the other sports do. Run the mm test suite and keep it green, add tests for my sport, and give me the honest readout — what's the edge, and how far is it from the gate. Then commit to a branch and update the docs so I can PR it."

Notice: one file, template-following, guardrails named, tests demanded, gate-honest, persisted. That's the whole style.

The real thing — prompts the owner actually sent, verbatim

Everything above is the theory. These six are the practice: real kickoff prompts from the owner's own sessions, lightly trimmed. Read them for the shape, not the polish — messy words, sharp intent.

a. "Ok you got the wheel…" — total delegation WHEEL
The owner's words
"Ok you got the wheel im gonna sleep do whats needed and rest till the next session, goodnight."
What the agent did

Ran the full overnight build loop solo — built, tested, verified, documented — and left a clean checkpoint for the morning.

Why it works

Total delegation works here because the guardrails live in the repo (AGENTS.md), not in the prompt. The agent wakes up already fenced in.

Steal this pattern

Hand the wheel explicitly; the constitution rides along automatically.

b. "audit the losses…" — questions, not answers POST-MORTEM
The owner's words
"audit the losses and see what kinda has changed, where are we losing, by how much, are they near by eachother, is the heatwave making us sell more than usual, are we fully accounting for the heatwave"
What the agent did

Produced the loss audit (case study e): regression-to-mean verdict, heat fully absorbed by calibration, losses concentrated-not-correlated.

Why it works

It names the QUESTIONS, not the answers — five falsifiable checks, zero suggested conclusions. The agent can't just agree with a hunch; it has to measure.

Steal this pattern

Interrogate losses with specific questions. Never say "make it win more."

c. "exactly what they would have been on Polymarket" — anti-fantasy P&L REALITY-MATCH
The owner's words
"Make sure wins and losses are exactly what they would have been on Polymarket."
What the agent did

Verified the live fee formula on-chain-exact: 0.05·p·(1−p), taker-only, tick 0.001 (case study f).

Why it works

It demands reality-matching to the cent — the anti-fantasy-P&L instinct. A ledger that drifts from the venue is a story, not a result.

Steal this pattern

Regularly ask: "would the real venue have paid this?"

d. "verify the volume numbers… find the trustable source" — source hierarchy VERIFY-OWN-NUMBERS
The owner's words
"Quickly verify the volume numbers that you have per market, per bucket... Find the trustable API or source... separate the different types of volumes and look at them entirely and respectively for what they mean, analyzing wise and trading wise."
What the agent did

Found its own error (bucket vs event volume), then built the source guide: screening vs real depth vs executed tape.

Why it works

It assumes numbers can be wrong and demands the source hierarchy. "Volume" means three different things across three endpoints — the prompt forces that apart.

Steal this pattern

Make the agent verify ITS OWN numbers against the primary source.

e. "find out why the volumes down and verify it" — the push-back MOST IMPORTANT
The owner's words
"yes but we won't lose the volume right trade days should come back with higher volume ?? find out why the volumes down and verify it."
What the agent did

Its first two answers were WRONG — a phantom drought from its own filter bug, then "market ghost town" from a bad metric. The owner's push-back forced the real, verified answer: market volume was fine at ~$848k/day — the EDGES left with the heatwave, and depth thinned.

Why it works — and why this is the most important card

The owner did not accept the first confident answer. Or the second. A good agent, told to "verify it," will audit itself and sometimes overturn its own diagnosis.

Steal this pattern

When an answer smells off, push back and say "verify it." Persistence beats politeness.

f. "update all the context files… to a t" — persist everything PERSIST
The owner's words
"update all the context files, the roadmaps, where we are, where we go, to a t."
What the agent did

Refreshed every context doc + memory so the NEXT session (or a friend) starts fully loaded.

Why it works

It treats documentation as part of the work, not an afterthought. The repo stays the shared brain only if every session writes back to it.

Steal this pattern

End every work block with a persist-everything prompt.

Map them back to the anatomy — Goal → Wheel → Guardrails → Verify → Persist:

  • a is pure Wheel — and shows the Guardrails can live in the repo instead of the prompt.
  • b is a sharp Goal plus built-in Verify — each question is a falsifiable check.
  • c and d are Verify at its strictest: match reality to the cent, and re-derive your own numbers from the primary source.
  • e is Verify applied twice — the push-back loop when the first answer fails the smell test.
  • f is Persist — the closing move of every work block.

The bans — the owner never asks for these; don't either

  • ❌ "Just tune it until it wins." (overfitting — the #1 banned move)
  • ❌ Re-tuning a locked strategy's spec (selection, band, lead, sizing, fees, calibration).
  • ❌ Relitigating a proven concept instead of checking our implementation of it.
  • ❌ Accepting "done" without tests / a verified read.
  • ❌ Touching live money, live ledgers, or the frozen engine files (that's the owner-maintainer's lane).
  • ❌ Dressing up a small sample as evidence ("it worked 3 times!").

Getting started — point the agent at the context

You don't have to explain the project — it's in the repo. First thing, tell your agent:

"Read AGENTS.md, BUILD_STATE.md (the top checkpoint), and NEXT_SESSION_PLAN.md before you touch anything. Then [your task]."

03Vocabulary — the Shared Language

The agent knows these terms cold. Using them makes you 3× faster and keeps you inside the guardrails. Plain-English glosses — type to filter.

TermWhat it means
the edgethe real, measured reason we make money on a market
the laneone strategy line (weather taker, sports staleness, market-making…)
the gatethe bar a lane must clear before it's trusted / goes real (a sample n, a Wilson LB)
accrue / accruingkeep collecting data toward the gate; "it's accruing to 300" = not there yet
the tape / the lakethe recorded data we replay (trades, order books, fair values) — read-only, never edited by hand
the boardthe live cockpit that shows each lane's health
the readout / the verdictthe honest result of a study ("BB-Z fade = dead; FLOW = promising")
paper / real_capital = NOeverything is simulated until the owner flips real money on
fv / fv_sharpfair value / the sharp (Pinnacle-derived) fair-value reference
basisthe gap between our fair value and the market's price
stalenessthe market lagging a fresh signal — the window we lift the stale price in
net edge / MIN_NET_EDGEedge after fees; the floor a bet must clear (locked at 2¢)
Wilson LBthe honest lower bound of a win-rate/edge given the sample; the claim we quote
ICIR / CLVconsistency of a signal / closing-line value — "did the market move our way"
suggestion-modethe code recommends a change; the owner applies it — nothing self-mutates
the plug-in surfacethe only files a collaborator edits (a signal file, params) — never the engine
frozen engine filescore files only the maintainer touches, via review (fair/quoter/tape/recorder/…)
per-sport package / auto-discoveredadd a sport = one new file; the system finds it — zero shared edits
Thor / Lokiweather takers (daily high / low) — LOCKED spec, never re-tuned
Togithe sports staleness taker — this is the lane you (friends) build, sport by sport
Odin / Hodr / Freyrthe market-maker configs (directional / pure / rewards)
Mimir / Muninn / Bifrostthe fair-value engine / the data lake / the London VPS

04The Edge Loop — the Whole Method on One Page

Every edge in this project — validated, accruing, or dead — went through the same seven steps. No exceptions, no shortcuts, and the order matters.

CONCEPT

Comes from the mentor list. The seven strategies (MM, latency arb, cross-exchange arb, resolution arb, MM + directional view, MM rewards, vulture) are treated as PROVEN — we never relitigate the concept. What we test is our implementation of it: our data, our latency, our fills, our fees, on our venue.

PAPER-IMPLEMENT OUR VERSION

A read-only study or a zero-order paper bot. In mm/ the package is zero-order by construction (no wallet, no key, no order call exists). The study reads the lake (Muninn), never places anything.

TRUE POINT-IN-TIME BACKTEST

Only data knowable at decision time. Three legs, all real: the real INPUT as-of decision time (for Thor: the forecast actually issued ~24h before, via the historical-forecast API — never ERA5 reanalysis), real FILLABILITY (a real ask/depth at our price, not a theoretical mid), real OUTCOME (on-chain outcomePrices, never a proxy).

MEASURE ON THE REAL TAPE

The proprietary lake (books + trade prints, recv-clock NTP-stamped) is the measurement surface. A fill exists only on a real print at/through our level. Fees are the exact live fee (0.05·p·(1−p), taker-entry-only — verified against the live market metadata, see case study f).

PRE-REGISTERED GATE

Declared BEFORE the data comes in: a sample size (n ≥ 300 for the MM studies; the canonical Thor gate is the frozen 3-condition data.gate) and the Wilson-95 lower bound as the claim — never the point estimate. Read once, verdict permanent.

VERDICT

One of three words: VALIDATED (gate met, edge positive at the LB), ACCRUING (honest at any n, keep collecting, no early promotion), DEAD (gate met, edge negative — or a methodology leak found). Verdicts are terminal. A DEAD edge stays dead; we don't re-run it with one more filter until it flatters. Re-opening requires a structural change in the world (e.g. Freyr rewards reopens only if Polymarket changes the 1000-share min-size gate), not a re-tune.

ONLY THE OWNER PROMOTES

Everything up to here is SUGGESTION-mode. The study recommends; the owner flips. Nothing self-wires, nothing auto-raises its own cap, and real_capital = NO until the canonical gate is met AND the owner flips the governor switches.

The single most important property of this loop: an idea is measured before it ever trades. BB-Z fade (case study c) lost money on paper without ever costing a cent, because the study ran first. That is the loop earning its keep.

How to prompt for this — the edge-work phrasings

The phrase-book in 02 Prompting covers the general style. These are the edge-work phrasings specifically — the owner's moves and what each one tells the agent to do:

The owner saysThe agent should do
"Audit the losses."Case study e, in full: distance-to-miss, bias vs calibration, concentration vs correlation. Deliver one of three verdicts — leak / break / variance — and if it's variance, say "do nothing" out loud. Never propose a new filter as the fix.
"Make sure wins/losses are exactly what they'd be on Polymarket."Re-derive P&L from the live mechanics: the real fee formula, the real tick, the real ask/depth at entry, settle vs on-chain outcomePrices. Reconcile to the cent; report any gap as a finding, not a rounding note.
"Measure it before we wire it live."Build a read-only study on our own tape (the flow_study / staleness_study pattern): pre-register the gate and the Wilson-LB claim FIRST, run zero-order, report honestly at any n. Wiring is a separate, later, owner-gated step.
"Look into X, make sure we aren't overpaying."Case study f: pull the live source, reproduce the exact number, name which endpoint is authoritative and why. Bring back the side-findings too (that's how the 0.001 tick was found).
"Verify the numbers, find the trustable source."Rank the candidate sources by what they actually measure, reconcile them against each other (event = Σ buckets), and write the ranking down so the next study doesn't re-litigate it.
"Don't relitigate — the concept is proven; validate OUR implementation."Skip the "does this strategy work in theory" essay. Test our data, our latency, our fills, our venue — and scope the verdict to exactly what was measured (moneyline ≠ totals).
"Adversarially review it before you report it."Attack your own study the way review attacked the maker study: is n independent? is the clock pre-trade? is the reference fresh? does the cohort survive incl-exits? Only then write the verdict.

The standing frame around all of it: paper only. Zero orders in mm/. No re-tunes to a locked spec. Suggestion-mode everywhere. The plug-in surface is mm/signals/ + mm/params.py + your Togi sport file. Engine files are single-maintainer. Only the owner promotes. The loop finds the edges; the constitution keeps them honest.

05Case Studies — How It Actually Went

Every number below is a real number from this repo's studies. If you're about to test an idea, read these first: the graveyard is half the moat.

a. STALENESS — the validated one VALIDATEDACCRUING to n≥300
The kickoff

The build order named it up front: "staleness study = the decisive $/day fork." The mentor concept (latency/staleness) was taken as proven; the question was whether OUR sharp reference and OUR lake could see it on Polymarket.

The method

mm/staleness_study.py — read-only, on the live fv tape. When the de-vigged sharp reference (Pinnacle) steps, how long does Polymarket's retail quote take to reprice, and what does lifting the stale price at various delays earn net of the honest fee and the depth clamp? A 15 s probe inside a sub-60 s window, per-window Wilson CI, pre-registered n ≥ 300 accrual gate.

The numbers

The sub-60 s window is VALIDATED: +2.8¢ @ 15 s, decaying to −9¢ @ 60 s, around a ~51 s reprice lag. The first concrete sign the MM directional edge is real. Still ACCRUING to the n ≥ 300 gate — reported honestly at any n; weeks to fill at the free sharp cadence.

The lesson

The edge has a shape — it isn't "staleness is good," it's "+2.8¢ if you're inside 15 s and negative past a minute." Measuring the decay curve is what made the finding actionable (it's also what justified reversing the earlier "no" on the $30/mo Odds API minute tier — a decision now backed by a validated edge instead of hope).

b. MAKER TILT — the refuted one DEAD (moneyline-scoped)
The kickoff

The make-or-break test for the "directional" half of MM + directional view. The question: when Polymarket sits off a FRESH sharp (a standing basis), does PM converge to us — so Odin's maker tilt earns? Owner-style framing: prove the mechanism on the real tape before investing any more in tuning the tilt.

The method

mm/maker_study.py, read-only on the real fv tape, look-ahead-safe: find basis events, measure gross convergence at fixed horizons, stratify by sharp freshness (ref_age).

The correction story — the important part

The first cut counted 7,414 per-row "events." Adversarial review of our own verdict found that was a ~29× autocorrelation over-count — the same standing basis re-sampled every few seconds, not independent observations. After episode-dedup: ~258 fresh basis episodes across ~36 tokens. The gate went from "met" to ACCRUING in one honest step. A fresh-sharp filter was added so a stale reference couldn't manufacture fake basis.

The numbers

Gross convergence at h=300 s is NEGATIVE across every fresh stratum (ref_age ≤300 s −1.32¢, ≤600 s −0.76¢, ≤1800 s −0.78¢; hit rate ~41%). A fresher sharp does NOT flip it positive.

The verdict — scoped honestly

The moneyline standing-basis tilt does not earn, even fresh. It explains why Odin ≈ Hodr (the tilt adds ~0). But the scope is MONEYLINE ONLY — the fv tape is ~100% moneyline (the wide lane is 100% sharp_missing), so this says NOTHING about totals/runline; building the de-vigged totals/runline sharp reference is the prerequisite to test that, not refuted by this. The sharp's edge is in its STEPS (the staleness taker) not its standing LEVEL (the maker tilt).

The lesson

Two, actually: adversarially review your own verdict before you report it (the 29× over-count was found by us, on our own study, before it banked), and n must be ~independent samples — a per-row count over an autocorrelated series is not an n.

c. BB-Z / FLOW — measure-before-wire BB-Z: DEADFLOW: ACCRUING
The kickoff

The owner sent the "loop engineering" reel and the TruthTick terminal: "explore both, how we use for maker/taker; plan and update, then launch." The synthesis framed the terminal as an instrument, not an alpha source — but it surfaced two candidate signals, FLOW (order-flow imbalance) and BB-Z (Bollinger-z mean reversion). Standing rule applied: "measure it before we wire it live."

The method

mm/flow_study.py — new, read-only, zero orders. Both signals measured on OUR OWN lake (tick bars off trades, mid band off books), per-horizon Wilson CI, honest 0.05·p·(1−p) fee, pre-registered n ≥ 300 gate. Wiring either as a live mm/signals/ nudge was DEFERRED behind the gate + an out-of-sample check + owner promotion — declared before the first readout, not after.

The numbers
  • BB-Z fade = DECISIVELY NEGATIVE, gate MET (n = 12,319). Mean net −0.83¢ → −1.02¢ across h=2/5/10, gross hit-rate under 33%, tight Wilson CIs. Fading a book-mid extreme loses because the extreme is mostly a genuine repricing that continues — coherent with the staleness edge (go WITH the step). DO NOT wire.
  • FLOW go-with = PROMISING but ACCRUING (n = 33). h=1: +11.1¢ mean net, 58% profitable, 67% hit — but the Wilson LB is only 0.32. A lead, not a verdict. Keep accruing.
The lesson

This is the loop's whole value in one readout: a signal that sounds right (mean reversion! every terminal ships it!) was measured on our tape and killed before it ever traded. And the FLOW half shows the discipline cuts both ways — a +11.1¢ point estimate with n=33 gets reported as "a lead," because the LB is the claim.

d. NET-EDGE FLOOR A/B — the discarded improvement RESOLVED → DISCARDED
The kickoff

After the first losing days the owner asked to "do sizing 10x better on a scaling level." The sizing workflow's verdict: flat 2% wins as the SIZE. Every up-sizing scheme — Kelly, edge-proportional, cheap-tilt — is negative out-of-sample once the ~$125 1-tick depth clamp bites. The one surviving candidate was raising the net-edge FLOOR from 2% toward ~5%. That one works by not betting, so it needs no fillable size.

The method

Not a re-tune — a shadow A/B: _floor_ab() in ned_api.py (surfaced as data.floor_ab) measured what each floor 3–7% WOULD have done on the real deploy book, with a forward out-of-sample window accruing after a declared cutover date. The live MIN_NET_EDGE stayed at 2.0 the entire time. Pre-registered: re-evaluate after the fresh forward fills arrive, read once, verdict permanent.

The numbers

118 fresh OOS fills refuted it — every 3–7% floor showed negative lift. RESOLVED → DISCARDED (2026-07-08). Keep MIN_NET_EDGE = 2.0.

The lesson

This is what the no-re-tune rule looks like when an idea is actually good on the training data (+5–7pp in-sample, positive in 7/7 walk-forward splits): you shadow it, you let fresh out-of-sample data vote, and when the OOS says no, the verdict is permanent. The floor-A/B discipline working IS the result — not a failure, a $0 lesson instead of a live one.

e. LOSS AUDIT — regression vs break VARIANCE — do nothing
The kickoff

The owner's actual phrasing (see the phrase-book): "Look at our losses — how much did we miss by, are they clustered, are we accounting for X?" The prompt asks for a post-mortem, not a reassurance.

The method

Decompose the WR dip on the real ledger: distance-to-bucket on every loss, model bias vs the walk-forward calibration, geographic concentration, and cross-loss correlation (dispersion) — because "concentrated" and "correlated" are different risks.

The numbers

Whole-book settled WR 38.3% (69/180) — squarely in the 35–39% design range for buckets paying ~3:1 (incl-exits, the gate basis, ≈33–34%). The dip is regression to the 38% mean, not a break: losses are ~1 °C adjacent-bucket coin-flips, broad rather than a new failure mode. HEAT is fully accounted for — the raw model runs +0.34 °C warm but the walk-forward calibration absorbs it (actual − BET bucket = −0.17 °C, effectively unbiased). Losses are concentrated (91% Asia+Europe, 8–20 bets/cycle) but NOT correlated (dispersion ~1.0) → the real risk is mechanical single-cycle variance, and the candidate fix (a region/cycle sub-cap) stays a SUGGESTION-only shadow, not a wired change. sao_paulo + munich = persistent warm WATCH flags — confirmed station MATCHES, genuine variance.

The lesson

An honest loss audit has three possible outputs: a leak (fix the plumbing), a break (a new failure mode — investigate), or variance (do nothing). Most dips are variance, and "do nothing" is a real answer — the banned move is treating variance as a break and "fixing" it with a new filter.

f. FEE / VOLUME VERIFICATION — never trust a number you haven't reproduced CONFIRMED
The kickoff

Owner-style asks, paraphrased: look into the fees and make sure we aren't overpaying; verify the volume numbers and find the trustable source. Thor's P&L had always assumed a fee model; assumption ≠ verification.

The method

Pull the live market metadata and reproduce the number, don't cite a docs page. Same for volume: reconcile the aggregate against its parts, and rank the sources by what they actually measure.

The numbers
  • Fee CONFIRMED LIVE + EXACT (2026-07-08): Polymarket weather markets carry feesEnabled=true, feeType=weather_fees, rate 0.05, exponent 1, takerOnly=true, makerRebate 0.25 — exactly Thor's 0.05·p·(1−p) taker-entry-only model. Not overpaying; if anything slightly conservative on the entry. Bonus finding you only get by looking: tick size on current weather markets = 0.001, not 0.01.
  • Volume RECONCILED: event volume = Σ its bucket sub-markets (Seoul Jul-9: $88.6k event ≈ $88.7k summed). And the sources ranked by use: gamma volume24hr for screening; the CLOB /book for real resting depth (the truth — gamma liquidity is only a proxy); the data-api /trades executed tape for VWAP/backtests.
The lesson

Every constant in a P&L model is a claim. Verify it against the live source, reproduce it exactly, and write down WHICH source is authoritative for which question — because the same word ("volume," "liquidity") means three different things across three endpoints.

06The Trap List

Each one has a body attached — a real study in this repo that hit it (or dodged it).

1 · OVERFITTING / RE-TUNE

Optimizing on your own build data finds "prettier noise faster." Every extra iteration is another chance to overfit. The defense is constitutional: NO RE-TUNES, EVER, on a locked spec.

BODY: the floor A/B (case d) — good in-sample, refuted OOS — and dodged in BB-Z (case c).

2 · LOOK-AHEAD / RECV-TIME ARTIFACT

Trades arrive ~10 s late vs ~5 s book polls, so a "prevailing" book keyed on receive time is actually post-trade. Distrust ANY recv-time markout study.

BODY: killed vulture v1 outright — its founding +$56–74/day vanished on an honest pre-trade clock.

3 · AUTOCORRELATION OVER-COUNT

A per-row count over a slowly-moving series is not a sample size. n = ~independent samples, always.

BODY: the maker study (case b) — 7,414 "events" were ~29× over-counted; ~258 real episodes.

4 · SURVIVORSHIP

Dropping exits (or any losing cohort) from the denominator.

BODY: the gate counts exits as losses — owner ruling; and the maker book only "looked up" until incl-exits showed −$2,495.

5 · SIGN-FOLD BIAS

Don't score a prediction against a SIGN-FOLDED realized move — one already credited in the prediction's own direction, like a clv column. That correlation manufactures fake skill.

BODY: the ICIR lens in signal_audit.py deliberately correlates the SIGNED nudge against the UN-folded realized move for exactly this reason (report-only, never a gate).

6 · DEPTH CLAMP

An edge% means nothing without fillable dollars. The 1-tick depth clamps Thor to ~$125 per market.

BODY: killed every up-sizing scheme in the sizing study (case d): Kelly and friends all die at the clamp.

7 · STALE-REFERENCE CONFOUND

A "basis" against an old reference is mostly the reference being wrong.

BODY: the maker study (case b) added a fresh-sharp filter for this; and the wide lane is 100% sharp_missing (Pinnacle moneyline de-vig ≠ a totals/runline reference), so a moneyline verdict must never be read as a totals/runline verdict.

8 · SMALL-N FLATTERY

A hot day-slice or a fat point estimate on tiny n. The Wilson lower bound is the claim; day-slice WR is noise.

BODY: FLOW (case c) at n=33 shows +11.1¢/67% hit but Wilson LB 0.32 → reported as "a lead."

07The Two Seats

Two friends, two tool setups, one loop. Ownership per AGENTS.md: the owner runs Loki, the live fleet, and the mm/ plug-in surface; the friends own Togi sport sets A and B.

The model, in brief: the repo is the shared brain — ~/ned on the owner's machine, with a private GitHub remote (git@github.com:bavatharannanthan7-lang/ned-v1.1.git — the owner controls access). It is source-only. Live ledgers (*.jsonl), bankroll.json, ned_access.json, caches, and the data lake are all gitignored; they live on the owner's Mac + the Bifrost VPS only. Your clone starts with empty ledgers — that's correct, not broken. You develop against fixtures and dry runs. The owner runs the one authoritative live fleet.

One sport = ONE new file, and you can never conflict. Every sport is a sibling file that calls core.register(...) on import. togi/__init__.py auto-discovers every module. So adding a sport touches zero shared files — two friends owning two sports literally cannot produce a merge conflict. The same pattern exists for data-point ideas: one new file in iterations/mm/signals/. The owner is the maintainer. He reviews and merges PRs, runs everything live, and solely maintains the engine files. Everyone inherits the constitution automatically — CLAUDE.md and GEMINI.md are symlinks to AGENTS.md, so whatever agent you run reads the same rules.

SEAT A

Claude MAX (Claude Code, the full agent)

Fully self-serve: your agent does the whole loop. The Max plan has the usage headroom for long agent sessions — the team now runs TWO Max accounts — the owner and Seat A.

Your loop: branch → agent writes/edits your one file → python3 -m togi → suite green → small PR → rebase when asked. Keep every change inside your file; if you genuinely must touch a shared file, say so in the group chat first and keep that PR tiny.

DAY-1 CHECKLIST

SEAT B

the NFL friend — Claude Free + Antigravity CLI + any free AI (the free stack)

One person, two tools. Antigravity CLI is your DAILY coding agent — it runs the same loop as Seat A, word for word, and reads the same constitution (GEMINI.md is a symlink to AGENTS.md, so nothing is Claude-specific). Claude Free is your judgment tool for the high-level moments.

"But Claude Free only gives me a handful of prompts a day." The stack is designed so that's ENOUGH:

  • The repo context files teach the project (AGENTS.md, BUILD_STATE.md, the guides) — agents need almost no explaining.
  • Antigravity CLI does the daily coding. It reads the same AGENTS.md and is unlimited by Claude's plan.
  • Claude Free is reserved for where its judgment matters most: designing the sport file, reviewing a tricky edge idea, sanity-checking a verdict. A few sharp prompts a day, written with the prompt patterns in this guide — one well-formed prompt beats ten vague ones.

Antigravity cautions: never edit CLAUDE.md or GEMINI.md — they're symlinks; the real file is AGENTS.md, and even that is the owner's to maintain. Antigravity is likelier to helpfully "improve" shared files than to stay in one file, so put the fence in the prompt every time: "Keep the change to iterations/togi/<sport>.py only; flag any shared-file edit before making it." The paste-ready brief at the bottom of docs/togi-onboarding.md already says this — use it verbatim. Run the same suite the same way; green means the same thing for everyone.

DAY-1 CHECKLIST

No agent handy? You can also land the file yourself with plain git (six commands):

git clone git@github.com:bavatharannanthan7-lang/ned-v1.1.git ned
cd ned
git switch -c feat/togi-<sport>
# save Claude's file as iterations/togi/<sport>.py, then:
git add iterations/togi/<sport>.py
git commit -m "togi: add <SPORT> sport module"
git push -u origin feat/togi-<sport>

08The Per-Sport Recipe

What a sport file actually is, mirrored from the real one (iterations/togi/mlb.py).

"""TOGI · <SPORT> — pre-game moneylines."""
from togi import core

core.register(
    "<SPORT>",           # must match sports_feed.SPORTS: MLB / NBA / NFL / NHL / WNBA
    home_edge=0.035,     # home-field prob bump (MLB uses +3.5pp)
    min_edge=0.07,       # log floor — below this the divergence is noise
    max_edge=0.15,       # log cap — above this the model is MISSING a feature, not finding edge
    # prob_fn=my_model,  # def my_model(game, cfg) -> P(home win); the seam where Mimir FV plugs in
)

That's the whole registration. The engine signature is

core.register(code, *, home_edge, min_edge=0.07, max_edge=0.15, prob_fn=None, model="log5")

— your file provides the config, core.py provides scan → dedup shadow-log → settle vs on-chain outcomePrices. Your prob_fn (if you pass one) receives the game dict from sports_feed.games() (home/away with rec/wpct, state) and returns P(home win) in (0,1), or None to skip. core only bets state == "pre" games — leak-safe by construction.

Where the edge actually comes from — read this before "improving" the model

Togi is a sports staleness-taker, not an out-modeler. The live tape measured MLB moneyline spreads at a median 1.0¢ and falsified record-based log5 "edges" of 14–47pp as phantoms — out-modeling a sharp-copied line FAILS, and that verdict is part of the moat. The winnable edge: a de-vigged sharp reference (Pinnacle via The Odds API, mm/sharp.py, game-gated scheduler on the free tier) feeds Mimir (mm/fair.py — de-vig → confidence → microprice → blend → basis → is_stale), and is_stale fires when the sharp just stepped AND Polymarket's basis is abnormally wide — the market lagging a fresh signal. The sub-60 s window is validated (+2.8¢ @ 15 s decaying past the ~51 s reprice lag) and accruing to its n≥300 gate. Togi consumes that same staleness event as a paper taker fill; your sport file's prob_fn is the seam where Mimir's blended FV plugs in when the owner sequences that lane. Until then the default record model runs as the honest negative control — expect it to lose to the line; that IS its finding.

Data-point ideas go in the other plug-in surface

A pitcher/lineup/park/rest idea isn't a sport — it's one file in iterations/mm/signals/<name>.py calling signals.register(name, fn, cap_c=0.5) with fn(ctx) -> (delta_p, confidence, note). Auto-discovered, hard-capped at 0.5¢ until it self-validates on the tape (total cap 1¢), scored in SUGGESTION-mode — the harness recommends a cap change, the owner applies it. Copy example_probable_pitcher.py. Signal fns must be fail-open and read from cached/local stores (the live ones read the mlb_features cache, the weather cache, or the lake events tape) — never make blocking network calls inside a scan pass (timer passes do the fetching).

What it must pass before the owner merges

  • The full suite green: cd iterations && NED_PUSH_DISABLE=1 python3 -m unittest discover -s mm/tests -q (any test that could touch notify paths MUST set NED_PUSH_DISABLE=1 — that's the notify contract).
  • A dry python3 -m togi that prints sane reads for your sport.
  • Honest n reporting. Report what the sample supports and say how small it is — Wilson lower bound, not the point estimate. "It worked 3 times" is not evidence; small n stated honestly is fine.
  • The diff stays inside your file(s). One sport file (or one signal file), tests if you added logic.

What NOT to do

  • No engine edits — togi/core.py, sports_feed.py, and all mm/ engine files are single-maintainer.
  • No re-tunes of anything locked, and no re-tuning your own sport into the market after the fact ("just one more filter" is the banned move).
  • No out-modeling the line and no relitigating falsified ideas (log5-as-edge, spread-capture on 1¢ moneylines, BB-Z fade — the graveyard is part of the moat).
  • No network calls inside scan-time signal fns; no committing ledgers (togi_shadow.jsonl is live single-owner data and gitignored); no hand-editing any live book, ever.

09Ground Rules — the Constitution Recap

From AGENTS.md. Everyone inherits these automatically — the repo teaches your agent. Everything is PAPER, real_capital = NO, fleet-wide; that never changes.

  1. PAPER only. real_capital = NO fleet-wide until the canonical gate (data.gate) is met AND the owner flips the governor switches.
  2. Zero orders in mm/ — by construction: no wallet, no key, no order call exists in the package.
  3. One lane at a time (owner directive) — don't start a lane the owner hasn't sequenced.
  4. NO RE-TUNES, EVER on locked specs; the tuning levers were exhausted to null by repeated audits.
  5. Engine files are single-maintainer. The plug-in surface is togi/<sport>.py, mm/signals/, and mm/params.py — nothing else.
  6. Single-owner live data. Ledgers, launchd/systemd jobs, keys: owner's machines only, all gitignored. Never write or "fix" a live book by hand — code changes only, via PR.
  7. Gates, not vibes. Every edge claim = the live gate object / Wilson lower bound, never a stale snapshot or a point estimate. Exits COUNT as losses in the gate.
  8. SUGGESTION-mode everywhere. Studies and scorers recommend; the owner applies. Nothing self-mutates its own deploy.
  9. Settle against reality. On-chain outcomePrices always; fees exact; a fill exists only on a real print. Measure a signal before wiring it live, and prove it out-of-sample.
  10. Rewards/rebates are ledgered separately and never flip a gate green.

Branch per person, rebase, small PRs, the owner merges and runs live. When in doubt: ask in the group chat before editing anything shared — that one habit prevents every collision this setup was designed to avoid.

10Owner's Per-Sport Data Points

The owner's domain map: what matters in each sport, where to look, and how each point feeds the model. The data-point lists are the owner's own words, organized. The "how it feeds the model" framing is the build-side synthesis. The constitution still applies: one point = one measured signal, paper only, no re-tunes, the scoreboard decides.

How ANY data point becomes edge here — read this first

The anchor is the bookmaker line, not the stat. We already ingest de-vigged sharp odds (Pinnacle via The Odds API — mm/sharp.py, budget-gated). That line already prices most public stats. So the bar for every data point below is never "is this stat good?" It is "does this stat move the probability BEYOND what the sharp line already knows?" The owner's phrasing is exactly right: "everything you can plug into your model to see if Vegas is missing something." In our machinery, "is Vegas missing it" has a precise score: CLV — does the point consistently beat the closing line? A point that does, earns. A point that doesn't, shrinks. Every source named below is verified + PIT-graded in docs/FREE_DATA_SOURCES.md — read it before wiring anything.

A data point can earn in exactly three ways:

  1. NUDGE — a small capped adjustment vs the sharp line (the mm/signals/ pattern: one file, 0.5¢ starter cap, self-scoring earn→1.0¢ / hold / shrink). This is where most fundamentals land — MLB already runs four (platoon splits, pitcher form, weather/park, scratch-veto).
  2. VETO — information the line may not have absorbed yet (a late scratch, an inactive, a weather flip) that blocks a take entirely. Often the highest-value form, because it's about SPEED, not disagreement.
  3. MODEL FEATURE — for markets with no live sharp reference (many props), the points feed the sport's prob_fn directly and BECOME the fair value. This is where deep domain maps like the NFL one below matter most, because there's no sharp line doing the work for you.

Honest expectation: the staleness studies taught us fundamentals are mostly priced — the durable edges are speed (reacting to sharp moves) plus many small residual nudges. Expect a good point to earn 0.5–1¢, not 10¢. Twenty measured half-cent points that survive their gates is a real model; one 10¢ opinion is a blown bankroll.

NFL — the owner's deepest map (for the NFL friend)

Team context

PointWhy it mattersWhere to look
Home / away splitsteams are not the same team on the roadnflverse (nflreadpynfl_data_py is deprecated), Pro-Football-Reference
Team power rankingsa stable prior beneath weekly noisebuild from EPA/play (nflverse) rather than pundit lists
Strength of schedulecontext for every rate statschedules in nflverse / PFR
Rest — days since last game, short weeks, Thursday games, post-byefatigue + prep time are real, measurable, and sometimes underpricedschedule math (ESPN feed — sports_feed.py already speaks ESPN)

Coaching & scheme (OC / DC)

PointWhy it mattersWhere to look
OC / DC identity + tendenciesthe scheme is the context every player stat lives innflverse FTN charting, team pages
Zone vs man coverage ratethe owner's core idea: players don't perform vs "a defense," they perform vs a COVERAGEnflverse participation (2016–22 in-season-safe; 2023+ releases only post-season — a look-ahead trap for backtests)
Blitz ratepressure changes everything downstreamFTN/nflverse
Zone-scheme run rate (inside/outside zone)run-game matchup vs frontFTN/nflverse play-by-play

The matchup engine (player-vs-coverage — the heart of the props model)

PointWhy it mattersWhere to look
WR/TE/RB production vs man vs zone (receptions, yards, targets)a WR who feasts on zone facing a zone-heavy DC is a real, specific edge — this is PROP fair valueFTN charting joined to play-by-play
RB receiving vs zone coveragecheckdown volume is scheme-drivensame
WR power rankings (separation, target share)who actually gets open + fednflverse target/route data
Red-zone targetsTD props live and die hereplay-by-play splits

Pressure ↔ QB conversion (the owner's two-sided read)

PointWhy it mattersWhere to look
Defense: blitz rate, pressure rate, time-to-pressurehow fast the pocket collapsesFTN/nflverse
O-line quality (pressure rate allowed, pass-block win rate)converts the defense's numbers into THIS gamenflverse; PFF if ever paid
QB time-to-throwfast-release QBs neutralize pressure; slow ones amplify itNFL Next Gen Stats (public pages)
QB performance under pressure vs clean pocketthe split that decides pressure-heavy matchupsnflverse splits

How NFL feeds the model: moneyline/spread → team-level nudges vs the sharp. But the real prize is the matchup engine → player props — receptions/yards vs coverage type. Props are exactly the "softer markets" our market-making work already flagged as the winnable pond (wider spreads, weaker lines, sometimes no sharp reference at all — so the model feature path applies). The synergy: owner's map picks the direction, the friend builds it as signals/prob_fn, our lake + books data says which prop markets are liquid enough to take.

MLB — the NFL pattern applied (for the MLB friend)

Four of these are ALREADY LIVE as capped signals (platoon splits, pitcher form, weather/park, scratch-veto) — the MLB friend extends the same pattern, one file per point.

Pitching (the "offense" of MLB edges)

PointWhy it mattersWhere to look
Pitch count trends / times-through-orderstarters decay predictably; lines lag the decayMLB StatsAPI (we already pull probable pitchers)
Pitch arsenal — mix, per-pitch velocity, movementarsenal vs lineup is the MLB matchup engineBaseball Savant / Statcast (pybaseball, free)
Velocity trendthe earliest fatigue/injury tell — a veto candidateStatcast game-by-game velo
The whole mound — bullpen quality + usage last 3 daysa gassed bullpen flips late-game probabilityStatsAPI reliever gameLogs + Statcast (FanGraphs is CAPTCHA-blocked for scripts)

Hitting & splits

PointWhy it mattersWhere to look
R/L handedness splits (batter vs pitcher hand)already live as platoon_splits — the templateStatsAPI / Baseball-Reference
Team season batting (BA/OPS/wRC+), recent formthe lineup-wide priorStatsAPI byDateRange (FG blocks scripts)
Batters vs pitch typesarsenal × lineup interactionStatcast

The "lines" analog + context

PointWhy it mattersWhere to look
Catcher framing / team defense (OAA/DRS)MLB's O-line: invisible runsStatcast OAA, FanGraphs DRS
Park factors + weatheralready live as weather_parkbuilt
Rest / schedule — series game #, travel, doubleheaders, SOSsame rest logic as NFLschedule math (ESPN/StatsAPI)

NBA · UFC — owner's maps coming next

◈ OWNER ADDS NBA / UFC NEXT

The owner knows these deepest and will dictate the points (rest/back-to-backs, rotations, style matchups for NBA; camp, reach, style, cardio for UFC). Same recipe will apply: anchor on the sharp, one point = one measured signal, props where the lines are soft.

The combination play — why this three-way split wins

Owner's domain map (what actually matters in the sport) × friend's build (one signal file per point, measured honestly) × the platform (sharp anchor + the data lake + self-scoring + gates) = the model.

  • The owner doesn't have to code; the friends don't have to know where the edge hides; the platform doesn't have to have opinions. Each supplies the piece the others can't.
  • Every point self-scores (hit-rate Wilson-LB, CLV vs the close, ICIR consistency). The scoreboard decides, not the loudest voice — a point the owner loves that doesn't beat the close shrinks to 0¢, and that's the system working, not an insult.
  • Bookmaker odds run through everything twice: as the anchor each nudge is measured against, and as the speed edge (staleness) when the sharp moves and the market lags — both already built.
  • Priority order for a new sport: (1) the veto-class points first (scratches/inactives — cheap, high value), (2) the matchup engine for props (where lines are softest), (3) team-level nudges last (where lines are sharpest). That's deliberately backwards from how most people start — and it's why it works.