Phase A4 slice 1: adopt evm-fork-cache cold-start (V2/V3 planners) - #9
Merged
Conversation
Close the highest-value coverage gaps in the adapter layer while A4 cold-start is blocked on evm-fork-cache. All additions are tests against existing, unchanged production behavior (characterization + previously-untested paths). Negative / malformed event-decode coverage (tests/adapter_a1.rs) — the decode_event error branches had zero coverage. Calls decode_event directly and asserts the exact AdapterEventResult: - V2 Sync: wrong-topic ignored, malformed data, non-address-keyed pool. - V3 Swap: malformed data, missing layout (Unsupported), non-address-keyed pool, no-topics / unknown-topic ignored. - V3 Mint/Burn: malformed data; missing tick topics (confirmed caught by decode_log_data_validate — the explicit per-topic guards are defensive). - Balancer V2 Swap: wrong-topic ignored, malformed data. - cold_start: V2/V3 non-address-keyed -> Unsupported. V3-family shifted-layout repair + policy coverage (tests/adapter_reactive.rs): - Pancake V3 and Slipstream Mint repair target their shifted-layout slots (previously only Uniswap V3 was exercised; asserts != the Uniswap layout). - Strict cold-start policy for V2/V3 (locks the current Strict==Eager behavior). - V3 cold-start with a cold liquidity slot still reaches Ready (slot0 is the only mandatory slot; liquidity is reapplied by the next reactive Swap). A coverage cross-check confirms every reachable decode error/ignore branch in uniswap_v2 / uniswap_v3 / balancer_v2 now has a test; the untested branches are unreachable behind decode_log_data_validate. Full CI matrix green (fmt; clippy default + adapters-only + no-default; tests default + adapters-only + no-default; cargo doc -D warnings). No production code changed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the imperative `AmmAdapter::cold_start` with a per-adapter
`ColdStartPlanner` driven by `EvmCache::run_cold_start`, and replace the
`cached_storage(..).is_none()` proxy with the upstream per-slot `SlotFetch`
classification (the archive-miss fix). V2/V3 only; Balancer = slice 2, reactive
`RepairAction::ColdStart` wiring = slice 3.
INTERIM dependency pin: evm-fork-cache is bumped from 27ae8762 to the
`cold-start-sync` tip (903af3d = 27ae8762 + the additive cold-start module),
since evm-fork-cache#12 is not yet merged to main. The bump is purely additive
(our existing code compiles unchanged). Re-pin to the main merge commit before
this consumer work merges to evm-amm-state main.
New `src/adapters/cold_start.rs` (always-on — the upstream `cold_start` module
rides the default-on `reactive` feature we already depend on):
- `AdapterColdStartPlanner` trait: the upstream initial_plan/on_results surface
plus a `finish` hook that maps accumulated state + the run report into a
`ColdStartOutcome` and mutates the pool's metadata/status.
- private `Bridge` newtype forwarding to `evm_fork_cache::cold_start::ColdStartPlanner`
(no trait-upcasting).
- `AdapterRegistry::cold_start(&mut PoolRegistration, &mut EvmCache, ColdStartPolicy)
-> Result<ColdStartOutcome, ColdStartError>`: resolves the adapter, drives the
bounded loop, finalizes. Missing adapter / unsupported -> Ok(Unsupported); an
upstream ColdStartError propagates as Err.
Trait change (`traits.rs`): `cold_start` -> `cold_start_planner(&self, &PoolRegistration,
ColdStartPolicy) -> Result<Box<dyn AdapterColdStartPlanner>, UnsupportedReason>`.
V2 planner (single verify-only round): reproduces the prior end-state (slots
6/7/8, metadata merge preserving config `fee_bps`, Lazy/HotSlotsOnly), sourcing
the reserves verdict from `SlotFetch`. The key improvement: a genuine on-chain
`Zero` (degenerate pool -> PurgeSlots) and a `FetchFailed` archive miss
(-> VerifySlots) now yield DISTINCT repairs.
V3 planner (multi-round): the prior current-tick-word warm-up re-expressed as
`Continue` rounds — round 1 slot0+liquidity, round 2 current-tick bitmap word,
round 3 that word's initialized tick {0,3} info slots; HotSlotsOnly stops after
round 1, Lazy defers the word, a cold/unfetchable slot0 -> NeedsRepair. The
multi-word adaptive scan stays deferred (future Continue rounds, no upstream
change needed). Config V3 metadata preserved.
Tests: new manager-authored `tests/cold_start_adoption.rs` (6 acceptance tests
incl. the Zero-vs-FetchFailed distinction and Lazy==Eager invariant). The 14
existing trait-level cold-start tests in `tests/adapter_reactive.rs` ported to
`registry.cold_start(..)`, assertions' intent preserved (incl. the slot0/reserves
warm -> exact-no-resync synergy). The 2 non-address-keyed cases in
`tests/adapter_a1.rs` adapted to assert `cold_start_planner(..)` returns
`Err(Custom)` (MockCache cannot drive the EvmCache loop). Spec at
`docs/phase-a4-slice1-spec.md`.
Full CI matrix green: fmt; clippy default + adapters-only + no-default
(-D warnings); tests default + adapters-only + no-default; cargo doc -D warnings.
The cold-start path compiles in the adapters-only (heavy-dep-free) build.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jun 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adopts the new protocol-neutral
evm_fork_cache::cold_startmechanism. Replaces the imperativeAmmAdapter::cold_startwith a per-adapterColdStartPlannerdriven byEvmCache::run_cold_start, and replaces thecached_storage(..).is_none()proxy with the upstream per-slotSlotFetchclassification (the archive-miss fix). V2/V3 only this slice — Balancer V2 (discover→verify) is slice 2; the reactiveRepairAction::ColdStartexecutor is slice 3.evm-fork-cacheis bumped from27ae8762to thecold-start-syncbranch tip903af3d(= 27ae8762+ the additive cold-start module), because evm-fork-cache#12 is not yet merged. The bump is purely additive. Re-pin to themainmerge commit before merging this toevm-amm-statemain.*_strict_*/missing_liquiditycold-start tests. The diff shows A8 + slice-1 until Phase A8 (slice): adapter test-matrix hardening #8 merges — merge Phase A8 (slice): adapter test-matrix hardening #8 first.What changed
New
src/adapters/cold_start.rs(always-on —cold_startrides the default-onreactivefeature we already depend on):AdapterColdStartPlanner— upstreaminitial_plan/on_results+ afinishhook mapping accumulated state + run report →ColdStartOutcome(mutating pool metadata/status).Bridgenewtype forwarding toevm_fork_cache::cold_start::ColdStartPlanner(no trait-upcasting).AdapterRegistry::cold_start(&mut PoolRegistration, &mut EvmCache, ColdStartPolicy) -> Result<ColdStartOutcome, ColdStartError>— resolves the adapter, drives the bounded loop, finalizes. Missing adapter / unsupported →Ok(Unsupported); an upstreamColdStartErrorpropagates asErr.Trait (
traits.rs):cold_start→cold_start_planner(&self, &PoolRegistration, ColdStartPolicy) -> Result<Box<dyn AdapterColdStartPlanner>, UnsupportedReason>.V2 planner (single verify-only round): reproduces the prior end-state (slots 6/7/8, metadata merge preserving config
fee_bps, Lazy/HotSlotsOnly), sourcing the reserves verdict fromSlotFetch. Key improvement — a genuine on-chainZero(degenerate →PurgeSlots) and aFetchFailedarchive miss (→VerifySlots) now produce distinct repairs.V3 planner (multi-round): the prior current-tick-word warm-up re-expressed as data-dependent
Continuerounds (slot0+liquidity → current-tick bitmap word → that word's initialized tick{0,3}slots);HotSlotsOnlystops after round 1,Lazydefers the word, a cold/unfetchable slot0 →NeedsRepair. The multi-word adaptive scan stays deferred (futureContinuerounds — no upstream change needed). Config V3 metadata preserved.Tests
tests/cold_start_adoption.rs(6 acceptance tests: the Zero-vs-FetchFailed distinction, Lazy==Eager invariant, V3 ready/missing-layout/failed-slot0).tests/adapter_reactive.rsported toregistry.cold_start(..), assertions' intent preserved (incl. the warm→ExactFromInput-no-resync synergy).tests/adapter_a1.rsadapted to assertcold_start_planner(..)returnsErr(Custom)(MockCache can't drive theEvmCacheloop).docs/phase-a4-slice1-spec.md.Validation
Full CI matrix green locally:
fmt; clippy default + adapters-only + no-default (-D warnings);cargo testdefault (109+22+4+28+6) + adapters-only + no-default;cargo doc -D warnings. The cold-start path compiles in the adapters-only (heavy-dep-free) build.🤖 Generated with Claude Code