You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Parts A (#138 — Rust validate_backrun + gRPC publish) and B (#139 — Go executor mempool bundle builder) wire the public-mempool backrun execution path end-to-end. This issue gates that path behind risk controls + a three-stage shadow rollout so we never accidentally submit a live bundle before measurement validates the system.
The existing AETHER_SHADOW=1 mechanism from PR #93 already blocks eth_sendBundle on the block-driven path. This issue extends it to cover the mempool path identically, adds mempool-specific risk gates, and ships forensic JSON dumps for every shadow-built bundle.
go test ./... -race -count=1 clean incl. new risk-gate tests
Out of scope
MEV-Share mev_sendBundle envelope (Phase 2)
Balancer Vault flashloan path in AetherExecutor.sol (Phase 2)
Stage B + C operator playbooks beyond the rollout doc
Per-builder inclusion-rate weighting (Phase 3)
Risk
Shadow gate failure = real money submitted prematurely. Mitigation: orchestrator hard-exits non-zero on any submission; CI smoke test inverts the gate to verify it actually blocks; risk manager pre-flight prints SHADOW MODE: ENABLED at startup with banner.
Risk-gate false positives (rejecting good arbs) cost EV. Mitigation: every gate has metric + tunable env var; Stage A measures false-positive rate before Stage B.
Stage gate drift — moving to Stage B without meeting acceptance criteria. Mitigation: runbook explicitly lists the metric thresholds; reviewer sign-off required before changing AETHER_SHADOW=0.
Context
Parts A (#138 — Rust
validate_backrun+ gRPC publish) and B (#139 — Go executor mempool bundle builder) wire the public-mempool backrun execution path end-to-end. This issue gates that path behind risk controls + a three-stage shadow rollout so we never accidentally submit a live bundle before measurement validates the system.The existing
AETHER_SHADOW=1mechanism from PR #93 already blockseth_sendBundleon the block-driven path. This issue extends it to cover the mempool path identically, adds mempool-specific risk gates, and ships forensic JSON dumps for every shadow-built bundle.Scope
1. Risk gates (
cmd/risk/manager.gomodify,cmd/executor/bundle.gocalls)Existing gates per CLAUDE.md (kept):
New mempool-specific gates:
min_profit_wei(envAETHER_MEMPOOL_MIN_PROFIT_WEI, default 1e15 = 0.001 ETH)max_tip_share_bps(envAETHER_MEMPOOL_MAX_TIP_BPS, default 9500 = 95%)max_victim_freshness_ms(envAETHER_MEMPOOL_VICTIM_FRESHNESS_MS, default 500)max_in_flight_per_target_block(envAETHER_MEMPOOL_MAX_INFLIGHT, default 5)(target_block, victim_tx_hash)Each gate emits
aether_mempool_risk_rejected_total{reason}counter on rejection.2. Shadow gate (
cmd/executor/submitter.gominor modify)AETHER_SHADOWenv var from PR feat(shadow): live mainnet shadow-mode runner + WS transport preference #93AETHER_SHADOW=1:${AETHER_REPORTS_DIR:-reports}/shadow_mempool_<ts>/bundles/<arb_id>.jsoneth_sendBundleHTTP POST never fired — hard-skip withaether_executor_bundles_shadow_blocked_total{source}counter{ "arb_id": "...", "source": "mempool_backrun", "victim_tx_hash": "0x...", "target_block": 25000000, "built_at": "2026-05-15T17:00:00Z", "envelope": ["0x...", "0x...", "0x..."], "expected_gross_profit_wei": "1234567", "expected_net_profit_wei": "1100000", "tip_share_bps": 8900, "gas_used": 280000, "base_fee_wei": "...", "priority_fee_wei": "...", "flashloan_provider": "balancer", "flashloan_amount": "...", "risk_decisions": [{"gate": "min_profit", "passed": true, "value": "..."}, ...] }3. Three-stage rollout (doc + acceptance gates)
Document in
docs/runbook/mempool-backrun-rollout.md:Stage A — Pure shadow (≥1 week)
AETHER_SHADOW=1Stage B — Conservative submit (≥1 week)
AETHER_SHADOW=0,AETHER_MEMPOOL_MIN_PROFIT_WEI=5e16(0.05 ETH)eth_sendBundleStage C — Live operation
AETHER_MEMPOOL_MIN_PROFIT_WEI=1e15(0.001 ETH)4.
scripts/mempool_backrun_shadow.sh(new)scripts/shadow_mode_live.shfrom PR feat(shadow): live mainnet shadow-mode runner + WS transport preference #93AETHER_SHADOW=1,MEMPOOL_TRACKING=1, builds + obs stack upcaffeinate -ion macOSaether_executor_bundles_submitted_total{source="mempool_backrun"}increments during the runSHADOW_DURATION_SEC5. Live mainnet validation
scripts/mempool_backrun_shadow.shfor 30 minutes on develop after merging Parts A + B + Creports/shadow_mempool_<ts>/and reference in PR descriptionAcceptance criteria
AETHER_SHADOW=1hard-blockseth_sendBundleforsource=mempool_backrunreports/shadow_mempool_<ts>/bundles/scripts/mempool_backrun_shadow.shexits non-zero if any mempool bundle is submitted during shadowdocs/runbook/mempool-backrun-rollout.mddescribes Stages A → B → C with concrete gatesgo test ./... -race -count=1clean incl. new risk-gate testsOut of scope
mev_sendBundleenvelope (Phase 2)AetherExecutor.sol(Phase 2)Risk
SHADOW MODE: ENABLEDat startup with banner.AETHER_SHADOW=0.Depends on
validate_backrun+ gRPC publishCloses
docs/research/strategy-class-analysis.md)