diff options
| -rw-r--r-- | docs/superpowers/plans/2026-10-20-corrections-and-signature-library.md | 57 |
1 files changed, 56 insertions, 1 deletions
diff --git a/docs/superpowers/plans/2026-10-20-corrections-and-signature-library.md b/docs/superpowers/plans/2026-10-20-corrections-and-signature-library.md index 7ec6c52..2572cc3 100644 --- a/docs/superpowers/plans/2026-10-20-corrections-and-signature-library.md +++ b/docs/superpowers/plans/2026-10-20-corrections-and-signature-library.md @@ -180,7 +180,7 @@ Phone to server. Needs an endpoint and server-side storage. Design note: a verdi *range of a specific episode's audio*, so it is only meaningful for episodes whose bytes the server itself served — gate on `audioFromServer`, the same invariant the refresh sweep uses. -### 3. The index spike — NOT STARTED, and it is the gate +### 3. The index spike — DONE 2026-10-24. **It passes.** **Do this before anything else in the library, because it decides whether the library is possible.** A linear scan of N signatures against each episode does not survive: at ~0.33s per @@ -201,6 +201,61 @@ true match produces many hashes agreeing on one offset; noise scatters. If it cannot do both, fast, the library stops there and nothing else is wasted. +**Result: it does both, with room to spare.** Landmark hashing was built as a throwaway harness +against the live corpus and measured on 6 true repeats and 16 non-repeats. + +**The original named files had rotated out of the 8-episode window**, so the test set was rebuilt +from current audio and is stronger than the one it replaces: 6 positives and 16 negatives rather +than 2 and 3. Template: `e86df60c3d8ae9cfc67b0193` at 785-822s, a 37s advertising break. Scored +first with the existing correlator to establish ground truth, then with the index. + +| | correlator `r` | index votes | +|---|---|---| +| 6 repeats, within Up First | 0.590 - 0.910 | 813 - 1564 | +| 16 non-repeats, Serial + Heavyweight + one Up First | 0.077 - 0.120 | 27 - 94 | + +The separation is **8.6x** at its narrowest (813 against 94), against 4.9x for the correlator it +replaces. Any threshold between them works; nothing sits in the gap. + +**Offsets are good enough to act on, and every one is cheap to confirm.** Three agreed with the +correlator to the frame, two were 1.3s out, and all were re-scored by correlating the template +against a 45-second window at the claimed position -- which costs almost nothing next to scanning +a whole episode. The top-scoring negative confirmed at r=0.071, exactly as it should. + +So the architecture is **index proposes, correlator disposes**. That matters because the index +is not always right about *which* occurrence: in one episode the advertisement appears twice and +the index picked the weaker instance (r=0.357 where the stronger was 0.590). Confirming is what +turns a shortlist into a published break. + +**Costs, measured.** + +| what | cost | +|---|---| +| hashing a 37s signature | 9.8ms, paid once when stored | +| lookup, 1 signature against 23 indexed episodes | 196ms, paid per scan | +| building the index | ~8s per episode | +| peak memory, 23 episodes | 353MB | +| **500 signatures against 23 episodes** | **98s** | +| the same by linear correlation | ~63 minutes | + +About **forty times** better, which is the answer the gate was asking for. + +**Parameters that worked**, so this can be rebuilt test-first rather than rediscovered: 2000Hz +(Nyquist 1kHz is enough for speech), 512-sample frames, 256 hop, 6 frequency bands with one peak +each per frame, an energy floor of 2x the frame's mean bin, fan-out 3, pairs 1-20 frames apart, +hash = (binA, binB, frameGap) packed into 24 bits. + +**The one weakness, and the lever if it is ever needed.** 3.49M hashes collapsed into only 86k +distinct values -- about 40 postings each -- and that density is what makes a lookup cost 196ms +rather than microseconds. The peaks cluster because a band maximum repeats. More bands, finer +time resolution or a larger transform would spread them out and cut the lookup cost +substantially. Not needed to pass the gate; worth knowing before anyone optimises the wrong +thing. + +**The harness is deliberately not committed.** It read absolute `/site/listen.terst.org` paths +and had no tests; its output was an answer, not code to keep. Everything needed to rebuild it +properly is above. + ### 4. Store and age signatures — NOT STARTED Two kinds, which behave nothing alike: |
