"""Warm-pool gate — the reorder/floor decision that keeps the shelf stocked without over-fetching.""" from app.engine.search import pool_decision FLOOR, REORDER = 90, 100 # the configured thresholds (POOL_SAFETY_FLOOR / POOL_REORDER_AT) def test_pool_healthy_serves_no_fetch(): assert pool_decision(150, False, FLOOR, REORDER) == "pool" assert pool_decision(100, False, FLOOR, REORDER) == "pool" # exactly at reorder → still no fetch def test_pool_dipping_serves_plus_background_refill(): assert pool_decision(99, False, FLOOR, REORDER) == "pool+refill" # below reorder → top up in bg assert pool_decision(90, False, FLOOR, REORDER) == "pool+refill" # at the floor → still serve, refill def test_pool_below_floor_blocks_and_fetches(): assert pool_decision(89, False, FLOOR, REORDER) == "sweep" # under the hard floor → blocking fetch assert pool_decision(0, False, FLOOR, REORDER) == "sweep" # empty pool (first search) → fetch def test_forced_fresh_always_fetches(): assert pool_decision(999, True, FLOOR, REORDER) == "sweep" # dev _fresh toggle bypasses the pool assert pool_decision(5, True, FLOOR, REORDER, exhausted=True) == "sweep" # force overrides exhaustion def test_exhausted_query_serves_instead_of_block_fetching(): # tapped-out niche query below the floor: serve what's pooled, DON'T re-buy duplicates assert pool_decision(30, False, FLOOR, REORDER, exhausted=True) == "pool" # below floor but exhausted assert pool_decision(1, False, FLOOR, REORDER, exhausted=True) == "pool" # even 1 job → serve it # but an EMPTY exhausted pool must still try a fetch (nothing to serve) assert pool_decision(0, False, FLOOR, REORDER, exhausted=True) == "sweep" # exhaustion does NOT suppress the healthy/refill paths assert pool_decision(200, False, FLOOR, REORDER, exhausted=True) == "pool" def test_floor_never_above_reorder_invariant(): # the gate only makes sense when floor ≤ reorder (reorder early, floor as the hard backstop) from app.config import get_settings s = get_settings() assert s.POOL_SAFETY_FLOOR <= s.POOL_REORDER_AT