diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-10-05 09:54:59 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-10-05 09:54:59 +0000 |
| commit | 217c982403a105e986fb7ce13b922d9f08583632 (patch) | |
| tree | 38f2d3a9556b3dfa1b835b9b2c1f7efcb547e719 /docs | |
| parent | 7cc88394458e9d03e3a6a6e58cdff9c8dd4ad7a3 (diff) | |
Move skip detection to a server, and find that it detects ads
The server is Peter's design and it works: listend polls the phone's feed
list, mirrors the newest 8 episodes per show, detects across all of them at
once, and serves the offsets *and the audio they belong to*. Deployed on
tungsten behind Apache at https://listen.terst.org. FingerprintWorker and
MidrollWorker are deleted -- the battery drain is gone because the work is.
Serving the audio is load-bearing. Dynamic ad insertion turned out to be on
every episode: Grass Apes declares 22:05 and the server was served 28:18. An
offset measured on one copy is minutes wrong for another, so the phone has to
play the bytes the detector examined. The offsets land in the same columns the
on-device detector wrote, so playback needed no changes and there is no
migration.
**The headline finding is a failure, and it is proved rather than suspected.**
Detection reported the intro confirmed on 8 of 8 Radiolab episodes and passed
its self-check. It had locked onto an advertisement. The chosen segment was
searched for in an ad-free copy of the same episode fetched hours earlier:
r = 0.0621. It is in the ad break, not the programme.
The confirmation threshold assumes three *independently fetched* episodes.
Mirroring 8 within one minute from the same ad server makes them maximally
dependent -- whatever campaign is running is in all of them, identical -- and
SelfCheck cannot catch it, because the segments genuinely are the same audio.
Moving to a server fixed the cost problem and broke the independence the
safety mechanism rests on. The published offsets are head-window matches, so
they happen to skip pre-roll advertising, which is useful by accident and will
move whenever the campaign rotates. It is not intro detection and is not
described as such anywhere.
The fix, not made: record when each episode was fetched and require the
agreeing episodes to span more than one fetch occasion. Reasoning, and an
argument for detecting the ads directly instead, in docs/detection-findings.md.
Also recorded there: two tooling traps that each cost real time. `android-ui
tap` can land on the soft keyboard, because the dump reports layout
coordinates the IME does not move -- a Save button and a text field both
appeared tapped and neither fired. And the server's token is alphanumeric now
because `adb shell input text` ate the leading "-" of a base64url one and
produced a silent 401 that looked like broken wiring.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/detection-findings.md | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/docs/detection-findings.md b/docs/detection-findings.md index 1bb7880..26b31b3 100644 --- a/docs/detection-findings.md +++ b/docs/detection-findings.md @@ -495,3 +495,77 @@ milliseconds, and `SelfCheck` tolerates half a second of position error for the one host with curl is not enough to conclude either way, and it should be measured properly before the design leans on it. - **Midroll detection is not ported.** Only intro/outro. + +--- + +## 2026-10-05, later: the server ships, and simultaneous mirroring defeats the threshold + +`server/` now runs on tungsten as `listend.service`, behind Apache at https://listen.terst.org +with a Let's Encrypt certificate. It polls the phone's subscriptions, mirrors the newest 8 +episodes per show, detects, and serves both the offsets and the audio they belong to. The phone +pushes its feed list from `SubscriptionRepository.refreshAll`, prefers the server's audio when it +has it, and writes the offsets into the same `detectedIntroMs`/`detectedOutroMs` columns the +on-device detector used -- so playback needed no changes at all. `FingerprintWorker` and +`MidrollWorker` are deleted. + +Verified live, phone to server: `POST /api/subscriptions` returned 200 from the app, the server +woke, mirrored 8 Radiolab episodes, and detected across all of them in 3m59s. + +### Dynamic ad insertion is on every episode, and it is not subtle + +Every one of the 8 came back longer than declared: + +| episode | declared | served | inserted | +| --- | --- | --- | --- | +| Grass Apes | 22:05 | 28:18 | 6:13 | +| The Sweetest Thing | 31:02 | 37:15 | 6:13 | +| 23 Weeks 6 Days | 63:27 | 72:26 | 8:59 | +| Nigel and the Real Gannet | 25:54 | 33:01 | 7:07 | +| The Shoe Thrower | 77:29 | 87:02 | 9:33 | + +This also corrects the earlier pass in this document, which found declared == served on four +fetches made with plain `curl` and doubted whether insertion was happening at all. It is, on +every episode, when fetched by the server. Why `curl` got clean files and the server does not is +unexplained and worth knowing -- the only obvious difference is the User-Agent. + +### The confirmation threshold does not survive simultaneous fetching + +Detection reported the intro confirmed on 8 of 8, self-check passed. **It had locked onto an +advertisement.** + +Proved, rather than suspected: the 8-second segment the detector chose was extracted from the +server's copy of Grass Apes and searched for in the `curl` copy of the same episode fetched +hours earlier with no inserted advertising. **r = 0.0621.** It is not in the programme. It is in +the ad break. + +The mechanism is the Darknet Diaries trap at a new scale. The threshold's whole premise is that +three *independently fetched* episodes are unlikely to share an inserted ad. Mirroring 8 +episodes within the same minute from the same ad server makes them maximally dependent: whatever +campaign is running is in all 8, identical, and the detector finds it with scores of 0.93 to +1.00. The self-check cannot catch this -- it only proves the located segments are the same +audio, and they genuinely are. + +This is *worse* than the phone's original design, where episodes arrived days apart and so were +genuinely independent. Moving to a server fixed the cost problem and broke the independence +assumption the safety mechanism rests on. + +### What the published offsets currently are + +Head-window matches only, so every offset lands inside the first four minutes, and skipping to +the end of a matched segment skips pre-roll advertising. That is useful by accident, not by +design, and it will move unpredictably whenever the ad campaign rotates. **It is not intro +detection and must not be described as such.** + +### The fix, not yet made + +Record when each episode's audio was fetched, and require the agreeing episodes to span more +than one fetch occasion before a segment is trusted as the show's own. The mirror already rolls +forward one episode at a time as feeds update, so independence arrives naturally -- it is only +the initial batch that is simultaneous. Expect no offsets at all for the first day or two after +a show is added, which is the correct answer rather than a confident wrong one. + +There is a reframing worth considering instead, which the data argues for: what this reliably +detects, with very high confidence, is **the inserted advertising itself** -- because +simultaneous fetches share it exactly. Skipping ads is the actual goal, and the declared-versus- +served gap is a free, independent check on whether a scan has accounted for all of it. Detecting +ads directly may be a better target than detecting intros and hoping ads do not get in the way. |
