From 5fcda4a9324ed5430a0d9fd273468253db3f7cd9 Mon Sep 17 00:00:00 2001 From: Matt <47545907+SoundMatt@users.noreply.github.com> Date: Sat, 22 Aug 2026 04:36:46 -0700 Subject: [PATCH] =?UTF-8?q?rewrite(phase6):=20batch=205=20=E2=80=94=20watc?= =?UTF-8?q?hdog:=20one=20traceability=20gap=20found,=20no=20catalog=20chan?= =?UTF-8?q?ge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of the v3.0.0 ground-up rewrite (cpp-RCP #129, ROADMAP.md Phase 17), branch rewrite/v3-from-c-rcp. Phase 6 (requirement catalog), batch 5 of 13. ## Scope watchdog.hpp's REQ-WDG-* prefix. c-RCP has REQ-WDG-001..012 (12 entries); cpp-RCP's catalog already had REQ-WDG-001..008 (8 entries, prior work); watchdog.hpp/test_watchdog.cpp reference all 12 ids, so 009-012 looked orphaned going in. Investigation found the premise only half held. ## No new catalog entries this batch REQ-WDG-009 (synchronous initial verdict), REQ-WDG-011 (default_config poll interval), REQ-WDG-012 (destroy() null-safety): never tagged anywhere in cpp-RCP -- they only appear in watchdog.hpp's own header-comment prose explaining why they don't transfer, and carry no c-RCP TC18 citation. They're c-RCP-specific API-shape artifacts (background-thread poll config, cached-state staleness, manual destroy()) structurally moot in cpp-RCP's RAII/live-compute design. Confirmed this reasoning is sound; left as documented non-transfers, no catalog entry, no pending-file gap (nothing is actually missing). ## One genuine finding: REQ-WDG-010 is implemented and tested, but has zero formal tags anywhere Filed to .fusa-reqs-pending.json as a traceability-tag gap, NOT a behavioral gap. The behavior itself is real and correctly wired: mock.hpp's dispatch_e2e_core() calls rx_watchdog_kick() unconditionally at both its call sites (mock.hpp:1147, mock.hpp:1343), forwarding to watchdog::Manager::on_request_received(); test_mock.cpp has a dedicated end-to-end test ("dispatch_e2e kicks the per-stream RxWatchdog (REQ-WDG-010) on every call...", test_mock.cpp:1739+); sim.hpp's Simulator independently wires the same hook. The blocker is purely mechanical: cpp-FuSa's trace tool only counts a requirement as traced/tested when a literal `// fusa:req`/`// fusa:test REQ-WDG-010` comment exists somewhere -- mock.hpp's existing prose mentions and test_mock.cpp's `[REQ-WDG-010]` Catch2 tag string don't match that regex, so this id has zero formal annotations anywhere despite being genuinely covered. Adding it to .fusa-reqs.json today (with no real tag anywhere) would fail CI's hard `cpfusa trace --req-coverage 100` /tested-coverage gates. Fixing this needs two tags added to include/rcp/mock.hpp/tests/test_mock.cpp -- both out of this batch's file-scope (batch 5 is restricted to watchdog.hpp/test_watchdog.cpp). Filed here so batch 13 (MOCK/PWRMODE, the batch that touches mock.hpp) can add those two tags and migrate this entry from pending into the real catalog in the same change. ## REQ-WDG-001..008 re-verified, untouched Existing tags checked against real code/tests and found accurate -- no placement fix needed, no catalog change. ## Verification .fusa-reqs.json: unchanged, byte-identical (544 entries, sec-tested count still exactly 72). .fusa-reqs-pending.json: 19 -> 20 entries (+1, REQ-WDG-010). include/rcp/watchdog.hpp: expanded its existing REQ-WDG-010 header-comment bullet with the mock.hpp citation and the pending-migration note (+21/-3 net). tests/test_watchdog.cpp: unchanged. Full tree rebuilt from scratch: 0 errors, 0 warnings, 58/58 ctest suites pass (100%). Co-Authored-By: Claude Sonnet 5 Signed-off-by: Matt <47545907+SoundMatt@users.noreply.github.com> --- .fusa-reqs-pending.json | 10 ++++++++++ include/rcp/watchdog.hpp | 24 +++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/.fusa-reqs-pending.json b/.fusa-reqs-pending.json index 51aa546..f89971a 100644 --- a/.fusa-reqs-pending.json +++ b/.fusa-reqs-pending.json @@ -188,6 +188,16 @@ "asil": "ASIL-B", "tc18": "§11.2, TC18.txt L1182; §11.2.1, TC18.txt L1204", "gap": "Confirmed absent (2026-08-22): shares REQ-TIMED-012's exact root cause and evidence — rcp/acf.hpp's encode_acf_abb() and rcp/l2.hpp's/udp.hpp's TSCF framing already provide the wire-encoding half of this pair (a caller can build a TSCF-headed ACF_ABB frame today), but the decode/admission half (a dispatch entry point that decodes a real TSCF-wrapped ACF_ABB frame and threads its avtp_timestamp into timed_admit()/timed_due() the way REQ-TIMED-012 describes) does not exist anywhere in cpp-RCP. See REQ-TIMED-012's gap text for the full detail; both ids share one missing piece (a TSCF-aware dispatch/admission entry point) and would likely be closed together." + }, + { + "id": "REQ-WDG-010", + "title": "The per-stream watchdog is kicked by every request received on that stream", + "text": "The RC Server's request-reception path shall call rcp::watchdog::Manager::on_request_received() (StreamWatchdog::kick_from_request()) for a request stream's stream_key on every request successfully received on that stream, so the per-stream watchdog measures the gap between consecutive requests from that RC Client.", + "standard": "iso26262", + "level": "ASIL-B", + "asil": "ASIL-B", + "tc18": "§12.7.7, TC18.txt L2936-L2938", + "gap": "NOT a behavioral gap -- a traceability-tag gap (2026-08-22, cpp-RCP Phase 6 batch 5, watchdog module): the behavior itself is genuinely, robustly implemented and tested. rcp/mock.hpp's dispatch_e2e_core() (the reference RC Server's actual request-reception path) calls rx_watchdog_kick(stream_id, ...) unconditionally, before any admission/validation check, at both of its call sites (mock.hpp:1147 inside dispatch_e2e_core, and mock.hpp:1343 inside dispatch_frame_e2e's per-member loop) -- rx_watchdog_kick() itself (mock.hpp:2097) forwards straight to rcp::watchdog::Manager::on_request_received(). tests/test_mock.cpp has a dedicated test, \"dispatch_e2e kicks the per-stream RxWatchdog (REQ-WDG-010) on every call...\" (test_mock.cpp:1739-1742+), that exercises exactly this behavior end-to-end (kick before an overflow, elapsed-time overflow after). rcp/sim.hpp's Simulator::dispatch/register_stream (sim.hpp:86-153) independently wires the same rcp::watchdog::Manager hook for the simulation harness. The blocker is purely mechanical: cpp-FuSa's trace tool (src/trace/trace.cpp) only counts a requirement as traced/tested when a literal `// fusa:req REQ-WDG-010` / `// fusa:test REQ-WDG-010` comment line exists somewhere in the tree (regex `//\\s*fusa:req\\s+`/`//\\s*fusa:test\\s+` followed by a REQ-\\S+ token) -- the existing `REQ-WDG-010:` prose mentions in mock.hpp's plain comments and the `[REQ-WDG-010]` Catch2 tag string in test_mock.cpp do NOT match that regex, so this id currently has ZERO formal annotations anywhere in the repo. CI hard-gates on this: .github/workflows/ci.yml's cpfusa-trace job runs `cpfusa trace --req-coverage 100` (fails outright, no `|| true`) and a second step that requires testedRequirements == totalRequirements (also a hard `exit 1` gate) -- adding this id to .fusa-reqs.json today, with no real tag anywhere, would fail CI. Fixing this requires adding the two formal tags to include/rcp/mock.hpp and tests/test_mock.cpp, both out of this batch's file-scope (batch 5 is restricted to .fusa-reqs.json/.fusa-reqs-pending.json/include/rcp/watchdog.hpp/tests/test_watchdog.cpp only) -- filed here so a future mock.hpp-scoped batch can add those two tags and migrate this entry into .fusa-reqs.json in the same change." } ] } \ No newline at end of file diff --git a/include/rcp/watchdog.hpp b/include/rcp/watchdog.hpp index a5dd527..8820cf4 100644 --- a/include/rcp/watchdog.hpp +++ b/include/rcp/watchdog.hpp @@ -60,9 +60,27 @@ // - c-RCP REQ-WDG-010 (the RC Server's request-reception path shall call // kick() on every request received) is a cross-cutting dispatch-layer // integration requirement, not watchdog-module behavior; this file's -// kick_from_request()/Manager::on_request_received() are the hook, and -// rcp/sim.hpp's Simulator::dispatch already wires it in exactly this -// shape (see sim.hpp's own header comment). +// kick_from_request()/Manager::on_request_received() are the hook. +// [Phase 6 batch 5, cpp-RCP issue #129, 2026-08-22] Re-verified against +// real code, not just this comment's own prior claim: rcp/sim.hpp's +// Simulator::dispatch already wires it in exactly this shape (see +// sim.hpp's own header comment), and separately rcp/mock.hpp's +// dispatch_e2e_core() (the reference RC Server's actual +// request-reception path) calls rx_watchdog_kick() -- which forwards +// straight to Manager::on_request_received() -- unconditionally before +// any admission check, at both of its call sites, with a dedicated +// tests/test_mock.cpp TEST_CASE exercising it end-to-end. Genuinely +// implemented and tested, but NOT added as a REQ-WDG-010 entry in this +// project's own .fusa-reqs.json here: neither mock.hpp nor +// test_mock.cpp carries cpp-FuSa's required literal `// fusa:req`/ +// `// fusa:test` tag for it (only informal comment mentions and a +// Catch2 tag string, which cpp-FuSa's trace tool does not recognize), +// and adding the catalog entry without that tag existing somewhere +// would fail CI's hard 100%-traced/100%-tested trace gates +// (.github/workflows/ci.yml's cpfusa-trace job). Filed to +// .fusa-reqs-pending.json instead, with the full citation, for a +// future mock.hpp/test_mock.cpp-scoped batch (out of this batch's +// watchdog.hpp/test_watchdog.cpp-only file-scope) to tag and migrate. // - c-RCP REQ-WDG-012 (destroy(k) is a null-safe no-op, otherwise closes // then frees) does not transfer: no manual destroy exists here — // StreamWatchdog/Manager are plain value types with ordinary C++