Skip to content

director: two ways a record aired twice in a day - #706

Merged
robert-dean merged 2 commits into
mainfrom
claude/duplicate-tracks-issue-efaaab
Oct 20, 2026
Merged

robert-dean merged 2 commits into
mainfrom
claude/duplicate-tracks-issue-efaaab

Conversation

@robert-dean

Copy link
Copy Markdown
Owner

On 2026-10-20 the station aired three records twice inside a 2-day repeat window: Detroit Rock City (10:30 and 14:08), Pride and Joy (07:38 and 09:25, both in Blues Highway), and Don't Stop Me Now (aired 10:00, chosen again at 13:36). There were two separate causes, fixed in one commit each.

A discovered copy was keyed by the provider's title, not the library row's

The model named "Detroit Rock City (Edit)". The strict name match missed the album cut the library has held since August, so the pick went to Spotify, which answered "Detroit Rock City - Edit". The ingest attached that copy to the existing row (created: false), but discover() keyed the pick from the provider's strings. The repeat window was asked about kiss:detroit rock city edit while play_history writes kiss:detroit rock city, so nothing could hold it. The feed showed it "discovered" at both 09:52 and 13:36.

When the ingest creates nothing, the pick is now keyed by the existing row's title and lead artist (new CandidatesRepository.findById), falling back to the provider's strings if the row can't be read.

The repeat window gave way whenever a batch came back short

At 08:45 a refill wanted 15 and the rules kept 14, so letRepeatsBackIn in PickResolver let Pride and Joy back in an hour after it aired, with eight records still queued. It did this silently: only the floor reported to RepeatWatch.

The window now gives way only when nothing else survived the rules, which is when the running order would actually run dry. Then it fills to want, oldest first, as before. The floor uses the same rule to decide when to read ages. PickResolver now reports the give-way and the floor no longer does, since the resolver decides what airs and two writers of one edge flag would flap. Callers that ask for no number (requests, mixed-in records) neither give way nor report.

Trade-off: a station whose whole reachable library is inside the window now adds a few records per refill and refills more often, instead of padding with repeats, until nothing fresh is left.

Checks

  • New resolver tests reproduce both live cases, plus rule tests for "short is not empty".
  • apps/api: typecheck clean (source and tests), 9919 tests pass, lint and prettier clean on the touched files.
  • docs/internals/programming.md updated; a changeset for each commit.

A pick the catalog misses by name is looked up at a provider and ingested,
and `discover()` keyed it by the provider's title and lead. That holds for
a new row, which the ingest writes with exactly those strings, but not for
a copy attached to a work the library already held: the row keeps its own
title, `play_history` writes that, and the repeat window was asked about a
song it never sees.

On 2026-10-20 the model named "Detroit Rock City (Edit)", the strict name
match missed the album cut held since August, Spotify answered "Detroit
Rock City - Edit", and the record aired at 10:30 and again at 14:08.
"Don't Stop Me Now" went the same way against its "Remastered 2011" row.

When the ingest reports it created nothing, the pick is now keyed by the
existing row's title and lead artist, read through a new
`CandidatesRepository.findById`; a row that cannot be read falls back to
the provider's strings as before.
`letRepeatsBackIn` gave way whenever a batch came back short of `want`,
and short is the ordinary case. On 2026-10-20 a refill wanted fifteen,
the rules kept fourteen, and "Pride and Joy" was let back in to make up
the number an hour after it aired, with eight records still queued. The
resolver did it silently: only the floor told `RepeatWatch`.

The window now gives way only when nothing else survived the rules,
which is when the running order would actually run dry; then repeats
fill the batch to `want`, oldest first, as before. A batch that brings
anything keeps the order growing and the director asks again when it
runs low. The floor reads the window's ages under the same rule.

`PickResolver` now reports the give-way to `RepeatWatch` and the floor
no longer does: the resolver decides what airs, a repeat the floor lets
back in can still be dropped there for a fresh record, and two writers
of one edge flag would put a row on the feed per refill. A caller that
asks for no number (a request, a mixed-in record) neither gives way nor
reports.
@robert-dean
robert-dean merged commit 2649f9f into main Oct 20, 2026
18 checks passed
@robert-dean
robert-dean deleted the claude/duplicate-tracks-issue-efaaab branch October 20, 2026 18:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant