{
  "schema_version": 1,
  "status": "Proposed S-CORE rules, not approved or enforced",
  "rules": [
    {
      "id": "SCR-RUST-001",
      "title": "Define the supported Rust language and build configuration",
      "misra_cpp_ids": [
        "4.1.1"
      ],
      "scope": "All production crates and their build inputs",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Each component shall record its compiler/toolchain revision, the language specification revision used as the reference for that toolchain (for example a Ferrocene Language Specification revision, with relevant known differences noted), Rust edition, target, dependency resolution, enabled features, panic strategy and overflow-check settings. Production builds shall use this controlled configuration. Stable toolchains reject unstable features; where a nightly or custom toolchain is permitted, the assessment shall list the permitted unstable features and the assumptions relied on. Links to the existing configuration and assessment records satisfy this requirement.",
      "enforcement": "Check manifests, lockfiles and Bazel toolchain/configuration in CI; review language and target assumptions against the referenced specification and the compiler documentation.",
      "coverage_limit": "A successful build does not establish tool qualification. Reconcile Cargo and Bazel inputs; a host-only build does not cover QNX or a different feature set.",
      "summary": "Pin the toolchain, edition, target, features, panic strategy and overflow settings for every production build, and record which language specification the toolchain follows.",
      "rationale": "Rust has no single frozen language standard. What a program means depends on the compiler release, the edition and the build settings. A behaviour verified on one configuration is not verified on another, and an unstable feature can change under you."
    },
    {
      "id": "SCR-RUST-002",
      "title": "Enforce selected diagnostics and control suppressions",
      "misra_cpp_ids": [
        "0.0.1",
        "0.2.1",
        "0.2.2",
        "0.2.3",
        "0.2.4",
        "4.1.2"
      ],
      "scope": "All first-party production crates",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "The adopted lint profile shall make selected unused-code, unused-value, unreachable-code and deprecated-API diagnostics blocking. Any suppression shall identify a scoped rationale and rule/deviation. Suppressions inherited from generated or third-party code shall be recorded separately.",
      "enforcement": "Candidate rustc lints: dead_code, unused_variables, unused_assignments, unreachable_code, unused_must_use and deprecated. Verify flags actually reach every Bazel and Cargo analysis action.",
      "coverage_limit": "Warnings are not hard language guarantees. These diagnostics are partial, especially for semantic unreachability, public APIs and feature-disabled code. Do not equate a warning-free build with complete coverage of the mapped rules.",
      "summary": "Turn the agreed unused-code, unreachable-code and deprecated-API warnings into errors, and make every suppression name its reason.",
      "rationale": "Warnings are only enforcement if the build fails on them. A warning that is allowed away, or that never reaches the Bazel action, provides no evidence. Dead and unreachable code hides logic errors and makes review harder."
    },
    {
      "id": "SCR-RUST-003",
      "title": "Avoid invariant decisions and ineffective writes",
      "misra_cpp_ids": [
        "0.0.2",
        "0.1.1"
      ],
      "scope": "Production control flow",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "A condition shall express a decision whose outcome can differ at runtime for inputs the component accepts. A condition whose outcome is fixed is a violation, whether it is a constant expression or fixed by construction, such as testing a value just assigned from a literal or comparing an integer with itself (floating-point self-comparison is not fixed, since ``x == x`` is false for NaN). Designated configuration choices (a ``cfg`` predicate or a named constant flag) and intentional loops with an explicit exit are permitted. A value shall not be written and then overwritten or dropped before any observation; this covers assignments overwritten before being read and owning values replaced before being observed. Replacing an owning value runs its ``Drop``, so such a write is unnecessary only when neither the value nor its destructor effect is required.",
      "enforcement": "rustc unused_assignments; selected Clippy condition/comparison checks; candidate CodeQL control-flow and value-use analysis; review intentional constant branches.",
      "coverage_limit": "Local diagnostics do not establish path feasibility or detect every overwritten value across calls, and unused_assignments does not consider destructor effects. Record intentional loop and configuration exceptions.",
      "level_rationale": "Required although both sources are Advisory: an invariant condition or an ineffective write usually indicates a logic defect, the consequence in Rust is the same as in C++, and compiler and Clippy checks make conformance cheap to demonstrate.",
      "example": {
        "compliant": "const MAX_FRAME: usize = 1024;\n\n// Compliant: the outcome depends on runtime input.\nfn accept(frame: &[u8]) -> Result<(), ()> {\n    if frame.len() > MAX_FRAME { return Err(()); }\n    Ok(())\n}",
        "non_compliant": "// Non-compliant: the condition is fixed by construction.\nfn accept(frame: &[u8]) -> Result<(), ()> {\n    let ready = true;\n    if ready { return Ok(()); }\n    Err(())\n}",
        "note": "Both compile. The first decides on the accepted input; the second always takes the first branch, so the else path is dead and the decision is meaningless unless ``ready`` is a documented configuration flag."
      },
      "summary": "Do not write conditions whose outcome cannot change at runtime, and do not write values that are overwritten or dropped before anyone reads them.",
      "rationale": "A fixed condition means one branch is dead and the decision it pretends to make does not exist. An overwritten write usually means a forgotten use or a wrong variable. In Rust, replacing an owning value also runs its destructor, so the write can have an effect you did not intend.",
      "adaptation_notes": "Adapts 0.0.2 (invariant controlling expressions) and 0.1.1 (dead writes). The object scope is widened from trivially destructible C++ objects to all Rust values, since replacing an owning value runs ``Drop``."
    },
    {
      "id": "SCR-RUST-004",
      "title": "Handle results and preserve error information",
      "misra_cpp_ids": [
        "0.1.2"
      ],
      "scope": "Production APIs and their callers",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Non-unit results of explicit function and method calls shall be used or deliberately discarded under the project's reviewed discard convention, for example a ``let _ =`` binding with a comment naming why the value is not needed. ``#[must_use]`` contracts apply in addition, including to functions returning unit. Errors shall be propagated, converted with necessary context, or handled according to the API's documented error-handling contract. A ``Result`` is critical when that contract states that the error requires action by the caller; discarding a critical error through ``let _``, ``drop``, ``.ok()``, a default value or a catch-all branch is prohibited unless the branch implements the documented recovery. Project APIs shall carry ``#[must_use]`` where omission is a defect and shall document which errors require action and what handling is acceptable.",
      "enforcement": "rustc unused_must_use and selectively unused_results; Clippy let_underscore_must_use; candidate CodeQL checks for project error-discard patterns; review recovery paths.",
      "coverage_limit": "``#[must_use]`` checks that a result is used, not that it is handled meaningfully. Whether ``.ok()`` or a catch-all branch discards or recovers rests on the API contract, which no lint can judge; broad unused_results can flag intentional side-effect APIs.",
      "summary": "Use every non-unit result or discard it deliberately with a visible reason, and never silently throw away an error the API says you must act on.",
      "rationale": "``Result`` makes errors visible, but ``let _ =``, ``.ok()`` and a catch-all arm make them invisible again. ``#[must_use]`` only tells you a value was ignored. Whether ignoring is acceptable depends on what the API's error contract says.",
      "adaptation_notes": "Adapts 0.1.2, which covers explicit function-call syntax and excludes operator syntax; an explicit ``let _ =`` with a reason is the Rust analogue of the void cast counting as use."
    },
    {
      "id": "SCR-RUST-005",
      "title": "Define floating-point range and precision contracts",
      "misra_cpp_ids": [
        "0.3.1"
      ],
      "scope": "Floating-point calculations, conversions and persistence",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Safety-relevant floating-point calculations shall be covered by a numerical contract that specifies acceptable range, precision, rounding, comparison tolerance, handling of NaN, infinity and signed zero, and serialization guarantees. One shared contract may cover all calculations it applies to, for example at a module or API boundary, provided each calculation is traceable to it. Serialization shall preserve the required information or reject values that cannot meet the contract.",
      "enforcement": "Selected Clippy floating-point/cast checks; boundary and round-trip tests; numerical review. Candidate CodeQL checks can locate values reaching sensitive conversion APIs.",
      "coverage_limit": "A lint cannot select application tolerances or prove numerical accuracy. Components that store integers as f64 (for example in a JSON backend) need an explicit round-trip contract.",
      "level_rationale": "Required although Directive 0.3.1 is Advisory: unspecified floating-point range, precision or special-value handling produces silent numerical error in stored and compared values, which is a safety consequence rather than a style concern.",
      "summary": "Write down the numerical contract for safety-relevant floating-point code: range, precision, rounding, tolerance, NaN and infinity handling, and what serialization preserves.",
      "rationale": "Floating-point arithmetic is approximate and ``f64`` cannot represent every integer or decimal exactly. Without a stated contract there is no way to test whether a comparison tolerance or a stored value is correct, and the error is silent.",
      "adaptation_notes": "Adapts Directive 0.3.1; the shared-contract permission is an S-CORE choice."
    },
    {
      "id": "SCR-RUST-006",
      "title": "Validate preconditions at trust boundaries",
      "misra_cpp_ids": [
        "0.3.2"
      ],
      "scope": "Public APIs, external data, stored data and unsafe wrappers",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "A function shall be called only when its documented preconditions hold. Encode invariants in validated types where possible; otherwise validate untrusted values before use and return a defined error. Stored data shall be treated as potentially malformed.",
      "enforcement": "Type/API review and negative tests; candidate CodeQL source-to-use checks with explicitly modeled validators and error paths.",
      "coverage_limit": "A validation call is not sufficient evidence unless the checked property and success branch match the precondition. Arbitrary application contracts require review.",
      "example": {
        "compliant": "// Compliant for this input contract: an untrusted rate is valid only in 1..=10.\nfn rate(raw: u8) -> Result<u8, ()> {\n    if (1..=10).contains(&raw) { Ok(raw) } else { Err(()) }\n}",
        "non_compliant": "// Non-compliant: accepts out-of-range input.\nfn rate(raw: u8) -> Result<u8, ()> {\n    Ok(raw)\n}",
        "note": "Both compile. Only the first rejects input outside the documented precondition."
      },
      "summary": "Only call a function when its documented preconditions hold; validate untrusted and stored input first and return an error otherwise.",
      "rationale": "The type system cannot express every precondition. A safe function that reads out of range on an unexpected input is still a defect, and a safe wrapper around ``unsafe`` that trusts its caller can make the whole program unsound."
    },
    {
      "id": "SCR-RUST-007",
      "title": "Isolate unsafe operations and establish their contracts",
      "misra_cpp_ids": [
        "4.1.3"
      ],
      "scope": "Unsafe code, unsafe traits/attributes, safe wrappers and their dependencies",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Undefined behavior is prohibited. Unsafe operations shall be confined to identified modules and justified by operation-specific invariants covering validity, lifetime, aliasing, alignment and concurrency as applicable. Safe APIs shall preserve soundness for all permitted safe callers. Crates designated safe-only shall forbid unsafe_code.",
      "enforcement": "rustc unsafe_op_in_unsafe_fn; Clippy missing_safety_doc and undocumented_unsafe_blocks; independent unsafe review; targeted Miri and applicable verification.",
      "coverage_limit": "Documentation checks establish presence, not correctness. Miri covers supported executed paths. A crate with no unsafe blocks may still rely on unsafe dependencies; panic freedom is a separate property.",
      "example": {
        "compliant": "// Compliant: handles every slice length without unsafe access.\nfn first(input: &[u8]) -> Option<u8> {\n    input.first().copied()\n}",
        "non_compliant": "// Non-compliant: the safe API permits an invalid read for input = &[].\nfn first(input: &[u8]) -> Option<u8> {\n    Some(unsafe { *input.as_ptr() })\n}",
        "note": "Both function bodies compile. An empty slice is a valid input to either safe function; Miri accepts the first and reports undefined behavior for the second on an empty slice. A safe wrapper must be sound for every input its signature admits."
      },
      "summary": "Keep ``unsafe`` in identified modules, document the invariant each unsafe operation relies on, and make sure every safe wrapper is sound for every input its signature allows.",
      "rationale": "``unsafe`` turns off the compiler's guarantees for that block. Undefined behaviour is not a crash you can catch; it can corrupt data silently anywhere in the program. A safe API that is unsound makes every caller unsafe without them knowing."
    },
    {
      "id": "SCR-RUST-008",
      "title": "Control shared state and memory ordering",
      "misra_cpp_ids": [
        "6.7.1",
        "6.7.2"
      ],
      "scope": "All shared state, including Mutex, atomics and unsafe implementations",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Shared mutable state shall have a documented owner, initialization protocol and synchronization design. The rule covers every item reachable from more than one thread, or from more than one function through a shared path, including ``static`` items without ``mut`` whose type provides interior mutability (``Mutex``, ``RwLock``, atomics, ``OnceLock``, ``UnsafeCell``) and ``thread_local!`` storage. ``const`` items, ``static`` items of types without interior mutability, and locals that never escape their function are excluded. ``static mut`` is prohibited in first-party production code. A reviewed exception requires single-writer or externally synchronized access documented at the declaration, no references to the item, and raw-pointer access confined to the owning module. Each use of shared globals, atomics and unsafe ``Send``/``Sync`` shall justify ordering and lifecycle assumptions. Lock ordering and reentrancy constraints shall be documented.",
      "enforcement": "Compiler trait checks; rustc static_mut_refs (deny by default in edition 2024) for references to mutable statics; a syntax check for ``static mut`` declarations; shared-state inventory, unsafe review and concurrency tests; candidate checks for global-state access and unsafe trait implementations.",
      "coverage_limit": "Safe Rust prevents many data races under soundness assumptions but does not prevent deadlocks, logical races or incorrect atomic protocols. static_mut_refs catches references, not declarations or raw-pointer uses; the declaration ban needs its own check.",
      "summary": "Give every piece of shared mutable state an owner, an initialization protocol and a synchronization design. Do not use ``static mut`` in production code.",
      "rationale": "Rust prevents data races in safe code, but not deadlocks, lock-order inversions, wrong atomic orderings or logically racy protocols. A ``static`` without ``mut`` can still be mutated through a ``Mutex`` or an atomic, and ``static mut`` has no protection at all.",
      "adaptation_notes": "Adapts 6.7.1 and 6.7.2. The C++ exclusions for ``const``/``constexpr`` objects correspond to ``const`` items and ``static`` items without interior mutability; a ``static`` holding a ``Mutex`` or atomic is in scope. The first-party ``static mut`` ban with reviewed exceptions is the S-CORE policy choice."
    },
    {
      "id": "SCR-RUST-009",
      "title": "Remove disabled code from comments",
      "misra_cpp_ids": [
        "5.7.1",
        "5.7.2"
      ],
      "scope": "Production source comments",
      "proposed_level": "Advisory",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Obsolete implementations shall be removed and recovered through version control when needed, rather than parked in comments or behind permanently false or undeclared ``cfg`` predicates. Supported feature, target and test configurations are intentional conditional compilation and are not affected. Nested block comments shall not be used to disable code, since Rust nests ``/* */`` and a stray delimiter can hide a whole section; a block comment containing code shall be a documentation example or explanatory pseudocode. Comments should explain intent and constraints.",
      "enforcement": "Code review; a comment-pattern checker may identify candidates; rustc unexpected_cfgs with check-cfg identifies undeclared predicates used to park code.",
      "coverage_limit": "Text matching cannot reliably distinguish obsolete code from useful documentation.",
      "level_rationale": "Advisory although Rule 5.7.1 is Required: text matching cannot reliably separate disabled code from documentation, so enforcement rests on review judgement. The nested block comment hazard from 5.7.1 is recorded in the requirement.",
      "summary": "Delete obsolete code instead of parking it in comments or behind a permanently false ``cfg``; let version control remember it.",
      "rationale": "Commented-out code rots, misleads readers and cannot be checked by the compiler. Rust nests block comments, so a stray ``/*`` can hide a whole section. A ``#[cfg(any())]`` block is the same thing with different syntax.",
      "adaptation_notes": "Adapts 5.7.2 (commented-out code) with permanently false ``cfg`` predicates as the Rust analogue of ``#if 0``, and the nested block comment concern of 5.7.1."
    },
    {
      "id": "SCR-RUST-010",
      "title": "Make array and buffer extents explicit at interfaces",
      "misra_cpp_ids": [],
      "scope": "Rust APIs and foreign buffer boundaries",
      "proposed_level": "Required",
      "origin": "S-CORE supplement (raw buffer extents at foreign interfaces)",
      "requirement": "Use arrays or slices that carry the required extent in native Rust interfaces. Raw buffer interfaces shall document pointer, length, ownership and validity together, with validation before constructing a slice.",
      "enforcement": "Compiler typing for native arrays/slices; API review and boundary tests for raw pointer/length pairs.",
      "coverage_limit": "Native array extents are largely compiler-enforced. FFI buffer validity is not, and bounds-checked access can still panic.",
      "summary": "Pass arrays and slices, which carry their length, in Rust interfaces; where a raw pointer and length must be used, document and validate them together before building a slice.",
      "rationale": "A slice is always in bounds. A raw pointer with a separate length is only as valid as the caller promises, and constructing a slice from a wrong pair is undefined behaviour even before the first access."
    },
    {
      "id": "SCR-RUST-011",
      "title": "Keep imports and module interfaces explicit",
      "misra_cpp_ids": [
        "19.0.3",
        "19.2.1"
      ],
      "scope": "Crate/module layout and source inclusion",
      "proposed_level": "Advisory",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Imports and re-exports should make dependencies and ownership of names clear. Keep ordinary imports together; document exceptions for narrow local scope. Glob imports should be limited to explicitly designated preludes or tests. Generated or included source (``include!``, ``include_str!``, build-script output, ``#[path]`` attributes) shall have controlled provenance: a reviewer can trace it to a reviewed source file or to a controlled build input recorded in the component's source and build records, and generation is reproducible from those inputs. ``include!`` shall not shadow items of an outer scope.",
      "enforcement": "Formatting, compiler name resolution, selected import lints and review of re-export/prelude design.",
      "coverage_limit": "Rust permits ``include!`` and generated source; valid syntax alone does not establish clarity or provenance.",
      "level_rationale": "Advisory although Rule 19.2.1 is Required: Rust's module system removes the undefined and ambiguous behavior of C++ header inclusion, leaving clarity and provenance of names as the residual concern.",
      "summary": "Make imports and re-exports show where each name comes from, keep glob imports to designated preludes, and make sure generated or included source can be traced to a reviewed input.",
      "rationale": "Readers and reviewers resolve names by eye. Glob imports and ``include!`` hide where an item is defined and can shadow items from an outer scope. Code that appears from a build script needs the same review as code that was typed.",
      "adaptation_notes": "Adapts 19.0.3 and 19.2.1 (``include!`` shadowing outer items). Provenance evidence is satisfied by existing source and build records."
    },
    {
      "id": "SCR-RUST-012",
      "title": "Reserve entry-point naming",
      "misra_cpp_ids": [
        "6.0.4"
      ],
      "scope": "First-party production functions",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Reserve main for actual executable entry points. Other production functions shall use names expressing their role. Generated wrappers and embedded entry-point conventions require an explicit scoped exception.",
      "enforcement": "A syntax/name checker can enforce the declared policy; review generated and platform entry points.",
      "coverage_limit": "This is a project naming restriction, not a Rust language requirement.",
      "example": {
        "compliant": "// Compliant: the helper's name describes its role.\nmod worker {\n    pub fn process() -> u8 { 1 }\n}\nfn main() { let _ = worker::process(); }",
        "non_compliant": "// Non-compliant: worker::main is not an executable entry point.\nmod worker {\n    pub fn main() -> u8 { 1 }\n}\nfn main() { let _ = worker::main(); }",
        "note": "Both compile and run. The nested ``main`` violates the naming policy; ``worker`` is an ordinary production module with no generated-wrapper or embedded-entry-point exception."
      },
      "summary": "Use the name ``main`` only for real executable entry points.",
      "rationale": "A nested function called ``main`` is legal Rust but misleads anyone searching for the program's entry point. This is a project naming convention, not a language rule."
    },
    {
      "id": "SCR-RUST-013",
      "title": "Control exported symbols and foreign declarations",
      "misra_cpp_ids": [
        "6.0.3",
        "6.2.1",
        "6.2.2"
      ],
      "scope": "Linkage attributes, exported symbols and foreign bindings",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Exported symbols shall have unique definitions and compatible declarations in each delivered binary. Centralize foreign declarations in reviewed binding modules or crates; an ``extern`` declaration shall be type-compatible with the foreign definition. Use minimal visibility and justify ``no_mangle``, ``export_name``, ``link_section`` and equivalent linkage controls. Items exported with ``#[no_mangle]``, ``#[unsafe(no_mangle)]`` or ``export_name`` enter the global symbol namespace: each shall be declared in a reviewed binding module and its name shall be unique across the delivered binary.",
      "enforcement": "Compiler/linker checks, binding review and final symbol-table inspection for each delivered target.",
      "coverage_limit": "Cross-crate/linker behavior is not fully captured by Rust name resolution. Edition 2021 permits syntax that edition 2024 marks unsafe; do not scope this check by unsafe blocks alone.",
      "summary": "Exported symbols need unique names and compatible declarations in each binary; keep foreign declarations in reviewed binding modules and justify every linkage attribute.",
      "rationale": "``#[no_mangle]`` and ``export_name`` put an item into the global symbol namespace shared with C. A duplicate or mismatched declaration is not caught by Rust's name resolution; the linker, or the running program, finds it.",
      "adaptation_notes": "Adapts 6.0.3 (``no_mangle`` items in the global namespace), 6.2.1 and 6.2.2 (extern declarations compatible with the C definition)."
    },
    {
      "id": "SCR-RUST-014",
      "title": "Avoid misleading name shadowing and method resolution",
      "misra_cpp_ids": [
        "6.4.1"
      ],
      "scope": "Bindings, inherent methods and trait methods",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Rebinding shall not silently change the logical meaning of a value. A same-name binding is permitted when the new value is the same quantity in a refined form (trimmed, parsed, validated, unwrapped) and the transformation is visible in the initializer. It is prohibited when the new binding represents a different quantity, unit or role. Where inherent and trait methods share a name but differ semantically, use explicit qualification or change the API.",
      "enforcement": "Selected Clippy shadowing checks plus type-aware custom checks and review of trait/inherent method collisions.",
      "coverage_limit": "This intentionally adapts the C++ restriction to Rust idioms. Rust trait composition is not class inheritance; a broad shadowing ban would enforce a different policy. Clippy shadow lints cannot judge whether a quantity changed meaning.",
      "example": {
        "compliant": "// Compliant: same quantity, refined form, transformation visible.\nfn parse(input: &str) -> Option<u32> {\n    let input = input.trim();\n    input.parse().ok()\n}",
        "non_compliant": "// Non-compliant: the same name now holds a different unit.\nfn schedule(timeout: u32) -> u32 {\n    let timeout = timeout * 1000; // seconds silently become milliseconds\n    timeout + 1\n}",
        "note": "Both compile. In the first the rebinding is still ``input``, only trimmed. In the second ``timeout`` changes unit under the same name, so later readers cannot tell which unit a use refers to."
      },
      "summary": "Do not rebind a name to a value that means something different. A same-name rebinding is fine when it is the same quantity, refined; use explicit paths when inherent and trait methods collide.",
      "rationale": "``let input = input.trim();`` is idiomatic and clear. ``let timeout = timeout * 1000;`` silently changes the unit under the same name, and later uses cannot tell which unit they get. Method resolution preferring inherent methods can likewise pick a different function than the reader expects.",
      "adaptation_notes": "Adapts 6.4.1. The inherent-versus-trait method resolution policy is an S-CORE addition: the SCRC draft assesses 6.4.2 as not applicable until ``supertrait_item_shadowing`` stabilizes."
    },
    {
      "id": "SCR-RUST-015",
      "title": "Preserve lifetimes across raw interfaces",
      "misra_cpp_ids": [
        "6.8.1",
        "6.8.2",
        "6.8.3",
        "6.8.4",
        "8.1.2",
        "28.6.3"
      ],
      "scope": "References, raw pointers, callbacks and ownership transfers",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "An access shall not outlive its referent. Do not expose a dangling local pointer as a usable API result or store borrowed addresses beyond their valid lifetime. A closure or callback that captures a raw pointer shall be invoked only while the pointee is live. That is satisfied when the pointee is owned by the callback or ``'static``, or when the callback's own type carries a lifetime bound that guarantees the borrow outlives every invocation, for example ``impl FnOnce() -> u8 + 'a`` holding a pointer into a ``&'a u8``. Storing or transporting a dangling raw-pointer value is permitted; accessing its expired referent is not. After a value has been moved out of or dropped from storage reachable through a raw pointer, a typed read of that storage requires initialization, validity and ownership to be re-established first; copying a ``Copy`` value leaves the source initialized. Raw-pointer wrappers shall establish lifetime invariants for returned references and asynchronous or foreign callbacks.",
      "enforcement": "Borrow checking for references; available dangling-pointer diagnostics; unsafe/API review and targeted Miri tests.",
      "coverage_limit": "Creating or returning a dangling raw pointer can compile. Compiler-enforced reference lifetimes do not establish equivalent guarantees for raw pointers or foreign callbacks.",
      "summary": "Never access memory after its referent has gone, and do not hand out raw pointers to locals or capture them in callbacks that may outlive the data.",
      "rationale": "The borrow checker protects references, not raw pointers. Creating, storing or passing a dangling raw pointer compiles; the undefined behaviour happens at the later access, often far from where the pointer was made.",
      "adaptation_notes": "Adapts 6.8.1 to 6.8.4 for raw pointers, 8.1.2 for closures capturing raw pointers, and 28.6.3 for typed reads of moved-from storage."
    },
    {
      "id": "SCR-RUST-016",
      "title": "Make numeric, Boolean and character conversions intentional",
      "misra_cpp_ids": [
        "7.0.1",
        "7.0.2",
        "8.2.2",
        "10.2.3"
      ],
      "scope": "All conversions, including safe casts and unsafe reinterpretation",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Conversions shall preserve the required value or perform explicit range or validity checks with a defined error. ``bool`` and ``char`` shall not be used as incidental numbers. Rust already rejects arithmetic directly on ``bool``; converting a flag explicitly with ``u8::from(flag)`` or ``usize::from(flag)``, for example to count how many flags are set, is permitted, while ``flag as u8`` inside arithmetic is not. Casts from ``char`` other than the lossless ``char as u32`` or ``u32::from(c)`` are prohibited outside documented encoding or decoding boundaries; at such a boundary a narrowing cast such as ``char as u8`` requires a preceding range check or a checked conversion such as ``u8::try_from(u32::from(c))``. Lossy floating-point conversion requires a precision contract.",
      "enforcement": "Clippy cast_possible_truncation, cast_possible_wrap, cast_sign_loss, cast_precision_loss and cast_lossless as candidate mappings; custom conversion inventory and boundary tests.",
      "coverage_limit": "``as`` is legal in safe Rust, so an inventory is needed. ``From``/``TryFrom`` are preferred where supplied, but not every numeric pair implements them. The encoding-boundary exception and the character-cast restriction are S-CORE adaptations, not verbatim MISRA requirements.",
      "summary": "Convert numbers, booleans and characters explicitly, preserving the value or checking the range, and prefer ``From``/``TryFrom`` over ``as``.",
      "rationale": "``as`` is legal in safe Rust and silently truncates, wraps or loses sign. ``char as u8`` drops the upper bits of a code point. A conversion lint can point at the cast but cannot know which values are acceptable.",
      "adaptation_notes": "Adapts 7.0.1, 7.0.2, 8.2.2 (SCRC draft guideline on ``as``) and 10.2.3 (enum discriminant casts). The prohibition of truncating character casts is an S-CORE addition; the SCRC draft assesses 7.0.3 as not applicable."
    },
    {
      "id": "SCR-RUST-017",
      "title": "Represent absent pointers explicitly",
      "misra_cpp_ids": [],
      "scope": "Raw-pointer and foreign APIs",
      "proposed_level": "Required",
      "origin": "S-CORE adaptation of the C++ null-pointer-constant concern; MISRA C++ 7.11.1 is assessed not applicable and is not retained as a source",
      "requirement": "Use typed null constructors when a raw null pointer is required. Use Option or another explicit type for optional references/handles in safe APIs. Check required pointer validity before dereference; a null check alone is insufficient.",
      "enforcement": "Compiler typing, candidate checks for integer-fabricated null pointers, and foreign API review.",
      "coverage_limit": "Raw null pointers can be created in safe Rust. Non-nullness alone establishes neither allocation validity nor lifetime/alignment.",
      "summary": "Represent an absent pointer with ``Option`` or a typed null constructor, and check the pointer's validity before dereferencing, not only that it is non-null.",
      "rationale": "``ptr::null()`` can be created in safe code and nothing stops it being passed where a valid pointer is expected. A non-null pointer can still be dangling, misaligned or point into freed memory. ``Option<&T>`` makes absence visible to the type system.",
      "adaptation_notes": "S-CORE adaptation of the C++ null-pointer-constant concern; 7.11.1 itself is assessed not applicable and not retained as a source."
    },
    {
      "id": "SCR-RUST-018",
      "title": "Make mixed-operator intent clear",
      "misra_cpp_ids": [
        "8.0.1"
      ],
      "scope": "Production expressions",
      "proposed_level": "Advisory",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Expressions mixing arithmetic, bitwise, shift or Boolean operators should use grouping that makes the intended evaluation clear. Split complex expressions when parentheses alone do not make them readable.",
      "enforcement": "Clippy precedence and code review.",
      "coverage_limit": "A precedence lint detects only selected patterns; this remains partly a readability judgment.",
      "summary": "Group mixed arithmetic, bitwise, shift and Boolean operators with parentheses or split the expression.",
      "rationale": "Rust's precedence rules differ from C in places, for example around ``as`` and ranges, and few readers know all of them. An expression the reader parses differently from the compiler is a defect waiting to happen."
    },
    {
      "id": "SCR-RUST-019",
      "title": "Use checked type recovery",
      "misra_cpp_ids": [
        "8.2.1"
      ],
      "scope": "Type-erased values and trait-object downcasts",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Recover concrete types through checked APIs such as Any downcasts, and handle failure. Unchecked type recovery requires a proven type-identity invariant within an approved unsafe abstraction. Do not invent a ban on ordinary TypeId queries.",
      "enforcement": "API inventory, compiler type checks and review of unchecked downcast/representation operations.",
      "coverage_limit": "A checked downcast establishes type identity at the point of the call only; it does not establish that the recovered value satisfies the invariants the caller expects, and a failed downcast still needs a defined error path. Only an inventory of unchecked recovery (transmute, pointer casts) finds bypasses. Ordinary checked native APIs need no custom MISRA-shaped check.",
      "summary": "Recover concrete types through checked downcasts and handle the failure case; do not reinterpret memory to get a type back.",
      "rationale": "``Any::downcast_ref`` tells you when the type does not match. A ``transmute`` or pointer cast does not, and a wrong guess is undefined behaviour rather than an error you can handle."
    },
    {
      "id": "SCR-RUST-020",
      "title": "Restrict pointer casts and representation changes",
      "misra_cpp_ids": [
        "8.2.3",
        "8.2.5",
        "8.2.6",
        "8.2.7",
        "8.2.8",
        "23.11.1"
      ],
      "scope": "All raw-pointer transformations, safe and unsafe",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Prefer typed pointer and reference APIs. Pointer-to-integer conversions, reconstruction of pointers, mutability-changing casts and ``transmute`` shall be restricted to reviewed low-level interfaces with documented provenance, alignment, validity and aliasing assumptions. Do not truncate addresses or fabricate a mutable reference from shared access outside valid interior-mutability rules. Creating an owning value from a raw pointer (``Box::from_raw``, ``Vec::from_raw_parts``, ``CString::from_raw``, ``Rc::from_raw``, ``Arc::from_raw`` and similar) shall satisfy that API's producer, allocation and ownership preconditions: the pointer came from the matching ``into_raw`` or from an allocation with the same layout, ownership is transferred exactly once, and for ``Rc``/``Arc`` the reference-count accounting (``from_raw`` paired with ``into_raw`` or ``increment_strong_count``) is documented. The resulting ownership obligations follow SCR-RUST-035.",
      "enforcement": "Candidate Clippy pointer/transmute lints and API restrictions; compiler invalid-reference diagnostics; custom AST inventory, unsafe review and Miri where applicable.",
      "coverage_limit": "Many pointer casts are legal outside unsafe. Inventory the entire crate; transmute is not a generally safer replacement for as. Provenance correctness cannot be inferred from equal sizes.",
      "summary": "Restrict pointer casts, pointer-integer conversions, ``transmute`` and rebuilding owning values from raw pointers to reviewed low-level modules with documented provenance, layout and ownership assumptions.",
      "rationale": "Many pointer casts are legal in safe Rust, but a pointer rebuilt from an integer has no provenance, equal size does not make a ``transmute`` valid, and ``Box::from_raw`` on the wrong pointer double-frees or frees the wrong allocation.",
      "adaptation_notes": "Adapts 8.2.3, 8.2.5 to 8.2.8 (pointer casts) and 23.11.1 (owning values from raw pointers)."
    },
    {
      "id": "SCR-RUST-021",
      "title": "Preserve function-call ABI and variadic contracts",
      "misra_cpp_ids": [
        "8.2.4",
        "8.2.11",
        "21.10.1"
      ],
      "scope": "Function pointers, callbacks and variadic foreign calls",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Calls shall use a compatible function signature, calling convention and ABI. Function-pointer representation changes require boundary review. Defining C-variadic functions in Rust is prohibited in first-party production code; the feature is unstable and its ``VaList`` handling is unsafe. Calling a foreign variadic function is limited to a reviewed adapter that validates argument types and applicable promotion rules.",
      "enforcement": "Compiler ABI/type diagnostics, binding generation checks, adapter review and cross-language integration tests.",
      "coverage_limit": "A successful link does not validate an incorrectly declared foreign signature or variadic argument contract. The paper excludes full FFI analysis.",
      "summary": "Call foreign functions with the exact signature and calling convention they have; do not define C-variadic functions in Rust and keep variadic calls inside reviewed adapters.",
      "rationale": "A wrong ABI or argument type links fine and fails at runtime, sometimes only on one target. Variadic calls have no type checking at all; the callee trusts the caller to pass what the format expects.",
      "adaptation_notes": "Adapts 8.2.4 and 8.2.11 (call-side ABI and promotion) and 21.10.1; prohibiting C-variadic definitions in first-party code is the S-CORE policy choice."
    },
    {
      "id": "SCR-RUST-022",
      "title": "Control recursion and stack consumption",
      "misra_cpp_ids": [
        "8.2.10"
      ],
      "scope": "Production call paths, including callbacks and recursive destruction",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Direct and indirect recursion that executes at runtime shall be prohibited in production call paths unless a scoped deviation establishes a finite depth and stack budget. Recursion in a ``const fn`` is permitted when the call is evaluated in a constant context, where the compiler bounds it through the const-evaluation limit; the same ``const fn`` called at runtime falls under the prohibition. Assess recursive parsing, traversal and destructor chains as well as explicit self-calls.",
      "enforcement": "Compiler unconditional_recursion provides a narrow check; candidate CodeQL/call-graph analysis and stack/depth testing provide additional evidence.",
      "coverage_limit": "Unconditional-recursion diagnostics do not detect all terminating recursion. Dynamic dispatch, callbacks and foreign calls leave call-graph gaps; static analysis is not a general proof of bounded stack use.",
      "summary": "Avoid runtime recursion in production code unless a deviation establishes a finite depth and a stack budget. Compile-time recursion in ``const fn`` is fine.",
      "rationale": "Rust has no stack-depth guarantee; an unbounded recursion ends in a stack overflow abort, not an error you can catch. Recursion also hides in parsers, tree traversals and destructor chains, not only in functions that call themselves by name.",
      "adaptation_notes": "Adapts 8.2.10 including its ``constexpr`` exception, which becomes ``const fn`` recursion evaluated in a constant context."
    },
    {
      "id": "SCR-RUST-023",
      "title": "Respect allocation boundaries in pointer operations",
      "misra_cpp_ids": [
        "8.7.1",
        "8.7.2",
        "8.9.1"
      ],
      "scope": "Raw-pointer arithmetic, differences, comparisons and later use",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Pointer operations shall meet their individual API contracts, including allocation/provenance and bounds requirements. Relational comparisons shall not infer object order across unrelated allocations. Prefer slice indexing/iteration; document any reviewed address-ordering exception separately.",
      "enforcement": "Unsafe review, targeted Miri tests, and candidate checks for pointer operations and their data flow.",
      "coverage_limit": "Some construction, wrapping arithmetic and comparisons are safe operations. An out-of-bounds intermediate is not universally forbidden by Rust; the applicable API and eventual access determine validity. The project comparison restriction is stronger than language UB rules.",
      "example": {
        "compliant": "// Compliant: no access occurs during the wrapping excursion.\nfn read_first() -> u8 {\n    let bytes = [1_u8, 2];\n    let p = bytes.as_ptr();\n    let q = p.wrapping_add(20).wrapping_sub(20);\n    // SAFETY: q is back at the initialized first byte; bytes is still live.\n    unsafe { *q }\n}",
        "non_compliant": "// Non-compliant: add(20) itself exceeds its permitted bounds.\nfn read_first() -> u8 {\n    let bytes = [1_u8, 2];\n    let p = bytes.as_ptr();\n    let q = unsafe { p.add(20) }.wrapping_sub(20);\n    unsafe { *q }\n}",
        "note": "Both function bodies compile and both are operations inside a reviewed low-level implementation; the pointer remains derived from the live two-byte array. Miri accepts the first and reports undefined behavior at ``add(20)`` in the second, before the read, because ``add`` requires the result to stay in bounds while ``wrapping_add`` does not. The individual pointer API contract decides, not the final address."
      },
      "summary": "Keep every pointer operation within its own API contract: ``add`` must stay in bounds, comparisons only within one allocation. Prefer slices and iterators.",
      "rationale": "Pointer arithmetic in Rust is undefined behaviour the moment ``add`` leaves the allocation, even if you never read through the result. ``wrapping_add`` has a different contract. The individual method decides, not the final address."
    },
    {
      "id": "SCR-RUST-024",
      "title": "Separate persistent effects from short-circuit decisions",
      "misra_cpp_ids": [
        "8.14.1"
      ],
      "scope": "Production Boolean expressions",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Required persistent effects shall not depend on accidental short-circuit evaluation. A state change or I/O on the right side of ``&&`` or ``||`` is acceptable only when skipping it is the specified behavior whenever the left operand decides the expression, and the call site documents that conditional-effect contract, for example filling a cache entry that is correctly skipped when the entry is already present. Otherwise move the effect out of the condition.",
      "enforcement": "Candidate AST checks for obvious mutations and CodeQL effect/call analysis; code review.",
      "coverage_limit": "Identifying arbitrary side effects through calls requires models. A function call in a condition is not automatically a violation.",
      "level_rationale": "Required although Rule 8.14.1 is Advisory: a state change skipped because the left operand short-circuits the expression alters program behavior silently and is not diagnosed by the compiler.",
      "summary": "Do not put state changes or I/O on the right side of ``&&`` or ``||`` unless skipping them is exactly what you want when the left side decides.",
      "rationale": "Short-circuit evaluation skips the right operand silently. An increment or a log write hidden there happens on some paths and not others, and the compiler has no reason to warn.",
      "adaptation_notes": "Adapts 8.14.1."
    },
    {
      "id": "SCR-RUST-025",
      "title": "Use memory-copy operations with valid overlap and ownership",
      "misra_cpp_ids": [
        "8.18.1",
        "24.5.2"
      ],
      "scope": "Raw copies and buffer movement",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Choose copy operations whose overlap contract matches the buffers: ``copy_nonoverlapping`` requires disjoint regions; overlapping movement must use ``ptr::copy``. The copy operation itself requires valid, aligned, in-bounds pointers for the element count, the overlap condition of the chosen API, and ownership handling without double drop; it may copy uninitialized storage such as ``MaybeUninit`` buffers. Using the destination as an initialized ``T`` is a separate step that requires ``T``'s validity invariant to hold for the copied bytes, since the raw copy preserves uninitialized padding. Byte-wise comparison of whole objects is permitted only where every compared byte is initialized and accessible under valid lifetime and aliasing conditions, and byte equality is the intended equality; otherwise compare semantically through ``PartialEq``.",
      "enforcement": "API review, boundary tests and Miri; candidate checks for raw copy calls and buffer relationships.",
      "coverage_limit": "``ptr::copy`` permits overlap; the C++ rule cannot become a blanket ban on overlap without changing its intent. ``repr(C)`` and ``Copy`` do not establish that padding is initialized, and even a valid byte view compares differently from value equality for signed zero or unused buffer bytes.",
      "summary": "Pick the raw copy function whose overlap rule matches your buffers, meet its pointer and size preconditions, and treat the copied bytes as valid ``T`` only after you have established that they are.",
      "rationale": "``copy_nonoverlapping`` with overlapping buffers is undefined behaviour; ``ptr::copy`` allows overlap. A raw copy also copies uninitialized padding, so byte-wise comparison of whole objects can differ from value equality.",
      "adaptation_notes": "Adapts 8.18.1 and 24.5.2. The conditional permission for byte comparison adapts the source's ban on the C++ memory functions."
    },
    {
      "id": "SCR-RUST-026",
      "title": "Specify arithmetic overflow and shift behavior",
      "misra_cpp_ids": [
        "7.0.4",
        "8.20.1"
      ],
      "scope": "Integer arithmetic, shifts and constant calculations",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Arithmetic shall stay within its required range or use explicit checked, saturating, wrapping or overflowing operations with justified semantics. A shift count shall be non-negative and less than the bit width of the left operand's type. Division and remainder shall check for a zero divisor and for ``MIN / -1``. Constants shall not silently wrap contrary to their intended value.",
      "enforcement": "Compiler constant/overflow diagnostics; Clippy arithmetic_side_effects as a candidate restriction; boundary tests under the delivered build settings.",
      "coverage_limit": "Panic and release-mode behavior depend on the operation and the delivered overflow-check setting; a shift by an out-of-range count panics in debug and masks in release unless overflow checks are on.",
      "summary": "Keep integer arithmetic in range or use the explicit ``checked_``, ``saturating_``, ``wrapping_`` or ``overflowing_`` operations; shift counts must be below the bit width; check divisors.",
      "rationale": "In release builds integer overflow wraps silently unless overflow checks are on, and a shift by too many bits masks the count. Debug and release then behave differently, which is the worst kind of bug to find in the field.",
      "adaptation_notes": "Adapts 7.0.4 (shift counts; shared criterion with the draft SCRC guideline) and 8.20.1 (constant expressions). The general runtime arithmetic policy is an S-CORE extension."
    },
    {
      "id": "SCR-RUST-027",
      "title": "Make decision fallbacks explicit",
      "misra_cpp_ids": [
        "9.4.1"
      ],
      "scope": "Production if/else-if decision chains",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Each ``if``/``else if`` chain with two or more conditions shall define behavior when no condition matches. Prefer an exhaustive ``match`` for finite cases; otherwise provide a final ``else`` that performs the defined fallback or documents the intentionally empty action. A single ``if`` without ``else if`` is an independent guard and is not affected.",
      "enforcement": "Compiler match exhaustiveness; candidate syntax check for missing final else; review of fallback requirements.",
      "coverage_limit": "A final ``else`` or wildcard arm does not prove that the fallback is correct.",
      "summary": "Every ``if``/``else if`` chain with two or more conditions ends in an ``else`` that defines the fallback, or becomes an exhaustive ``match``.",
      "rationale": "A chain without a final ``else`` silently does nothing for the unexpected case. ``match`` forces you to say what happens; ``if``/``else if`` does not, so the rule restores that discipline.",
      "adaptation_notes": "Adapts 9.4.1 and applies to all production chains, as the source does."
    },
    {
      "id": "SCR-RUST-028",
      "title": "Separate volatile I/O from synchronization",
      "misra_cpp_ids": [
        "10.1.2"
      ],
      "scope": "Hardware access and volatile operations",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Volatile operations shall be confined to reviewed hardware/platform abstractions with documented address, width, alignment and device-ordering assumptions. Use appropriate synchronization for shared memory; volatile shall not be used as a substitute for atomics or locks.",
      "enforcement": "API restriction/inventory, platform review and hardware integration tests.",
      "coverage_limit": "Miri and host tests do not establish real device behavior. Validity requirements differ for the specific I/O operation and memory region.",
      "summary": "Keep volatile reads and writes inside reviewed hardware abstractions, and never use volatile as a replacement for atomics or locks.",
      "rationale": "Volatile only prevents the compiler from removing or reordering the access itself. It does not synchronize threads. Using it for shared memory is a data race that happens to work until the hardware or the optimizer changes."
    },
    {
      "id": "SCR-RUST-029",
      "title": "Restrict assembly to reviewed platform modules",
      "misra_cpp_ids": [
        "10.4.1"
      ],
      "scope": "Inline and global assembly",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Assembly is prohibited in ordinary application components. A platform exception shall document the instruction contract, registers/clobbers, stack, memory effects, target assumptions and safe wrapper invariants.",
      "enforcement": "Source/macro inventory, compiler assembly checks and specialist review of each exception.",
      "coverage_limit": "Compiler acceptance does not establish correctness of declared assembly effects. Scan generated and macro-expanded code too.",
      "summary": "No inline or global assembly in ordinary components; a platform exception documents the instruction contract, registers, clobbers and the safe wrapper's invariants.",
      "rationale": "``asm!`` bypasses every Rust guarantee. A wrong clobber list or memory effect corrupts registers or memory the compiler assumed were untouched, and no tool checks the contract for you."
    },
    {
      "id": "SCR-RUST-030",
      "title": "Limit raw-pointer indirection",
      "misra_cpp_ids": [
        "11.3.2"
      ],
      "scope": "Raw-pointer APIs and declarations",
      "proposed_level": "Advisory",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Raw-pointer interfaces should use no more than two pointer-indirection levels. Deeper foreign interfaces should be isolated behind a typed adapter with explicit ownership and extent contracts. Native references and smart-pointer composition require separate design assessment.",
      "enforcement": "A type-aware syntax check and interface review.",
      "coverage_limit": "Indirection count is a complexity restriction, not proof of memory safety; benign safe abstractions must not be classified solely by textual asterisks. Scope choice: the SCRC draft assesses 11.3.2 as applicable to safe Rust because it includes references. This rule deliberately counts raw pointers only; reference and smart-pointer composition such as ``&&T`` or ``Box<Rc<T>>`` is left to the component's design assessment because the type system makes that nesting explicit and checked.",
      "summary": "Keep raw-pointer interfaces to at most two levels of indirection; wrap deeper foreign interfaces in a typed adapter.",
      "rationale": "``*mut *mut *mut T`` is hard to reason about and easy to get wrong for ownership and lifetime. References and smart pointers nest safely because the type system tracks them; raw pointers do not.",
      "adaptation_notes": "Adapts 11.3.2. The SCRC draft assesses it as applicable to safe Rust because it includes references; this rule deliberately counts raw pointers only and leaves reference and smart-pointer nesting to design assessment because the type system makes it explicit."
    },
    {
      "id": "SCR-RUST-031",
      "title": "Establish initialization and value validity before use",
      "misra_cpp_ids": [
        "11.6.1",
        "11.6.2",
        "15.1.4"
      ],
      "scope": "Native initialization, MaybeUninit, unions and raw storage",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Every value observed as its type ``T`` shall be initialized and valid for ``T``. For ``MaybeUninit<T>`` and raw storage the requirement applies to producing or accessing the payload as ``T``: ``assume_init``, ``assume_init_ref`` and ``assume_init_mut``, ``ptr::read`` as ``T``, and creating ``&T`` or ``&mut T``. Operations on the container are not restricted: taking ``&mut MaybeUninit<T>``, calling ``MaybeUninit::write``, and reading or copying the storage as ``MaybeUninit<T>`` (or as ``MaybeUninit<u8>`` bytes) are valid while the payload is uninitialized. Reading a byte as ``u8`` is a payload read and requires that byte to be initialized. Track partial initialization and avoid duplicate destruction. Zero-filled storage shall not be treated as a valid arbitrary ``T``.",
      "enforcement": "Compiler definite-initialization checks; unsafe review and Miri tests for low-level storage; candidate inventories for initialization-bypassing APIs.",
      "coverage_limit": "Compiler checks for ordinary locals do not establish initialization of raw storage. Creating ``&T`` to an invalid value is already undefined behavior, before any explicit read; Miri detects such payload accesses on executed paths.",
      "summary": "Only use a value as type ``T`` once it is fully initialized and valid for ``T``. Operating on a ``MaybeUninit<T>`` container is fine; reading its payload before initialization is not.",
      "rationale": "Reading uninitialized memory is undefined behaviour, and so is creating a ``&bool`` to a byte that is not 0 or 1. Zero-filled memory is not a valid value of every type. The compiler checks ordinary locals but cannot see through raw storage.",
      "adaptation_notes": "Adapts 11.6.1, 11.6.2 and 15.1.4 (``MaybeUninit``)."
    },
    {
      "id": "SCR-RUST-032",
      "title": "Prefer enums over untagged unions",
      "misra_cpp_ids": [
        "12.3.1"
      ],
      "scope": "Application data models and foreign/low-level representations",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Use enums for application alternatives. A union shall be confined to a justified representation boundary with a documented discriminant/active-field protocol, field validity and destruction policy.",
      "enforcement": "Syntax inventory and review of each union definition/access; targeted tests.",
      "coverage_limit": "Rust union reads have validity obligations that a documented active-field name alone cannot satisfy. FFI layout may require a reviewed exception.",
      "summary": "Model alternatives with ``enum``; use a ``union`` only at a documented representation boundary with a clear active-field protocol.",
      "rationale": "An ``enum`` knows which variant it holds; a ``union`` does not, and reading the inactive field is undefined behaviour. Enums also give you exhaustive ``match`` for free."
    },
    {
      "id": "SCR-RUST-033",
      "title": "Make parameter roles consistent",
      "misra_cpp_ids": [
        "13.3.3"
      ],
      "scope": "Trait methods, implementations and public API documentation",
      "proposed_level": "Advisory",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Parameter names should consistently describe their semantic roles across trait declarations, implementations and examples. Mark intentionally unused parameters explicitly and explain why an implementation ignores them.",
      "enforcement": "Compiler unused_variables and API review; optional trait/implementation name comparison.",
      "coverage_limit": "Rust permits unnamed patterns such as _. This adaptation concerns readable contracts, not C++ overriding syntax.",
      "level_rationale": "Advisory although Rule 13.3.3 is Required: Rust has neither default arguments nor overload sets, so the residual concern is consistent naming of parameter roles across trait and implementation signatures, which the compiler accepts either way.",
      "example": {
        "compliant": "trait Distance {\n    fn millimetres(&self, metres: u32) -> u64;\n}\nstruct Converter;\nimpl Distance for Converter {\n    // Compliant: preserves the parameter's stated role.\n    fn millimetres(&self, metres: u32) -> u64 {\n        u64::from(metres) * 1000\n    }\n}",
        "non_compliant": "trait Distance {\n    fn millimetres(&self, metres: u32) -> u64;\n}\nstruct Converter;\nimpl Distance for Converter {\n    // Non-compliant: seconds misstates the parameter's role.\n    fn millimetres(&self, seconds: u32) -> u64 {\n        u64::from(seconds) * 1000\n    }\n}",
        "note": "Both compile and produce the same result. The second describes a distance as a duration, a semantic mismatch the compiler accepts."
      },
      "summary": "Name parameters for their semantic role, consistently between trait declarations and implementations, and mark deliberately unused parameters.",
      "rationale": "The compiler checks types, not meaning. An implementation that calls a distance ``seconds`` compiles and runs, and misleads the next reader into a unit error."
    },
    {
      "id": "SCR-RUST-034",
      "title": "Protect type invariants through visibility",
      "misra_cpp_ids": [
        "14.1.1"
      ],
      "scope": "Struct fields and constructors",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Fields whose arbitrary mutation can violate an invariant shall be private and changed through validating APIs. Plain data carriers may expose fields when all representable states are valid for their contract. Review mixed visibility explicitly.",
      "enforcement": "API/design review; custom checks may inventory public fields and constructor bypasses.",
      "coverage_limit": "Making every field public or private does not itself prove invariant preservation. This replaces the C++ structural recommendation with a Rust invariant-oriented policy.",
      "level_rationale": "Required although Rule 14.1.1 is Advisory: visibility is the only language mechanism that protects a type invariant in Rust; a public field lets safe code create an invalid state without any diagnostic.",
      "example": {
        "compliant": "// Compliant: callers outside the module cannot bypass validation.\nmod percentage {\n    pub struct Percent { value: u8 }\n    impl Percent {\n        pub fn new(value: u8) -> Option<Self> {\n            if value <= 100 { Some(Self { value }) } else { None }\n        }\n        pub fn value(&self) -> u8 { self.value }\n    }\n}",
        "non_compliant": "// Non-compliant for the same invariant: callers can bypass validation.\nmod percentage {\n    pub struct Percent { pub value: u8 }\n}\nfn break_invariant() {\n    let mut p = percentage::Percent { value: 50 };\n    p.value = 101;\n}",
        "note": "Both compile. ``Percent`` promises a value in 0..=100; the second permits an invalid state through safe public access."
      },
      "summary": "Keep fields private when arbitrary mutation can break an invariant, and change them only through validating methods.",
      "rationale": "Visibility is the only mechanism that protects an invariant in Rust. A ``pub`` field lets safe code anywhere in the program put the type into a state the rest of its methods assume cannot exist."
    },
    {
      "id": "SCR-RUST-035",
      "title": "Review ownership traits and resource lifecycle",
      "misra_cpp_ids": [
        "15.0.1",
        "15.8.1",
        "21.6.2",
        "28.6.1"
      ],
      "scope": "Copy/Clone/Drop, pinning, custom owners and raw allocation wrappers",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "``Copy``, ``Clone`` and ``Drop`` implementations shall preserve ownership and type invariants. Every acquired resource shall have a defined release or transfer policy, including partial failure paths. Unsafe pinning abstractions shall preserve their promised pinning invariants. Do not rely on destructors running to maintain memory safety. Synchronization and resource guards shall remain bound for the intended duration; do not accidentally discard them immediately. Where a borrowed-to-owned conversion matters, use an explicit operation such as ``to_vec()``, ``to_owned()`` or ``clone()`` rather than a generic ``From``/``Into`` call whose behavior, moving an owner or copying from a borrow, depends on the argument type. APIs that emulate move or assignment through raw pointers, including ``Pin``-based move emulation and in-place replacement, shall define behavior when source and destination coincide: either the aliasing case preserves the value, invariants and resources, or it is an explicit unsafe precondition that every safe wrapper establishes.",
      "enforcement": "Compiler move/trait checks, review of custom implementations and targeted Miri/resource-failure tests; inventory mem::forget, leaks and manual ownership transfer. Include the rustc let_underscore_lock diagnostic where supported.",
      "coverage_limit": "Safe Rust permits leaks and ``mem::forget``, and termination may skip ``Drop``. ``Pin`` is a type, not a trait. The compiler decides whether a generic conversion moves or copies, but a reader cannot see which without an explicit operation.",
      "summary": "Implement ``Copy``, ``Clone`` and ``Drop`` so they preserve ownership and invariants, give every resource a release policy, keep guards alive for their intended duration, and be explicit when converting borrowed data to owned.",
      "rationale": "Rust does not guarantee destructors run: ``mem::forget``, leaks and aborts skip them. A ``let _ = mutex.lock()`` releases the lock immediately. A generic ``.into()`` may move or copy depending on the argument type, and the reader cannot tell which.",
      "adaptation_notes": "Adapts 15.0.1, 21.6.2, 28.6.1 (explicit borrowed-to-owned conversion) and Directive 15.8.1 (self-aliasing in move emulation)."
    },
    {
      "id": "SCR-RUST-036",
      "title": "Define panic, termination and cleanup behavior",
      "misra_cpp_ids": [
        "18.1.1",
        "18.4.1",
        "18.5.1",
        "18.5.2"
      ],
      "scope": "Production library code, process boundaries and destructors",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Recoverable failures shall use explicit error handling. Application libraries shall not terminate the process directly or indirectly: calling ``std::process::exit`` or ``abort``, taking or storing their addresses, or reaching them through foreign code is prohibited. The only accepted fail-stop is the abort produced by a failed assertion or by the delivered panic strategy; any broader fail-stop path requires a documented system response including cleanup or external recovery. Each boundary declares one of two levels: a **panic-free** path never initiates a panic, including implicit panics from indexing, arithmetic and allocation; a **panic-contained** boundary may see a panic but shall not let it escape. Destructors are panic-free: a custom ``Drop`` and the field cleanup it relies on shall not panic. No panic shall cross a foreign-language boundary. Panic payloads shall carry only owned data or ``'static`` references. The conditions for ``catch_unwind``, the panic strategy and payload contents are specified in :ref:`rust_boundary_contracts_panic`.",
      "enforcement": "Selected Clippy panic/unwrap_used/expect_used restrictions; ``clippy::exit`` for direct calls plus an inventory of stored or passed function pointers to termination APIs; failure-injection tests and call-path review; Miri or tests for destructor panic paths.",
      "coverage_limit": "Absence of ``panic!`` and ``unwrap`` does not prove panic freedom: indexing, arithmetic, dependencies and destructors can fail. ``clippy::exit`` sees direct calls only. Panic is not synonymous with Rust undefined behavior; the system may nevertheless treat it as a safety failure.",
      "summary": "Handle recoverable failures with ``Result``, never terminate the process from a library, keep destructors panic-free, and decide per boundary whether a path must be panic-free or only panic-contained.",
      "rationale": "A panic is not an error you can always catch: under ``panic=abort`` it ends the process, a panic during unwinding aborts, and indexing, arithmetic and allocation panic implicitly. ``std::process::exit`` skips every destructor. Whether a wrapper may catch and convert a panic is a design decision that has to be made explicitly.",
      "adaptation_notes": "Adapts 18.1.1 (payloads; permitting ``'static`` references is a Rust adaptation of the C++ pointer restriction), 18.4.1 (destructor panics), 18.5.1 (unwinding across boundaries) and 18.5.2 (termination, including indirect calls; the only accepted fail-stop is the assertion or panic-strategy abort)."
    },
    {
      "id": "SCR-RUST-037",
      "title": "Validate attributes and configuration coverage",
      "misra_cpp_ids": [
        "19.0.1"
      ],
      "scope": "cfg/features, attributes and build-generated configuration",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "All cfg names/values and features shall be declared and checked. Invalid or unrecognized attributes/configuration diagnostics shall block analysis. Maintain and analyze the supported configuration matrix, including mutually exclusive features, rather than assuming one all-features build is representative.",
      "enforcement": "rustc unexpected_cfgs and appropriate check-cfg flags, attribute diagnostics, build-matrix checks and configuration review.",
      "coverage_limit": "Inactive code is not necessarily type-checked. Correct configuration syntax does not establish that every delivered variant was analyzed.",
      "example": {
        "compliant": "// Compliant feature spelling.\n#[cfg(feature = \"enabled\")]\nfn feature_marker() {}\nfn main() {}",
        "non_compliant": "// Non-compliant: undeclared, misspelled feature value.\n#[cfg(feature = \"enabeld\")]\nfn feature_marker() {}\nfn main() {}",
        "note": "With the only declared feature value being ``enabled`` and ``--check-cfg 'cfg(feature, values(\"enabled\"))' -D unexpected_cfgs``, the first passes and the second is rejected by the ``unexpected_cfgs`` lint even though the feature is inactive. See the rustc check-cfg documentation."
      },
      "summary": "Declare every ``cfg`` name and feature value and have the compiler check them; analyze every supported configuration, not just one all-features build.",
      "rationale": "A misspelled ``#[cfg(feature = \"enabeld\")]`` silently removes the code it guards. Inactive code is not type-checked, so a bug behind the wrong flag only appears when that configuration ships."
    },
    {
      "id": "SCR-RUST-038",
      "title": "Control macro expansion and argument effects",
      "misra_cpp_ids": [
        "19.0.2",
        "19.3.4"
      ],
      "scope": "Declarative/procedural macros and generated Rust",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Prefer a function where a function can express the intended behavior. A macro is justified for variadic arity, item or implementation generation, compile-time token or string processing, or capturing the caller location, and the crate shall state which of these exceptions it uses. Macros shall document whether arguments are evaluated once, more than once or not at all. Use expression fragments where expression semantics are intended. Safety-relevant macro-generated unsafe code and effects shall be included in review and checker coverage.",
      "enforcement": "Macro expansion inspection, tests using arguments with observable effects, and lint coverage checks on generated code.",
      "coverage_limit": "Rust macros avoid some C++ textual-substitution hazards but can still duplicate evaluation, introduce panics or unsafe code. Compiler type checking is not a substitute for semantic review.",
      "summary": "Prefer a function to a macro unless the macro is needed for variadic arity, item generation, compile-time processing or caller location, and document how often a macro evaluates its arguments.",
      "rationale": "Macros duplicate or skip the evaluation of their arguments without any warning, and the code they generate escapes ordinary review. A function has a signature the compiler and the reader can check.",
      "adaptation_notes": "Adapts 19.0.2 (functions preferred over function-like macros, with stated exceptions) and 19.3.4."
    },
    {
      "id": "SCR-RUST-039",
      "title": "Bound allocation and isolate manual allocators",
      "misra_cpp_ids": [
        "21.6.1",
        "21.6.3"
      ],
      "scope": "Heap allocation, container growth and custom allocation",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "Each component shall declare where allocation is permitted and justify peak memory, growth limits and failure behavior. Unbounded input-driven growth is prohibited. Manual allocators and raw allocation APIs shall be restricted to reviewed modules with allocator/layout/ownership contracts.",
      "enforcement": "Allocation API inventory, workload/boundary/failure tests and memory-budget review; candidate CodeQL flow checks for untrusted size inputs.",
      "coverage_limit": "A blanket no-allocation profile is an optional stricter component policy, not silently imposed here. try_reserve covers only particular failures; RAII does not bound memory, prevent leaks or guarantee recovery from OOM.",
      "summary": "Say where allocation is allowed, bound input-driven growth, and keep custom allocators and raw allocation APIs in reviewed modules.",
      "rationale": "An attacker-controlled length that reaches ``Vec::with_capacity`` is a denial of service. Allocation failure aborts by default; ``try_reserve`` covers only some cases. RAII frees memory but does not bound how much you hold.",
      "adaptation_notes": "Adapts 21.6.1 and 21.6.3; 21.6.4 is assessed not applicable because ``GlobalAlloc::dealloc`` always receives the layout."
    },
    {
      "id": "SCR-RUST-040",
      "title": "Separate compile-time and runtime assertions",
      "misra_cpp_ids": [
        "22.3.1"
      ],
      "scope": "Assertions and invariant checks",
      "proposed_level": "Required",
      "origin": "S-CORE interpretation of MISRA C++:2023 guidelines",
      "requirement": "An invariant intended for compile-time checking shall use a const-evaluated construct supported by the pinned compiler. Required runtime validation shall remain active in production and return the specified error or enter the approved failure path. Do not put required side effects inside debug_assert!.",
      "enforcement": "Compiler const evaluation; Clippy assertions_on_constants as a candidate; release-configuration tests and assertion review.",
      "coverage_limit": "A constant argument to an ordinary assert! does not by itself request const evaluation. debug_assert! can be disabled and must not carry a required safety check.",
      "example": {
        "compliant": "// Compliant: the check remains active in production.\nfn check(value: u8) -> Result<(), ()> {\n    if value <= 10 { Ok(()) } else { Err(()) }\n}",
        "non_compliant": "// Non-compliant: the required check can disappear.\nfn check(value: u8) -> Result<(), ()> {\n    debug_assert!(value <= 10);\n    Ok(())\n}",
        "note": "Both compile. The API must reject values above 10 in production builds too; with ``-C debug-assertions=no`` the second returns ``Ok(())`` for 11. ``debug_assert!`` is conditional on that build setting and cannot carry a required runtime check."
      },
      "summary": "Check compile-time invariants with const evaluation; keep required runtime checks active in release builds and never put needed logic inside ``debug_assert!``.",
      "rationale": "``debug_assert!`` disappears when debug assertions are off, which is the normal release setting. A check that only exists in test builds is not a check."
    },
    {
      "id": "SCR-RUST-041",
      "title": "Account for dependency and generated-code soundness",
      "misra_cpp_ids": [],
      "scope": "Transitive crates, standard library assumptions, macros and generators",
      "proposed_level": "Required",
      "origin": "S-CORE supplement (dependency and generated-code soundness)",
      "requirement": "Maintain the dependency/generator inventory and record the evidence relied on for unsafe implementations, feature selection and foreign code. Component safe-only status shall describe first-party source scope separately from the full linked dependency graph.",
      "enforcement": "Dependency lock/configuration review, unsafe/binding inventories, change-impact review and relevant integration tests.",
      "coverage_limit": "No-unsafe in first-party source is not a soundness proof for dependencies. The paper analyzes language constructs, not the delivered dependency graph.",
      "summary": "Keep an inventory of dependencies and code generators, record the evidence relied on for their unsafe code and features, and state clearly that a crate's safe-only status covers first-party code only.",
      "rationale": "``#![forbid(unsafe_code)]`` says nothing about the crates you link. Your soundness depends on every unsafe block in every dependency and every generated file."
    },
    {
      "id": "SCR-RUST-042",
      "title": "Assess foreign-language boundaries explicitly",
      "misra_cpp_ids": [
        "18.5.1",
        "21.10.2",
        "21.10.3",
        "22.4.1",
        "25.5.1",
        "25.5.2",
        "25.5.3"
      ],
      "scope": "Every Rust/C/C++ boundary",
      "proposed_level": "Required",
      "origin": "S-CORE supplement informed by MISRA C:2025 Addendum 6",
      "requirement": "Foreign bindings shall match the actual ABI, layout, types and exported definitions. Document ownership, pointer and length contracts, threading and callback lifetime, error conventions and unwinding behavior in both directions. No Rust panic shall reach a foreign frame and no foreign exception shall enter Rust. ``setjmp``/``longjmp`` and similar nonlocal transfers shall not cross a Rust frame. Signal handling, ``errno`` and error-state handling, the process-wide locale, and storage returned by C library functions shall follow the contracts in :ref:`rust_boundary_contracts_ffi`. Assess C and C++ implementations under their own applicable policy.",
      "enforcement": "Binding, layout and symbol review and tests on delivered targets; MISRA C:2025 Addendum 6 cross-check, whose comments on R.8.3, R.8.5, R.8.6 and R.8.15 provide boundary cross-references; review of each contract on the boundary contracts page.",
      "coverage_limit": "MISRA C:2025 Addendum 6 is an applicability assessment with 223 guideline entries. S-CORE has not yet derived and checked an obligation for every MISRA C guideline the addendum assesses as applicable to Rust boundaries; this supplement covers the boundary concerns of its linked MISRA C++ sources and the addendum comments on R.8.3, R.8.5, R.8.6 and R.8.15. Completing that derivation is open work for a later rulebook revision.",
      "summary": "Make every Rust/C boundary explicit: matching ABI and layout, documented ownership and lifetimes, no panic or exception crossing the boundary, and the C library's own rules for errno, locale, signals and returned storage.",
      "rationale": "FFI is where both languages' guarantees stop. A panic reaching an ``extern \"C\"`` frame aborts, a C++ exception entering Rust is undefined behaviour, and a pointer returned by ``getenv`` or ``localtime`` can be invalidated by the next call on another thread.",
      "adaptation_notes": "Adapts 18.5.1 (unwinding), 21.10.2 (``setjmp``/``longjmp``), 21.10.3 (signals, with the disabling exception), 22.4.1 (``errno`` writes; a Rust ``const`` equal to zero counts as a constant, computed values do not), 25.5.1 (locale changes prohibited), 25.5.2 (returned storage read-only; address-taking restriction adopted) and 25.5.3 (invalidation by later calls). Full per-API conditions are on the boundary contracts page."
    },
    {
      "id": "SCR-RUST-043",
      "title": "Record coverage, deviations and residual obligations",
      "misra_cpp_ids": [],
      "scope": "Every adopted guideline and delivered configuration",
      "proposed_level": "Required",
      "origin": "S-CORE governance supplement",
      "requirement": "Each required adopted rule shall have evidence of conformance or an approved scoped deviation. Record rule version, configuration, checker version, known blind spots and review/test evidence. Advisory nonconformances shall be considered and dispositioned. Safety-relevant liveness, timing and persistence guarantees need separate requirements and verification.",
      "enforcement": "Rule-to-checker coverage register, deviation validation and release evidence review. Separate test/tooling profiles shall not suppress production library obligations.",
      "coverage_limit": "A clean lint/SARIF report proves neither full rule coverage nor functional safety. This draft defines obligations; it installs no checker and grants no approval.",
      "summary": "For every adopted rule, record how it is checked, which checker version and configuration, what the checker misses, and every deviation with its owner.",
      "rationale": "A clean lint run is only evidence for the cases the lint sees. Without a record of coverage and blind spots, nobody can tell a verified rule from an unchecked one."
    }
  ]
}
