{
  "notes": "EPISODE 3 (2026-11-07). STATE: wave r1 (13 code items) still running: 13 running, 0 accepted, 0 failed, no trunk yet. writeups (2) and theory (1) research items running. Nothing handed. Episode 2's anchors batch was REFUSED: its brief asked about the worker's machine (I had asked for a cross-machine determinism check with machine details). Lesson: never ask a worker anything about its host; compare two items' per-seed edges myself instead. DECIDED: (a) anchors2, 4 research items (vanilla-a/b = VanillaStrategy 30 bps, starter-a/b = StarterStrategy 50 bps) scoring the requester's calibration set 900000..909999 via run_batch with explicit seeds, chunked, 40-minute cap with the covered prefix reported, first 10 per-seed edges to 6 decimals; a and b of the same file must agree exactly or local runs are not bit-reproducible across workers and every paired comparison must then run inside one item. (b) r1x, 4 research items with mechanisms NOT in r1 (edge-max = closed-form expected-edge maximiser from router share + online sigma/lambda/size; one-sided = cheap side/wide side flipped by last arb direction; arb-vol = realised sigma from consecutive arb-implied prices; param-lookup = estimate sigma/rate/size early then pick a fee pair from an offline-tuned table). Research mode so results arrive as JSON with the full .sol even if the wave never merges; they pair against StarterStrategy on 300000..301999 (episode-3 fresh block) and report score on 0..999. Items used after this episode: 24 of 600. Wake: r1 settles or 720 min. Reads: r1/* (13), anchors2/* (4), r1x/* (4).\n\nCARRIED FORWARD:\n- Trunk layout (r1/layout writes it): best/Strategy.sol = current best; best/SCOREBOARD.md; candidates/<key>/{Strategy.sol,result.json,NOTES.md}; tools/amm-challenge/ = simulator at commit 6b6921f8 as plain files (no submodule); tools/pair.py A.sol B.sol --seed-start S --n N -> JSON {n, mean_a, mean_b, mean_diff, se, worst, seconds_per_simulation}; tools/README.md = install. Later waves write only candidates/<key>/**; promotion = one item with scope [\"best/**\"]; one scope [] check item per wave; never overlapping scopes. A brief is <=3000 chars, so a best .sol travels only through the trunk, or pasted into a brief if under ~2400 chars (r1x items were told to stay compact for this reason).\n- Seeds: `amm-match run --simulations N` = seeds 0..N-1 (MatchRunner._build_configs: numpy default_rng(seed) draws mean size, rate, sigma; Rust price seed = seed, retail seed = seed+1); per-seed edges via amm_sim_rs.run_batch. POLICY: tune only on 0..99999. Fresh confirmation block for episode e = e*100000..e*100000+1999 (ep1 100000-101999 used by r1; ep3 300000-301999 used by r1x; ep4 400000-401999 next). Promote only when paired mean_diff >= 2*se with n >= 2000 on the episode's fresh block vs the current best. Current best = contracts/src/StarterStrategy.sol (50 bps), no promotion yet, round 1 not yet scored.\n- REQUESTER (02:04Z + 02:25Z correction; follow): calibration set = seeds 900000..909999, default config, run_batch with explicit seeds, report-only, never used to choose. Each round report the best file's mean edge + se on it; anchors (Vanilla 30 bps, Starter 50 bps) once on the same set (anchors2 does this). Say in notes when the best reaches 525, 527, 528 there; near/above 528 = in range, requester submits. Board 2026-11-07: 528.40, 528.32, 528.26, 528.21, 528.10. If anchors2 shows seconds_per_simulation makes 10,000 sims exceed ~40 min per item, split later calibration runs across items by seed prefix (e.g. 4 items x 2500 seeds) and combine: mean = weighted mean, se from pooled per-seed variance.\n- Simulator facts: 10000 steps; GBM per-step sigma U(0.000882,0.001008) fixed per sim; arb each step on each AMM, optimal size leaves spot at band edge (AMM bought X: p = spot_post*(1-bidFee); sold X: p = spot_post/(1-askFee)); Poisson(lambda U(0.6,1.0)) retail, lognormal size mean U(19,21) sigma 1.2, 50/50, router splits each order between us and 30 bps normalizer so marginal prices equalise; fees kept aside. Edge: sell X = amountX*p - amountY; buy X = amountY - amountX*p. TradeInfo: isBuy, amountX, amountY, timestamp, reserveX, reserveY post-trade. Gas 250000/call; solc 0.8.24 viaIR; slots 0..31; no CALL/CREATE/EXT*; max fee 10%.\n- Public write-ups (cite): github.com/jiayaoqijia/amm-challenge-yq (claims 523.21 board; fixed 30 bps ~522.13), github.com/dipankar/amm-challenge, github.com/eliizabethzhang/market-making-challenge. writeups batch (keys likely github, social) extends this.\n- r1 item keys: layout, static-grid, example-tuned, fair-centered, band-state, interval-tracker, router-optimal, vol-estimate, flow-estimate, inventory, size-toxicity, bandit, public-replica.\n\nNEXT EPISODE (4):\n1) If r1 settled: read r1/* and r1x/*; build the scoreboard: per item sha256, score on 0..999, paired mean_diff and se vs starter (r1 on 100000..101999, r1x on 300000..301999), seconds_per_simulation. Best = largest paired diff clearing 2*se; ties by se. Round 1 = r1 + r1x together. If none clears, keep the starter: round 1 counts as no promotion.\n2) Spawn wave r2 (15-20 items + promote item scope [\"best/**\"] + check item scope [] that runs tools/pair.py best vs starter on 400000..401999 and the calibration score of best on 900000..909999 if time allows): ~40% deepen the best (its `next` lines, theory's recommended post-arb policy, best + strongest secondary signal), 30% fresh (unused ideas from writeups and theory), 15% simplify the best, 15% replicate (top two re-measured on 400000..401999 by other workers). If the best came from r1x (research, not in trunk), the promote item gets its compact source pasted into the brief (sha256 stated) and writes best/Strategy.sol. Tell r2 items: trunk has tools/README.md, tools/pair.py, best/Strategy.sol; write only candidates/<key>/**; fresh block 400000..401999; result JSON per objective. No two items the same idea.\n3) If r1 is still running with nothing accepted after ~20 h total, treat the wave as stuck: cancel r1 and run round 1 as research batches (full .sol in JSON, maxBytes 64000, compact code), carrying the best by sha256 + pasted source; promotion then = notes + a later single code wave that writes the trunk from the pasted sources.\n4) If r1 failed widely: read batches[r1].failures, mend (maturin/Rust build time, solc download, numpy) and re-run with itemsFrom failed.\n5) anchors2: record vanilla/starter calibration means + se; check a vs b first_edges agree bit-for-bit; if not, every paired comparison must run inside one item (say so in every brief).\nStop rule: two rounds in a row without promotion, or episode 10. Budget after this episode: 576 items, 7 episodes.",
  "spawn": [
    {
      "name": "anchors2",
      "mode": "research",
      "brief": "Paradigm AMM fee challenge: calibration anchor. Clone github.com/benedictbrady/amm-challenge into a fresh empty directory, check out commit 6b6921f8d463314aa7c96234e1be25a25245f704, install per its README (Rust toolchain, Python>=3.10, maturin, numpy, py-solc-x, pyrevm), and confirm `amm-match validate contracts/src/{{file}}` passes. Score the repository's own contracts/src/{{file}} ({{label}}) with the default config on the fixed calibration set: simulation seeds 900000..909999, in that order. Seeding: MatchRunner._build_configs in the Python package uses numpy default_rng(seed) per simulation to draw mean retail size, retail rate and sigma (in that order) and passes seed to the Rust engine as the price seed and seed+1 as the retail seed; `amm-match run --simulations N` only covers seeds 0..N-1, so replicate _build_configs with explicit seeds and call amm_sim_rs.run_batch (or the runner's equivalent) directly. Read the source to confirm this mapping before relying on it and name the file and function in the result. Run in chunks of 500 seeds. Stop starting new chunks once 40 minutes of simulation have elapsed and report what you covered: the scored set must be a prefix 900000..900000+n-1. Edge per simulation = the engine's edge for the strategy AMM, the figure that `amm-match run` averages into its score. Do not change the simulator or the contract. Return JSON only: {\"strategy\": \"{{label}}\", \"file\": \"{{file}}\", \"commit\": \"6b6921f8\", \"seed_start\": 900000, \"n\": <simulations scored>, \"mean_edge\": <mean edge>, \"se\": <sample std with ddof=1 divided by sqrt(n)>, \"first_edges\": [edges of seeds 900000..900009 in order, 6 decimals], \"min_edge\": {\"seed\", \"edge\"}, \"max_edge\": {\"seed\", \"edge\"}, \"seconds_per_simulation\": <wall seconds of simulation divided by n>, \"seeding_confirmed\": \"<one or two sentences: where the seed mapping lives and whether it matches the description above>\", \"notes\": \"<anything that went wrong, or empty>\"}.",
      "items": [
        {
          "key": "vanilla-a",
          "vars": {
            "file": "VanillaStrategy.sol",
            "label": "vanilla 30 bps"
          }
        },
        {
          "key": "vanilla-b",
          "vars": {
            "file": "VanillaStrategy.sol",
            "label": "vanilla 30 bps"
          }
        },
        {
          "key": "starter-a",
          "vars": {
            "file": "StarterStrategy.sol",
            "label": "starter 50 bps"
          }
        },
        {
          "key": "starter-b",
          "vars": {
            "file": "StarterStrategy.sol",
            "label": "starter 50 bps"
          }
        }
      ],
      "output": {
        "format": "json",
        "maxBytes": 8000
      }
    },
    {
      "name": "r1x",
      "mode": "research",
      "brief": "Paradigm AMM fee challenge, round 1 extra: build one complete strategy from one mechanism and measure it paired. Clone github.com/benedictbrady/amm-challenge into a fresh empty directory, check out commit 6b6921f8d463314aa7c96234e1be25a25245f704, install per its README (Rust, Python>=3.10, maturin, numpy, py-solc-x, pyrevm). Contract: `contract Strategy is AMMStrategyBase` importing only ./AMMStrategyBase.sol and ./IAMMStrategy.sol; afterInitialize() and afterSwap(TradeInfo calldata) return (bidFee, askFee) in WAD (30*BPS = 30 bps; max 10%); slots[0..31] only; no loops over history; must pass `amm-match validate`. Read the Rust engine first: 10000 steps; GBM fair price p, per-step sigma fixed per simulation; each step an arbitrageur trades each AMM if profitable with the size that leaves spot exactly at the fee band edge (after an arb where our AMM bought X: p = spot_post*(1-bidFee); sold X: p = spot_post/(1-askFee)); then Poisson retail orders, lognormal size, 50/50 side, each split by a router between us and a fixed 30 bps normalizer so marginal prices equalise; fees kept aside. TradeInfo: isBuy, amountX, amountY, timestamp (= step), reserveX, reserveY post-trade. Silence between timestamps means no arb hit us. MECHANISM FOR THIS ITEM: {{idea}} Tune constants only on seeds inside 0..99999 (`amm-match run --simulations N` is seeds 0..N-1); then confirm once on the fresh block 300000..301999 (n=2000) paired against contracts/src/StarterStrategy.sol (50 bps) on identical seeds. Per-seed runs: MatchRunner._build_configs uses numpy default_rng(seed) per simulation (draws mean size, rate, sigma in that order), price seed = seed, retail seed = seed+1; replicate it with explicit seeds through amm_sim_rs.run_batch. Paired: d_i = edge_candidate_i - edge_starter_i; mean_diff = mean(d); se = std(d, ddof=1)/sqrt(n); worst = 5 most negative d_i with seeds. Keep the source compact (under 2400 chars, no comments) and gas-light. Return JSON only: {\"approach\": <=600 chars, \"tried\": [variants with paired diff on tuning seeds], \"next\": [up to 3 follow-ups], \"code\": <full .sol>, \"code_sha256\", \"score\": {\"n\": 1000, \"mean_edge\": <seeds 0..999>}, \"paired\": {\"n\": 2000, \"seed_start\": 300000, \"mean_diff\", \"se\", \"worst\": [{\"seed\", \"diff\"} x5]}, \"starter_mean_edge\": <starter on 300000..301999>, \"seconds_per_simulation\", \"validate\": \"pass\" or \"fail: why\"}. Never return a strategy that failed validate or was not measured on 300000..301999.",
      "items": [
        {
          "key": "edge-max",
          "vars": {
            "idea": "Closed-form edge maximiser: on each call choose bid and ask fees that maximise expected retail fee revenue minus expected arbitrage loss over the next step, using the router's split rule (our share of a retail order as a function of our fee against the 30 bps normalizer, from the source), a fixed-gain online estimate of per-step sigma from the fair-price jumps the arbs imply, and of retail rate and mean size from non-arb trades per timestamp. Precompute the mapping as a small piecewise table in code so each call stays cheap."
          }
        },
        {
          "key": "one-sided",
          "vars": {
            "idea": "One-sided quoting: keep one side cheap (well under 30 bps so the router sends it most retail flow) and the other side wide; the cheap side is the one whose retail flow moves reserves back toward the fair price the last arb revealed (an arb that bought X from us means p fell: make our bid cheap and our ask wide, or the reverse if that measures worse); flip on each arb, revert to a tuned symmetric pair after k quiet steps. Tune the cheap level, the wide level and k."
          }
        },
        {
          "key": "arb-vol",
          "vars": {
            "idea": "Realised volatility from arbitrage prints: after each arb the fair price is known exactly (band edge); the squared log-change between two consecutive arb-implied prices divided by the steps between them estimates sigma^2 per step. Keep a fixed-gain average and set both fees as a*sigma*sqrt(expected steps to the next arb)+b, widening the hit side for a few steps. Tune a and b and the gain."
          }
        },
        {
          "key": "param-lookup",
          "vars": {
            "idea": "Parameter lookup: each simulation has fixed sigma, retail rate and mean size. Spend the first 300-500 steps estimating all three (arb-implied price jumps; non-arb trades per timestamp; mean amountY of non-arb trades), then select a fee pair from a lookup table tuned offline on seeds 0..99999 per bucket (3 sigma x 3 rate x 2 size buckets), with a small post-arb widening. Report the table and how much each bucket gains over the single best fixed pair."
          }
        }
      ],
      "output": {
        "format": "json",
        "maxBytes": 64000
      }
    }
  ],
  "read": [
    "r1/layout",
    "r1/static-grid",
    "r1/example-tuned",
    "r1/fair-centered",
    "r1/band-state",
    "r1/interval-tracker",
    "r1/router-optimal",
    "r1/vol-estimate",
    "r1/flow-estimate",
    "r1/inventory",
    "r1/size-toxicity",
    "r1/bandit",
    "r1/public-replica",
    "anchors2/vanilla-a",
    "anchors2/vanilla-b",
    "anchors2/starter-a",
    "anchors2/starter-b",
    "r1x/edge-max",
    "r1x/one-sided",
    "r1x/arb-vol",
    "r1x/param-lookup"
  ],
  "cancel": [],
  "wake": {
    "batches": [
      "r1"
    ],
    "afterMinutes": 720
  },
  "finish": false
}
