Three-Tier Architecture

TierWhenPattern
Pure unitNo external depsCall the function directly
Seeded cacheNeeds _POOL_CACHE statemonkeypatch the global dict via seeded_pool_cache fixture
Fake adapterScheduler/executor needs a venueFakeDexAdapter / FakeCexAdapter in-process doubles
Anvil forkReal contracts, real EVM mathSpawned Anvil process (anvil_base, anvil_bsc fixtures)

Mocks (AsyncMock) are reserved for the DB layer in scheduler tests only.

Static Checking

source .venv/bin/activate && python -m mypy engine --no-error-summary

mypy runs in strict mode on engine/, the production Python package. It intentionally excludes tests/ and dashboard/ because test doubles are looser by design and frontend code is checked by its own toolchain.

Running the Suite

source .venv/bin/activate && python -m pytest -x -q --ignore=tests/test_dex_fork.py

Fork tests (requires anvil CLI from Foundry):

source .venv/bin/activate && python -m pytest -q tests/test_dex_fork.py -v

CI runs the strict mypy check above plus the default pytest command inside Docker. It intentionally skips tests/test_dex_fork.py because those tests require anvil and fork-capable RPC endpoints.

Per-File Coverage

FileModuleTests
test_params_validation.pyengine/types.py, config.pyDexParams/CexParams/WalletParams defaults, custom values
test_schemas.pyengine/types.py, api/schemas.pyDomain types (types.py) and HTTP response types (schemas.py)
test_config.pyconfig.pySettings defaults
test_price_math.pyvenues/dex/shared.py, lp/uniswap_v4.pyTick/price math, compute_ewma_stats, calculate_tick_range recovery skew
test_capital_allocation.pylp/uniswap_v4.pycalculate_mint_amounts caps
test_price_aggregation.pycore/price_aggregation.pyVWAP, confidence, blended price
test_accounts.pycore/accounts.pyHD derivation, role access
test_inventory.pycore/arbitrage/inventory.pyLimits, circuit breakers, reconcile_stables
test_database.pydb/database.pySQLite CRUD
test_orderbook.pycore/arbitrage/cex_dex.pywalk_orderbook_*, _ternary_search
test_pool_state.pycore/arbitrage/pool_state.pySwap math, update_pool_state_from_event, cache reads
test_cex_dex.pycore/arbitrage/cex_dex.pyfind_optimal_arb, compute_arb_curve
test_dex_dex.pycore/arbitrage/dex_dex.pyfind_optimal_dex_arb null cases and result structure
test_router.pycore/arbitrage/router.pyselect_route sizing, filtering, tiebreak
test_valuation.pycore/arbitrage/valuation.pyportfolio_value, CEX/DEX holdings valuation
test_scheduler.pyscheduler/core.py + scheduler/jobs/*Shell wiring plus _check_dex_rebalance, _rebalance_dex_position, _create_dex_position, DEX bootstrap and wallet activity delegation
test_executor.pycore/arbitrage/executor.pyDetection mode, CEX-CEX, half-open, unknown venue
test_dex_fork.pyV4 pool state + lifecycleSection A: reads; Section B: funded wallet; Section C: rebalance

Adding Tests for a New Venue

  1. DEX venue — add a FakeDexAdapter with the venue's token decimals configured, seed _POOL_CACHE with realistic sqrtPriceX96 values, add to seeded_pool_cache fixture in conftest.py.
  2. CEX venue — add a FakeCexAdapter variant; test place_market_order success/failure paths.
  3. Fork tests — add a new anvil_<chain> fixture in conftest.py, write Section A reads using update_single_v4_pool_state or update_single_pool_state.