Skip to content

quest(wildcard): Wildcard advertisements - #4403

Merged
kixelated merged 32 commits into
mainfrom
quest/m0/wildcard/README
Oct 6, 2026
Merged

kixelated merged 32 commits into
mainfrom
quest/m0/wildcard/README

Conversation

@kixelated

Copy link
Copy Markdown
Collaborator

Questline branch for /quest/m0/wildcard/README.md. Continues #4037 at the m0 path: main moved the line to quest/m0/wildcard/ in #4213, so quest branch now expects quest/m0/wildcard/README. Child quests merge here; this stays a draft until the line's Required list is empty.

This branch is quest/m1/wildcard/README with origin/main merged in:

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

kixelated and others added 14 commits September 24, 2026 10:34
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Franz Heinzmann <frando@unbiskant.org>
Co-authored-by: Grok <noreply@x.ai>
Co-authored-by: moq-bot[bot] <186640430+moq-bot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Franz Heinzmann <frando@unbiskant.org>
Co-authored-by: Grok <noreply@x.ai>
Co-authored-by: moq-bot[bot] <186640430+moq-bot[bot]@users.noreply.github.com>
Co-authored-by: opencode agent <agent@opencode.ai>
Co-authored-by: GPT-6 Astra <codex@openai.com>
Co-authored-by: bgreenway <brad.greenway@me.com>
Co-authored-by: Brad Greenway <brad.greenway@surveillx.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… origin (#4279)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…nchmark findings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A transcoder claims a `.`-named service prefix (`.transcode/`), which is
hidden from default discovery, so the player's cross-broadcast check never
saw the claim and filtered the rendition it covers. The check now opts into
hidden routes; it only decides availability and lists nothing to the user.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mirror derived output under `.pro/<service>/`, moq.pro's convention, in
the line README, the broadcast-epoch layout, and the watch test fixtures.
The prefix is hidden so customers on moq-lite-06 or older never see it,
and the player's covering check sees it only on lite-07, so the line now
requires lite-07 to be finalized and negotiated by default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Moves the wildcard line to quest/m0/wildcard/ to match main (#4213) and
keeps main's audit decisions: suffix routing dropped, processors on the
service-prefix layout, pop-skipping deleted.

Code: a standing refusal still ends the front (the line), and a closed
source's standing route stays excluded from reselection (#4232), now the
only thing the front's excluded set holds. FETCH_OK decoding moves into
main's fetch setup, replacing the reader.done() accept on lite-07.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… merge

main's SUBSCRIBE_END stream count and the line's started flag together push
SubStream past clippy's large_enum_variant threshold.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uest/m1/wildcard/hidden-demand

# Conflicts:
#	quest/m1/broadcast-epoch/README.md
fix(watch): see hidden .pro claims when gating renditions
kixelated and others added 4 commits September 30, 2026 07:24
- lite publisher: main's held first group (resolved against the source's
  start) now sends SUBSCRIBE_START with the serving origin; a datagram that
  goes first still resolves the start from its own sequence.
- front: Anonymous keeps `here` and gains main's rule that the route gaining
  a first hop ends it; an aborted track refuses its copies' admission before
  main's `io.end()` keeps the entry for the linger.
- js/net lite subscriber: main's tail grace, end checks, and fetch
  cancellation around the branch's SUBSCRIBE_START / FETCH_OK origin.
- relay cluster doc and cluster draft: main's overlap authorization and
  in-place publisher update, with the branch's terminal refusal and hashing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Align the README with the audit's moved quests and drop the lite-07
Required bullet: finalizing lite-07 is a rollout condition, not a blocker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The line lives at quest/m0/wildcard/, so its children do too, listed under
Required. datagram-start notes main's held first group.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Merged origin/main (through the 2026-09-30 audit, #4589) into the line. Not finalizing yet: #4386's three children still block it (see below).

Merge resolutions

  • lite/publisher.rs: main now holds the first group until the source resolves where its feed starts. The held path sends SUBSCRIBE_START with the serving origin through one send_start helper. A datagram that goes first still resolves the start from its own sequence, which is now tracked in datagram-start.
  • model/front.rs: Identity::Anonymous { route, here } keeps the branch's here and takes main's rule that the route gaining a first hop ends it.
  • model/origin.rs: an aborted track refuses its copies' admission, then calls main's io.end(), which keeps the entry for the linger instead of removing it.
  • js/net lite subscriber: main's tail grace, end checks, and fetch cancellation now sit around the branch's SUBSCRIBE_START / FETCH_OK origin. Main's new fetch-cancel tests pass the front.
  • Relay cluster doc and cluster draft: main's overlap authorization and in-place publisher update, plus the branch's terminal refusal and path hashing. A short paragraph on refusal finality and shedding load by re-pricing moved here from the README.
  • README: the audit's moved quest links, and the lite-07 Required bullet is dropped. Finalizing lite-07 is a rollout condition, not a blocker. The quest pin now matches main (8590d2a).

Checks: quest check, just check, cargo test -p moq-net (1374 passed), and just test interop --all all pass.

Still blocking: #4386 moves its children to quest/m0/wildcard/ (datagram-start [M], js-origin [S], pool-bench [S]). All three findings still hold after the merge.

(Written by Claude Opus 5.5)

kixelated and others added 2 commits September 30, 2026 08:31
quest(wildcard): block the line on the #4279 datagram, origin, and benchmark findings
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
kixelated and others added 2 commits October 4, 2026 21:34
Main's #4741 makes the path the only content identity, and the wildcard
README (#4761) drops the reply Origin. Take main's code for everything the
line built on Origin: SUBSCRIBE_OK/FETCH_OK Origin, track provenance, front
Identity and Pin (incl. Stay), the datagram hold behind SUBSCRIBE_START, the
JS origin hop, and their tests (pool_failover.rs, lite/origin.test.ts).

Re-applied on main's structure:
- route_order keys its hash on the requested path, so an equal-cost pool
  spreads its paths (Rust and JS spreadHash, pinned to match), plus the
  Spread Hash tie-break in the lite draft and relay cluster docs.
- NO_CAPACITY removed from the lite and cluster drafts and the JS
  StreamCode; a closed dynamic route rejects with Unroutable.
- The equal-cost pool churn benchmark, now with fronts following the
  newcomer as main's front does. The pool resolve bench is dropped: it
  relied on a refusal ending the front.
- js/watch counts hidden service claims when gating renditions.

Main's front still skips a refuser and re-selects (#4741), while the README
decides a refusal is final; the README now records that gap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Picks up the stats and JS package bumps landed since the previous merge;
no conflicts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated
kixelated marked this pull request as ready for review October 5, 2026 04:34
@kixelated

Copy link
Copy Markdown
Collaborator Author

Merged main into the line (99b3688) and marked it ready.

Conflict resolutions

  • fix(net)!: resume route changes by reading the routes' copies; a path is one broadcast #4741 (a path is one broadcast) and the README's "No reply Origin" decision win. I took main's code for everything built on Origin: SUBSCRIBE_OK/FETCH_OK Origin, track provenance, front Identity/Pin (incl. Stay), the datagram hold behind SUBSCRIBE_START (fix(lite): keep datagrams behind SUBSCRIBE_START #4611), the JS origin hop (fix(net): JS names its own origin, drops a copy whose origin changes #4599), and their tests (tests/pool_failover.rs, lite/origin.test.ts). The draft's Origin text went with them.
  • Re-applied on main's structure: route_order hashes the requested path, so an equal-cost pool spreads its paths (Rust fnv_key and JS spreadHash, pinned to the same values). Also the Spread Hash tie-break in the lite draft and doc/bin/relay/cluster.md, NO_CAPACITY removed from both drafts and the JS StreamCode (a closed dynamic route now rejects with Unroutable), and the js/watch hidden-claim gating.
  • origin/pool_churn bench kept, without its "no front moves" assertion, since a front now follows the best route. origin/pool_resolve dropped: it relied on a refusal ending the front.

Open decision: refusal semantics. #4741 made a standing refusal skip the refuser and re-select (standing_refusal_tries_the_next_route_then_ends, "audit F2"). That can reach a sibling advertiser or a shorter prefix. The README and both drafts say every refusal is final, and this line had implemented that (#4218). I kept main's code and left the refusal docs claims out of the relay docs. The README's "What already exists" now records the gap. Recommendation: restore terminal refusal in Front::resolved and stop best_route from falling through to a shorter prefix, then re-add the pool resolve bench and the two refusal tests.

Checks

  • just check passed (5623 Rust tests).
  • bun test passed in js/net (1209) and js/watch (257).
  • quest check is ok.
  • The origin/pool_churn bench passes in --test mode.
  • just test interop --all: in the first run every Go publisher pair failed with an internal error after 10s. go -> rust alone passed, and a full rerun passed 32/32.

(Written by Claude Opus 5.5)

@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You'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 23 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7d822f7f-07de-40d9-8a6b-4d8a360d8ec3
📥 Commits

Reviewing files that changed from the base of the PR and between 06400a9 and 8d24696.

📒 Files selected for processing (15)
  • doc/bin/relay/cluster.md
  • drafts/draft-lcurley-moq-cluster.md
  • drafts/draft-lcurley-moq-lite.md
  • js/net/src/error.test.ts
  • js/net/src/error.ts
  • js/net/src/ietf/publisher.ts
  • js/net/src/internal.ts
  • js/net/src/origin.test.ts
  • js/net/src/origin.ts
  • js/watch/src/broadcast.test.ts
  • js/watch/src/broadcast.ts
  • quest/m0/wildcard/README.md
  • rs/moq-net/benches/origin.rs
  • rs/moq-net/src/error.rs
  • rs/moq-net/src/model/origin.rs
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kixelated

kixelated commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator Author

Grok review of 99b3688dae03e502121a8a3f29cd714c1f3a61e5 (full review: first review since the PR was marked ready)

The merge looks clean. The Rust and JS spread hashes match byte for byte, and the pinned vectors (spread_hash_matches_js / the spread hash matches rs/moq-net byte for byte) are a good guard. Switching route_order to hash on the requested path rather than entry.prefix is the right fix: before this, every path under a pool prefix hashed alike and piled onto one member. Two things keep the line from being done, though.

Blocking

  1. Required isn't empty, but the PR is marked ready. quest/m0/wildcard/README.md still lists Transcoders start at group boundaries under ## Required. The README says "this line cannot ship with workers that can be spliced mid-group", and the PR body says it "stays a draft until the line's Required list is empty". That quest is still open on main, and its fix (fix(transcode): refuse a fetch that starts mid-group #4812) is a draft. With front-follows-best-route plus per-path hashing, a pool member joining or leaving moves about 1/N of the fronts that have no concrete announcement yet. Until fix(transcode): refuse a fetch that starts mid-group #4812 lands, any of those moves can splice two encoders mid-group.
    Fix: put the PR back in draft until fix(transcode): refuse a fetch that starts mid-group #4812 (and whatever else that quest needs) merges into the line, or decide explicitly to drop it from Required.

  2. The drafts now say every refusal is terminal, but the code (yours and main's) re-selects, including through a shorter prefix. best_route (rs/moq-net/src/model/origin.rs:3375) drops refused entries before candidates.peek(). So if a tier's only advertiser refused, that tier has no candidates and the walk settles on a shorter covering prefix. Concretely: one transcoder claims .pro/transcode, the archive claims the root, and the transcoder refuses .pro/transcode/x. The front then marks it refused, re-selects, and sends the request to the archive. That is exactly what the Goal ("A terminal concrete refusal does not fall through to a catch-all"), the Decisions bullet, draft-lcurley-moq-lite.md §Resolution ("Every refusal is terminal and propagates without re-resolution"), and draft-lcurley-moq-cluster.md ("A refusal never moves to another publisher") rule out. The README's "What already exists" admits the gap, but the two drafts and the relay doc don't, and they would land on main as normative text the reference implementation breaks. JS has the same problem: route() "refuses (then is skipped)".
    Fix: either land your stated recommendation in this line (terminal refusal in Front::resolved, best_route not falling past the winning tier, and the pool-resolve bench and two refusal tests restored), or keep the drafts' refusal paragraphs from claiming terminality until that lands. Shipping the line with Goal and code disagreeing is the outcome to avoid.

Non-blocking

  • doc/bin/relay/cluster.md overclaims convergence. It says "every relay picks the same one for a given path". fnv_key hashes the whole hop chain, so relays that see the same pool through different chains ([W1]/[W2] at the attaching relay vs [W1,R]/[W2,R] one hop down, or via R1 vs R2) can rank the pool differently. The README's double-claim bullet already admits this ("Two relays can hash one path to different workers"). Use the lite draft's wording instead: "on every relay that holds the same routes". Alternative worth considering: keying the hash on the route's originating (first non-zero) hop instead of the whole chain would make equal-cost ties agree across vantage points and narrow the double-claim window. Cost and hop-count differences would still dominate, as intended.
  • JS doesn't apply the spread-hash tie-break when choosing which route to advertise. The lite draft now says "When choosing which route to advertise for a prefix, the requested path is the prefix itself". Rust does this (sync_route / sync_cursor call route_order(prefix, …)), but JS compareCandidates (js/net/src/origin.ts:211) stops at hop count, and its stable sort leaves the newest route first. So a JS relay and a Rust relay holding the same routes can forward different hop lists for a prefix, which in turn changes the downstream spread hash. Add the spreadHash(prefix, hops) tie-break there to match.
  • Unroutable is missing from the round-trip list in toStreamCode and fromTransport agree on what a code means (js/net/src/error.test.ts). It also isn't in the "lite-only codes do not reach an IETF peer" list, even though it's in the 48–63 range and assignedLite now includes it.
  • A closed Dynamic / ServeState now rejects with Unroutable instead of NoCapacity. That matches Rust, but it's a JS-visible behavior change for anyone matching on the old code. NoCapacity disappearing from StreamCode is also a public-API break, so it deserves a changeset or upgrade note if one isn't already in the line.
  • Interop flake: the first just test interop --all run had every Go-publisher pair fail with an internal error after 10 s. A rerun passed, but it's worth confirming that's pre-existing on main and not something the hash change caused in Go↔Rust resolution.
  • Stale reference: README cites rs/moq-net/src/model/origin.rs:426 for Cost { warm, cold }. The struct is at :404 now.
  • CI is still pending on this head.

Verdict: ITERATE. The spread-hash work is good to go. What's left is the open Required quest and the refusal-terminality contradiction between Goal, drafts, and code.

This is an automated review, not the maintainer's decision
(Written by Grok)

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: 99b3688. Reviewed the full current 15-file diff against base 75a0e75; no previous review submission was available.

  • P2: Apply Spread Hash to JS advertisement selection too. js/net/src/origin.ts:247–252 adds the hash only to preferredEntry, but advertisements still use candidates() → compareCandidates (:210–216, :443–445), which breaks equal-cost/equal-length ties by arrival order. For prefix pool with hops [11] followed by [10], JS advertises [10], while its request for pool and Rust's advertisement selection choose [11]. Reversing arrival order changes JS's advertisement despite identical routes, so reconnects can churn the advertised winner and the new cross-language deterministic ordering is incomplete. Pass the prefix into advertisement sorting and apply the same hash before newest; add reversed-arrival tests for announced() and the publisher-facing advertised table, not only request winners.
  • Existing blocker, already identified in the author's update: terminal refusal is still not implemented in Rust. rs/moq-net/src/model/front.rs:342–349 reselects after a standing refusal, and rs/moq-net/src/model/origin.rs:3381–3394 can fall through to a shorter prefix once that tier is excluded. This contradicts the updated refusal contract (drafts/draft-lcurley-moq-lite.md:450–453), potentially probing sibling workers and the catch-all for one refused request. Resolve that decision and align implementation/tests with the chosen contract before treating the quest as complete; no duplicate inline finding added.

Direction: requested-path spreading and hidden service-claim discovery fit the stated goal, but advertisement parity and the acknowledged refusal gap remain.

Verification limits: connector-based static review; no builds, tests, benchmark timings, or interop runs executed by me. The six returned GitHub workflow runs for this SHA were queued when checked; the author's reported local passes are not independent verification.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop the NO_CAPACITY one-retry exception #4875 added to the lite and
cluster drafts, since this line removes NO_CAPACITY. Keep #4875's
excluded rename alongside the spread-hash tie-break.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Grok follow-up review of 1926714527bb037cde04a08f4585690274fd088c (re-review after push; previous review was on 99b3688d)

This push is two origin/main merges. Apart from conflict resolution, the PR's own +/- lines are identical to 99b3688d. The conflict resolution drops the "except for NO_CAPACITY's one re-resolution" clauses that #4875 added to draft-lcurley-moq-lite.md §Resolution, its changelog, and draft-lcurley-moq-cluster.md. That's consistent with this line removing NO_CAPACITY. Nothing in Rust or JS on this head still references it, so the drafts and the code agree that every refusal is terminal. The base also changed in ways that matter for the earlier findings.

Earlier findings

  • Fixed (via main): refusal terminality. fix(moq-net): a standing refusal ends the front #4875 is now in the branch. A standing refusal from the winning route ends the front (rs/moq-net/src/model/front.rs:345), the refused set became excluded (only source_closed fills it), and JS refuse ends the slot. Goal, Decisions, both drafts, and the code now agree. quest/m0/wildcard/refusal-final.md is gone, so nothing links to a dead quest.
  • Fixed: stale line reference. README now cites origin.rs:404 for Cost, which matches.
  • Still open (blocking): Required isn't empty. quest/m0/wildcard/README.md:208 still lists Transcoders start at group boundaries. fix(transcode): refuse a fetch that starts mid-group #4812 merged, but by its own description it's only the first step, and the quest stays open: the two-instance catalog check and the subscription-side resolve-to-(N+1, 0) wait on feat(net)!: negotiate publisher epochs as metadata #4817. The PR body still says this "stays a draft until the line's Required list is empty", yet the PR is marked ready. Fix: put it back in draft until feat(net)!: negotiate publisher epochs as metadata #4817 settles the quest, or make an explicit decision to drop or demote it from Required.
  • Still open (non-blocking), unchanged by this push: doc/bin/relay/cluster.md:97-98 still says "every relay picks the same one for a given path" (the lite draft's "on every relay that holds the same routes" is the accurate wording). Unroutable still isn't in the toStreamCode/fromTransport round-trip list in js/net/src/error.test.ts, and 0x36 isn't pinned next to the other 48–63 values (:238-243). JS compareCandidates (js/net/src/origin.ts:210) still has no spread-hash tie-break, though preferredEntry (:232) does.

New

  1. The README's "What already exists" now contradicts the merged code (quest/m0/wildcard/README.md:66-68): "A standing refusal does not yet end the front: since fix(net)!: resume route changes by reading the routes' copies; a path is one broadcast #4741 the front skips the refuser and re-selects…". After fix(moq-net): a standing refusal ends the front #4875 that's false. Fix: replace it with something like "A standing refusal from the winning route ends the front (fix(moq-net): a standing refusal ends the front #4875); only a route whose source ended while still advertised is excluded and re-selected."
  2. Dropping NO_CAPACITY also frees 0x30 and rewrites a released changelog. Published @moq/net 0.4.2 has StreamCode.NoCapacity = 0x30 and sends it from Dynamic/ServeState close, so peers on the wire can still emit it. This PR deletes the Rust "0x30 NO_CAPACITY … Do not reuse it" guard (rs/moq-net/src/error.rs:200, and the test comment at :686). It also edits the moq-lite-06 changelog entry to remove "Assigned 0x30 NO_CAPACITY" and to say "Every code is terminal". If a later change hands 0x30 to a different meaning, a 0.4.x JS peer's capacity refusal would decode as that new code. Fix: keep 0x30 reserved (keep the Rust comment, and add a line to the draft's stream error table or the IANA note saying it's reserved and not reassigned). Also leave the -06 entry as published and add a moq-lite-07 entry: "Removed 0x30 NO_CAPACITY and its re-resolution; every refusal is terminal." The same applies to the cluster draft's 0x40B5A registration.

CI is still pending on this head (Check, Test, Quest, and the platform jobs).

Verdict: ITERATE. The refusal contradiction is resolved now that #4875 is in. What's left is the open Required transcode quest (or an explicit call to drop it), plus the stale README sentence and keeping 0x30 reserved.

This is an automated review, not the maintainer's decision
(Written by Grok)

kixelated and others added 2 commits October 5, 2026 23:23
compareCandidates stopped at hop count, so an equal-cost pool's advertised
route depended on arrival order and could differ from rs/moq-net's
route_order. Break the tie on spreadHash(prefix, hops) like Rust does.

Also pin Unroutable in the JS error tables, scope the cluster doc's
convergence claim to relays holding the same routes, and record that a
standing refusal now ends the front (#4875).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

Grok follow-up review of 8d24696c050e6c32e17913b4c83dcf74bc939be9 (re-review after push; previous review was on 19267145)

This push is one real commit, dc8e5aab ("JS advertisement selection applies the spread hash"), plus an origin/main merge that touches none of this PR's files.

Earlier findings

  • Fixed: JS compareCandidates tie-break. js/net/src/origin.ts:213 now takes the prefix and, after route, local-first, and hop count, breaks ties on spreadHash(prefix, hops). Together with the stable sort's newest-first fallback, that matches Rust route_order (rs/moq-net/src/model/origin.rs:632: anonymous, cost, !local, hops, fnv_key, newest). The hash only runs on a tie, so the common single-route prefix pays nothing. The new test (origin.test.ts:1713) feeds the two pool members in both orders and checks the same one is advertised. That's the right regression test, because before this fix the advertisement followed arrival order.
  • Fixed: cluster.md overclaim. doc/bin/relay/cluster.md:97-98 now says "every relay that holds the same routes picks the same one".
  • Fixed: Unroutable test gaps. 0x36 is pinned in the spec-table test, and Unroutable is in both the round-trip list and the lite-only/IETF list in js/net/src/error.test.ts.
  • Fixed: stale README sentence. quest/m0/wildcard/README.md:66 now says a standing refusal ends the front (fix(moq-net): a standing refusal ends the front #4875).
  • Still open (blocking): Required isn't empty. quest/m0/wildcard/README.md:207 still lists Transcoders start at group boundaries. feat(net)!: negotiate publisher epochs as metadata #4817, which the rest of that quest waits on, is still an open draft. The PR body still says it "stays a draft until the line's Required list is empty", yet it's marked ready. Fix: move it back to draft, or make an explicit call to drop or demote that quest.
  • Still open (non-blocking): 0x30 isn't kept reserved. rs/moq-net/src/error.rs no longer has a "do not reuse 0x30" note. The moq-lite-06 changelog entry (drafts/draft-lcurley-moq-lite.md:1389) is still rewritten to say "Every code is terminal" instead of recording NO_CAPACITY's removal in the moq-lite-07 entry (:1359). Published @moq/net 0.4.x peers can still send 0x30, so a later reassignment would make them decode wrong. The same goes for the cluster draft's 0x40B5A.

No new issues in this push. CI is still pending on this head (Check, Test, Quest, WASM, and the platform jobs).

Verdict: ITERATE. Every code and test finding is now fixed. What's left is the open Required transcode quest (or an explicit decision to drop it), plus keeping 0x30 reserved in the drafts and the Rust comment.

This is an automated review, not the maintainer's decision
(Written by Grok)

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex adversarial review of 8d24696c050e6c32e17913b4c83dcf74bc939be9 (branch diff against origin/main)

Verdict: approve. No material findings.

Focus areas: spread-hash tie-break parity between route_order in rs/moq-net/src/model/origin.rs and compareCandidates/preferredEntry plus spreadHash in js/net; NO_CAPACITY removal across Rust, JS, and both drafts; js/watch counting hidden routes for rendition selection; lite and cluster draft text and the lite-07 changelog.

Codex reports that the hash matches across languages in byte order and overflow behavior, that JS now applies it when choosing the advertisement as well as when resolving a request, and that the refusal removal and hidden-route counting agree with the updated drafts. It reviewed statically and ran no tests.

This is an automated review, not the maintainer's decision.

(Written by Codex)

@kixelated

Copy link
Copy Markdown
Collaborator Author

Merged origin/main into the line again (through #4848), fixed the open review findings, and queued the merge.

Conflict resolutions

Review fixes (from the automated reviews of 99b3688)

  • JS advertisement selection now applies the spread hash. compareCandidates stopped at hop count, so the route a JS relay advertised for an equal-cost pool depended on arrival order and could differ from Rust's route_order. It now breaks the tie on spreadHash(prefix, hops). The regression test "an equal-cost pool advertises the same member whatever order it arrived in" fails without the fix.
  • StreamCode.Unroutable is pinned to 0x36 and added to the JS round-trip list and the lite-only list.
  • doc/bin/relay/cluster.md now limits the convergence claim to relays "that hold the same routes".
  • The README's "What already exists" no longer says a standing refusal re-selects. fix(moq-net): a standing refusal ends the front #4875 made it end the front.
  • The terminal-refusal blocker from those reviews was fixed on main by fix(moq-net): a standing refusal ends the front #4875.

Checks (on 8d24696)

  • just check origin/main passed: 5169 + 418 + 147 + 89 Rust tests, and all JS packages.
  • cargo test -p moq-net passed.
  • bun test passed in js/net (1216) and js/watch (292).
  • just drafts check passed.
  • quest check is ok.
  • just test interop --all: all 32 pairs and the browser close-code check passed.

Review: Codex adversarial review on this head approved with no findings. CodeRabbit was rate limited.

Still open: the line's Required child Transcoders start at group boundaries waits on #4817. The README stays on main with that child listed.

(Written by Claude Opus 5.5)

@kixelated
kixelated enabled auto-merge (squash) October 6, 2026 06:31

@kixelated kixelated left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated review by review (OpenAI)

Reviewed commit: 8d24696
Incremental review since 99b3688, accounting for merged main changes.

The prior advertisement-order finding is fixed: js/net/src/origin.ts:213–221 now hashes the advertised prefix, and :448–450 passes that prefix into candidate sorting. The reversed-arrival regression at js/net/src/origin.test.ts:1713–1725 checks the same winner. The earlier Rust refusal blocker is also resolved by the merged main implementation: rs/moq-net/src/model/front.rs:334–347 reselects only a withdrawn/superseded route and ends the request on a standing refusal. JS's corresponding refusal path checks supersession, including a winning local broadcast (origin.ts:514–525).

Direction: deterministic advertisement/request selection and terminal refusal now align with the stated routing contract. No new actionable defect found in the reviewed update. A publisher-facing advertised-table assertion would further protect the advertisement fix; the new regression currently asserts the consumer broadcasts view.

Verification limits: static review of the changed routing/error-contract code and relevant tests; no JS/Rust tests, benchmarks, or interop runs executed here. Returned head workflows include successful Release JS, Android and WASM runs, while Check/Platform/Audio quality remain queued; this is not an all-checks-passed assessment.

@kixelated
kixelated merged commit f79a047 into main Oct 6, 2026
11 checks passed
@kixelated
kixelated deleted the quest/m0/wildcard/README branch October 6, 2026 07:34
kixelated added a commit that referenced this pull request Oct 6, 2026
Resolves cluster-routing/README.md against #4946 (main's audit edits win,
the epoch wording stays). Also applies the audit decisions this PR owns:

- Delete quest/m0/wildcard/README.md and transcode-group-start.md: claim
  workers mint their own epoch, so they are never spliced, and #4403
  landed the rest of the line. Remove every link to either.
- m0 README: Wildcard landed in #4403.
- hop-removal: drop the NO_CAPACITY bullet (#4403 removed it), and `moq`
  mints the epoch when --epoch is omitted.
- cluster-routing/selection: identity is path plus epoch.
- stats-split: relate the QoS line (#4133 rebases onto its tracks).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated added a commit that referenced this pull request Oct 7, 2026
…r failover

The ranking, path-keyed rendezvous hash, epoch identity, and upstream
spread already landed (#4403, #4741, #4816, #4942). What was left were
tests: the equal-cost pool test now also proves losing an advertiser
moves only its paths, and route_change covers a redundant pair (two
publishers under one explicit epoch) failing over mid-group, whether the
incumbent becomes unreachable or ends, with no timestamp rewind.

Deletes the finished quest and moves its ranking guidance into Routes
and announces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant