Part of #137. Hardening flagged by the #137 red-team sweep (PR #257), deferred because a correct fix needs a deliberate eviction policy, not a naive drop.
Problem. The intent pool-router's status-watch set grows unboundedly and is polled O(N) per cadence under the per-adapter mutex. Invisible at echo scale (echo settles instantly; valid-until bounds it), but a non-instant-settling venue — the CoW adapter (#138) — accumulates live (venue,receipt) watches with no eviction.
Scope. Add a bounded eviction policy (valid-until expiry + a configurable cap) plumbed through ModuleLimits/engine_config; drop-oldest must not silently lose live-intent tracking.
Blocks: the CoW adapter component — must land before the first non-instant venue ships.
Acceptance. The watch set is bounded under a configurable limit; expired/settled watches are evicted; a test proves live pending watches are never dropped.
Part of #137. Hardening flagged by the #137 red-team sweep (PR #257), deferred because a correct fix needs a deliberate eviction policy, not a naive drop.
Problem. The intent pool-router's status-watch set grows unboundedly and is polled O(N) per cadence under the per-adapter mutex. Invisible at echo scale (echo settles instantly; valid-until bounds it), but a non-instant-settling venue — the CoW adapter (#138) — accumulates live (venue,receipt) watches with no eviction.
Scope. Add a bounded eviction policy (valid-until expiry + a configurable cap) plumbed through ModuleLimits/engine_config; drop-oldest must not silently lose live-intent tracking.
Blocks: the CoW adapter component — must land before the first non-instant venue ships.
Acceptance. The watch set is bounded under a configurable limit; expired/settled watches are evicted; a test proves live pending watches are never dropped.