Severity: ⚪ low • Category: correctness
Location: src/store.rs : 302-342, 411-430
What's wrong
With max_size=0, new() computes per_shard = 0.div_ceil(1) = 0, so capacity=0. In the insert path the eviction loop while shard.map.len() >= shard.capacity is 0 >= 0 (true), calls evict_one on an empty order (no-op), then if shard.order.is_empty() break, and proceeds to insert anyway. The result is the cache always retains one entry. A max_size of 0 is most naturally read as "do not cache", so this is a surprising edge case (current_size=1 observed).
Trigger
Decorate with @cache(max_size=0); call with distinct args; cache_info().current_size == 1.
Suggested fix
Special-case capacity == 0 (or max_size == 0) to skip insertion entirely, or validate max_size >= 1 in new()/the Python cache() factory and raise a clear error.
Adversarial verification note
Confirmed in the real code. In src/store.rs new() (lines 302-307): with max_size=0, n_shards = (0/8).clamp(1,16).next_power_of_two().min(16) = 1, and per_shard = 0.div_ceil(1) = 0, so each shard has capacity=0. In call insert path (lines 411-430): on a miss with an empty shard, needs_insert=true, the eviction loop while shard.map.len() >= shard.capacity evaluates 0 >= 0 true, calls evict_one which returns immediately on an empty order (verified at lines 185-189), then if shard.order.is_empty() break exits the loop, and the code unconditionally inserts at lines 428-429. The map then holds 1 entry. Subsequent distinct-key misses evict the prior entry (oscillating at most 1), so current_size caps at 1 rather than 0. The Python factory (warp_cache/_decorator.py:135-186) performs no max_size validation, so max_size=0 reaches new() directly. The finding's mechanism, math, and trigger are all accurate. Severity 'low' is correct: max_size=0 is an unusual input, there is no crash, memory unsafety, or systematically wrong results — just a surprising 1-entry retention instead of disabling the cache (TTL still applies to that one entry).
Filed from a multi-agent code review (finder → adversarial verification → synthesis). Confirmed real after a skeptic re-read the code.
Severity: ⚪ low • Category: correctness
Location:
src/store.rs: 302-342, 411-430What's wrong
With max_size=0, new() computes per_shard = 0.div_ceil(1) = 0, so capacity=0. In the insert path the eviction loop
while shard.map.len() >= shard.capacityis0 >= 0(true), calls evict_one on an empty order (no-op), thenif shard.order.is_empty() break, and proceeds to insert anyway. The result is the cache always retains one entry. A max_size of 0 is most naturally read as "do not cache", so this is a surprising edge case (current_size=1 observed).Trigger
Decorate with @cache(max_size=0); call with distinct args; cache_info().current_size == 1.
Suggested fix
Special-case capacity == 0 (or max_size == 0) to skip insertion entirely, or validate max_size >= 1 in new()/the Python cache() factory and raise a clear error.
Adversarial verification note
Confirmed in the real code. In src/store.rs new() (lines 302-307): with max_size=0, n_shards = (0/8).clamp(1,16).next_power_of_two().min(16) = 1, and per_shard = 0.div_ceil(1) = 0, so each shard has capacity=0. In call insert path (lines 411-430): on a miss with an empty shard, needs_insert=true, the eviction loop
while shard.map.len() >= shard.capacityevaluates0 >= 0true, calls evict_one which returns immediately on an empty order (verified at lines 185-189), thenif shard.order.is_empty() breakexits the loop, and the code unconditionally inserts at lines 428-429. The map then holds 1 entry. Subsequent distinct-key misses evict the prior entry (oscillating at most 1), so current_size caps at 1 rather than 0. The Python factory (warp_cache/_decorator.py:135-186) performs no max_size validation, so max_size=0 reaches new() directly. The finding's mechanism, math, and trigger are all accurate. Severity 'low' is correct: max_size=0 is an unusual input, there is no crash, memory unsafety, or systematically wrong results — just a surprising 1-entry retention instead of disabling the cache (TTL still applies to that one entry).Filed from a multi-agent code review (finder → adversarial verification → synthesis). Confirmed real after a skeptic re-read the code.