# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/how-should-an-instance-decide-whether-to-branch-speculatively-when-its-own-latency-budget-is-smaller-than-the-p99-fan-out-latency-of-the-federated-swa.md
# Remnant Warrant:    https://corpusfetch.com/c/how-should-an-instance-decide-whether-to-branch-speculatively-when-its-own-latency-budget-is-smaller-than-the-p99-fan-out-latency-of-the-federated-swa.warrant.json
# Markdown SHA-256:   4e759d0ab497b8f1c4462cdb626b2ed182eda78ea3dd0d1df94bfb116a15dfa4
# Code AST SHA-256:   8e2b013a16e66945c8bb6542ea6ede73012cedae0d8f39a25c1f08884fd3f112
# Verified Classes:   SpeculationBudgetViolation
# Defensive Guards:   3 fail-closed invariants (zero external deps)

class SpeculationBudgetViolation(RuntimeError):
    """Raised when a coordinator issues a speculative branch whose deadline
    cannot be met at the p99 fan-out latency of the slowest required peer."""
    pass


def should_speculate(
    budget_remaining_ms: float,
    p50_fanout_ms: float,
    p99_fanout_ms: float,
    abandon_cost_ms: float,
    decision_relevant: bool,
) -> bool:
    if budget_remaining_ms <= 0:
        raise SpeculationBudgetViolation(
            f"negative or zero budget ({budget_remaining_ms} ms); "
            "coordinator must degrade, not speculate"
        )
    if p99_fanout_ms < p50_fanout_ms:
        raise SpeculationBudgetViolation(
            f"p99 ({p99_fanout_ms}) < p50 ({p50_fanout_ms}); "
            "latency estimate is corrupt or stale"
        )
    if not decision_relevant:
        return False
    required = p99_fanout_ms + abandon_cost_ms
    if budget_remaining_ms > required:
        return True
    if budget_remaining_ms > p50_fanout_ms:
        # synchronous issue is preferable to speculation here
        return False
    # below p50: cannot even complete a median round trip
    return False


def issue_branch(coordinator, peer_set, budget_remaining_ms, abandon_cost_ms):
    p50 = peer_set.p50_fanout_latency_ms()
    p99 = peer_set.p99_fanout_latency_ms()
    relevant = coordinator.next_action_can_flip(peer_set)
    if should_speculate(budget_remaining_ms, p50, p99, abandon_cost_ms, relevant):
        return coordinator.speculate(peer_set)
    if budget_remaining_ms <= p50:
        raise SpeculationBudgetViolation(
            f"budget {budget_remaining_ms} ms <= p50 {p50} ms; "
            "coordinator must fall back to local/cached decision"
        )
    return coordinator.issue_synchronous(peer_set)
