diff --git a/backend/packages/harness/deerflow/community/e2b_sandbox/capacity/redis.py b/backend/packages/harness/deerflow/community/e2b_sandbox/capacity/redis.py index 22795639b..573f8851b 100644 --- a/backend/packages/harness/deerflow/community/e2b_sandbox/capacity/redis.py +++ b/backend/packages/harness/deerflow/community/e2b_sandbox/capacity/redis.py @@ -18,6 +18,13 @@ local function now_ms() return tonumber(current[1]) * 1000 + math.floor(tonumber(current[2]) / 1000) end +-- Number of 'meta:*' fields initialize() writes. Live entries ('r:'/'s:') are +-- counted as HLEN minus this, so the two must move together: adding a meta +-- field without updating this constant makes the ledger over-count usage and +-- reject one reservation early. test_ledger_meta_field_count_matches_constant +-- pins it against initialize()'s actual output. +local META_FIELD_COUNT = 3 + local function initialize(hard_limit) redis.call('HSET', KEYS[1], 'meta:state', 'initializing', @@ -57,7 +64,7 @@ if operation == 'reserve' then if redis.call('HEXISTS', KEYS[1], field) == 1 then return 'GRANTED' end - if redis.call('HLEN', KEYS[1]) - 3 >= tonumber(hard_limit) then + if redis.call('HLEN', KEYS[1]) - META_FIELD_COUNT >= tonumber(hard_limit) then return 'FULL' end redis.call('HSET', KEYS[1], field, tostring(now_ms())) diff --git a/backend/tests/test_e2b_capacity_store_redis.py b/backend/tests/test_e2b_capacity_store_redis.py index 65e59ae06..ea8356a69 100644 --- a/backend/tests/test_e2b_capacity_store_redis.py +++ b/backend/tests/test_e2b_capacity_store_redis.py @@ -176,3 +176,33 @@ def test_mismatched_hard_limits_fail_closed(make_store) -> None: gateway_b.revision() with pytest.raises(CapacityBackendError, match="configuration mismatch"): gateway_b.reserve("reservation") + + +def test_ledger_meta_field_count_matches_constant(make_store) -> None: + # Admission derives the live-entry count as HLEN - META_FIELD_COUNT, so the + # Lua constant must equal the number of 'meta:*' fields initialize() writes. + # Adding a meta field without updating the constant also trips the existing + # concurrency tests, but those report an unexpected reservation outcome; this + # one names the cause. + store = make_store(3) + _initialize(store) + fields = store._redis.hkeys(store.key) + + assert _counts(store) == (0, 0) + assert sorted(fields) == ["meta:hard_limit", "meta:revision", "meta:state"] + assert len(fields) == 3 + + +def test_reserve_admits_exactly_hard_limit_entries(make_store) -> None: + # Locks the invariant the constant exists to protect: an off-by-one in the + # HLEN offset shifts the ceiling, which this catches regardless of how the + # offset happens to be spelled. + store = make_store(3) + _initialize(store) + + granted = [store.reserve(f"reservation-{index}") for index in range(3)] + + assert granted == [ReserveStatus.GRANTED] * 3 + assert _counts(store) == (0, 3) + assert store.reserve("reservation-overflow") is ReserveStatus.FULL + assert store.reserve("reservation-0") is ReserveStatus.GRANTED