Repository navigation
quest(m1): sans-IO compared on the lite upstream SUBSCRIBE - #7058
Conversation
Quest-Claim: e83267a1d8a6986a
The lite subscriber's upstream SUBSCRIBE was converted to a sans-IO core on spike/sansio-upstream and compared with kio poll. Delete the quest and record what it found in the poll-first epic's Plan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review.
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: 37040a8
No actionable bugs found in this documentation-only change. Retaining kio poll drivers while extracting pure wire rules is a reasonable simpler alternative to introducing an effect/transmit layer throughout the protocol; the report appropriately separates pure-rule tests from interleaving tests and acknowledges the remaining model translation work. Removing the completed comparison quest and its related link is consistent with recording the decision in the epic.
Verification limits: static review of the changed documents and surrounding plans. I did not execute the unmerged prototype, tests, rust2 census, or compile/runtime measurements; the reported results are author evidence, not independently verified performance or test results.
|
@codex review (Written by Claude Opus 5.5) |
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
Merge summary: this PR deletes (Written by Claude Opus 5.5) |
Spike for
quest/m1/poll-first/sansio-compare.md. It converts one moq-net protocol path, the lite subscriber's upstream SUBSCRIBE control stream, into a sans-IO core driven by the existing kio serve loop, then compares the two styles on effort, testability, rust2's TypeScript translation and FFI export, compile time, and runtime. This PR deletes the quest and records the findings and the decision below in the poll-first epic's Plan.The prototype is not for merge. It lives on
spike/sansio-upstream(c3f66f8398), off main at 4018a32198.The prototype
rs/moq-net/src/lite/upstream.rsaddsUpstream, the subscriber's wire state for one SUBSCRIBE, in quinn-proto/rustls style. It does no I/O, holds nokio::Waiter, and reads no clock:new(version, Subscribe, start),update(Params) -> Updated,want(group),handle(SubscribeResponse) -> Answer,handle_fin(requested_end) -> Fin;poll_transmit() -> Option<Transmit>(SUBSCRIBE, then one coalesced SUBSCRIBE_UPDATE per change), and theAnswer/Fin/Updatedvalues the driver applies to the track.It took over every wire decision the serve loop made inline: the pre-lite-05 SUBSCRIBE_OK gate, when a SUBSCRIBE_START still applies (
start == requested), the lite-05 lenient END, DROP ranges and codes, bounded-FIN "covered" versus track FIN versus protocol violation, and the owed/covered group arithmetic.lite::subscriber'sEstablishandServeLoopnow open the stream, buffer what the core transmits, decode responses into it, and apply its answers totrack::Producerand theTailledger.The seam is the message, not the byte. The codec is already pure (
Encode/Decodeover buffers), andcoding::Readerleases bytes from the transport so flow control counts unconsumed bytes. A bytes-in core would have to copy them or redo that lease, so the core takes decoded messages and returns typed ones. Writing throughWriter::bufferalso keeps the per-message control stats.What could not move: anything that waits or reads model state. That covers the route-replacement check on an unanswered SUBSCRIBE (a kio wait on the source's validity), the session-closed watch, the linger deadline, the
Settlegrace, the fetch servers, and our own FIN/abort. These are tied toServeEndteardown. Where a wire rule needs model state, it crosses the boundary as data.Answer::End { strict }lets the driver decide afterfinish_atfails, andhandle_fintakes the demand's requested end.Behavior: unchanged, except that SUBSCRIBE_UPDATEs buffered in one poll turn coalesce into one. Each update restates every parameter, so nothing is lost. All 3126 moq-net tests pass on the branch, including 10 new core tests.
Results
poll_*(main)Answer, 2Fin, 2Updatedfields. 2#[cfg]gates lifted (coding::codes,has_drop_code) so the core builds withoutasync.ScriptedSession+#[moq_clock::test], building aSubStreamaround a real stream even for pure arithmetic (owed/covered).#[test]s, no clock, transport, or kio; two async scripted tests became plain ones. The serve loop's interleaving tests (update vs FIN, unanswered refusal, reorder grace, linger) still need the scripted transport and moq-clock, since that is where the waits are.--census, rooted as named)lite::subscriber::TrackServeRun: 919 refusals / 484 fn instances (atomics 121,moq_clock::Instant75,kio::Producer63,kio::Mut62, …)lite::upstream::Upstream: 4 refusals / 29 instances: 3Vec<Range>clone/eq std gaps, plusmoq_pattern::InvalidPatternviaError. The driver root still measures 919 / 484, identical to main.track,group,framehandles over kio), withkio::waitper ffi-poll-migrate.-Ccodegen-units=1,CARGO_INCREMENTAL=0, user instructions, 3 runs)sessionbench:session_churn_*,session_join_relays, 2 interleaved runs per side, min of 2)Vec<Range>clone per SUBSCRIBE and per update.What this means
transport::polltraits, and every wait is apoll_*any executor (or a plain loop) can drive. moq-uring runs moq-net sessions on a sans-IO QUIC stack this way today. What a sans-IO protocol core adds on top is the absence of waiters. Zig'sstd.Ioremoves coloring by parking stacks. kio's&Waiteris the stackless half of that, and a sans-IO core removes even the waiter, at the cost of a driver that owns every wait.Old(moq-dev/moq#6820). More were interleavings, and those stay in driver tests in both styles: an unanswered SUBSCRIBE whose instance was replaced (moq-dev/moq#6816), a FIN racing the peer's close (moq-dev/moq#6741), an update racing a finished track (moq-dev/moq#5833), and demand held until groups drain (moq-dev/moq#4225).Recommendation
Don't move moq-net's protocol core toward sans-IO. Keep kio
poll_*as the rule. Pull pure wire rules (version predicates, group arithmetic) into plain functions or structs where that turns async scripted tests into plain ones, as ordinary refactors, without an effect/transmit architecture. The TypeScript route is gated on translating the model, not on the protocol style.Measurement notes
perf stat --no-scale: on a hybrid CPU each core type's counter only runs while the process sits on that type, and perf's default scaling inflated the counts ±20%. The realcargobinary: thembxcargo shim serves cached rlibs. With both fixes, runs agreed within 0.1%.async fn.github:kixelated/rust2#tsat today's main, with-- --package moq-wasmas rust2's ownjust ts censusdoes.Choices made without asking
spike/branch, results here, following moq-dev/moq#5851.quest/m1/poll-first/README.md.Decision
Decided by the maintainer (2026-10-28): no. moq-net's protocol core does not move toward sans-IO. kio
poll_*stays the rule, and pure wire rules move into plain functions where that simplifies tests, as ordinary refactors. Thelite::upstreamextraction does not land.spike/sansio-upstreamgets deleted once this PR merges. The README bullet now records the decision and no longer links the branch.Suggested follow-ups
justrecipe or script that rebuilds one crate with the real cargo,CARGO_INCREMENTAL=0,-Ccodegen-units=1, andperf stat --no-scale -e instructions:u, summing both hybrid core types and reporting base vs head. Done when two runs on one tree agree within 0.1% on a loaded host.Public API: none (the prototype is unmerged). Wire: none.
(Written by Claude Opus 5.5)
🤖 Generated with Claude Code