Repository navigation
feat(net)!: prove cache-aware routing settles under fresh seeds - #8732
Conversation
Quest-Claim: 91b52f31b950853f
Rebuild the cache-routing proof on route::path::Router and settle every scenario of the long sweep under 12 seeds (72,000 scenarios): - Offers do not depend on demand: a carrier offers its copy at no cost, and a relay with no reader offers each neighbour its best source whose hops name neither relay. - A carrier pulls its best source among its route and lower-ranked carriers' copies, whoever pulls from it. A relay with no reader pulls what it offered each neighbour it serves, or a lower-ranked carrier's copy, else its route. - A lingering pull runs out on IDLE_LINGER's timer even while busy. Lite-07: WARM_START and WARM_UPDATE carry Flags (draining) and a priority, with the carrier as the first hop, in place of Carrier Index. SUBSCRIBE and SUBSCRIBE_UPDATE end with a Warm byte. The Rust and js/net codecs match. The long sweep runs nightly from test/route-sweep.sh. Delete the paths.rs prototype and the completed quest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 20 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
# Conflicts: # drafts/draft-lcurley-moq-lite.md # quest/m3/cache-routing/select.md # rs/moq-net/src/lite/announce.rs
There was a problem hiding this comment.
ℹ️ No critical issues. Two small things inline, plus one tradeoff for the maintainer to decide.
Reviewed changes
I read the full diff at 4866726: the lite-07 wire reshaping in the draft, the Rust and JS codecs, the rebuilt cache.rs proof, and the nightly and quest wiring. paths.rs is a pure deletion, and nothing still references it.
- Warm route wire:
WARM_START/WARM_UPDATEreplaceCarrier IndexwithFlags (8)andPriority (8), and Hops now run carrier-first. The Rustencode_warm/decode_warmand the byte-exact layout test agree with the draft. Warmbyte on SUBSCRIBE and SUBSCRIBE_UPDATE: Rust andjs/netboth write 0, check that a received value is ≤1 and otherwise ignore it, and gate the byte onhas_warm/hasWarm. No other in-repo encoder of lite SUBSCRIBE needs updating, becausemoq-ffigoes through Rust.- Draft Warm Routes section: offers no longer depend on pulls, and pulls follow a three-layer rule. The ranking (drain, then priority, then cost, then warm, then the lower carrier hash) matches
Mesh::pick/best/decide. - Proof sim:
Meshnow runs onpath::Routerdirectly. Lingers run out on a timer, andsteadychecks the distributed offers againstfixed_point. - Nightly:
test/route-sweep.shrunssweep_cache_routing_longat 3000 cases under thesweepprofile, from the script's freshMOQ_ROUTE_SEED.
ℹ️ Transient cycles are now much more frequent, and most of them starve a reader
The maintainer accepted transient loops on 2026-11-13 at #8615's measured rate: 0.39% of churn steps, gone within 53 deliveries. This rule produces a cycle after 3.3% of churn steps (about 8× as often), each lasting up to 142 deliveries, and about 9 in 10 of those steps leave some reader unfed. The PR says the sweeps aren't directly comparable and that nobody dug into the difference. That is fair, but approving the move to the new rule also accepts these numbers, so the maintainer should decide it explicitly rather than assume it falls under the earlier acceptance.
Technical details
# Transient-cycle cost of item 14's rule vs #8615's
## Affected sites
- rs/moq-net/src/route/tests/cache.rs `sweep` — reports `loops`, `steps`, `looped`, `starved`, `longest`
- quest/m3/cache-routing/README.md item 14 — records 3.3% / 142 deliveries
## Required outcome
- Either an explicit maintainer acceptance of the higher transient rate and starvation, or a comparison that attributes the increase (e.g. run #8615's sweep config, with no per-link priorities, against this rule) so the follow-up is scoped.
## Open questions for the human
- Is ~3% of churn steps with a reader starved until the crossing message arrives acceptable for the implementation quest (`quest/m3/cache-routing/select.md`), or should a follow-up quest own reducing it?claude-opus-5-5 | 𝕏
There was a problem hiding this comment.
ℹ️ The merge resolution introduces no new issues. The two inline notes from the previous review are still open, since this push doesn't touch either line.
Reviewed changes
Since 4866726, the only new commit merges origin/main. Its conflict resolution adapts this PR's warm route codec to #8672's Refused Content.
- Warm route refusals:
decode_warmnow returnsContent<Warm>. An unknown flag, 0 hops, or more than 32 hops is refused withRefusal::Flags,Refusal::Carrier, orRefusal::Hops, and the rest of the body is skipped. Before, each of these was aDecodeError. Each refusal fires before a later field is read, so skipping the rest of the body cannot desync the stream. Refusal::Carrier: this variant replaces main's "carrier not among its hops" case, which no longer exists because the carrier is now the first hop. Its message now reads "a warm route with no hops, so no carrier".- Draft: the Refused Content field list names the warm route's
Flagsinstead ofCarrier Index. The WARM_START field rules say "refused" instead of PROTOCOL_VIOLATION, which matches the Rust decoder. - Test:
lite07_warm_route_hops_and_flags_are_boundednow assertsAnnounceBroadcast::Refused { message: Refusable::WarmUpdate { id: 7 }, .. }for each case. Its byte vectors match the new layout, including the 32-hop boundary. - Quest links: the merge carried the removed
cache-routing-proof.mdlink intoquest/m3/route-trace-validation.md, where main moved that file. Nothing in the repo still referencescache-routing-proof.mdorpaths.rs.
claude-opus-5-5 | 𝕏
Address Pullfrog's review: the draft now says which reading the model takes, and the test inventory drops a header with nothing left under it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # sh/gh/test-inventory.allow
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Since 6f5d756, one new commit addresses both prior review threads.
- Draft pull rule: the Warm Routes text now bounds a relay's pull only by neighbours it offered a warm route, and says a neighbour it offered none (e.g. one whose SUBSCRIBE crossed a WARM_END) bounds nothing. This matches the sim's
decide. - Test inventory allowlist: the
# Too slow for the merge gate…comment is now attached to thesweep_cache_routing_longentry, and thestream-creditentry has its own comment.
claude-sonnet-5-5 | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Since 18f7e4c, the only new commit merges origin/main (8088d55). It doesn't change the routing rule, the sim, either codec, or the draft.
- Merged
maininto the branch:mainhad already dropped thestream-creditentry fromsh/gh/test-inventory.allow, so this PR's change to that file now only removes thesweep_cache_routing_longblock. Nothing in the repo still referencescache-routing-proof.mdorpaths.rs.
claude-opus-5-5 | 𝕏
#8732 rewrote the warm-route ranking and the cache sweep on the path router: the draft takes its Warm Routes text and the Route Offer refusal list keeps this branch's, the sweep originates without a seqno, and the verify-route skill points at its sweep. switch.md stays deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Completes quest/m2/cache-routing-proof.md: cache-aware routing's warm routes now settle under every fresh seed tried. The proof is rebuilt on the real
route::path::Routerfrom moq-dev/moq#8622, thepaths.rsprototype is deleted, the long sweep runs nightly, and lite-07's warm fields carry the new rule. The quest file is deleted; the epic's item 14 records the rule.What changed
rs/moq-net/src/route/tests/cache.rs), in three layers that each settle before the next depends on them:path::Router's, which copies never change.steady()checks the distributed offers against a fixed point computed centrally.Warmbyte says whether a pull joins the copy offered or follows the route, and a relay pulled along its route follows its own.path::Routerwith per-link priorities and drains, two publishers, and six relays.track::IDLE_LINGER), even while the mesh is busy.Sim::now()was added.a_pull_along_the_route_stays_on_the_routeanda_copy_ranks_by_priority_before_cost. The unranked pair inequal_relays_pull_one_copy_owned_by_the_lower_hashnow settles into a cycle that feeds neither, which shows why the rank is needed.0x1marks a draining copy), a priority (i8), and the Hops, carrier first and sender last. These replace theCarrier Index.Warmbyte (0 = follow the route, 1 = join the copy offered; above 1 is a violation).lite/announce.rs,lite/subscribe.rs) andjs/net(lite/subscribe.ts,lite/version.ts) match. Both sendWarm= 0 and ignore it when read, until the implementation.test/route-sweep.shrunssweep_cache_routing_longfrom its freshMOQ_ROUTE_SEED, and its line insh/gh/test-inventory.allowis gone.select.mdpoints at item 14.verify-route's skill no longer namespaths.rs.Validation
MOQ_ROUTE_SEED= 3401901550, 305419896, 1 to 8, 1777, 2026111401): 72,000 scenarios, 3000 each with and without held links per seed, all settle. That covers every seed that failed under feat(net)!: prove propagating warm routes on paths, and carry their hops, cost, and carrier in moq-lite-07 #8615's rules, and every scenario this rule failed while I was developing it. Each failure was traced by hand from the sweep's dump and delivery trace before its rule changed. Settled means: each reader is fed, subscriptions and offers match their senders, the distributed offers equal the fixed point computed centrally, no pull lingers, and nothing changes on a further tick.quest gate cargo nextest run -p moq-net --lib -E 'test(/route::tests::cache/)': 15 passed, including the gate sweep (100 scenarios with held links and 100 without).lite07_warm_route_layout(byte for byte),lite07_warm_route_hops_and_flags_are_bounded, andwarm_trails_subscribe_only_on_lite07;js/net'ssubscribe.test.ts.quest gate just checkpasses, before and after mergingmain(13,142 Rust tests after), plusjs/net's tests, drafts, and quest checks.quest gate just test interop --allpasses on both, Rust, JS, and Python onmoq-lite-07-wipincluded.just fixchanged nothing in this diff; its biome step failed while installingjs/libav(the Nix daemon disconnected), so I ran biome on the three changed JS files directly: no fixes.Decisions
All taken by the agent under /quest-afk, for the maintainer's review:
track::IDLE_LINGER(30 s) on a timer, and the pulls around it may move until that runs out. A lingering pull can hold a copy its parent promised another neighbour; all the scenarios still unsettled after the rules above (4 in 48,000) were such a pull and its neighbours flipping.settlestops counting busy rounds while a linger is pending, for up to four lingers, so "settled" means once demand, lingers included, stops changing. Rejected: expiring lingers only once the mesh is quiet, which reported those 4 as never settling; dropping a pull with no demand at once, which throws away the linger's purpose (a reader that comes back finds the copy warm); a rule that moves a lingering pull, since it has no demand to rank sources by.path::Router, andpaths.rsis deleted. Rejected: keeping the prototype beside the router that ships.Carrier Index; ranking copies by cost alone, which ignores what a route's own rank already says.Warmon both SUBSCRIBE and SUBSCRIBE_UPDATE. Rejected: inferring it from the offer, which a crossing WARM_UPDATE makes ambiguous; carrying it on SUBSCRIBE only, which forces a new stream to switch between the copy and the route.RouteHandoff.tla, which the quest suggested only while scenarios still failed.Public API and wire impact
No public API change: the codec lives in the private
litemodule.Wire: moq-lite-07 only, which is unpublished (
moq-lite-07-wip). WARM_START and WARM_UPDATE replaceCarrier Indexwith a Flags byte and a priority, and SUBSCRIBE and SUBSCRIBE_UPDATE gain a trailingWarmbyte. Migration: peers on an earliermoq-lite-07-wipbuild ofmainmust upgrade together. Thereleasebranch carries none of these fields.Caused by
Not a bug fix: moq-dev/moq#8615 left scenarios under fresh seeds that never settled, and moq-dev/moq#8622 landed the router to build the proof on.
Follow-ups
Warmbyte.Models
Size: L
Implementer: Claude Code, claude-opus-5-5, unknown effort
(Written by Claude Opus 5.5)
🤖 Generated with Claude Code
Review
Rewritten by
quest reviewafter each round.Head: a7ce45d
Base: origin/main at 8088d55
Reviewer: Codex, gpt-6.1-sol, xhigh effort
Session:
01a1d65d-060c-7f70-9cdb-787a0d3dc76f, round 4Score: 10/10,
The draft clarification matches the existing routing model, and the merge introduces no actionable regressions; builds, tests, and model checks were not run as instructed.Rounds: 5; findings 0: fixed 0, refuted 0, open 0
Findings: none