summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/detection-findings.md91
1 files changed, 62 insertions, 29 deletions
diff --git a/docs/detection-findings.md b/docs/detection-findings.md
index 708400f..cacb2f0 100644
--- a/docs/detection-findings.md
+++ b/docs/detection-findings.md
@@ -9,15 +9,19 @@ The prototype is the right tool for this and the only one: it can hold a whole c
plot correlations, and sweep parameters in seconds. Do not tune the constants from the app.
**Update, later the same day:** the leading hypothesis below (the 8-second reference window
-being too wide for a ~6-second sting) is disproven. See "What the desktop session actually
-found" -- the production algorithm, run against real Up First audio at its real defaults,
-confirms cleanly on every pair tested, both ends. The mystery is now sharper, not solved: the
-identical algorithm works on desktop and reportedly found nothing on the phone. That gap is very
-unlikely to be in `DEFAULT_REFERENCE_SECONDS`, `MIN_SCORE`, `CONFIRM_THRESHOLD` or the resampler
--- all four were checked directly -- which points at something specific to the on-device run
-itself (which episodes, in what order, whether each `FingerprintWorker` run actually completed)
-rather than at the signal-processing approach. Diagnosing that needs on-device state, which this
-sandbox cannot reach; see "What to check on the phone" at the end.
+being too wide for a ~6-second sting) is disproven -- see "What the desktop session actually
+found." The production algorithm, run against real Up First audio at its real defaults, confirms
+cleanly on every pair tested, both ends.
+
+**Second update, the phone reconnected the same day:** pulled the live database and WorkManager's
+own execution history straight off it (read-only, via `run-as`). The pipeline is not broken --
+**Cruising the Waves Podcast reached a real Tentative candidate (confirmedCount=2) today.** Up
+First specifically is stuck: its `show_fingerprints` row hasn't updated since its *first* episode
+was ever processed, even though a second real episode was downloaded, played and decoded
+successfully (by a different worker) the next day. `FingerprintUpdater` upserts on every outcome,
+match or not, so that frozen timestamp means the second episode's comparison never ran at all --
+not a score that failed. See "What the phone actually showed" below for the detail and "What to
+check on the phone" for the one live test that would settle it.
---
@@ -127,26 +131,55 @@ one.
---
-## What to check on the phone
-
-Everything above rules out the algorithm and its tuned constants as an explanation, on real Up
-First audio, at the app's real settings. That leaves the actual on-device run as the place to
-look, and none of it can be done from this sandbox:
-
-- **What did the three downloaded episodes actually decode to?** A quick temporary log of
- `clip.samples.size` and a couple of sample values in `FingerprintUpdater.process` would show
- whether `MediaCodecClipSource` produced a full ~240s clip each time, or something truncated --
- a decode that silently stops early would explain "nothing found" without any correlation math
- being wrong.
-- **Did all three `FingerprintWorker` runs actually complete and persist?** `adb shell` +
- `sqlite3` against `show_fingerprints` after each download would show `confirmedCount` climbing
- toward 3 (or not) and whether `pendingEpisodeId` ever got set at all -- distinguishing "never
- got past Waiting" from "got to Tentative and stalled," which "Nothing found yet" in the UI
- cannot.
-- **Were the three episodes actually three *different* episodes?** `IntroOutroDetector.check`'s
- dedup guard silently no-ops on an id it has already seen (`lastConfirmedEpisodeId` or
- `pendingEpisodeId`) -- worth ruling out that a re-queued or re-triggered download fed the same
- episode through twice.
+## What the phone actually showed (2026-09-29, later)
+
+The phone reconnected mid-session. Pulled `listen.db` (via `run-as` + `adb exec-out cat`, no
+device modification) and `no_backup/androidx.work.workdb` -- WorkManager's own execution
+history, which nothing in this app writes to but which turned out to answer the question the app
+state alone couldn't.
+
+**The pipeline is not broken.** `show_fingerprints` for **Cruising the Waves Podcast** shows
+`kind=INTRO, confirmedCount=2, referenceClipPcm` populated -- a real Tentative candidate, found
+today, from an ordinary download. Something *does* reach Tentative on this exact build, on this
+exact phone. The mechanism works in general; Up First specifically is the anomaly, not Tier 3.
+
+**Up First's `show_fingerprints` row is frozen at its very first episode.** Both INTRO and OUTRO
+show `confirmedCount=0`, `referenceClipPcm=NULL`, `pendingEpisodeId` pointing at one single
+episode ("Powerful storms hit the US..."), and `updatedAtMs = 2026-09-27T02:19` -- the moment
+that first episode was processed. A second real episode ("Can clergy candidates help Democrats
+win in red states?") was downloaded, played and swept by retention the *next day*, and its
+`midrollCheckedAtMs` is set, proving `MidrollWorker`'s `decodeFull` read that file successfully
+that day. But `show_fingerprints.updatedAtMs` never moved again.
+
+That is the specific, damning fact: `FingerprintUpdater.processEnd` calls `fingerprints.upsert(...)`
+on **every** outcome -- a confirmed match, a failed match, all of it -- so if a comparison
+involving the second episode had run at all, this row would show a later timestamp regardless of
+whether it found anything. It doesn't. **The second episode's `FingerprintWorker` run either was
+never enqueued, or `decodeHead`/`decodeTail` both returned null for it** -- and the latter looks
+unlikely given `decodeFull` (the same underlying decode, just a different window) succeeded on
+the identical file later that day. `EpisodeDownloader.downloadOverHttp` was read end to end look
+for a race between "downloaded" and "playable" -- there isn't one, it's a fully blocking
+download-to-`.part`-then-atomic-rename before `onDownloaded` fires, so a half-written file is not
+the likely explanation either.
+
+WorkManager prunes completed `WorkSpec` rows after roughly a week, so the actual historical
+`FingerprintWorker` run (if any) for that second episode is already gone -- only today's runs and
+the next periodic `MidrollWorker` firing were still in the table. This is now a live-observation
+question, not an archaeology one.
+
+## What to check on the phone (updated -- narrower than the original three)
+
+- **Trigger a fresh Up First download and watch `androidx.work.workdb` and `show_fingerprints`
+ immediately after**, the same way this session just did. If a `FingerprintWorker` `WorkSpec`
+ row appears for the new episode's id and reaches `SUCCEEDED`, but `show_fingerprints.updatedAtMs`
+ still doesn't move, that is a real bug in `processEnd`/the upsert path, reproduced live. If no
+ `WorkSpec` row appears at all, `onDownloaded` isn't firing for this show specifically -- check
+ whether Up First episodes are reaching playback through a route other than
+ `EpisodeDownloader.download()`.
+- **If a `FingerprintWorker` row does appear and reaches SUCCEEDED with no DB change**, add a
+ temporary log of `clip.samples.size` in `FingerprintUpdater.process` for exactly this case --
+ the one thing still not directly observed is whether `decodeHead`/`decodeTail` returned null or
+ an empty/garbage clip for that specific file.
## Experiments, in order (updated)