The One What-If Bible

The complete book of how the What-If works — engine, arbs, data, laws.

← back to One What-If

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

  1. What this product is
  2. The house laws
  3. The LPX pool mechanism from zero
  4. The engine contract (engine/src/index.ts)
  5. The recenter state machine
  6. The fill math, step by step
  7. Flow charts
  8. The trust chain: frozen reference, golden fixtures, parity
  9. The website (web/src/main.ts and friends)
  10. The headline math — the most important formula on the site
  11. Data provenance — the contracts, where everything comes from
  12. The Arb book — everything the arbs taught us
  13. Yield accounting laws
  14. Validation history — how we know the engine is right
  15. Open questions — the honest unknowns
  16. Glossary of every symbol
  17. 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):

  1. If ext < C·(1−ntz) (below floor): if breach is null, set breach = t.
  2. Else (at/above floor): breach = null; chasing = false. Any single recovery tick fully disarms the gate.
  3. If breach is armed: the required persistence is
  4. not chasing: t − breach ≥ COOLDOWN_S (10 700 s ≈ 3 h)
  5. chasing: t − last_step ≥ BURST_S (700 s)
  6. 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 = t A trace row [t,'RC', ext, marginal, C, 0, F, A, iF, iA] is appended.
  7. 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


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:

  1. reference/lpx_reference_core.py — FROZEN. Never edit it. It was extracted verbatim from multipool_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.
  2. reference/golden_fixtures.json — input/output pairs generated by running the frozen Python core. Includes a rel_tol for float fields.
  3. engine/test/parity.test.ts — loads the fixtures and requires: fills and recenters exactly equal; trace length exactly equal; every state field and every trace-row float within rel_tol; plus determinism (same call twice → identical JSON), statelessness (interleaved runs don't contaminate), and performance (crash_chain_medium under 250 ms). Prints PARITY_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)

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

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)

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 * * * * *.

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:


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

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)

12.7 Other measured laws worth having in one place


13. Yield accounting laws

How to convert engine flows into honest yield numbers:

  1. 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.
  2. 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).
  3. The 50/50 split language in old notes means the yield COMPOUNDING split, not a fund/anchor holding split.
  4. 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:


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:

  1. 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).
  2. No closed form for the capture ratio (theoretical 4.0 → measured ≈ 0.084 through discretization/fees/saturation).
  3. Up-trend validation (task #14) and token/token anchor math — engine proven mostly on down/sideways histories.
  4. Gap tokens (HELGO/uPLS/PRINT/HDRN + tail) still need off-chain price backfill (task #5).
  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.