diff options
| author | Claude <noreply@anthropic.com> | 2026-10-20 06:52:17 +0000 |
|---|---|---|
| committer | Claude <noreply@anthropic.com> | 2026-10-20 06:52:17 +0000 |
| commit | d53a8c54351ccf5e0ecfd890abe53e13c65c60fa (patch) | |
| tree | 4f439a8b6c27203754c34045dfa1574a5447acee /server/internal | |
| parent | 9cc92e743dda2609a67595439c4694f6a4efae27 (diff) | |
Publish how many episodes shared each break, and plan the rest
The server has computed and stored Partners since ad detection shipped --
state.json carries it on every break -- but breakRange never put it on the
wire, so the phone's new tap-a-break popup could only ever say "the server
did not say how many other episodes carried this audio". That count is the
one piece of evidence a listener can weigh before judging a break, and the
popup exists to show it.
My brief for the popup asserted the server already sent it. It did not.
The implementing agent checked rather than taking my word, which is why
this is a two-line fix now instead of a wrong "why" line forever.
Also lands the handover plan for the correction channel and the signature
library, written before a context compaction, including the gesture design
Peter specified for the notification button and the jump-size argument he
correctly rejected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AwnALZL6bD4VBtATDVv3B
Diffstat (limited to 'server/internal')
| -rw-r--r-- | server/internal/api/api.go | 11 | ||||
| -rw-r--r-- | server/internal/api/api_test.go | 23 |
2 files changed, 33 insertions, 1 deletions
diff --git a/server/internal/api/api.go b/server/internal/api/api.go index e50c94e..0aeef8a 100644 --- a/server/internal/api/api.go +++ b/server/internal/api/api.go @@ -74,6 +74,10 @@ type breakRange struct { StartMs int64 `json:"startMs"` EndMs int64 `json:"endMs"` Kind string `json:"kind,omitempty"` + // Partners is how many other episodes were found to carry this audio. The phone shows it + // when a break is tapped: it is the only evidence a listener can weigh before deciding + // whether the detector got this one right. + Partners int `json:"partners,omitempty"` } // Handler returns the routed, authenticated handler. @@ -164,7 +168,12 @@ func (s *Server) episode(w http.ResponseWriter, r *http.Request) { breaks := make([]breakRange, 0, len(found.Breaks)) for _, br := range found.Breaks { - breaks = append(breaks, breakRange{StartMs: br.StartMs, EndMs: br.EndMs, Kind: br.Kind}) + breaks = append(breaks, breakRange{ + StartMs: br.StartMs, + EndMs: br.EndMs, + Kind: br.Kind, + Partners: br.Partners, + }) } writeJSON(w, http.StatusOK, episodeResponse{ Status: "ready", diff --git a/server/internal/api/api_test.go b/server/internal/api/api_test.go index 028bbd8..d4d3ee6 100644 --- a/server/internal/api/api_test.go +++ b/server/internal/api/api_test.go @@ -347,3 +347,26 @@ func seedMirrored(t *testing.T, st *store.State, audioDir, contents string) { func episodeID(st *store.State) string { return st.Match("https://f", "g1", "", "").ID } + +// Partners -- how many other episodes carried the same audio -- is the one piece of evidence a +// listener can judge a break by, and the phone's popup exists to show it. The server has always +// computed and stored it; it simply never put it on the wire, so every break arrived claiming +// nothing was known about it. +func TestEpisodeResponseCarriesHowManyEpisodesSharedEachBreak(t *testing.T) { + s, st, _, audioDir := newServer(t) + seedMirrored(t, st, audioDir, "audio-bytes") + e := st.Match("https://f", "g1", "", "") + e.Breaks = []store.Break{{StartMs: 0, EndMs: 98_000, Kind: "ad", Partners: 6}} + + rec := get(t, s, "/api/episode?feed=https://f&guid=g1") + var got episodeResponse + if err := json.Unmarshal(rec.Body.Bytes(), &got); err != nil { + t.Fatal(err) + } + if len(got.Breaks) == 0 { + t.Fatal("no breaks found") + } + if got.Breaks[0].Partners != 6 { + t.Errorf("partners %d, want 6", got.Breaks[0].Partners) + } +} |
