# How the Speculative Turn Tracker Handles Turn Revisions During User Interruptions

> Learn how the speculative turn tracker ensures audio consistency by managing turn revisions during user interruptions with monotonically increasing revision numbers.

- Repository: [Hugging Face/speech-to-speech](https://github.com/huggingface/speech-to-speech)
- Tags: internals
- Published: 2026-08-08

---

**The speculative turn tracker guarantees audio consistency by assigning monotonically increasing revision numbers to each turn and atomically managing pending reopen candidates when users interrupt mid-response.**

The `huggingface/speech-to-speech` repository implements a sophisticated concurrency control mechanism to handle real-time conversational interruptions. The speculative turn tracker ensures that when users cut off the system during audio generation, the pipeline maintains state consistency through revision-based synchronization rather than discarding partial outputs.

## Core Architecture of the Speculative Turn Tracker

The tracker maintains consistency through three specialized mutable structures defined in [`src/speech_to_speech/pipeline/speculative_turns.py`](https://github.com/huggingface/speech-to-speech/blob/main/src/speech_to_speech/pipeline/speculative_turns.py).

### Tracking Latest Revisions

The `_latest_revision` structure (an `OrderedDict[str, int]`) serves as the source of truth for turn states. Located at [line 33](https://github.com/huggingface/speech-to-speech/blob/main/src/speech_to_speech/pipeline/speculative_turns.py#L33), this mapping stores the most recent revision number observed for each turn ID, enabling constant-time validation of whether a component holds stale data.

### Pending Reopen Management

When interruptions occur, the tracker stages changes in `_pending_reopen` (line 35), a dictionary mapping turn IDs to `_PendingReopen` objects. Each entry tracks the `base_revision` being superseded and the `candidate_revision` (typically `base + 1`) proposed to replace it.

### Grace Period Protection

The `_reopen_grace` dictionary (line 36) contains `_ReopenGrace` objects that impose a time window after confirmation during which additional reopen attempts are suppressed. This prevents race conditions when rapid user interruptions occur.

## The Turn Revision Lifecycle During Interruptions

The speculative turn tracker manages interruptions through a four-phase atomic workflow.

### Phase 1: Detecting Interruptions with `begin_reopen_candidate`

When the VAD handler detects user speech during system output, it invokes `begin_reopen_candidate(turn_id, current_revision)` at [lines 26-53](https://github.com/huggingface/speech-to-speech/blob/main/src/speech_to_speech/pipeline/speculative_turns.py#L26-L53). This method performs two critical validations:

- Verifies the turn is not already committed
- Confirms the supplied `revision` matches `_latest_revision.get(turn_id)`

Upon validation, it creates a pending entry with `candidate_revision = revision + 1` and stores it in `_pending_reopen`.

### Phase 2: Synchronizing Consumers During Pending State

While a reopen candidate exists, consumers must verify output validity through `is_latest_after_pending_reopen()`. This method internally invokes `_wait_for_pending_reopen_locked()` ([lines 60-62](https://github.com/huggingface/speech-to-speech/blob/main/src/speech_to_speech/pipeline/speculative_turns.py#L60-L62)), which blocks execution with a configurable timeout (`_PENDING_REOPEN_WAIT_TIMEOUT_S`) until the pending entry is resolved via confirmation or cancellation.

### Phase 3: Confirming or Cancelling the Reopen

The system resolves the pending state through one of two paths:

- **`confirm_reopen_candidate(turn_id, base_rev, candidate_rev)`** ([lines 55-92](https://github.com/huggingface/speech-to-speech/blob/main/src/speech_to_speech/pipeline/speculative_turns.py#L55-L92)): Validates that the pending entry matches the supplied revisions, then atomically promotes `_latest_revision[turn_id] = candidate_revision` and removes the pending entry. Optionally triggers `start_reopen_grace()` to prevent immediate subsequent reopens.

- **`cancel_reopen_candidate()`** ([lines 94-106](https://github.com/huggingface/speech-to-speech/blob/main/src/speech_to_speech/pipeline/speculative_turns.py#L94-L106)): Simply deletes the pending entry, allowing the original revision to remain current.

### Phase 4: Committing Only Valid Revisions

Final persistence occurs through `commit()` or conditional variants like `commit_if_latest_after_pending_reopen()`. The internal `_commit_locked()` method ([lines 19-39](https://github.com/huggingface/speech-to-speech/blob/main/src/speech_to_speech/pipeline/speculative_turns.py#L19-L39)) verifies that `_latest_revision[turn_id]` matches the committing revision before writing data, ensuring interrupted turns never corrupt the output stream.

## Practical Implementation Example

The following workflow demonstrates the complete interruption handling sequence:

```python
from speech_to_speech.pipeline.speculative_turns import SpeculativeTurnTracker

tracker = SpeculativeTurnTracker()

# 1. Observe a new speculative turn (e.g., from the VAD handler)

tracker.observe(turn_id="t123", revision=0)

# 2. User interrupts – start a reopen candidate

candidate_rev = tracker.begin_reopen_candidate("t123", 0)

# candidate_rev == 1

# 3. Component validates output relevance (blocks until resolved)

if tracker.is_latest_after_pending_reopen("t123", 0):
    # Safe to process audio for this revision

    process_audio_chunk()

# 4. Confirm the new revision after generating corrected audio

tracker.confirm_reopen_candidate("t123", base_revision=0, candidate_revision=1)

# 5. Start grace period to prevent rapid re-interruptions

tracker.start_reopen_grace("t123", 1, grace_s=0.2)

# 6. Commit only if still current

tracker.commit_if_latest_after_pending_reopen("t123", 1)

```

## Summary

- **Revision tracking**: The speculative turn tracker uses monotonically increasing integers in `_latest_revision` to version each turn state.
- **Atomic interruption handling**: `begin_reopen_candidate()` creates pending entries that block consumers until resolved, preventing stale data consumption.
- **Grace periods**: The `_reopen_grace` mechanism suppresses rapid successive interruptions to maintain pipeline stability.
- **Safe commits**: Write operations validate against current revisions, ensuring only non-interrupted turn states persist to output.

## Frequently Asked Questions

### What happens if a user interrupts multiple times in quick succession?

The speculative turn tracker prevents cascading race conditions through the `_reopen_grace` mechanism. After `confirm_reopen_candidate()` promotes a new revision, `start_reopen_grace()` records a deadline during which `begin_reopen_candidate()` will reject additional reopen attempts for that turn ID. This ensures downstream components complete processing before handling subsequent interruptions.

### How does the tracker prevent race conditions between audio generation and user input?

The tracker implements a blocking synchronization model through `_wait_for_pending_reopen_locked()`. When a reopen candidate exists, consumers calling `is_latest_after_pending_reopen()` block until the pending state resolves. This guarantees that audio generation components either complete work on a valid revision or detect obsolescence before committing output.

### What is the purpose of the reopen grace period?

The grace period, managed by `_reopen_grace` and initiated via `start_reopen_grace()`, provides a configurable time window (typically 0.2 seconds) during which new interruption requests are rejected. This prevents the system from entering oscillation states where rapid user interruptions create competing revision candidates before downstream processing completes.

### Where is the speculative turn tracker integrated in the speech-to-speech pipeline?

According to the source code, the tracker is instantiated in [`src/speech_to_speech/s2s_pipeline.py`](https://github.com/huggingface/speech-to-speech/blob/main/src/speech_to_speech/s2s_pipeline.py) (around [line 365](https://github.com/huggingface/speech-to-speech/blob/main/src/speech_to_speech/s2s_pipeline.py#L365)) and invoked by the VAD handler at [`src/speech_to_speech/VAD/vad_handler.py`](https://github.com/huggingface/speech-to-speech/blob/main/src/speech_to_speech/VAD/vad_handler.py) (around [line 62](https://github.com/huggingface/speech-to-speech/blob/main/src/speech_to_speech/VAD/vad_handler.py#L62)) when voice activity detection triggers during system speech output.