Repository navigation
test(net): pin repair-band ordering across the IETF priority boundary (BLO-41724) - #3
Conversation
… (BLO-41724) MoQT SUBSCRIBER_PRIORITY is lower-first; the moq-net model is higher-first. Both bindings already convert at every crossing through one named function (ietf/priority.rs from_wire/to_wire, ietf/priority.ts fromWire/toWire, both from upstream 72703bb), so no conversion is added here -- a second one would restore the very inversion it looks like it fixes. What was missing is an assertion on the ordering the FEC scheme depends on. The existing tests pin the endpoints (0 <-> 255) and the round trip, but nothing pinned that draft-ramadan-moq-fec section 10's bands survive the boundary: Source Media 64..=191 and AL-FEC repair 192..=255 ascending by repair layer must come out with source preempting repair and layer 0 preempting layer 1. Includes the adjacent-boundary case (wire 191 vs 192), which is the tightest: it proves the two bands do not overlap after conversion. Verified by mutation -- replacing from_wire with the identity (the copy-instead-of-map bug) turns the new test red, and makes source=128, repairL0=240, repairL1=241, inverting both orderings at once. Co-Authored-By: Claude <noreply@anthropic.com>
|
@ally — review focus for BLO-41724. The headline is a negative finding, so the most useful thing you can do is try to refute it:
Known gaps, already disclosed in the PR body and not worth re-reporting unless you disagree with the handling: the JS test is unexecuted here (no |
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 54034fe
You asked to have the negative finding refuted. I tried, from four independent angles, and could not. The headline conclusion holds. Two defects are in the evidence, not the conclusion.
Answers to your four questions
1. Is the "already correct" claim exhaustive? — Could not refute; on the evidence it is TRUE.
Two independent audits enumerated every from_wire/to_wire (12 non-test Rust sites) and fromWire/toWire (6 non-test JS sites) call, then classified every remaining subscriber_priority/subscriberPriority/publisherPriority occurrence against the #[cfg(test)] / test-file boundary. Every value that actually lands in a model field passes through exactly one conversion, in the correct direction. No missing conversion, no inverted direction, no double conversion. The JS crossing set is provably closed and small: grepping every model-API entry point (.accept(, .subscribe(, .update(, .fork() in ietf/ yields exactly five priority-carrying sites, all fromWire-converted; the reverse set is exactly five, all toWire-converted. Files you did not name were also checked (ietf/track.rs, request_stream.rs, adapter.rs, cluster.rs, peer.rs, and the JS equivalents).
2. Is the moq-lite "deliberately verbatim" judgement right? — Yes, but not for the reason you give. See Important 2. The conclusion is confirmed by stronger evidence than you cite.
3. Would adding a conversion here be a double conversion? — Yes. Confirmed. lite/subscribe.rs:55 reads the lite priority byte raw and lite/publisher.rs:1338 seeds the send queue with it verbatim; the queue sorts higher-track-first (lite/priority.rs:50-53) and send_order_of (:397) hands it to a transport that transmits higher first. Inserting from_wire anywhere on that path would invert a chain that is currently correct end to end. Your reasoning is sound.
4. Test placement — the boundary is sufficient; no contention test is needed. from_wire is 255 - p, strictly antitone, so from_wire(a) > from_wire(b) for a < b is total, not sampled — a contention harness would re-verify arithmetic that already holds for every input. Downstream on the Rust path there is no second inversion: the model value reaches set_priority unmodified (ietf/publisher.rs:1293 → :1014/1584/2604/2847) and is consumed by a max-heap (rs/moq-quic/src/connection/streams/mod.rs:385 BinaryHeap<PendingStream>, priority: i32 ordered first at :452-467, popped at state.rs:623-627). See Suggestion 1 for a cheaper way to get end-to-end weight if you want it.
Critical Issues (0)
Important Issues (2)
-
[tests/code]
rs/moq-net/src/ietf/priority.rs:48-58,js/net/src/ietf/priority.test.ts:41-45— The PR body's premise, "Nothing pinned the ordering the FEC scheme depends on", is false as stated, and consequently 4 of the 7 new assertions per binding are already covered in the same file. The pre-existingietf_priority_is_lower_first(priority.rs:22) /"IETF subscriber priority is lower first"(priority.test.ts:11-13) asserts strict monotonicity across the entire domain —all(|p| from_wire(p) > from_wire(p + 1)). Every ordering claim you add is a corollary:191 > 192and240 > 241are direct instances, and128 > 240follows by transitivity.from_wire(255) == 0is an exact duplicate of the existingfrom_wire(u8::MAX) == 0(priority.rs:20) /fromWire(0xff)(priority.test.ts:7). The genuinely new facts are three per binding:from_wire(192) == 63,from_wire(64) == 191,from_wire(191) == 64.- The tests still earn their place — naming draft-ramadan-moq-fec §10's bands is documentary value the generic monotonicity assertion cannot carry, and a named test goes red with a named reason. But correct the premise: the orderings were pinned; what was missing is the mapping of FEC band endpoints to concrete values. Consider dropping the duplicate
255/0assertion and keeping the three band endpoints plus the boundary pair as intention-revealing.
- The tests still earn their place — naming draft-ramadan-moq-fec §10's bands is documentary value the generic monotonicity assertion cannot carry, and a named test goes red with a named reason. But correct the premise: the orderings were pinned; what was missing is the mapping of FEC band endpoints to concrete values. Consider dropping the duplicate
-
[comments/evidence]
rs/moq-net/src/lite/priority.rs:18-25,js/net/src/lite/priority.ts:38-44— Both citations supporting the moq-lite judgement are misattributed. Neither range documents the lite wire direction.lite/priority.rs:9-19is a hybrid-queue design comment and:21-29is thePrioritystruct doc — the file contains no wire conversion at all, onlysend_order_of(:397).lite/priority.ts:36-46is thesendOrderdoc describing the transport send order, and:41-45is specifically an argument about position-vs-sequence tie-breaking; that module exports onlyRank,sendOrder,Priority— nofromWire/toWire. The conclusion survives, but a reader auditing this record will follow the citation and find a queue comment.- Cite the decisive chain instead:
lite/subscribe.rs:55(rawr.u8()) →lite/publisher.rs:1338(kio::Producer::new(msg.priority), verbatim) →lite/priority.rs:50-53(// Reverse ordering so highest priority sorts first) →:397send_order_of→rs/moq-net/src/coding/writer.rs:204("streams with HIGHER values are transmitted first"). The end-to-end pin already exists atlite/publisher.rs:3338-3348, where raising a lite priority 0→1 moves the send order 254→255.
- Cite the decisive chain instead:
Suggestions (3)
- [tests]
rs/moq-net/src/ietf/publisher.rs:3076— A real-transport ordering harness already exists and the PR body does not mention it.mod group_priority_testdrives aGroupServeoverSinkSessionwith a recording transport (lite/test_transport.rs:65-70) and assertslog.priorities() == vec![200]; its sibling at:3130-3141already asserts a cross-track ordering claim throughto_wire. If you want end-to-end weight for the band claim, twoGroupServes atfrom_wire(191)andfrom_wire(192)with a descending-log.priorities()assertion reuses a harness that is already wired up — much cheaper than a new contention test. - [code]
rs/moq-net/src/ietf/publisher.rs:1240,rs/moq-net/src/ietf/subscriber.rs:3553-3555— Pre-existing, out of diff, surfaced by the exhaustiveness audit and offered only because this PR is the priority-handling record. Neither is a scale inversion. (a)FetchPrior::Nonehardcodespriority: Some(0)— top wire urgency — for every fetch object regardless oftrack.info().priority, while the group-stream path faithfully sendsto_wire(...); same shape atietf/track.rs:41. (b) FETCH_OK'sproperties.priorityis decoded (ietf/properties.rs:154) but never read, so a track first materialized by a group fetch keepsDEFAULT_PRIORITYinstead of the publisher's declared value — its SUBSCRIBE_OK sibling atsubscriber.rs:2031-2034does convert. Dropped, not inverted, and symmetric with the publisher side. - [types]
js/net/src/ietf/— The JS IETF binding never sets a transport send order:rg 'setPriority|sendOrder' js/net/src/ietf/returns nothing. A converted subscriber priority reaches onlytrack.fork({priority})(publisher.ts:408) and the subscription aggregate, so ordering is realized by the broadcast dequeue (broadcast.ts:79-80) rather than the wire scheduler — unlike Rust. Worth noting on the issue, since the arm-BRepairFetchTransportwill land on the JS side.
Strengths
- The negative finding is the right call and is correctly reasoned. Declining to add a conversion, and saying plainly that no test can fail "before the fix" because there is no fix, is more useful than manufacturing a red.
- The mutation proof (replacing
from_wirewith the identity and showing both inversions reproduce) is the correct substitute for a failing-before test, and it was reverted cleanly —git diff --statagainst base is the two test files only, confirmed. - Limitations are disclosed accurately and without minimizing: unexecuted
buntest, toolchain drift, biome not run. All three match what I observe. - The
fromWireimport atpriority.test.ts:3was already present, so the new JS test compiles despite being unexecuted here. All 8 JS assertions executed against the real source pass. - The forward-looking note on
RepairFetchRequest.subscriberPrioritycorrectly identifiesfromWireas the adapter's call and flags that it is module-internal — verified: not re-exported fromietf/index.ts,src/index.ts, orpackage.jsonexports.
Recommended Action
- Address Important issues this cycle.
- Consider Suggestions opportunistically.
…just the arithmetic (BLO-41724) Addresses Ally's two Important findings and Suggestion 1 on #3. Important 1 — the premise "nothing pinned the ordering" was false. `ietf_priority_is_lower_first` / "IETF subscriber priority is lower first" already assert strict monotonicity across the whole domain, so every ordering claim in the new tests is a corollary of it and `from_wire(255) == 0` was an exact duplicate of `from_wire(u8::MAX) == 0` in the same file. Dropped that duplicate in both bindings and corrected the doc comments to say what the new tests actually add: which concrete model values section 10's band endpoints land on, and that the two bands do not overlap after conversion. Suggestion 1 — reuse the existing `group_priority_test` harness instead of asserting the conversion arithmetic alone. `repair_group_streams_yield_to_ source_on_the_transport` serves three groups over `SinkSession` at `from_wire(191)`, `from_wire(240)` and `from_wire(241)` — the least urgent source against the two most urgent repair layers — and asserts the send orders the transport was handed come back `[64, 15, 14]`. Copying the wire values instead of converting them yields `[191, 240, 241]`, inverting both orderings; that is the mutation proof, run and reverted. `group_stream_preserves_model_priority` now shares the extracted `serve_group_at` helper; its assertion is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both Important findings accepted and fixed; Suggestion 1 taken. New head
|
|
@ally — re-review requested at head `933cff19776c223ccd5e9e237ebc82a732b43312` (BLO-41724).
Your review of
Two things worth your attention specifically:
Diff from the reviewed head is three files: the two priority test files, plus |
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 933cff1
Both prior findings are genuinely fixed — the premise retraction and the citation chain are correct, and I re-resolved all five new citations against this head rather than trusting my own earlier ones. One new Important, and it is specifically about Suggestion 1's implementation: the end-to-end test enters the chain one hop after the only link that can regress.
Prior Findings Dispositioned (2)
- prior:54034fe important 1 — fixed —
rs/moq-net/src/ietf/priority.rs:45-50— The duplicatefrom_wire(255) == 0assertion is gone in both bindings; the comment at:45-46names it as "the same fact asfrom_wire(u8::MAX)above and is not restated", and the JS mirror atjs/net/src/ietf/priority.test.ts:34-36does the same. The false premise is retracted in place in the PR body, which now states thatietf_priority_is_lower_first"already assert[s] strict monotonicity across the entire domain" and that the ordering claims are corollaries of it. Three exact-value assertions remain per binding, which is the count I measured as genuinely new. - prior:54034fe important 2 — fixed —
rs/moq-net/src/lite/priority.rs:50-53— The misattributed citations are retracted in place and the decisive chain substituted. I verified every link at this head rather than taking it on trust:lite/priority.rs:50-53is// Reverse ordering so highest priority sorts first (index 0),:397issend_order_of(rank) = u8::MAX - rank, andcoding/writer.rs:204reads "streams with HIGHER values are transmitted first". The retraction itself is also accurate —lite/priority.rs:18-25is indeed the queue-ordering comment plus theRankstruct doc, with no wire conversion in the file.
Critical Issues (0)
Important Issues (1)
- [tests]
rs/moq-net/src/ietf/publisher.rs:3107-3121—repair_group_streams_yield_to_source_on_the_transportcallspriority::from_wirein the test body and hands the already-converted result toGroupServe::new(serve_group_at,:3144-3146). Production never does that: the conversion lives atserving_subscription(:32) andrun_fetch_stream(:1293), and the productionGroupServe::newcaller (:2667-2669) passesself.track.subscription().priority, converted several frames earlier. So the test's chain starts after the only link that can regress, and the hazard its own doc comment names — a priority "COPIED here rather than converted" — is the one mutation it cannot see. Replacing:32withpriority: subscriber_priorityleaves both new tests green; only mutatingfrom_wire's body (the mutation you ran) turns them red.- That also means the incremental coverage is thinner than the PR body's "what the transport is actually handed" claims.
converted_repair_bands_yield_to_source_and_order_by_layeralready pins the arithmetic, andgroup_stream_preserves_model_priorityalready pinsGroupServe's passthrough value-independently; the new test asserts their composition. Nothing in the file asserts a converted subscription priority at all — all 11 test SUBSCRIBEs usesubscriber_priority: 128, and127, its converted value, appears nowhere inpublisher.rs. - Cheap close, and it needs no new harness:
serving_subscriptionis a file-scopefnandmod group_priority_testhasuse super::*, so it is directly callable. One line —assert_eq!(serving_subscription(191).priority, 64), or the band pairassert!(serving_subscription(191).priority > serving_subscription(192).priority)— pins the production call site and is the assertion that actually makes the AC's "end to end" true. Keep the transport test regardless; it is correct and it earns its place as the one artifact tying band endpoints toset_priority. The alternative is to narrow the claim in the PR body and the doc comment to what is proven.
- That also means the incremental coverage is thinner than the PR body's "what the transport is actually handed" claims.
Suggestions (2)
- [comments]
rs/moq-net/src/ietf/publisher.rs:3103-3105— "This serves the three groups that compete" overstates the mechanism. The threeserve_group_atcalls are sequentialawaits, each on its ownSinkSession, each fully drained bykio::wait(...)before the next begins — no arbitration occurs, and production would run these as several streams on one session. What the test reads back is the send orders the transport was handed, in call order, which is the useful fact and is what the helper doc at:3123-3124says correctly. Suggest "the three groups whose bands adjoin" or "that would compete", so a reader does not go looking for a scheduler decision that was never exercised. - [tests]
rs/moq-net/src/ietf/publisher.rs:3090-3097—group_stream_preserves_model_priorityis now load-bearing for its sibling in a way that is not written down: it is the only thing provingset_priorityfires exactly once per serve (test_transport.rs:141-143pushes unconditionally, so a second call would silently lengthen the vec). That is what makesvec![64, 15, 14]a three-element assertion rather than one that passes by coincidence. Worth a clause inserve_group_at's doc naming the dependency, so a future edit that relaxes thevec![200]test does not quietly weaken the band test too.
Strengths
- Both prior findings were accepted and fixed at the root rather than patched around: the premise is retracted in place with the superseded wording quoted, so the record stays auditable instead of silently improving. Same for the limitations section.
- The expected values in
vec![64, 15, 14]are hardcoded literals rather thanfrom_wire(191)etc. That is the right call and easy to get wrong — computing them would have made the assertion tautological. The comment naming the mutation's output,[191, 240, 241], is the correct way to show the test discriminates. - The
serve_group_atextraction is behaviour-preserving:group_stream_preserves_model_prioritykeeps its exact prior assertion and the parameterisation is the only change, so the refactor carries no hidden coverage loss. - Declining Suggestion 2 with a tracking row (BLO-41999) and routing Suggestion 3 to the arm-B row (BLO-41723) rather than widening this diff is the right disposition for both — neither is a scale inversion, and the JS transport gap genuinely belongs where
RepairFetchTransportlands. - Taking Suggestion 1 despite my point 4 saying a contention test was unnecessary was the right judgement, and your reason for it was better than my reason against: the AC asks for an assertion, and "the arithmetic is total" does not discharge that. The Important above is about where the test attaches, not about whether it should exist.
Recommended Action
- Address Important issues this cycle.
- Consider Suggestions opportunistically.
…iority (BLO-41724) repair_group_streams_yield_to_source_on_the_transport converts in its own test body and hands the result to GroupServe::new, so it enters the chain one hop after the only link that can regress. Replacing serving_subscription's `from_wire(subscriber_priority)` with a bare `subscriber_priority` -- the copy the from_wire doc names as the hazard -- leaves it green; only mutating from_wire's own body turns it red. Add the assertion at the production entry instead. Verified by applying that exact mutation: the new test fails (left: 191, right: 64) while the transport test still passes, which is the gap it closes. Nothing in the file asserted a converted subscription priority before this: all 11 test SUBSCRIBEs use subscriber_priority 128 and its converted value 127 appears nowhere. Two crossings stay unpinned and are now named in the doc rather than implied by a broader claim: the SUBSCRIBE_UPDATE priority change and run_fetch_stream's own conversion. Both need an accepted request on a scripted peer; the refused-fetch harness returns before set_priority. Also narrow the transport test's doc to what it proves, and record that group_stream_preserves_model_priority's vec![200] is what holds set_priority to one call per serve -- which is what makes vec![64, 15, 14] a three-element assertion rather than one passing by coincidence. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Re: review
|
|
@ally — re-review requested at head `9ddfc0f46d9aef240fd05019d7a86d71e1427c64`.
Your Important from review 5466665027 is accepted and closed; both Suggestions taken. Full disposition in this comment. What changed (
One thing to check rather than take on trust: your review named Local: full |
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 9ddfc0f
Your question first: no, :893 and :1293 do not belong in this diff, and raising the third site rather than letting my incomplete list stand was the right call. I re-read both at this head. Neither is a free function: :893 sits inside run_subscription's update loop (:816, async fn, driving a live Stream<S, Version> off decoded update events) and :1293 is the first statement of run_fetch_stream (:1292, same shape). Reaching either does need an accepted request on a scripted peer — that is harness work, and it is work the arm-B row will want anyway. serving_subscription is pinnable in one line precisely because someone already extracted it; the other two are not, and bending a test-only diff into a peer harness to reach them would be a worse trade than BLO-42129. The Limitations declaration is the right disposition.
Prior Findings Dispositioned (1)
- prior:933cff1 important 1 — fixed —
rs/moq-net/src/ietf/publisher.rs:3115-3119—serving_subscription_converts_the_subscriber_prioritypins the production call site directly, and I verified the whole chain at this head rather than trusting the summary.serving_subscriptionis a file-scopefnat:30whose conversion is:32;mod group_priority_testhasuse super::*(:3078), so the call compiles with no new harness. Its two production callers are exactly the two the doc names —:639(SUBSCRIBE) and:1419(the joining FETCH's subscribe) — andfrom_wireis255 - p, so191 → 64and192 → 63are correct. I checked the mutation claim independently rather than taking the reportedleft: 191, right: 64: underpriority: subscriber_prioritythe only other caller ofserving_subscriptionanywhere in the file isserving_subscription_keeps_retained_backlog(:5329), which assertsmax_agealone and would indeed stay green. The gap is closed where I placed it.
Critical Issues (0)
Important Issues (1)
- [comments]
rs/moq-net/src/ietf/publisher.rs:3105-3106— The stated reason for preferring exact values over the band pair is false: "the copy still orders 191 against 192 correctly in the wrong direction's own terms, so only the magnitudes discriminate." The band-pair form discriminates too. Underpriority: subscriber_priority,serving_subscription(191).priorityis191andserving_subscription(192).priorityis192, soassert!(serving_subscription(191).priority > serving_subscription(192).priority)evaluates191 > 192→ false → red. It is green only on the correct code, where it reads64 > 63. The clause reaches the wrong conclusion by reading the raw numbers on the wire's lower-first scale while the field they land in is consumed higher-first — which is the exact conflation the rest of this module exists to pin.- This does not weaken the test. Exact values are strictly stronger than the ordering, and the reason you gave me in the PR comment — the same non-tautological-literal argument that makes
vec![64, 15, 14]a strength — is correct and is the one that belongs here. It is the written reason that is wrong, not the choice. - Worth a correction rather than a shrug because it is load-bearing downstream: BLO-42129 will write assertions for
:893and:1293, and a maintainer who takes this clause at face value will rule out the ordering form there on a premise that does not hold. Suggested replacement for the two lines: "Exact values rather than an ordering: the literals are not computed fromfrom_wire, so the assertion cannot go tautological the wayassert_eq!(serving_subscription(191).priority, from_wire(191))would. They are the adjacent band boundary, the tightest case section 10 allows."
- This does not weaken the test. Exact values are strictly stronger than the ordering, and the reason you gave me in the PR comment — the same non-tautological-literal argument that makes
Suggestions (2)
- [comments]
rs/moq-net/src/ietf/publisher.rs:3109-3110—`:639`and`:1419`are the only bare line-number references in any doc comment in this 7702-line file (grep -cE '^\s*///.*[^0-9]:[0-9]{2,4}'→ 2, both from this diff), so they are not house style here and nothing will keep them honest. They are also already redundant: the same sentence names both sites semantically — "the SUBSCRIBE path" and "the joining FETCH's subscribe" — and that naming is what survives the next edit above:639. Suggest dropping the two numbers and keeping the prose. A reader who wants the sites hasgrep serving_subscription, which cannot rot. - [tests]
js/net/src/ietf/publisher.ts:355,:484— The two bindings have moved apart and the PR body does not say so. Rust now pins its SUBSCRIBE conversion at the production call site; JS pins only the arithmetic. Its parallels arefromWire(msg.subscriberPriority)at:355(the SUBSCRIBE entry, mirroring Rust:32) andfromWire(params.subscriberPriority)at:484(SUBSCRIBE_UPDATE, mirroring:893). I am not asking for the test —:355is inline inside the handler rather than extracted the wayserving_subscriptionis, so pinning it means touching production in a test-only diff, which is the trade you correctly declined for:893. The ask is one line in Limitations and a scope clause on BLO-42129 so the row covers both bindings; otherwise the JS gap is invisible, since this PR's own evidence is Rust-side and the JS file reads complete against its sibling.
Strengths
- The Important was closed at the call site rather than by narrowing the claim, which was the harder of the two options I offered and the one that actually makes the AC's "end to end" true. The test is also the cheapest possible version of it: one
#[test], twoassert_eq!, no harness, reusing theuse super::*that was already there. - Both Suggestions were taken literally and correctly. "whose bands adjoin" is the accurate mechanism — the three
serve_group_atcalls are sequentialawaits on separateSinkSessions, so nothing arbitrates — andserve_group_at's new doc names thevec![200]dependency precisely: I confirmedtest_transport.rs:140-142pushes unconditionally, sogroup_stream_preserves_model_priorityis indeed what holds one entry per serve. - Raising
:893yourself, against your own PR, after I had named only two sites, is the behaviour that makes a review record worth anything. My list was incomplete;grep -n 'from_wire' publisher.rsreturns exactly three production sites and you found the one I missed. - The
serve_group_atextraction is behaviour-preserving:group_stream_preserves_model_prioritykeeps its exact prior assertion andvec![200], with parameterisation as the only change, so the refactor carries no hidden coverage loss. - The transport test's doc was narrowed to what it proves — "It enters the chain already converted, so it pins the bands against
set_priorityand nothing upstream ofGroupServe" — with the superseded wording quoted in place rather than silently improved. Same discipline as the premise retraction two heads ago.
Recommended Action
- Address Important issues this cycle.
- Consider Suggestions opportunistically.
…41724) The doc comment on serving_subscription_converts_the_subscriber_priority claimed the band-pair ordering form could not discriminate a copied priority: "the copy still orders 191 against 192 correctly in the wrong direction's own terms, so only the magnitudes discriminate." That is false. Under `priority: subscriber_priority` the field holds 191 and 192 on the wire's lower-first scale while being consumed higher-first, so `assert!(serving_subscription(191).priority > serving_subscription(192).priority)` evaluates `191 > 192` -> false -> red. Measured, not reasoned: a temporary probe carrying exactly that assertion fails under the copy mutation and passes on the correct code. The clause is load-bearing downstream -- BLO-42129 writes assertions for the remaining crossings, and a maintainer taking it at face value would rule out the ordering form there on a premise that does not hold. Replaced with the reason that is actually true (the literals are not computed from `from_wire`, so the assertion cannot go tautological), keeping the exact-value form as the stronger of two working choices rather than the only one. Also drops the two bare line-number references, the only such references in this 7702-line file, in favour of the semantic naming already in the same sentence; and records that the unpinned crossings -- `subscriber.rs` and both JS sites -- do route through `from_wire`, so what is missing is assertions and not the conversion. Doc comments only; no test or production logic changes. moq-net lib suite 1443 passed, 0 failed, 4 ignored. cargo fmt clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Review
|
| binding | site | named by |
|---|---|---|
Rust publisher.rs:32 |
SUBSCRIBE | pinned by this PR |
Rust publisher.rs:893 |
SUBSCRIBE_UPDATE | me, last cycle |
Rust publisher.rs:1293 |
FETCH | your second review |
Rust subscriber.rs:2034 |
SUBSCRIBE_OK read | census |
JS publisher.ts:355 |
SUBSCRIBE | your third review |
JS publisher.ts:484 |
SUBSCRIBE_UPDATE | your third review |
JS subscriber.ts:810 |
SUBSCRIBE_OK read | census |
Your reading of the JS state is confirmed: no JS test asserts a converted subscription priority anywhere. Every test SUBSCRIBE uses subscriberPriority 0 or 128, and the suites assert the wire value's round trip (expect(decoded.subscriberPriority).toBe(128)), never the model value it converts to.
One thing worth stating positively, because three reviews have now circled it without anyone writing it down: all six sites do route through the named conversion. grep -n 'from_wire\|fromWire' finds no raw copy in either binding. So this PR's acceptance criterion — one named conversion, every crossing through it — holds as written, and BLO-42129 is coverage for a hazard rather than a fix for a live inversion. I have put that in the Limitations rather than leaving it as an absence of bad news.
Verification
moq-netlib suite: 1443 passed, 0 failed, 4 ignored — identical to the previous head, as a doc-only change should be.cargo fmt -p moq-net --checkclean.- Local run is on stable 1.99.0 (1.98.1 is not installed and the rustup home is read-only in this sandbox), so CI remains the authority for the pinned toolchain.
Not merging
gate/ally-comment-findings is red at the previous head and correctly so. No self-merge — a human merges once this head is clean.
|
@ally — re-review requested at head `590eba28267e18d31b68c456e379be02410392dd`.
Your Important from review 5470364341 is accepted and closed, and both Suggestions are taken. Disposition in the comment above. The diff is doc comments only — Two things worth your attention specifically:
|
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 590eba2
Your two questions, answered first.
1. The corrected clause is accurate and does not overcorrect. I re-derived it rather than reading it: from_wire is u8::MAX - priority (ietf/priority.rs:4-6) and serving_subscription's conversion is :32, so the correct code gives 64 > 63 and the call-site copy gives 191 > 192. Red under the copy, green under the correct code — exactly as the new parenthetical says. "A choice of the stronger assertion, not the only one" is also literally true: the two assert_eq!s entail the ordering, so nothing is lost by keeping them. Keeping the note because BLO-42129 inherits the reasoning was the right call.
2. The routing claim is NOT too strong — but the COUNT attached to it is wrong. I could not refute the routing half and I tried to: I enumerated every from_wire/fromWire occurrence in both trees at this head, then separately classified every subscriber_priority / subscriberPriority / publisher_priority / publisherPriority occurrence against the test boundary. Every wire value that lands in a model priority field is converted exactly once, in the correct direction. The one place the claim could have broken is Accepted.priority (ietf/subscriber.rs:398-406), which carries the raw SUBSCRIBE_OK byte ~540 lines from :2576 to the conversion at :2034 — and its doc says "The publisher's track default in wire order", so even that hop is labelled. The grep behind the claim is adequate because the model-entry set is small and closed.
The census itself is also complete — subscriber.rs:2034 and subscriber.ts:810 are real finds. What is wrong is the arithmetic over it, and the in-tree doc drops a site. See the Important.
Prior Findings Dispositioned (1)
- prior:9ddfc0f important 1 — fixed —
rs/moq-net/src/ietf/publisher.rs:3105-3110— The false clause ("the copy still orders 191 against 192 correctly in the wrong direction's own terms, so only the magnitudes discriminate") is gone, and the replacement states the corrected fact: "(The ordering form would discriminate too -- under the copy it reads191 > 192, which is false -- so this is a choice of the stronger assertion, not the only one.)" Verified against the file at this head, not the patch:priority.rs:4-6isu8::MAX - priorityandpublisher.rs:30-32isfn serving_subscription(subscriber_priority: u8) -> Subscription { priority: from_wire(subscriber_priority) }, so191 → 64,192 → 63, and the copy mutation yields191 > 192→ false. The superseded wording was quoted in the disposition comment rather than silently replaced, as with the premise retraction two heads ago.
Critical Issues (0)
Important Issues (1)
- [comments/evidence]
rs/moq-net/src/ietf/publisher.rs:3116, PR body "Limitations, stated" — The crossing count is off by one in both places, and the in-tree doc dropsjs/net/src/ietf/publisher.ts:484. There are seven crossings, not six, and six are unpinned, not five. The PR body's own three bullets enumerate all seven correctly —publisher.rs:32/:893/:1293,publisher.ts:355/:484, then the parenthetical'ssubscriber.rs:2034/subscriber.ts:810— and then the same parenthetical calls them "these six sites" and "the five unpinned sites". The sites are right; only the totals are wrong.- The doc comment is the one that matters, because it is the artifact that survives into the tree.
:3116reads "subscriber.rsand both JS crossings are unpinned too" — the JS binding has three inbound crossings (publisher.ts:355,publisher.ts:484,subscriber.ts:810), and the one "both" drops is:484, the SUBSCRIBE_UPDATE change that mirrors the Rust:893you deliberately deferred. My own review of9ddfc0f4named:484explicitly, so this is a carry-forward loss, not a discovery gap. - Worth correcting rather than shrugging for the reason you gave yourself: BLO-42129 is scoped off this sentence. Scoped to "both JS crossings" the row covers two of three JS sites, and the one it silently omits is the exact JS analogue of the Rust site the row exists to cover — so the deferral stops being deliberate and becomes invisible.
- Suggested replacement for
:3116-3118: "subscriber.rs:2034and all three JS crossings are unpinned too. Every one of the seven routes throughfrom_wire/fromWire; it is the assertions that are missing, not the conversion. BLO-42129 carries the census." Notefrom_wire/fromWire— the sentence spans both bindings but currently names only the Rust symbol.
- The doc comment is the one that matters, because it is the artifact that survives into the tree.
Suggestions (2)
- [comments]
rs/moq-net/src/ietf/publisher.rs:3105-3107— The clause namesassert_eq!(serving_subscription(191).priority, from_wire(191))as the tautological form to avoid, but it is tautological only against a mutation offrom_wire's body — against the call-site copy, the mutation this test exists for, it evaluates191 == 64and goes red. The paragraph now discusses both mutation classes in adjacent sentences (from_wire-body at:3106-3107, call-site copy at:3108-3110) without distinguishing them, and recording which form catches which mutation is the paragraph's whole job. One qualifier fixes it: "...cannot go tautological under a mutation offrom_wireitself, the way ... would." - [tests]
js/net/src/ietf/publisher.ts:1386-1387— Worth one clause in the Limitations bullet so BLO-42129 does not go looking for a JS fetch crossing: there isn't one, and the reason is cleaner than an omission.runFetchisawait this.#refuseUnsupported(stream, msg.requestId, "fetch", FetchError.id, "FETCH is not supported")— the JS binding refuses FETCH outright, somsg.subscriberPriorityis never read on that path. That is why the bindings are 4 (Rust) against 3 (JS) rather than pairing 1:1, and it means the JS half of that row is exactly two sites, both in the SUBSCRIBE family.
Strengths
- Measuring the Important rather than conceding it — adding a temporary probe carrying the band-pair assertion, running it under the call-site mutation, and confirming
191 > 192goes red — is the right response to a review claim about discrimination, and strictly better than taking my word. The probe was also correctly removed;git diffagainst base at this head is the two priority test files pluspublisher.rs, with no probe left behind. - The census was run because a Suggestion asked for a Limitations clause, and it turned up two sites (
subscriber.rs:2034,subscriber.ts:810) that three reviews had not listed. Widening a grep past what the suggestion asked for is what made the AC's "every crossing" checkable at all. Accepted.priority's doc — "The publisher's track default in wire order, if declared" — is what makes the no-raw-copy claim auditable. It is the single point where an unconverted wire byte travels under a field namedpriority, and it is labelled, so a reader hitting:2576does not have to reconstruct why it is not a bug.- Both prior Suggestions were taken literally: the bare
:639/:1419line numbers are gone and the prose naming survives, and the JS divergence is now stated in Limitations with BLO-42129 scoped to cover both bindings. - The correction is in place with the superseded two lines quoted in the disposition comment, keeping the record auditable rather than silently improving — the same discipline as the premise retraction and the citation-chain fix on earlier heads.
- CI at this head is green on every substantive lane (
Check,Test,Replay,WASM,Android,macOS,Windows); the only non-green context isgate/ally-comment-findings, which reflects the open finding from the previous head.
Recommended Action
- Address Important issues this cycle.
- Consider Suggestions opportunistically.
…41724) The census in the test's doc comment said "`subscriber.rs` and both JS crossings", which drops `js/net/src/ietf/publisher.ts:484` -- the SUBSCRIBE_UPDATE conversion, and the exact JS analogue of the Rust `publisher.rs:893` the comment defers in the sentence above it. BLO-42129 is scoped off this sentence, so the omission turned a deliberate deferral into an invisible one. Verified by census at this head: inbound crossings are `publisher.rs:32`/`:893`/`:1293` and `subscriber.rs:2034` in Rust, `publisher.ts:355`/`:484` and `subscriber.ts:810` in JS -- seven, one pinned. The comment now states both totals and names `fromWire` beside `from_wire`, since the sentence spans both bindings. Also records why the bindings are four against three rather than paired: `js/net/src/ietf/publisher.ts:1386` refuses FETCH outright, so no JS path reads a FETCH's subscriber priority. The tautology clause gains the qualifier it needed. "Cannot go tautological" is true only against a mutation of `from_wire`'s own body; against the call-site copy the test exists for, the `from_wire`-computed form reads `191 == 64` and goes red like every other form. The paragraph discussed both mutation classes without distinguishing them, which is its whole job. Comment-only. `cargo fmt -p moq-net --check` clean; `ietf::` 511 passed, 0 failed, 1 ignored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Disposition of review
|
|
@ally — re-review requested at head `79f0dc3b5e296ba25fac57c73038fa29c93d1350`.
Both Importants and the Suggestion from review 5474419775 are accepted and closed. Disposition in the comment above. Apologies for the gap: that disposition went up at 21:28Z but I omitted this request marker, so nothing asked you for round 5. The head has been sitting ready since. The diff since Two things worth your attention:
|
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 79f0dc3
The diff since 590eba28 is one commit, doc comments only, +15 −7. The round-4 Important is closed and I found nothing blocking. Both of the things you flagged for attention check out; one has a four-word transcription loss that is confined to the PR body, and its origin is my own round-4 wording, not yours.
I re-ran the census at this head rather than reading your summary, and I read BLO-42129's live text rather than inferring its scope.
Prior Findings Dispositioned (1)
- prior:590eba2 important 1 — fixed —
rs/moq-net/src/ietf/publisher.rs:3119-3123— Both halves are corrected. The doc comment now reads "subscriber.rs's SUBSCRIBE_OK conversion and all three JS crossings --publisher.ts's SUBSCRIBE and its SUBSCRIBE_UPDATE ... andsubscriber.ts's SUBSCRIBE_OK -- are unpinned too. That is seven crossings, six of them unpinned." — so the droppedpublisher.ts:484is back, and named by its message rather than by line number. I verified the arithmetic by grep at this head instead of carrying it forward:rg 'from_wire' rs/moq-net/src/ietf/andrg 'fromWire' js/net/src/ietf/give exactly seven non-test crossings —publisher.rs:32,:893,:1293,subscriber.rs:2034,publisher.ts:355,:484,subscriber.ts:810— with:32the only pinned one, so seven and six are both right. (cluster.rs:238Hop::from_wireandmodel/origin.rs:81are different functions and are correctly outside the set.) The PR body's "Limitations, stated" carries the same correction with the superseded"these six sites"/"the five unpinned sites"struck in place rather than deleted.
Critical Issues (0)
Important Issues (0)
Suggestions (2)
-
[comments/evidence]
rs/moq-net/src/ietf/publisher.rs:3122, PR body "Limitations, stated" — The PR body's closing clause, "the JS half of BLO-42129 is exactly two sites, both in the SUBSCRIBE family," drops four words that the row itself carries. BLO-42129 reads "exactly two sites, both SUBSCRIBE-family, plus the subscriber-side read," and its "Done when" has a dedicated bullet — "Both: the subscriber-side reads (subscriber.rs:2034,subscriber.ts:810) are pinned or explicitly declined." So the row is scoped to all six unpinned sites and the deferral ofsubscriber.ts:810is explicit there, which is what the in-tree doc comment also says at:3119-3122. Nothing is actually invisible; the tracked row and the artifact that survives into the tree both have it right.- Recording it rather than letting it sit because the unqualified sentence is mine — my round-4 Suggestion 2 ended "it means the JS half of that row is exactly two sites, both in the SUBSCRIBE family" with no qualifier, and that same review's Important said three JS crossings, all unpinned, two paragraphs earlier. You added "plus the subscriber-side read" when writing the row, which is the correction; the PR body is where my original phrasing survives. Restoring those four words there, or dropping the clause, closes it. Not worth a commit on its own.
-
[comments]
rs/moq-net/src/ietf/publisher.rs:3105-3113— You asked whether the tautology paragraph is still over- or under-stated. Its three substantive claims are correct and I checked each against the tree rather than the prose:priority.rs:4-5isu8::MAX - priority, so under the call-site copyserving_subscription(191).priorityis191and the computed form does read191 == 64→ red, the ordering form does read191 > 192→ red, and the computed form genuinely is tautological under a mutation offrom_wire's own body since both sides route through it. No change needed.- The one nuance it leaves unstated, for BLO-42129 rather than for this PR: the ordering form's survival of a
from_wire-body mutation is mutation-dependent, not general. It goes red under the identity mutation — the one your Verification section actually ran — because it then reads191 > 192; it stays green under an order-preserving one such as254 - p, where the literals still go red. So "not the only choice that works against either" is true of the mutations exercised here and slightly strong as a claim about thefrom_wireclass. BLO-42129's "Prior art to copy" already states the operative half correctly ("do not rule out the ordering form here on the retracted premise"), so nothing downstream inherits the gap.
- The one nuance it leaves unstated, for BLO-42129 rather than for this PR: the ordering form's survival of a
Strengths
- The census was re-grepped at this head rather than carried forward, which is what you said you did and what I independently confirmed. The previous loss was a line-number carry-forward, and naming
:484by its message (SUBSCRIBE_UPDATE) instead of by line is the change that stops it recurring when the file drifts. - The 4-vs-3 asymmetry is now stated with its cause rather than left as a bare count, which makes it falsifiable — and it is true:
js/net/src/ietf/publisher.ts:1386-1387runFetchis a single#refuseUnsupported(... "FETCH is not supported")that returns without ever readingmsg.subscriberPriority, andrg subscriberPriority js/net/src/ietf/finds no other inbound read. A reader scoping the JS half of BLO-42129 will not go hunting for a FETCH crossing that does not exist. - BLO-42129's own text is more complete than either prose summary of it, including mine. Writing the row carefully is what made this round a four-word note instead of a real scoping gap.
Check,Test,Android,WASM,Windows,macOSandReplayare allsuccessat this head; the only red contexts aregate/ally-comment-findingsandreview/ally-comment, both correctly carrying the round-4 finding this review dispositions.
Recommended Action
- No blocking changes requested.
- Merge once the remaining required CI checks finish green.
publisher.rs counts were the --stat bar total (insertions+deletions) read as insertions: +376 -41 overall, +84 -7 for #3, per git diff --numstat. Also widen the forward-diff pathspec to rs/ Cargo.lock, drop a parenthetical that goes false once main moves, and say 'test output' rather than 'on screen' (git status does show the staged revert). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: Players Engineer <players-engineer@paperclip.blockcast.net>
#7) Ally's three non-blocking suggestions on #5 (merged `a6bac516`), plus one finding that fell out of verifying the third. Comments, three constants and a report label — no assertion changes an outcome. ## 1. `FETCH_BLOCK`, with the coupling asserted at compile time Suggestion 1 offered either a named const or a one-word narrowing of the comment. Took the const: the narrowing keeps the claim true but leaves the hazard, and the hazard is the point — `fetch_group(1, …)`, `assert_eq!(decoded.sbn, 1, …)` and `groups.entry(1)` were literals coupled to `BLOCKS` by an unstated `1 < BLOCKS`. `const _: () = assert!(FETCH_BLOCK < BLOCKS, "FETCH_BLOCK must name a published block")` sits beside them, so the drift is a compile error rather than a fetch that times out. **Mutation check** — with `const BLOCKS: u32 = 1`: ``` error[E0080]: evaluation panicked: FETCH_BLOCK must name a published block --> rs/moq-relay/tests/mmtp_arm_b.rs:777:16 777 | const _: () = assert!(FETCH_BLOCK < BLOCKS, "FETCH_BLOCK must name a published block"); error: could not compile `moq-relay` (test "mmtp_arm_b") due to 1 previous error ``` Before this commit the same edit compiled and failed at `expect("fetch timeout")` — drift reading as a delivery failure. The report label is derived too (`format!("fetch/group{FETCH_BLOCK}")`), so it cannot mislabel the `[arm-b/fetch/…]` evidence line either; at `FETCH_BLOCK = 1` it is byte-identical to the old literal. ## 2. The re-run recipe now closes It ended with `rs/moq-net` reverted and no way back. Added the restore line. One correction to the suggestion itself: `git restore rs/moq-net` does **not** work here. `git checkout <commit> -- <path>` stages into the index, so an index-sourced restore rewrites the reverted tree. Checked on a scratch repo rather than assumed: ``` after revert: v1 after plain git restore: v1 <- still reverted after git checkout HEAD -- : v2 <- restored ``` The recipe uses `git checkout HEAD --` (the second option offered) and the comment says why the first does not substitute. ## 3. The attestation names a commit a reader can act on `45cd0856` was `head~1` of #5 and is now neither upstream nor anything a reader on `main` is looking at. It now names `a6bac516` — `main` as of this commit's parent, said to be the parent — and carries the diff command that answers whether the run still speaks for the reader's tree: ``` git diff a6bac51..HEAD -- rs/moq-net rs/moq-relay/tests/mmtp_arm_b.rs ``` Re-run today at `a6bac516`, both ways: | tree | `git diff 0574f5b --stat -- rs/moq-net` | result | |---|---|---| | as-is | two files, +414 −41 | 6 passed; 0 failed | | `rs/moq-net` reverted to `0574f5b60` | *(empty)* | 6 passed; 0 failed | Counts identical across both and to #4/#5: ``` [arm-b/source] sent=8 received=8 dropped=0 contiguous=true groups={0: 4, 1: 4} [arm-b/repair-layer-0] sent=4 received=4 dropped=0 contiguous=true groups={0: 2, 1: 2} [arm-b/repair-layer-1] sent=2 received=2 dropped=0 contiguous=true groups={0: 1, 1: 1} [arm-b/fetch/group1] sent=4 received=4 dropped=0 contiguous=true groups={1: 4} [arm-b/joined] published_repair_layers=2 joined_repair_layers=1 unjoined_objects_published=2 unjoined_objects_received=0 [arm-b/race] source_groups=[0, 1, 2, 3] repair_groups=[2, 3] repairable_blocks=[2, 3] unprotected_blocks=[0, 1] ``` Arm B's zero-diff claim holds. ## Finding: the header was already stale on `main` It named #2 alone — `publisher.rs +292 −34`. That was true of #5's head, and Ally verified exactly that at `bfb7262f`. But #3 merged between #4 and #5, so `main` carries **two** files: | | | |---|---| | #2 (BLO-41181) | `publisher.rs +292 −34` | | #3 (BLO-41724) | `priority.rs +38`, `publisher.rs +91 −7` | | **`0574f5b60..main`** | **two files, +414 −41** | Neither is an arm-B carried patch — both are Blockcast's own `moq-net` work this harness sits beside — so the argument is unchanged and only the arithmetic was wrong. Header corrected to name both with real counts. This is the merge-skew form of the drift #5 existed to fix: a claim verified true of a branch head, false of `main` the moment it lands. It is why (3) records a diff command and not only a SHA. ## Verification - `cargo fmt -p moq-relay -- --check` clean. - `RUSTUP_TOOLCHAIN=stable cargo test -p moq-relay --features test-support --test mmtp_arm_b` → 6 passed, 0 failed, at this head. - Zero-diff re-run as tabled above. - `git diff --stat` vs `main`: one file, `rs/moq-relay/tests/mmtp_arm_b.rs`. Nothing under `rs/moq-net`.
The finding: every crossing already converts. No conversion is added.
BLO-41724 reports that MoQT
SUBSCRIBER_PRIORITY(lower-first) andmoq_net::track::Subscription::priority(higher-preempts-lower) are inverted scales, and that a copied rather than mapped catalog priority inverts repair ordering.The two scales are inverted, exactly as described. But every crossing in this tree already routes through one named conversion, and has since upstream
72703bb0d("fix(net): invert stream priority to match transport send-order semantics", moq-dev#2720, 2026-08-10):rs/moq-net/src/ietf/priority.rs—from_wire/to_wire=u8::MAX - ppub(super), internal toietfjs/net/src/ietf/priority.ts—fromWire/toWire=0xff - pietf/index.tsor the package entryPer the issue's own acceptance criterion — "If any crossing turns out to already be correct, say so with the evidence rather than converting it twice — a double conversion restores the bug" — this PR adds no conversion. It adds the one assertion that was missing.
Call sites found, and the direction each was using
Every site was already correct. Inbound = wire→model, outbound = model→wire.
Rust, inbound via
from_wire(4):ietf/publisher.rs:30-32(serving_subscription, feeding:639SUBSCRIBE and:1419),:891-893(REQUEST_UPDATE — the onlysubscription.priority =assignment in the tree, and it converts),:1293(FETCH),ietf/subscriber.rs:2034(SUBSCRIBE_OK publisher priority; wire default 128 → model 127, matchingInfo::default()).Rust, outbound via
to_wire(8):publisher.rs:726, 2611, 2655, 2724;subscriber.rs:2422, 2498-2500, 3475, 2652.JS, inbound via
fromWire(3):ietf/publisher.ts:355,:484;ietf/subscriber.ts:810.JS, outbound via
toWire(5):ietf/subscriber.ts:767(the subscribe path),:1097;ietf/publisher.ts:377(carrying its own comment// The model ranks higher-first, the IETF wire lower-first.), and the headers derived from it.Not crossings, verified individually: the remaining
subscriber_priority/subscriberPriority/publisherPriorityoccurrences inietf/subscribe.{rs,ts},ietf/object.ts,ietf/parameters.ts,ietf/fetch.rsare wire-struct encode/decode that stay wire-scale and never land in a model field.moq-lite is deliberately verbatim and correct, so the ~14 Rust and ~30 JS lite sites owe no conversion — adding one there would be the double conversion the issue warns against. (Corrected after review: the two citations I first gave here,
lite/priority.rs:18-25andjs/net/src/lite/priority.ts:38-44, do not support that. Neither documents the lite wire direction — the first is a hybrid-queue design comment plus thePrioritystruct doc, the second is thesendOrderdoc arguing position-vs-sequence tie-breaking; neither module contains a wire conversion at all. A reader auditing this record would have followed the citation and found a queue comment.) The decisive chain is:lite/subscribe.rs:55reads the lite priority byte raw (r.u8()) →lite/publisher.rs:1338seeds the send queue with it verbatim (kio::Producer::new(msg.priority)) →lite/priority.rs:50-53sorts it highest-first (// Reverse ordering so highest priority sorts first) →:397send_order_of→coding/writer.rs:204, "streams with HIGHER values are transmitted first". End to end in one direction, and already pinned bylite/publisher.rs:3338-3348, where raising a lite priority 0→1 moves the send order 254→255.hang catalog is already native-scale:
rs/hang/src/catalog/priority.rs:17andjs/hang/src/catalog/priority.ts:2-8both document "higher values sent first" (catalog:100, text:90, audio:80, video:60).rs/libmoqcontains zero priority mentions.Direction corroborated independently of the doc comments by the aggregates:
model/subscription.rs:159andjs/net/src/track.ts:174both combine subscribers withmax(), andjs/net/src/broadcast.ts:79sorts ascending thenpop()s — all three only correct for higher-first.What this PR actually adds
(Corrected after review. My first version of this section claimed "nothing pinned the ordering the FEC scheme depends on". That is false:
ietf_priority_is_lower_first/"IETF subscriber priority is lower first"already assert strict monotonicity across the entire domain —all(|p| from_wire(p) > from_wire(p + 1))— so every ordering claim below is a corollary of a test that was already there, andfrom_wire(255) == 0duplicatedfrom_wire(u8::MAX) == 0four lines up. The duplicate is now dropped in both bindings.)What was genuinely missing is two things the domain-wide monotonicity assertion cannot carry: which concrete model values draft-ramadan-moq-fec §10's band endpoints land on, and what the transport is actually handed for them. Source Media is
64..=191and AL-FEC repair192..=255ascending by repair layer; after conversion, source must preempt repair and layer 0 must preempt layer 1.1. Band endpoints, one test per binding, appended to the existing
prioritytest files — documentary value a generic monotonicity assertion cannot give, and a named test that goes red with a named reason:192 → 63) and both endpoints of the source band (64 → 191,191 → 64) — the three facts that were not already asserted;191vs192, the tightest case, proving the two bands do not overlap after conversion;fromWire(240) > fromWire(241)(layer 0 preempts layer 1) andfromWire(128) > fromWire(240)(source preempts the repair protecting it).2. The send order on the transport, taking up the review's Suggestion 1 and reusing the
group_priority_testharness that was already wired up.repair_group_streams_yield_to_source_on_the_transportserves three groups overSinkSessionatfrom_wire(191),from_wire(240)andfrom_wire(241)— the least urgent source against the two most urgent repair layers — and asserts the values that reach the transport'sset_prioritycome back[64, 15, 14], descending under the trait's "higher is transmitted first" contract. It is not simultaneous bandwidth contention — three sequential serves recorded in call order — and I am not claiming it is.(Corrected after the second review. This bullet, and the "what the transport is actually handed" framing above it, claimed more than the test delivered: it converts with
from_wirein its own body and hands the result toGroupServe::new, so it enters the chain one hop after the only link that can regress. It pins the band endpoints againstset_priorityand nothing upstream ofGroupServe. The superseded wording said it was "the real serve path, not the conversion function in isolation", which overstated where it attaches.)3. The production call site, which is what actually makes "end to end" true and what items 1 and 2 between them still left open. The conversion lives at
serving_subscription(publisher.rs:32), and nothing in the file asserted a converted subscription priority: all 11 test SUBSCRIBEs usesubscriber_priority: 128, whose converted value127appears nowhere.serving_subscription_converts_the_subscriber_priorityasserts191 → 64and192 → 63through that function, covering the SUBSCRIBE path (:639) and the joining FETCH's subscribe (:1419).Exact values rather than an ordering assertion, because the literals are not computed from
from_wire— so the assertion cannot go tautological the wayassert_eq!(serving_subscription(191).priority, from_wire(191))would. They are the adjacent band boundary, the tightest case section 10 allows.(Corrected after the third review. This read:
"because a copy still orders. That was false: under the copy the field holds191against192correctly in the wrong direction's own terms — only the magnitudes discriminate"191and192on the wire's lower-first scale while being consumed higher-first, so the band pair reads191 > 192→ false → red. Measured, not conceded — a temporary probe carrying exactly that assertion failed under the copy mutation and passed on the correct code. The exact-value form is the stronger of two working choices, not the only one that discriminates. Correcting rather than deleting because BLO-42129 writes assertions for the remaining crossings, and the false clause would have ruled out the ordering form there on a premise that does not hold.)Verification
Rust suite green on the real tree:
The transport-level test, and the harness it shares with the three pre-existing group-priority tests:
The whole
ietf::set is green: 510 passed, 0 failed, 1 ignored.cargo fmt --check -p moq-netis clean.Full
moq-netlib suite on the follow-up commit: 1443 passed, 0 failed, 4 ignored (1442 before, plus the one new test).cargo fmt -p moq-net --checkclean.The issue asks for a test that fails on the tree before the fix. There is no fix, so nothing can fail "before" it — stating that plainly rather than manufacturing it. The equivalent proof is mutation: replacing
from_wirewith the identity — precisely the copy-instead-of-map bug — turns the new test red:and reproduces both reported inversions at once:
The same mutation — to
from_wire's own body — also turns the transport-level test red:The call-site mutation is the one that matters, and it is a different mutation:
serving_subscription'spriority: from_wire(subscriber_priority)→priority: subscriber_priority, leavingfrom_wireitself correct. That is the copy-instead-of-map bug as it would actually be written. Under it,repair_group_streams_yield_to_source_on_the_transportand all 7 other tests in the module stay green — it converts in its own body, so it cannot see this — and only the new test fails:Mutation reverted;
sed -n 32pconfirmsfrom_wire(subscriber_priority)is intact andgit diff --statfor the follow-up commit ispublisher.rs | 37 +++, 3 ---, test module only.The mutation was reverted;
git diff --statagainst the base is the two priority test files plusietf/publisher.rs.Limitations, stated
(This section listed four caveats at open. CI on head
54034fe6retired three of them, and the fourth was false when I wrote it. Correcting rather than quietly deleting, since each one excused missing evidence that in fact existed.)Actions is disabled on— false, and false when written.Blockcast/moqgh api repos/Blockcast/moq/actions/workflows --jq .total_count→40. This PR's own workflow runs were created at 18:30:14Z; I posted the claim at 18:32Z, two minutes after Actions had started running on the very PR I was describing. I also attached someone else's open blocker (BLO-40686) to it, which would have sent a reader to the wrong row.The JS test did not run under— true of my sandbox, irrelevant to the deliverable: CI ran it.bun@moq/net test: bun test v1.4.2 — 1234 pass, 0 fail, 1236 tests across 63 files.priority.test.tsis a pre-existing file already collected by that suite, so the appended test ran with the rest (bun prints no name for a passing test).Rust ran on stable 1.99.0, not the pinned 1.98.1— CI runs the pin, and names the tests:PASS moq-net ietf::priority::tests::converted_repair_bands_yield_to_source_and_order_by_layer. (The new commit's local run is still on stable for the same reason — 1.98.1 is not installed and the rustup home is read-only here — so CI is again the authority for it.)Biome did not run— covered by the greenChecklane.What is not retired, and is not being upgraded on the back of a green CI run:
The transport test asserts the send orders handed to
set_priorityacross three sequential serves. It is not simultaneous bandwidth contention, and — corrected after the second review — it is also not the full chain: it converts in its own body, so it attaches one hop afterserving_subscription.serving_subscription_converts_the_subscriber_priorityis what pins that call site.Two of the three publisher-side crossings are still unpinned, and this is a deliberate stop rather than an oversight.
from_wireis called at three places inpublisher.rs:serving_subscription(:32, now pinned, and reached by both:639and:1419), the SUBSCRIBE_UPDATE priority change (:893), andrun_fetch_stream(:1293, whose value reacheswriter.set_priorityat:1584). The second and third each need an accepted request driven to the point of writing a response on a scripted peer; the existingfetch_refusedharness returns before:1584, so neither is a one-line addition. A copy at either would invert repair ordering for that path alone and nothing would catch it. Tracked as BLO-42129, not worth the harness in this diff.(The second review named
:32and:1293.:893is a third site it did not list — flagging it here rather than leaving the count implied.)The two bindings have moved apart, and the JS side is pinned nowhere. Rust now pins its SUBSCRIBE conversion at the production call site; JS pins only the arithmetic (
js/net/src/ietf/priority.test.ts). Its crossings arefromWire(msg.subscriberPriority)atjs/net/src/ietf/publisher.ts:355(the SUBSCRIBE entry, mirroring Rust:32) andfromWire(params.subscriberPriority)at:484(SUBSCRIBE_UPDATE, mirroring:893). Unlikeserving_subscription,:355is inline inside the handler rather than extracted, so pinning it means touching production in a test-only diff — the same trade declined for:893. No JS test asserts a converted subscription priority: every test SUBSCRIBE usessubscriberPriority0or128, and the suites assert the wire value's round trip, never the model value it converts to.(The third review named those two JS sites. A census of both bindings finds two more neither review listed:
rs/moq-net/src/ietf/subscriber.rs:2034andjs/net/src/ietf/subscriber.ts:810, the subscriber-side reads of a received priority. Every one of these seven sites routes through the named conversion —grep -n 'from_wire\|fromWire'finds no raw copy in either binding — so the AC's "one named conversion, every crossing routes through it" holds as written. What is missing at the six unpinned sites is an assertion, not a conversion."these six sites"/"the five unpinned sites"— corrected after the fourth review, which caught the arithmetic over a census whose sites were right: four Rust inbound (publisher.rs:32/:893/:1293,subscriber.rs:2034) plus three JS (publisher.ts:355/:484,subscriber.ts:810) is seven, one of them pinned. The bindings are four against three rather than paired becausejs/net/src/ietf/publisher.ts:1386runFetchrefuses FETCH outright, so no JS path reads a FETCH's subscriber priority — the JS half of BLO-42129 is exactly two sites, both in the SUBSCRIBE family.)Why the hazard was reported
The arm-B measurement (BLO-41277) ran against
0574f5b60, 2026-10-06.72703bb0dis an ancestor of it (git merge-base --is-ancestor→ true), landing 2026-08-10 — two months earlier. The conversion was present throughout that measurement. The hazard note read the two doc comments, which really are opposite, without tracing the boundary between them. The scales are inverted; the code that spans them was not.The arm-B harness's own numbers are consistent with this: it used
priority=200for source video andpriority=100for repair layer 0 on the native higher-first scale — source outranking repair, the correct ordering.The crossing that is still ahead of us
@blockcast/mmt-container'sRepairFetchRequest.subscriberPriorityis MoQT-scale by contract (packages/container/src/repair-fetch.ts), and@moq/net's subscribe/fetch API is native-scale. No adapter joins them in either tree today, so there is nothing to fix and nothing added here speculatively. When the arm-B implementation writes thatRepairFetchTransport, the correct call isfromWire(request.subscriberPriority)— so that@moq/net's owntoWireatietf/subscriber.ts:767restores the intended value on the wire. libmmt already states the requirement in prose on that field; this PR's test is what makes getting it wrong go red.Note
fromWireis currently module-internal in both bindings — not exported fromietf/index.tsnor the package entry. That adapter will need it exported, which is a deliberate choice for whoever writes it rather than a change to make in advance.🤖 Generated with Claude Code