Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions .fusa-reqs-pending.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,16 +169,6 @@
"tc18": "§11.2.2.6 (\"If the first request in an AVTPDU is a chain request, then there is no predecessor to chain to, thus the entire chain will be ignored. An error response with the error code 'CHAIN_ERROR' to each request will be generated\"), TC18.txt L1796-1798",
"gap": "Confirmed absent (2026-08-22): RequestRecord::chained_predecessor is std::optional<uint8_t> (request.hpp:1315), and RequestLedger::submit() (request.hpp:1354-1362) never inspects it — a Chained-opcode record with chained_predecessor == std::nullopt is accepted and tracked exactly like any other Pending record, with no special rejection path. RequestErrc (request.hpp:270-285) has no CHAIN_ERROR-equivalent enumerator at all — the closest neighbors (request_not_found, request_canceled, invalid_lifecycle_transition) are semantically unrelated. This is distinct from REQ-CHAIN-009's 'already-aborted chain' case (which cascade_cancel()/propagate_chain_completion() genuinely do handle, unconditionally cancelling every downstream chained_successor once one member aborts — see request.hpp's own file-header delta #4/judgment-call note at lines 207-217): REQ-CHAIN-008 is about a chained member that never had a predecessor relationship recorded in the first place, which nothing in RequestLedger detects or rejects today. A caller assembling chained_predecessor/chained_successors links at submission time (this codebase's own design, not c-RCP's positional has_predecessor bool) could in principle already choose not to submit a first-frame Chained request with a false chained_predecessor link, but RequestLedger itself provides no enforcement or detection of the case, and no test in test_request.cpp exercises it."
},
{
"id": "REQ-TIMED-012",
"title": "A request carried under a TSCF header is postponed until the header's presentation time",
"text": "A caller-facing admission/dispatch entry point shall, given an AVTPDU decoded under a TSCF header (carrying its own avtp_timestamp), defer executing any request in it until that timestamp is reached, using the already-implemented timed_admit()/timed_due() primitives (REQ-TIMED-007/008/011) as the gate.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B",
"tc18": "§11.2, TC18.txt L1159; §11.2.1, TC18.txt L1204",
"gap": "Confirmed absent (2026-08-22): rcp/request.hpp implements every TSCF-admission PRIMITIVE this requirement depends on (timed_admit()/timed_due()/timed_too_far(), request.hpp:1094-1125) but, by this file's own explicit design note (request.hpp:246-250, 'this header... does not implement a running scheduler thread; wiring select_next_due()'s output into an actual dispatch loop is left to the embedding application'), provides no dispatch/admission LOOP that actually calls them against a real TSCF-decoded avtp_timestamp. Grepped the whole tree (include/, src/) for a dispatch-tscf/admit-gate equivalent to c-RCP's rcp_mock_server_dispatch_tscf()/rcp_server_endpoint_admit(): none exists — rcp/l2.hpp/udp.hpp encode/decode TSCF *framing* (use_tscf bit, avtp_timestamp field) but never route a decoded timestamp into timed_admit()/timed_due(). This is a genuine, confirmed absence of end-to-end behavior (not merely an unwired primitive): nothing in cpp-RCP today defers ANY request's execution until a TSCF header's presentation time arrives. Per this file's own design note this may be intentionally out of request.hpp's charter (a library of primitives, not a server), but the requirement's own text (postponement actually happening) has no home anywhere else in the tree either."
},
{
"id": "REQ-TIMED-013",
"title": "Standard requests, and timed requests under a TSCF header, are sent as ACF_ABB",
Expand Down Expand Up @@ -1302,18 +1292,6 @@
"tc18_master_id": "",
"gap": "NOT a behavioral gap -- an id-collision traceability gap (2026-08-22, cpp-RCP Phase 6 batch 11 (RMAP/SRV)). The behavior itself is genuinely implemented and tested. The blocker is that this batch's REQ-REGMAP-* -> REQ-RMAP-* rename (ROADMAP.md Phase 17) claimed this id for cpp-RCP's own pre-existing, unrelated content first: this id is already taken in .fusa-reqs.json by that renamed entry. Already taken by: this catalog's own REQ-RMAP-015 (\"EndpointGenericConfig's per-endpoint E2E CRC safe-mode toggles\"). Genuinely implemented+tested: regmap::named_signal_string() -- tests/test_regmap.cpp's \"named_signal_string names are unique across the whole index\" TEST_CASE, dual-tagged [REQ-RMAP-044][REQ-RMAP-015] in this batch."
},
{
"id": "REQ-RMAP-081",
"title": "EP_RESP_ON_ERROR (Table 31 prose, IO-pin gauging error response) is a dangling spec reference",
"text": "NOT IMPLEMENTED, matching c-RCP's own disposition verbatim: TC18's own prose names a configuration parameter (EP_RESP_ON_ERROR) that Table 31 itself never actually defines a bit or field for -- a genuine, confirmed TC18 spec defect, not an addressable local gap. ep_generic_cfg::render()'s own reserved-octet spans (bits [3:1] and [7:6] of octet 1, mask 0xCE) deliberately stay zero for every input rather than inventing a bit position for this dangling reference.",
"standard": "iso26262",
"level": "QM",
"asil": "QM",
"scope": "tc18-gap",
"status": "not-implemented",
"tc18": "§13.2 Table 31 (EP_RESP_ON_ERROR prose reference, no defined bit/field)",
"gap": "Genuine spec-defect gap, matching c-RCP's own disposition verbatim (2026-08-22, cpp-RCP Phase 6 batch 11 (RMAP/SRV)): TC18 names EP_RESP_ON_ERROR in prose without ever defining where it lives on the wire. cpp-RCP additionally has a positive, already-tested defensive guarantee beyond c-RCP's own scope for this id -- ep_generic_cfg::render() never invents a bit for it (tests/test_regmap.cpp's \"ep_generic_cfg::render never sets a bit for the dangling EP_RESP_ON_ERROR reference\" TEST_CASE, tagged [REQ-RMAP-081]) -- but the underlying requirement (a real EP_RESP_ON_ERROR mechanism) remains genuinely unimplementable per the same spec silence c-RCP already confirmed, so this entry is filed as a gap rather than force-fit as implemented."
},
{
"id": "REQ-RMAP-068",
"title": "Register-write outcome: a read-only register succeeds silently, a write-prohibited register errors",
Expand Down
38 changes: 38 additions & 0 deletions .fusa-reqs.json
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,22 @@
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-SHMEM-009",
"title": "A Channel's state is freed exactly once regardless of shared_ptr release order",
"text": "A shmem::Channel's underlying state shall be freed exactly once, and only once every std::shared_ptr<Channel> holder has released it, regardless of the order in which holders release -- constructing, copying, and releasing shared_ptr<Channel> handles in either order shall neither crash nor leak, matching c-RCP's own refcounted rcp_avtp_transport_t contract (shmem.c:151-181).",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-SHMEM-010",
"title": "request() plays both the c-RCP send-side and recv-side ErrClosed role",
"text": "Channel::request() shall return ErrClosed once the Channel has been closed, regardless of which of c-RCP's own two separate shmem_side_send()/shmem_side_recv() roles a given call is standing in for -- a single request() call plays both the \"send\" and \"recv\" side of that split API, and each of c-RCP's own analogs independently reports RCP_ERR_CLOSED once its own side is closed (shmem.c:64-67/100-113,109-113).",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B"
},
{
"id": "REQ-TSN-001",
"title": "apply_priority sets SO_PRIORITY per RequestCategory",
Expand Down Expand Up @@ -4988,6 +5004,17 @@
"status": "implemented",
"tc18": "§11.2.2.7 (\"In any case the presentation_time is the earliest point in time, when the request shall be executed.\"), TC18.txt L1952"
},
{
"id": "REQ-TIMED-012",
"title": "A request carried under a TSCF header is postponed until its own presentation time",
"text": "rcp::server::Endpoint::admit()/admit_with_ack() shall, whenever the caller reports tv true (an enclosing TSCF header's own avtp_timestamp), postpone execution of the admitted request -- of any kind, Standard, Cancellation, or a conditional kind with its own start condition -- until avtp::extend_timestamp(avtp_timestamp, gptp_reference_now)'s reconstructed 48-bit instant is reached; select_due()/is_due() shall AND this envelope-level presentation gate with (not substitute for) each kind's own existing execution condition, and shall fail closed -- never report the request due -- whenever gptp_locked is false, regardless of how far in the past the gate's own instant already is.",
"standard": "iso26262",
"level": "ASIL-B",
"asil": "ASIL-B",
"scope": "tc18",
"status": "implemented",
"tc18": "§11.2, TC18.txt L1159; §11.2.1, TC18.txt L1204"
},
{
"id": "REQ-CANCEL-002",
"title": "encode_clear_all() encodes a zero-payload clear-all request",
Expand Down Expand Up @@ -11484,6 +11511,17 @@
"tc18": "§13.2 Table 28/31, TC18.txt L3570-3574",
"tc18_master_id": "TC18-13.2-001"
},
{
"id": "REQ-RMAP-081",
"title": "EP_RESP_ON_ERROR (Table 31 prose, IO-pin gauging error response) is a dangling spec reference",
"text": "PARTIAL, matching c-RCP's own disposition: TC18's own prose names a configuration parameter (EP_RESP_ON_ERROR) that Table 31 itself never actually defines a bit or field for -- a genuine, confirmed TC18 spec defect, not an addressable local gap. What IS implemented and tested: ep_generic_cfg::render() deliberately invents no bit for it -- both reserved spans of octet 1 (bits [3:1] and [7:6], mask 0xCE) stay zero for every input, including inputs deliberately chosen to be non-zero/extreme everywhere else. What remains open: a real EP_RESP_ON_ERROR mechanism itself, which TC18's own spec silence makes genuinely unimplementable, not merely unwired.",
"standard": "iso26262",
"level": "QM",
"asil": "QM",
"scope": "tc18-gap",
"status": "partial",
"tc18": "§13.2 Table 31 (EP_RESP_ON_ERROR prose reference, no defined bit/field)"
},
{
"id": "REQ-RMAP-082",
"title": "named_signal_string() returns \"unknown\" for an out-of-range value",
Expand Down
4 changes: 3 additions & 1 deletion .fusa.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
{
"version": "1",
"standard": "iso26262",
"asil": "ASIL-C",
"project": {
"name": "cpp-RCP",
"version": "3.0.0",
"module": "github.com/SoundMatt/cpp-RCP",
"standard": "iso26262",
"asil": "ASIL-B"
"asil": "ASIL-C"
},
"rules": {
"exclude": [],
Expand Down
26 changes: 19 additions & 7 deletions AUDIT_PACK.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**Document version**: 2.0.0
**Date**: 2026-07-28
**Standards**: ISO 26262 (ASIL-B), IEC 61508 (SIL-2), ISO 21434, IEC 62443 SL-2
**Standards**: ISO 26262 (ASIL-C — corrected from ASIL-B, see `HARA.md` H-001), IEC 61508 (SIL-2), ISO 21434, IEC 62443 SL-2

This revision (ROADMAP.md milestone 62, "Certification Refresh", v2.18.0)
supersedes the pre-replacement audit pack authored at milestone 43. All
Expand All @@ -28,9 +28,19 @@ across Phase 13-16 (v2.0.0-v2.17.0).

## 2. ASIL-D Gap Analysis (ISO 26262 §7)

cpp-RCP targets **ASIL-B** for the RC Client/RC Server communication
subsystem. The following table records deliberate derogations from
ASIL-D:
cpp-RCP targets **ASIL-C** for the RC Client/RC Server communication
subsystem (corrected from a previously-stated ASIL-B; see `HARA.md`'s
H-001 rationale — S3/E4/C2 maps to ASIL-C, not ASIL-B, and no
decomposition is claimed for it). The table and decomposition paragraph
below predate that correction and still frame this subsystem's
derogation from ASIL-D as an ASIL-B(D) = ASIL-A + ASIL-B decomposition —
per `HARA.md`'s own H-001 rationale, no such decomposition is actually
claimed (ASIL-C is met directly). **This section has not yet been
re-derived for an ASIL-C target and is flagged as a follow-up, not
resolved by this pass** — re-deriving which ASIL-D requirements still
warrant derogation, and on what rationale, at an ASIL-C (rather than
ASIL-B) target is a safety-case judgment call outside the scope of a
documentation-consistency fix.

| ASIL-D Requirement | Derogation Rationale | ASIL-B Coverage |
|--------------------|----------------------|-----------------|
Expand All @@ -39,9 +49,11 @@ ASIL-D:
| MISRA C++:2023 compliance | MISRA advisory rules selectively suppressed with justification | clang-tidy clean on safety-critical rules |
| 100% MC/DC structural coverage | 80% branch coverage enforced in CI | 80% branch + path coverage reported by `cpfusa coverage` |

ASIL decomposition: the RC Client/RC Server link is decomposed as
ASIL-B(D) = ASIL-A + ASIL-B per ISO 26262-9 §5 (independent channel
decomposition) — see `HARA.md`'s per-hazard decomposition rationale.
ASIL decomposition (pre-dates the ASIL-C correction above — see this
section's own flagged-follow-up note): the RC Client/RC Server link was
previously described as decomposed as ASIL-B(D) = ASIL-A + ASIL-B per ISO
26262-9 §5 (independent channel decomposition). `HARA.md`'s current
per-hazard rationale for H-001 claims no such decomposition.

---

Expand Down
37 changes: 23 additions & 14 deletions FORMAL_VERIFICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,29 @@ comparison against the high-water mark.
**STATUS CORRECTED 2026-08-21 (cpp-RCP issue #129 / RELAY Phase 17 Phase 2
pass) — two distinct corrections, both documentation-only:**

1. **Wiring gap, not algorithm gap.** This section previously implied
`RxSequenceGuard` — and by extension the SP1/SP2 properties verified
here — functions as a real, active mitigation for H-004. It does not:
`RxSequenceGuard` is **never instantiated anywhere outside its own unit
test** — not in `mock::Server`'s dispatch, and not in any transport
`Server`. SP1/SP2 are correctly verified properties of the
`RxSequenceGuard` *primitive itself*, but a formally-verified primitive
that nothing in this codebase calls provides no actual protection
against H-004 today. See `HARA.md`'s own corrected H-004 section for
the full account (mirroring c-RCP's own resolution of the identical
ambiguity, issues #601/#606). Wiring `RxSequenceGuard` into
`rcp/mock.hpp`'s dispatch is explicitly out of scope for this pass
(Phase 4/server-dispatch work) — this correction only makes this
section stop overstating what already-verified fact it establishes.
1. **Wiring gap, now closed for this codebase's own reference dispatch.**
This section previously stated that `RxSequenceGuard` was **never
instantiated anywhere outside its own unit test** — not in
`mock::Server`'s dispatch, and not in any transport `Server`. That was
accurate as of the 2026-08-21 pass that added this note, but is
superseded by Phase 4 batch C, "mock.hpp batch C — wire
RxSequenceGuard, StreamFaultTracker, RxWatchdog" (CHANGELOG.md, cpp-RCP
issue #129, PR #148): `rcp/mock.hpp`'s `Server` now holds a
`std::array<e2e::RxSequenceGuard, ...> seq_trackers_` member, and both
`Server::dispatch_e2e()` and `Server::dispatch_frame_e2e()` call it
(via a shared `seq_gate_admits()` helper) on every dispatched
request/frame before CRC unwrap — integration-tested in
`tests/test_mock.cpp` ("dispatch_e2e's sequence gate (REQ-E2E-028/029)
rejects a non-increasing sequence_num"), not merely the standalone
primitive's own `tests/test_e2e.cpp` unit test. See `HARA.md`'s own
corrected H-004 section and `include/rcp/e2e.hpp`'s file header
("UPDATE (Phase 4/Phase 17 batch C...)") for the full account
(mirroring c-RCP's own earlier resolution of the identical ambiguity,
issues #601/#606). SP1/SP2 as verified here are therefore properties of
a primitive that **is** now wired into this codebase's own reference
dispatch — with the same "an integrator bypassing `mock::Server`'s own
dispatch is on their own" caveat every primitive in this codebase
carries (see `HARA.md`'s H-004 Residual Risks entry).
2. **This spec models the pre-Phase-2-pass algorithm.** The same Phase 2
pass that produced this correction also content-corrected
`e2e::RxSequenceGuard`'s actual comparison rule against c-RCP's
Expand Down
Loading
Loading