# Checklist: windows-ioring-sys
Design decisions are in [DESIGN-NOTES.md](DESIGN-NOTES.md); the session that produced them is
[DESIGN-SESSION-2026-08-22-ioring-architecture.md](design-sessions/DESIGN-SESSION-2026-08-22-ioring-architecture.md).
Everything through M18 is archived in [COMPLETED-CHECKLIST.md](COMPLETED-CHECKLIST.md): M1-M6
[here](COMPLETED-CHECKLIST.md#moved-2026-08-22----m1-through-m6-ring-lifecycle-through-consumer-documentation),
M7 [here](COMPLETED-CHECKLIST.md#moved-2026-08-23----m7-ring-copy-a-topology-aligned-sample), M11-M14 in their
own dated groups, M8-M10
[here](COMPLETED-CHECKLIST.md#moved-2026-08-30----m8-through-m10-handle-lifetime-cross-ring-identity-and-the-contract-audit),
and M15-M18
[here](COMPLETED-CHECKLIST.md#moved-2026-08-30----m15-through-m18-the-testing-strategy-response-to-eight-defects).
M19 is archived [here](COMPLETED-CHECKLIST.md#m19). `M20` through `M24`, and the `M21+`, `M22+` and
`M28+` buckets, are archived
[here](COMPLETED-CHECKLIST.md#moved-2026-10-01-m20-through-m24); `M26+` and `M28`
[here](COMPLETED-CHECKLIST.md#moved-2026-10-01-m26-and-m28); and `M27`
[here](COMPLETED-CHECKLIST.md#moved-2026-10-01-m27).
The plan these belonged to is recorded in [COMPLETED-PLANS.md](COMPLETED-PLANS.md); add a milestone
here and a row in [PLANS.md](PLANS.md) when new work is planned.
**`M26.13`, the pool stall, is not archived -- it was transferred.** The fault was never this
crate's, so the question, its timeline and its 33 measurement captures now live in
[windows-threadpool-sys](../windows-threadpool-sys/CHECKLIST.md) as `M-T7.1`. The reproducer stays
here, because the ring is what reaches the state.
**An `M{n}+` heading is parked rather than pending** -- the convention is noted here because the
archived groups use it: such a heading is gated work with no current obligation, not an unfinished
milestone. When this file carries milestones again, which of them are open is what the headings
say; this preamble deliberately does not restate it, because a second copy is one nobody updates.
## M-R1 -- The stall post-mortem after the hooking facility was removed
Opened 2026-10-03. `windows-threadpool-sys` deleted its inline hooking facility, because this
workspace ships no undocumented APIs and no assumptions about undocumented behaviour -- see
[DESIGN-NOTES.md](../../DESIGN-NOTES.md#no-undocumented-apis). The reproducer in this crate was its
real consumer, so what that costs the post-mortem is recorded here rather than left to be inferred
from an absence.
- [x] **M-R1.1** -- **Strip the post-mortem probes that depended on the hooking facility.** Done
2026-10-03.
**What was removed from `tests/event_delivery.rs`:**
- the worker-factory counter and completion-port depth reads taken at the moment of failure, in
`hand_rolled_trigger`, deliberately ordered *before* the liveness probe because submitting
work is the one action measured to release this stall and asking afterwards would describe a
pool the question had already repaired;
- `poke_the_stalled_port`, gated on `IORING_POKE_PORT`, which posted a packet to a stalled port
and read the factory's worker count either side. This is the experiment behind the recorded
answer that **an ordinary completion-port arrival has never been seen to recover this stall**;
- `capture_healthy_factory_state`, gated on `IORING_CAPTURE_HEALTHY`, the healthy-arm contrast
for the same reading.
**What the apparatus can no longer answer.** Whether a stalled factory has zero workers while
holding queued work -- the signature the investigation turned on -- and whether poking the port
changes that. The reproducer still detects the stall and still reports outstanding counts, ring
state and pool liveness; what it has lost is the ability to say *why* the pool did not dispatch.
**What survives, and where.** The captures taken with the facility are committed under
`windows-threadpool-sys/measurements/`, and the central finding -- the pool's first worker is
never created -- was reproduced independently of the hooks by an ETW kernel trace across 900
runs (`M26.13.19`). ETW is the documented route and is where any rebuild should start.
- [ ] **M-R1.2** -- **Decide whether to rebuild the two experiments on ETW.** Not started, and
deliberately not scoped yet.
The two questions `M-R1.1` retired are worth answering and are not answerable in-process on
documented ground. An ETW kernel trace reaches both: thread-create events say whether the
stalled factory ever made a worker, and the same session spans the poke, so the before/after
contrast survives the move. Whether it is worth building depends on whether `M-T7.1` is resumed,
which is a decision for the engineer rather than something this item should assume.
## M29 -- The `epoch_log` sample treats a failed commit as repairable by a later one
Opened 2026-10-05 from the durable-ioring design session
([DESIGN-SESSION-2026-10-05-epoch-ring.md](../../design-sessions/DESIGN-SESSION-2026-10-05-epoch-ring.md),
Scenarios 1 and 2). Queued here rather than in [durable-ioring](../durable-ioring/CHECKLIST.md)
because the sample is wrong whatever becomes of that crate
([DI-D-7](../durable-ioring/DESIGN-NOTES.md#di-d-7)).
- [ ] **M29.1** -- **Stop letting a later successful commit report an earlier failed epoch durable.**
`Committer::claim` in [commit.rs](examples/epoch_log/commit.rs) argues under "A failed commit is
not permanent, and that is not a loophole" that commit *N+1*'s covering flush settles a failed
commit *N*, and advances `durable_through` past it. That holds only if the writes in the suspect
window -- every write pushed before the failure was observed that no earlier successful covering
flush covers -- are re-issued before
the later flush. Without that, a lower layer that discarded the data on the failed flush (the
documented Linux behaviour, and undocumented either way on Windows) leaves *N* reported durable
and gone. Correct the code and its rustdoc so the watermark stays at the last epoch below the
failure, and update `commit/tests.rs`, which presumably pins the current behaviour. **Sweep the
same reasoning** in [checkpoint.rs](examples/epoch_log/checkpoint.rs) (its `settle` advances by
`max`; a later checkpoint rewrites the whole record, which is the re-issue case, so it may be
correct -- argue it either way in the code) and in
[strategy.rs](examples/epoch_log/strategy.rs)'s `settle`, and check
[contract.rs](examples/epoch_log/contract.rs) for a statement that relies on it.
## M32 -- Write-through needs an unbuffered handle
Opened 2026-10-07 from durable-ioring's `DI-3.2.2.1`, whose test of its caching option found this.
- [ ] **M32.1** -- **State, and pin, what `WriteCaching::WriteThrough` does on a cached handle.**
Measured through dioring's ring on 2026-10-07: a write-through write to a handle opened for cached
I/O -- including one opened with `FILE_FLAG_WRITE_THROUGH` -- completes with Win32 error 509 ("The
specified operation is not supported on a file opened for cached IO"), and to a handle opened with
`FILE_FLAG_NO_BUFFERING` as well, it completes as a transfer. This crate's documentation presents
the flag as a cache directive a caller may add alongside a covering flush, and none of it says the
handle must be unbuffered: `WriteCaching`'s rustdoc in `batch.rs`, the write push's in
`batch/push.rs`, `lib.rs`, the README's durability section, and
[D-25](DESIGN-NOTES.md#d-25). Sweep all of them. **Test in both directions:** the cached handle
fails with 509, and the unbuffered one transfers, with a buffer and offset that meet unbuffered
I/O's alignment rules (a page-aligned allocation, for instance), so the test does not pass by
accident of the allocator. No crate test exercises write-through today, which is why this was not
found here.
## M33 -- A wake-only delivery for a caller that owns its ring
Opened 2026-10-11 from durable-ioring's `DI-3.10.3.5.6`
([DI-D-53](../durable-ioring/DESIGN-NOTES.md#di-d-53)), whose backend owns its ring threadlessly and
needs the thread pool only to be told when to drain.
- [x] **M33.1** -- `CompletionWake`: the thread pool wakes an owner, who drains its own ring; `EventDelivery` re-expressed on it, so the delivery protocol is written once. -> [completed 2026-10-11](COMPLETED-CHECKLIST.md#m331)
- [ ] **M33.2** -- **The engineer's review of the assistant's choices in `M33.1`**: the name
`CompletionWake`; `new(&mut IoRing, on_wake, env)`; `on_wake: Fn() + Send + Sync + 'static`; one
waiter per ring stated, not enforced, as D-21 is; `EventDelivery` holding a `CompletionWake`
where it held a `ThreadpoolWait`, its explicit `Drop` folded into the wake's; the setup-signal
sabotage moved to the wake as one site serving both; and the explicit drain in the wake's `Drop`
recorded as an equivalent mutant, since `ThreadpoolWait`'s own `Drop` drains too and only the
obligation report differs.
> **-> CROSS-COMPONENT HANDOFF:** next work is in component `crates/durable-ioring` -> `DI-3.10.3.5` -> `DI-3.10.3.5.6.1` (pool delivery over the threadless backend, built on this wake). See [CHECKLIST.md](../durable-ioring/CHECKLIST.md).