Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
id: TASK-80
title: Stop reading an unrecorded bitrate as a bad one
status: Done
assignee: []
created_date: '2026-09-19 03:14'
updated_date: '2026-09-19 03:25'
labels: []
dependencies: []
priority: high
ordinal: 80000
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
meetsQualityFloor compares station.bitrate to a floor, and the directory writes 0 when it simply has not recorded a bitrate. Unknown is therefore judged as 0 kbps and the station is dropped. Measured share of live stations with no recorded bitrate: Bangladesh 43%, India 49%, Egypt 45%, Nigeria 50%.

This is the main reason Dhaka had no voices. Bangladesh has 6 speech stations; 3 are offered, and those 3 are two Quran recitation channels plus Jago FM, whose stream is dead. The three dropped ones, including Radio Vivid Voice and Spice FM which are tagged talk outright, were dropped only because no bitrate is on file. Nigeria loses 13 of its 18 speech stations the same way.

Treat an unrecorded bitrate as unknown rather than as zero, and let the stream probe decide, since it already rejects anything that does not answer. Rank stations with a known good bitrate above unknown ones so quality still wins where it is known.
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 A station with no recorded bitrate is not dropped by the quality floor
- [ ] #2 A station with a recorded bitrate below the floor is still dropped
- [ ] #3 Known-good bitrates are preferred over unknown ones in ordering
- [ ] #4 Measured voices pool for BD, EG, NG, MX, TR, CU recorded before and after
<!-- AC:END -->

## Implementation Notes

<!-- SECTION:NOTES:BEGIN -->
Measured voices pool per country, before -> after:
BD 3 -> 6, EG 2 -> 9, NG 5 -> 18, KE 4 -> 10, MX 3 -> 5, PK 8 -> 10, CU 1 -> 2, TR 9 -> 10, VN 14 -> 17, IN 8 -> 8.
Music pools roughly double in the same countries (IN 37 -> 83, NG 25 -> 43).

Dhaka now offers six voice stations instead of three, and the three added are the ones tagged talk outright: Radio Vivid Voice, Spice FM and Universal Health Radio.

On the third acceptance criterion: the candidate pool is deliberately NOT partitioned into known-bitrate first. Doing so would bury the unknown stations behind the same few known ones, which in Bangladesh means the probe would keep landing on the two Quran channels and the dead Jago FM: the exact complaint this task exists to fix. Quality preference is applied where it costs no variety, in dedupe's betterEntry, which keeps the row with a recorded bitrate when two entries describe one stream. The stream probe decides the rest.
<!-- SECTION:NOTES:END -->
18 changes: 18 additions & 0 deletions lib/stations/listening-mode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,24 @@ describe("the quality floor", () => {
it("does not let a floor of zero through", () => {
expect(meetsQualityFloor(talk("a", 0))).toBe(false);
});

it("lets a station through when no bitrate was ever recorded", () => {
// The directory writes 0 when it has nothing on file, which normalizing
// turns into undefined. Reading that as 0 kbps dropped 43% of Bangladesh's
// live stations and 50% of Nigeria's, including talk-tagged ones. Unknown
// is not bad: the stream probe decides whether it actually answers.
const unknown = makeStation("unknown", {
countryCode: "BD",
tags: ["talk"],
bitrate: undefined,
});
expect(meetsQualityFloor(unknown)).toBe(true);
});

it("still refuses a bitrate that is on file and below the floor", () => {
expect(meetsQualityFloor(music("a", 32))).toBe(false);
expect(meetsQualityFloor(talk("b", 16))).toBe(false);
});
});

describe("matchesMode", () => {
Expand Down
19 changes: 18 additions & 1 deletion lib/stations/listening-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,25 @@ export function minBitrateFor(station: Station): number {
return isSpeechStation(station) ? MIN_SPEECH_BITRATE : MIN_MUSIC_BITRATE;
}

/*
* An unrecorded bitrate is not a bad one.
*
* The directory writes 0 when it has no bitrate on file, which normalizing
* turns into undefined. Reading that as 0 kbps failed the floor and dropped the
* station outright, and the gap is not small: of the live stations measured,
* 43% in Bangladesh, 45% in Egypt, 49% in India and 50% in Nigeria carry no
* bitrate at all. It fell hardest on exactly the stations this mode exists to
* find. Bangladesh has six speech stations and offered three, all because
* Radio Vivid Voice and Spice FM, both tagged talk, had nothing on file.
* Nigeria lost thirteen of eighteen the same way.
*
* So unknown passes, and the stream probe decides: it already rejects anything
* that does not answer, which is the thing a listener actually cares about. A
* bitrate that is on file and genuinely below the floor is still refused.
*/
export function meetsQualityFloor(station: Station): boolean {
return (station.bitrate ?? 0) >= minBitrateFor(station);
if (station.bitrate === undefined) return true;
return station.bitrate >= minBitrateFor(station);
}

/** Does this station suit what the listener asked for? */
Expand Down
Loading