Repository navigation
refactor(mux): TS and fMP4 export lifecycles hold one phase each - #8297
Conversation
Quest-Claim: 129f9e9cf4c85bb9
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fMP4 export track's subscription is one Phase and its fragment run one Buffer; the export's init and catalog are each one enum, replacing the u32::MAX first-late marker. The TS export program's input is one Feed, each track's read one Read (absorbing the program's stale set), the follower's refusal a Serving variant, the passthrough's objects live inside its seen clock, and a group buffer's content kind is one enum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 28 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head b0faaeb.
No actionable findings identified in the lifecycle refactor. Checked fMP4 buffering, departure/rejoin and stop paths; TS retirement, withdrawal/resubscription and PID replacement; follower refusal handling; passthrough PCR/group state; and consumer marker transitions. The previously reported double-close frame-loss issue is fixed: Buffer::close preserves Closed batches, with a focused regression test.
Verification: GitHub-only static inspection of the diff and supporting source. Builds, tests and live media playback were not run.
There was a problem hiding this comment.
ℹ️ Minor suggestion only — one misplaced doc block.
Reviewed changes
- Quest done: deletes
quest/m1/explicit-state/mux-gst.mdand its line in the epic README's## Required, with no other tree references left behind. - fMP4 export lifecycle: the track is one
Phase { Reading, Ended, Departed, Stopped }and its fragment run oneBuffer { Empty, Open, Closed }; the export's catalog feed and init segment areFeedandInit, removingfirst_late_id = u32::MAX. - fMP4 close fix:
Buffer::closepreserves an already-Closedbatch andendpreserves non-Readingphases, withclosing_a_closed_buffer_keeps_its_framescovering the double close. - TS export lifecycle:
Feed { Live, Ended, Retired }replaces the program flags andleft, andRead { Live, Ended, Withdrawn, Stale }absorbsfinished,withdrawn, and the program'sstaleset;resume,resubscribe,rebind,retire,list, and the "gone" predicate all map cleanly onto the new transitions. - TS follower, passthrough, and group buffer:
Serving::Refused,Clock/Groups, andContent { Empty, Marker, Bare, Media }each collapse a flag set into one variant, and the two.expect()phase guards inPassthroughare gone.
The old flag assignments in the base were checked one by one against their new transitions, including the deliberately changed Stale listed track that rebind moves to Live (in practice resubscribe handles it first, so the state is unreachable). Every change is crate-private, so the body's Impact: None holds.
One note outside the code: b0faaebc6 has no completed Check run (the refactor's run on 70c108b8d was cancelled by the new push, and the head's run is skipped), so this head is not CI-verified.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Re-reviewed the delta since the prior Pullfrog review (b0faaebc6..d10450904), a single comment-only commit.
group_startdoc restored: the///block orphaned by the new double-close test now sits directly abovefn group_startinrs/moq-mux/src/container/fmp4/export.rs, resolving the only prior finding. No behavior change.
The rest of the lifecycle refactor is unchanged from the previously reviewed head. Check was still running on d10450904 at review time, so CI has not yet confirmed this head.
deepseek-v4.1-flash-1017 (free via Pullfrog for OSS) | 𝕏

Closes the quest
quest/m1/explicit-state/mux-gst.md(deleted here, with its link in the explicit-state epic).Problem
moq-mux's TS and fMP4 export lifecycles were stored as flags,
Options, and side sets. Their combinations stood for phases, and.expect()calls or call order kept the invalid ones out (the shapes REVIEW.md's State check flags). No confirmed bug was folded in. The quest's two suspected bugs had already been checked and found not to be defects.Approach
Each lifecycle is now one enum whose variants carry their own data:
fmp4/export.rs):Phase { Reading, Ended, Departed(Resume), Stopped }, with aSubscription { source, described }replacingsource/described/finished/resume. ABuffer { Empty, Open(Batch), Closed(Batch) }replacesbuffer/buffer_independent/group_finished.Init { Waiting(queued), Written { first_late, queued } }replacesinit_emitted,queued, and thefirst_late_id = u32::MAXmarker.Feed { Live(S), Ended, Stopped }replacescatalog: Option<S>+stopped.ts/export.rs):Feed { Live, Ended, Retired(left) }replacescatalog_ended,retired, andleft, andresumenow resets one value instead of six fields. Two deadif catalog_ended { return Ok(false) } return Ok(false)branches are gone.Read { Live, Ended, Withdrawn, Stale }replacesfinished+withdrawnand the program'sstale: HashSet<String>. The "gone" predicate now reads!cataloged && matches!(read, Ended | Withdrawn) && <nothing left to go out>.Follower:refusedis nowServing::Refused, which the next instance change overwrites.Passthrough:Clock { Unseen, Seen { timebase, open, queue } }, so objects exist only once a PCR can time them, and the"an object follows a PCR"expect is gone.Groups { Waiting(since), Writing(Group) }replacesgroup+waiting_since, and the"the first object starts a group"expect is gone.GroupBuffer(container/consumer.rs):Content { Empty, Marker, Bare { ended }, Media }replacesempty/media/bare/ended.Choices made without asking:
catalog: Option<S>with itscatalog_formatexpect. An expired follow must drop the old catalog subscription (a_cancelled_replacement_after_the_follow_can_follow_againpins this), but a selected program always holds a catalog. Folding the catalog intoFeedwould bring the sameOptionback.Passthrough::writetreats an object written before any group as starting one (Start::Fallback) instead of panicking. The path is unreachable: only a group-starting object opens before the first group.rebindmoves now leaves Stale. Before, it was unfinished but still listed instale.fmp4/export.rs(only its test), so the fMP4 part did not wait for it.Impact
None: every change is crate-private. No public API or wire change.
Alternatives
Listingstate for the TS track'slisted+parked: dropped.parkedalready empties the moment a track is listed, and the enum would touch about 20 sites for no reachable bad state.psi: Option<Psi>phases of the TS program: left alone. Itsexpect("checked above")calls are local borrow splits, not phase guards.Follow-ups
None.
Models
Size: M
Implementer: Claude Code, claude-opus-5-5, medium effort
Implementer: Claude Code, claude-opus-5-5, medium effort (iterate, M)
(Written by Claude Opus 5.5 with medium)
Review
Rewritten by
quest reviewafter each round.01a1bc5a-330c-7591-80f7-552e35fe4363, round 3The only incremental change moves a documentation comment onto its intended helper, introducing no behavioral changes or new issues.