diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-09-26 12:57:26 -1000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-09-26 12:57:26 -1000 |
| commit | 4e37185852ef3d1a2ed6348dd4c513648dafdd5d (patch) | |
| tree | e6142a1ed2d5f8de77b293df2602f2e49fc85fd3 /CLAUDE.md | |
| parent | 6a1847b391b87969a0fc4682a8fe33642d98105d (diff) | |
Tier 3 skip detection: audio fingerprinting, prototyped and built
Closes the last deferred Phase 2 item. Desktop-prototyped first, per the
design plan's own instruction, against three real shows (see the prototype
findings recorded in memory): NPR Up First (a clean ~6s intro sting, r
0.96-0.998 across every pair tested), Tangle (a long 60-90s open/sponsor
read, equally reliable), and Darknet Diaries (no real intro -- a segment
that matched between two temporally-close episodes turned out to be a
dynamically-inserted ad, confirmed by checking a 2018 episode that matched
the same "intro" despite the multi-year gap).
That last finding drove the actual design: IntroOutroDetector requires 3+
independently-fetched episodes to agree before trusting a candidate and
auto-applying it, which is exactly what the Darknet Diaries ad would not
have survived. The confirmation threshold is the safety mechanism, not
just caution for its own sake -- and it's now a parameter, not a hardcoded
assumption, after coverage review found the "still tentative" branch was
unreachable at the original threshold.
- AudioCorrelation: FFT-based normalized cross-correlation, a Kotlin port
of the validated prototype. Tested against numpy/scipy-derived ground
truth fixtures, not just self-consistency -- the prototype's own
normalization bug (global mean instead of each window's local mean,
producing a bogus 0.98 "match" plain correlation put at -0.02) is exactly
what that guards against being ported here unnoticed.
- IntroOutroDetector: the pure state machine (waiting/tentative/confirmed/
discard-on-mismatch), mirroring DripSchedule's shape.
- MediaCodecClipSource: the one Android-only piece (MediaExtractor/
MediaCodec decode to mono 8kHz PCM), on the framework-adapter coverage
exclusion list for the same reason PlayerConnection is.
- Storage: AppDatabase 6->7, a new show_fingerprints table (one row per
show per intro/outro, tracking the current candidate clip and how many
episodes have confirmed it) and two new nullable EpisodeEntity columns.
Tier 2's manual per-show offset remains the fallback -- PlaybackProgress
itself is unchanged; DetectedSkip.kt is the entire integration surface.
- Trigger: EpisodeDownloader gained an onDownloaded hook (every download
route ends up there, manual or queued) firing a new one-shot
FingerprintWorker per episode.
Coverage improved (90.13% -> 91.70%): the new pure logic is fully tested,
and closing two real gaps the coverage review surfaced (an untested
first-two-episodes-disagree path, and ShowFingerprintEntity's hand-written
equals/hashCode, needed because a ByteArray property breaks the generated
one) accounted for more than the new Android-glue lines cost.
Not yet verified on a device -- no phone connected this session. The
MigrationTest 6->7 case and the actual decode/match pipeline both need a
real run before this is trusted with real playback.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sj3CoWEedM56bebByKgNxA
Diffstat (limited to 'CLAUDE.md')
0 files changed, 0 insertions, 0 deletions
