From c12838b9fdc28f49ede3c75de0f132c40971c4ea Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Fri, 31 Jul 2026 10:45:39 +0200 Subject: [PATCH] fix: dropped frames fail the run instead of printing a footer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A drop was reported to stderr and the process exited 0, so a run that discarded 320 frames "succeeded" and produced a truth file that looked complete. The output in that case is a claim about footage that was never analysed, and nothing in the file says so. Now exits 2 and says why. Distinct from 1 (node crash) because the failures are different: a crash produced no output, a drop produced output that cannot be trusted. This is also the regression test for AR-004 that otherwise did not exist. The backpressure fix is one line in the KPN submodule — easy to lose in an update — and with data pushes blocking, a drop can no longer occur on the data path. So any drop now means either that fix regressed or a channel was disabled mid-run, and both are worth stopping for. Verified: a clean run still exits 0. Co-Authored-By: Claude Opus 5 TRACES: AR-004 | SR-002 --- src/main.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index dcf2dd1..b117199 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -282,15 +282,30 @@ int main(int argc, char** argv) { net.stop(); net.print_diagnostics(); + /// TRACES: AR-004 | SR-002 + // A dropped frame does not degrade a result, it silently changes one — + // the output is a claim about footage that was never analysed, and + // nothing in the file says so. Since AR-004 made data pushes block, a + // drop can no longer happen on the data path, so any drop here means + // either that fix regressed (it lives in the KPN submodule, one line, + // easy to lose in an update) or a channel was disabled mid-run. + // + // Reporting it in a footer and exiting 0 made both invisible: the run + // "succeeded" and the truth file looked complete. Fail instead. + bool dropped = false; { std::lock_guard lk(event_mtx); if (!overflow_counts.empty()) { - std::cerr << "[main] dropped frames (channel overflow):\n"; + dropped = true; + std::cerr << "[main] ERROR: frames were dropped (channel overflow):\n"; for (const auto& [name, count] : overflow_counts) std::cerr << " " << name << ": " << count << "\n"; + std::cerr << "[main] The output would describe footage that was never " + "analysed. Refusing to report success.\n"; } } - return node_crashed.load(std::memory_order_acquire) ? 1 : 0; + if (node_crashed.load(std::memory_order_acquire)) return 1; + return dropped ? 2 : 0; }; // ── Build static network and run ──────────────────────────────────────────