Summary
EscalationHandler.resolve() (escalation.py:176, :424-431) wakes as soon as the first vote event is set and runs the quorum check once. If quorum is not yet satisfied it falls through to default_action immediately, without waiting the remaining timeout for additional votes to arrive.
This means a 2-of-3 quorum requirement can never succeed: the first vote unblocks resolve(), quorum is not met, and the request resolves via default_action before the second voter has a chance to respond.
Reproduction
handler = EscalationHandler(
backend=queue,
timeout_seconds=5,
default_action=DefaultTimeoutAction.DENY,
quorum=QuorumConfig(required_approvals=2, total_approvers=3),
)
request = handler.escalate("agent", "action", "reason")
# First vote arrives at t=0.1s
queue.approve(request.request_id, approver="reviewer-1")
# Second vote at t=0.3s -- but resolve() already returned DENY at t=0.1s
queue.approve(request.request_id, approver="reviewer-2")
decision = handler.resolve(request.request_id, timeout=5)
# Expected: ALLOW (quorum met within timeout)
# Actual: DENY (fell through to default_action after first vote)
Fix direction
resolve() should loop on the event, re-checking quorum after each wakeup, and only fall through to default_action once the full timeout has elapsed without quorum being satisfied.
Context
Surfaced during review of #3127 (escalation quorum fix) by @MohammadHaroonAbuomar. Not introduced by that PR but becomes reachable once quorum is configured.
Summary
EscalationHandler.resolve()(escalation.py:176, :424-431) wakes as soon as the first vote event is set and runs the quorum check once. If quorum is not yet satisfied it falls through todefault_actionimmediately, without waiting the remaining timeout for additional votes to arrive.This means a 2-of-3 quorum requirement can never succeed: the first vote unblocks
resolve(), quorum is not met, and the request resolves viadefault_actionbefore the second voter has a chance to respond.Reproduction
Fix direction
resolve()should loop on the event, re-checking quorum after each wakeup, and only fall through todefault_actiononce the full timeout has elapsed without quorum being satisfied.Context
Surfaced during review of #3127 (escalation quorum fix) by @MohammadHaroonAbuomar. Not introduced by that PR but becomes reachable once quorum is configured.