Repository navigation
Conversation
Quest-Claim: d0a47146843f5368
A relay dropped its copy the moment the upstream finished the track: a FETCH in flight was cancelled, and a later fetch of a group below the end found the copy closed and waited out the subscriber's budget. The copy now keeps answering fetches while it is read, and only fetches: a reader's miss still settles at once, as the subscription's tail already accounted for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A fetch-only handler gets its own counter and a unit test. The verify-failover skill and the quest now describe only the remaining EndedRelay case, which the real stack replays as a hang. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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 41 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. |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
I reviewed the full diff at c2d0679. It keeps a relay's finished copy serving fetch_group fills, adds fetch-only Requests, adds kio::Tasks::retain, and updates the failover tests and quest docs.
- Finished copy keeps serving fetches: on
ServeEnd::Finishedwith FETCH support,TrackServeRunnow holds aFinishedServe. It keeps only the fetchFillServeRuns and takes new fetches throughRequests::fetches_only(). It is released once nobody reads the copy and no fetch is in flight, or when the session closes. - Fetch-only fill handlers:
FillStatecountsfetchersseparately fromhandlers, and a fill records whether a fetch asked for or joined it. A fetch queues whentakes_fetches()is true. A reader's miss, a lookup and a flight still need a full handler, so they settle through the tail as before. - Revocation covers the finished copy:
revoke_finishedaborts the copy withUnauthorized.poll_runchecks the denial duringEndingandFinishwhile a finished copy exists, andrevoke()callsrevoke_finishedin the other states. kio::Tasks::retain: a public method that cancels rejected tasks and frees their slots the same wayremovedoes.- Tests and docs: the two residual tests now assert delivery, a test checks a fetch after release, and
residual_a_fetch_cannot_move_off_a_dying_route_after_the_endpins the remainingEndedRelay.cfghang. The quest is narrowed to that case.
I checked these edge cases and none is a problem:
- Polling
Doneagain: once a request is admitted,Gate::poll_readystays ready, so pollingpoll_runagain inDoneis safe. - No busy loop:
Demand::wantedandwrite_unwantedread the same consumer count, so theabort_unwantedretry inFinishedServe::pollcannot spin. - Fetches use FETCH:
fetch_groupalways asks for one group, so its fills become FETCH runs rather than lite-07range_fills, which the finish drops.
claude-opus-5-5 | 𝕏

Works on quest/m1/failover-fetch-residuals.md.
Summary
A relay's copy of a track used to drop its serving loop once a lite upstream finished the track. That cancelled FETCHes already in flight and closed the copy, so a reader's
fetch_groupfor an unfinished group below the end either failed or waited out the subscriber's budget.FailoverChain.tlaalready rules both out.Now a finished copy keeps a fetch-only handler (
FinishedServeinlite/subscriber.rs). It still servesConsumer::fetch_groupfills and keeps FETCHes in flight. It is released once nobody reads it and no fetch is in flight. Readers' misses still settle through the subscription's tail.track::Requestscan be fetch-only.FillStatecounts fetchers apart from handlers, and a fill remembers whether a fetch asked or joined it.kio::Tasks::retaincancels the tasks a predicate rejects. The finish uses it to keep only fetch runs.ending_the_track_keeps_a_fetch_in_flightanda_fetch_from_a_completed_copy_goes_on_the_wire. A third test checks a fetch made after the finished copies are released (a_fetch_after_the_finished_copies_linger_goes_on_the_wire).EndedRelay.cfg's mesh finding is replayed on the real stack asresidual_a_fetch_cannot_move_off_a_dying_route_after_the_end, which pins the hang. The quest is narrowed to that case.Decisions
Taken while the user was away; each can be undone in review.
SwitchandAbortchanges inFailoverChain.tla. That is a front redesign on its own, and feat(route): a dual-homed publisher's other links survive doubt about it #8734 is reworking route code in parallel. The quest file now describes only this remaining work.subscribe_ranges::a_relay_with_holes) and stretched drop settlement (drop_record).drop_record's settle budget.TrackServeRun, not aTrackRunStatephase. It runs alongside the subscription's Ending, Finish, and Done phases. Revoking the grant now ends it in any of them (a_revoked_grant_ends_a_finished_copy_awaiting_its_fin, from review round 1).kio::Tasks::retainis added as a public method on kio, rather than draining and rebuilding the set.Validation
just testfor moq-net (with--features async) and kio: 4203 passed, clippy clean. New unit tests area_fetch_only_handler_takes_fetches_aloneandretain_cancels_only_the_rejected.quest gate just checkpasses. After review:cargo nextest run -p moq-net --features async3994 passed.FailoverChain.cfgpasses (1,961,020 distinct states) andLeave.cfgpasses (2,162,238).EndedRelay.cfgstill breaksNoSkipWhileHeldat depth 31, as pinned.ResumeReader.tlapasses on its default cfg (14,334,670) and onThreeRoutes.cfg(7,053,230).Public API
No breaking change.
kio::Tasks::retainis a public addition. In moq-net, the fetch-onlyRequestsandFill::is_fetcharepub(crate).Wire
None.
Caused by
No single PR. The finished branch dropped the serving loop from the start, and FETCH-after-end was never served.
Follow-ups
Models
Size: M
Implementer: Claude, claude-opus-5-5, unknown effort (arm A)
(Written by Claude Opus 5.5)
🤖 Generated with Claude Code
Review
Rewritten by
quest reviewafter each round.Head: c2d0679
Base: origin/main at 505a86f
Risk: high,
This change governs authorization during finished-copy FETCH serving, where a regression could expose data after permission ends and reverting cannot retract delivered data.Classified: medium by default
Reviewer: Codex, gpt-6.1-sol, high effort
Session:
01a1df84-139d-7382-a698-9a3b2f97c3d6, round 2Score: 10/10,
Code inspection confirms the revocation fix addresses the earlier finding without introducing new issues; builds and tests were not run, as instructed.Raised the risk to high:
This change governs authorization during finished-copy FETCH serving, where a regression could expose data after permission ends and reverting cannot retract delivered data.Rounds: 2; first round 1 (medium 1); findings 1 (medium 1): fixed 1, refuted 0, open 0
Findings: none
The last round's findings, at 65e1c0c:
rs/moq-net/src/lite/subscriber.rs:12335:Model finished-copy serving within TrackRunState;subscriber.rs:12745 checks authorization while a finished copy exists, including Ending and Finish, and revoke_finished at line 12665 removes the copy and drops its FETCH runs while preserving FIN handling.