The One What-If Bible
The complete book of how the What-If system works. Every section, every constant, every law, every data contract — including the small and the obvious. Written 2026-07-07 by the conductor session that carried the overnight build, so that any future agent (Fable, Opus, agy, Jules) or human can pick this up cold and not re-suffer the derivation.
Rule of this book: every number and formula here was read from the actual files on disk at writing time, with the source file named. If a claim has no file behind it, it is marked OPEN or MEASURED-EXTERNALLY.
Table of contents
- What this product is
- The house laws
- The LPX pool mechanism from zero
- The engine contract (engine/src/index.ts)
- The recenter state machine
- The fill math, step by step
- Flow charts
- The trust chain: frozen reference, golden fixtures, parity
- The website (web/src/main.ts and friends)
- The headline math — the most important formula on the site
- Data provenance — the contracts, where everything comes from
- The Arb book — everything the arbs taught us
- Yield accounting laws
- Validation history — how we know the engine is right
- Open questions — the honest unknowns
- Glossary of every symbol
- File map — where everything lives
1. What this product is
One What-If (name chosen by Yahya, 2026-07-06) is the cofounder's what-if website, live at one-what-if.pages.dev. A visitor pastes a PulseChain token contract address. The system fetches that token's real market price history in the background, then lets the visitor play a what-if: "if an LPX pool had existed on this token through this history, with this band width and this arb appetite — what would the pool hold now, versus just holding the coin?"
It answers with a chart, two glass cylinders (fund side and anchor side), an animated 15-second playback of the whole history, and one headline number: how much MORE (or less) of the coin the pool position holds versus just holding.
It is a what-if, never a forecast. That sentence is printed on the answer card and is law (see §2).
This replaces the earlier Excel deliverable entirely. The repo is /Users/dynamic/Projects/lpx-whatif (GitHub yddptyltd-hub/what-if).
Why it exists: the cofounder needs to show, on any real token and its real history, what the LPX mechanism would have done — honestly, with zero curve-fitting, and playable by a non-technical person on a phone.
2. The house laws
These four laws (recorded in README.md) override convenience in every build decision:
Honesty law. Arb flow is exogenous — nobody can know how hungry future arbitrage will be. Therefore the site never displays a predicted arb-yield number or a predicted trade count as fact. Arb intensity is a user-facing dial (Appetite), and arb-dependent outcomes are shown as a range across the dial (Low → Hungry), never a single number. Everything is denominated in the user's own token units. Any optimizer result must carry the verbatim label: "Best on this history — historic performance does not indicate future preference." The product answers "what would have happened," never "what will happen."
Identity law. A token is identified by its contract address only, never by its symbol. Symbols are duplicated and spoofed on PulseChain; addresses are unique. Symbols are display sugar fetched from the pool name, nothing more.
Visual law. Light / day mode by default, everywhere — site, videos, exports. Never ship dark unless Yahya asks.
Money law. Free infrastructure only. Cloudflare Pages + Workers + D1 + R2 free tier; GeckoTerminal free API. No paid keys, no paid data.
3. The LPX pool mechanism from zero
Read this section before touching any code. It is the mental model everything else hangs on.
3.1 It is NOT a 50/50 AMM
An LPX pool holds real reserves of two tokens: the fund token F (the coin the position is about, e.g. WPLS) and the anchor token A (the stable or reference side, e.g. DAI). But unlike Uniswap, the pool does not price on real reserves alone. It adds imaginary reserves iF and iA — bookkeeping numbers, not actual tokens — and quotes every swap on the totals:
Ft = F + iF At = A + iA
raw_out = In · R_out / (R_in + In) (constant-product on TOTALS)
This is the invisible-token design. It was proven by matching the deployed bytecode: the vault's per-trade outputs are exact to 1e-4..1e-5 against this formula on 2000+ real trades (see §14). The imaginary reserves let a pool with small real inventory quote like a deep pool, concentrate liquidity around a chosen price, and refuse to sell below its floor — because output is always capped by real inventory (the contract reverts if out > real).
3.2 The band: center C, ceiling M, floor C·(1−ntz)
Each pool has a center price C and a no-trade-zone width ntz (a fraction, e.g. 0.03 = 3%). The band floor is C·(1−ntz). The pool's marginal price lives inside this band. rho = C0/M0 is the center-to-ceiling ratio — a per-pool protocol constant (UI default 0.0117) that fixes the shape of the imaginary-reserve construction.
3.3 Fees and margins on top of the curve
Two house margins wrap the raw curve output:
pool SELLS fund (price rising): fund_out = raw_out / ((1−profit)·(1−fee))
pool BUYS fund (price dipping): anchor_out = raw_out · (1−ntz) · (1+fee)
fee is the swap fee (UI default 0.0029), profit the house profit margin (UI default 0.01). These make the pool's effective ask sit above and its effective bid sit below the marginal price — the pool always sells high and buys back low within the band. That asymmetry is the whole yield mechanism: sell on the way up, buy back cheaper on the dip, keep the difference.
3.4 The recenter ratchet — the band only steps DOWN
If the external market price falls below the band floor and stays there (persistence-gated — one wick doesn't count), the pool concedes: it steps its center down toward the market, by at most 2.3% per step (STEP = 0.023, a protocol constant). It never steps up. Recentering re-derives the imaginary reserves from the current real reserves so the marginal price lands exactly on the new center (§5, §6.1). This is the ratchet: the band chases a crashing price down in controlled 2.3% steps, buying fund cheaply the whole way, so that when (if) price recovers, the pool holds far more coin than a holder does.
3.5 Why the design survives an 80% crash
Because buys on the way down accumulate fund at ever-cheaper prices, and the terminal position is valued in coin: the anchor pile converts to a huge number of coins at the crashed price. On the real Pool 1 WPLS history the mechanism came out +26% more coin through an 80% crash (the "homecoming" teaching video). The what-if engine reproduces this class of outcome mechanically, with zero fitted constants.
4. The engine contract
Source of truth: engine/src/index.ts (TypeScript, 186 lines) — a line-faithful port of reference/lpx_reference_core.py (frozen, §8).
4.1 The three protocol constants
export const STEP = 0.023; // max 2.3% down-step per recenter
export const COOLDOWN_S = 10700; // initial breach persistence, seconds
export const BURST_S = 700; // chase-mode re-step interval, seconds
Where these come from (do not re-derive): the v11 research engine ticked in PulseChain blocks (~10 s each) with gates COOLDOWN = 1070 blocks and BURST = 70 blocks. The website ticks in timestamped candles, so the reference core converts exactly: 1070 × 10 s = 10 700 s (~3 h persistent breach), 70 × 10 s = 700 s. This is the one deliberate unit change versus v11; no other constant changed. STEP = 0.023 is the measured protocol ratchet (whole band shifts down a fixed ~2.3% per reset — measured on chain, not fitted).
4.2 The input contract: SimulateConfig
interface SimulateConfig {
F0: number; // starting real fund reserve
A0: number; // starting real anchor reserve (website always passes 0)
C0?: number; // starting center; null/absent → first price in the series
ntz: number; // no-trade-zone width, fraction (0.03 = 3%)
fee?: number; // swap fee, default 0
profit?: number; // house profit margin, default 0
rho: number; // center-to-ceiling ratio C0/M0, protocol constant per pool
SL?: number; // arb slice = appetite dial, default 1.0 (full take to parity)
G?: number; // gas gate: min arb profit per take, default 0 (gate-free)
W?: number; // recovery wait: min seconds between fills, default 0
REBAL?: boolean; // recentering on/off, default true
}
And the price series: prices: [t_seconds, ext_price][], strictly increasing t. Ticks with ext <= 0 or falsy are skipped (bad candle guard).
4.3 The output contract: SimulateResult and TraceRow
type TraceRow = [t, ev, ext, marginal, C, amount, F, A, iF, iA]
// ev: 'RC' (recenter) | 'SELL' (pool sells fund, anchor comes IN)
// | 'BUY' (pool buys fund, anchor goes OUT)
// marginal = (A+iA)/(F+iF) — the pool's own price
// amount = anchor amount of the fill (x for SELL, ao for BUY; 0 for RC)
interface SimulateResult {
F; A; iF; iA; C; // final state
fills; recenters; // event counts
gross_sell_anchor; // Σ anchor in (all SELL fills)
gross_buy_anchor; // Σ anchor out (all BUY fills)
trace: TraceRow[]; // every event, in time order
}
Everything the website draws — beads, cylinders, playback, headline — is derived from trace plus final state. There is no second data path.
4.4 SELL/BUY naming convention (read this twice)
Events are named from the pool's perspective: - SELL = the pool sells fund token to an arb. Happens when price rises above the ask. Anchor flows in. Drawn red on the chart. - BUY = the pool buys fund token back from an arb. Happens when price dips below the bid. Anchor flows out. Drawn green.
This mirrors the on-chain convention (trade direction is pool-perspective in the ledger too).
5. The recenter state machine
The exact logic, from the code (both Python reference and TS port are identical):
State: breach (timestamp of first tick below floor, or null), chasing (bool), last_step (timestamp of last recenter).
Per tick with price ext (only when REBAL is true):
- If
ext < C·(1−ntz)(below floor): ifbreachis null, setbreach = t. - Else (at/above floor):
breach = null; chasing = false. Any single recovery tick fully disarms the gate. - If
breachis armed: the required persistence is - not chasing:
t − breach ≥ COOLDOWN_S(10 700 s ≈ 3 h) - chasing:
t − last_step ≥ BURST_S(700 s) - When persistence is met, step:
Cn = max(ext, C·(1−STEP)) // down at most 2.3%, never below market C = Cn (iF, iA) = rearm(F, A, C, rho) // §6.1 — marginal lands ON Cn chasing = true; last_step = tA trace row[t,'RC', ext, marginal, C, 0, F, A, iF, iA]is appended. - After stepping, if
ext ≥ C·(1−ntz)(the step brought the floor down to the market):breach = null; chasing = false— the chase ends.
So a deep crash produces: one ~3-hour wait, then a chain of 2.3% steps every ~11⅔ minutes until the floor catches the price. That is exactly the staircase of blue diamonds you see on the chart during a crash.
6. The fill math, step by step
6.1 rearm — the recenter construction (proven exact)
r = √( min(rho, 0.999999) )
iF = F·r / (1−r)
iA = (F+iF)·Cn − A
Given real reserves F, A and a new center Cn, this re-derives the imaginary reserves so the pool's marginal price (A+iA)/(F+iF) equals Cn exactly. Verified 100.00% on 7 654 real recenter events (anchor leg). The min(rho, 0.999999) clamp only guards the r→1 pole.
6.2 Headrooms, ask, bid
Every tick:
h_s = 1 / ((1−profit)·(1−fee)) // sell headroom (>1)
h_b = (1−ntz)·(1+fee) // buy floor (<1)
Ft = F + iF; At = A + iA; k2 = Ft·At
ask = At / (h_s·Ft) // pool sells fund above this
bid = h_b·At / Ft // pool buys fund below this
If Ft ≤ 0 or At ≤ 0, or t − lastf < W (recovery wait not elapsed), the tick makes no fill.
6.3 SELL fill (ext > ask, and F > 0)
The arb pushes anchor in until the pool's marginal price reaches external parity — closed form:
x = SL · ( √(ext·h_s·k2) − At ) // anchor in (SL slices the full take)
fo = h_s·x·Ft / (At + x) // fund out
if fo > F: // real-inventory clamp (bytecode: revert out>real)
x = F·At / (h_s·Ft − F) (if denominator > 0)
fo = F
gain = ext·fo − x // arb's profit at external price
if gain ≥ G and x > 0: A += x; F −= fo; gross_sell_anchor += x
6.4 BUY fill (ext < bid, and A > 0)
Symmetric — the arb pushes fund in:
y = SL · ( √(h_b·k2/ext) − Ft ) // fund in
ao = h_b·y·At / (Ft + y) // anchor out
if ao > A: // real-inventory clamp
y = A·Ft / (h_b·At − A) (if denominator > 0)
ao = A
gain = ao − ext·y
if gain ≥ G and y > 0: F += y; A −= ao; gross_buy_anchor += ao
6.5 What the dials mean physically
- SL (Appetite) slices the parity take: SL=1.0 means arbs take the full profitable amount every opportunity ("Hungry"); 0.25 means a quarter ("Medium"); 0.1 a tenth ("Low"). This is the arb-flow-intensity dial — the honest way to express "we don't know how aggressive arbs will be."
- G is a gas gate: an arb only trades if its profit
gainclears G. 0 = gate-free reference behavior. - W is a recovery wait: minimum seconds between fills (models the real drip/impact-cap behavior where a rebalance executes as capped slices with recovery pauses, not one giant trade).
7. Flow charts
7.1 The whole system — data flow
visitor's phone/browser
│ pastes CONTRACT ADDRESS (identity law: never a symbol)
▼
┌─────────────────────────┐ POST /api/jobs {address}
│ one-what-if.pages.dev │ ─────────────────────────────┐
│ static site (Vite, │ ▼
│ Cloudflare Pages) │ ┌────────────────────────────┐
└─────────────────────────┘ │ one-whatif-ingest (Worker) │
▲ │ D1 "whatif-jobs": jobs row│
│ GET /api/series/{addr} │ cron: * * * * * (1/min) │
│ (409 until ready) └──────────────┬─────────────┘
│ │ oldest active job
│ ▼
│ queued ──► pick best pool (GeckoTerminal
│ /tokens/{addr}/pools, sort by
│ 24h volume, gate ≥ $5k liquidity)
│ │
│ fetching ─► 5-min OHLCV candles, ≤18 pages
│ per tick, back to 183 days;
│ each page batch → R2 chunk
│ chunks/{addr}/{cursor}.json
│ │
│ assemble ─► dedup + sort + drop close≤0;
│ FAIL if span < 14 days;
│ series/{addr}.json (meta+prices)
│ │
└────────────────────────────────────────────────┘
status: ready
then, entirely IN THE BROWSER (no server math):
series prices ─► transform (optional min/max remap, log-space)
─► simulate(prices, cfg) ← engine/src/index.ts
─► trace + final state
─► chart, beads, cylinders, playback, HEADLINE
7.2 simulate() — one tick
for each (t, ext) in prices:
│
ext valid? ──no──► skip tick
│yes
▼
┌── RECENTER BLOCK (if REBAL) ──────────────┐
│ ext < C·(1−ntz)? │
│ yes → arm breach (if unarmed) │
│ no → disarm breach, stop chasing │
│ armed AND waited long enough │
│ (COOLDOWN_S first, BURST_S while chasing)?│
│ yes → C = max(ext, C·(1−STEP)) │
│ rearm iF,iA ; trace 'RC' │
│ floor caught price? → stop chase │
└───────────────────┬───────────────────────┘
▼
┌── FILL BLOCK ─────────────────────────────┐
│ totals ok AND t−lastf ≥ W ? │
│ ext > ask AND F>0 → SELL (§6.3) trace │
│ ext < bid AND A>0 → BUY (§6.4) trace │
│ else → no fill │
└───────────────────┬───────────────────────┘
▼
next tick
7.3 The recenter state machine
┌───────────┐ ext < floor ┌──────────┐
│ QUIET │───────────────►│ ARMED │
│ breach=∅ │◄───────────────│ breach=t │
└───────────┘ ext ≥ floor └────┬─────┘
▲ │ t−breach ≥ 10700 s
│ step brought floor ▼
│ down to market ┌──────────┐
│ (ext ≥ new floor) │ CHASING │──┐ t−last_step ≥ 700 s
└──────────────────────│ │◄─┘ → step again
or ext recovers └──────────┘ (2.3% max each)
7.4 The ingest job lifecycle
POST /api/jobs ──► queued ──► fetching ──► ready
│ │
│ └──► failed ("No valid price data",
│ "under 14 days of price history")
└──► failed ("no pools with real liquidity",
"best pool liquidity under $5k — data too
thin to simulate honestly")
8. The trust chain
How we know the TypeScript engine in the browser is the real mechanism and not a vibe:
reference/lpx_reference_core.py— FROZEN. Never edit it. It was extracted verbatim frommultipool_whatif_v11.py, the research engine whose fill core was proven against deployed bytecode: per-trade exact to 1e-4..1e-5 on 2000+ real trades; recenter anchor leg 100.00% on 7 654 events; zero fitted per-trade constants. Everything database-bound was removed; only the pure simulator remains.reference/golden_fixtures.json— input/output pairs generated by running the frozen Python core. Includes arel_tolfor float fields.engine/test/parity.test.ts— loads the fixtures and requires:fillsandrecentersexactly equal; trace length exactly equal; every state field and every trace-row float withinrel_tol; plus determinism (same call twice → identical JSON), statelessness (interleaved runs don't contaminate), and performance (crash_chain_mediumunder 250 ms). PrintsPARITY_PASS fixtures=… rows_checked=….
Law: the parity tests are untouchable. Any PR that edits the frozen reference, the fixtures, or weakens the parity test is wrong by definition — the engine port must bend to the reference, never the reverse. Every Jules brief for this repo carries this clause.
9. The website
Source: web/index.html (layout), web/src/main.ts (1 162 lines — all logic), plus four small pure modules with their own tests.
9.1 Controls (index.html)
- Band Width (ntz) slider: 0.5%–30%, default 3.0%.
- Min Price / Max Price: optional remap of the raw history into a chosen price range (see transform, §9.4).
- Appetite select: Low = 0.1, Medium = 0.25 (default), Hungry = 1.0 → passed to the engine as
SL. - Advanced (collapsed): F0 = 1 000 000, rho = 0.0117, fee = 0.0029, profit = 0.01.
- Play button → the 15-second animated playback.
9.2 Starting position — A0 = 0, always
The what-if models "I held 100% of my coin": the position starts as F0 fund tokens and zero anchor. Everything the anchor pile becomes is generated by the mechanism itself. This is deliberate and load-bearing for the headline (§10).
9.3 The appetite range — honesty law in code
The site runs the simulation three times, once per appetite [0.1, 0.25, 1.0], and displays the anchor net flow as a range (Low → Hungry). The single number for the selected appetite drives the visuals; the range is always shown so no single arb-intensity guess is presented as truth.
9.4 transform.ts — the min/max price remap
transformPrices(prices, minTarget, maxTarget) maps the raw series into the user's chosen [min, max] in log space (affine on ln p), preserving the shape of the history while letting the user ask "what if this token traded between 0.01 and 0.05". Degenerate cases: min == max → constant series at that value; constant raw series → constant at the geometric midpoint √(min·max).
9.5 aggregate.ts — detail levels
Levels 5m | 1h | 1d | 1w. Buckets plot their close (last raw point), timestamped at bucket start; the partial trailing bucket keeps its last real close. getAutoLevel picks the finest level keeping ≤ 2 buckets per canvas pixel. 5m is the raw series (source candles are 5-minute).
9.6 zoom.ts / axis.ts
Zoom keeps the anchor-point time at the same screen fraction (anchor-ratio invariant), min window 3 000 s (10 raw candles), clamped to data bounds; pan clamps at the edges. Axis ticks: time steps ladder from 1 minute to 3 months with UTC labels; value ticks snap to 1/2/5 × 10ⁿ with k/M suffixes and exponential formatting below 0.01.
9.7 What the chart draws
- Price line (the external history).
- C line (band center) in blue; band floor
C·(1−ntz)dashed. - SELL beads red, BUY beads green (pool perspective, §4.4), RC diamonds blue.
- Below: the reserves chart; then the hero card with the headline and the two glass cylinders — fund teal
#07969b, anchor gold#e8a000, with a visual fill floor of 0.34 so a nonzero pile never renders invisibly small. - Play animates the entire history in ~15 seconds: chart sweep, cylinders filling/draining, headline counting.
9.8 Display law for deltas
Negative deltas render with two decimals: −X.XX%. Positive with one: +X.X%. (Yahya's standing format law.) Headline text: +X.XX% MORE {SYM} THAN JUST HOLDING / −X.XX% BEHIND JUST HOLDING — the headline keeps two decimals both ways per the implemented main.ts.
10. The headline math
The single most important formula on the site, from web/src/main.ts:
const lpCoin = currentF + (currentPrice > 0 ? currentA / currentPrice : 0);
const hodlCoin = F0 + (currentPrice > 0 ? A0 / currentPrice : 0);
const pct = (lpCoin / hodlCoin − 1) * 100;
Value BOTH piles in coin, at the CURRENT market price. The LP position is its fund tokens plus its anchor pile converted to coin at today's price; the holder benchmark is the original F0 (A0 = 0, so hodlCoin = F0). The headline compares whole position to whole position — never the fund pile alone (that was a real bug, fixed in commit "count the WHOLE position in coin, not the fund pile alone").
Why this is the honest comparison: the vs-HODL headline must include both sides plus accumulated yield-in-anchor; and the terminal conversion of the anchor pile at the (often crashed) end price is where most of the "more coin" comes from — on measured history roughly 80% of the coin gain is that terminal convert. Skipping it, or converting along the way at interim prices for a stable anchor, misstates the mechanism (see §13).
11. Data provenance
"The contracts, where it gets from everything." Every data artifact and its exact source.
11.1 Price history — GeckoTerminal (free)
- API base:
https://api.geckoterminal.com/api/v2(wrangler varGT_API_BASE). - Pool discovery:
GET /networks/pulsechain/tokens/{address}/pools?page=1&sort=h24_volume_usd_desc. - Candles:
GET /networks/pulsechain/pools/{pool}/ohlcv/minute?aggregate=5&limit=1000¤cy=usd&token={base|quote}withbefore_timestampcursor paging (GT returns descending time). - Series prices are candle closes; candles with close ≤ 0 are dropped.
- GeckoTerminal's WAF rejects UA-less requests: the worker sends a full browser User-Agent and versioned Accept (
application/json;version=20230302) and logsGT {status} {url}forwrangler tail. 429s are handled by simply retrying next cron tick (no backoff state needed at 1 req-burst/min). Known constraint: GT has rate-limited Cloudflare-egress fetches aggressively even with the browser UA — heavy bulk fetching (like catalog builds) runs from the Mac instead (catalog/build_token_catalog.mjs); the worker's slow one-job-per-minute drip is what makes ingest viable from Cloudflare at all.
11.2 The ingest worker (ingest/)
Cloudflare Worker one-whatif-ingest. Bindings (ingest/wrangler.toml): D1 database whatif-jobs (id e3545326-965c-4d11-ab07-d57ccf0d1b76), R2 bucket whatif-data, cron * * * * *.
- Jobs live in D1, keyed by lowercase address, states
queued → fetching → ready | failed(§7.4). One job per cron tick, oldestupdated_atfirst. - Pool choice: pools sorted by 24h volume; best pool must have ≥ $5 000 liquidity or the job fails with "data too thin to simulate honestly". The token's side (base/quote) is detected by matching the address against the pool's base token id; the display symbol is split from pool name "BASE / QUOTE".
- Backfill: 183 days target, ≤ 18 pages per tick, cursor = oldest timestamp in each page.
- Chunks: each tick's candles → R2
chunks/{address}/{cursor}.json. - Assembly: read all chunks, dedup by timestamp, sort ascending, require ≥ 14 days span, write R2
series/{address}.jsonas{meta, prices}. - API (api.ts):
POST /api/jobs(validates^0x[40 hex]$, idempotent — an existing job is returned as-is with 200; new job 202),GET /api/jobs/{addr}(status +progress_days),GET /api/series/{addr}(the series JSON; 409 with job status while not ready). CORS*.
11.3 The series meta contract (types.ts SeriesMeta)
Every series file self-describes: token, token_contract, anchor, source, network, pool, pool_name, timeframe_minutes (5), candles, span_start, span_end, fetched_at, note. Consumers must read provenance from here, never assume it.
11.4 The bundled demo series
data/sample_prices_wpls_dai.json: WPLS (contract 0xa1077a294dde1b09bb078844df40758a5d0f9a27), pool DAI/WPLS 0xe56043671df55de5cdf8459710433c10324de0ae, 48 600 five-minute candles, real market snapshot "used as the demo scenario texture."
11.5 The token catalog
catalog/token_catalog_pulsechain.json (built by catalog/build_token_catalog.mjs, run from the Mac): 138 tokens ranked, 729 pools walked across 6 dexes (pulsex, pulsex-v2, velocimeter-pulsechain, eazyswap, pulse-rate, phux), liquidity gate $5 000 (112 tokens rejected), 48 with images — image_url null means the front-end must render a fallback badge. Rank rule: first appearance in global-then-per-dex pool pages sorted by 24h volume.
11.6 The measured-truth database (NOT shipped with the site)
lpx.db at ~/.orchestra/plusx/lpx.db — the on-chain indexed ledger. READ-ONLY law: always open with mode=ro. The engine constants and all arb knowledge (§12) were measured here, not in this repo. Key tables for the what-if lineage:
trade_yield— 122 673 trades with maker/arb yield split, pro-rata from real claims, zero fitted constants. Per-claim is the finest REAL granularity (true per-trade yield is proven NOT log-recoverable). Landed 2026-07-06 alongsiderecon_claims; human copy TRADE_YIELD.xlsx.c_dex_swap_logs— 472k rows of true external DEX prices (the arb simulator's ground truth).c_band_history,c_pool_start_funding— per-decimal-verified reserve columns and clean F0. Data-integrity trap: an indexer mislabeling family exists (profit-named columns that are really reserves/volume; blanket /1e18 corrupts non-18-decimal pools like HEX/USDC). Trust only per-decimal-verified columns; a schema tripwire guard lives at~/.orchestra/schema_guard.- SQL trap: after
ATTACH, qualifyDROP TABLE main.x.
12. The Arb book
Everything the arbs ("the Arbys") taught us, distilled from the alpha team's verified final report (~/.orchestra/plusx/lpx_sim/alpha_agy_out.md, machine-verdict PASS_ARB_MISSION) and the measurements on lpx.db. This is the knowledge that took the overnight grind — do not re-derive it.
12.1 The two kinds of yield
- Maker yield — the pool's structural take from its sell-high/buy-low asymmetry (profit margin + fee). Modelable per fill directly from the engine's own flows.
- Arb yield — the extra flow arbs generate closing gaps to the external market. Exogenous. The honesty law exists because of this line.
12.2 The arb norm — lifetime ratio arb ≈ NORM × maker
Measured on disk per pool (lifetime arb-yield / maker-yield):
| pool | lifetime norm |
|---|---|
| 1 | 0.2096 |
| 4 | 0.292 |
| 5 | 0.2243 |
| 8 | 0.2534 |
| 13 | 0.1991 |
| 14 | 0.2087 |
Healthy pools cluster 0.20–0.29, center ≈ 0.23. Protocol-wide median including everything: 0.40 (i.e. total ≈ maker × 1.4). The old fitted 0.232 is rehabilitated as a LIFETIME estimator only — using it per-trade or for timing stays banned. Manipulated/volatile pools are wild outliers; do not apply the norm there.
Regime split: trending markets ≈ 0.11–0.12; sideways ≈ 0.24–0.28. AUTO mode (in the optimizer brief): per window compute trend efficiency E = |net move| / Σ|per-step moves|; E ≥ 0.6 → norm 0.12, E ≤ 0.2 → 0.26, linear blend between.
12.3 The per-trade arb law (and its limit)
arb_yield = C × gap × |fund_amt|, gated at the band edge (arb only fires when the external gap opens past the band). Pool-1 fitted C = 0.062 gives +3.64% error; a global C = 0.064 gives +6.98% and closes 8/10 pools. But C drifts ~8× across regimes (Pool 1: window-1 C = 0.0127 vs window-2 C = 0.0986) — unexplained, OPEN (§15). Theoretical capture ratio is 4.0, deflated in practice to ≈ 0.084 by discretization, fees, and reserve saturation; no closed form known.
12.4 The gate-not-dial law
The arb ratio is a GATE, not a DIAL: arb behavior is per-trade mechanistic (fires when the gap crosses the band edge), and the "tune a fraction" approach was falsified out-of-sample. This is why the engine models arbs as parity-takers behind a gate with an intensity slice (SL), not as a fitted yield multiplier.
12.5 The 7% gap story (why sim matched reality)
The sim-vs-actual gap on real pools was solved by two findings, conductor-verified: 1. Unmodeled PENDING yield — yield earned but not yet claimed. Pool 1: 690.38 maker + 155.62 arb = 846 DAI pending = 18.7% of lifetime yield; accounting for it took the gap 6.39% → 2.6%. 2. The column-swap fallacy — a "fix" swapping two loader columns was mathematically impossible (it implied 5.1% vs 110% pending/claimed ratios; without the swap both sit ~23%). It was REMOVED. After removal: pool 4 went −7.5% → −3.50% PASS; 6/7 pools within 5%.
12.6 Known outlier pools (don't panic when they don't fit)
- Pool 2: staked-multiplier double-count in the ledger; corrected norm 0.048.
- Pools 42/43/44 (HELGO): a routing bug in measurement; correct route HELGO→HEX→WPLS→DAI; corrected norms 0.098–0.128.
- "Zero arb" entries in the ledger are data gaps, not true zero (Yahya called this correctly).
12.7 Other measured laws worth having in one place
- Maker law: per-pool fill-size dispersion σ = 0.39 × ntz.
- Recenter timing is endogenous — the outside chart gives step size, direction, and regime but NOT when a recenter fires; timing depends on the pool's own persistence gate (this is why the engine simulates it rather than reading it off the chart).
- An LPX rebalance on chain executes as impact-capped slices with recovery waits and a gas gate — not one trade per band crossing. The engine's W and G dials model exactly this; it also explains chart-vs-real trade-count mismatches.
13. Yield accounting laws
How to convert engine flows into honest yield numbers:
- Stable anchor (e.g. DAI): accumulate arb+maker yield in the anchor through the whole run, convert to fund token ONCE at the END price. That terminal convert at a crashed low price is ~80% of the coin gain. Converting along the way understates the mechanism.
- Volatile anchor (e.g. WPLS as anchor): convert per-window at that window's price. Once-at-end overstates arb yield by ~40% (measured, pool 32).
- The 50/50 split language in old notes means the yield COMPOUNDING split, not a fund/anchor holding split.
- The vs-HODL headline includes yield — both sides plus yield, whole position vs whole position (§10).
14. Validation history
The lineage that lets us trust every number:
- v11 core (the one ported here): curve-true invisible-token fill core, per-trade exact to 1e-4..1e-5 on 2000+ real trades against deployed bytecode; recenter anchor leg 100.00% on 7 654 events; zero fitted per-trade constants. Vault math is EXACT; the only residual is arb-flow intensity, which is a scenario INPUT (the appetite dial), not a model parameter.
- Accuracy on real pools: median worst-case error 13.86%, direction correct 28/31 pools (beats v10's 15.43%); after the pending-yield + loader fixes, 6/7 major pools within 5% of actual.
- The invisible-token model itself was PROVEN (imaginary reserves; x·y=k on real+imaginary), and the recenter law (fixed ~2.3% whole-band down-step, ceiling pinned) measured on chain.
- Independent replication: three models blind-derived the recenter law from the data; note that ~128 genuine up-steps exist on chain (rare regime, engine deliberately models the dominant down-ratchet; up-trend validation is task #14, in progress).
- TS port: parity-tested to the frozen Python core (§8) —
PARITY_PASSwith exact event counts and per-row float tolerance.
15. Open questions
Honest unknowns at writing time. A future agent picking one of these up should start from the alpha report and lpx.db, not from scratch:
- The ~8× capture drift. Per-trade capture C moves from 0.0127 to 0.0986 between windows on the same pool. Unexplained. Until it is, per-trade arb prediction stays banned (norms are lifetime-only).
- No closed form for the capture ratio (theoretical 4.0 → measured ≈ 0.084 through discretization/fees/saturation).
- Up-trend validation (task #14) and token/token anchor math — engine proven mostly on down/sideways histories.
- Gap tokens (HELGO/uPLS/PRINT/HDRN + tail) still need off-chain price backfill (task #5).
- In-flight builds: the creation-wizard site build and the optimizer + yield-layer build (arb norm ladder, §12.2) are dispatched to Jules; the optimizer must ship the verbatim honesty label (§2).
16. Glossary of every symbol
| symbol | meaning |
|---|---|
| F, A | real fund / anchor reserves (actual tokens) |
| iF, iA | imaginary fund / anchor reserves (bookkeeping; the invisible token) |
| Ft, At | totals F+iF, A+iA — the curve trades on these |
| k2 | Ft·At, the constant-product invariant on totals |
| C | band center price |
| Cn | new center after a recenter step |
| M | band ceiling; rho = C0/M0 (protocol constant, UI default 0.0117) |
| ntz | no-trade-zone width; band floor = C·(1−ntz) |
| STEP | 0.023 — max fractional down-step per recenter |
| COOLDOWN_S | 10 700 s — first-breach persistence (1070 blocks × 10 s) |
| BURST_S | 700 s — chase-mode re-step interval (70 blocks × 10 s) |
| fee | swap fee (UI default 0.0029) |
| profit | house profit margin (UI default 0.01) |
| h_s | sell headroom = 1/((1−profit)(1−fee)) |
| h_b | buy floor = (1−ntz)(1+fee) |
| ask | At/(h_s·Ft) — pool sells fund above this |
| bid | h_b·At/Ft — pool buys fund below this |
| ext | external market price (the candle close) |
| marginal | (A+iA)/(F+iF) — the pool's own price |
| SL | appetite / arb-flow-intensity slice (0.1 / 0.25 / 1.0) |
| G | gas gate — min arb profit per fill |
| W | recovery wait — min seconds between fills |
| x, fo | SELL fill: anchor in, fund out |
| y, ao | BUY fill: fund in, anchor out |
| gain | arb's profit on a fill, must clear G |
| SELL / BUY | pool-perspective event names (§4.4) |
| RC | recenter event |
| F0, A0 | starting reserves; website: F0 = 1 000 000, A0 = 0 always |
| lpCoin / hodlCoin | whole positions valued in coin at current price (§10) |
| NORM | lifetime arb/maker yield ratio (§12.2) |
17. File map
lpx-whatif/
├── README.md product name, house laws, layout, engine summary
├── docs/BIBLE.md THIS BOOK (also served at /bible.html on the site)
├── reference/
│ ├── lpx_reference_core.py FROZEN Python source of truth — NEVER EDIT
│ └── golden_fixtures.json reference outputs + rel_tol for parity
├── engine/
│ ├── src/index.ts the TS engine (constants, rearm, simulate)
│ └── test/parity.test.ts untouchable parity/determinism/perf tests
├── web/
│ ├── index.html controls, chart, hero card, answer card
│ ├── public/bible.html rendered Bible (built from docs/BIBLE.md)
│ └── src/
│ ├── main.ts all site logic incl. headline math (1 162 lines)
│ ├── transform.ts log-space min/max remap
│ ├── aggregate.ts 5m/1h/1d/1w close-bucket levels + auto level
│ ├── zoom.ts anchor-invariant zoom + clamped pan
│ └── axis.ts time/value tick generation
├── ingest/
│ ├── wrangler.toml worker one-whatif-ingest, D1 whatif-jobs, R2 whatif-data, cron 1/min
│ └── src/ index (fetch+scheduled), api, cron, gecko, store, types
├── catalog/
│ ├── build_token_catalog.mjs Mac-side catalog builder (GT rate-limit workaround)
│ └── token_catalog_pulsechain.json 138 ranked tokens, $5k gate, 6 dexes
├── data/sample_prices_wpls_dai.json bundled real WPLS/DAI demo history
└── vite.config.ts root=web, build → dist/, vitest incl. engine tests
External (NOT in repo):
~/.orchestra/plusx/lpx.db measured truth (READ-ONLY, mode=ro)
~/.orchestra/plusx/lpx_sim/alpha_agy_out.md the alpha team's final arb report
~/.orchestra/plusx/BRIEF_jules_optimizer_arb_norm.md optimizer build brief (norm ladder)
End of the Bible. If you change the system, change this book in the same commit — a stale Bible is worse than none.