diff --git a/quest/m2/cluster-routing/routes/stale-copies.md b/quest/m1/route-stale-copies.md similarity index 98% rename from quest/m2/cluster-routing/routes/stale-copies.md rename to quest/m1/route-stale-copies.md index d3c6356fea..f035afce3a 100644 --- a/quest/m2/cluster-routing/routes/stale-copies.md +++ b/quest/m1/route-stale-copies.md @@ -27,7 +27,9 @@ wire, and the draft do not change here. Decided 2026-11-11 (maintainer, /quest-plan after #8487's two adversarial reviews, revised the same day once the first plan's rule was tried on the -router). +router). Moved here from the routes epic the same day (maintainer): the epic +and m2 wait on m1 quests this needs nothing from, it changes tests only, and +the m1 model quests wait on its outcome. Why: today a relay believes a neighbour's copy of a publisher's claims only while that neighbour is "feasible", which means strictly cheaper than the diff --git a/quest/m2/cache-routing-proof.md b/quest/m2/cache-routing-proof.md index a864b4ee6e..985f83a9d4 100644 --- a/quest/m2/cache-routing-proof.md +++ b/quest/m2/cache-routing-proof.md @@ -30,7 +30,7 @@ second trip to the maintainer for choosing lite-07. Reopened 2026-11-11 (maintainer, /quest-plan on the route redesign, epic Plan item 8): a warm route propagates, and the rule that keeps it free of loops and stale copies is -[the prototype](/quest/m2/cluster-routing/routes/stale-copies.md)'s to pick. +[the prototype](/quest/m1/route-stale-copies.md)'s to pick. The eligibility rule and the fixtures below are for the one-hop warm route first decided, which [moq-dev/moq#8457](https://github.com/moq-dev/moq/pull/8457) proves. Once the prototype's pick is recorded, rewrite both for it: the @@ -82,7 +82,7 @@ extension and record the choice and its reason in the epic's Plan. ## Required -- [A prototype settles what keeps a route free of stale copies](/quest/m2/cluster-routing/routes/stale-copies.md) - the rule a propagating warm route rests on, which replaces the one this proved +- [A prototype settles what keeps a route free of stale copies](/quest/m1/route-stale-copies.md) - the rule a propagating warm route rests on, which replaces the one this proved ## Related diff --git a/quest/m2/cluster-routing/README.md b/quest/m2/cluster-routing/README.md index 8704e22e12..220d37e7d7 100644 --- a/quest/m2/cluster-routing/README.md +++ b/quest/m2/cluster-routing/README.md @@ -40,7 +40,7 @@ Decided with the maintainer, 2026-10-13: Reopened 2026-11-11 (maintainer, /quest-plan after [moq-dev/moq#8487](https://github.com/moq-dev/moq/pull/8487)'s reviews): whether Babel's distance stays is - [the prototype](/quest/m2/cluster-routing/routes/stale-copies.md)'s to + [the prototype](/quest/m1/route-stale-copies.md)'s to measure, against paths alone with a withdrawal that names the hop that died. The distance refuses a longer way round until the publisher advances its seqno, and refuses a cached copy at a neighbour no closer to the diff --git a/quest/m2/cluster-routing/routes/README.md b/quest/m2/cluster-routing/routes/README.md index 3d61c5e772..39e54ae09d 100644 --- a/quest/m2/cluster-routing/routes/README.md +++ b/quest/m2/cluster-routing/routes/README.md @@ -43,7 +43,7 @@ The items below were decided 2026-11-10 (maintainer, /quest-plan on lite-07 rout 25. ✅ Asked how a relay safely forgets a publisher that is gone, after the model showed a per-neighbour echo is not enough once the origin sits behind a relay: **each route names the nodes it crossed, and a node never uses a route that names itself** ([moq-dev/moq#8487](https://github.com/moq-dev/moq/pull/8487), which holds the counterexamples and the model results). Feasibility still selects routes; the list is one per origin route, not the per-claim Hop ID list item 6 removed, and the echo and the drain rule stay as they are. As built: Babel's feasibility condition is unchanged, and a node never selects or certifies through such a route. Where the condition refuses it, it still counts as infeasible, so a relay whose neighbours all route through it holds its claims while one of them finds another way. Under a qualified key it counts only while its hops extend those of the route the node last sent under that key: a copy that a scoped peer hands back under a key derived from the node's own route never moves, so nothing waits on it. The origin names itself too, so a rotated identity's route is refused where it began, and a node names itself by a Hop ID that a rotation leaves alone. The hop limit is the wire's 32 and no lower. A change of hops or RTT alone lets go of no region, unless it changes whether the node may use the route: by crossing it, or by reaching the hop limit. This supersedes the claim, in the handoff contract and in decision 6 below, that the echo alone makes forgetting safe. First decided as a relay echoing a ROUTE_END only once its own downstream had; the model ran that the same day and it fails when a session closes before answering. Rejected: that deferred echo; never dropping the distance; a timer; relays as the only origin nodes. -26. ✅ Decided 2026-11-11 (maintainer, /quest-plan after [moq-dev/moq#8487](https://github.com/moq-dev/moq/pull/8487)'s reviews), asked whose copy of a publisher's claims a relay believes: **a route is shared per publisher and per scope, and a relay believes a route by that route's own path** ([the prototype](/quest/m2/cluster-routing/routes/stale-copies.md), [the model](/quest/m2/cluster-routing/routes/scope-model.md), then [the router](/quest/m2/cluster-routing/routes/scope.md)). A scope is the prefix a relay asked a neighbour for when its grant there is narrower than its interest. Today only a feasible neighbour counts, one strictly cheaper than the distance the relay remembers, so a relay's claims move whenever a cost or seqno does: it can forget a claim for good, a mesh with two grants never settles after one seqno advance, and behind a scoped neighbour it never shows what a farther one knows. Only a broadcast some relay carries gets its own route, and that route propagates ([cache-aware routing](/quest/m3/cache-routing/README.md) Plan item 8). Open, for the prototype to measure and the maintainer to pick: whether Babel's distance or the path alone, with a withdrawal that names the hop that died, keeps a route free of loops and stale copies. The contract's bullet on which neighbours certify stands until the model quest rewrites it. First decided the same day as any neighbour whose path to the publisher does not pass through the relay; tried on the router, two relays behind a scoped relay then keep a dead claim alive through each other, and the relay behind a scoped neighbour shows a claim it has no route to request. Rejected: that rule; believing a neighbour that is cheaper than the relay is now, which fixed the storm and the forgotten claim with no wire change but rests belief on distance; a path per broadcast as lite-06 has; link-state among relays; routes to relays. +26. ✅ Decided 2026-11-11 (maintainer, /quest-plan after [moq-dev/moq#8487](https://github.com/moq-dev/moq/pull/8487)'s reviews), asked whose copy of a publisher's claims a relay believes: **a route is shared per publisher and per scope, and a relay believes a route by that route's own path** ([the prototype](/quest/m1/route-stale-copies.md), [the model](/quest/m2/cluster-routing/routes/scope-model.md), then [the router](/quest/m2/cluster-routing/routes/scope.md)). A scope is the prefix a relay asked a neighbour for when its grant there is narrower than its interest. Today only a feasible neighbour counts, one strictly cheaper than the distance the relay remembers, so a relay's claims move whenever a cost or seqno does: it can forget a claim for good, a mesh with two grants never settles after one seqno advance, and behind a scoped neighbour it never shows what a farther one knows. Only a broadcast some relay carries gets its own route, and that route propagates ([cache-aware routing](/quest/m3/cache-routing/README.md) Plan item 8). Open, for the prototype to measure and the maintainer to pick: whether Babel's distance or the path alone, with a withdrawal that names the hop that died, keeps a route free of loops and stale copies. The contract's bullet on which neighbours certify stands until the model quest rewrites it. First decided the same day as any neighbour whose path to the publisher does not pass through the relay; tried on the router, two relays behind a scoped relay then keep a dead claim alive through each other, and the relay behind a scoped neighbour shows a claim it has no route to request. Rejected: that rule; believing a neighbour that is cheaper than the relay is now, which fixed the storm and the forgotten claim with no wire change but rests belief on distance; a path per broadcast as lite-06 has; link-state among relays; routes to relays. The route layer's core landed in [moq-dev/moq#7676](https://github.com/moq-dev/moq/pull/7676): a diff --git a/quest/m2/cluster-routing/routes/scope-model.md b/quest/m2/cluster-routing/routes/scope-model.md index 31f70e0165..8fe1a8d5d6 100644 --- a/quest/m2/cluster-routing/routes/scope-model.md +++ b/quest/m2/cluster-routing/routes/scope-model.md @@ -8,8 +8,10 @@ the prefix it covers, carries its own path, and is believed by a relay it did not cross. TLC shows on it: - A relay shows a claim exactly while it holds a route that covers the claim - and did not cross the relay, and the newest revision the relay knows still - has the claim. It shows the claim as it is at that revision. + and did not cross the relay, and the newest revision any covering route gave + it still has the claim. It shows the claim as it is at that revision. A + newer revision from a route that does not cover the claim says nothing + about it. - Once nothing is in flight, no relay shows a claim that no path from its publisher carries. - A change of path or seqno alone starts, ends, and changes no claim a reader @@ -20,7 +22,7 @@ not cross. TLC shows on it: offers. The model uses the rule -[the prototype](/quest/m2/cluster-routing/routes/stale-copies.md) picked for +[the prototype](/quest/m1/route-stale-copies.md) picked for keeping a route free of stale copies. The rule this settles is written into the epic's contract for [the router](/quest/m2/cluster-routing/routes/scope.md) to implement. The @@ -29,7 +31,7 @@ router's behaviour, the wire, and the draft do not change here. ## Plan Decided 2026-11-11 (maintainer, /quest-plan). The decisions and what was -tried are in [the prototype](/quest/m2/cluster-routing/routes/stale-copies.md)'s +tried are in [the prototype](/quest/m1/route-stale-copies.md)'s Plan and the [epic](/quest/m2/cluster-routing/routes/README.md)'s Plan item 26. @@ -92,7 +94,7 @@ Public API: none. Wire: none. ## Required -- [A prototype settles what keeps a route free of stale copies](/quest/m2/cluster-routing/routes/stale-copies.md) - the rule for loops and stale copies that this model is written on +- [A prototype settles what keeps a route free of stale copies](/quest/m1/route-stale-copies.md) - the rule for loops and stale copies that this model is written on ## Related diff --git a/quest/m2/cluster-routing/routes/scope.md b/quest/m2/cluster-routing/routes/scope.md index 97280cf01a..5cdd4c56e6 100644 --- a/quest/m2/cluster-routing/routes/scope.md +++ b/quest/m2/cluster-routing/routes/scope.md @@ -5,12 +5,12 @@ `route::Router` keys a route by its publisher and the prefix it covers, and believes a route that did not cross it, as [the model](/quest/m2/cluster-routing/routes/scope-model.md) settled. A relay -shows a claim exactly while such a route covers it and the newest revision -the relay knows still has the claim, two relays never keep a +shows a claim exactly while such a route covers it and the newest revision a +covering route gave it still has the claim, two relays never keep a dead route alive through each other, a change of path or seqno alone changes no claim a reader sees, and a relay behind a scoped neighbour reaches what a farther one offers. The `residual_` tests -[the prototype](/quest/m2/cluster-routing/routes/stale-copies.md) pinned pass +[the prototype](/quest/m1/route-stale-copies.md) pinned pass as plain tests, a sweep over meshes with scoped relays holds the rules at every quiet point, and the draft and the epic's contract say what the router does. diff --git a/quest/m3/cache-routing/README.md b/quest/m3/cache-routing/README.md index c8baa12eeb..20e34f08aa 100644 --- a/quest/m3/cache-routing/README.md +++ b/quest/m3/cache-routing/README.md @@ -87,7 +87,7 @@ Decided 2026-11-08 (maintainer, /quest-plan): join a copy at a neighbour that is no closer to the publisher: the join the Goal wants, and why item 2 stopped at one hop. What keeps a warm route free of loops and stale copies is - [the prototype](/quest/m2/cluster-routing/routes/stale-copies.md)'s to + [the prototype](/quest/m1/route-stale-copies.md)'s to measure, and the proof then holds that rule. Items 1 and 3 stand. [moq-dev/moq#8457](https://github.com/moq-dev/moq/pull/8457) proves items 2 and 4 as first decided. diff --git a/quest/m3/route-keep-next-hop.md b/quest/m3/route-keep-next-hop.md index 2c5c312070..29e004f267 100644 --- a/quest/m3/route-keep-next-hop.md +++ b/quest/m3/route-keep-next-hop.md @@ -39,7 +39,7 @@ selection. down-only route still moves to an equal one it may export, and test that. - Check that every router test that names the next hop it expects still means what it says, rather than editing expectations to match. -- [The prototype](/quest/m2/cluster-routing/routes/stale-copies.md) may +- [The prototype](/quest/m1/route-stale-copies.md) may replace how a route is selected. If it has, apply this to the rule that stands. - Measure with `Sim`'s `hop_updates` count and, if it has landed,