feat(slots-rpc): available_slots capacity hint 추가 (BAT-037 / REQ-073 AC-6)
slots RPC 응답에 available_slots: int|null 포함. max_active_slots 미설정 시 null, 설정 시 max(0, M-active). 16 tests passed (AC-6 신규 3개 포함), 423 전체 통과. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,7 @@ def _wire(items=None, *, max_active_slots=None):
|
||||
snapshot_store=store,
|
||||
pause_store=pause,
|
||||
watchdog_store=watchdog,
|
||||
max_active_slots=max_active_slots,
|
||||
)
|
||||
return repo, svc, store, pause, watchdog, handler
|
||||
|
||||
@@ -45,13 +46,12 @@ def _req(filter=None, spy=False):
|
||||
return RpcRequest(payload=payload, correlation_id="test-corr")
|
||||
|
||||
|
||||
# REQ-073 AC-3: response keys only {slots/degraded/reason/message}
|
||||
# REQ-073 AC-3: response keys include available_slots; assets/watchdog/strategy absent
|
||||
def test_response_keys_only_slots_health():
|
||||
_, _, _, _, _, handler = _wire()
|
||||
resp = handler(_req())
|
||||
assert set(resp.payload.keys()) == {"slots", "degraded", "reason", "message"}
|
||||
assert set(resp.payload.keys()) == {"slots", "available_slots", "degraded", "reason", "message"}
|
||||
assert "assets" not in resp.payload
|
||||
assert "available_slots" not in resp.payload
|
||||
assert "watchdog" not in resp.payload
|
||||
|
||||
|
||||
@@ -210,3 +210,34 @@ def test_spy_false_updates_watchdog():
|
||||
sid = str(holding.slot_id)
|
||||
handler(_req(filter="holding", spy=False))
|
||||
assert watchdog.last_seen(sid) is not None # updated
|
||||
|
||||
|
||||
# REQ-073 AC-6: available_slots capacity hint
|
||||
def test_available_slots_null_when_uncapped():
|
||||
_, _, _, _, _, handler = _wire(max_active_slots=None)
|
||||
resp = handler(_req())
|
||||
assert resp.payload["available_slots"] is None
|
||||
|
||||
|
||||
def test_available_slots_remaining_capacity():
|
||||
repo, svc, _, _, _, handler = _wire(max_active_slots=2)
|
||||
# 0 active → available = 2
|
||||
assert handler(_req()).payload["available_slots"] == 2
|
||||
# buy pf-A into holding → 1 active, available = 1
|
||||
slot_a = repo.find_slot_by_portfolio("default", "pf-A")
|
||||
pending = svc.transit_slot(slot_a.slot_id, SlotState.INACTIVE, SlotState.PENDING_BUY,
|
||||
reason="buy", actor="test", symbol="005930")
|
||||
svc.transit_slot(pending.slot_id, SlotState.PENDING_BUY, SlotState.HOLDING,
|
||||
reason="filled", actor="test", avg_price=100.0, qty=5.0)
|
||||
assert handler(_req()).payload["available_slots"] == 1
|
||||
|
||||
|
||||
def test_available_slots_zero_when_full():
|
||||
repo, svc, _, _, _, handler = _wire(max_active_slots=1)
|
||||
slot_a = repo.find_slot_by_portfolio("default", "pf-A")
|
||||
pending = svc.transit_slot(slot_a.slot_id, SlotState.INACTIVE, SlotState.PENDING_BUY,
|
||||
reason="buy", actor="test", symbol="005930")
|
||||
svc.transit_slot(pending.slot_id, SlotState.PENDING_BUY, SlotState.HOLDING,
|
||||
reason="filled", actor="test", avg_price=100.0, qty=5.0)
|
||||
# M=1, active=1 → available=0
|
||||
assert handler(_req()).payload["available_slots"] == 0
|
||||
|
||||
Reference in New Issue
Block a user