docs(roadmap): the login the catalogue asks for, and an order to read the lines by - #204
Merged
Merged
Conversation
… the lines by Adds a sixth line and a priority column. The new line 5 — an opt-in, guided login for an auth-gated source — is not a new want: DESIGN.md §5 excluded NetEase (login cookie, VIP) and Spotify (no no-app-no-membership path; librespot needs Premium) with reasons, and spec 03-01 deferred it as one work item naming cliamp as the credential reference. What is new is that yt-dlp, already murmur's only provider, ships the netease:* extractors and takes --cookies / --cookies-from-browser, so the NetEase half is a credential reaching the provider we run, not a second provider. Spotify gets the seam and an honest refusal. The P column gives the lines an order the row numbers no longer carry: line 0 blocks every by-ear judgement above it, lines 1/2/5 change what murmur is, line 3 is reliability, line 4 is distribution. The Tracked-as cells catch up with what has landed since the file was written (the lead-in half of line 1, line 2 built and unmerged). Line 0 also records a status check: no fix has landed for the dropped first line, the settled guard predates the repro, and a stub run neither reproduces nor clears it — the suspected seam is unconfirmed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sx3J45TyoScFDneRF7qX14
`PersistentMemoryStore.forget`'s reload assertion reopened the store with the real clock while the rows under it were written on a frozen 2026-09-01, so the 48h recent window in `load()` dropped them for age. It passed on the day it landed and went red on 2026-09-04 with nothing changed — a calendar failure, not a regression. The reopen now reads the same clock as the writes, which is what the assertion was ever about: the row survived `forget`, not the window. Found on CI for the roadmap PR, which touches no code. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sx3J45TyoScFDneRF7qX14
Six factual corrections from the codex review, all of them places where the document overstated what it knew: - Line 1: speaking over a ducked track is not the missing piece — the lead-in (#199) and the coda (#200) both do it today. What is left in #163 is the autonomous mid-track beat, so the line and its table cell say that instead. - Line 5: a yt-dlp auth failure comes back through `provider.resolve` and is caught by `submit_pick` as "pick another" — it never reaches the stream probe, so an expired cookie is a silent stream of rejected candidates, not "one more dead probe". - Line 5: a free Spotify account does have a stream (the desktop app, ads and on-demand limits — DESIGN §5); the refusal is that murmur cannot conduct it, the external-player duck path being out of scope in spec 03-02. - Line 5: says outright that it does not reopen DESIGN §8's v1 exclusion. - Line 0: the crash-report offer landed 08-31, after the 08-25 repro, so it cannot have eaten that line; the repro conditions are the August boot state, and the offer is a separate new reader worth its own check. - Line 0: #187 did touch `LineQueue` (hasReader + the IpcHost echo flow), so the claim narrows to the take/peek semantics the plain path uses. Peer review (codex gpt-5.6-sol): 6 findings, 6 applied, 0 dismissed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sx3J45TyoScFDneRF7qX14
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
ROADMAP.mdgains a sixth line and a priority column, and itsTracked-as cells catch up with what has landed since it was written.
The new line 5 — an opt-in login for an auth-gated catalogue (P1)
Not a new want:
specs/DESIGN.md§5 already excluded both sources by name andsaid why — NetEase Cloud Music has the best Chinese catalogue but only
unofficial APIs, needs a login cookie, and gates its good tracks behind VIP;
Spotify has no clean no-app-no-membership path, and headless librespot needs
Premium.
specs/spec03/03-01-brain-harness.mddeferred it as a single workitem and named cliamp as the credential
reference — the auth flow only, never its user-picks interaction model.
What is new is the lazy road in: yt-dlp — already murmur's only provider —
ships
netease:song / playlist / singer / djradioextractors and takes--cookies FILE/--cookies-from-browser(checked against yt-dlp2026.08.19). So the NetEase half is not a second provider; it is a credential
reaching the provider murmur already runs, plus URL-shaped candidate sources
beside the open-ended search.
MusicProvider(src/contracts.ts:175) issearch+resolvewith no notion of a source that can fail on auth, andsrc/app.ts:248constructsYtDlpMusicProviderdirectly — so an expired cookiewould surface today as one more dead stream probe, which is the exact confusion
line 3 exists to remove. Spotify gets the seam and an honest refusal.
Opt-in, never a shipped default (DESIGN §3.7's personal-experiment tier): the
default install stays login-free yt-dlp.
The P column
The row numbers were the order, and the order has moved. P0 = line 0, because
every by-ear judgement above it is worthless while the listener's first typed
line disappears. P1 = lines 1, 2 and 5 — the ones that change what murmur is.
P2 = line 3 (reliability). P3 = line 4 (distribution and not rotting), with a
note that its eval half (#98) becomes P2 the moment lines 1/2 land, since both
are entirely stochastic behaviour.
Line 0 gets a status check
Recorded rather than left for the next session to re-derive: no fix has
landed for the dropped first line — the
settledguard inlineReaderpredates the 2026-08-25 repro (it came in on 08-18/08-19) and
LineQueuehasnot changed since. A stub plain-mode run with a pre-seeded persona echoed and
acted on the first typed line, but that path runs with no harness, so neither
the crash-report offer nor the setup conversation opens a pre-broadcast reader
— it therefore neither reproduces the bug nor clears it. The suspected seam
also reads clean today (every
read()is awaited;settledis set in therace's own
finally), so the suspected cause is marked unconfirmed and thenext attempt should start from the repro conditions, not from that seam.
One test fix rides along
CI came back red on a docs-only branch:
test/memory-fold.test.ts:312reopenedPersistentMemoryStorewith the real clock while the rows under it werewritten on a frozen
2026-09-01, so the 48h recent window inload()droppedthem for age. It passed the day it landed (#196) and went red on 2026-09-04
with nothing changed — a calendar failure, not a regression, and it blocks
every PR until it is fixed. The reopen now reads the same clock as the writes,
which is what that assertion was ever about: the row survived
forget, not thewindow.
Verification
Docs, plus that one test line.
pre-commit run --files ROADMAP.md→ source-language gate passed;tsc / oxlint / path-governance had no files to check. Every factual claim in
the new text was checked against the tree:
yt-dlp --list-extractorsandyt-dlp --helpon 2026.08.19 for the extractors and cookie flags,git blamegit logfor thesettledguard's date andLineQueue's history, and thetwo code references (
src/contracts.ts:175,src/app.ts:248) read directly.Full local gate after the test fix:
npx vitest run --dir test1366 passed / 0failed,
tsc --noEmitclean,oxlintclean.Peer review (codex
gpt-5.6-sol): 6 findings, 6 applied, 0 dismissed —verdict was
request changes, all six on claims the document overstated, andall six now corrected in a follow-up commit:
lead-in (feat(music): the way into a track, not a label on it [spec 03-02] #199) and the coda (feat(director): a coda — the beat that knows the song happened [spec 04] #200) both do it today; Interject a talk beat over a ducked song: the engine ducks, the director never asks [spec 03-02 §3.5] #163 is the autonomous
mid-track beat, and the line and its table cell now say that;
provider.resolveand is caught bysubmit_pickas "pick another" — it never reaches the stream probe, so anexpired cookie reads as a silent run of rejected candidates, not "one more
dead probe";
on-demand limits, per DESIGN §5) — the refusal is that murmur cannot conduct
it, the external-player duck path being out of scope in spec 03-02;
have eaten that first line — the repro conditions are the August boot state,
and the offer is a separate new reader worth its own check;
LineQueue(hasReader()+ theIpcHostecho flow), so the"unchanged" claim narrows to the take/peek semantics the plain path uses.
It also confirmed independently that yt-dlp 2026.08.19 lists the cited NetEase
extractors and accepts both cookie options, and that the two code references
match.
AI coding brief
Original request. The user asked what is on the roadmap and what is done —
which surfaced that
ROADMAP.mdhad gone stale (line 2 built and unmerged,line 1 half-landed). They then asked to add the NetEase/Spotify login they
remembered from the original specs, mark it P1, and assign priorities to the
existing lines. The why: the roadmap is the document the README points at, and
an order that only lives in a conversation is not an order.
Manual interventions. The user set line 5's priority (P1) themselves and
left the rest of the priorities to analysis. They also pushed back on line 0 —
"I thought that was fixed" — which turned into the status-check paragraph after
git blameshowed the guard predates the repro and a stub run turned out toprove nothing either way.
Retro. The roadmap and the issue tracker had already drifted apart in four
days; reading
gh issue list+gh pr listbefore answering "what is done"was what caught it, and doing that first would have made the first answer
correct rather than the second. Verifying the yt-dlp extractor claim before
writing it into the doc (one
--list-extractorscall) is what turned line 5from "build an auth provider" into "pass a cookie to the provider we run" —
worth the 20 seconds, since it changes the size of the work.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Sx3J45TyoScFDneRF7qX14