EcoStrategy scenario D shares after_tick closure across runs — leader_guarded pollution invalidates ordering deltas #169
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:open_issues
agents
agent:security_audit
agent:verify
area
timecurve
arena
arena-v2
audit
block:feature_review
block:security
bug
contracts
design
devops
docs
documentation
enhancement
epic
feature
frontend
indexer
low priority
megaeth
operations
ops
performance
QA
qa checklist
referrals
removal
security
smart-contracts
tech-debt
testing
time-arena
timecurve
visual-qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
code/yieldomega#169
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
logic bug in
simulations/ecostrategy/scenarios.pythat pollutes scenario D output. caught on a code review pass against390f9be.scenario D goal is "same setup, different ordering" — paired buy-first vs pvp-first runs with identical seed/pop/horizon, so the ordering deltas (
ordering_bp_leader_idx_match,ordering_steals_abs_delta, etc.) reflect ordering and only ordering. the comparison breaks because both runs share the sameafter_tickclosure object, and the closure carries mutablenonlocalstate (leader_guarded) that persists across the runs.Repro
scenarios.py:448builds the closure once:scenarios.py:459and:477pass the sameafter_tickto both_simulate_salecalls (m_buy and m_pvp).inside the factory at
scenarios.py:329-339,leader_guardedis captured vianonlocal:after
m_buyruns,leader_guarded = True. whenm_pvpruns against the same closure, theif guard_once and not leader_guardedbranch never fires — m_pvp gets zero guards.Observable in current output
output/ecostrategy_report.jsonscenario D with seed 42:buy_first_warbow_guards: 1pvp_first_warbow_guards: 0the divergence is structural, not ordering-driven. the leader in pvp_first runs the entire final window unguarded, so steals against them apply
WARBOW_STEAL_DRAIN_BPS(10%) instead ofWARBOW_STEAL_DRAIN_GUARDED_BPS(1%). that meanspvp_first_warbow_stealsand_revengesare inflated by guard-state pollution rather than pure ordering effects.Why this matters
every metric scenario D produces under
_abs_delta(ordering_steals_abs_delta,ordering_revenges_abs_delta,ordering_flags_planted_abs_delta) and the BP leader comparison (ordering_bp_leader_idx_match) is partially driven by this guard-state asymmetry, not just the ordering flag. the audit narrative for scenario D as MEV-relevant ordering risk is undermined because the experiment does not actually isolate ordering.Fix shape
build
after_tickseparately for each run:or convert the factory to a class with an explicit
reset()method.Test gap
simulations/tests/test_ecostrategy.py:94-99only asserts metric keys exist and thatlaunch_anchor_cl8y_per_charm_at_clearing > 0. no assertion onwarbow_guardsparity between buy_first and pvp_first under deterministic seeds. would have caught the asymmetry. recommend adding:or assert both are nonzero when
guard_once=True.Disposition vs #161
this was missed during my #161 D+E PASS verification. the metrics are still interpretable as upper-bound ordering signals, but they are not pure. happy to follow up on #161 with the corrected interpretation once this is fixed.
severity: P2 sim correctness. not a blocker — sims are non-authoritative per
INV-SIM-161— but the fix is trivial and restores the audit narrative for D.cc @PlasticDigits
mentioned in issue #161
mentioned in commit
d734901f7dImplemented (merged to
main—d734901)Problem: Scenario D reused one
_scenario_c_style_after_tickclosure for bothbuy_firstandpvp_firstruns. Theleader_guardednonlocalcarried over, so after the first run the second got noguard_onceguard — ordering deltas were polluted (e.g. seed 42: guards 1 vs 0).Change:
run_scenario_dnow buildsafter_tick_buyandafter_tick_pvpseparately.Tests:
test_scenario_d_ordering_branchesassertsbuy_first_warbow_guards == pvp_first_warbow_guards;test_scenario_d_warbow_guards_parity_seed_42pins the reported regression.Docs:
INV-SIM-169-Dindocs/testing/invariants-and-business-logic.md; cross-links insimulations/README.mdandskills/README.md.Verification checklist
cd simulations && PYTHONPATH=. python3 -m unittest discover -s tests -v— all green (ran twice locally).PYTHONPATH=. python3 -m ecostrategy --scenario D --seed 42 --out /tmp/d.json— JSON showsbuy_first_warbow_guards==pvp_first_warbow_guards(expect1/1for defaults).run_scenario_ddocstring +INV-SIM-169-Dsubsection for the closure-isolation invariant.@brouie — could you confirm this matches your review expectations and that scenario D metrics are now ordering-isolated as intended? Leaving the issue open for your sign-off.
mentioned in issue #167
@PlasticDigits — verification PASS on
d734901.closure isolation lands at
scenarios.py:495-510—after_tick_buyandafter_tick_pvpbuilt from separate_scenario_c_style_after_tick(...)factory calls, each holding its ownleader_guardednonlocal. passed to_simulate_saleat:525and:543respectively. no shared closure path remains.both regression tests landed in
simulations/tests/test_ecostrategy.py:test_scenario_d_ordering_branchesat:148-159— equality assertion onbuy_first_warbow_guardsvspvp_first_warbow_guards, with explicitGitLab #169cite at line 154test_scenario_d_warbow_guards_parity_seed_42at:161-167— pins the originally-filed regression (seed 42, population 240, horizon 28_800)docstring on
run_scenario_dmakes the closure-isolation contract explicit. matches the filed report.rng_buy and rng_pvp re-seeding behavior preserved (both still start from the same seed so cross-run determinism holds). only warbow_guards parity is asserted equal — steals/revenges/flags-planted are intentionally not pinned because measuring those deltas is the point of scenario D in the first place. correct scope.
ready for close on your side.
mentioned in commit
8560f23bac