From 5711daefd4ba80806f3f6191c3891858ecfd6bbe Mon Sep 17 00:00:00 2001 From: Timo <6156589+Shik3i@users.noreply.github.com> Date: Sat, 15 Aug 2026 17:20:45 +0200 Subject: [PATCH] docs: record the open episode-transition stray-pause investigation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A peer can be left paused at the end of an episode while the other moves on, and nothing recovers it. The episode guard, the title on the wire and the comparison all exist already, so the interesting part is why the guard lets that one pause through — and that cannot be settled without logs from both sides while it happens. Records what was verified from the code, the three candidate causes that are still hypotheses, the exact log lines that separate them, the planned fix order, and the approaches already ruled out (forcing the comparison would break every platform that exposes no media title). Co-Authored-By: Claude Opus 5 --- docs/episode-transition-stray-pause.md | 169 +++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 docs/episode-transition-stray-pause.md diff --git a/docs/episode-transition-stray-pause.md b/docs/episode-transition-stray-pause.md new file mode 100644 index 0000000..1918d19 --- /dev/null +++ b/docs/episode-transition-stray-pause.md @@ -0,0 +1,169 @@ +# Stray pause at an episode transition (open investigation) + +> **Status:** Open. Root cause **not** confirmed — blocked on logs from both sides while it +> happens. Everything below marked *verified* was read from the code; everything marked +> *hypothesis* was not observed yet. Do not "fix" this from the hypotheses alone. +> +> Reported: 2026-08-15, against v3.1.0. Affected platform supports episode auto-sync +> (parseable `SxxEyy` titles) — title *parsing* is explicitly **not** the problem here. + +--- + +## Symptom + +Two peers watch a series together. At the end of an episode, one of them moves on to the +next episode while the other stays **paused at the end of the previous one** and never +recovers. Happens intermittently, not on every transition. + +## Reported sequence + +1. Peer A finishes episode 1, the player advances to episode 2. +2. A detects the transition, opens an episode lobby and pauses itself in episode 2, + waiting for the others. +3. Peer B is still a few seconds from the end of episode **1**. +4. B receives a `PAUSE` and applies it — although that pause originates from a peer that + is already on episode 2, so it should have been discarded. +5. B is now paused before its own transition, so its player never auto-advances, so B + never reports ready. A's lobby runs into the 60 s timeout and is cancelled. + From then on A and B are on different episodes and the guard (correctly) blocks + everything, so nothing recovers. + +## What the code does today (verified) + +**The episode guard already exists and already runs before anything is applied.** +[`content.js:1197-1213`](../extension/content.js) is the first thing in the +`SERVER_COMMAND` branch (after the host-control desync check). It compares the sender's +title from the payload against the local title and skips `PLAY`/`PAUSE`/`SEEK`/ +`FORCE_SYNC_*` on mismatch. + +**The title is already shipped with every content-script command.** `sendContentEvent` +attaches `mediaTitle` to play/pause/seek ([`content.js:1450-1469`](../extension/content.js)), +and `routeToContent` forwards the payload to the content script unchanged +([`background.js:2576`](../extension/background.js)). *Adding* the title to these events is +therefore not an available fix — it is already there. + +**The guard is permissive by design.** `isDifferentEpisode` +([`content.js:897-903`](../extension/content.js)) returns `false` — i.e. "allow" — when +either side has no title or no parseable episode ID. This is deliberate: Netflix exposes +no media title at all, JkAnime none, Disney+ only the series name (see +[TESTED_SERVICES.md](TESTED_SERVICES.md)). Making the comparison mandatory would silently +break sync on those platforms. + +**Titles come from `navigator.mediaSession.metadata`** +([`content.js:863`](../extension/content.js)) — a page-level signal that is *not* coupled +to what the `