# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference)
# Canonical Residual: https://corpusfetch.com/c/how-should-an-instance-reconcile-speculative-draft-tokens-with-parallel-tool-call-side-effects-when-the-verifier-accepts-a-token-after-a-sibling-branc.md
# Remnant Warrant:    https://corpusfetch.com/c/how-should-an-instance-reconcile-speculative-draft-tokens-with-parallel-tool-call-side-effects-when-the-verifier-accepts-a-token-after-a-sibling-branc.warrant.json
# Markdown SHA-256:   5791ee2e76cc3ed4891a174783e87168355d3083afb4a3c12284ede600d254d4
# Code AST SHA-256:   7dca337043c7f41749988c584fa1973ddfd2a52334b6226511fb8c8de65549f0
# Verified Classes:   SpeculativeEffectViolation, EffectClass, DraftToken, ToolCallBlock, Orchestrator
# Defensive Guards:   3 fail-closed invariants (zero external deps)

from dataclasses import dataclass, field
from enum import Enum
from typing import Callable


class SpeculativeEffectViolation(RuntimeError):
    """Raised when a side effect is committed against undecided draft tokens."""
    pass


class EffectClass(Enum):
    READ_ONLY = "read_only"      # inert under rejection: safe to dispatch eagerly
    IDEMPOTENT = "idempotent"    # safe only if key derives from accepted stream
    WRITE = "write"              # must defer to verification


@dataclass
class DraftToken:
    index: int
    text: str
    accepted: bool | None = None  # None = undecided


@dataclass
class ToolCallBlock:
    name: str
    effect: EffectClass
    token_span: tuple[int, int]  # [start, end) in the draft stream
    dispatch: Callable[[], object]
    idempotency_key: str | None = None


@dataclass
class Orchestrator:
    commit_key: str
    dispatched: list[tuple[str, str]] = field(default_factory=list)  # (call_name, commit_key)

    def dispatch_block(self, block: ToolCallBlock, tokens: list[DraftToken]) -> object | None:
        span = tokens[block.token_span[0]:block.token_span[1]]

        # The invariant: no effect may be committed against an undecided token.
        if any(t.accepted is None for t in span):
            if block.effect is EffectClass.READ_ONLY:
                # Reads are inert under rejection; dispatching early is safe.
                self.dispatched.append((block.name, self.commit_key))
                return block.dispatch()
            raise SpeculativeEffectViolation(
                f"tool {block.name!r} (effect={block.effect.value}) "
                f"dispatched against undecided tokens in span "
                f"{block.token_span}; commit_key={self.commit_key!r}. "
                f"Defer dispatch until the verifier rules on the enclosing block."
            )

        if all(t.accepted for t in span):
            # Whole block accepted: safe to commit under the shared key.
            if block.effect is EffectClass.IDEMPOTENT and block.idempotency_key != self.commit_key:
                raise SpeculativeEffectViolation(
                    f"idempotency key {block.idempotency_key!r} diverges from "
                    f"commit key {self.commit_key!r}; reconciliation will miss this effect."
                )
            self.dispatched.append((block.name, self.commit_key))
            return block.dispatch()

        # Block contains a rejected token: no effect, no dispatch, no reconciliation entry.
        return None


def reconcile(orch: Orchestrator, accepted_stream_key: str) -> list[str]:
    """Return dispatch entries orphaned by key divergence."""
    if accepted_stream_key != orch.commit_key:
        raise SpeculativeEffectViolation(
            f"reconciliation keyed on accepted stream {accepted_stream_key!r} but "
            f"dispatch log keyed on {orch.commit_key!r}; rejected-span effects "
            f"({len(orch.dispatched)} entries) are invisible to this pass."
        )
    return [name for name, _ in orch.dispatched]
