From 1141172b0400885e3f6232846141b3e7a70b8a7c Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Wed, 5 Aug 2026 18:24:41 +0200 Subject: [PATCH] chore: update KPN to the wedging-audit fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Twenty commits, of which the one that matters for this repo is the filter and router losslessness. FilterNode and RouterNode were the last nodes on a data path still using the throwing push() and swallowing the exception, so `decimate` — which passes EOF by predicate — discarded that token whenever its output was full. Which it reliably is: the embedder is the slowest node in the chain. Nothing downstream ever received EOF, `done` was never set, and the run had to be killed. That is the wedge. The rest, in rough order of how much they affect a run here: - A sentinel could be delivered ahead of a value still queued behind it, losing that value to any consumer treating EOF as a hard stop. - Two fire_once invocations for one node could overlap, which breaks the one-slot park: a parked value can be overwritten with no drop recorded. - A node's push/space callbacks were written while a running neighbour read them — ten ThreadSanitizer races, and the root cause of the startup lost wake that AR-004 records as closed by a level-triggered re-check. - shutdown() polled every channel in the graph with no deadline, and could fail to terminate outright on an index underflow in the fill calculation. - Submitting to a stopped pool indexed a cleared vector: a segfault, which reproduced 12 runs in 20 once sources stopped before their consumers. - stop() returned while a firing was still touching the node's members. - Idle pool workers burned ~6.5 cores while one task ran (1991 ms of CPU against 0.4 ms). Latent here, since every node owns a private one-thread pool, but not for anything using a shared one. Two consequences worth holding onto. `decimate` is now a backpressure point rather than a relief valve, so the source throttles to the face branch instead of quietly thinning it — the intended behaviour, but it changes the shape of a loaded run and has not been benchmarked. And a channel now carries at most one undelivered sentinel; a second is refused and reported rather than silently overwriting the first. Verified: KPN 148/148 with ThreadSanitizer clean across six runs, this repo 138/138 with every target building warning-free against the new headers. TRACES: AR-004 | SR-002 --- external/KPN | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/KPN b/external/KPN index 454f72c..27f8844 160000 --- a/external/KPN +++ b/external/KPN @@ -1 +1 @@ -Subproject commit 454f72c1674d34e8ee552ed3859936d10e8466e1 +Subproject commit 27f884496d03a88e66b6592c3a457486ccc00c4c