The offline maker-sim gate harness is BUILT, per-task-reviewed, final-reviewed, and READY-FOR-GATE-RUN — subagent-driven, deterministic end-to-end, 15/15 tests, clippy/fmt clean. The study asks whether a maker (resting-order) fill posture recovers the edge that taker fills lose to last-look adverse selection. No gate has run yet — the calibration/confirmatory runs are blocked on live data fetches that had to be rerouted to the deploy/infra VM (Cloudflare now TLS-resets this workstation). This is the build-completion checkpoint that follows the spec grounding round.

For Agents

The lane stays SHELVED regardless of this build. Building the harness is not a decision to trade — the gate can only produce a KILL or a “passed, escalate to a separate Phase-2 decision” verdict. The load-bearing outputs here are (a) the harness design + its pre-registered rules, (b) two bugs the review loop caught in the plan’s own reference code, (c) the fee verdict that sets the PRIMARY gating number, and (d) two durable environment gotchas (Cloudflare TLS-reset + pooler prepared-statement break) that will bite any future live-data run.

What was built

All subagent-driven, each task peer-reviewed, then a final cross-cutting review pass.

crates/analysis/src/bin/makersim.rs — the sim harness

  • Quote engine — posts maker quotes from lagged book snapshots / pulls (models a resting order that cannot react instantly).
  • Bracketed fill engine — the pessimistic bracket assumes adverse-certain / at-quote fills with φ = 0.25 (a resting quote gets hit precisely when it is about to be wrong).
  • Inventory cap ±3, hold-to-settlement — no intra-window unwind; bounded exposure.
  • Day-clustered bootstrap z-stat — the same day-clustering used across the Phase-0 gates (never window-level, which understates variance).
  • Fixed 48-config grid — pre-registered, no post-hoc grid growth.
  • 15/15 tests pass, clippy + fmt clean, deterministic end-to-end (seeded).

Three fetch scripts + a DRY common module

  • makersim_resolve_markets — fired-window condition_id → CLOB /markets/{condition_id} (the resolution path from the grounding round; gamma slug query is broken for 5m).
  • makersim_clob_winners — CLOB tokens[].winner backfill (mandatory for ALL scored 5m windows — resolved_up is unusable at the 53% 5m near-tie rate).
  • makersim_tape_backfilldata-api /trades?market={conditionId} taker tape.
  • makersim_common — shared logic extracted (DRY) across the three scripts.
  • All four are fixture-proven offline (unit-tested against recorded fixtures, no live calls needed to validate their logic).

Review loop caught two bugs in the plan’s OWN reference code

The per-task + final review found the specification’s reference implementation was itself wrong in two places — a good argument for the review loop over trusting a plan’s sample code:

  1. Unsorted-prints self-inconsistency — reference code processed prints in nondeterministic order, so identical inputs printed different results. Fixed by an internal stable sort before processing.
  2. Unresolved-CLOB-market silent Down-label — a market that failed CLOB resolution was silently labeled Down (a false, tradeable-looking label). Fixed by an exactly-one-winner guard that hard-fails instead of mislabeling.

Pre-registered rule added before any data existed

Untraded (0-print) windows COUNT in the bootstrap denominator

Final review pre-registered this before any data was fetched (survivorship rationale): a maker posture that simply declines to quote in hard windows must not get to drop those windows from its EV denominator. Locked into the spec addendum so the result can’t be gamed after the fact.

All 7 accumulated minor review findings were triaged DEFER — none blocking for the gate run.

Fee verdict — the 0.07-charged variant is the PRIMARY gating number

Live 5m market advertises maker_base_fee == taker_base_fee

The live 5m updown market returns maker_base_fee = 1000 == taker_base_feemaker_fee_zero: false. A maker posture does NOT escape the fee on these markets. Therefore the 0.07-fee-charged variant is the PRIMARY number the gate is judged on, not a hypothetical zero-maker-fee variant.

This directly kills the naive “makers pay no fee” income assumption and connects to the rebate audit (maker-rebate = $0, we are pure takers, venue fee = exactly 0.07). Verification artifact: data/makersim/fee_verification.md.

Environment gotchas (durable — will bite any future live-data run)

*.polymarket.com Cloudflare TLS-resets this workstation since ~11:00Z 2026-07-22

After ~3k API calls that morning, Cloudflare began TLS-resetting this workstation on all *.polymarket.com, AND it blocks agent sandboxes too. All live fetches were rerouted to the deploy/infra VM (babylon #1242 / #1243 staged handoff; the fetch scripts are resumable). Any future Polymarket live pull from this box should expect to be reset and should route through the VM.

sqlx + transaction-mode pooler (:6543) breaks on prepared statements at process rerun

The transaction-mode pooler (:6543) breaks sqlx prepared statements when a process reruns (statement-name collisions across pooled sessions). Gate runs must use the session-mode pooler (:5432). The same latent issue exists in walkforward.rs — worth fixing there before the next walk-forward run. (Complements the standing direct-DB-is-IPv6-only note: use the pooler, but the session-mode one for rerun-safe prepared statements.)

State and the pre-committed gate chain

Waiting on deploy’s VM runs: markets → winners → tape (~10–25k polite calls; the tape back-transfer is ~0.5–1.5 GB). Then the pre-committed chain runs:

  1. Task 8 — sanity STOP-gate (data-integrity checks before any scoring).
  2. Task 9 — calibration gate. KILL rule: if no lag==1 config reaches z ≥ 3.07 under the pessimistic 0.07-fee bracket, the study dies here. (z ≥ 3.07 = the multiple-testing-deflated bar for the 48-config grid.)
  3. Task 10 — a single confirmatory run (minimal-trials discipline — one shot, pre-registered).

The lane remains SHELVED regardless

Even a full pass of Tasks 8→9→10 does not re-arm anything. It only clears the gate; a separate Phase-2 decision (Andras) is required before any live posture. A KILL at Task 8 or 9 ends the maker-sim direction and the lane stays shelved with observe recording.

Artifacts

  • Plan: docs/superpowers/plans/2026-07-22-maker-sim-gate.md
  • Spec: docs/superpowers/specs/2026-07-22-maker-sim-gate-design.md (v2 + addendum with the 0-print-denominator pre-registration)
  • SDD ledger: .superpowers/sdd/progress.md
  • Harness: crates/analysis/src/bin/makersim.rs
  • Fetch scripts: makersim_resolve_markets, makersim_clob_winners, makersim_tape_backfill, makersim_common
  • Fee verification: data/makersim/fee_verification.md