Skip to content

Arc Safety Case

This file is an engineering evidence map, not a functional-safety certificate. Arc is not certified to MISRA C++:2023, ISO 26262, IEC 61508, DO-178C, or any life-critical product standard. A product using Arc still needs its own hazard analysis, process evidence, traceability, review records, tool qualification, hardware validation, and certification authority acceptance.

Scope

The current safety case only covers the Arc repository's ESP32-S3 firmware substrate:

  • public headers under components/arc/include
  • CMake dependency mapping under cmake/
  • host tests and static repo checks under tools/
  • lightweight formal specs under specs/
  • documented HIL shape in docs/hil-test-jig.md

Application policy, external wiring, sensors, actuators, enclosure safety, network service policy, operator procedures, and any product-specific failsafe remain outside Arc.

Claims And Evidence

ClaimEvidence
Target selection is explicit and cannot silently drift away from ESP32-S3.cmake/arc-idf.cmake, env.sh, env.fish, tools/check-repo.sh, and CI guards reject missing target declarations and idf.py set-target docs.
Public headers compile under the actual ESP-IDF component graph.tools/clangd-compile-commands.py --validate-arc-headers validates public Arc headers from generated compile databases.
Realtime loop entry points are kept away from known blocking, heap, queue send/receive/peek, task delay/suspend, timer-pend, task-notify wait, and logging calls.go run tools/arc-audit.go -root . -all is run by tools/check-repo.sh.
Core-local state can carry its AMP owner and scoped callback leakage checks in the C++ type.arc::CoreLocal<T, Core> exposes copy-out snapshot(), owner-inferred set(value) / with(fn) / msg<To>() / accept(msg) helpers, CoreLocal::Msg<To> / Incoming<From> message contracts, public CoreLocalType / CoreMsgType concepts, and explicit scoped with<Core>(fn) callbacks only to the owner core template argument, rejects reference/pointer/reference-wrapper/non-owning-view results and standard/result wrappers containing them, and arc::CoreMsg<T, From, To> exposes payload snapshots and scoped destination reads with the same callback-return checks; both CoreLocal and CoreMsg reject direct borrowed-storage payload carriers, with compile-contract checks in tests/host/logic.cpp and negative cases in tools/compile-fail-check.py.
Static application state can carry static lifetime, access mode, optional core owner, same-contract alias checks, and scoped callback leakage checks in the C++ type.components/arc/include/arc/borrow.hpp implements arc::StaticRef, arc::StaticLoan, copy-out snapshot() / snapshots() helpers, whole-value set(value), arc::StaticReads, arc::StaticWrites, arc::StaticEdit, arc::LoanPack, and scoped with_read/with_reads/with_write/with_edit helpers over static objects, including StaticRef::Reads<...> / StaticRef::Edit<...> contracts plus member StaticRef::snapshots<ReadRefs...>(), StaticRef::with_reads<ReadRefs...>(fn), and StaticRef::with_edit<ReadRefs...>(fn) for owner-anchored scopes, with callback checks rejecting reference/pointer/reference-wrapper/non-owning-view/static-loan returns and standard/result wrappers containing them, compile-contract checks in tests/host/logic.cpp, tests/host/safety_patterns_compile.cpp, and negative compile cases in tools/compile-fail-check.py.
Queue, fan-in, RPC, and flow payloads reject direct borrowed-storage carriers at the type boundary.components/arc/include/arc/spsc.hpp, components/arc/include/arc/mpsc.hpp, components/arc/include/arc/fanin.hpp, components/arc/include/arc/rpc.hpp, and components/arc/include/arc/flow.hpp require copied payload values and reject pointer/reference-wrapper/non-owning-view payloads plus standard/result wrappers containing them, with negative compile cases in tools/compile-fail-check.py.
Queue and fan-in ownership can be narrowed at setup boundaries.arc::Spsc, arc::Mpsc, arc::Fanin, and their arc::Audit<...> wrappers expose producer/consumer role endpoints with host coverage in tests/host/logic.cpp.
Queue, fan-in, and RPC direct mutation can be removed from the static type surface.arc::Roles<Lane> owns a lane privately, exposes only role endpoints such as producer/consumer or client/server, offers role endpoint concepts such as PushRole, PopRole, RpcClientRole, and RpcServerRole, and scopes role callbacks so captured endpoint/reference/pointer/reference-wrapper/non-owning-view returns and standard/result wrappers containing them fail, with compile-contract checks and host coverage in tests/host/logic.cpp, tests/host/safety_patterns_compile.cpp, and tools/compile-fail-check.py.
DMA descriptor binding rejects invalid topology before handoff.components/arc/include/arc/dma_chain.hpp implements checked arc::DmaChain::try_bind for descriptor indexes, hardware-sized lengths, and optional arc::CacheLines coherent regions, with host coverage in tests/host/logic.cpp.
DMA descriptor buffers can be owned beside their descriptors.components/arc/include/arc/dma_chain.hpp implements arc::OwnedDmaChain, which allocates DMA-capable arc::CapsBuf storage and binds descriptors to those owned buffers, with host coverage in tests/host/logic.cpp.
DMA/cache handoff avoids unaligned invalidation by default.components/arc/include/arc/cache.hpp makes arc::Cache::from_device and discard require whole cache lines; from_raw and discard_raw are unavailable unless ARC_ENABLE_UNSAFE_CACHE_RAW=1 and arc::unsafe_raw are used deliberately.
Cache-line handoff regions can be validated once and reused.components/arc/include/arc/cache.hpp exposes arc::Cache::lines and arc::CacheLines for aligned whole-line regions, with host coverage in tests/host/logic.cpp.
DMA cache ownership can be carried in the C++ type when using Arc-owned buffers.components/arc/include/arc/cache.hpp implements arc::DmaBuf<T, arc::CacheState>, whose CPU state exposes spans and whose device state only exposes handoff metadata until from_device() succeeds, with host coverage in tests/host/logic.cpp.
Async DMA copy completion can be bound to scope.arc::Copy::lease_coherent returns move-only leases that finish the exact ticket on explicit finish() or destruction, with host coverage in tests/host/logic.cpp.
Async DMA buffer lifetime can be structurally owned for Arc-allocated DMA slabs.components/arc/include/arc/copy.hpp implements arc::Copy::lease_coherent(std::move(dst), std::move(src)), which moves arc::CapsBuf storage into the active lease so the transfer owns both buffers until finish or destruction.
SDIO slave DMA queue and finish can be bound to one coherent buffer lifetime.components/arc/include/arc/sdio_slave.hpp implements arc::SdioSlave::lease_coherent, which queues only strict cache-line buffers and invalidates them on finish, with host coverage in tests/host/logic.cpp.
Hardware crypto DMA completion can be bound to scope.components/arc/include/arc/crypto_dma.hpp implements arc::CryptoDma::lease, with bounded-wait and explicit-finish host coverage in tests/host/logic.cpp.
Workloads can carry source-visible proof metadata beside a measured cycle budget.components/arc/include/arc/proof.hpp implements arc::proof::Pack, arc::proof::Fact, common fact aliases, and subject-specific compile-time claim queries, with host coverage in tests/host/logic.cpp.
Formal-model files have at least structural coverage in every repo policy run.tools/check-repo.sh runs tools/arc-prove.sh, which validates required TLA+ modules such as specs/Spsc.tla, specs/Roles.tla, and specs/Consensus.tla, checks the SPSC model head/tail names against components/arc/include/arc/spsc.hpp, and uses Apalache or TLC when available.
Moved-from handle misuse has static-analysis coverage on the host compile surface.tools/check-repo.sh runs tools/use-after-move-check.sh, which invokes clang-tidy with bugprone-use-after-move as an error when the tool is available; intentional moved-from state probes in tests/host/logic.cpp must carry narrow NOLINT annotations.
HIL evidence has a machine-checkable artifact shape.docs/hil-test-jig.md defines the required physical cases, and tools/hil-evidence-check.py --format json validates captured JSONL artifacts before they are used as board evidence.
Safety claims stay tied to live repo evidence and non-claims.tools/check-repo.sh runs tools/safety-case-check.py, which verifies claim evidence paths, required evidence commands, non-claim coverage, and certification-overclaim wording; tools/safety-case-check.py --format report and --format json emit the same claim/path/command map as human or structured release evidence.

Required Local Evidence

Use Safety Patterns when writing the first local ownership contract for a task or module. This safety case is the evidence map after the contract exists.

Run these before treating a safety-relevant Arc change as reviewed:

bash
./tools/check-repo.sh
./tools/host-tests.sh
./tools/arc-prove.sh
python3 tools/compile-fail-check.py
./tools/clangd-compile-commands.py --validate-arc-headers --changed-arc-headers HEAD -o /tmp/arc_compile_commands.json

Use ./tools/safety-case-check.py --format report when a human review needs the claim/path/command/non-claim map, or --format json when the same evidence must be consumed by release tooling. Use python3 tools/compile-fail-check.py --format report when a human review needs the grouped negative borrow-check case list, or --format json when the same evidence must be consumed by release tooling.

For broad include or dependency changes, also run full public-header validation:

bash
./tools/clangd-compile-commands.py --validate-arc-headers -o /tmp/arc_compile_commands.json

Firmware-facing changes still need the relevant ESP-IDF firmware build and, for hardware behavior, board logs or HIL evidence. Passing host checks alone is not evidence for electrical safety, timing margins on a real board, or product hazard mitigation.

Non-Claims

Arc does not claim:

  • certification for aerospace, automotive, medical, industrial control, or other regulated life-critical deployment
  • whole-program C++ lifetime safety equivalent to a borrow checker
  • proof that application-owned std::span objects outlive every asynchronous hardware transaction
  • safety of raw ESP-IDF driver interop adopted outside Arc's ownership wrappers
  • safety of board wiring, external actuators, RF exposure, optics, ultrasonics, motor drives, or operator workflows
  • security certification for cryptographic key lifecycle, provisioning policy, update provenance, or cloud/backend infrastructure

Any product that needs those claims must build a separate product safety case on top of Arc and keep Arc's evidence as only one input.

ESP32-S3 first. ESP-IDF native. Static ownership by default.