diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-09-29 06:32:10 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-09-29 06:32:10 +0000 |
| commit | 26c95926cecb036a23ff0c53700e1219678596b8 (patch) | |
| tree | 20d0da34767f9f9e26fbcaf4242c72bad7fa99be | |
| parent | 16a47088a315786a940590794d7ce4003447cf7c (diff) | |
Write the desktop session's brief for Tier 3 detection
The fingerprinting runs on a device now and has still confirmed nothing for
a real show. That is an open question, not a known bug, and answering it
needs the prototype rather than the app -- only the prototype can show what
a parameter change costs in false positives, which is the number that
matters here.
docs/detection-findings.md collects what this round established: that the
pipeline works, that the confirmation threshold earns its place, and the
finding that reframes the problem -- dynamic ad insertion means the same
Grass Apes came back 29:34 on one fetch and 27:39 on another, so ad content
and the offset of everything behind it differ per request. It lists the
experiments in order, including using insertedAdMs as ground truth for the
midroll scan, and what not to touch.
Linked from the known-gaps list, which is where a future session looks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
| -rw-r--r-- | CLAUDE.md | 16 | ||||
| -rw-r--r-- | docs/detection-findings.md | 124 |
2 files changed, 133 insertions, 7 deletions
@@ -194,13 +194,15 @@ by default and correct; it is simply waiting for a publisher who marks breaks. - **Auto-downloads are not retried.** A rule's download that fails is left FAILED rather than requeued: retrying forever against a 404 would burn the battery, and the failed row is visible in the episode list. Retry is the manual Download button. -- **Tier 3 has never confirmed a real intro or outro.** The pipeline runs on hardware and the - worker succeeds, but three consecutive Up First downloads produced no candidate at either - end. Untested hypothesis: `FingerprintUpdater.DEFAULT_REFERENCE_SECONDS` is 8 and the - prototype measured Up First's sting at about 6, so every 8-second window compared also - contains two seconds of different speech. Do not change that constant without re-running the - desktop prototype -- it is tuned, and the confirmation threshold is what keeps a rotating ad - from being learned as an intro. +- **Tier 3 has never confirmed a real intro, outro or midroll.** The pipeline runs on hardware + and the worker succeeds, but three consecutive Up First downloads produced no candidate at + either end. Two live hypotheses -- an 8-second reference window against a ~6-second sting, + and pre-roll ads moving the intro to a different offset in every file. **See + `docs/detection-findings.md`**, which is the brief for the desktop session that settles it: + what is already known, the experiments in order, and what not to touch. Do not tune + `DEFAULT_REFERENCE_SECONDS`, `MIN_SCORE` or `CONFIRM_THRESHOLD` from the app -- the app + cannot show you what a change costs in false positives, and the threshold is the whole + safety mechanism. - **Android Auto is verified in a real car**, as of 2026-09-28. It appears, and connects. The notification Peter saw on first connect was Android Auto's own new-media-app announcement, diff --git a/docs/detection-findings.md b/docs/detection-findings.md new file mode 100644 index 0000000..1eac20a --- /dev/null +++ b/docs/detection-findings.md @@ -0,0 +1,124 @@ +# Tier 3 detection: what is known, and what the next desktop session should measure + +Written 2026-09-29, after getting both halves of the fingerprinting onto a device for the first +time. The code is built, tested and running. **It has not yet confirmed an intro, an outro or a +midroll for a real show**, and the reason is an open question rather than a known bug. This is +the brief for answering it. + +The prototype is the right tool for this and the only one: it can hold a whole corpus in memory, +plot correlations, and sweep parameters in seconds. Do not tune the constants from the app. + +--- + +## What is settled + +**The pipeline runs on hardware.** `MediaCodecClipSource` decodes, `FingerprintWorker` completes +SUCCESS per download, the re-decode path for the pending episode is exercised. This was never +true before 2026-09-28 and two real defects were hiding behind it (below). + +**The confirmation threshold earns its place.** Three independently-fetched episodes must agree +before a candidate is trusted. The original prototype found why: two Darknet Diaries episodes +fetched minutes apart agreed on a segment that turned out to be a rotating inserted ad, not the +show's intro. Everything below makes that trap *more* likely, not less. Do not lower it to make +something confirm. + +**Storage limits are real and were learned the hard way.** Android reads every Room row through +a CursorWindow that refuses anything over 2MB *on the way out* — the insert succeeds and the +next read throws. A 240-second clip at 8kHz 16-bit is 3.84MB. Intro/outro pending clips are no +longer stored at all (the episode id is, and the audio is re-decoded); midroll candidate clips +live in files. `StoredClip` owns the limit and `StoredClipSizeTest` pins it. + +--- + +## The finding that changes the problem + +**Dynamic ad insertion is not a detail; it is the environment.** + +Radiolab declares Grass Apes at `00:22:05`. Measured on two separate fetches of the same +episode: **29:34 once, 27:39 another time.** The ads are stitched in per request, so: + +- the served file's length is not a property of the episode, +- the ad *content* differs between two downloads of the same episode, +- and anything at a fixed offset in one file is at a different offset in the next. + +`insertedAdMs` (declared vs measured) now exposes this per episode in the app. It is free, needs +no audio analysis, and is the obvious cross-check on the detector: **whatever the midroll scan +finds should add up to roughly that much.** If it finds 30 seconds where the gap says seven +minutes, the scan is missing breaks; if it finds more, it is matching content. + +This reframes the intro/outro question. The head window is 240 seconds, which was chosen to +comfortably contain an intro. With a variable-length pre-roll in front of it, a show's real +intro sits at a *different offset in every file* — which the scan does handle, since it searches +the window rather than a fixed position — but the window now has to contain pre-roll **plus** +intro, and the pre-roll is the thing most likely to produce a false match between two +close-together fetches. + +--- + +## The specific open question + +Three consecutive Up First downloads left both ends at "Nothing found yet". + +`FingerprintUpdater.DEFAULT_REFERENCE_SECONDS` is **8**. The original prototype measured Up +First's intro sting at about **6 seconds**. If that is right, every 8-second window being +compared also contains ~2 seconds of differing speech, which would plausibly hold correlation +under `MIN_SCORE` (0.6) for every pair. That is the leading hypothesis and it is untested. + +The competing hypothesis is that pre-roll variability is defeating it — that there is no stable +8-second stretch anywhere in the head window because the ads differ per fetch and the intro's +position moves with them. + +These are distinguishable by measurement, and the measurements are cheap. + +--- + +## Experiments, in order + +1. **Quantify pre-roll variability.** Fetch the *same* episode three times, some hours apart. + Diff the first 240 seconds. How much differs, and where does the common content start? This + also tells you whether `insertedAdMs` varies for one episode, which it did for Grass Apes. + +2. **Locate and measure a real intro.** Across several Up First episodes, find the sting: where + does it start (after how much pre-roll) and how long is it actually? The 6-second figure is + from an earlier note and should be confirmed, not inherited. + +3. **Sweep the two constants against a real corpus.** `DEFAULT_REFERENCE_SECONDS` at 4, 6, 8 and + `MIN_SCORE` around 0.6. Report what confirms and — more importantly — what *falsely* confirms. + A setting that finds Up First's intro but also learns a rotating ad is worse than the current + state, which at least fails safe. + +4. **Check 240 seconds is still enough.** Pre-roll plus intro, on the worst show you can find. + If it is marginal, the window is a cheaper thing to raise than the thresholds — but note it + costs decode time per download, and the clip must never be persisted (see the CursorWindow + note above). + +5. **Validate midroll totals against `insertedAdMs`.** Take a show with a known declared/measured + gap, run the midroll scan across several episodes, and compare the total detected break + duration against the gap. This is the best available ground truth and it costs nothing. + +6. **Re-check the Darknet Diaries trap under the new understanding.** The 2017 episode that + shared an "intro" with 2026 episodes was the original evidence for the threshold. Given ad + insertion varies per *request*, re-fetch that pair now and see whether the false match still + reproduces — it may have been a stable house promo rather than a rotating ad, which would + change what the threshold is actually protecting against. + +--- + +## Do not + +- **Do not change `DEFAULT_REFERENCE_SECONDS`, `MIN_SCORE` or `CONFIRM_THRESHOLD` from the app.** + They are tuned numbers and the app cannot show you what a change costs in false positives. +- **Do not persist a decoded clip in a database row.** See the CursorWindow note. +- **Do not read `EpisodeEntity.durationMs` when you mean the real length.** It is the feed's + claim, it is rewritten on every refresh, and on these shows it is minutes short. Use + `playbackDurationMs`. +- **Do not lower the confirmation threshold to make something confirm.** Failing to skip is a + non-event; skipping real content is the failure that loses trust in the feature. + +--- + +## Environment note + +YouTube extraction and resolution **cannot be exercised from tungsten** — every watch URL gets a +302 to a bot-check page. Anything touching YouTube has to be verified on the phone. Podcast +feeds, Room migrations, playback and the fingerprint pipeline are all fine on the emulator. |
