Close the ioring mutation survivors, drop the topology dev-dependency pin, and queue the NUMA repairs - #68
Conversation
The 2026-09-02 sweep ran this crate with its default features, and eight mutants survived across the batch, error, event-delivery, and ring surfaces. The tests here close them. Two needed a seam before anything could reach them: - `Ring::set_supported_ops_for_test` builds an arbitrary `OpSupport` mask, so the refusal paths for an unsupported opcode can be exercised without a kernel that happens to lack one. - `DROP_RUNS` counts drop-glue runs through a thread-local, which is what makes "the drop ran exactly once" assertable. Both are `#[cfg(test)]`, so neither exists in a real build and no published surface changes. Typed `test` for that reason -- release-please attributes by path, and nothing here has earned a version. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The `windows-topology-sys` dev-dependency carried both a `path` and a `version`, and the version was doing harm rather than work. It was never checked where it was supposed to matter: publish verification builds the library alone, not examples or tests, so a dev-dependency requirement is never exercised at that moment. Cargo also omits a versionless dev-dependency from the published manifest entirely -- verified by packaging this crate and reading the result -- so nothing is lost downstream by removing it. What it did do was break the workspace. Cargo enforces `path` and `version` agreement at every build regardless of dependency kind, so a pin reading "0.1.0" against a `windows-topology-sys` bumped to 0.2.0 failed `cargo metadata` for every crate here. That turns a release of an unrelated crate into a red `main`, which is the opposite of what a pin is for. The examples still build from a checkout, which is where anyone reads them. They were only ever incidentally buildable from the packaged tarball. Typed `chore`: this changes a dev-dependency's manifest entry, which no consumer resolves, so the crate has earned no version. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…y test M20 collects the documentation and policy-test repairs the 2026-08-30 NUMA-sharding measurement made necessary: the L3 heuristic's justification, the measurement itself as a decision, `ring_copy`'s degraded-fallback path as something a test can observe, and the "what is not reachable" section that the measurement contradicted. The test-failure record gains one entry. `flush_barrier::a_covering_flush_waits_for_preceding_writes_and_an_unordered_one_does_not` failed once under `cargo test --workspace --all-features` on 2026-09-03 and passes in isolation. It measures real I/O ordering, so it is sensitive to load -- a full-workspace run has every other suite competing for the disk, and the window it asserts is a timing one. It is recorded rather than fixed because the choice between making it load-independent and marking it serial is a decision, not a repair, and it has not been seen to fail in CI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Review of the peel found M20's four items citing design-sessions/DESIGN-SESSION-2026-08-30-numa-sharded-io-execution-domains.md, which lives only on the unmerged feature branch. Every one of M20.1 through M20.4 is queued from it, so on merge the whole milestone's justification would have been a dead link. This is the same defect the previous peel in this series shipped -- the referrer taken without the referent -- and the same remedy: peel the referent rather than drop the pointer. The session is the reasoning behind four checklist items, and restating 65 KB of it inline would be a second source of truth for exactly the kind of content the three-tier scheme exists to keep in one place. Checked its own outbound links before moving it, since that is the identical failure one level down: all twenty-six resolve at this branch, including the two NUMA spike sources, which landed on `main` in PR #65. Two smaller findings from the same review, fixed here: - The crate's PLANS.md row still read "leaving only `M6+`, which is parked rather than pending" while the same change added M20 to it, so the cell asserted both. The row now matches CHECKLIST.md, which the peel had already corrected. - The Cargo.toml comment ended by citing SH-2.5 in CHECKLIST-ship-topology-and-queues.md, another feature-branch-only file. The citation is dropped rather than followed, because the surrounding comment already states the whole reasoning. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
New tests include unbounded/over-assumptive completion popping and brittle string-based error assertions that can cause hangs or flakiness under load.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR peels out the windows-ioring-sys slice of earlier work by closing mutation-test survivors with targeted new tests and test-only seams, removing a harmful dev-dependency version pin, and queuing follow-up NUMA documentation/policy repairs based on the 2026-08-30 measurement/design session.
Changes:
- Add focused tests (and small
#[cfg(test)]seams) to kill previously surviving mutants across ring/batch/error/event-delivery surfaces. - Remove the
windows-topology-sysdev-dependency version pin (keep path-only) to avoid workspace-widepath+versionmismatch breakage. - Add the NUMA-sharding design session record and queue the resulting documentation/policy repair milestone (M20), plus record a known flaky test in
UNRESOLVED-TEST-FAILURES.md.
File summaries
| File | Description |
|---|---|
| design-sessions/DESIGN-SESSION-2026-08-30-numa-sharded-io-execution-domains.md | Adds Tier-3 design-session record that motivates/feeds the queued M20 repairs. |
| crates/windows-ioring-sys/UNRESOLVED-TEST-FAILURES.md | Records one flaky flush_barrier test per repo policy. |
| crates/windows-ioring-sys/src/ring/tests.rs | Adds tests to close mutation survivors (supports set, drop runs, injection zeroing, Debug rendering). |
| crates/windows-ioring-sys/src/ring.rs | Adds #[cfg(test)] capability override seam and a thread-local drop counter; documents equivalent-mutant rationale. |
| crates/windows-ioring-sys/src/event_delivery/tests.rs | Adds test that RingScope::supports reflects a deliberately restricted capability set. |
| crates/windows-ioring-sys/src/error/tests.rs | Adds Debug formatting assertion to close an IoRingError Debug survivor. |
| crates/windows-ioring-sys/src/batch/tests.rs | Adds tests covering Batch::require, Debug formatting, and Windows behavior for empty buffer registrations. |
| crates/windows-ioring-sys/src/batch.rs | Documents why RegisteredBuffers::is_empty() is effectively unreachable today and ties it to a platform-behavior test. |
| crates/windows-ioring-sys/PLANS.md | Updates the crate plan summary and links in the new NUMA design session / M20 milestone. |
| crates/windows-ioring-sys/CHECKLIST.md | Queues M20 items (doc/policy/test repairs) from the NUMA-sharding measurement. |
| crates/windows-ioring-sys/Cargo.toml | Drops the dev-dependency version pin for windows-topology-sys while keeping the path dependency. |
Review details
Suppressed comments (1)
crates/windows-ioring-sys/src/batch/tests.rs:531
- Asserting on
error.to_string()is brittle (it depends onDisplayformatting staying exactly the same). Since this error should be an HRESULT-backedIoRingError, assert on the actual code via the sealed downcast helper instead.
assert!(
error.to_string().contains("0x80070057"),
"expected E_INVALIDARG, got {error}"
);
- Files reviewed: 11/11 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| let completion = ring | ||
| .try_pop() | ||
| .expect("pop") | ||
| .expect("the registration completion is ready"); | ||
| assert_eq!(completion.user_data(), user_data); |
There was a problem hiding this comment.
Fixed in 669e23f -- same helper as the sibling comment, so both spellings of the assumption are gone.
You identified the exact contract line: submit_and_wait's own docs say "Returning does not mean wait_operations completions are poppable: the timeout can expire first, and the returned count is entries submitted rather than completed." The test read that guarantee as stronger than it is, and .expect("the registration completion is ready") would have failed under load with a message asserting something the API never promised.
It now goes through the bounded pop_within, which retries with a yield until a thirty-second deadline and then fails naming what it waited for.
Worth noting the two findings are one defect with two faces: a single try_pop flakes, and the obvious repair -- looping -- turns the flake into a suite-wide hang. The helper exists so neither has to be reasoned about at the call site.
| batch.submit_and_wait(1, 30_000).expect("submit and wait"); | ||
| let completion = loop { | ||
| if let Some(completion) = ring.try_pop().expect("pop") { | ||
| break completion; | ||
| } | ||
| }; |
There was a problem hiding this comment.
Fixed in 669e23f, at four sites rather than the one.
You are right, and the consequence is worse than a slow test. cargo test runs tests as threads in one process, so a hung test stops the whole harness reporting -- the run dies with no test name attached. This repository's own mutation-sweep notes document that exact failure mode (a timeout there is usually a detection that lost its name). An unbounded spin is the reliable way to produce it, and this one had no yield either.
Both sites now call one helper:
#[cfg(test)]
pub(crate) fn pop_within(ring: &mut IoRing, what: &str) -> Completion {
const BOUND: std::time::Duration = std::time::Duration::from_secs(30);
let deadline = std::time::Instant::now() + BOUND;
loop {
if let Some(completion) = ring.try_pop().expect("pop") { return completion; }
assert!(std::time::Instant::now() < deadline, "timed out after {BOUND:?} waiting for {what}");
std::thread::yield_now();
}
}Thirty seconds and yield_now match the idiom the crate's failure_paths integration test already uses. It is a hang bound, not a latency expectation. The bound and the message come from one constant so they cannot drift apart.
It is used at four sites, not the two the review named. The loop you flagged was a copy of two older ones in the same file -- including the one inside real_completion, which every injection test goes through. Fixing only the new one would have left the wrong idiom sitting directly beside the right one, for the next person to copy. The class is gone from these files rather than the reported instances.
Verified by sabotage, not by reading. With the helper's try_pop forced to yield nothing:
thread 'ring::tests::an_injected_failure_zeroes_the_transferred_byte_count' panicked at ring.rs:1063:9:
timed out after 30s waiting for the fixture read's completion
test result: FAILED. 0 passed; 1 failed; finished in 30.00s
30.00s and a named failure, rather than a hang. That is the behaviour the fix exists to produce, so it is the behaviour I measured.
… its text Three findings from the PR #68 review, all real. `Batch::submit_and_wait` returning does not mean a completion is poppable -- its own documentation says so, because the timeout can expire first. Two tests here took that guarantee anyway, in the two different ways it can be taken: - A single `try_pop().expect("the registration completion is ready")`, which flakes when the completion lands just after the check. - A bare `loop` around `try_pop`, which converts that flake into a hang -- and worse than it sounds. `cargo test` runs tests as threads in one process, so a hung test stops the whole harness reporting and the failure arrives with no test name attached, which this repository's own mutation-sweep notes describe at length. Both now call one `pop_within` helper: a thirty-second deadline with a yield, matching the idiom the crate's `failure_paths` integration test already uses. The bound is a hang bound, not a latency expectation. **The helper is used at four sites, not the two the review named.** The loop it flagged was a copy of two older ones in the same file, and fixing only the new one would have left the wrong idiom sitting beside the right one for the next person to copy. The class is gone from these files rather than the two reported instances. Verified by sabotage rather than by reading: with the helper's `try_pop` forced to yield nothing, the test fails in 30.00s with `timed out after 30s waiting for the fixture read's completion` and names itself, instead of hanging. The bound and the message it prints come from one named constant so they cannot drift apart. The third finding: the empty-registration test asserted `error.to_string().contains("0x80070057")`. The point is which HRESULT the kernel returned, and matching formatted text would also fail if the message were reworded -- reporting a documentation change as a platform change. It now downcasts through the crate's own `IoRingErrorExt` and compares against `E_INVALIDARG`. Still `test`-typed: `pop_within` is `#[cfg(test)] pub(crate)`, so no published surface changes and no crate is bumped. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
All three findings from this review are fixed in 669e23f, including the suppressed one. The two inline comments have replies on the threads. The suppressed finding -- let code = crate::IoRingErrorExt::as_ioring_error(&error)
.expect("a kernel refusal carries an HRESULT")
.code();
assert_eq!(code, windows_sys::Win32::Foundation::E_INVALIDARG, ...);The point of that test is which HRESULT the kernel returned when refusing an empty buffer registration. Matching One note on scopeThe completion-pop fix is applied at four sites, not the two flagged. The loop the review named was a copy of two pre-existing ones in the same file -- one of them inside Verification
|
There was a problem hiding this comment.
🔵 Needs a closer look
The new design-session doc contains at least one incorrect API reference (Topology::discover()), which should be corrected to avoid sending readers to a non-existent symbol.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
design-sessions/DESIGN-SESSION-2026-08-30-numa-sharded-io-execution-domains.md:137
Topology::discover()does not exist inwindows-topology-sys(the type was renamed toMachineMemoryTopology). As written, this session record points readers to a non-existent API; use the current type name in the backticked call.
- Files reviewed: 11/11 changed files
- Comments generated: 0 new
- Review effort level: Lite
The 2026-08-30 session cites `Topology::discover()`, which no longer exists -- the type became `MachineMemoryTopology` on 2026-09-02. Raised in the PR #68 review, and a reader following it today finds nothing. The session predates the rename by three days, so the text was correct when written. Editing it to match current code would make the record say something that was not said, which is the one thing a dated Tier-3 transcript is for. The current name is given in brackets at the site instead, and the header states that convention once so the brackets read as annotation rather than as part of the discussion. The review said "at least one", and it was right to hedge: there were two stale claims across three sites. The second is that `efficiency_class` is "exposed on `Core`" -- there is no `Core` type at all now, and that field moved to `ProcessorFacts` as an `Observed<u8>`. Worth naming precisely rather than just repointing, because the type change is material to the session's own argument: it calls this an input that "exists", and it is now explicitly maybe-absent-with-a-reason, which is the distinction `Observed<T>` was added to carry. Verified rather than assumed, since asserting a wrong name is the defect being fixed: `MachineMemoryTopology::discover` is `topology.rs:238` and is re-exported from `lib.rs:156`; `ProcessorFacts` is re-exported from `lib.rs:139`; and `efficiency_class` is a public field on it, not a method -- the first wording said "reached through `ProcessorFacts`", which was true but vaguer than it needed to be. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Fixed in 9f911d2 -- and there were two stale claims, not one, so the "at least one" hedge was warranted. The judgment call, statedThe session is dated 2026-08-30; the rename landed 2026-09-02 22:25, three days later. So That makes this a Tier-3 question rather than a typo. Editing the transcript to match current code would make the record say something that was not said, which is the one thing a dated session record exists to prevent -- and the file's own header already declares So the text stays and the current name goes in brackets beside it: with the convention stated once in the header, so the brackets read as annotation rather than as part of the discussion. The second one
That one is worth naming precisely rather than just repointing, because the type change is material to the session's own argument. It calls this an input that "exists"; it is now explicitly maybe-absent-with-a-reason, which is exactly the distinction Verified, since asserting a wrong name is the defect being fixed
My first wording said "reached through Swept the whole document for the class: three sites, all three now annotated, none left bare. Encoding clean over 598 files. |
There was a problem hiding this comment.
🟢 Approval recommended
The changes are scoped to tests/docs/planning plus a dev-dependency pin removal, and the added test seams are #[cfg(test)]-only with no runtime surface impact.
Review details
- Files reviewed: 11/11 changed files
- Comments generated: 0 new
- Review effort level: Lite
Brings in PR #68, the ioring peel. Six conflicts, all files that peel touched, all resolved to main's copy: those carry four review rounds this branch's originals predate -- a bounded `pop_within` replacing an unbounded completion loop, an HRESULT assertion replacing a Display string match, the dropped citation of a checklist that is not on main, and the design session's stale API names annotated rather than rewritten. Confirmed the branch had made no independent change to any of the six since the peel was taken, so taking main's loses nothing. The merged tree then failed one test: `flush_barrier::a_covering_flush_waits_for_preceding_writes_and_an_unordered_one_does_not`, with `left: 1, right: 0` -- one of 32 writes completed ahead of the covering flush. That is the flake this branch already documented, not a merge defect, and it was verified rather than assumed: - The merge touches neither `tests/flush_barrier.rs` nor `src/batch.rs`. - Ten consecutive isolated runs pass. - The full suite passes on immediate re-run: 2913 of 2913. Two records updated as a result. UNRESOLVED-TEST-FAILURES.md said "observed once"; it is now twice in three days, so it carries both sightings, the measurements taken after the second, and the observation that two in three days is a rate rather than an anomaly -- both were local full-workspace runs, and if the rate holds it will eventually land in CI, where it would read as a real ordering defect to whoever sees it first. CHECKLIST.md gains M20.5, because the decision that record has been describing since the first sighting was scheduled nowhere. A note that says work is needed, with no checklist item, is the orphaned-work shape this repository's rules forbid; the second failure is what made it visible. The item states why the two candidate answers are not equivalent -- making the assertion load-independent keeps coverage under contention but may weaken what it proves, while marking the test serial preserves the assertion and gives up the contended case, which is the case a real consumer runs in -- and says not to close it by loosening the assertion without naming the guarantee surrendered. Verified: cargo check --all-targets clean, 2913 tests pass across 105 suites, encoding clean over 625 files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Peels the
windows-ioring-syswork out of PR #56: eight mutation survivors closed, a dev-dependency pin removed, and the milestone that the 2026-08-30 NUMA-sharding measurement made necessary.No crate is bumped, and that was verified rather than assumed -- see the bottom of this description.
The tests
The 2026-09-02 sweep ran this crate with its default features, and eight mutants survived across the batch, error, event-delivery, and ring surfaces. Two needed a seam before any test could reach them, and both are
#[cfg(test)] pub(crate), so neither exists in a real build:Ring::set_supported_ops_for_testbuilds an arbitraryOpSupportmask, so the refusal path for an unsupported opcode can be exercised without needing a kernel that happens to lack one. It builds the mask the same wayOpSupport::probedoes (1 << Op::ALL.position(op)) andOpSupport::containsreads it -- a helper that indexed differently would let tests pass over broken production code.DROP_RUNScounts drop-glue runs through a thread-local, which is what makes "the drop ran exactly once" assertable at all.One test replaces a comment.
ring/tests.rspreviously carried a "deliberately not tested" note claiming theinformation: 0zeroing on an injected failure was unobservable. It is observable from the child module, so the note is gone andan_injected_failure_zeroes_the_transferred_byte_countasserts it -- reading the pre-injection value first, so it cannot pass against a completion that was already zero.The dev-dependency pin
windows-topology-syscarried both apathand aversion, and theversionwas doing harm rather than work.It was never checked where it was supposed to matter: publish verification builds the library alone, not examples or tests, so a dev-dependency requirement is never exercised at that moment. And cargo omits a versionless dev-dependency from the published manifest entirely -- confirmed by packaging the crate and reading the result, which contains
serde_json,windows-overlapped-io-sysandwindows-sysunder[dev-dependencies]and nowindows-topology-sysentry at all.What it did do was break the workspace. Cargo enforces
path+versionagreement at every build regardless of dependency kind, so a pin reading0.1.0against awindows-topology-sysbumped to0.2.0failedcargo metadatafor every crate here -- turning a release of an unrelated crate into a redmain.The examples still build from a checkout, which is where anyone reads them. They were only ever incidentally buildable from the packaged tarball.
The milestone, and the design session it rests on
M20 queues four documentation and policy-test repairs from the 2026-08-30 measurement: a shipping ARM laptop reports no L3 cache domain at all, which falsifies the stated justification for the last-level-cache heuristic (though not the heuristic's preference over the NUMA node, and not
ring_copy, whose degraded fallback already handles it).The design session those four items are queued from is peeled with them. A review of this branch caught it citing a file that lives only on the unmerged feature branch -- the same defect the previous peel in this series shipped, the referrer taken without the referent. The remedy is the same: peel the referent, not drop the pointer. I checked the session's own twenty-six outbound links before moving it, since that is the identical failure one level down; all resolve here, including the two NUMA spike sources, which landed on
mainin #65.The same review found two smaller instances, both fixed: a
Cargo.tomlcomment citing another feature-branch-only checklist, and aPLANS.mdrow still reading "leaving onlyM6+" while the same change added M20 to it.One flaky test, recorded rather than fixed
flush_barrier::a_covering_flush_waits_for_preceding_writes_and_an_unordered_one_does_notfailed once undercargo test --workspace --all-featureson 2026-09-03 (2,899 of 2,900) and passes in isolation. It measures real I/O ordering, so it is load-sensitive: a full-workspace run has every other suite competing for the disk, and the window it asserts is a timing one. Whether to make it load-independent or mark it serial is a decision rather than a repair, so it is recorded inUNRESOLVED-TEST-FAILURES.md. It has not been seen to fail in CI.Why nothing is bumped
release-please attributes a bump by the paths a commit touches, not by its scope, so this matters more than the subject lines suggest -- the
chore(ioring)commit edits that crate'sCargo.tomland thetest(ioring)commit edits six files under itssrc/. Either typedfix:would have taken an unearned patch bump.docs,docs,chore,test-- nofeat,fix,!,BREAKING CHANGE, orRelease-Ascheck-commit-scope.ps1)feat/fix/!; clean on all four commitsx-release-please-versionline, manifest, or config touched -- the onlyversionin the diff is the dev-dep requirement being removedtest:/docs:commits over seven crates) and changed noCargo.tomland no release manifest; no release PR is opendesign-sessions/sits outsidecrates/, so it maps to no package at all.Verification
cargo fmt --check,cargo clippy --workspace --all-targets --all-features, andcargo test --workspace --all-features(2,964 passing, 99 suites) all clean. Encoding clean over 598 files;check-baseline,check-publishable,check-borrow-surfaceandcheck-workflow-refsall green.Before opening this I re-ran the link sweep the review's first finding called for -- every relative link the peel adds, resolved against this branch. Zero dangling. That check is cheap and belongs before review, not after it.