Repository navigation
fix(ffi): follow publisher runs by lifecycle, keeping wire errors - #7479
Conversation
Quest-Claim: 7719874c06f60ee8
Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
Keep the quest open for a publisher-side mapping or lifecycle decision. Stream reset zero cannot safely be decoded as an end. Co-Authored-By: GPT-6.1 Sol <noreply@openai.com>
A track withdrawn unfinished keeps the error its wire carries: Unroutable over moq-lite, INTERNAL_ERROR over moq-transport, which has no code for it. Readers follow runs by announcement instead. The live FFI run-end test now follows the path on lite-07 and IETF drafts 18, 20, and 22, sees the announcement end, and picks up a replacement run from the next available(). Drop the doc claim that readers take Unroutable as the publisher leaving, and finish the ffi-ietf-run-end quest. 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 6 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. CodeRabbit Verify
|
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: 14a2271d5d23e1efeb8b4cd381b17d0ce8fa569e.
No actionable bugs found in the changed areas. Following publisher instances through the existing announcement lifecycle is simpler and more accurate than reclassifying an unfinished track as clean EOF. The shared FFI test covers finished media, unfinished-track errors, catalog/broadcast closure, and replacement-run delivery across lite-07 and IETF 18/20/22; the documentation now matches the existing Rust/JS error mappings without adding API or wire behavior.
Verification limits: static GitHub review of the diff and relevant lifecycle/error-handling code only. I did not run tests or independently verify the reported local checks.
(Written by OpenAI)
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — Documentation, test, and generated-binding updates for how the FFI follows publisher runs; no production logic and no wire change.
- Binding guides corrected — the c, cpp, dart, go, kt, py, and swift guides plus the Rust, Go, Python, and Swift wrapper docs no longer tell readers to take
Unroutableas the publisher leaving. They state that a track withdrawn unfinished endsUnroutable(Internalover moq-transport, whose registry has no such code) and point at/concept/identity. identity.mdnames FFI following — adds the bindings'follow(path)/available()alongside the Rust and JS forms, and says a track's error kind is not the restart signal.- Cross-protocol lifecycle test —
server_client_run_endnow runs overmoq-lite-07-wipand moq-transport drafts 18, 20, and 22, proving a finished track ends cleanly, the catalog ends andclosed()resolves, the unfinished track keeps its wire error (Unroutableon lite /Internalon IETF), the announcementEndarrives, and a replacement run at the same path is handed out by the nextavailable(). - Regenerated Dart checksum — the
close()docstring moves the UniFFI method checksum, and only that line changes in the generated file (generated Dart strips doc comments); consistent. - Quest removed —
quest/m1/ffi-ietf-run-end.mdand itsREADME.mdentry are deleted, following the maintainer-approved goal change.
I also checked for leftovers: no remaining occurrences of the removed "readers take as the publisher leaving" phrasing, no dangling references to the deleted quest, and the version strings used by the test are valid. The remaining publisher leaving comments (in moq-c/src/publish.rs, audio.rs:406, video.rs:546) describe the cause of Unroutable, not reader guidance, so they are accurate and in scope to leave.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
…-end Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — the delta since the prior Pullfrog review is a single merge of main (e1e37dd4e) into the branch, and its conflict resolution. The branch was far behind main, so the merge brought in a large body of upstream code; only the conflicts touch this PR's surface.
identity.mdmerged — retains main's newer "stream"/"broadcast" wording alongside this PR's moq-ffifollow(path)/available()sentence and the "not a restart signal" note.- Binding guides merged — each keeps main's newer
Closingtext (moq-lite-05 and newer wait for the peer to receive finished tails) with this PR'sEnding cleanlytext, so both intents survive. rs/moq-ffi/src/test.rsadapted —frame.timestamp_usbecamemicros(frame.timestamp)for main's timestamp API; themicros/ushelpers and the non-optionalMoqMediaFrame::timestampmake it consistent.- Dart checksum re-derived —
moqbroadcastproducer_closemoves26090→21298, tracking only theclose()docstring change (main did not churn the UniFFI checksum algorithm, so no mass rewrite).
Verified no conflict markers remain, no dangling reference to the deleted quest, and c/index.md still carries main's Discovery bullet. Test/just check claims were reviewed statically only.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Problem
When a publisher withdraws a track it never finished, an FFI consumer sees
Protocol/Unroutableover moq-lite andMoqError.Internalover the retained moq-transport drafts. The bindings' guides told readers to treatUnroutableas the publisher leaving. That cannot work over moq-transport:ietf::publisher::Served::statussends every failed track as PUBLISH_DONE/INTERNAL_ERROR, and group resets also carry INTERNAL_ERROR, because neither registry on draft 18, 20, or 22 has an Unroutable code.Decision
Maintainer, 2026-11-01. The recommended option 1 was chosen:
Also decided: do not decode 0 as EOF, and do not send TRACK_ENDED for unfinished content. The maintainer approved the change this makes to the quest's error-kind-based Goal and to its milestone index entry.
Approach
js/net/src/ietf/publisher.ts) maps a failed track the same way Rust does, and@moq/watchalready followsrequest.activeandfollow, never a track's error. So JS needed no change.follow(path), the way a player does, and checks each step:closed()resolvesUnroutableon lite,Internalon IETFEndarrivesavailable()and delivers a frameUnroutableas the publisher leaving. They say the track ends withUnroutable(Internalover moq-transport, which has no such code). The guides also point readers to follow runs by announcement, citing identity and recovery. That concept page now names the moq-ffi bindings'follow(path)/available()and says that a track's error kind is not a signal to restart.quest/m1/ffi-ietf-run-end.mdand itsquest/m1/README.mdentry withquest rm. The brief said to rewrite the Goal and the milestone description. Deleting the quest follows the guide's rule that the PR finishing a quest deletes it, rather than leaving behind a quest whose goal is already met. The moq.pro samples moving toavailable()belong to moq.pro's reader quest.Impact
Validation
On head
a3732f575f, after mergingorigin/maine1e37dd4ed:just rs test -p moq-ffi: all 287 passed. This includesserver_client_roundtrip(lite-07) andserver_client_run_end_draft{18,20,22}. On today'smain, a stream reset still sends INTERNAL_ERROR forUnroutable(rs/moq-net/src/ietf/error.rs,unregistered_conditions_are_internal). So the IETF assertion still holds.just check origin/main: passed (py, rs, c, cpp, js, markdown, gh, kt, swift, go, quest, shell, dart, and the rest).quest check --base origin/main: 550 documents ok.Merge with
main(2026-11-02)The conflicts were all prose in the binding guides (C, Dart, Go, Kotlin, Python, Swift) and in
doc/concept/identity.md. Both sides' intent is kept:main: the newerClosingtext (fix(net): lite-05/06 close waits for the subscriber's FIN; drop the legacy close quest #7296), the C guide'sDiscoverybullet (feat(ffi)!: require announcement captures #7484), and identity's "stream"/"broadcast" wording (feat(net)!: routes carry an instance and a per-instance epoch #7489).Ending cleanlytext and the FFIfollow(path)/available()sentence.The FFI
follownow takes an optionalinstance, which defaults to none, sofollow(path)is still correct.Review
Codex CLI,
gpt-6.1-sol, medium effort (quest review --base origin/main --new), session01a19ff5-44da-7f92-9bd2-8bf7164d0a7b, round 1, reviewed heada3732f575f25f72c597f7c7011e4b264b13542b6againstorigin/main5583782acd: no findings.Automated reviews posted on the previous head
14a2271d5d, from OpenAI and Pullfrog, reported no findings. CodeRabbit was rate-limited.🤖 Generated with Claude Code
(Written by Claude Opus 5.5)