fix(safety-docs): correct ASIL declaration + RxSequenceGuard/Zone-model staleness - #178
Merged
Conversation
…el staleness
Fixes three confirmed findings from the cpp-RCP v3.0.0 deep audit.
Finding A (HIGH) — .fusa.json project ASIL contradicted .fusa-hara.json:
- .fusa.json's project.asil was ASIL-B; H-001 (and SG-001/SG-003/SG-007)
in .fusa-hara.json are ASIL-C, with HARA.md's H-001 rationale
explicitly stating no decomposition is claimed. Corrected to ASIL-C.
- Discovered en route: the pinned cpp-FuSa v0.18.0 binary's config
loader (src/config/config.cpp) only reads a top-level "asil"/
"standard" key, never the nested "project.asil"/"project.standard"
this repo's .fusa.json schema used — so the HARA005 rule was silently
falling back to its own hardcoded "ASIL-B" default regardless of what
project.asil said (the previous ASIL-B value only ever "matched" by
coincidence). Added top-level "asil"/"standard" fields (matching
cpp-FuSa's own dogfooded .fusa.json) alongside the existing nested
ones so the pinned tool actually reads the corrected value. Verified:
`cpfusa check` before this fix reproduces "HARA005: Hazard ASIL
ASIL-C exceeds project ASIL ASIL-B" even after editing only the
nested field; after adding the top-level fields, `cpfusa check`
reports [iso26262/ASIL-C] and HARA005 no longer fires (0 errors,
1 pre-existing unrelated warning: FUSA004, missing evidence file).
- Propagated the same correction, with a one-line justification citing
HARA.md/H-001, to the other project-wide "target ASIL" declarations
found by grepping the repo: README.md, AUDIT_PACK.md (doc metadata +
intro sentence only — its ASIL-D-derogation/decomposition table and
math predate the correction and are explicitly flagged in-document as
a follow-up needing dedicated safety-case re-derivation, not resolved
here), TARA-ANALYSIS.md, and SAFETY_PLAN.md (also part of Finding C's
fix).
- Left narrowly-scoped ASIL-B claims alone (SG-002/004/005/006/008/010/
011 stay ASIL-B, matching .fusa-hara.json). Flagged as ambiguous and
deliberately NOT changed: README.md's per-header ASIL-B design-pattern
labels (watchdog.hpp/redundancy.hpp table rows) and
INCIDENT-RESPONSE.md's "ASIL-B requirement violation" severity
example — none clearly assert the project's own target ASIL.
- Not touched: safety-case.json/md, sas.json/md, sci.json, fmea.*,
tooling/tara.* — these are regenerated by `cpfusa safety-case`/etc. on
every tagged release (release.yml) and will pick up the corrected
ASIL automatically once regenerated; hand-editing them would just be
overwritten.
Finding B (HIGH) — HARA.md/FORMAL_VERIFICATION.md said RxSequenceGuard
was unwired; it has been wired since Phase 4 batch C:
- Verified directly against include/rcp/mock.hpp: Server holds a
seq_trackers_ member (std::array<e2e::RxSequenceGuard, ...>), and both
dispatch_e2e() and 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, not just
RxSequenceGuard's own standalone tests/test_e2e.cpp unit test.
include/rcp/e2e.hpp's own "UPDATE (Phase 4/Phase 17 batch C...)" file
header comment corroborates this as the authoritative account.
- Updated HARA.md's SG-004 row, full H-004 section, and its Residual
Risks table row from "not wired"/"effectively Open" to the current
"Mitigated (opt-in)" state (matching c-RCP's own disposition for its
equivalent mechanism), while being explicit that this covers
mock::Server's own reference dispatch — a caller driving a transport
Server with fully custom dispatch logic instead of wiring
mock::Server::dispatch_frame()/dispatch_frame_e2e() as the
FrameHandler is not automatically covered (per udp.hpp/l2.hpp's own
header notes on the correct integration path).
- Updated FORMAL_VERIFICATION.md's SP1/SP2 point 1 (the wiring-gap
claim) to match. Left point 2 (the TLA+ spec modeling the
pre-RFC-1982 algorithm) untouched — a separate, still-true, and
still-open issue unrelated to this finding.
- Did not touch H-004's S2/E3/C2/ASIL-B classification or any
coverage/testing claim beyond what mock.hpp/test_mock.cpp actually
show.
Finding C (HIGH) — SAFETY_PLAN.md still documented the retired
Zone/Command/Controller model:
- Verified all five dead requirement ids (REQ-CTRL-025/026/027/004,
REQ-ERR-011) are absent from .fusa-reqs.json, .fusa-reqs-pending.json,
and include/.
- "Zone mismatch detection" repointed to REQ-MOCK-010 ("dispatch to an
unmapped byte_bus_id reports invalid_parameter"), the real current
endpoint-addressing-validation mechanism in mock::Server::dispatch,
matching HARA.md's SG-002 "Addressed By" entry.
- "Deadline monitor" row's description reworded to drop "zone"/
"Config.Deadline" wording (REQ-DL-002 id was already correct).
- "Payload copy-on-send", "Payload copy-on-publish", and "Context /
deadline propagation" rows (also citing dead REQ-CTRL-026/027/004,
which the audit finding's own text named but its concrete fix
guidance didn't walk through): verified no current analog exists for
any of the three in the stream/endpoint/register-map wire-protocol
architecture (no in-process handler-invocation/pub-sub/context-
cancellation model remains). Marked "No direct analog" per instructions,
rather than inventing a false mapping.
- Also fixed the Safety Goals table in the same document (SG-001/003/007
ASIL-B -> ASIL-C per .fusa-hara.json, part of Finding A; "Commands"/
"CmdWatchdog"/"Dead zone" terminology retired in favor of the current
request/watchdog/RC-Server wording, part of Finding C) since it sits
directly above the mechanisms table and shares the identical root
causes (stale terminology + stale ASIL).
Verification: `python3 -c "import json; json.load(open('.fusa.json'))"`
passes. `cpfusa check`: HARA005 gone (0 errors, 1 pre-existing unrelated
warning). `cpfusa lint`: 146 warnings both before and after (git stash
diff) — unchanged, confirming no new findings from these doc/JSON edits.
`cpfusa trace`: pre-existing dangling-test-tag/no-LLR-children warnings
only, all in tests/*.cpp already unrelated to and untouched by this
batch.
Follow-ups noted, not resolved by this pass:
- AUDIT_PACK.md §2's ASIL-D gap-analysis derogation table and its
ASIL-B(D) = ASIL-A + ASIL-B decomposition math predate the ASIL-C
correction and need dedicated safety-case re-derivation (flagged
in-document).
- AUDIT_PACK.md §3's "ASIL-C upgrade path"/"80% ASIL-C target" MC/DC
wording now reads oddly against a project that already targets
ASIL-C; left untouched since the underlying coverage-gap facts are
unaffected and touching MC/DC threshold language felt too far outside
a documentation-consistency fix to do safely here.
- .fusa-hara.json itself has a latent, separate inconsistency (H-003
and H-005 are rated ASIL-B as hazards, but their own safety goals
SG-003/SG-007 are rated ASIL-C) discovered while reading the file for
this batch; out of scope for these three findings, noted for a future
pass.
- No new requirement ids were invented.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Matt <47545907+SoundMatt@users.noreply.github.com>
…talog entries
The prior commit on this branch correctly raised .fusa.json's declared
ASIL from B to C. That bump surfaced four `// fusa:test REQ-ID`
tags in tests/test_shmem.cpp, tests/test_regmap.cpp, and
tests/test_server.cpp whose ids had no corresponding entry in
.fusa-reqs.json:
- REQ-SHMEM-009 (tests/test_shmem.cpp:9, TEST_CASE ~line 482):
a Channel's underlying state is freed exactly once regardless of
std::shared_ptr<Channel> release order.
- REQ-SHMEM-010 (tests/test_shmem.cpp:10, TEST_CASE ~line 181):
Channel::request() returns ErrClosed after close(), playing both
the "send" and "recv" role of c-RCP's split shmem_side_send()/
shmem_side_recv() API.
- REQ-RMAP-081 (tests/test_regmap.cpp:37, TEST_CASE ~line 828):
already staged in .fusa-reqs-pending.json as a spec-defect gap
(TC18's own EP_RESP_ON_ERROR prose reference is never given a
wire field by Table 31), but never migrated into the confirmed
catalog despite carrying a real, tested defensive guarantee
(ep_generic_cfg::render() invents no bit for it). Migrated here
with status "partial", matching the REQ-RMAP-067 precedent for a
confirmed-gap-but-tested entry, and removed from the pending file
per its own migration rule (real impl+test tags now exist).
- REQ-TIMED-012 (tests/test_server.cpp:45, TEST_CASE ~line 1143):
also staged in .fusa-reqs-pending.json, marked "confirmed absent"
-- but that analysis is stale. rcp::server::Endpoint::admit()/
admit_with_ack()/admit_under_tscf_gate()/select_due() (server.hpp)
already implement and test full TSCF presentation-time admission
end-to-end (the pending entry's own grep for a
dispatch-tscf/admit-gate equivalent evidently missed this code's
actual naming). Migrated to the confirmed catalog as implemented
and removed from pending.
Verification (all via the pinned /tmp/cpfusa/build/cpfusa, matching
the exact CI invocations in .github/workflows/ci.yml):
- `cpfusa trace` (bare, the blocking "Traceability check" step):
the four dangling //fusa:test references are gone -- confirmed
zero remaining, and all four new ids resolve impl:[✓] test:[✓].
`cpfusa check`, `cpfusa lint`, and `cpfusa trace --req-coverage
100` are unchanged before/after (byte-identical output modulo
timestamps for check/lint; trace --req-coverage 100 mirrors
trace's own diff exactly).
IMPORTANT CAVEAT discovered during verification: `cpfusa trace`'s
exit code is still 1 after this fix, and this fix cannot make it 0.
Reading cpfusa's own source (src/trace/trace.cpp, src/cmd/cli.cpp)
shows the bare `trace` subcommand's only exit(1) path is
`result.hlr_gate_failed`, which is driven entirely by a separate
HLR/LLR two-tier decomposition check ("WARN: HLR ... has no LLR
children"), promoted from warn-only to a hard gate whenever the
project's declared ASIL is C or D. Dangling //fusa:test references
are WARNING-level only and never gate the exit code, at any ASIL --
confirmed by grepping cli.cpp's trace callback and by reproducing
before/after: reverting only .fusa.json's asil to B (not committed,
diagnostic only) yields exit 0 with this fix in place, while ASIL-C
+ this fix still yields exit 1 with zero dangling refs. This
project's .fusa-reqs.json has never populated parent_id, so every
requirement is its own childless "HLR" (HLR-covered: 0/1137 both
before and after this commit) -- already flagged as a known,
unaddressed gap in ARCHITECTURE.md's schema-compat table ("the tool
also expects an HLR/LLR two-tier hierarchy this repo's schema
doesn't populate ... needs its own investigation"). Closing that gate
requires a much larger, separate effort (retrofitting parent_id
across the whole requirements catalog, or an explicit tooling
decision) and is out of scope for this additive four-entry backfill.
PR #178's CI will still fail the "Traceability check" step after
this commit for that unrelated, pre-existing reason.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Matt <47545907+SoundMatt@users.noreply.github.com>
17 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes three confirmed HIGH findings from the cpp-RCP v3.0.0 deep audit, verified individually against source before editing.
Finding A —
.fusa.jsonproject ASIL contradicted.fusa-hara.json.fusa.json'sproject.asilwasASIL-B, but.fusa-hara.json's H-001 (and its safety goals SG-001/SG-003/SG-007) areASIL-C, andHARA.md's H-001 rationale explicitly states no decomposition is claimed — S3/E4/C2 maps to ASIL-C directly.Fix:
.fusa.json'sasil/project.asilcorrected toASIL-C.Tooling bug discovered en route: the pinned
cpp-FuSav0.18.0 binary's config loader (src/config/config.cpp) only reads a top-levelasil/standardkey — never the nestedproject.asil/project.standardthis repo's.fusa.jsonschema used. SoHARA005was silently falling back to the tool's own hardcoded"ASIL-B"default regardless of whatproject.asilsaid; the previousASIL-Bvalue only ever "matched" that default by coincidence. Confirmed by editing only the nested field first —cpfusa checkstill printedHARA005: Hazard ASIL ASIL-C exceeds project ASIL ASIL-B. Fixed by adding top-levelasil/standardfields (matchingcpp-FuSa's own dogfooded.fusa.json) alongside the existing nested ones.Verified:
cpfusa checknow reports[iso26262/ASIL-C]and HARA005 no longer fires (0 errors, 1 pre-existing unrelated warning —FUSA004, missing evidence file, expected without a test run).Docs updated (project-wide "target ASIL" statements only, each with a one-line justification citing HARA.md/H-001):
README.md,AUDIT_PACK.md(doc metadata + intro sentence only — see follow-ups),TARA-ANALYSIS.md,SAFETY_PLAN.md.Left alone (narrowly-scoped, correctly ASIL-B per
.fusa-hara.json): SG-002/004/005/006/008/010/011.Flagged as ambiguous, deliberately not changed:
README.md's per-header "(ASIL-B)" design-pattern labels (watchdog.hpp/redundancy.hpprows),INCIDENT-RESPONSE.md's "ASIL-B requirement violation" severity example — neither clearly asserts the project's own target ASIL.Not touched:
safety-case.json/md,sas.json/md,sci.json,fmea.*,tooling/tara.*— these are regenerated bycpfusa safety-case/etc. on every tagged release (release.yml) via a bot PR and will pick up the corrected ASIL automatically; hand-editing would just be overwritten.Finding B —
HARA.md/FORMAL_VERIFICATION.mdsaid RxSequenceGuard was unwired; it's been wired since Phase 4 batch CVerified directly against
include/rcp/mock.hpp:Serverholds aseq_trackers_member (std::array<e2e::RxSequenceGuard, ...>), and bothdispatch_e2e()anddispatch_frame_e2e()call it via a sharedseq_gate_admits()helper on every dispatched request/frame before CRC unwrap — integration-tested intests/test_mock.cpp, not justRxSequenceGuard's own standalonetests/test_e2e.cppunit test.include/rcp/e2e.hpp's own "UPDATE (Phase 4/Phase 17 batch C...)" file-header comment corroborates this as the authoritative account.Fix: updated
HARA.md's SG-004 row, full H-004 section, and its Residual Risks row from "not wired"/"effectively Open" to the current "Mitigated (opt-in)" state (matching c-RCP's own disposition for its equivalent mechanism) — while being explicit this coversmock::Server's own reference dispatch; a caller driving a transportServerwith fully custom dispatch logic instead of wiringmock::Server::dispatch_frame()/dispatch_frame_e2e()as theFrameHandlerisn't automatically covered (perudp.hpp/l2.hpp's own header notes). UpdatedFORMAL_VERIFICATION.md's SP1/SP2 point 1 to match; left point 2 (the TLA+ spec modeling the pre-RFC-1982 algorithm — a separate, still-true, still-open issue) untouched.Did not change H-004's S2/E3/C2/ASIL-B classification or claim anything about coverage/testing beyond what
mock.hpp/test_mock.cppactually show.Finding C —
SAFETY_PLAN.mdstill documented the retired Zone/Command/Controller modelVerified all five dead requirement ids (
REQ-CTRL-025/026/027/004,REQ-ERR-011) are absent from.fusa-reqs.json,.fusa-reqs-pending.json, andinclude/.REQ-MOCK-010("dispatch to an unmapped byte_bus_id reports invalid_parameter"), the real current endpoint-addressing-validation mechanism, matchingHARA.md's SG-002 "Addressed By" entry.REQ-DL-002id was already correct)..fusa-hara.json, part of Finding A; "Commands"/"CmdWatchdog"/"Dead zone" terminology retired, part of Finding C) since it sits directly above the mechanisms table and shares the identical root causes.Verification
python3 -c "import json; json.load(open('.fusa.json'))"— passes.cpfusa check— HARA005 gone; 0 errors, 1 pre-existing unrelated warning.cpfusa lint— 146 warnings both before and after (git stashdiff) — unchanged, confirming no new findings from these doc/JSON edits.cpfusa trace— pre-existing dangling-test-tag/no-LLR-children warnings only, all intests/*.cpp, unrelated to and untouched by this batch.Follow-ups flagged, not resolved by this pass
AUDIT_PACK.md§2's ASIL-D gap-analysis derogation table and itsASIL-B(D) = ASIL-A + ASIL-Bdecomposition math predate the ASIL-C correction and need dedicated safety-case re-derivation (flagged in-document with an explicit note).AUDIT_PACK.md§3's "ASIL-C upgrade path"/"80% ASIL-C target" MC/DC wording now reads oddly against a project that already targets ASIL-C; left untouched since the underlying coverage-gap facts are unaffected and touching MC/DC threshold language felt too far outside a documentation-consistency fix..fusa-hara.jsonitself has a latent, separate inconsistency discovered while reading it for this batch: H-003 and H-005 are ratedASIL-Bas hazards, but their own safety goals SG-003/SG-007 are ratedASIL-C. Out of scope for these three findings; noted for a future pass.This closes 3 findings from the cpp-RCP v3.0.0 deep audit.