Repository navigation
test(js): say the fixed cache window, not maxAge, keeps a group cached - #7694
Conversation
Quest-Claim: 633c447f8f7be612
The JS track cache evicts an idle group on its fixed 30 s CACHE_WINDOW; Track.Info.maxAge only bounds which cached groups a reader still gets. Several tests, comments, and docs called maxAge "retention" or relied on it to keep or drop cached groups. - js/watch retention test: drop the maxAge that claimed to keep the replay cache flat; it had no effect on what the test counts. - track/broadcast tests: rename the ones that called maxAge a retention window, and say the stalled-track test checks staleness, not eviction. - doc/lib/js/net.md: state the 30 s idle window and that neither maxAge nor delay.max changes it. - doc/lib/js/publish.md: video's cache keeps groups for the window, and the meta.json example no longer sets a day-long maxAge to replay the last value, which the live edge already does. - MIGRATE.md and a lite publisher comment: call maxAge a staleness bound. Finishes quest/m1/js-cache-window.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: 5137a69
The revised distinction between delivery staleness and idle cache retention matches the implementation, and simplifying the leak test avoids implying that maxAge controls eviction. No actionable bugs found in this static review. I did not run the tests or mutation check.
|
No actionable comments were generated in the recent review. WalkthroughThe changes clarify that Merge Risk:
|
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- JS docs align with the fixed cache window.
doc/lib/js/net.mdgains a bullet on the 30 s idle window and its live-edge exemption, and now callsTrack.Info.maxAgethe publisher's staleness bound that capsdelay.maxand fetches rather than "retention". publish.mdencoding section corrected. The video cache keeps an idle group for 30 s regardless ofmaxAge; raw PCM history is the part actually bounded bymaxAge(30 s fallback). Themeta.jsonexample drops its day-longmaxAgeand the now-unusedMilliimport.MIGRATE.mdandlite/publisher.tsreworded. "Publisher retention is optional" heading becomes "Track.Info.maxAgeis optional", and "retention bound" becomes "staleness bound".- Tests renamed / one option dropped.
track.test.tsandbroadcast.test.tsnames now saymaxAgewhere they mean staleness;js/watch/src/retention.test.tsdropsmaxAge: Milli(1)since the fixed window keeps the groups regardless. - Quest retired.
quest/m1/js-cache-window.mdand itsREADME.mdline are deleted.
I verified the load-bearing claims against source: CACHE_WINDOW/CACHE_EXPIRY is 30 s (js/net/src/ledger.ts:22) matching Rust cache::DEFAULT_EXPIRY (rs/moq-net/src/model/cache.rs:89), #prune evicts on write-idle activity independent of maxAge, maxAge only clamps subscriber/fetch budgets, and the "unless it failed" edge exemption matches #edge(). The renamed heading has no TOC anchor, no references to js-cache-window remain, and the removed Milli import is unused in that snippet. I could not run bun test here because dependency installation fails in this environment (js/libav needs Nix), so the test-pass claims rest on the author's runs.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Finishes quest/m1/js-cache-window.md, a follow-up of moq-dev/moq#7219.
Problem
The JS track cache evicts a group after 30 s with no writes (
CACHE_WINDOWinjs/net/src/track.ts, matching Rustcache::DEFAULT_EXPIRY).Track.Info.maxAgedoesn't change that. It only decides which cached groups a reader still receives. Several tests, comments, and docs still calledmaxAge"retention" or relied on it to keep or drop cached groups.Approach
Search. I grepped the JS tests,
doc/, and@moq/net's docs formaxAgeused as retention. As a mutation check, I disabled time-based eviction (#prunekeeps every entry) and ran every JS test file that mentionsmaxAge, eviction, or retention. Every test that checks eviction failed under the mutation, including all the idle-retention tests intrack.test.tsand theparked-expiryand broadcast eviction tests. The tests that still passed check staleness or survival, so they also pass when nothing is evicted. None of them relied onmaxAgefor eviction. The ones below only named or describedmaxAgeas retention.Fixes
js/watch/src/retention.test.ts: removedmaxAge: Milli(1). Its comment claimed it kept "the track's own replay cache" flat, but the cache keeps idle groups for its fixed window whatevermaxAgesays. The test passes unchanged without it. A comment now says why it sets nomaxAge.js/net/src/track.test.ts:js/net/src/broadcast.test.ts: renamed "tightens publisher retention" to "tightens the publisher's maxAge".doc/lib/js/net.md: added a bullet on the 30 s idle window, with the live-edge exemption. NeithermaxAgenordelay.maxchanges the window. Thedelaybullet now callsmaxAgethe publisher's staleness bound, not "retention".doc/lib/js/publish.md:maxAge". The cache keeps an idle group for 30 s, andmaxAgebounds how far back a reader may reach. Raw PCM audio really is bounded bymaxAge, and that sentence stays.meta.jsonexample dropped its day-longmaxAge, which claimed to make a late viewer replay the last value. A live track's newest group is never stale or evicted, so it already does.js/net/MIGRATE.md,js/net/src/lite/publisher.ts: callmaxAgea staleness bound, not retention. The unlinked heading "Publisher retention is optional" is now "Track.Info.maxAgeis optional".quest/m1/README.md.Choices made without asking
doc/lib/js/publish.md, not just the@moq/netpages, because it is underdoc/and made the same claim. That includes removingmaxAgefrom themeta.jsonexample code.maxAgein@moq/hangand@moq/publishsource docs and tests, such asContainer.trackInfoandBroadcast.maxAge. They describe how far back a fetch may reach, which is accurate. See the follow-ups.Impact
Tests, docs, and comments only. Public API: none. Wire: none.
Validation
#prune): every eviction test in the touched files fails; the renamed tests pass, as staleness tests should.bun test src/track.test.ts src/broadcast.test.ts src/lite/publisher.test.tsinjs/net: 401 pass.bun test src/retention.test.tsinjs/watch: passes.net,hang,publish, andwatchsuites passed on the base before the edits.biome checkon changed files,tsc --noEmitforjs/netandjs/watch,quest check --base origin/main: clean.Review
Codex
gpt-6.1-sol, medium effort (quest review, round 1), reviewed headcdef3a5db304525313fc3f48fe2083d42d595b21againstorigin/main: no findings.Since then, head
5137a69132only adds a conflict-free merge ofmain(review-exempt). The touched test files andquest checkpass on it.Suggested follow-ups
js/publish/src/broadcast.tscreates the catalog track withmaxAge: Milli(Number.MAX_SAFE_INTEGER), commented as keeping the sole snapshot replayable "after the ordinary media retention window". A live track's newest group is never stale or evicted, in JS or Rust, so this probably does nothing for that goal. It does advertise an effectively unboundedmaxAgein TRACK_INFO to relays. Decide whether to drop it or document what it is for.@moq/hang(Container.trackInfo,MAX_AGE_MS) and@moq/publish(Broadcast.maxAge) callmaxAgea "retention" budget, for example "how long relays keep a non-latest group … fetchable". It is the bound past which a cached group is no longer served, not how long anything keeps it. Align the wording with@moq/net's "staleness bound", or settle on one term repo-wide, Rust included.track.test.tstests check that state survives eviction, for example "an evicted successor with unread frames still starts the wall clock" and "a mid-group end survives eviction". They pass with eviction disabled because they never assert that the eviction happened. Adding that assertion would make them catch a broken eviction path.🤖 Generated with Claude Code
(Written by Claude Opus 5.5)