[
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-001",
    "links": [],
    "rationale": "One error-reporting path keeps call sites uniform and works from ISRs and across partitions; EmbCC compiles thread-local storage to a single instance on embedded targets, which rules out `errno`-style state (09 \u00a73).",
    "statement": "Every public function shall return `emb_status_t`, or a value type whose every value is documented, or `void` only when the function cannot fail. No public function shall report an error through a global or thread-local variable.",
    "status": "Accepted 2026-10-07",
    "title": "Return type discipline",
    "trace": "SPEC-001 \u00a74.4; ADR-002; 05 \u00a71.2",
    "verification": "Analysis: `tools/apidoc` rejects a public prototype whose return type is not `emb_status_t`, a documented value type, or `void`; a header grep forbids `errno`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-002",
    "links": [],
    "rationale": "Unbounded waits hidden in signatures are the first cause of hangs; absolute deadlines are what periodic real-time code needs to avoid drift (KRN-TIM-011).",
    "statement": "Every public function that may block shall take an `emb_timeout_t` as its last parameter and shall accept `EMB_NO_WAIT` and `EMB_WAIT_FOREVER`. Every such function shall have an absolute-deadline variant named with the `_until` qualifier taking an `emb_instant_t` as its last parameter.",
    "status": "Accepted 2026-10-07",
    "title": "Timeouts on blocking functions",
    "trace": "SPEC-001 \u00a73, \u00a77.4; ADR-002",
    "verification": "Analysis: `tools/apidoc` checks that every `@blocks timeout` function ends with `emb_timeout_t` and has a `_until` sibling ending with `emb_instant_t`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-003",
    "links": [],
    "rationale": "Documentation, static analysis, and the conformance-suite generator must read the same contract, or they drift from each other and from the code.",
    "statement": "Every public function shall carry the annotation tags `@ctx`, `@blocks`, `@time`, `@owns`, `@config`, `@req`, `@since`, and `@stable` in its documentation comment, with values from the grammar in SPEC-001 \u00a79. A missing or malformed mandatory tag shall fail the build's documentation gate.",
    "status": "Accepted 2026-10-07",
    "title": "Machine-readable contract annotations",
    "trace": "SPEC-001 \u00a79; 05 \u00a71.4",
    "verification": "Analysis: `tools/apidoc` parses every header under `include/emb/` and fails on a missing or invalid tag; its JSON output validates against `tools/apidoc/schema.json`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-004",
    "links": [],
    "rationale": "The headers are the contract with three compilers and two languages; EmbCC does not enforce a standard level, so GCC and Clang do (09 \u00a73).",
    "statement": "Every public header shall compile without warnings under the project warning set as C11 (`-std=c11 -pedantic` on GCC and Clang) and as C++17, on EmbCC, GCC, and Clang, for every supported target.",
    "status": "Accepted 2026-10-07",
    "title": "Header portability",
    "trace": "SPEC-001 \u00a78; ADR-023",
    "verification": "Test: `tests/api/headers/` compiles each header alone and the umbrella header, in C and C++, across the compiler matrix."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-005",
    "links": [
      "KRN-CAP-001"
    ],
    "rationale": "Application source must move between the tiny, base, and isolated profiles unchanged (principle 9).",
    "statement": "The public API shall be identical in names, signatures, and documented semantics for privileged and unprivileged callers. The build shall select a direct call or a system-call stub per partition without changing the header a caller includes.",
    "status": "Accepted 2026-10-07",
    "title": "One API for all privilege levels",
    "trace": "SPEC-001 \u00a75.3; 03 \u00a78.1; KRN-CAP-001",
    "verification": "Test: the conformance suite builds and passes once as privileged and once inside an unprivileged partition on the isolated profile, from the same sources."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-006",
    "links": [],
    "rationale": "A predictable prefix lets tooling key on the API, and `embOS` is an existing commercial RTOS trademark (ADR-002).",
    "statement": "Identifiers beginning with `emb_`, `EMB_`, or `Emb` shall be reserved for the project. Identifiers beginning with `__emb_` or `_EMB_` shall appear only in generated headers and the compiler-portability layer. No project identifier shall contain the sequence `embos` in any letter case.",
    "status": "Accepted 2026-10-07",
    "title": "Namespace reservation",
    "trace": "SPEC-001 \u00a72; ADR-002",
    "verification": "Analysis: identifier scan in CI over `include/`, `kernel/`, `arch/`, `drivers/`, `subsys/`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-007",
    "links": [],
    "rationale": "Uniform names make the API learnable from one example per verb and let generated documentation group operations by subject.",
    "statement": "Every public function shall be named `emb_<subject>_<verb>[_<qualifier>]` with the verb taken from the standard verb table in SPEC-001 \u00a73. A subject introducing a verb not in the table shall document it in that subject's specification. Public types shall be named `emb_<subject>[_<noun>]_t`; public macros and enumerators `EMB_<SUBJECT>_<NAME>`.",
    "status": "Accepted 2026-10-07",
    "title": "Identifier grammar",
    "trace": "SPEC-001 \u00a73",
    "verification": "Analysis: `tools/apidoc` checks every public identifier against the grammar and the verb table."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-008",
    "links": [],
    "rationale": "A fixed order removes a class of call-site mistakes and lets the annotation checker identify the typed timeout and explicit argument relationships mechanically (API-002).",
    "statement": "Public function parameters shall appear in the order: object handle, input parameters, timeout/deadline where applicable, then output parameters named with the prefix `out_`; functions without outputs place the timeout last. The existing per-function prototype is authoritative (A26).",
    "status": "Accepted 2026-10-07",
    "title": "Parameter order",
    "trace": "SPEC-001 \u00a73",
    "verification": "Analysis: `tools/apidoc` checks parameter order and `out_` naming."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-009",
    "links": [],
    "rationale": "A zero timeout is `EMB_NO_WAIT`; ISR safety is a documented property of the single function (ADR-003). Duplicates double the surface and the documentation.",
    "statement": "The public API shall not define functions whose names end in `_try` or `_from_isr`, nor any other duplicated variant whose only difference is the calling context or a zero timeout.",
    "status": "Accepted 2026-10-07",
    "title": "No `_try` and no `_from_isr` variants",
    "trace": "SPEC-001 \u00a73, \u00a75.2; ADR-003",
    "verification": "Analysis: identifier scan."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-010",
    "links": [],
    "rationale": "Status values cross the syscall boundary, appear in trace and crash records, and are stored by applications; they are ABI.",
    "statement": "Each status code's numeric value shall be fixed when first released and shall never change or be reused. Kernel core codes shall occupy -1 to -31, kernel reserved -32 to -63, driver classes and subsystems -64 to -127, application-defined -128 to -255. No status value below -255 shall be defined.",
    "status": "Accepted 2026-10-07",
    "title": "Stable status values",
    "trace": "SPEC-001 \u00a74.2",
    "verification": "Test: `tests/api/status/` asserts every value against a frozen table; Analysis: enumerators outside their range fail a header check."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-011",
    "links": [],
    "rationale": "A closed, small set keeps error handling uniform and each code's meaning unambiguous across subsystems.",
    "statement": "The kernel shall define exactly the status codes `EMB_OK`, `EMB_EPERM`, `EMB_EINVAL`, `EMB_EBUSY`, `EMB_ETIMEDOUT`, `EMB_ECANCELED`, `EMB_EDESTROYED`, `EMB_EOWNERDEAD`, `EMB_ENOMEM`, `EMB_ENOTSUP`, `EMB_EIO`, `EMB_EFAULT`, `EMB_ENOENT`, `EMB_EEXIST`, `EMB_ESTATE`, `EMB_EOVERFLOW`, `EMB_ESTALE`, and `EMB_EINTR` with the values and meanings in SPEC-001 \u00a74.2. A driver class or subsystem shall define its additional codes in its own specification within its range.",
    "status": "Accepted 2026-10-07",
    "title": "Status code set",
    "trace": "SPEC-001 \u00a74.2",
    "verification": "Test: `tests/api/status/`; Inspection of each subsystem specification for range compliance."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-012",
    "links": [
      "KRN-WAIT-004"
    ],
    "rationale": "One outcome, one code; the wait protocol produces the single result `TIMEOUT` for both cases (03 \u00a73.5).",
    "statement": "A blocking function whose awaited condition does not become true within the allowed wait shall return `EMB_ETIMEDOUT`, including when the allowed wait is `EMB_NO_WAIT`.",
    "status": "Accepted 2026-10-07",
    "title": "One code for an unsatisfied wait",
    "trace": "SPEC-001 \u00a74.2; KRN-WAIT-004",
    "verification": "Test: conformance tests for every blocking primitive with `EMB_NO_WAIT` and with a finite timeout."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-013",
    "links": [],
    "rationale": "Callers and tests can rely on a deterministic code when several faults coincide.",
    "statement": "When more than one error applies to a call, the function shall report in this order: `EMB_EPERM`, then `EMB_EINVAL`, then `EMB_ESTALE`, then state and resource errors, then wait-result errors.",
    "status": "Accepted 2026-10-07",
    "title": "Error precedence",
    "trace": "SPEC-001 \u00a74.4",
    "verification": "Test: conformance misuse tests that combine two faults."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-014",
    "links": [
      "KRN-IRQ-010",
      "KRN-IRQ-011"
    ],
    "rationale": "The context class is the contract that replaces duplicated ISR variants (ADR-003) and is what static analysis checks at call sites.",
    "statement": "Every public function shall belong to exactly one context class declared by its `@ctx` tag: ISR-safe (`thread isr`, optionally `prekernel`), thread-only (`thread`), or pre-kernel (`prekernel`, optionally `thread`). An ISR-safe function shall never block and shall have a `@time` bound that names its variables.",
    "status": "Accepted 2026-10-07",
    "title": "Context classes",
    "trace": "SPEC-001 \u00a75.2; KRN-IRQ-010, KRN-IRQ-011",
    "verification": "Analysis: `tools/apidoc` validates tag combinations; Test: each `thread isr` function is exercised from an ISR in the conformance suite."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-015",
    "links": [],
    "rationale": "Fail loudly in development and predictably in production, without ever silently converting misuse into different behavior (principle 11).",
    "statement": "API misuse (wrong context, blocking with a nonzero timeout while the scheduler is locked or in a critical section, invalid handle, null required pointer, out-of-range constant, non-owner unlock, destroy with waiters without `ABORT_WAITERS`, misaligned or undersized storage) shall raise a kernel fault in checked builds and return the status in SPEC-001 \u00a75.3 in release builds. Runtime conditions (`EMB_ESTATE`, `EMB_ESTALE`, `EMB_EBUSY` for resources, `EMB_ENOMEM`, `EMB_ENOTSUP`, and the wait results) shall return their status in both build kinds.",
    "status": "Accepted 2026-10-07",
    "title": "Misuse behavior",
    "trace": "SPEC-001 \u00a75.3; 01 \u00a73 principle 11",
    "verification": "Test: `tests/conformance/misuse/` runs every row of the table in both build kinds (TEST-010)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-016",
    "links": [
      "KRN-CAP-002"
    ],
    "rationale": "A partition must not be able to take the system down by misusing the API (KRN-CAP-002, KRN-PART-003).",
    "statement": "In isolated profiles, a call entering the kernel from an unprivileged partition shall have every check of API-015 performed at the system-call boundary and shall return a status to the caller; it shall never raise a kernel fault.",
    "status": "Accepted 2026-10-07",
    "title": "No kernel fault from an unprivileged caller",
    "trace": "SPEC-001 \u00a75.3; KRN-CAP-002",
    "verification": "Test: the misuse suite runs inside an unprivileged partition and observes statuses only."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-017",
    "links": [],
    "rationale": "A fault without its cause costs a reproduction; the crash record exists to avoid that (FLT-001).",
    "statement": "A kernel fault raised by API misuse shall record the fault class, the public function identifier, and the index of the offending argument in the crash record.",
    "status": "Accepted 2026-10-07",
    "title": "Misuse faults are attributable",
    "trace": "SPEC-001 \u00a75.3; 03 \u00a710.2",
    "verification": "Test: provoke each misuse class on the native port and decode the crash record."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-018",
    "links": [
      "KRN-CAP-001"
    ],
    "rationale": "One word costs the same as a pointer on every ABI, the struct keeps object types apart at compile time, and the representation can change by profile without changing a signature (ADR-014).",
    "statement": "Every kernel object handle shall be a struct type containing a single `uintptr_t`, declared with `EMB_DECLARE_HANDLE`, distinct per object type, passed and returned by value. Applications shall operate on handles only by copying, by `EMB_HANDLE_EQ`, and by `EMB_HANDLE_IS_NULL`. The same declaration shall serve the pointer, tagged-pointer, and table-index representations.",
    "status": "Accepted 2026-10-07",
    "title": "Handle representation",
    "trace": "SPEC-001 \u00a76.1; KRN-CAP-001",
    "verification": "Analysis: header check that every `*_t` object handle is declared via `EMB_DECLARE_HANDLE`; Test: `sizeof(handle) == sizeof(uintptr_t)` on every target."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-019",
    "links": [],
    "rationale": "Opaque objects and static allocation are both required (KRN-MEM-002, KRN-TCB-008); generated sizes reconcile them without compiler extensions (ADR-006).",
    "statement": "Every kernel object type shall have a generated storage type `emb_<object>_storage_t` and constants `EMB_<OBJECT>_STORAGE_SIZE` and `EMB_<OBJECT>_STORAGE_ALIGN` derived from the configured kernel layout. The kernel shall assert at compile time that the real object fits the generated size and alignment.",
    "status": "Accepted 2026-10-07",
    "title": "Generated storage types",
    "trace": "SPEC-001 \u00a76.2; ADR-006",
    "verification": "Analysis: `_Static_assert` in the kernel; Test: configuration-matrix build."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-020",
    "links": [],
    "rationale": "Fixed-width fields keep layout independent of enum size (EmbCC enums are `int`, 09 \u00a74); the default function serves C++17, which lacks designated initializers.",
    "statement": "Construction options shall be passed in a plain struct `emb_<object>_attr_t` whose fields are fixed-width integers or pointers; a `NULL` attribute pointer shall select defaults; and a function `emb_<object>_attr_default()` shall fill a struct with the defaults.",
    "status": "Accepted 2026-10-07",
    "title": "Attribute structs",
    "trace": "SPEC-001 \u00a76.3",
    "verification": "Analysis: header check of attribute struct field types; Test: `attr_default` followed by `init` equals `init(NULL)` for every object."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-021",
    "links": [
      "KRN-OBJ-001",
      "KRN-OBJ-003"
    ],
    "rationale": "Static definition without hand-written init code is how tables of objects stay in data, not code (principle 14).",
    "statement": "Every object type shall provide `emb_<object>_init(storage, attr, out_handle)` with context class pre-kernel and thread, which shall set `*out_handle` to `EMB_HANDLE_NULL` on failure, and `emb_<object>_destroy(handle)`. A compile-time `EMB_<OBJECT>_DEFINE` form shall declare storage and handle and register the object in the generated initialization table.",
    "status": "Accepted 2026-10-07",
    "title": "Construction and destruction",
    "trace": "SPEC-001 \u00a76.4; KRN-OBJ-001, KRN-OBJ-003",
    "verification": "Test: conformance init/destroy and `_DEFINE` tests per object type."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-022",
    "links": [
      "KRN-TIM-010"
    ],
    "rationale": "Passing an instant where a duration is expected is a silent real-time bug in scalar-typed APIs; the struct makes it a compile error (ADR-002). Macros avoid EmbCC's inliner limit on struct-valued helpers (09 \u00a77).",
    "statement": "The public API shall use three distinct struct types over `emb_tick_t`: `emb_instant_t` for points on the kernel monotonic clock, `emb_duration_t` for lengths of time, and `emb_timeout_t` for permitted waits, with the sentinels `EMB_NO_WAIT` and `EMB_WAIT_FOREVER`. Constructors `EMB_TICKS`, `EMB_NS`, `EMB_US`, `EMB_MS`, `EMB_SEC`, and `EMB_TIMEOUT` shall be macros usable in constant initializers.",
    "status": "Accepted 2026-10-07",
    "title": "Distinct time types",
    "trace": "SPEC-001 \u00a77.1, \u00a77.3; KRN-TIM-010",
    "verification": "Test: negative compile tests that mixing the types fails; positive tests of constant initializers on all compilers."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-023",
    "links": [
      "KRN-TIM-007"
    ],
    "rationale": "A wait must never be shorter than requested, and silent truncation is the overflow class KRN-TIM-007 forbids.",
    "statement": "The tick length shall be the configuration constant `CONFIG_EMB_TICK_NS`. Conversion from a duration to ticks shall round up; conversion from ticks to a duration shall be exact. Unit conversions shall saturate for constants and runtime values, with caller-detectable saturation. No generic compile-time overflow diagnostic is promised; raw `EMB_TICKS` requires a representable input (A1).",
    "status": "Accepted 2026-10-07",
    "title": "Time conversion rules",
    "trace": "SPEC-001 \u00a77.2, \u00a77.3; KRN-TIM-007",
    "verification": "Test: `tests/api/time/` conversion vectors including boundary and saturation cases in the 64-bit and 32-bit tick profiles."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-024",
    "links": [
      "KRN-TIM-001",
      "KRN-TIM-003",
      "KRN-TIM-011"
    ],
    "rationale": "These are the timing promises applications build periodic and watchdog logic on; they must be stated to be measured (KRN-RT-001).",
    "statement": "Satisfaction, cancellation or destruction may complete a blocking call before its timeout. For an unsatisfied wait, expiry shall make the waiter eligible to return a timeout result; actual return shall include dispatch delay, suspension/eligibility and any mandatory mutex reacquisition. A finite return-time bound shall be claimed only under documented workload/resource assumptions. `EMB_NO_WAIT` shall never block or yield. A past `_until` wait shall use the nonblocking path; sleep with a zero duration or past deadline shall yield with `EMB_OK` (SPEC-003 \u00a76).",
    "status": "Accepted 2026-10-07",
    "title": "Blocking time bounds",
    "trace": "SPEC-001 \u00a77.4; KRN-TIM-001, KRN-TIM-003, KRN-TIM-011",
    "verification": "Test: timeout accuracy tests on the native port with virtual time; Demonstration: HIL latency benchmarks record the bound per board."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-025",
    "links": [],
    "rationale": "Headers are the ABI surface for three compilers and two languages (API-004); each rule removes a known portability or layout hazard, including those EmbCC documents (09 \u00a73, \u00a74).",
    "statement": "Every public header shall have an include guard named `EMB_<PATH>_H`, wrap declarations in `extern \"C\"` for C++, include only `<stddef.h>`, `<stdint.h>`, `<stdbool.h>`, and `<emb/...>` headers, and shall contain no variable-length arrays, no bit-fields in structs that cross the API, no anonymous structs, no `volatile`, no function definitions other than trivial `static inline` accessors, and no macro that evaluates an argument more than once. Pointers to input data shall be `const`. Structs that cross the API shall use fixed-width members with explicit padding.",
    "status": "Accepted 2026-10-07",
    "title": "Public header rules",
    "trace": "SPEC-001 \u00a78",
    "verification": "Analysis: header lint in CI (guard names, include list, forbidden constructs); Inspection for padding."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-026",
    "links": [],
    "rationale": "The headers are included from C++ unchanged (API-004).",
    "statement": "No public identifier, parameter name, or struct member shall be a C++17 keyword.",
    "status": "Accepted 2026-10-07",
    "title": "No C++ keywords",
    "trace": "SPEC-001 \u00a78",
    "verification": "Analysis: identifier scan against the C++17 keyword list."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-027",
    "links": [],
    "rationale": "EmbCC's enums are always `int`-sized and `-fshort-enums` is refused; layouts must not depend on it (09 \u00a74).",
    "statement": "A struct that crosses the API shall store enumeration values in fixed-width integer fields, not in `enum`-typed fields. An `enum` type shall appear in a prototype only when its value set is closed and fully documented.",
    "status": "Accepted 2026-10-07",
    "title": "Enumerations in the API",
    "trace": "SPEC-001 \u00a76.3, \u00a78",
    "verification": "Analysis: header lint."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-028",
    "links": [],
    "rationale": "One parser, one truth; three consumers that each parse would disagree in corner cases.",
    "statement": "The annotation tool shall export one JSON object per public function containing every tag of API-003 with parsed values, validated against a published schema, and the reference manual, the static-analysis rules, and the conformance-suite generator shall consume that export rather than re-parsing headers.",
    "status": "Accepted 2026-10-07",
    "title": "Annotation export",
    "trace": "SPEC-001 \u00a79; 05 \u00a71.4",
    "verification": "Analysis: schema validation in CI; Inspection that the three consumers import the export."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-029",
    "links": [
      "PORT-ABI-002"
    ],
    "rationale": "Scattered `__attribute__` and `__builtin_` uses are how toolchain independence is lost (PORT-ABI-002, BLD-002).",
    "statement": "Generic kernel, port-independent, driver, and subsystem code shall express compiler-specific attributes and builtins only through the macros of SPEC-001 \u00a710, defined in `include/emb/compiler/<compiler>.h`. Each macro shall have a defined fallback so that an unknown compiler compiles with the generic header.",
    "status": "Accepted 2026-10-07",
    "title": "Compiler portability layer",
    "trace": "SPEC-001 \u00a710; PORT-ABI-002; BLD-002",
    "verification": "Analysis: CI grep forbids `__attribute__`, `__builtin_`, and `__asm` outside `include/emb/compiler/` and `arch/`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-030",
    "links": [],
    "rationale": "Products on long support windows need a written compatibility promise (05 \u00a77.1).",
    "statement": "The headers shall define `EMB_VERSION_MAJOR`, `EMB_VERSION_MINOR`, `EMB_VERSION_PATCH`, `EMB_VERSION`, and `EMB_API_VERSION`, and the kernel shall provide `emb_version_string()`. From release 1.0, a function tagged `@stable yes` shall keep its signature and documented semantics for all 1.x releases; a compatible addition shall increment `EMB_API_VERSION`; a deprecated function shall carry `EMB_DEPRECATED` and `@stable deprecated:<version>` and remain for at least one minor release; experimental functions shall live under `include/emb/experimental/`.",
    "status": "Accepted 2026-10-07",
    "title": "Versioning and stability",
    "trace": "SPEC-001 \u00a711; 05 \u00a77",
    "verification": "Analysis: API export diff between releases fails CI on an incompatible change to a `@stable yes` function; Inspection of release notes."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-031",
    "links": [],
    "rationale": "Callback context confusion is a classic RTOS bug class; variadics defeat annotation and type checking and are poorly supported for inlining on EmbCC (09 \u00a77).",
    "statement": "Every public callback type shall document its execution context in the same terms as `@ctx`. No public function shall be variadic or take a variadic function, except the logging macros, which shall expand to deferred-format calls.",
    "status": "Accepted 2026-10-07",
    "title": "Callbacks and variadics",
    "trace": "SPEC-001 \u00a712; ADR-009",
    "verification": "Analysis: prototype scan for `...`; Inspection of callback documentation."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/API.md",
    "evidence": "not evaluated",
    "group": "API",
    "id": "API-032",
    "links": [
      "KRN-THR-014"
    ],
    "rationale": "Hidden state is unsafe from ISRs and across partitions and is impossible on targets where thread-local storage is a single instance (09 \u00a73).",
    "statement": "The kernel shall keep no global or per-thread last-error state. `emb_status_name()` shall be available when `CONFIG_EMB_STATUS_NAMES` is enabled and shall otherwise compile out.",
    "status": "Accepted 2026-10-07",
    "title": "No hidden error state",
    "trace": "SPEC-001 \u00a74.3; KRN-THR-014",
    "verification": "Analysis: symbol scan of the kernel image for error-state objects; Test: `emb_status_name` presence per configuration."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/ARCH-AVR.md",
    "evidence": "not evaluated",
    "group": "ARCH-AVR",
    "id": "ARCH-AVR-001",
    "links": [],
    "rationale": "SPEC-012 \u00a72; ADR-036.",
    "statement": "The AVR port shall declare 8-bit words, 16-bit pointers, byte stack alignment, a 37-byte context frame, no nesting, no zero-latency class, no compare-and-swap, no interrupt stack, no protection, no fault entry, and tickless limited to idle modes; the tiny defaults (table scheduler, 32-bit time, 8-bit notifications, no system work queue, no idle thread) shall be mandatory on it.",
    "status": "Accepted 2026-10-07",
    "title": "Manifest and tiny defaults",
    "trace": "SPEC-012 \u00a72",
    "verification": "Manifest schema check; configuration test refusing the isolated profile on AVR."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/ARCH-AVR.md",
    "evidence": "not evaluated",
    "group": "ARCH-AVR",
    "id": "ARCH-AVR-002",
    "links": [],
    "rationale": "One switch path (PORT-004) and the cheapest possible P1 on a core without an interrupt stack.",
    "statement": "The thread-context switch, the interrupt epilogue switch, and the initial frame shall use the single 35-byte frame layout (37-byte call/context reserve) of SPEC-012 \u00a74.1 (return address, `r0`, `SREG`, `r1`, `r2..r31`), so that an interrupt-exit switch is an exchange of stack pointers.",
    "status": "Accepted 2026-10-07",
    "title": "One frame layout",
    "trace": "SPEC-012 \u00a74",
    "verification": "Test: `arch/avr/frame_layout`, `arch/avr/switch_from_isr_and_thread_interoperate`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/ARCH-AVR.md",
    "evidence": "not evaluated",
    "group": "ARCH-AVR",
    "id": "ARCH-AVR-003",
    "links": [],
    "rationale": "The actual restore tail and pending IRQ entry must be validated together; the historical out/ret-only description did not match the assembly.",
    "statement": "The switch and launch sequences shall restore the incoming SREG and r0 before `ret`; M1 uses `out SREG; pop r0; ret`. A physical pending-interrupt test shall establish coherent context throughout that tail; a one-instruction enable delay shall not be used to claim the intervening pop is absent or the return necessarily precedes IRQ entry (A27).",
    "status": "Accepted 2026-10-07",
    "title": "Atomic launch and switch tail",
    "trace": "SPEC-012 \u00a74.2, \u00a74.3",
    "verification": "Test: `arch/avr/launch_with_pending_interrupt`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/ARCH-AVR.md",
    "evidence": "not evaluated",
    "group": "ARCH-AVR",
    "id": "ARCH-AVR-004",
    "links": [],
    "rationale": "SPEC-002 \u00a76.2, \u00a77.2 on this core.",
    "statement": "`EMB_ISR` shall save the full frame with `I` forced set in the saved `SREG`, run the body with interrupts masked, and switch at exit when a reschedule is pending and the scheduler is unlocked; `EMB_ISR_RAW` shall be a `signal` handler that may not call the kernel; every thread stack shall include `CONFIG_EMB_AVR_ISR_STACK_RESERVE` (default 64 bytes), documented per release from supported compiler stack reports plus call-graph/disassembly accounting of naked routines; avr-gcc cannot report those routines with `-fstack-usage`.",
    "status": "Accepted 2026-10-07",
    "title": "Interrupt prologue, epilogue, and reserve",
    "trace": "SPEC-012 \u00a74.4, \u00a75",
    "verification": "Test: `arch/avr/isr_frame`, `arch/avr/isr_reserve_check`; documentation review."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/ARCH-AVR.md",
    "evidence": "not evaluated",
    "group": "ARCH-AVR",
    "id": "ARCH-AVR-005",
    "links": [],
    "rationale": "SPEC-003 \u00a713; KRN-TIM-036.",
    "statement": "The default tick shall be an exact 1 ms Timer1 CTC interrupt (prescaler 64, `OCR1A = 249` at 16 MHz); tickless shall use Timer1 free-running at prescaler 256 with a 1.048 s `MAX_INTERVAL`; arming latency shall be measured at init; `emb_arch_cycles` shall be a prescaled 32-bit count with its resolution documented; deep sleep shall be `EMB_ENOTSUP` until a tick-loss policy exists.",
    "status": "Accepted 2026-10-07",
    "title": "Timer1 modes and latency",
    "trace": "SPEC-012 \u00a77",
    "verification": "HIL test: tick exactness over one minute against the host clock; `arch/avr/tickless_hop`; latency measurement test."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/ARCH-AVR.md",
    "evidence": "not evaluated",
    "group": "ARCH-AVR",
    "id": "ARCH-AVR-006",
    "links": [],
    "rationale": "R-003 \u00a74.",
    "statement": "The tiny reference configuration on this port shall fit the T1 and T2 targets: kernel text at most 4 KB at `-Os` on EmbCC and avr-gcc, kernel static RAM at most 64 bytes, TCB at most 32 bytes; the footprint test shall enforce them from the map file.",
    "status": "Accepted 2026-10-07",
    "title": "Footprint budget",
    "trace": "SPEC-012 \u00a78, \u00a713",
    "verification": "Footprint test in CI on both compilers."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/ARCH-AVR.md",
    "evidence": "not evaluated",
    "group": "ARCH-AVR",
    "id": "ARCH-AVR-007",
    "links": [],
    "rationale": "09 \u00a72 (`const` in RAM), \u00a77 (no linker scripts on AVR); HW-006.",
    "statement": "Kernel tables shall use `EMB_FLASH_CONST` and its accessors so that avr-gcc places them in program memory while EmbCC builds still work; large tables shall be compiled out on tiny; the generator shall emit the `embld` option set and a GNU ld script for the board from one region model.",
    "status": "Accepted 2026-10-07",
    "title": "Flash constants and linker outputs",
    "trace": "SPEC-012 \u00a78",
    "verification": "Footprint comparison EmbCC versus avr-gcc; generator test for both outputs."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/ARCH-AVR.md",
    "evidence": "not evaluated",
    "group": "ARCH-AVR",
    "id": "ARCH-AVR-008",
    "links": [],
    "rationale": "No fault hardware; the watchdog and the guards are the only safety nets.",
    "statement": "Checked builds on this port shall enable the switch-out stack guard check, the interrupt-reserve check, and the software watchdog service; a kernel fault shall write the small crash record to `.noinit` and reset through the watchdog by default.",
    "status": "Accepted 2026-10-07",
    "title": "Robustness without faults",
    "trace": "SPEC-012 \u00a78, \u00a79; FLT-001, FLT-004",
    "verification": "Test: `arch/avr/guard_detects_overflow`, `arch/avr/crash_record_survives_wdt_reset`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/ARCH-AVR.md",
    "evidence": "not evaluated",
    "group": "ARCH-AVR",
    "id": "ARCH-AVR-009",
    "links": [],
    "rationale": "EmbCC's AVR DWARF and remote layout are now implemented (09 \u00a77/\u00a79, reviewed 2026-10-14), but tool capability does not replace RTOS target/session qualification (SIM-002, SIM-003). The original acceptance date below is design status, not evidence that those runs passed.",
    "statement": "Symbolic debugging shall use the qualified avr-gcc reference build until the EmbCC RTOS debugging path is qualified; the EmbCC build shall be verified by the conformance suite under QEMU and on the `arduino_uno` board, and timing from emulation shall never be published.",
    "status": "Accepted 2026-10-07",
    "title": "Debug and emulation path",
    "trace": "SPEC-012 \u00a710, \u00a712",
    "verification": "CI: QEMU AVR run of the conformance suite on both compilers; HIL run on the Uno."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/ARCH-AVR.md",
    "evidence": "not evaluated",
    "group": "ARCH-AVR",
    "id": "ARCH-AVR-010",
    "links": [],
    "rationale": "A new board on this SoC is a description file (01 \u00a76).",
    "statement": "`boards/arduino/arduino_uno.yaml` shall describe the 16 MHz crystal, the USART0 console, the user LED, and the flash partitions leaving Optiboot's 512 bytes reserved; board init shall configure only the console and the LED.",
    "status": "Accepted 2026-10-07",
    "title": "Board description",
    "trace": "SPEC-012 \u00a711",
    "verification": "Generator test; boot test on the board."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-001",
    "links": [],
    "rationale": "No hand-written board C for things the description knows (01 \u00a76).",
    "statement": "Every peripheral instance, interrupt binding, clock setting, pin assignment, memory region, and flash partition shall originate in the hardware description.",
    "status": "Accepted 2026-10-07",
    "title": "Single source for hardware facts",
    "trace": "SPEC-014 \u00a73 to \u00a76; ADR-004",
    "verification": "Analysis: CI grep for register addresses and IRQ numbers in `boards/` and `soc/` C sources; review of generated outputs."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-002",
    "links": [],
    "rationale": "Authors fix descriptions, not generator stack traces.",
    "statement": "The hardware model shall be validated against a published schema before generation; validation errors shall name the file and node.",
    "status": "Accepted 2026-10-07",
    "title": "Schema validation with named errors",
    "trace": "SPEC-014 \u00a71, \u00a77",
    "verification": "Generator tests with malformed inputs; the error message names file and node path."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-003",
    "links": [],
    "rationale": "BLD-004; drift between description and code is the failure this pipeline prevents.",
    "statement": "Generated files shall be reproducible and never edited by hand.",
    "status": "Accepted 2026-10-07",
    "title": "Reproducible generated files",
    "trace": "SPEC-014 \u00a79",
    "verification": "CI regenerates and diffs against the committed outputs."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-004",
    "links": [],
    "rationale": "Authors curate rather than transcribe.",
    "statement": "Importers for CMSIS-SVD and DeviceTree source shall exist to bootstrap SoC and board descriptions; the SVD importer builds on EmbCC's `embsvd` parser (09 \u00a79).",
    "status": "Accepted 2026-10-07",
    "title": "SVD and DeviceTree importers",
    "trace": "SPEC-014 \u00a78",
    "verification": "Importer tests on the STM32F407 SVD and a Zephyr board DTS; the drafts validate and carry provenance."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-005",
    "links": [],
    "rationale": "EmbStudio, EmbDebug, the HIL runner, and the harness consume one artifact and never parse YAML.",
    "statement": "The normalized model shall be exported in a stable JSON form for tooling.",
    "status": "Accepted 2026-10-07",
    "title": "Normalized JSON export",
    "trace": "SPEC-014 \u00a76, \u00a79",
    "verification": "Schema for `hw.json`; consumer tests."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-006",
    "links": [],
    "rationale": "Preserve a common layout with the legacy AVR option-set path. EmbCC now supports AVR scripts (09 \u00a77, reviewed 2026-10-14); the existing two-output contract is retained, not justified by a current compiler limitation. Removing that compatibility output requires a separate reviewed amendment; the generator remains unimplemented.",
    "statement": "From the same region model, the generator shall emit both a GNU ld linker script and an `embld` option set (`-Ttext`, `-Tdata`, `--rom-limit`); the two outputs shall be tested for agreement.",
    "status": "Accepted 2026-10-07",
    "title": "Two linker outputs from one region model",
    "trace": "SPEC-014 \u00a76; SPEC-012 \u00a78",
    "verification": "Generator test comparing the memory maps produced by both outputs for the Uno board."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-007",
    "links": [],
    "rationale": "One grammar for every hardware fact; DeviceTree's good ideas without its macro layer (R-002 \u00a71).",
    "statement": "Descriptions shall be YAML 1.2 files of kind `soc`, `board`, or `system` with a `schema_version`, validated by JSON Schema 2020-12, supporting unit suffixes, cross-file references, `extends` inheritance, provenance, `curated` marks, and `doc` text.",
    "status": "Accepted 2026-10-07",
    "title": "Three description kinds and common conventions",
    "trace": "SPEC-014 \u00a71, \u00a72",
    "verification": "Schema files exist for the three kinds; conformance of the shipped descriptions."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-008",
    "links": [],
    "rationale": "SPEC-014 \u00a73, \u00a74 fix what the generator can rely on.",
    "statement": "A SoC description shall carry `arch`, `cpu`, `memory`, `interrupts`, and `peripherals` (clocks, DMA, flash, power, errata, debug optional) and shall reference a port manifest; a board description shall carry the SoC reference, oscillators, pins, devices, console, flash partitions, LEDs, buttons, probe hints, and defaults.",
    "status": "Accepted 2026-10-07",
    "title": "SoC and board content",
    "trace": "SPEC-014 \u00a73, \u00a74",
    "verification": "Schema required fields; the STM32F407, RP2350, and ATmega328P descriptions validate."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-009",
    "links": [],
    "rationale": "SPEC-009 \u00a74.1, \u00a75.2; SPEC-010 \u00a72; SPEC-005 \u00a73.4.",
    "statement": "The system description shall declare the profile, configuration overrides, partitions, kernel-partition threads and objects, ceiling mutexes with users, shares, trace and log configuration, and images; the generator shall derive kstore sizes, capability tables, ceilings, and init ordering from it.",
    "status": "Accepted 2026-10-07",
    "title": "System description as the static source",
    "trace": "SPEC-014 \u00a75",
    "verification": "Generator tests for a two-partition system; the isolated reference configuration is one."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-010",
    "links": [],
    "rationale": "The complete list is what downstream specifications depend on.",
    "statement": "The generator shall emit `hw_config.h`, `soc_devices.c`, `soc_clocks.c`, `board_pins.c`, `regions.ld` and `embld.opts`, `partitions.c`, `caps_init.c`, `ceilings.h`, `init_order.c`, `Kconfig.board` and `Kconfig.system`, `board.md`, `hw.json`, `build_report.md`, and the CTF trace metadata, each as SPEC-014 \u00a76 describes.",
    "status": "Accepted 2026-10-07",
    "title": "Generated outputs",
    "trace": "SPEC-014 \u00a76",
    "verification": "Generator golden-file tests per output."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-011",
    "links": [],
    "rationale": "Every rule here was a runtime bug somewhere else.",
    "statement": "The generator shall fail the build, naming file and node, on unresolved references, duplicate names, overlapping or misaligned regions or partitions, independently writable flash partitions sharing erase units or violating write/update alignment, duplicate or out-of-range interrupts, pin conflicts, clock cycles or bus overspeed, dependency cycles, partition hardware constraint violations, undeclared ceiling users, port manifest mismatches, inapplicable errata, and uncurated nodes under the `safety` attribute.",
    "status": "Accepted 2026-10-07",
    "title": "Semantic validation",
    "trace": "SPEC-014 \u00a77",
    "verification": "One negative generator test per rule."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-012",
    "links": [],
    "rationale": "Curation is the value; tooling must not destroy it.",
    "statement": "Importers shall produce drafts with `imported_from` provenance and `todo` markers; re-import shall produce a diff for the author and shall never overwrite curated nodes.",
    "status": "Accepted 2026-10-07",
    "title": "Importers produce drafts, never overwrites",
    "trace": "SPEC-014 \u00a78",
    "verification": "Importer tests: re-import after curation leaves curated nodes intact and reports differences."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-013",
    "links": [],
    "rationale": "HW-003 made checkable.",
    "statement": "Generated outputs shall be sorted, free of timestamps, and stamped with the generator version, schema version, and input hashes; `hw.json` shall carry the same stamps.",
    "status": "Accepted 2026-10-07",
    "title": "Determinism and stamps",
    "trace": "SPEC-014 \u00a79",
    "verification": "Two generator runs produce identical outputs; stamp fields present."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-014",
    "links": [],
    "rationale": "Descriptions are long-lived assets of users.",
    "statement": "Schema v0 is unstable until its own stable release and ships a migration tool for breaking changes; from that release the schema shall follow the API versioning policy.",
    "status": "Accepted 2026-10-07",
    "title": "Schema versioning and migration",
    "trace": "SPEC-014 \u00a710; SPEC-001 \u00a711",
    "verification": "Migration test on a v0 fixture at each breaking change."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/HW.md",
    "evidence": "not evaluated",
    "group": "HW",
    "id": "HW-015",
    "links": [],
    "rationale": "One source for the numbers that make measurements comparable (R-003 \u00a76).",
    "statement": "`hw.json` shall provide the board, SoC revision, clock, and timer-source fields the benchmark metadata record of 05 \u00a74.4 requires, and the probe hints the HIL runner needs.",
    "status": "Accepted 2026-10-07",
    "title": "Benchmark and tooling metadata",
    "trace": "SPEC-014 \u00a74, \u00a76; TEST-012",
    "verification": "Harness metadata test reads them from `hw.json`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-CAP.md",
    "evidence": "not evaluated",
    "group": "KRN-CAP",
    "id": "KRN-CAP-001",
    "links": [],
    "rationale": "ADR-014: one API from tiny to isolated.",
    "statement": "Every public handle shall be a capability whose representation is selected by profile without changing API signatures.",
    "status": "Accepted 2026-10-07",
    "title": "One handle type, profile-selected representation",
    "trace": "SPEC-009 \u00a73",
    "verification": "Analysis: `EMB_DECLARE_HANDLE` is the same in every profile; the conformance suite compiles unchanged for POINTER, INDEXED, and TABLE."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-CAP.md",
    "evidence": "not evaluated",
    "group": "KRN-CAP",
    "id": "KRN-CAP-002",
    "links": [],
    "rationale": "An unprivileged partition can never cause a kernel fault by misusing a handle (SPEC-001 \u00a75.3).",
    "statement": "In isolated profiles, every kernel entry from an unprivileged partition shall validate the capability's type, rights, and generation before use.",
    "status": "Accepted 2026-10-07",
    "title": "Validation at the boundary",
    "trace": "SPEC-009 \u00a73.3; 03 \u00a78.1",
    "verification": "Isolated-profile tests `part/bad_handle_*` return statuses, never fault; fuzzing of the syscall boundary."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-CAP.md",
    "evidence": "not evaluated",
    "group": "KRN-CAP",
    "id": "KRN-CAP-003",
    "links": [],
    "rationale": "The capability discipline.",
    "statement": "Rights shall be reducible on derivation and never increasable.",
    "status": "Accepted 2026-10-07",
    "title": "Rights only reduce",
    "trace": "SPEC-009 \u00a74.1",
    "verification": "Test: `cap/derive_cannot_add_rights`, `cap/grant_subset_only`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-CAP.md",
    "evidence": "not evaluated",
    "group": "KRN-CAP",
    "id": "KRN-CAP-004",
    "links": [],
    "rationale": "Memory of the isolation mechanism is a visible number (ADR-033).",
    "statement": "Capability tables shall be statically sized per partition at build time.",
    "status": "Accepted 2026-10-07",
    "title": "Static capability tables",
    "trace": "SPEC-009 \u00a73.3",
    "verification": "Analysis: generator output `partitions.c`; Test: `cap/table_exhausted_enomem`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-CAP.md",
    "evidence": "not evaluated",
    "group": "KRN-CAP",
    "id": "KRN-CAP-005",
    "links": [],
    "rationale": "Footprint target T1.",
    "statement": "In the tiny profile the capability layer shall compile to pointer passing with no runtime cost.",
    "status": "Accepted 2026-10-07",
    "title": "Zero cost on tiny",
    "trace": "SPEC-009 \u00a73.1, \u00a74.3",
    "verification": "Footprint and benchmark comparison of the tiny profile with the capability functions present and absent."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-CAP.md",
    "evidence": "not evaluated",
    "group": "KRN-CAP",
    "id": "KRN-CAP-006",
    "links": [],
    "rationale": "A real generation in O(1) where wanted, nothing where not; no tagged pointers.",
    "statement": "`CONFIG_EMB_HANDLE_MODEL` shall select `POINTER` (object pointer; type and lifecycle checked in checked builds), `INDEXED` (global registry slot plus 16-bit slot generation), or `TABLE` (per-partition capability index plus 16-bit slot generation); every lookup shall be O(1).",
    "status": "Accepted 2026-10-07",
    "title": "Handle models",
    "trace": "SPEC-009 \u00a73",
    "verification": "Test: `obj/handle_models` runs the handle misuse tests under each model; Benchmark: lookup cost."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-CAP.md",
    "evidence": "not evaluated",
    "group": "KRN-CAP",
    "id": "KRN-CAP-007",
    "links": [],
    "rationale": "Fixes the exact check order and codes so that the generated stubs and the conformance suite agree.",
    "statement": "A capability entry shall hold the object pointer, the object generation at grant time, the slot generation, the type tag, and the rights; validation shall check index range, slot generation, type, rights, object lifecycle, and object generation, returning `EMB_EINVAL`, `EMB_EPERM`, `EMB_ESTATE`, or `EMB_ESTALE` accordingly.",
    "status": "Accepted 2026-10-07",
    "title": "Capability entry and validation",
    "trace": "SPEC-009 \u00a73.3, \u00a78",
    "verification": "Test: `cap/validation_matrix`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-CAP.md",
    "evidence": "not evaluated",
    "group": "KRN-CAP",
    "id": "KRN-CAP-008",
    "links": [],
    "rationale": "One source of truth for rights, machine-checked.",
    "statement": "Each object type shall define its rights within eight bits with `DESTROY` and `GRANT` as the two universal top bits, as listed in SPEC-009 \u00a74.2; every operation's explicit `@right` metadata shall name the right each handle parameter needs, separately from `@req` requirement identifiers and the generated stubs shall check exactly that right.",
    "status": "Accepted 2026-10-07",
    "title": "Rights per type",
    "trace": "SPEC-009 \u00a74.2; SPEC-001 \u00a79",
    "verification": "Analysis: `tools/apidoc` cross-checks annotations against the stub generator's table."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-CAP.md",
    "evidence": "not evaluated",
    "group": "KRN-CAP",
    "id": "KRN-CAP-009",
    "links": [],
    "rationale": "Complete, small capability algebra with coarse revocation.",
    "statement": "`grant` shall copy a capability with a subset of rights into another partition's table and require `GRANT` on it and `GRANT_TO` on the target partition; `derive` shall create a reduced copy in the caller's table; `delete` shall free the caller's slot; `revoke` (requires `DESTROY`) shall bump the object's generation and so invalidate every capability to it; `renew` shall give the owner a fresh capability afterwards.",
    "status": "Accepted 2026-10-07",
    "title": "Grant, derive, delete, revoke, renew",
    "trace": "SPEC-009 \u00a74.1",
    "verification": "Test: `cap/grant_*`, `cap/derive_*`, `cap/revoke_all_stale`, `cap/renew`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-CAP.md",
    "evidence": "not evaluated",
    "group": "KRN-CAP",
    "id": "KRN-CAP-010",
    "links": [],
    "rationale": "Static systems need no runtime grant protocol.",
    "statement": "The generator shall emit each partition's initial capability table from the system description, including device and port capabilities granted to driver partitions.",
    "status": "Accepted 2026-10-07",
    "title": "Build-time grants",
    "trace": "SPEC-009 \u00a74.1; 04 \u00a71.3; SPEC-014",
    "verification": "Generator test `hw/gen_cap_tables`; isolated-profile boot test."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-CAP.md",
    "evidence": "not evaluated",
    "group": "KRN-CAP",
    "id": "KRN-CAP-011",
    "links": [],
    "rationale": "One source tree per application across profiles (C3).",
    "statement": "Under `POINTER` and `INDEXED`, the capability functions shall exist: trivial ones return `EMB_OK`, cross-partition ones `EMB_ENOTSUP`, so that isolated-profile code compiles and runs unchanged.",
    "status": "Accepted 2026-10-07",
    "title": "Pointer models keep the API",
    "trace": "SPEC-009 \u00a74.3",
    "verification": "Test: `cap/api_present_in_pointer_models`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-CAP.md",
    "evidence": "not evaluated",
    "group": "KRN-CAP",
    "id": "KRN-CAP-012",
    "links": [],
    "rationale": "Table sizing and a security signal.",
    "statement": "Registry and table occupancy high-water and stale-handle rejections per partition shall be optional statistics.",
    "status": "Accepted 2026-10-07",
    "title": "Statistics",
    "trace": "SPEC-009 \u00a79",
    "verification": "Statistics API test."
  },
  {
    "design_status": "Proposed",
    "document": "requirements/KRN-CAP.md",
    "evidence": "not evaluated",
    "group": "KRN-CAP",
    "id": "KRN-CAP-013",
    "links": [],
    "rationale": "Resetting or wrapping a generation can revalidate stale authority; a stale DESTROY capability cannot authorize its own renewal.",
    "statement": "Slot and object generation state shall retain its incremented value across reinitialization and partition restart. A generation value shall not be reused while a stale reference with that value may survive; exhaustion shall refuse the operation or invoke a reviewed reclamation scheme. Lookup/revocation shall preserve object lifetime for in-flight operations, and renew shall require current trusted recovery authority.",
    "status": "Proposed 2026-10-14; unimplemented.",
    "title": "Incarnation persistence and exhaustion",
    "trace": "SPEC-009 \u00a713; SPEC-010 \u00a77, \u00a717",
    "verification": "Planned forced wrap/exhaustion, stale renew, concurrent lookup/revoke and restart tests on INDEXED/TABLE configurations."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-001",
    "links": [],
    "rationale": "One protocol (SPEC-004) under every primitive.",
    "statement": "IPC primitives that block shall use the common wait mechanism.",
    "status": "Accepted 2026-10-07",
    "title": "Common wait mechanism",
    "trace": "SPEC-007 \u00a71; SPEC-004; v0.1 \u00a79.4",
    "verification": "Analysis: every blocking entry in `kernel/ipc/` uses `embk_wait_prepare`/`embk_wait_commit` or `embk_block_on`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-002",
    "links": [],
    "rationale": "No hidden allocation on an MCU.",
    "statement": "Queue capacity and memory use shall be determinable from configuration and application allocation.",
    "status": "Accepted 2026-10-07",
    "title": "Determinable capacity and memory",
    "trace": "SPEC-007 \u00a72.1, \u00a73.1, \u00a74.1; 03 \u00a79.2",
    "verification": "Analysis: `EMB_MSGQ_RING`, `EMB_POOL_STORAGE`, and the pipe buffer are caller-provided; the storage generator reports object sizes."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-003",
    "links": [],
    "rationale": "SPEC-001 \u00a75.2.",
    "statement": "ISR-safe IPC operations shall never block.",
    "status": "Accepted 2026-10-07",
    "title": "ISR-safe IPC never blocks",
    "trace": "SPEC-007 \u00a71, \u00a77",
    "verification": "Analysis: `@ctx thread isr` forms accept only `EMB_NO_WAIT`; Test: `misuse/ipc_block_from_isr`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-004",
    "links": [],
    "rationale": "Lifetime hazards are the price of zero copy (v0.1 \u00a79.3).",
    "statement": "Zero-copy APIs, if provided, shall define ownership and lifetime rules explicitly.",
    "status": "Accepted 2026-10-07",
    "title": "Explicit zero-copy ownership",
    "trace": "SPEC-007 \u00a74.3",
    "verification": "Analysis: SPEC-007 \u00a74.3 rules; Test: checked-build `misuse/pool_free_non_owner`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-005",
    "links": [
      "KRN-WAIT-001"
    ],
    "rationale": "Analyzability.",
    "statement": "Wake ordering for multiple waiters shall be deterministic and documented.",
    "status": "Accepted 2026-10-07",
    "title": "Deterministic wake order",
    "trace": "SPEC-007 \u00a72.2, \u00a73.2, \u00a74.2; KRN-WAIT-001, 002",
    "verification": "Test: `wait/order_*` against queues, pipes, and pools."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-006",
    "links": [],
    "rationale": "03 \u00a76.5.",
    "statement": "Zero-copy transfer shall move ownership explicitly; a transferred block shall not be accessed by the sender after transfer.",
    "status": "Accepted 2026-10-07",
    "title": "Ownership moves with the message",
    "trace": "SPEC-007 \u00a74.3",
    "verification": "Test: checked-build `misuse/pool_use_after_send` faults; release-build documentation review."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-007",
    "links": [],
    "rationale": "Real-time paths.",
    "statement": "Buffer pools shall be bounded and allocation shall be O(1).",
    "status": "Accepted 2026-10-07",
    "title": "Bounded pools, O(1) allocation",
    "trace": "SPEC-007 \u00a74.2",
    "verification": "Benchmark: pool alloc and free in the harness; Analysis: intrusive free list."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-008",
    "links": [],
    "rationale": "One mental model from a single image to a multi-core, multi-partition system.",
    "statement": "Cross-partition and cross-core messaging shall use the same handle, timeout, and wake semantics as intra-image queues.",
    "status": "Accepted 2026-10-07 (FUTURE feature; the constraint binds the queue API now)",
    "title": "Ports share queue semantics",
    "trace": "SPEC-007 \u00a75; 03 \u00a76.6",
    "verification": "Analysis at port specification time: the port API is a superset of the queue API."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-009",
    "links": [],
    "rationale": "ADR-032.",
    "statement": "Cross-partition buffers larger than the configured copy threshold shall be transferred by lease, validated on every access, and revoked by the client's wake.",
    "status": "Accepted 2026-10-07 (FUTURE feature)",
    "title": "Leases for large cross-partition buffers",
    "trace": "SPEC-007 \u00a75; ADR-032",
    "verification": "Deferred to the port specification."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-010",
    "links": [],
    "rationale": "Hand-off semantics (KRN-WAIT-012) applied to both sides; no silent drops (R-001 \u00a76, RIOT).",
    "statement": "A message queue shall copy fixed-size items by value into a caller-provided ring; send with a waiting receiver shall copy directly into the receiver and wake it; receive that frees a slot shall move a waiting sender's item into it and wake the sender; a woken thread shall not re-check; a full queue shall return `EMB_ETIMEDOUT` to a non-blocking sender and never drop.",
    "status": "Accepted 2026-10-07",
    "title": "Message queue semantics",
    "trace": "SPEC-007 \u00a72.2",
    "verification": "Test: `ipc/msgq_*` including `msgq_direct_to_receiver`, `msgq_slot_handoff_to_sender`, `msgq_full_nowait_timedout`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-011",
    "links": [],
    "rationale": "Simplicity and bounded masking (R-003 T7) without a reservation protocol.",
    "statement": "`item_size` shall be bounded by `CONFIG_EMB_MSGQ_MAX_ITEM` (default 64, tiny 16); the copy shall run inside the object's critical section and its cost shall be included in the masked-time budget.",
    "status": "Accepted 2026-10-07",
    "title": "Bounded item copy under the lock",
    "trace": "SPEC-007 \u00a72.2, \u00a72.3",
    "verification": "Test: `misuse/msgq_item_too_large`; Benchmark: masked time of a maximum-size send."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-012",
    "links": [],
    "rationale": "Urgent messages without a second queue (03 \u00a76.3).",
    "statement": "`send_front` shall place an item at the head, shall accept only `EMB_NO_WAIT`, and shall be ISR-safe.",
    "status": "Accepted 2026-10-07",
    "title": "Send to front",
    "trace": "SPEC-007 \u00a72.2",
    "verification": "Test: `ipc/msgq_send_front_order`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-013",
    "links": [],
    "rationale": "Partial transfers with per-call minimums are what stream consumers need (Zephyr pipe rewrite, R-001 \u00a76).",
    "statement": "A pipe shall write as much as fits and block for the remainder when the timeout allows, reporting the partial count on timeout; read shall return once `min_len` bytes are available, up to `len`; readers shall be woken with the available count handed over and shall copy in their own context.",
    "status": "Accepted 2026-10-07",
    "title": "Pipe semantics",
    "trace": "SPEC-007 \u00a73.2",
    "verification": "Test: `ipc/pipe_partial_write_timeout`, `ipc/pipe_read_min_len`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-014",
    "links": [],
    "rationale": "Bounded masking for general pipes; a lock-free fast path for the common single-producer single-consumer case (FreeRTOS stream buffers).",
    "statement": "Pipe copies shall run in chunks of at most `CONFIG_EMB_PIPE_CHUNK` bytes inside the critical section, releasing it between chunks; writes of at most one chunk shall be atomic with respect to other writers; with `EMB_PIPE_SPSC` the data copy shall run without the critical section and publish indices with release semantics.",
    "status": "Accepted 2026-10-07",
    "title": "Pipe chunking and SPSC path",
    "trace": "SPEC-007 \u00a73.2",
    "verification": "Test: `ipc/pipe_chunk_atomicity`, `ipc/pipe_spsc_lockfree` (monitor shows no masked copy); checked-build `misuse/pipe_spsc_second_writer`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-015",
    "links": [],
    "rationale": "A defined end-of-stream and a defined restart.",
    "statement": "`close` shall refuse further writes with `EMB_ESTATE`, wake blocked writers with `EMB_ESTATE`, and let readers drain before returning `EMB_ESTATE`; `reset` shall discard contents, wake every waiter with `EMB_ESTATE`, and reopen.",
    "status": "Accepted 2026-10-07",
    "title": "Pipe close and reset",
    "trace": "SPEC-007 \u00a73.2",
    "verification": "Test: `ipc/pipe_close_drain`, `ipc/pipe_reset`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-016",
    "links": [],
    "rationale": "03 \u00a76.5, \u00a79.2.",
    "statement": "A pool shall keep an intrusive O(1) free list; `alloc` on an exhausted pool shall block with the wait protocol; `free` with a waiter shall hand the block over; destroy with blocks outstanding shall be misuse.",
    "status": "Accepted 2026-10-07",
    "title": "Buffer pool semantics",
    "trace": "SPEC-007 \u00a74.2",
    "verification": "Test: `ipc/pool_alloc_free`, `ipc/pool_handoff`, `misuse/pool_destroy_outstanding`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-017",
    "links": [],
    "rationale": "Zero-copy bugs are found in development at no production cost.",
    "statement": "Checked builds shall track each block's owner (thread, `IN_QUEUE`, or transferred) and shall fault on free, transfer, or ownership send by a non-owner, on double free, and on a pointer outside the pool; release builds shall track nothing.",
    "status": "Accepted 2026-10-07",
    "title": "Ownership tracking in checked builds",
    "trace": "SPEC-007 \u00a74.3, \u00a77",
    "verification": "Test: `misuse/pool_*` in checked builds; footprint test shows no owner field in release builds."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-018",
    "links": [],
    "rationale": "KRN-NOTIF-004.",
    "statement": "Message queues (receive side, empty to non-empty), pipes (fill reaching `notify_trigger`), and pools (exhausted to available) shall support the notification binding, and a transition consumed by a hand-off shall not signal it.",
    "status": "Accepted 2026-10-07",
    "title": "Bindings on IPC objects",
    "trace": "SPEC-007 \u00a72.2, \u00a73.2, \u00a74.2; SPEC-006 \u00a73",
    "verification": "Test: `notif/bind_msgq`, `notif/bind_pipe`, `notif/bind_pool`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-019",
    "links": [],
    "rationale": "Word copies and intrusive free lists need alignment the application should not have to compute.",
    "statement": "`EMB_MSGQ_RING`, `EMB_POOL_STORAGE`, and the pipe buffer rules shall declare correctly sized and aligned caller storage; misaligned or undersized storage shall be misuse.",
    "status": "Accepted 2026-10-07",
    "title": "Storage declaration helpers",
    "trace": "SPEC-007 \u00a72.1, \u00a74.1, \u00a77",
    "verification": "Test: `misuse/ipc_storage_misaligned`; Analysis: macro review."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-020",
    "links": [
      "OBS-005",
      "OBS-008"
    ],
    "rationale": "Queue sizing and leak hunting need these numbers.",
    "statement": "Send, receive, blocked send, pipe write, read and close, pool alloc, free and transfer shall be trace events; high-water occupancy, blocked-send counts, minimum pool availability and blocks outstanding shall be optional statistics; the debug descriptor shall export ring and free-list layouts.",
    "status": "Accepted 2026-10-07",
    "title": "Trace and statistics",
    "trace": "SPEC-007 \u00a78; OBS-005, OBS-008",
    "verification": "Test: trace decoder; statistics API test."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-021",
    "links": [],
    "rationale": "Footprint targets T1 and T2.",
    "statement": "The tiny profile shall offer message queues and pools with 8-bit counts under `CONFIG_EMB_IPC_SMALL`, a 16-byte default item bound, and pipes only when configured.",
    "status": "Accepted 2026-10-07",
    "title": "Tiny profile",
    "trace": "SPEC-007 \u00a79",
    "verification": "Footprint test of the tiny reference configuration."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IPC.md",
    "evidence": "not evaluated",
    "group": "KRN-IPC",
    "id": "KRN-IPC-022",
    "links": [
      "KRN-WAIT-007"
    ],
    "rationale": "The same evidence standard as semaphores and mutexes.",
    "statement": "Message queues and pools shall be added to the reference model with their M2 conformance tests, with conservation properties (every item received exactly once or still in the ring; every block owned by one party or free).",
    "status": "Accepted 2026-10-07",
    "title": "Model coverage",
    "trace": "SPEC-007 \u00a710; KRN-WAIT-007",
    "verification": "Analysis: `tools/model` scenarios exist before the M2 implementation of queues and pools."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-001",
    "links": [],
    "rationale": "An ISR has no thread to block; blocking there corrupts the scheduler's model of who is running.",
    "statement": "Interrupt context shall not perform blocking operations.",
    "status": "Accepted (v0.1)",
    "title": "No blocking in interrupt context",
    "trace": "v0.1 \u00a73.7; SPEC-002 \u00a73.1; SPEC-001 \u00a75.2",
    "verification": "Test: `tests/conformance/misuse/` calls each thread-only function from an ISR in checked and release builds (API-015)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-002",
    "links": [],
    "rationale": "Every context-class check and every ISR-safe code path depends on it.",
    "statement": "Interrupt context shall be distinguishable from thread context.",
    "status": "Accepted (v0.1)",
    "title": "Interrupt context is distinguishable",
    "trace": "v0.1 \u00a73.7; SPEC-002 \u00a72; SPEC-001 \u00a75.1",
    "verification": "Test: `emb_context()` returns `EMB_CONTEXT_ISR` inside every handler level and `EMB_CONTEXT_THREAD` outside, on every port."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-003",
    "links": [],
    "rationale": "This is the definition of preemptive scheduling driven by events rather than ticks.",
    "statement": "An interrupt that makes a higher-priority thread READY shall permit scheduling before returning to thread execution when preemption is enabled.",
    "status": "Accepted (v0.1)",
    "title": "Wakeup from an interrupt permits scheduling before thread resume",
    "trace": "v0.1 \u00a73.7; SPEC-002 \u00a76; KRN-SCH-020",
    "verification": "Test: ISR wakes a higher-priority thread; that thread runs before the interrupted thread's next instruction (measured by a sequence counter)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-010",
    "links": [
      "API-014"
    ],
    "rationale": "Callers cannot guess; the annotation is the contract.",
    "statement": "ISR-safe kernel operations shall be explicitly identified.",
    "status": "Accepted (v0.1)",
    "title": "ISR-safe operations are explicit",
    "trace": "v0.1 \u00a76.6; SPEC-001 \u00a79; API-014",
    "verification": "Analysis: every public function has a `@ctx` tag (API-003); the ISR-safe set is the functions tagged `thread isr`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-011",
    "links": [
      "API-014"
    ],
    "rationale": "Follows from KRN-IRQ-001 for the kernel's own implementation paths.",
    "statement": "An ISR-safe operation shall not require the caller to block.",
    "status": "Accepted (v0.1)",
    "title": "ISR-safe operations never block the caller",
    "trace": "v0.1 \u00a76.6; API-014",
    "verification": "Analysis: `@ctx thread isr` functions are `@blocks no`, or `@blocks timeout` with a documented ISR-safe `EMB_NO_WAIT` path."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-012",
    "links": [],
    "rationale": "The outermost-exit rule, stack sizing, and diagnostics all need the depth.",
    "statement": "Nested interrupt depth shall be observable to the kernel when nesting is supported.",
    "status": "Accepted (v0.1)",
    "title": "Nesting depth is observable",
    "trace": "v0.1 \u00a76.6; SPEC-002 \u00a77.1",
    "verification": "Test: `emb_irq_nesting_depth()` equals the actual depth in a nested-interrupt test on Cortex-M, RISC-V with nesting, and native."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-013",
    "links": [],
    "rationale": "Switching threads from inside a nested interrupt would leave an interrupted handler's frame on the wrong stack.",
    "statement": "A reschedule requested during nested interrupt handling shall remain pending until a legal thread-resume boundary.",
    "status": "Accepted (v0.1)",
    "title": "Reschedule during nested handling stays pending",
    "trace": "v0.1 \u00a76.6; SPEC-002 \u00a76.1; KRN-SCH-021",
    "verification": "Test: nested ISR wakes a higher-priority thread; the switch occurs only after the outer handler returns."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-014",
    "links": [],
    "rationale": "Kernel masking is the floor of every interrupt latency figure.",
    "statement": "Interrupt masking used by kernel internals shall have bounded duration.",
    "status": "Accepted (v0.1)",
    "title": "Bounded kernel masking",
    "trace": "v0.1 \u00a76.6; SPEC-002 \u00a74.2, \u00a710; KRN-RT-003",
    "verification": "Demonstration: `CONFIG_EMB_IRQ_LOCK_STATS` under the stress suite on HIL reports the maximum; it is published per release."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-015",
    "links": [],
    "rationale": "NVIC, PLIC, CLIC, AVR's fixed vectors, and the simulator are all targets.",
    "statement": "The generic kernel shall not assume a specific interrupt-controller architecture.",
    "status": "Accepted (v0.1)",
    "title": "No controller assumption in the generic kernel",
    "trace": "v0.1 \u00a76.6; SPEC-002 \u00a78",
    "verification": "Analysis: `kernel/` includes no architecture header and references no controller register (02 \u00a75 dependency check)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-016",
    "links": [],
    "rationale": "A port's correctness is reviewable only against a written description.",
    "statement": "Architecture documentation shall define interrupt-entry, interrupt-exit, context-save, and rescheduling behavior.",
    "status": "Accepted (v0.1)",
    "title": "Documented entry, exit, save, and reschedule behavior",
    "trace": "v0.1 \u00a76.6; SPEC-002 \u00a713",
    "verification": "Inspection: each `docs/ports/<arch>.md` has the sections named in 05 \u00a79."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-017",
    "links": [],
    "rationale": "Zero-latency interrupts are a real-time requirement the kernel can only meet by staying out of their way (v0.1 \u00a76.3).",
    "statement": "The kernel shall distinguish kernel-aware interrupts, which it may mask and whose handlers may call ISR-safe API, from kernel-independent interrupts, which it shall never mask and whose handlers shall call no kernel function. The boundary shall be the configured level `CONFIG_EMB_IRQ_KERNEL_LEVEL`. The kernel-independent class shall be available only on architectures with interrupt priority masking and shall be rejected at configuration time elsewhere.",
    "status": "Accepted 2026-10-07",
    "title": "Two interrupt classes",
    "trace": "SPEC-002 \u00a73",
    "verification": "Test: with the class enabled on Cortex-M, a kernel-independent interrupt fires inside a kernel critical section and its handler runs within hardware latency; Analysis: Kconfig rejects `CONFIG_EMB_IRQ_ZERO_LATENCY` on Armv6-M, AVR, and native."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-018",
    "links": [],
    "rationale": "Key-based masking nests for free, works identically from ISRs, and maps to one or two instructions on every architecture (SPEC-002 \u00a74.1).",
    "statement": "The kernel shall provide `emb_irq_lock()` returning the previous mask state and `emb_irq_unlock(key)` restoring exactly that state, callable from thread, interrupt, and pre-kernel context, nestable, with unlocks in reverse order of locks. Both shall be O(1), shall never block or yield, and shall act as compiler barriers.",
    "status": "Accepted 2026-10-07",
    "title": "Key-based, nestable critical sections",
    "trace": "SPEC-002 \u00a74.1; KRN-RT-003",
    "verification": "Test: nesting test restores the outer state exactly; Analysis: the inline wrappers carry a `\"memory\"` clobber on all three compilers."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-019",
    "links": [],
    "rationale": "Masking is a local operation; pretending otherwise is the classic SMP porting bug (KRN-SMP-004).",
    "statement": "`emb_irq_lock()` shall protect against interrupts and preemption on the current CPU only. Data shared across CPUs shall be protected by a spinlock acquired with interrupts masked, which on uniprocessor builds shall compile to the critical section alone.",
    "status": "Accepted 2026-10-07",
    "title": "Critical sections are per CPU",
    "trace": "SPEC-002 \u00a74.3; KRN-SMP-002, KRN-SMP-004",
    "verification": "Analysis: SMP specification lock-ordering rules; Test: the spinlock reduces to `emb_irq_lock()` on UP (symbol inspection)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-020",
    "links": [],
    "rationale": "Evidence, not assertion (principle 6, KRN-RT-007).",
    "statement": "Each architecture port shall declare a cycle budget for the kernel's own critical sections and scheduler locks, and a configuration option shall measure the longest observed durations with the cycle counter. The measured maxima shall be published per reference board with full metadata.",
    "status": "Accepted 2026-10-07",
    "title": "Measured critical-section budgets",
    "trace": "SPEC-002 \u00a710",
    "verification": "Demonstration: benchmark pipeline output per release; Test: checked builds fault when a declared budget is exceeded under the stress suite."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-021",
    "links": [],
    "rationale": "A critical section that spans a preemption point leaves interrupts masked for an unbounded time in another thread.",
    "statement": "A blocking call with a nonzero timeout, a thread-only operation, or a scheduler-lock release that would reschedule, made while a critical section opened by the caller is active, shall be misuse: a kernel fault in checked builds and `EMB_EPERM` in release builds.",
    "status": "Accepted 2026-10-07",
    "title": "No blocking inside a critical section",
    "trace": "SPEC-002 \u00a74.2; SPEC-001 \u00a75.3; KRN-RT-002",
    "verification": "Test: `tests/conformance/misuse/` in both build kinds."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-022",
    "links": [],
    "rationale": "Restates KRN-SCH-016 to 019 at the API level and fixes the two edge cases v0.1 left open.",
    "statement": "`emb_sched_lock()` and `emb_sched_unlock()` shall be thread-only, nestable by depth, shall not mask interrupts, and the unlock that reaches depth zero shall perform any pending reschedule immediately. A scheduler-lock operation from interrupt context shall be misuse. Yield while locked shall keep the reschedule pending and shall not switch.",
    "status": "Accepted 2026-10-07",
    "title": "Scheduler lock semantics",
    "trace": "SPEC-002 \u00a75; KRN-SCH-016, KRN-SCH-017, KRN-SCH-018, KRN-SCH-019",
    "verification": "Test: conformance tests for nesting, ISR wakeup while locked, yield while locked, and the ISR misuse case."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-023",
    "links": [
      "KRN-IRQ-013"
    ],
    "rationale": "A closed list of preemption points is what makes the kernel's behavior analyzable and the reference model finite (ADR-013).",
    "statement": "A thread switch shall occur only at: the outermost exit of a kernel-aware interrupt when a reschedule is pending and the scheduler is not locked; inside a thread-context kernel operation that changes schedulability when the caller is not in a critical section and the scheduler is not locked; and kernel start. A thread switch shall never occur inside a nested interrupt or inside a critical section.",
    "status": "Accepted 2026-10-07",
    "title": "Enumerated preemption points",
    "trace": "SPEC-002 \u00a76.1; KRN-SCH-021; KRN-IRQ-013",
    "verification": "Test: differential tests against the reference model's switch oracle on the native port; Analysis: the kernel has one switch call site per architecture path."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-024",
    "links": [],
    "rationale": "This is the single mechanism by which interrupts drive scheduling (KRN-SCH-020, KRN-IRQ-003).",
    "statement": "When an ISR-safe operation changes the scheduling decision, the kernel shall set the per-CPU reschedule-pending flag and request the architecture's deferred switch; the architecture's outermost interrupt exit shall perform the switch when the flag is set and the scheduler is not locked, and shall clear the flag.",
    "status": "Accepted 2026-10-07",
    "title": "Reschedule on outermost exit",
    "trace": "SPEC-002 \u00a76.2; KRN-SCH-020",
    "verification": "Test: ISR wakeup latency test on each port; the switch happens exactly once per outermost exit."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-025",
    "links": [],
    "rationale": "Cortex-M handlers are plain functions, AVR needs a full-context `naked` vector, RISC-V needs a dispatcher entry; the application should not know (09 \u00a78).",
    "statement": "The kernel shall provide `EMB_ISR(name)` as the only portable declaration of a kernel-aware handler, expanding per architecture to the form that provides the kernel's entry and exit behavior, and `EMB_ISR_RAW(name)` for handlers that call no kernel function.",
    "status": "Accepted 2026-10-07",
    "title": "Portable handler declaration",
    "trace": "SPEC-002 \u00a76.2, \u00a78.3",
    "verification": "Test: the same handler source builds and passes the ISR conformance tests on every port."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-026",
    "links": [],
    "rationale": "Unbounded nesting is unbounded stack use.",
    "statement": "Kernel-aware interrupt nesting shall be enabled only where the architecture permits and the configuration selects it. The maximum depth shall be a configuration constant used to size the interrupt stack, and exceeding it shall be a kernel fault in checked builds.",
    "status": "Accepted 2026-10-07",
    "title": "Bounded nesting",
    "trace": "SPEC-002 \u00a77.1",
    "verification": "Test: nesting-depth test on the native port with fault injection; Analysis: Kconfig gating per architecture."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-027",
    "links": [],
    "rationale": "Thread stacks must be sized for thread work only wherever the hardware allows (KRN-MEM-011).",
    "statement": "Where the architecture permits, kernel-aware interrupts shall execute on a dedicated per-CPU interrupt stack sized from the maximum nesting depth and the handlers' measured frames. Where it does not (AVR), every thread's stack budget shall include a configured interrupt reserve, and the architecture documentation shall state its size derivation.",
    "status": "Accepted 2026-10-07",
    "title": "Interrupt stacks",
    "trace": "SPEC-002 \u00a77.2; KRN-MEM-011",
    "verification": "Analysis: `-fstack-usage` sums in the stack report; Test: interrupt-stack overflow detection fires in checked builds under the nesting stress test."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-028",
    "links": [],
    "rationale": "One priority direction across threads and interrupts removes a documented source of configuration mistakes, and the mapping belongs in one place per architecture.",
    "statement": "Generic interrupt priorities shall use the thread convention (a larger number is more urgent), with level 0 the least urgent kernel-aware level and levels above `CONFIG_EMB_IRQ_KERNEL_LEVEL` kernel-independent. The architecture port shall map generic levels to hardware encodings, and the hardware description shall store generic levels.",
    "status": "Accepted 2026-10-07",
    "title": "Generic interrupt priority numbering",
    "trace": "SPEC-002 \u00a78.1",
    "verification": "Test: `emb_irq_set_level()` followed by observed preemption order on each port; Analysis: generator emits encoded values from generic input."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-029",
    "links": [
      "HW-001"
    ],
    "rationale": "A static table costs no RAM and no init code; dynamic connection is an option for the applications that need it.",
    "statement": "The kernel shall provide O(1), non-blocking `emb_irq_enable`, `emb_irq_disable`, `emb_irq_is_enabled`, `emb_irq_set_level`, `emb_irq_pend`, and `emb_irq_clear_pending`, and, only when `CONFIG_EMB_IRQ_DYNAMIC` is selected, `emb_irq_connect`. By default the vector table shall be generated from the hardware description and static.",
    "status": "Accepted 2026-10-07",
    "title": "Interrupt management API",
    "trace": "SPEC-002 \u00a78.2; HW-001",
    "verification": "Test: API conformance per port; Analysis: no RAM vector table in the tiny profile image."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-030",
    "links": [],
    "rationale": "Fault handling that is designed, not improvised (01 \u00a76); isolation requires the partition classification.",
    "statement": "Synchronous faults shall enter through the architecture fault entry, which shall capture the available context and dispatch to the fault manager, classifying a fault from an unprivileged partition as a partition fault and any other as a kernel fault. System-call traps shall not be treated as faults. The crash record shall be written before any recovery action.",
    "status": "Accepted 2026-10-07",
    "title": "Exceptions route to the fault manager",
    "trace": "SPEC-002 \u00a79; 03 \u00a710; FLT-001, FLT-002",
    "verification": "Test: provoked faults of each class on native and Cortex-M (emulated) produce decodable crash records and the right classification."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-031",
    "links": [
      "KRN-TIM-006"
    ],
    "rationale": "Timeout jitter should depend on critical sections and zero-latency interrupts only, and the handler must not become a place where work accumulates.",
    "statement": "The system timer interrupt shall be a kernel-aware interrupt whose level defaults to the highest kernel-aware level and is configurable, and whose handler shall be bounded to moving expired timeouts to READY, setting the reschedule flag, and programming the next event.",
    "status": "Accepted 2026-10-07",
    "title": "Timer interrupt level and bound",
    "trace": "SPEC-002 \u00a711; KRN-TIM-006",
    "verification": "Demonstration: timer jitter benchmark; Analysis: handler `-fstack-usage` and cycle budget."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-032",
    "links": [],
    "rationale": "KRN-RT-004 to 007 require measurability; this fixes what is measured.",
    "statement": "The project shall define interrupt latency, kernel masking latency, ISR overhead, ISR-to-thread latency, and scheduler-lock latency as in SPEC-002 \u00a710.1, shall measure them on every reference board with the benchmark pipeline, and shall publish worst observed values with full metadata.",
    "status": "Accepted 2026-10-07",
    "title": "Latency metrics are defined and published",
    "trace": "SPEC-002 \u00a710; KRN-RT-004, KRN-RT-005, KRN-RT-006, KRN-RT-007; TEST-006",
    "verification": "Demonstration: published benchmark data per release."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-033",
    "links": [],
    "rationale": "A kernel that enables interrupts inside a caller's critical section breaks the caller's invariant silently.",
    "statement": "An ISR-safe kernel operation called while the caller holds a critical section shall return with the caller's mask state unchanged; kernel internals shall save and restore mask state with the same key-based primitive and shall never unconditionally enable interrupts.",
    "status": "Accepted 2026-10-07",
    "title": "The kernel never unmasks behind a caller",
    "trace": "SPEC-002 \u00a74.2",
    "verification": "Test: every ISR-safe function called under `emb_irq_lock()`; the key read after the call equals the key before; Analysis: no unconditional enable instruction in `kernel/` or in the ports' kernel paths."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-034",
    "links": [
      "KRN-IRQ-002"
    ],
    "rationale": "It is executed on every checked API entry and must be cheap and right.",
    "statement": "`emb_context()` shall be O(1), callable from any context including nested interrupts and pre-kernel, and shall agree with the hardware's notion of exception activity on architectures that expose one.",
    "status": "Accepted 2026-10-07",
    "title": "Context query is O(1) and exact",
    "trace": "SPEC-002 \u00a72.1; KRN-IRQ-002",
    "verification": "Test: context query inside nested interrupts and before kernel start on every port."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-035",
    "links": [
      "API-015"
    ],
    "rationale": "These bugs are invisible in release builds until they corrupt state.",
    "statement": "Checked builds shall detect and raise a kernel fault for: out-of-order `emb_irq_unlock()`, scheduler-lock operations from interrupt context, nesting beyond the configured maximum, interrupt stack overflow, and kernel calls from `EMB_ISR_RAW` handlers on architectures where context can be distinguished.",
    "status": "Accepted 2026-10-07",
    "title": "Checked-build detection",
    "trace": "SPEC-002 \u00a712; API-015",
    "verification": "Test: `tests/conformance/misuse/irq/` provokes each condition on the native port and on an emulated Cortex-M."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-IRQ.md",
    "evidence": "not evaluated",
    "group": "KRN-IRQ",
    "id": "KRN-IRQ-036",
    "links": [],
    "rationale": "Zero-latency handlers need a way to wake threads without touching kernel state.",
    "statement": "The architecture port shall provide `emb_arch_irq_pend_soft()`, callable from a kernel-independent handler, that pends a kernel-aware software interrupt whose handler may perform kernel work on behalf of the kernel-independent handler. Documentation shall present this as the only sanctioned path from a kernel-independent handler to the kernel.",
    "status": "Accepted 2026-10-07",
    "title": "Handoff from kernel-independent interrupts",
    "trace": "SPEC-002 \u00a73.2",
    "verification": "Test: on Cortex-M with the class enabled, a kernel-independent handler pends the software interrupt and a thread is woken with measured latency."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-NOTIF.md",
    "evidence": "not evaluated",
    "group": "KRN-NOTIF",
    "id": "KRN-NOTIF-001",
    "links": [],
    "rationale": "The cheapest completion path from an interrupt to a thread (R-001 \u00a76).",
    "statement": "Each thread shall own a notification bit set that can be set from ISR context without blocking.",
    "status": "Accepted 2026-10-07",
    "title": "Per-thread bits, ISR-settable",
    "trace": "SPEC-006 \u00a72; 03 \u00a76.1",
    "verification": "Test: `notif/set_from_isr`; Analysis: `emb_notify_set` is `@ctx thread isr`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-NOTIF.md",
    "evidence": "not evaluated",
    "group": "KRN-NOTIF",
    "id": "KRN-NOTIF-002",
    "links": [],
    "rationale": "One possible waiter makes the structure a single slot and every operation O(1).",
    "statement": "Only the owning thread shall wait on its notifications.",
    "status": "Accepted 2026-10-07",
    "title": "Owner-only wait",
    "trace": "SPEC-006 \u00a72.2",
    "verification": "Analysis: `emb_notify_wait` has no thread argument."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-NOTIF.md",
    "evidence": "not evaluated",
    "group": "KRN-NOTIF",
    "id": "KRN-NOTIF-003",
    "links": [],
    "rationale": "It is the primitive everything else is built on.",
    "statement": "Notification set and wait shall be O(1) and allocation free.",
    "status": "Accepted 2026-10-07",
    "title": "O(1), allocation free",
    "trace": "SPEC-006 \u00a72.2; R-003 \u00a74 T8",
    "verification": "Benchmark: harness operation T8 (R-003 \u00a74); Analysis: no list and no allocation in the path."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-NOTIF.md",
    "evidence": "not evaluated",
    "group": "KRN-NOTIF",
    "id": "KRN-NOTIF-004",
    "links": [],
    "rationale": "Multi-object wait without poll objects (ADR-027).",
    "statement": "Every waitable kernel object shall support binding to one notification bit of one thread; the set shall be O(1) and shall happen on every transition to the ready condition.",
    "status": "Accepted 2026-10-07",
    "title": "Binding on every waitable object",
    "trace": "SPEC-006 \u00a73; ADR-027",
    "verification": "Test: `notif/bind_<object>` for every object type; model scenario `binding_hook`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-NOTIF.md",
    "evidence": "not evaluated",
    "group": "KRN-NOTIF",
    "id": "KRN-NOTIF-005",
    "links": [],
    "rationale": "A binding is an observer of transitions, not a waiter.",
    "statement": "Binding shall not change the object's own wait-queue semantics for threads blocked directly on it.",
    "status": "Accepted 2026-10-07",
    "title": "Direct waiters unaffected",
    "trace": "SPEC-006 \u00a73.2; SPEC-004 \u00a76.3",
    "verification": "Test: `notif/bind_with_direct_waiter` (the direct waiter is served, no bit is set)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-NOTIF.md",
    "evidence": "not evaluated",
    "group": "KRN-NOTIF",
    "id": "KRN-NOTIF-006",
    "links": [],
    "rationale": "Bindings need spare bits (answers 08 Q7).",
    "statement": "The `base` profile shall reserve at least 16 notification bits for application use after the kernel-reserved bits; the `tiny` profile may select 8 bits with at least 4 reserved for the application.",
    "status": "Accepted 2026-10-07",
    "title": "Bit budget",
    "trace": "SPEC-006 \u00a71, \u00a72.1",
    "verification": "Analysis: `EMB_NOTIFY_APP_BITS` is 24, 12, or 4 for 32, 16, 8-bit words."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-NOTIF.md",
    "evidence": "not evaluated",
    "group": "KRN-NOTIF",
    "id": "KRN-NOTIF-007",
    "links": [],
    "rationale": "Work queues, supervisor fault delivery, and budget notices need bits the application cannot forge.",
    "statement": "The high `EMB_NOTIFY_KERNEL_BITS` of the word are reserved for the kernel (`K_WORK`, `K_FAULT`, `K_BUDGET`, rest reserved); application code shall not be able to set them (`EMB_EINVAL`), and they shall not be settable across a partition boundary.",
    "status": "Accepted 2026-10-07",
    "title": "Kernel bits",
    "trace": "SPEC-006 \u00a72.1, \u00a72.2",
    "verification": "Test: `misuse/notify_kernel_bit`; isolated profile test `part/notify_kernel_bit_cross_partition`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-NOTIF.md",
    "evidence": "not evaluated",
    "group": "KRN-NOTIF",
    "id": "KRN-NOTIF-008",
    "links": [],
    "rationale": "The edge-plus-re-check contract the multi-source pattern relies on (SPEC-006 \u00a73.2, \u00a73.3).",
    "statement": "Bits set while nobody waits shall persist until consumed; a set that satisfies the waiting owner shall hand over the satisfied bits, apply the waiter's `CLEAR` to those bits, and wake it in the same step; a bound object's transition shall produce no lost wakeup and at most one spurious pass of the bound thread.",
    "status": "Accepted 2026-10-07",
    "title": "Level semantics and hand-off",
    "trace": "SPEC-006 \u00a72.2, \u00a73.2",
    "verification": "Test: `notif/level_then_wait`, `notif/all_across_two_sets`, `notif/bound_multi_source`; model scenarios `notify_set_in_window`, `notify_level`, `notify_all_two_sets`, `bound_two_sems`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-NOTIF.md",
    "evidence": "not evaluated",
    "group": "KRN-NOTIF",
    "id": "KRN-NOTIF-009",
    "links": [],
    "rationale": "Deterministic ownership of the single binding slot; no dangling-pointer action.",
    "statement": "`bind` on an already bound object shall return `EMB_EEXIST`; `unbind` shall remove the binding; destroying the object shall not touch the thread's bits; a set to a terminated or restarted thread shall be dropped (detected by generation where generations are checked).",
    "status": "Accepted 2026-10-07",
    "title": "Binding lifecycle",
    "trace": "SPEC-006 \u00a73.1, \u00a73.2",
    "verification": "Test: `notif/bind_twice`, `notif/unbind_rebind`, `notif/bind_target_restarted` (isolated profile)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-NOTIF.md",
    "evidence": "not evaluated",
    "group": "KRN-NOTIF",
    "id": "KRN-NOTIF-010",
    "links": [
      "KRN-CAP-002"
    ],
    "rationale": "A notification is a cross-partition signal; capabilities govern it like every other cross-partition action.",
    "statement": "In isolated profiles, setting another partition's thread notification shall require a thread capability with the `NOTIFY` right, and binding an object shall require the object's `BIND` right and the thread's `NOTIFY` right.",
    "status": "Accepted 2026-10-07",
    "title": "Rights in isolated profiles",
    "trace": "SPEC-006 \u00a72.2, \u00a73.1; KRN-CAP-002",
    "verification": "Test: `part/notify_without_right` returns `EMB_EPERM`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-NOTIF.md",
    "evidence": "not evaluated",
    "group": "KRN-NOTIF",
    "id": "KRN-NOTIF-011",
    "links": [
      "OBS-005"
    ],
    "rationale": "\"Who set my bit\" is the first debugging question of event-driven code.",
    "statement": "Notification set (with whether it woke the owner), wait begin and result, and binding signals shall be trace events compiled out when tracing is disabled.",
    "status": "Accepted 2026-10-07",
    "title": "Trace",
    "trace": "SPEC-006 \u00a77; OBS-005",
    "verification": "Test: trace decoder reconstructs every set of the conformance run."
  },
  {
    "design_status": "Proposed",
    "document": "requirements/KRN-NOTIF.md",
    "evidence": "not evaluated",
    "group": "KRN-NOTIF",
    "id": "KRN-NOTIF-012",
    "links": [],
    "rationale": "Matches the M1 semaphore API and prevents confusing a bit index with a mask or waiting for an edge that already occurred.",
    "statement": "Public binding operations shall take one nonzero application-bit mask, reject zero, multiple bits, and kernel bits, and preserve the object's existing readiness. A caller shall bind before producers start or check and drain existing readiness before its first notification wait; edge-driven consumers shall drain their selected sources before waiting again.",
    "status": "Proposed 2026-10-14; mask validation is implemented for semaphore binding, broader lifecycle validation is pending.",
    "title": "Binding mask and initial readiness",
    "trace": "SPEC-006 \u00a73; A18; A23",
    "verification": "Existing `tests/conformance/test_sem.c` binding cases; planned initial-ready, multi-item drain, and invalid-mask cases mapped individually in the traceability matrix."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-OBJ.md",
    "evidence": "not evaluated",
    "group": "KRN-OBJ",
    "id": "KRN-OBJ-001",
    "links": [],
    "rationale": "ADR-020: lifecycle bugs are caught; deliberate teardown is explicit.",
    "statement": "Destroying an object with waiters is a kernel fault in checked builds unless the object was created with `ABORT_WAITERS`, in which case every waiter wakes with `DESTROYED`.",
    "status": "Accepted 2026-10-07",
    "title": "Destroy with waiters",
    "trace": "SPEC-009 \u00a76; SPEC-004 \u00a76.7; ADR-020",
    "verification": "Test: `wait/destroy_abort_waiters`, `misuse/destroy_with_waiters`; model scenario `destroy_with_waiters`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-OBJ.md",
    "evidence": "not evaluated",
    "group": "KRN-OBJ",
    "id": "KRN-OBJ-002",
    "links": [],
    "rationale": "Use-after-destroy becomes `EMB_ESTALE` instead of corruption.",
    "statement": "After destruction, the object's generation shall be bumped so stale capabilities fail validation in profiles that check them.",
    "status": "Accepted 2026-10-07",
    "title": "Generation bump on destroy",
    "trace": "SPEC-009 \u00a73.2, \u00a73.3, \u00a76",
    "verification": "Test: `obj/stale_after_destroy` (INDEXED and TABLE models)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-OBJ.md",
    "evidence": "not evaluated",
    "group": "KRN-OBJ",
    "id": "KRN-OBJ-003",
    "links": [],
    "rationale": "No allocator in the kernel path.",
    "statement": "Object storage ownership belongs to whoever provided it; the kernel never frees caller storage.",
    "status": "Accepted 2026-10-07",
    "title": "Caller owns storage",
    "trace": "SPEC-009 \u00a75, \u00a76",
    "verification": "Analysis: no free call in `kernel/`; Test: storage reusable after destroy."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-OBJ.md",
    "evidence": "not evaluated",
    "group": "KRN-OBJ",
    "id": "KRN-OBJ-004",
    "links": [],
    "rationale": "uC/OS-III's safety-critical start; a frozen object set is what a certification argument wants.",
    "statement": "`emb_system_freeze()` shall, once called, make every create and destroy operation fail with `EMB_EPERM` (fault in checked builds) for the rest of the run; the isolated reference configuration shall call it at the end of initialization.",
    "status": "Accepted 2026-10-07",
    "title": "System freeze",
    "trace": "SPEC-009 \u00a76",
    "verification": "Test: `obj/freeze_blocks_init_destroy`; isolated configuration review."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-OBJ.md",
    "evidence": "not evaluated",
    "group": "KRN-OBJ",
    "id": "KRN-OBJ-005",
    "links": [],
    "rationale": "ADR-032: restarts are visible to peers.",
    "statement": "Thread and partition handles shall carry a generation in every profile that checks generations; a wait on a handle whose generation changed because of a restart shall complete with `EMB_ESTALE`.",
    "status": "Accepted 2026-10-07",
    "title": "Thread and partition generations",
    "trace": "SPEC-009 \u00a76; ADR-032",
    "verification": "Isolated-profile test `part/join_restarted_thread_estale`; model scenario (SPEC-010)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-OBJ.md",
    "evidence": "not evaluated",
    "group": "KRN-OBJ",
    "id": "KRN-OBJ-006",
    "links": [],
    "rationale": "One place for validation, registry, binding, and naming; zero cost where not used.",
    "statement": "Every object shall begin with the header of SPEC-009 \u00a72 (`type_tag`, `lifecycle`, `flags`, and the configured optional fields); fields not configured shall occupy no storage; the tiny release header shall be one byte.",
    "status": "Accepted 2026-10-07",
    "title": "Common header",
    "trace": "SPEC-009 \u00a72",
    "verification": "Analysis: `_Static_assert` on header size per configuration; footprint test."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-OBJ.md",
    "evidence": "not evaluated",
    "group": "KRN-OBJ",
    "id": "KRN-OBJ-007",
    "links": [],
    "rationale": "Double init and destroy races have defined outcomes.",
    "statement": "Objects shall move `UNINIT` to `ACTIVE` at init, `ACTIVE` to `DESTROYING` to `UNINIT` at destroy; init on active storage shall be `EMB_EEXIST` (fault in checked builds); operations on a `DESTROYING` object shall return `EMB_ESTATE`.",
    "status": "Accepted 2026-10-07",
    "title": "Lifecycle states",
    "trace": "SPEC-009 \u00a76",
    "verification": "Test: `misuse/double_init`, SMP test `obj/op_during_destroy_estate`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-OBJ.md",
    "evidence": "not evaluated",
    "group": "KRN-OBJ",
    "id": "KRN-OBJ-008",
    "links": [],
    "rationale": "ADR-006 without mirrored structs or exposed layouts.",
    "statement": "`<emb/storage.h>` shall be generated from a layout probe compiled for the target with the final configuration and read with the toolchain's object reader; kernel sources shall statically assert the real sizes and alignments against it; the header shall carry the configuration hash and a mismatch shall fail the build.",
    "status": "Accepted 2026-10-07",
    "title": "Generated storage types",
    "trace": "SPEC-009 \u00a75.1; ADR-006; BLD-007",
    "verification": "Build test: a deliberately stale header fails to build; Analysis: generator review."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-OBJ.md",
    "evidence": "not evaluated",
    "group": "KRN-OBJ",
    "id": "KRN-OBJ-009",
    "links": [],
    "rationale": "Static objects without hand-written init code, on AVR too (09 \u00a77).",
    "statement": "`_DEFINE` macros shall register objects in the bracketed section `.emb_init_table`; `emb_kernel_init()` shall construct them in link order before scheduler start; `EMB_INIT_AFTER` shall order dependent objects; the mechanism shall use the port's supported section/table mechanism; M1 AVR requires the board linker script to bracket flash entries (A8).",
    "status": "Accepted 2026-10-07",
    "title": "Init table",
    "trace": "SPEC-009 \u00a75.2; SPEC-001 \u00a76.4",
    "verification": "Test: init-table construction during `emb_kernel_init()` on every port including AVR."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-OBJ.md",
    "evidence": "not evaluated",
    "group": "KRN-OBJ",
    "id": "KRN-OBJ-010",
    "links": [],
    "rationale": "The kernel never leaves a dangling owner.",
    "statement": "Destroy shall be refused with `EMB_EBUSY` (fault in checked builds) for an owned mutex, a pool with outstanding blocks, a timer with a pending or running callback, a work queue with items, and a thread that is not inactive or terminated-and-reusable.",
    "status": "Accepted 2026-10-07",
    "title": "Type-specific destroy conditions",
    "trace": "SPEC-009 \u00a76, \u00a78",
    "verification": "Test: `misuse/destroy_*` per type."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-OBJ.md",
    "evidence": "not evaluated",
    "group": "KRN-OBJ",
    "id": "KRN-OBJ-011",
    "links": [
      "OBS-008"
    ],
    "rationale": "Debuggers and statistics enumerate objects without symbols (ADR-011).",
    "statement": "With `CONFIG_EMB_OBJ_NAMES` objects shall keep their attribute name by pointer; with `CONFIG_EMB_OBJ_LIST` every active object shall be on a per-type list iterable under the scheduler lock; the debug descriptor shall export header offsets, type tags, list heads, and the registry or capability table layout.",
    "status": "Accepted 2026-10-07",
    "title": "Names and registry",
    "trace": "SPEC-009 \u00a77; OBS-008",
    "verification": "Test: debug descriptor consumer lists every object of the conformance run."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-OBJ.md",
    "evidence": "not evaluated",
    "group": "KRN-OBJ",
    "id": "KRN-OBJ-012",
    "links": [],
    "rationale": "A const form would expose the layout the storage type hides.",
    "statement": "Kernel objects shall live in RAM and be constructed at boot; no const-initializer form of an object shall be part of the public API in 1.0.",
    "status": "Accepted 2026-10-07",
    "title": "No flash-resident objects in 1.0",
    "trace": "SPEC-009 \u00a75.3, \u00a712.5",
    "verification": "Analysis: header review."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-OBJ.md",
    "evidence": "not evaluated",
    "group": "KRN-OBJ",
    "id": "KRN-OBJ-013",
    "links": [
      "OBS-005"
    ],
    "rationale": "Lifecycle debugging.",
    "statement": "Object init and destroy (with the number of waiters flushed), capability changes, and system freeze shall be trace events.",
    "status": "Accepted 2026-10-07",
    "title": "Trace",
    "trace": "SPEC-009 \u00a79; OBS-005",
    "verification": "Test: trace decoder."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-001",
    "links": [],
    "rationale": "The partition is the unit of accounting, rights, and containment.",
    "statement": "Every thread shall belong to exactly one partition.",
    "status": "Accepted 2026-10-07",
    "title": "Every thread has one partition",
    "trace": "SPEC-010 \u00a72; ADR-015",
    "verification": "Analysis: generator rejects a thread without a partition; the kernel partition is the default in unprotected builds."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-002",
    "links": [],
    "rationale": "Footprint of tiny and base.",
    "statement": "Builds without protection hardware shall have exactly one partition and no partition code.",
    "status": "Accepted 2026-10-07",
    "title": "Compiles to nothing without protection hardware",
    "trace": "SPEC-010 \u00a714",
    "verification": "Footprint test: the partition symbols are absent from tiny and base images."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-003",
    "links": [],
    "rationale": "Freedom from interference.",
    "statement": "On protection hardware, memory access of an unprivileged partition shall be limited to its regions; violations shall be partition faults.",
    "status": "Accepted 2026-10-07",
    "title": "Memory confinement",
    "trace": "SPEC-010 \u00a74, \u00a76",
    "verification": "Isolated-profile tests `part/access_outside_region_faults` on Armv7-M and Armv8-M; fuzzing of pointer arguments."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-004",
    "links": [],
    "rationale": "Recovery of a contained fault while the rest of the system keeps its guarantees.",
    "statement": "Partition restart shall not require system reboot and shall restore the partition's static data to its initial image.",
    "status": "Accepted 2026-10-07",
    "title": "Restart without reboot",
    "trace": "SPEC-010 \u00a77",
    "verification": "Test: `part/restart_restores_data`, `part/restart_keeps_other_partition_latency` (T12 measurement)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-005",
    "links": [],
    "rationale": "Hubris and Tock: policy outside the kernel keeps the kernel small and the policy testable.",
    "statement": "Fault policy shall be per partition and applied by a supervisor partition, not hard-coded in the kernel.",
    "status": "Accepted 2026-10-07",
    "title": "Policy in the supervisor",
    "trace": "SPEC-010 \u00a76",
    "verification": "Analysis: the kernel's fault path only records and notifies; Test: replacing the reference supervisor changes the behavior."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-006",
    "links": [],
    "rationale": "Static tables are auditable and need no kernel allocator.",
    "statement": "Partition definitions shall be static, build-time data in the first isolated release; dynamic partition creation is FUTURE.",
    "status": "Accepted 2026-10-07",
    "title": "Static partitions in the first isolated release",
    "trace": "SPEC-010 \u00a71, \u00a72",
    "verification": "Analysis: no runtime partition creation API exists."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-007",
    "links": [],
    "rationale": "ADR-033.",
    "statement": "In isolated profiles, the kernel state that describes a partition (its threads, objects, wait nodes, capability table) shall live in a kernel-owned sub-region of that partition's memory, sized by the generator and re-initialized on restart; a partition shall not be able to consume kernel memory outside it.",
    "status": "Accepted 2026-10-07",
    "title": "Partition-local kernel storage",
    "trace": "SPEC-010 \u00a73",
    "verification": "Analysis: generator report lists kstore size per partition; Test: `part/init_outside_kstore_refused`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-008",
    "links": [],
    "rationale": "One source of truth for isolation (SPEC-014).",
    "statement": "A partition shall be described by privilege, supervisor, fault policy, restart limit, regions, threads, objects, initial capabilities, capability table size, and optional share; the generator shall emit the partition table, capability tables, descriptors with kstore addresses, device grants, linker sections, and protection tables from it.",
    "status": "Accepted 2026-10-07",
    "title": "Partition description",
    "trace": "SPEC-010 \u00a72",
    "verification": "Generator tests `hw/gen_partitions_*`; schema validation."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-009",
    "links": [],
    "rationale": "Armv7-M's power-of-two regions and the region budget are the hard part; it belongs to the generator, not to runtime.",
    "statement": "Each partition's RAM shall be one block with the kstore at its end, privileged-only; code shall be in per-partition flash sections; the generator shall enforce the region count, alignment, size, and kstore-exclusion constraints of the protection hardware and shall fail the build naming the violated constraint.",
    "status": "Accepted 2026-10-07",
    "title": "Layout and hardware constraints",
    "trace": "SPEC-010 \u00a73, \u00a74.1, \u00a74.3",
    "verification": "Generator tests for Armv7-M and Armv8-M constraint violations; boot test of the isolated reference configuration."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-010",
    "links": [],
    "rationale": "Isolation must not tax every switch.",
    "statement": "Only a context switch between threads of different partitions shall reprogram the protection hardware and the privilege bit; switches within a partition shall cost the same as in the base profile.",
    "status": "Accepted 2026-10-07",
    "title": "Cross-partition switch cost only",
    "trace": "SPEC-010 \u00a74.4",
    "verification": "Benchmark: harness switch cost intra- and cross-partition (T5, T12)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-011",
    "links": [],
    "rationale": "Blocking is impossible in exception context; the kstore accounts the memory to the partition.",
    "statement": "Every unprivileged thread shall have a kernel stack in its partition's kstore; a system call shall switch to it and execute the marshaller and implementation in privileged thread mode with interrupts enabled, so that it can block through the wait protocol; the per-CPU exception stack shall be used only for trap entry and exit.",
    "status": "Accepted 2026-10-07",
    "title": "Per-thread kernel stack, syscalls in privileged thread mode",
    "trace": "SPEC-010 \u00a75.2",
    "verification": "Test: `part/syscall_blocks_and_resumes`; stack high-water of kernel stacks reported."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-012",
    "links": [],
    "rationale": "No hand-written wrapper layer (R-001 \u00a77, FreeRTOS); the review gate for new API is the generator.",
    "statement": "Trap stubs, marshallers, and the syscall table shall be generated from the API annotations with explicit argument-kind classification; the generator shall refuse an unclassifiable prototype; syscall numbers shall be stable within a release line.",
    "status": "Accepted 2026-10-07",
    "title": "Generated stubs, marshallers, and table",
    "trace": "SPEC-010 \u00a75.3",
    "verification": "Generator test with a deliberately unclassifiable prototype; ABI document check in CI."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-013",
    "links": [
      "KRN-CAP-002"
    ],
    "rationale": "Attribute snapshots avoid top-level field races; buffer lifetime, nested pointers and safe copies additionally require KRN-PART-025. No unvalidated user pointer (R-001 \u00a77, NuttX).",
    "statement": "Marshallers shall validate handles through capability lookup with the annotated right, pointer arguments against the caller's regions with the needed access and bounded length, attribute structs by copy before validation, names by copy into kstore buffers, scalars by range, and callback pointers against executable regions; every failure shall be a status to the caller.",
    "status": "Accepted 2026-10-07",
    "title": "Argument validation",
    "trace": "SPEC-010 \u00a75.4; KRN-CAP-002",
    "verification": "Test: `part/validate_*` matrix; fuzzing of the boundary with random arguments never faults the kernel."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-014",
    "links": [],
    "rationale": "One ordinary calling convention per privilege level; the authenticated internal syscall-return trap is a separate exception (SPEC-010 \u00a75.2, KRN-PART-026).",
    "statement": "Privileged code shall call kernel implementations directly; an ordinary API-entry `SVC` or `ecall` from privileged code shall be a kernel fault in checked builds and `EMB_ENOTSUP` in release builds.",
    "status": "Accepted 2026-10-07",
    "title": "Privileged code never traps",
    "trace": "SPEC-010 \u00a75.1, \u00a712",
    "verification": "Test: `misuse/svc_from_privileged`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-015",
    "links": [],
    "rationale": "Containment with the evidence intact for the supervisor and the debugger.",
    "statement": "A fault in an unprivileged thread shall suspend that thread with its state preserved and the `FAULTED` flag, append a descriptor to the supervisor's fault ring, and set `EMB_NOTIFY_K_FAULT` on the supervisor's thread; a `halt` policy shall suspend the whole partition first; without a supervisor the fault shall be a kernel fault; faults in privileged threads, interrupt context, the kernel partition, or the supervisor shall be kernel faults.",
    "status": "Accepted 2026-10-07",
    "title": "Fault capture and delivery",
    "trace": "SPEC-010 \u00a76",
    "verification": "Test: `part/fault_delivered_to_supervisor`, `part/fault_without_supervisor_is_kernel_fault`, `part/fault_halt_policy`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-016",
    "links": [],
    "rationale": "A defined, auditable sequence that leaves no dangling reference.",
    "statement": "Restart shall, in order: stop every thread of the partition without delivering results, flush other partitions' waiters on its objects and threads with `STALE`, release mutexes it owns outside itself with owner-death semantics; bump its generations; quiesce its asynchronous device/DMA requests before memory reuse, reset exclusively owned devices without disturbing shared clients, and preserve authoritative incremented generations; re-copy `.data`, zero `.bss`, re-initialize the kstore, objects, and capability table from the generated tables; start its autostart threads and count the restart.",
    "status": "Accepted 2026-10-07",
    "title": "Restart procedure",
    "trace": "SPEC-010 \u00a77",
    "verification": "Test: `part/restart_*` for each step's observable effect; model scenario `partition_restart` (M3)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-017",
    "links": [],
    "rationale": "Hubris's lesson: a crash loop must be visible, and the evidence must survive it.",
    "statement": "The reference supervisor shall enforce a per-partition restart limit over a window, escalating to the system action when exceeded, and shall wait a configurable minimum delay (default 5 ms) before restarting so that the faulted state can be recorded.",
    "status": "Accepted 2026-10-07",
    "title": "Restart limits and delay",
    "trace": "SPEC-010 \u00a76.3",
    "verification": "Test: `supervisor/restart_limit_escalates`, `supervisor/min_delay`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-018",
    "links": [],
    "rationale": "Policy out of the kernel, mechanism in it.",
    "statement": "The kernel shall offer the supervisor: dequeue of fault descriptors, partition info, suspend, resume, restart, and resumption of a faulted thread for debugging, each gated by the corresponding partition rights; the reference supervisor shall ship as a replaceable subsystem.",
    "status": "Accepted 2026-10-07",
    "title": "Supervisor interface",
    "trace": "SPEC-010 \u00a76.3",
    "verification": "Test: `supervisor/*`; `misuse/partition_restart_without_right`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-019",
    "links": [],
    "rationale": "Drivers in partitions without kernel code per driver (Hubris, R-001 \u00a77).",
    "statement": "A device capability shall map the device's MMIO range into the partition and deliver its interrupts as a notification bit on a designated thread after the kernel masks the line; the thread shall unmask with `emb_irq_ack`, which requires the `irq` right; DMA shall require the DMA capability and buffers in a `DMA` region the partition may access.",
    "status": "Accepted 2026-10-07",
    "title": "Device capabilities and interrupt delivery",
    "trace": "SPEC-010 \u00a78",
    "verification": "Test: `part/device_irq_as_notification`, `misuse/irq_ack_without_right`; latency measured (T6 class)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-020",
    "links": [],
    "rationale": "Zero-copy sharing with explicit permissions.",
    "statement": "Shared memory between partitions shall be declared at top level with each participant's permissions and mapped as a region for each; the kernel shall not mediate accesses to it.",
    "status": "Accepted 2026-10-07",
    "title": "Shared regions",
    "trace": "SPEC-010 \u00a79",
    "verification": "Test: `part/shared_region_perms`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-021",
    "links": [],
    "rationale": "Temporal protection needs per-partition time.",
    "statement": "When partition shares are configured, the kernel shall charge thread execution to the thread's partition at every switch and deliver share and budget events per ADR-029.",
    "status": "Accepted 2026-10-07",
    "title": "Partition accounting",
    "trace": "SPEC-010 \u00a710; KRN-TP-007 to 009",
    "verification": "Test: `tp/partition_share_enforced_under_load`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-022",
    "links": [
      "OBS-005",
      "OBS-008"
    ],
    "rationale": "Containment that cannot be observed cannot be trusted.",
    "statement": "Partition faults, restarts, suspends, resumes, denied capability uses, and delivered interrupts shall be trace events; syscall tracing shall be an option; per-partition statistics shall include syscalls, denials, faults, restarts, and CPU time; the debug descriptor shall export the partition table, kstore layouts, and capability tables; contained faults shall optionally produce retained crash-record entries.",
    "status": "Accepted 2026-10-07",
    "title": "Observability",
    "trace": "SPEC-010 \u00a713; OBS-005, OBS-008",
    "verification": "Test: trace decoder; descriptor consumer; retained record read-back after a contained fault."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-023",
    "links": [],
    "rationale": "The roadmap's M3 exit criteria (07 \u00a72).",
    "statement": "M3 shall implement static partitions, kstores, generated layout and protection tables, cross-partition switching, the syscall boundary, fault delivery, the reference supervisor, restart, device capabilities with interrupt delivery, and shared regions on Armv7-M and Armv8-M; PMP, ports and leases, budget donation, secure partitions, and the trap-free kernel page are deferred.",
    "status": "Accepted 2026-10-07",
    "title": "M3 scope",
    "trace": "SPEC-010 \u00a715; 07 \u00a72 M3",
    "verification": "M3 exit review against this list."
  },
  {
    "design_status": "Proposed",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-024",
    "links": [
      "KRN-PART-003"
    ],
    "rationale": "CPU protection does not generally constrain bus masters; restart must not leave writes into reused memory.",
    "statement": "An untrusted partition shall not directly program a DMA-capable device unless independent hardware constrains all addresses/descriptors it can use. Otherwise a trusted driver shall validate and own DMA requests. Before partition memory is reset or reused, all asynchronous producers shall be quiesced within a declared deadline or recovery shall escalate. Shared devices shall use per-client cancellation rather than an unrelated global reset.",
    "status": "Proposed 2026-10-14; unimplemented.",
    "title": "DMA confinement and quiescence",
    "trace": "SPEC-010 \u00a77, \u00a78, \u00a717; KRN-PART-003, 004",
    "verification": "Planned physical-board negative DMA access tests; fault injection during transfers/restart; stalled-device escalation and shared-client continuity cases."
  },
  {
    "design_status": "Proposed",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-025",
    "links": [],
    "rationale": "Entry-time pointer validation alone cannot protect a blocking call or a restarted partition.",
    "statement": "Marshallers shall check address/length arithmetic without overflow and complete-region permissions, snapshot security-relevant descriptors, and keep mappings, object references and permitted buffer ownership valid until completion or bounded cancellation. Completion shall reject a changed caller incarnation; restart shall remove every in-flight reference to memory it will reuse.",
    "status": "Proposed 2026-10-14; unimplemented.",
    "title": "Blocking syscall buffer lifetime",
    "trace": "SPEC-010 \u00a75.4, \u00a717; SPEC-007 \u00a72",
    "verification": "Planned range-overflow/hole/permission tests; mutate descriptors after entry; restart/cancel while remote sends or DMA reference user buffers; safe-copy fault recovery tests."
  },
  {
    "design_status": "Proposed",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-026",
    "links": [
      "KRN-PART-011"
    ],
    "rationale": "Protected storage and stacks are ineffective if marshalling permits authority bypass.",
    "statement": "Ordinary user entry and internal privileged syscall return shall be validated as distinct paths. A user shall not forge privileged return state or overwrite arbitrary kstore bytes through object initialization; construction shall be restricted to a kernel-authorized typed slot.",
    "status": "Proposed 2026-10-14; unimplemented.",
    "title": "Authenticated syscall return and object construction",
    "trace": "SPEC-010 \u00a73, \u00a75.2, \u00a717; KRN-PART-011, 013",
    "verification": "Planned forged syscall number/frame/stack tests, nested entry tests, out-of-slot/overlapping init requests and fuzz campaigns."
  },
  {
    "design_status": "Proposed",
    "document": "requirements/KRN-PART.md",
    "evidence": "not evaluated",
    "group": "KRN-PART",
    "id": "KRN-PART-027",
    "links": [
      "KRN-CAP-013",
      "KRN-PART-004"
    ],
    "rationale": "Preemptible steps alone do not establish progress or freedom from interference.",
    "statement": "Restart shall declare stop/quiescence and protected-step bounds, preserve incremented incarnation state across image restoration, and complete remote waits with their specified outcomes. A claimed unrelated-partition response-time guarantee shall include priority, locks, bus interference and device stopping; a missed stop deadline shall escalate safely.",
    "status": "Proposed 2026-10-14; unimplemented.",
    "title": "Restart progress and evidence",
    "trace": "SPEC-010 \u00a77, \u00a717; KRN-PART-004, 016; KRN-CAP-013",
    "verification": "Planned fault/restart campaigns with remote lock owners/waiters, stale handles, DMA and unrelated workload; generation-exhaustion tests; archived physical latency analysis and samples."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-001",
    "links": [],
    "rationale": "One protocol under every primitive (SPEC-004) means one set of race rules, one model, one set of tests.",
    "statement": "Blocking synchronization shall use the common kernel wait mechanism.",
    "status": "Accepted 2026-10-07",
    "title": "Common wait mechanism",
    "trace": "SPEC-005 \u00a71; SPEC-004; v0.1 \u00a78.6",
    "verification": "Analysis: every blocking entry in `kernel/sync/` calls `embk_wait_prepare` and `embk_wait_commit` or `embk_block_on`; a grep in CI rejects any other path to `BLOCKED`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-002",
    "links": [
      "KRN-SYNC-008"
    ],
    "rationale": "A mutex is not a semaphore; unlock by a non-owner is the classic silent corruption.",
    "statement": "Mutex ownership shall be explicit and validated where configuration permits.",
    "status": "Accepted 2026-10-07",
    "title": "Explicit, validated ownership",
    "trace": "SPEC-005 \u00a73.1, \u00a73.3; KRN-SYNC-008",
    "verification": "Test: `misuse/mutex_unlock_non_owner` in checked and release builds (TEST-010); `sync/mutex_is_owner`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-003",
    "links": [],
    "rationale": "Priority inversion is a first-class real-time problem (v0.1 \u00a78.3).",
    "statement": "The mutex subsystem shall support priority inheritance for configurations that enable real-time mutexes.",
    "status": "Accepted 2026-10-07",
    "title": "Priority inheritance available",
    "trace": "SPEC-005 \u00a72, \u00a73.2; ADR-028",
    "verification": "Test: `sync/pi_classic_inversion` checks that the medium-priority thread never runs while the high one waits on the low one's mutex; model scenario `classic_inversion`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-004",
    "links": [
      "KRN-SYNC-009"
    ],
    "rationale": "H waits for A held by M, M waits for B held by L: H's priority must reach L (v0.1 \u00a78.3).",
    "statement": "Priority inheritance shall support nested dependency chains.",
    "status": "Accepted 2026-10-07",
    "title": "Nested dependency chains",
    "trace": "SPEC-005 \u00a72.2; KRN-SYNC-009, 019",
    "verification": "Test: `sync/pi_nested_chain` to depth 3; model scenario `nested_chain_timeout`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-005",
    "links": [
      "KRN-IRQ-010"
    ],
    "rationale": "The ISR-safe path has no ownership and no inheritance; the annotation is the contract (SPEC-001 \u00a75.2).",
    "statement": "ISR-safe signaling operations shall be distinct from blocking thread-only operations.",
    "status": "Accepted 2026-10-07",
    "title": "ISR-safe signaling is distinct",
    "trace": "SPEC-005 \u00a71; SPEC-001 \u00a75.2; KRN-IRQ-010",
    "verification": "Analysis: `tools/apidoc` checks that `give`, `set`, `clear` carry `@ctx thread isr` and every `lock`, `take`, `wait` carries `@ctx thread`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-006",
    "links": [
      "KRN-WAIT-001"
    ],
    "rationale": "Schedulability analysis needs to know who wakes first.",
    "statement": "Synchronization object wait ordering shall be documented and deterministic.",
    "status": "Accepted 2026-10-07",
    "title": "Deterministic wait ordering",
    "trace": "SPEC-005 \u00a71; KRN-WAIT-001, 002",
    "verification": "Test: the `wait/order_*` group runs against every primitive of SPEC-005."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-007",
    "links": [
      "KRN-WAIT-010"
    ],
    "rationale": "Determinism and the tiny profile.",
    "statement": "No synchronization primitive used on a real-time path shall require hidden dynamic allocation after initialization.",
    "status": "Accepted 2026-10-07",
    "title": "No hidden allocation",
    "trace": "SPEC-005 \u00a71; KRN-WAIT-010; KRN-MEM",
    "verification": "Analysis: no allocator symbol is reachable from `kernel/sync/` (link-map check in CI)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-008",
    "links": [],
    "rationale": "Misuse, per SPEC-001 \u00a75.3.",
    "statement": "Unlock by a non-owner shall be a kernel fault in checked builds and `EMB_EPERM` in release builds.",
    "status": "Accepted 2026-10-07",
    "title": "Unlock by a non-owner",
    "trace": "SPEC-005 \u00a73.3, \u00a711",
    "verification": "Test: `misuse/mutex_unlock_non_owner`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-009",
    "links": [],
    "rationale": "Unbounded walks are a latency hazard; the bound is a design parameter.",
    "statement": "Priority inheritance shall be transitive through chains of mutexes with a configurable maximum depth; exceeding it is a kernel fault in checked builds.",
    "status": "Accepted 2026-10-07",
    "title": "Transitive inheritance with a depth bound",
    "trace": "SPEC-005 \u00a72.2; ADR-028",
    "verification": "Test: `sync/pi_depth_bound` builds a chain of `CONFIG_EMB_PI_MAX_DEPTH + 1` and checks the fault (checked) and the truncation trace event (release)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-010",
    "links": [],
    "rationale": "The one-mutex simplification of other kernels (R-001 \u00a75) is wrong as soon as two mutexes are held.",
    "statement": "On unlock, the owner's effective priority shall be recomputed as the maximum of its base priority and the highest priority waiter across all mutexes it still owns.",
    "status": "Accepted 2026-10-07",
    "title": "Recomputation on unlock",
    "trace": "SPEC-005 \u00a72.1, \u00a73.3",
    "verification": "Test: `sync/pi_two_mutexes_restore`; model invariant `eff == effective(base, owned)`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-011",
    "links": [
      "KRN-SYNC-025"
    ],
    "rationale": "Both are legitimate: a fault for systems where it must never happen, recovery for systems that restart partitions.",
    "statement": "When a mutex owner terminates while owning mutexes, the behavior is a configuration choice: fault (default) or release-with-`EMB_EOWNERDEAD` delivered to the next owner.",
    "status": "Accepted 2026-10-07",
    "title": "Owner termination",
    "trace": "SPEC-005 \u00a73.6; KRN-SYNC-025",
    "verification": "Test: `sync/owner_death_fault`, `sync/owner_death_release_with_waiter`, `sync/owner_death_release_no_waiter`; model scenarios `owner_death_*`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-012",
    "links": [],
    "rationale": "One mutex type, two protocols; the effective-priority machinery already exists.",
    "statement": "Priority ceiling protocol shall be available as a per-mutex option on the same object type, using the effective-priority mechanism.",
    "status": "Accepted 2026-10-07",
    "title": "Ceiling protocol on the same object type",
    "trace": "SPEC-005 \u00a73.4; ADR-030",
    "verification": "Test: `sync/ceiling_lock_raises`, `sync/ceiling_unlock_restores`; model scenario `ceiling_mutex`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-013",
    "links": [
      "KRN-SYNC-023"
    ],
    "rationale": "Recursion hides locking-discipline errors; it is offered, not default.",
    "statement": "Recursive locking shall be a per-mutex creation option, disabled by default.",
    "status": "Accepted 2026-10-07",
    "title": "Recursive locking is an option",
    "trace": "SPEC-005 \u00a73.2; KRN-SYNC-023",
    "verification": "Test: `sync/mutex_recursive`, `sync/mutex_nonrecursive_self_relock`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-014",
    "links": [],
    "rationale": "Deferred drops leave a thread boosted for an unbounded time (Zephyr's documented limitation, R-001 \u00a75).",
    "statement": "Each thread shall keep an intrusive list of the mutexes it owns; the recomputation of KRN-SYNC-010 shall use it and shall run at unlock, at waiter timeout or cancel, and at waiter priority change, immediately and not deferred to the waiter's resumption.",
    "status": "Accepted 2026-10-07",
    "title": "Owned-mutex list and immediate recomputation",
    "trace": "SPEC-005 \u00a72.3, \u00a73.3; ADR-028",
    "verification": "Test: `sync/pi_timeout_disinherits_immediately` checks the owner's priority in the same tick as the timeout; model scenario `nested_chain_timeout`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-015",
    "links": [
      "KRN-SYNC-024"
    ],
    "rationale": "The walk visits the chain anyway; detection is free.",
    "statement": "The inheritance walk shall detect a cycle that returns to the caller and shall report `EMB_EDEADLK` (kernel-reserved status range) in release builds and fault in checked builds.",
    "status": "Accepted 2026-10-07",
    "title": "Deadlock detection",
    "trace": "SPEC-005 \u00a73.5; KRN-SYNC-024",
    "verification": "Test: `sync/deadlock_two_lockers`; model scenario `deadlock_two_lockers` (every terminal state has a detected cycle, none a silent one)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-016",
    "links": [],
    "rationale": "ChibiOS's LIFO rule is a usability trap (R-001 \u00a75); the owned list makes any order cheap.",
    "statement": "Mutexes may be unlocked in any order; there is no LIFO requirement.",
    "status": "Accepted 2026-10-07",
    "title": "Any unlock order",
    "trace": "SPEC-005 \u00a73.3",
    "verification": "Test: `sync/unlock_non_lifo`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-017",
    "links": [],
    "rationale": "RTIC's compile-time ceilings for threads in a C kernel (ADR-030).",
    "statement": "A ceiling mutex declared in the system description shall receive its ceiling from the generator as the highest base priority among its declared users; locking it shall raise effective priority to the ceiling; a queue-free optimization shall additionally prove the UP execution restrictions in SPEC-005 \u00a73.4, including no blocking/yield/suspension/budget-induced ineligibility while held. M1 retains wait queues and owned-list scans.",
    "status": "Accepted 2026-10-07",
    "title": "Static ceilings from the system description",
    "trace": "SPEC-005 \u00a73.4; ADR-030",
    "verification": "Test: generator test `hw/gen_ceiling` plus `sync/ceiling_static_no_queue` on the tiny profile."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-018",
    "links": [],
    "rationale": "One definition that every operation recomputes; no incremental bookkeeping that can drift.",
    "statement": "A thread's effective priority shall be the maximum of its scheduling base priority, the effective priority of the highest waiter on each `INHERIT` mutex it owns, and the ceiling of each `CEILING` mutex it owns; a change shall be applied to the ready structure, to the thread's wait-queue position, or to the reschedule decision in the operation that caused it.",
    "status": "Accepted 2026-10-07",
    "title": "Effective priority definition",
    "trace": "SPEC-005 \u00a72.1",
    "verification": "Analysis: model invariant checked after every step; checked builds assert it after every priority-touching operation (SPEC-005 \u00a711)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-019",
    "links": [],
    "rationale": "Non-propagated lowerings leave distant owners boosted (Zephyr); propagating both keeps the invariant of KRN-SYNC-018 global.",
    "statement": "A change of a thread's effective priority shall propagate along the chain of `INHERIT` mutexes it waits on, for raises and for lowerings, in the same operation, stopping where a hop's effective priority does not change or at the configured depth.",
    "status": "Accepted 2026-10-07",
    "title": "Propagation in both directions",
    "trace": "SPEC-005 \u00a72.2",
    "verification": "Test: `sync/pi_chain_lowering`; model scenarios `nested_chain_timeout`, `waiter_priority_change`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-020",
    "links": [],
    "rationale": "R-003 target T9.",
    "statement": "Lock/unlock timing shall include owned-mutex append/remove/recomputation, wait insertion or requeue, separate deadlock traversal, inheritance depth and configured scheduler scans. M1 shall be documented as holding one caller section across propagation; per-hop sections and constant-time uncontended bookkeeping shall not be claimed without implementation and evidence.",
    "status": "Accepted 2026-10-07",
    "title": "Mutex lock cost",
    "trace": "SPEC-005 \u00a73.2, \u00a72.2; R-003 \u00a74 T9",
    "verification": "Benchmark: harness operation \"mutex lock and unlock uncontended; contended with chains of depth 1, 2, 4\" (TEST-012); monitor of ADR-034 for section lengths."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-021",
    "links": [],
    "rationale": "No barging, wait-order fairness (KRN-WAIT-012).",
    "statement": "Unlock shall transfer ownership to the highest waiter in the same step as its wake; the new owner shall inherit from the remaining waiters at once; a thread that arrives between the unlock and the new owner's run shall not acquire the mutex.",
    "status": "Accepted 2026-10-07",
    "title": "Hand-off on unlock",
    "trace": "SPEC-005 \u00a73.3",
    "verification": "Test: `sync/mutex_no_barging`; model scenario `two_waiters_handoff`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-022",
    "links": [],
    "rationale": "Timeout, cancellation, destroy, and priority change all change the owner's contribution; one hook covers them.",
    "statement": "A mutex's wait queue shall carry the inherit flag; the wait protocol shall call the mutex's waiters-changed hook after any dequeue or requeue that is not a hand-off, and the hook shall recompute the owner's chain.",
    "status": "Accepted 2026-10-07",
    "title": "Waiter removal hook",
    "trace": "SPEC-005 \u00a73.3; SPEC-004 \u00a75.2",
    "verification": "Test: `sync/pi_cancel_disinherits`, `sync/pi_destroy_disinherits`; model scenario `cancel_waiter_disinherits`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-023",
    "links": [],
    "rationale": "Self-deadlock is the most common mutex bug; it must not hang.",
    "statement": "A `RECURSIVE` mutex shall count nested locks by its owner up to 255 and return `EMB_EOVERFLOW` beyond; a non-recursive mutex locked again by its owner shall return `EMB_EDEADLK` (fault in checked builds).",
    "status": "Accepted 2026-10-07",
    "title": "Recursion and self-relock",
    "trace": "SPEC-005 \u00a73.2",
    "verification": "Test: `sync/mutex_recursive_depth`, `misuse/mutex_self_relock`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-024",
    "links": [],
    "rationale": "A stable code for a condition that is always a program error.",
    "statement": "`EMB_EDEADLK` shall be defined with value -32 in the kernel-reserved status range; it shall be returned for a detected cycle through `INHERIT` mutexes and for a non-recursive self-relock; cycles through `NONE` mutexes are not detected and the documentation shall say so.",
    "status": "Accepted 2026-10-07",
    "title": "`EMB_EDEADLK`",
    "trace": "SPEC-005 \u00a73.1, \u00a73.5; SPEC-001 \u00a74.2",
    "verification": "Analysis: `emb/status.h` and `emb_status_name()`; Test: `sync/deadlock_two_lockers`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-025",
    "links": [
      "KRN-SYNC-011"
    ],
    "rationale": "Robust-mutex semantics simple enough for an MCU; the next owner always learns that state may be inconsistent.",
    "statement": "`CONFIG_EMB_MUTEX_OWNER_DEATH=FAULT` (default) shall fault in checked builds and record a non-fatal crash-record event in release builds while releasing the mutexes; `RELEASE` shall hand each owned mutex to its highest waiter with `EMB_EOWNERDEAD` or mark it inconsistent so that the next lock returns `EMB_EOWNERDEAD`; the inconsistent mark shall be cleared by the recovering owner's unlock or by `emb_mutex_mark_consistent()`.",
    "status": "Accepted 2026-10-07",
    "title": "Owner death policies",
    "trace": "SPEC-005 \u00a73.6; KRN-SYNC-011; 08 Q5",
    "verification": "Test: `sync/owner_death_*`; model scenarios `owner_death_with_waiter`, `owner_death_no_waiter`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-026",
    "links": [
      "KRN-SYNC-017"
    ],
    "rationale": "Immediate-ceiling guarantees require an analyzed execution/resource model; declared users alone do not establish no contention or deadlock freedom.",
    "statement": "Locking a `CEILING` mutex shall raise the caller's effective priority to the ceiling immediately; a caller whose base priority exceeds the ceiling, or that is not a declared user of a statically declared mutex, is misuse (`EMB_EPERM` in release builds); a future `CONFIG_EMB_MUTEX_CEILING_STATIC_ONLY` optimization shall omit a wait queue only after enforcing the complete restrictions of SPEC-005 \u00a73.4; it is unimplemented in M1.",
    "status": "Accepted 2026-10-07",
    "title": "Ceiling rules",
    "trace": "SPEC-005 \u00a73.4; KRN-SYNC-017",
    "verification": "Test: `sync/ceiling_*`, `misuse/ceiling_violation`; footprint test on the tiny profile."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-027",
    "links": [],
    "rationale": "An ISR cannot own anything, so it cannot participate in inheritance (R-001 \u00a75, FreeRTOS).",
    "statement": "Mutexes, condition variables, and barriers shall have no ISR-callable operation; semaphores and event flags shall have ISR-safe `give`, `set`, and `clear`.",
    "status": "Accepted 2026-10-07",
    "title": "No ISR operation on mutexes",
    "trace": "SPEC-005 \u00a71, \u00a73.1, \u00a711",
    "verification": "Analysis: `@ctx` annotations; Test: `misuse/mutex_from_isr`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-028",
    "links": [],
    "rationale": "Hand-off gives fairness; the bound makes binary semaphores a configuration, not a type; resets with waiters are the hazard ADR-020 refuses.",
    "statement": "A semaphore shall have a configurable count width (8, 16, or 32 bits), an initial count and a maximum; `give` with a waiter shall hand the unit over without touching the count, otherwise increment, returning `EMB_EOVERFLOW` at the maximum unless `SATURATE` is set; `take` shall decrement when positive else wait; the kernel shall offer no `give_all` and no `reset`.",
    "status": "Accepted 2026-10-07",
    "title": "Semaphore semantics",
    "trace": "SPEC-005 \u00a74",
    "verification": "Test: `sync/sem_*`; model: the semaphore of `tools/model` with unit conservation."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-029",
    "links": [],
    "rationale": "Deterministic consumption of overlapping bits; a single batch wake.",
    "statement": "Each event waiter shall carry its own mask and mode; `set` shall wake every satisfied waiter in queue order, handing it the satisfied bits, and shall apply a waiter's `CLEAR` before evaluating the next waiter; `clear` shall never wake; `set` shall be ISR-safe and O(waiters on that group).",
    "status": "Accepted 2026-10-07",
    "title": "Event flag semantics",
    "trace": "SPEC-005 \u00a75",
    "verification": "Test: `sync/event_any_all_clear`, `sync/event_overlapping_clear_order`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-030",
    "links": [],
    "rationale": "Classic, analyzable semantics; the relock-always rule is what callers can reason about.",
    "statement": "`cond_wait` shall require ownership with recursion count 1, shall enqueue and then fully unlock the mutex atomically with respect to `signal`, and shall relock the mutex before returning on every result; `signal` shall wake the highest waiter and `broadcast` all; the kernel shall never wake a condition waiter without a signal or broadcast.",
    "status": "Accepted 2026-10-07",
    "title": "Condition variable semantics",
    "trace": "SPEC-005 \u00a76",
    "verification": "Test: `sync/cond_*` including relock after timeout; `misuse/cond_wait_not_owner`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-031",
    "links": [],
    "rationale": "Phase synchronization for parallel work on multicore targets.",
    "statement": "With `CONFIG_EMB_BARRIER`, the arrival that completes the count shall wake all waiters with one reschedule and return serial to exactly one caller; a waiter that times out or is canceled shall leave the barrier without releasing the others.",
    "status": "Accepted 2026-10-07",
    "title": "Barrier semantics",
    "trace": "SPEC-005 \u00a77",
    "verification": "Test: `sync/barrier_*`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-032",
    "links": [],
    "rationale": "Setting the priority of a boosted owner must not drop the boost (ChibiOS gets this right; several others do not).",
    "statement": "Changing a thread's base priority shall preserve inherited and ceiling contributions and shall propagate along the chain the thread waits on; a thread's visible priority shall be queryable as base and as effective.",
    "status": "Accepted 2026-10-07",
    "title": "Priority change preserves contributions",
    "trace": "SPEC-005 \u00a710, \u00a72.3",
    "verification": "Test: `sync/set_priority_keeps_boost`, `sync/set_priority_of_waiter_propagates`; model scenario `waiter_priority_change`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-033",
    "links": [],
    "rationale": "SMP correctness depends on discipline that only a validator keeps honest.",
    "statement": "Spinlocks shall be acquired with interrupts masked, shall never be held across a blocking call or a preemption point, shall not be recursive, shall follow the declared lock order, and shall compile to the critical section on uniprocessor builds; checked SMP builds shall validate these rules.",
    "status": "Accepted 2026-10-07",
    "title": "Spinlock rules",
    "trace": "SPEC-005 \u00a78; SPEC-002 \u00a74.3; KRN-SMP-002",
    "verification": "Analysis: spinlock validator; Test: SMP `misuse/spin_*`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-034",
    "links": [],
    "rationale": "09 \u00a76; KRN-TIM-016.",
    "statement": "The atomics API shall provide 32-bit and pointer-sized operations with explicit memory orders on 32-bit targets, 8-bit hardware atomics on AVR with 32-bit operations implemented by critical section, and no 64-bit atomic type.",
    "status": "Accepted 2026-10-07",
    "title": "Atomics",
    "trace": "SPEC-005 \u00a79",
    "verification": "Test: `sync/atomic_*` on every architecture; Analysis: no 64-bit atomic builtin in the link map."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-035",
    "links": [],
    "rationale": "Multi-object wait without poll objects (KRN-NOTIF-004).",
    "statement": "Semaphores and event groups shall support the notification binding of ADR-027; a count transition from zero to one, or a set that leaves changed nonzero bits after serving direct waiters, shall signal the binding; a transition consumed by a hand-off shall not.",
    "status": "Accepted 2026-10-07",
    "title": "Binding on semaphores and events",
    "trace": "SPEC-005 \u00a74.2, \u00a75.2; SPEC-004 \u00a76.3",
    "verification": "Test: `notif/bind_sem`, `notif/bind_event`; model scenario `binding_hook`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-036",
    "links": [
      "OBS-005"
    ],
    "rationale": "Inheritance bugs are invisible without a trace that names the cause.",
    "statement": "Lock, unlock with hand-off target, every inheritance change with its cause, depth-exceeded, deadlock-detected, semaphore give with hand-off, event set with woken count, and condition signal shall be trace events; contention counts, maximum boost, and maximum walk depth shall be optional statistics.",
    "status": "Accepted 2026-10-07",
    "title": "Trace and statistics",
    "trace": "SPEC-005 \u00a712; OBS-005",
    "verification": "Test: the trace decoder reconstructs every priority change of the conformance run."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-037",
    "links": [],
    "rationale": "Footprint targets T1 and T2 with correctness kept by default.",
    "statement": "The tiny profile shall offer inheritance as an option (default on), ceiling mutexes without a wait queue, 8-bit semaphore counts and event bits, and shall build condition variables and barriers only when configured.",
    "status": "Accepted 2026-10-07",
    "title": "Tiny profile options",
    "trace": "SPEC-005 \u00a713; ADR-036",
    "verification": "Test: footprint of the tiny reference configuration; conformance `sync/` group on it."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-SYNC.md",
    "evidence": "not evaluated",
    "group": "KRN-SYNC",
    "id": "KRN-SYNC-038",
    "links": [
      "KRN-WAIT-007"
    ],
    "rationale": "The algorithm's correctness claims (R-001 \u00a75 columns) are checked by exploration before implementation.",
    "statement": "The reference model shall include the mutex with inheritance, ceiling, recursion, hand-off, owner death, and deadlock detection, and shall be explored exhaustively over at least: the three-thread inversion, a two-level chain with timeout, deadlock in both lock orders, owner death with and without a waiter, a waiter's priority change, and cancellation of a waiter.",
    "status": "Accepted 2026-10-07",
    "title": "Model coverage for inheritance",
    "trace": "SPEC-005 \u00a715; KRN-WAIT-007; TEST-008",
    "verification": "Analysis: `tools/model/tests/test_explore.py` covers the listed scenarios; CI runs it."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-001",
    "links": [],
    "rationale": "Definition of the scheduler's invariant.",
    "statement": "At most one thread shall be in the RUNNING state on each online logical processor.",
    "status": "Accepted 2026-10-07",
    "title": "One RUNNING thread per processor",
    "trace": "SPEC-008 \u00a71; 03 \u00a71.1; v0.1 \u00a73.3",
    "verification": "Analysis: model invariant (`current` per CPU); Test: SMP conformance `sched/one_running_per_cpu`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-002",
    "links": [],
    "rationale": "State definition.",
    "statement": "A READY thread shall be eligible for scheduling.",
    "status": "Accepted 2026-10-07",
    "title": "READY is eligible",
    "trace": "SPEC-008 \u00a71",
    "verification": "Analysis: model invariant 5 of SPEC-004 \u00a75.4."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-003",
    "links": [],
    "rationale": "State definition.",
    "statement": "A BLOCKED thread shall not be eligible for scheduling.",
    "status": "Accepted 2026-10-07",
    "title": "BLOCKED is ineligible",
    "trace": "SPEC-008 \u00a71",
    "verification": "Analysis: model invariant 5."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-004",
    "links": [],
    "rationale": "Preemptive multithreading.",
    "statement": "Each normal thread shall possess an independent execution context and stack.",
    "status": "Accepted 2026-10-07",
    "title": "Independent context and stack",
    "trace": "SPEC-008 \u00a74, \u00a710",
    "verification": "Test: `thr/stacks_independent` (fill pattern of one thread untouched by another)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-005",
    "links": [],
    "rationale": "No fall-off-the-end crash.",
    "statement": "Returning from a thread entry function shall cause controlled thread termination through the kernel.",
    "status": "Accepted 2026-10-07",
    "title": "Entry return terminates",
    "trace": "SPEC-008 \u00a74, \u00a75",
    "verification": "Test: `thr/entry_return_exits_with_zero`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-006",
    "links": [],
    "rationale": "The exit code and the storage outlive execution; the object can exist before start.",
    "statement": "Thread execution lifetime and thread-object lifetime shall be independent.",
    "status": "Accepted 2026-10-07",
    "title": "Execution and object lifetimes are independent",
    "trace": "SPEC-008 \u00a71, \u00a75, \u00a76, \u00a78",
    "verification": "Test: `thr/join_after_exit_returns_code`, `thr/init_without_start_then_destroy`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-007",
    "links": [],
    "rationale": "KRN-MEM-001; the tiny profile.",
    "statement": "The kernel shall support statically allocated threads without requiring a dynamic allocator.",
    "status": "Accepted 2026-10-07",
    "title": "Static threads",
    "trace": "SPEC-008 \u00a72, \u00a74",
    "verification": "Analysis: `emb_thread_init` allocates nothing; `EMB_THREAD_DEFINE` is fully static."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-008",
    "links": [],
    "rationale": "Handles and debugger views.",
    "statement": "Thread identity shall remain stable for the lifetime of the thread object.",
    "status": "Accepted 2026-10-07",
    "title": "Stable identity",
    "trace": "SPEC-008 \u00a73, \u00a78",
    "verification": "Test: `thr/index_stable_across_states`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-009",
    "links": [],
    "rationale": "One protocol (SPEC-004).",
    "statement": "Thread start, suspend, and resume shall be expressed through the common wait mechanism as wait reasons, not as additional scheduler states.",
    "status": "Accepted 2026-10-07",
    "title": "Start, suspend, resume are wait reasons",
    "trace": "SPEC-008 \u00a74, \u00a77; SPEC-004 \u00a76.5",
    "verification": "Analysis: `emb_thread_start` is a wake with reason START; suspend is the overlay."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-010",
    "links": [
      "KRN-WAIT-014"
    ],
    "rationale": "Removes the classic suspend-while-waiting ambiguity.",
    "statement": "A suspended thread shall retain any pending object wait and its deadline; resume shall re-enter that wait without losing the thread's wait-queue position relative to later waiters.",
    "status": "Accepted 2026-10-07",
    "title": "Suspend keeps the wait",
    "trace": "SPEC-008 \u00a77; KRN-WAIT-014",
    "verification": "Test: `wait/suspend_while_waiting`; model scenario `suspend_while_waiting`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-011",
    "links": [
      "KRN-WAIT-015"
    ],
    "rationale": "Asynchronous kills leave locks and buffers in undefined states.",
    "statement": "Thread cancellation shall be cooperative: a cancel request is delivered as a wake result at the next blocking call or explicit cancellation point; threads are never asynchronously killed.",
    "status": "Accepted 2026-10-07",
    "title": "Cooperative cancellation",
    "trace": "SPEC-008 \u00a75, \u00a77; KRN-WAIT-015",
    "verification": "Test: `thr/cancel_*`; model scenarios `cancel_*`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-012",
    "links": [],
    "rationale": "POSIX-shaped lifetime control without an allocator.",
    "statement": "Join shall be supported for joinable threads; a detached thread's object storage becomes reusable immediately on termination according to its storage policy.",
    "status": "Accepted 2026-10-07",
    "title": "Join and detach",
    "trace": "SPEC-008 \u00a76",
    "verification": "Test: `thr/join_*`, `thr/detach_*`; model scenarios `join_*`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-013",
    "links": [],
    "rationale": "Per-thread state for libraries without compiler TLS.",
    "statement": "Thread-local storage slots shall be available as a compile-time option with a fixed per-thread slot count.",
    "status": "Accepted 2026-10-07",
    "title": "TLS slots",
    "trace": "SPEC-008 \u00a79",
    "verification": "Test: `thr/tls_slots`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-014",
    "links": [],
    "rationale": "Toolchain constraint.",
    "statement": "The kernel, ports, and drivers shall not use compiler thread-local storage (`_Thread_local`, `__thread`); EmbCC compiles it to one shared instance on embedded targets (09 \u00a73). Kernel TLS slots are the only per-thread storage mechanism.",
    "status": "Accepted 2026-10-07",
    "title": "No compiler TLS",
    "trace": "SPEC-008 \u00a79; 09 \u00a73",
    "verification": "Analysis: CI grep for `_Thread_local` and `__thread` in kernel, arch, drivers."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-015",
    "links": [],
    "rationale": "A defined reuse point instead of idle-task reclamation (R-001 \u00a71, FreeRTOS) or a spin on in-flight timeouts (Zephyr).",
    "statement": "A thread object shall pass through `INACTIVE` (initialized, not started), the scheduler states, and `TERMINATED`; its storage shall become reusable only when it is `INACTIVE`, or `TERMINATED` and either detached or joined, and the switch-out of its last execution has completed.",
    "status": "Accepted 2026-10-07",
    "title": "Lifecycle states and reusability",
    "trace": "SPEC-008 \u00a75, \u00a78",
    "verification": "Test: `thr/reuse_after_join`, `thr/reuse_detached`; SMP test `thr/destroy_waits_switch_out`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-016",
    "links": [],
    "rationale": "One way to begin execution; no implicit start at init.",
    "statement": "`start` shall be ISR-safe, legal before kernel start, shall make an `INACTIVE` thread READY behind its peers, and shall return `EMB_ESTATE` for any other state; statically defined threads shall autostart at kernel start unless marked otherwise.",
    "status": "Accepted 2026-10-07",
    "title": "Start semantics",
    "trace": "SPEC-008 \u00a74",
    "verification": "Test: `thr/start_before_kernel_start`, `thr/start_twice_estate`, `thr/define_autostart`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-017",
    "links": [],
    "rationale": "Deterministic teardown order that other specifications can rely on.",
    "statement": "Termination shall release owned mutexes per `CONFIG_EMB_MUTEX_OWNER_DEATH`, finalize statistics, store the exit code, wake the joiner with the code handed over, discard the thread's timeout, notification bits, TLS slots and bindings, set `TERMINATED`, and switch away, in that order; a pending cancel request shall not be delivered during the exit path.",
    "status": "Accepted 2026-10-07",
    "title": "Exit path",
    "trace": "SPEC-008 \u00a75",
    "verification": "Test: `thr/exit_releases_mutex`, `thr/exit_wakes_joiner`; trace check of the event order."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-018",
    "links": [],
    "rationale": "One-slot join is O(1) and unambiguous.",
    "statement": "Exactly one thread may join a given thread (`EMB_EBUSY` for a second); the exit code shall be delivered by hand-off; joining oneself shall be `EMB_EDEADLK`, joining a detached thread `EMB_EINVAL`, joining a restarted thread's old generation `EMB_ESTALE`; join of a `TERMINATED` thread shall return at once.",
    "status": "Accepted 2026-10-07",
    "title": "Single joiner, exit-code hand-off",
    "trace": "SPEC-008 \u00a76",
    "verification": "Test: `thr/join_*`; model scenarios `join_before_exit`, `join_after_exit`, `join_timeout`, `join_second_ebusy`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-019",
    "links": [],
    "rationale": "Lifetime control for fire-and-forget threads.",
    "statement": "`detach` shall make a joinable thread detached, shall make an already terminated thread reusable at once, and shall be refused with `EMB_EBUSY` while a joiner is blocked.",
    "status": "Accepted 2026-10-07",
    "title": "Detach",
    "trace": "SPEC-008 \u00a76",
    "verification": "Test: `thr/detach_*`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-020",
    "links": [],
    "rationale": "Counting suspends are a classic source of stuck threads.",
    "statement": "`suspend` and `resume` shall be idempotent, shall implement the overlay of SPEC-004 \u00a76.5, and shall be refused with `EMB_EPERM` on kernel threads.",
    "status": "Accepted 2026-10-07",
    "title": "Suspend and resume are idempotent and overlaid",
    "trace": "SPEC-008 \u00a77, \u00a711",
    "verification": "Test: `thr/suspend_twice_resume_once`, `misuse/suspend_idle`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-021",
    "links": [],
    "rationale": "Threads need regions where cancellation cannot interrupt a protocol.",
    "statement": "A cancel request shall wake a blocked cancelable wait at once when cancellation is enabled, otherwise be delivered at the next cancellation point; delivery shall clear the request; a per-thread disable count (bounded at 255) shall defer delivery while nonzero; `cancel_point()` shall be a cancellation point.",
    "status": "Accepted 2026-10-07",
    "title": "Cancellation delivery and disable count",
    "trace": "SPEC-008 \u00a77",
    "verification": "Test: `thr/cancel_disabled_deferred`, `thr/cancel_point`; model scenarios `cancel_*`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-022",
    "links": [],
    "rationale": "v0.1 \u00a73.5; consistency with the interrupt numbering of SPEC-002 \u00a78.",
    "statement": "Larger numeric values shall mean higher priority; `0` shall be the idle level and not assignable to application threads; application priorities shall be `1 .. CONFIG_EMB_PRIORITY_COUNT - 1`; `get_priority` shall return the base and `get_effective_priority` the effective priority.",
    "status": "Accepted 2026-10-07",
    "title": "Priority range and direction",
    "trace": "SPEC-008 \u00a71, \u00a73; SPEC-005 \u00a72.3",
    "verification": "Test: `misuse/thread_priority_zero`; Analysis: KRN-SCH-036 range."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-023",
    "links": [],
    "rationale": "KRN-MEM-009, 010, 011 applied to threads.",
    "statement": "Thread stacks shall be caller-provided, aligned to `EMB_STACK_ALIGN`, at least `EMB_THREAD_STACK_MIN` for the architecture; `EMB_THREAD_STACK` shall declare one; checked and statistics builds shall fill stacks at init and report the high-water mark; overflow shall be checked at every switch-out when `CONFIG_EMB_STACK_CHECK` is set and by hardware limits or MPU guards where available.",
    "status": "Accepted 2026-10-07",
    "title": "Stacks",
    "trace": "SPEC-008 \u00a710; KRN-MEM-009 to 011",
    "verification": "Test: `thr/stack_high_water`, `thr/stack_overflow_detected` (fault injection)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-024",
    "links": [],
    "rationale": "KRN-OBJ-001 to 003 for threads.",
    "statement": "`destroy` shall require `INACTIVE`, or `TERMINATED` and reusable; it shall remove the thread from the all-threads list and bump the handle generation; anything else shall be misuse.",
    "status": "Accepted 2026-10-07",
    "title": "Destroy",
    "trace": "SPEC-008 \u00a78",
    "verification": "Test: `misuse/thread_destroy_running`, `thr/destroy_after_join`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-025",
    "links": [],
    "rationale": "Tooling and statistics.",
    "statement": "The kernel shall report a thread's state and wait reason, name, stable index, base and effective priority, and (optionally) stack usage, and shall offer `emb_thread_foreach` when `CONFIG_EMB_THREAD_LIST` is set.",
    "status": "Accepted 2026-10-07",
    "title": "Introspection",
    "trace": "SPEC-008 \u00a73, \u00a713",
    "verification": "Test: `thr/state_queries`; debug descriptor consumer test."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-026",
    "links": [],
    "rationale": "The kernel's own progress must not depend on application calls.",
    "statement": "The idle thread and work queue threads shall be kernel threads: not suspendable, cancelable, joinable, or re-prioritizable by the application (`EMB_EPERM`), invisible to `foreach` unless asked for.",
    "status": "Accepted 2026-10-07",
    "title": "Kernel threads",
    "trace": "SPEC-008 \u00a711",
    "verification": "Test: `misuse/kernel_thread_ops`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-027",
    "links": [
      "KRN-CAP-002",
      "KRN-PART-001"
    ],
    "rationale": "KRN-PART-001, ADR-033, SPEC-009.",
    "statement": "A thread shall belong to one partition; an unprivileged partition shall create threads only in itself, from storage in its own region, before freeze; cross-partition thread operations shall require the corresponding right on a thread capability.",
    "status": "Accepted 2026-10-07",
    "title": "Isolated profile rules",
    "trace": "SPEC-008 \u00a74; KRN-PART-001, 007; KRN-CAP-002",
    "verification": "Isolated-profile tests `part/thread_create_*`, `part/thread_op_without_right`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-028",
    "links": [],
    "rationale": "04 \u00a77.5.",
    "statement": "Init, start, exit with code, join, suspend, resume, cancel, priority change, and destroy shall be trace events; CPU time, switch count, blocked time, and stack high-water shall be optional per-thread statistics.",
    "status": "Accepted 2026-10-07",
    "title": "Trace and statistics",
    "trace": "SPEC-008 \u00a713",
    "verification": "Test: trace decoder; statistics API test."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-029",
    "links": [],
    "rationale": "ADR-036; targets T1 and T2.",
    "statement": "With the table scheduler a thread's slot shall be its unique priority, up to 16 threads including idle; `start`, `suspend`, `resume`, and `join` shall be bit operations; TLS and stack statistics shall default off; destroy shall be allowed only before freeze.",
    "status": "Accepted 2026-10-07",
    "title": "Tiny profile",
    "trace": "SPEC-008 \u00a714",
    "verification": "Footprint test of the tiny reference configuration; `thr/` conformance group on it."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-THR.md",
    "evidence": "not evaluated",
    "group": "KRN-THR",
    "id": "KRN-THR-030",
    "links": [
      "KRN-WAIT-007"
    ],
    "rationale": "Lifecycle races are protocol races.",
    "statement": "The reference model shall include start of inactive threads, join with exit-code hand-off and the one-joiner rule, explicit exit codes, and shall be explored over join before and after exit, join with timeout, cancellation of a joiner, start by another thread, and exit while owning a mutex.",
    "status": "Accepted 2026-10-07",
    "title": "Model coverage",
    "trace": "SPEC-008 \u00a715; KRN-WAIT-007",
    "verification": "Analysis: `tools/model/tests` scenarios `JOIN`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-001",
    "links": [],
    "rationale": "A clock that moves backward makes deadlines meaningless.",
    "statement": "Kernel time used for scheduling and timeouts shall be monotonic.",
    "status": "Accepted (v0.1)",
    "title": "Monotonic kernel time",
    "trace": "v0.1 \u00a77.5; SPEC-003 \u00a73",
    "verification": "Test: `emb_time_now()` never decreases across tick, tickless wake, and wall-clock adjustment tests."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-002",
    "links": [],
    "rationale": "Calendar time is adjusted, stepped, and synchronized; deadlines must not move with it.",
    "statement": "Timeout correctness shall not depend on wall-clock time.",
    "status": "Accepted (v0.1)",
    "title": "Independence from wall-clock time",
    "trace": "v0.1 \u00a77.5; SPEC-003 \u00a72, \u00a710",
    "verification": "Test: pending timeouts are unaffected by `emb_wallclock_set` and `emb_wallclock_adjust`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-003",
    "links": [],
    "rationale": "24-bit, 32-bit, and 16-bit hardware counters wrap within seconds to days.",
    "statement": "Finite timeout handling shall remain correct across underlying counter wraparound.",
    "status": "Accepted (v0.1)",
    "title": "Correct across counter wraparound",
    "trace": "v0.1 \u00a77.5; SPEC-003 \u00a75.2",
    "verification": "Test: `tests/api/time/` and the timeout conformance tests run with the clock pre-set near every wrap boundary in both tick profiles."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-004",
    "links": [],
    "rationale": "Power and deadline precision (ADR-017, 04 \u00a74).",
    "statement": "The kernel shall permit tickless operation.",
    "status": "Accepted (v0.1)",
    "title": "Tickless operation permitted",
    "trace": "v0.1 \u00a77.5; SPEC-003 \u00a74.2",
    "verification": "Test: the conformance suite passes in tickless mode on native and on a Cortex-M emulated target."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-005",
    "links": [],
    "rationale": "Callback context confusion is a leading cause of RTOS bugs.",
    "statement": "One-shot and periodic software timers shall have defined callback-context semantics.",
    "status": "Accepted (v0.1)",
    "title": "Defined callback-context semantics",
    "trace": "v0.1 \u00a77.5; SPEC-003 \u00a77.3",
    "verification": "Test: callback context observed with `emb_context()` for default and `ISR_CONTEXT` timers."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-006",
    "links": [],
    "rationale": "Timer start and stop are called from ISRs and critical paths.",
    "statement": "Timer operations on real-time paths shall have bounded behavior for a defined configuration.",
    "status": "Accepted (v0.1)",
    "title": "Bounded timer operations",
    "trace": "v0.1 \u00a77.5; SPEC-003 \u00a75.1, \u00a77.2",
    "verification": "Analysis: `@time` annotations; Demonstration: benchmark of start and stop with N armed timers."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-007",
    "links": [],
    "rationale": "Unit bugs are silent until a field failure.",
    "statement": "Time conversion and tick-rate behavior shall be explicitly documented to avoid silent truncation or overflow.",
    "status": "Accepted (v0.1)",
    "title": "Documented conversions",
    "trace": "v0.1 \u00a77.5; SPEC-001 \u00a77.3; SPEC-003 \u00a711",
    "verification": "Inspection: SPEC-001 \u00a77.3 and each port's time section; Test: conversion vectors (API-023)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-008",
    "links": [],
    "rationale": "64 bits remove wrap handling where the core can afford it; 32 bits keep the ATmega328P affordable (ADR-017).",
    "statement": "Kernel monotonic time shall be a 64-bit tick count in the base and larger profiles; the tiny profile may select a 32-bit count with wrap-safe comparison.",
    "status": "Accepted (03 \u00a74.1)",
    "title": "Clock width",
    "trace": "03 \u00a74.1; SPEC-003 \u00a73",
    "verification": "Test: both profiles in the time test matrix."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-009",
    "links": [],
    "rationale": "The API unit must not change with the clock mode, or application code is not portable between them.",
    "statement": "The tick unit shall be the configuration constant `CONFIG_EMB_TICK_NS`; in tickless mode the achievable resolution is bounded by the hardware timer period, and the unit of the API stays the configured one.",
    "status": "Accepted (03 \u00a74.1, refined 2026-10-07)",
    "title": "Tick unit",
    "trace": "03 \u00a74.1; SPEC-003 \u00a73, \u00a74.2",
    "verification": "Test: identical conversion results in periodic and tickless modes."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-010",
    "links": [],
    "rationale": "See API-022.",
    "statement": "Public time types shall be distinct: `emb_instant_t` (absolute), `emb_duration_t` (relative), `emb_timeout_t` (relative or sentinel). Mixing them shall be a compile error where the language allows.",
    "status": "Accepted (03 \u00a74.1)",
    "title": "Distinct time types",
    "trace": "03 \u00a74.1; SPEC-001 \u00a77.1",
    "verification": "Test: negative compile tests (API-022)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-011",
    "links": [],
    "rationale": "See API-002.",
    "statement": "Absolute-deadline variants shall exist for sleep and for every blocking operation, so that periodic work does not accumulate drift.",
    "status": "Accepted (03 \u00a74.1)",
    "title": "Absolute-deadline variants",
    "trace": "03 \u00a74.1; SPEC-003 \u00a76",
    "verification": "Analysis: API-002 check; Test: a periodic loop with `sleep_until` shows zero accumulated drift over 10 000 periods on the native port."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-012",
    "links": [],
    "rationale": "Cycle counters wrap fast and may stop in sleep; they measure, they do not schedule.",
    "statement": "A high-resolution cycle counter API shall exist for measurement where hardware provides one; it shall not be the scheduling clock.",
    "status": "Accepted (03 \u00a74.1)",
    "title": "Cycle counter is not the scheduling clock",
    "trace": "03 \u00a74.1; SPEC-003 \u00a79",
    "verification": "Analysis: no kernel timeout path reads `emb_cycles_now`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-013",
    "links": [],
    "rationale": "Interrupt-context callbacks are dangerous for general code (ADR-019).",
    "statement": "Software timer callbacks shall execute by default on a work queue in thread context.",
    "status": "Accepted (03 \u00a74.3)",
    "title": "Callbacks on a work queue by default",
    "trace": "03 \u00a74.3; SPEC-003 \u00a77.3",
    "verification": "Test: default timer callback observes `EMB_CONTEXT_THREAD` and runs on the configured queue's thread."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-014",
    "links": [],
    "rationale": "A few callbacks need interrupt-level latency; the rest must not pay for it or risk it.",
    "statement": "A timer may be created with `ISR_CONTEXT` only when its callback is declared ISR-safe; such callbacks shall be bounded and shall not block.",
    "status": "Accepted (03 \u00a74.3)",
    "title": "ISR-context callbacks are opt-in and bounded",
    "trace": "03 \u00a74.3; SPEC-003 \u00a77.3",
    "verification": "Test: a blocking call from an `ISR_CONTEXT` callback faults in checked builds."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-015",
    "links": [],
    "rationale": "Re-arming from completion accumulates callback latency into the period.",
    "statement": "One-shot and periodic timers shall be supported; a periodic timer's next expiry shall be computed from the previous expiry, not from callback completion.",
    "status": "Accepted (03 \u00a74.3)",
    "title": "Periodic re-arm without drift",
    "trace": "03 \u00a74.3; SPEC-003 \u00a77.4",
    "verification": "Test: a periodic timer's expiry instants are exact multiples of the period from the first expiry over 10 000 periods on native."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-016",
    "links": [],
    "rationale": "32-bit targets do not provide them under EmbCC (09 \u00a76).",
    "statement": "64-bit time values shall be read and written under a critical section or a sequence lock; the kernel shall not depend on 64-bit atomic loads, stores, or read-modify-write operations.",
    "status": "Accepted (03 \u00a74.1)",
    "title": "No 64-bit atomics for time",
    "trace": "03 \u00a74.1; SPEC-003 \u00a73.1",
    "verification": "Analysis: no `_Atomic` 64-bit object in `kernel/`; Test: clock read torture test under continuous timer updates."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-017",
    "links": [],
    "rationale": "A mode that changes behavior is a fork in disguise.",
    "statement": "The kernel shall support a periodic-tick mode and a tickless mode selected at configuration time. Every time, timeout, sleep, and timer requirement shall hold identically in both modes, and the conformance suite shall run in both.",
    "status": "Accepted 2026-10-07",
    "title": "Two clock modes, one semantics",
    "trace": "SPEC-003 \u00a74",
    "verification": "Test: conformance suite in both modes on native and on an emulated Cortex-M."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-018",
    "links": [],
    "rationale": "Missing an input means a late wake; an expensive computation means it cannot run on every change.",
    "statement": "In tickless mode the kernel shall program the timer source for the earliest of: the earliest armed timeout, the earliest software timer, the running thread's quantum expiry when time slicing applies, the next budget replenishment when temporal protection is enabled, and `now` plus the port's maximum interval. The computation shall be O(1) given the ordered timeout structure.",
    "status": "Accepted 2026-10-07",
    "title": "Next-deadline computation",
    "trace": "SPEC-003 \u00a74.2",
    "verification": "Test: each input is the earliest in turn and the observed wake matches; Analysis: no loop over all timers in the reprogram path."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-019",
    "links": [],
    "rationale": "A wake from a non-timer interrupt must still see correct time and wake threads whose timeouts have passed.",
    "statement": "In tickless mode, on any interrupt that ends idle, the kernel shall update the clock from the hardware counter and process expired deadlines before any scheduling decision is made.",
    "status": "Accepted 2026-10-07",
    "title": "Clock update on wake",
    "trace": "SPEC-003 \u00a74.2, \u00a74.3",
    "verification": "Test: a GPIO-class interrupt wakes the idle core after a timeout deadline has passed; the timed-out thread runs before the interrupt's own woken thread when its priority is higher."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-020",
    "links": [],
    "rationale": "One contract for every timer source keeps the kernel's time code portable (KRN-IRQ-015 for timers).",
    "statement": "Each port shall implement `emb_arch_timer_init`, `emb_arch_timer_now_raw`, `emb_arch_timer_set_deadline_raw`, `emb_arch_timer_cancel`, `emb_arch_timer_hz`, and `emb_arch_timer_max_ticks`, and its timer ISR shall call `embk_time_timer_isr`; tickless ports shall call `embk_time_on_wake` at the outermost exit of any interrupt that ended idle. Raw-to-tick conversion shall be exact when the periods divide, and otherwise documented with a bounded, non-accumulating error.",
    "status": "Accepted 2026-10-07",
    "title": "Architecture timer contract",
    "trace": "SPEC-003 \u00a74.3",
    "verification": "Test: port conformance for the timer contract on each architecture; Analysis: configuration-time divisibility check."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-021",
    "links": [],
    "rationale": "ADR-010; intrusive nodes satisfy KRN-TCB-007 and KRN-RQ-004.",
    "statement": "Armed timeouts and timers shall be kept in an intrusive structure with O(1) removal on the base profile (bounded O(armed nodes) removal on the tiny singly linked profile), O(1) access to the earliest deadline, and expiry in deadline order with arming order as the tie-break. The default shall be a doubly linked list ordered by absolute deadline; an alternative structure may be selected per profile behind the same interface only on the basis of measurements.",
    "status": "Accepted 2026-10-07",
    "title": "Timeout structure",
    "trace": "SPEC-003 \u00a75.1; ADR-010",
    "verification": "Test: ordering and tie-break tests; Demonstration: insertion cost measured versus armed count per reference board."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-022",
    "links": [],
    "rationale": "This is the condition under which wrap-safe comparison is correct (KRN-TIM-003).",
    "statement": "In the 32-bit tick profile, a finite timeout shall be clamped to `2^31 - 1` ticks ; absolute deadlines supplied by callers shall remain within the half-range because an out-of-range future value aliases a past instant and cannot be rejected as overflow; deadline comparisons shall use signed wrap-safe differences.",
    "status": "Accepted 2026-10-07",
    "title": "32-bit profile timeout range",
    "trace": "SPEC-003 \u00a75.2",
    "verification": "Test: boundary tests at `2^31 - 1` and `2^31` in the 32-bit profile."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-023",
    "links": [
      "API-024"
    ],
    "rationale": "API-024 at the kernel boundary.",
    "statement": "Arming with a duration shall compute the deadline as `now + duration` saturating at `EMB_TICK_MAX`, where a saturated deadline is forever; a deadline at or before `now` shall take the `EMB_NO_WAIT` path.",
    "status": "Accepted 2026-10-07",
    "title": "Deadline computation",
    "trace": "SPEC-003 \u00a75.2; API-024",
    "verification": "Test: saturation and past-deadline cases for every blocking primitive."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-024",
    "links": [
      "KRN-THR-009"
    ],
    "rationale": "Sleep is a wait with no object; zero sleep as yield is the common expectation and gives equal-priority threads a turn.",
    "statement": "`emb_thread_sleep` and `emb_thread_sleep_until` shall block the caller with wait reason `SLEEP` until the deadline, returning `EMB_OK` on expiry or `EMB_ECANCELED` if canceled. A zero duration or a past deadline shall behave exactly as `emb_thread_yield`.",
    "status": "Accepted 2026-10-07",
    "title": "Sleep semantics",
    "trace": "SPEC-003 \u00a76; KRN-THR-009; KRN-SCH-008",
    "verification": "Test: conformance tests for sleep, sleep_until, zero sleep ordering among equal-priority threads, and cancellation."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-025",
    "links": [],
    "rationale": "Timers are driven from ISRs as often as from threads; teardown needs a synchronous stop.",
    "statement": "The kernel shall provide `emb_timer_init`, `emb_timer_destroy`, `emb_timer_start`, `emb_timer_start_at`, `emb_timer_start_periodic`, `emb_timer_stop`, `emb_timer_stop_sync`, `emb_timer_restart`, `emb_timer_is_running`, `emb_timer_remaining`, and `emb_timer_get_counts` with the context classes and bounds of SPEC-003 \u00a77.2. Start, stop, restart, and the queries shall be ISR-safe; `stop_sync` shall be thread-only and blocking with a timeout.",
    "status": "Accepted 2026-10-07",
    "title": "Software timer API",
    "trace": "SPEC-003 \u00a77.2",
    "verification": "Test: API conformance including each function from ISR context where allowed."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-026",
    "links": [],
    "rationale": "KRN-TIM-013 and 014 at the mechanism level; the expiry path must stay bounded regardless of callback behavior.",
    "statement": "At expiry, a work-queue timer shall submit its embedded work item to its configured queue in O(1) without calling application code; an `ISR_CONTEXT` timer shall call its callback directly in the expiry path. Expiry shall never run a work-queue callback in interrupt context.",
    "status": "Accepted 2026-10-07",
    "title": "Expiry processing",
    "trace": "SPEC-003 \u00a77.3, \u00a77.4",
    "verification": "Test: callback context tests; Analysis: expiry path `@time` and stack usage."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-027",
    "links": [],
    "rationale": "No drift (KRN-TIM-015), no unbounded backlog, and visibility when the system cannot keep up.",
    "statement": "A periodic timer shall be re-armed from its previous deadline before its callback is run; whole periods already past at expiry shall be skipped and counted as overruns; an expiry whose work item is still queued from the previous expiry shall coalesce and count as an overrun. Expiry and overrun counts shall be readable and a trace point shall record each overrun.",
    "status": "Accepted 2026-10-07",
    "title": "Periodic re-arm and overrun accounting",
    "trace": "SPEC-003 \u00a77.4",
    "verification": "Test: overload and sleep-past-several-periods scenarios on native; counts and trace match the model."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-028",
    "links": [
      "KRN-OBJ-001"
    ],
    "rationale": "Use-after-destroy in a work queue is otherwise undetectable.",
    "statement": "Destroying a timer whose callback is pending or running shall be misuse: a kernel fault in checked builds and `EMB_EBUSY` in release builds. `emb_timer_stop` shall report whether the callback was idle, pending, or running; `emb_timer_stop_sync` from the timer's own callback shall be misuse.",
    "status": "Accepted 2026-10-07",
    "title": "Timer lifecycle",
    "trace": "SPEC-003 \u00a77.5; KRN-OBJ-001",
    "verification": "Test: misuse suite for timers in both build kinds."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-029",
    "links": [],
    "rationale": "Round-robin without a timer object per thread, and v0.1 \u00a75.8's rule that an uncontested quantum does not rotate.",
    "statement": "When time slicing is enabled for the running thread's priority level, the kernel shall track its quantum expiry as a per-CPU deadline included in the next-deadline computation, and at expiry shall move the thread to the tail of its class only if another READY thread exists at the same effective priority.",
    "status": "Accepted 2026-10-07",
    "title": "Time slicing quantum as a deadline",
    "trace": "SPEC-003 \u00a78; KRN-SCH-007, KRN-SCH-026, KRN-SCH-037",
    "verification": "Test: round-robin ordering tests in both clock modes; uncontested quantum does not cause a switch."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-030",
    "links": [],
    "rationale": "Benchmarks and critical-section statistics need a cheap fine-grained counter (KRN-RT-004 to 006).",
    "statement": "The kernel shall provide `emb_cycles_now`, `emb_cycles_hz`, and `emb_cycles_to_ns`, O(1) and callable from any context, with a resolution of at least 1 MHz where the hardware allows, sourced per architecture as documented.",
    "status": "Accepted 2026-10-07",
    "title": "Cycle counter API",
    "trace": "SPEC-003 \u00a79",
    "verification": "Test: monotonic within a non-sleeping interval; frequency matches the documented source within tolerance on HIL."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-031",
    "links": [],
    "rationale": "KRN-TIM-002 made concrete.",
    "statement": "When `CONFIG_EMB_WALLCLOCK` is enabled, wall-clock time shall be the kernel monotonic clock plus an offset; setting or adjusting it shall change the offset only and shall not move any timeout, timer, or deadline. No kernel path shall read the wall clock.",
    "status": "Accepted 2026-10-07",
    "title": "Wall clock is an offset",
    "trace": "SPEC-003 \u00a710",
    "verification": "Test: pending deadlines unchanged across set and adjust; Analysis: no reference to wall-clock symbols from `kernel/` time paths."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-032",
    "links": [
      "KRN-TIM-016"
    ],
    "rationale": "Refines KRN-TIM-016 into the two concrete mechanisms EmbCC's atomic support allows (09 \u00a76).",
    "statement": "`emb_time_now` shall read a multi-word clock with a sequence lock on architectures whose word is at least 32 bits, and with a critical section on AVR; it shall be O(1), callable from any context, and shall never mask interrupts on the sequence-lock architectures.",
    "status": "Accepted 2026-10-07",
    "title": "Clock read mechanism",
    "trace": "SPEC-003 \u00a73.1; KRN-TIM-016",
    "verification": "Test: clock read torture test under continuous timer updates on each architecture; Analysis: no masking instruction in the sequence-lock read path."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-033",
    "links": [
      "KRN-IRQ-031"
    ],
    "rationale": "KRN-IRQ-031 at the time subsystem's side.",
    "statement": "The timer interrupt body shall be bounded to updating the clock, expiring due deadlines, charging the quantum, setting the reschedule flag, and reprogramming the next deadline, and shall emit the trace points `tick`, `timeout_expire`, and `timer_expire` when tracing is enabled.",
    "status": "Accepted 2026-10-07",
    "title": "Bounded timer interrupt",
    "trace": "SPEC-003 \u00a74.1, \u00a75.3; KRN-IRQ-031",
    "verification": "Analysis: handler stack usage and cycle budget; Demonstration: timer jitter benchmark."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-034",
    "links": [],
    "rationale": "Tickless and power decisions depend on facts only the port knows.",
    "statement": "Each architecture port's documentation shall state its timer source, counter width, frequency and the exact tick values it supports, maximum interval, tickless capability and the sleep states in which the counter runs, wake latency from each state, and cycle counter source.",
    "status": "Accepted 2026-10-07",
    "title": "Port time documentation",
    "trace": "SPEC-003 \u00a711, \u00a713",
    "verification": "Inspection: `docs/ports/<arch>.md` time section against this list."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-TIM.md",
    "evidence": "not evaluated",
    "group": "KRN-TIM",
    "id": "KRN-TIM-035",
    "links": [
      "API-015"
    ],
    "rationale": "These are the time-related misuses that corrupt state silently in release builds.",
    "statement": "Checked builds shall detect and raise a kernel fault for arming an already armed timeout node, a blocking call from an `ISR_CONTEXT` timer callback, destroying a timer with a pending or running callback, and `emb_timer_stop_sync` from the timer's own callback; a `_until` deadline out of the 32-bit profile's range shall return `EMB_EOVERFLOW` in both build kinds.",
    "status": "Accepted 2026-10-07",
    "title": "Checked-build detection for time",
    "trace": "SPEC-003 \u00a712; API-015",
    "verification": "Test: `tests/conformance/misuse/time/` on the native port in both build kinds."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-001",
    "links": [],
    "rationale": "Priority order is what every real-time analysis assumes; FIFO among equals gives bounded waiting. ThreadX's FIFO default is a documented source of unexpected inversion (R-001 \u00a74.1).",
    "statement": "Default wake order shall be highest effective priority first, FIFO among equal priority.",
    "status": "Accepted 2026-10-07",
    "title": "Default wake order",
    "trace": "SPEC-004 \u00a73; 03 \u00a73.3; R-001 \u00a74.1",
    "verification": "Test: conformance `wait/order_priority_fifo` blocks threads of mixed priorities in several arrival orders and checks wake order against the reference model."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-002",
    "links": [],
    "rationale": "Barriers and some streams need arrival order.",
    "statement": "Objects may be created with pure FIFO wake order where the application requires fairness over priority.",
    "status": "Accepted 2026-10-07",
    "title": "FIFO option",
    "trace": "SPEC-004 \u00a73; 03 \u00a73.3",
    "verification": "Test: conformance `wait/order_fifo`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-003",
    "links": [
      "KRN-SYNC-009"
    ],
    "rationale": "Inheritance and explicit priority changes are meaningless if the queue keeps the old order.",
    "statement": "A waiter whose effective priority changes while blocked shall be repositioned in a PRIORITY_FIFO wait queue.",
    "status": "Accepted 2026-10-07",
    "title": "Repositioning on priority change",
    "trace": "SPEC-004 \u00a76.4; 03 \u00a73.3; KRN-SYNC-009",
    "verification": "Test: conformance `wait/requeue_on_priority_change` raises and lowers a blocked thread's priority and checks `expected_order`; model property \"queue order maintained\"."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-004",
    "links": [],
    "rationale": "Two sources acting on one wait corrupt queues and deliver two results.",
    "statement": "Exactly one wake source shall win for a given blocked thread; the losers shall observe that the thread is no longer waiting and shall not modify it.",
    "status": "Accepted 2026-10-07",
    "title": "Exactly one winner",
    "trace": "SPEC-004 \u00a75; 03 \u00a73.4; ADR-026",
    "verification": "Analysis: exhaustive exploration of the reference model (SPEC-004 \u00a713) proves it for the bounded configuration. Test: conformance `wait/race_signal_timeout` and `wait/race_cancel_signal` with the deadline interrupt forced into the window on the native port."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-005",
    "links": [],
    "rationale": "A woken thread may run on another CPU or at the next instruction; it must find its result.",
    "statement": "The winning wake source shall set the wake result and the hand-off word before making the thread READY.",
    "status": "Accepted 2026-10-07",
    "title": "Result before READY",
    "trace": "SPEC-004 \u00a75.2; 03 \u00a73.4",
    "verification": "Analysis: model property; review of `embk_wait_wake`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-006",
    "links": [],
    "rationale": "A node left in one structure after being removed from the other produces a stale wake.",
    "statement": "Removal from the wait queue and from the timeout structure shall be atomic with respect to each other, as seen by any other wake source.",
    "status": "Accepted 2026-10-07",
    "title": "Atomic removal from queue and timeout structure",
    "trace": "SPEC-004 \u00a75.2, \u00a75.3, \u00a78; 03 \u00a73.4",
    "verification": "Analysis: model property \"no timeout acts after its generation changed\"; Test: `wait/race_signal_timeout`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-007",
    "links": [],
    "rationale": "Race rules cannot be reviewed by reading; they are checked by exploring every interleaving.",
    "statement": "The protocol shall be expressed in the executable reference model and verified by randomized and, where practical, exhaustive state exploration before implementation.",
    "status": "Accepted 2026-10-07",
    "title": "Modeled and explored before implementation",
    "trace": "SPEC-004 \u00a713; 03 \u00a73.4; ADR-013; 05 \u00a74",
    "verification": "Analysis: the model and its exploration log are committed before the first kernel source file of M2; CI runs the exhaustive exploration on every change to the model."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-008",
    "links": [],
    "rationale": "This is what bounds the kernel's longest masked section by one list operation instead of by the whole block path (R-001 \u00a74.2; R-003 target T7).",
    "statement": "The wait state shall be a three-state flag (READY, INTEND_TO_BLOCK, BLOCKED) changed by compare-and-set on cores that provide it and by a bounded critical section otherwise; no lock or masked section shall be held from the decision to block until the switch.",
    "status": "Accepted 2026-10-07",
    "title": "Three-state wait flag, no lock across the block window",
    "trace": "SPEC-004 \u00a75.1, \u00a75.4; ADR-026",
    "verification": "Analysis: model invariant 6 of SPEC-004 \u00a75.4. Test: the critical-section monitor (ADR-034) on the conformance run reports every masked section of the wait path within the T7 budget."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-009",
    "links": [
      "KRN-TIM-026"
    ],
    "rationale": "Generations make late wake sources harmless without holding locks across them; the superseded bit closes the SMP window between popping a node and acting on it.",
    "statement": "Every wait shall carry a generation; a timeout, cancel, or destroy that observes a different generation shall do nothing. On SMP a timeout whose handler is running on another CPU shall be marked superseded and its cancellation retried.",
    "status": "Accepted 2026-10-07",
    "title": "Wait generation and superseded timeouts",
    "trace": "SPEC-004 \u00a75.3, \u00a78; ADR-026; KRN-TIM-026",
    "verification": "Analysis: model property \"no timeout acts after its generation changed\"; the SMP model exercises the superseded path. Test: `wait/stale_timeout_counted` checks the statistics counter."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-010",
    "links": [],
    "rationale": "Static memory, O(1) wake, and a single place for a debugger to look.",
    "statement": "A thread shall wait on at most one object at a time; its wait node and its timeout node shall be embedded in its thread control block, and the kernel shall allocate nothing to block a thread.",
    "status": "Accepted 2026-10-07",
    "title": "One wait at a time, node in the thread control block",
    "trace": "SPEC-004 \u00a72.1; KRN-MEM",
    "verification": "Analysis: structure review; the debug descriptor exports the node offsets. Test: footprint test shows no allocation on the wait path."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-011",
    "links": [],
    "rationale": "Makes the T7 masked-time bound a structural property rather than a measurement.",
    "statement": "A blocking operation shall consist of at most three lock-domain sections (condition check and enqueue; timeout arm; commit and switch), with the lock domain released between phases; each phase shall state its complete configured bound including list operations, wake hooks, inheritance propagation, and scheduler scans.",
    "status": "Accepted 2026-10-07",
    "title": "Three bounded sections",
    "trace": "SPEC-004 \u00a75.1; R-003 \u00a74 T7",
    "verification": "Analysis: review of `embk_block_on`, `embk_wait_prepare`, `embk_wait_commit`. Test: monitor of ADR-034 on the conformance run."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-012",
    "links": [],
    "rationale": "Prevents barging, gives wait-order fairness, and removes the retry loops that other kernels need (R-001 \u00a74.2, FreeRTOS \"loop back to the top\").",
    "statement": "A wake source that satisfies a wait shall deliver the satisfaction (ownership, unit, message, bits, exit code) with the result in one step, and the woken thread shall not re-check the object's condition.",
    "status": "Accepted 2026-10-07",
    "title": "Hand-off with the result",
    "trace": "SPEC-004 \u00a76.1; SPEC-005; SPEC-007",
    "verification": "Test: conformance `wait/no_barging` has a higher-priority thread attempt the operation between the give and the waiter's run and checks the waiter still gets the unit."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-013",
    "links": [],
    "rationale": "Deterministic order and no switch storm.",
    "statement": "Waking all waiters of a queue shall deliver results in queue order, make every thread ready, and request one reschedule at the end.",
    "status": "Accepted 2026-10-07",
    "title": "Wake-all order and single reschedule",
    "trace": "SPEC-004 \u00a76.7, \u00a77",
    "verification": "Test: `wait/wake_all_order` with a trace check of a single switch after the operation."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-014",
    "links": [
      "KRN-THR-010"
    ],
    "rationale": "Defines the classic \"suspend while waiting\" ambiguity once, from the protocol's side (KRN-THR-010).",
    "statement": "Suspending a blocked thread shall leave its wait-queue position and its deadline untouched; a wake that arrives while suspended shall complete the wait and take effect when the thread is resumed.",
    "status": "Accepted 2026-10-07",
    "title": "Suspend is an overlay",
    "trace": "SPEC-004 \u00a76.5; 03 \u00a71.1; KRN-THR-010",
    "verification": "Test: `wait/suspend_while_waiting` in three variants (wake, timeout, resume first); model property \"a suspended thread keeps its queue position and deadline\"."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-015",
    "links": [
      "KRN-THR-011"
    ],
    "rationale": "One mechanism for cooperative cancellation (KRN-THR-011); no \"wait abort\" API with ambiguous ownership.",
    "statement": "A thread cancellation request shall wake a thread blocked with reason SLEEP, OBJECT, JOIN, or NOTIFY with result CANCELED; a thread blocked with reason START or SUSPEND, or not blocked, shall receive the request at its next blocking call, which returns CANCELED before enqueuing. There shall be no other way for one thread to end another's wait.",
    "status": "Accepted 2026-10-07",
    "title": "Cancellation as a wake source",
    "trace": "SPEC-004 \u00a76.6; KRN-THR-011",
    "verification": "Test: `wait/cancel_blocked`, `wait/cancel_pending_delivered`, `wait/cancel_start_not_woken`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-016",
    "links": [
      "KRN-OBJ-001"
    ],
    "rationale": "Restates KRN-OBJ-001, 002, and 005 from the protocol's side so that one flush primitive serves both.",
    "statement": "Destroying an object created with `ABORT_WAITERS` shall wake every waiter with DESTROYED in queue order and then bump the object's generation; a thread or partition restart shall wake waiters on its join queues and ports with STALE and bump the handle generation.",
    "status": "Accepted 2026-10-07",
    "title": "Flush on destroy and on stale peers",
    "trace": "SPEC-004 \u00a76.7; ADR-020; ADR-032; KRN-OBJ-001, 002, 005",
    "verification": "Test: `wait/destroy_abort_waiters`, `wait/destroy_refused_with_waiters`, `wait/stale_on_restart` (isolated profile)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-017",
    "links": [],
    "rationale": "A fixed order is the only deadlock-free discipline; the expiry rule is what makes the order hold for timeouts.",
    "statement": "Wait queues shall be protected by the lock domain of the object that embeds them. On SMP the order shall be object, then scheduler, then timeout, never reversed; the timeout expiry path shall call the wake with no lock held.",
    "status": "Accepted 2026-10-07",
    "title": "Lock domains and order",
    "trace": "SPEC-004 \u00a78; ADR-012; KRN-SMP",
    "verification": "Analysis: the spinlock validator (SMP checked builds) records lock order and faults on inversion; the SMP reference model encodes the order."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-018",
    "links": [
      "KRN-IRQ-024"
    ],
    "rationale": "Preemption latency on SMP must not depend on the woken CPU's next tick; the INTEND_TO_BLOCK rule keeps the common wake lock-free.",
    "statement": "A wake that readies a thread which should preempt the current thread of another CPU shall send that CPU the reschedule interrupt; a wake on a thread in INTEND_TO_BLOCK shall not touch any ready structure.",
    "status": "Accepted 2026-10-07",
    "title": "Cross-CPU wake",
    "trace": "SPEC-004 \u00a75.2, \u00a78; KRN-IRQ-024",
    "verification": "Test: SMP conformance `wait/cross_cpu_preempt` measures wake-to-run on the other CPU; model property on the SMP model."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-019",
    "links": [],
    "rationale": "Saves two pointers per thread and makes wake-highest O(1) on the smallest targets (ADR-036).",
    "statement": "With the table scheduler, a wait queue shall be one word with one bit per thread; prepare sets the bit, wake-first is the highest set bit, wake clears it; the state machine, generations, results, and the suspend overlay shall be identical to the list form.",
    "status": "Accepted 2026-10-07",
    "title": "Tiny profile bitmap wait sets",
    "trace": "SPEC-004 \u00a711; ADR-036; KRN-SCH-042",
    "verification": "Test: the whole `wait/` conformance group runs on the tiny reference configuration unchanged, within its documented restrictions (unique priorities, no FIFO policy)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-020",
    "links": [
      "OBS-005",
      "OBS-008"
    ],
    "rationale": "\"Blocked on what, behind whom, for how long\" is the first question in every scheduling investigation.",
    "statement": "The protocol shall emit trace events for wait begin, wait end with result and blocked duration, wake with source, and requeue; and, as an option, per-object contention count and maximum queue length, per-thread blocked time, and per-CPU stale-timeout count.",
    "status": "Accepted 2026-10-07",
    "title": "Trace and statistics",
    "trace": "SPEC-004 \u00a710; OBS-005, OBS-008",
    "verification": "Test: the trace decoder reconstructs every wait of the conformance run; OBS tests check compile-out."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-021",
    "links": [
      "KRN-IRQ-001"
    ],
    "rationale": "SPEC-001 \u00a75.3 rule applied to this protocol.",
    "statement": "Checked builds shall fault on: blocking with a nonzero timeout from an ISR, under the scheduler lock, or inside the caller's critical section; blocking while the wait state is not READY; a wake asserted on a thread that does not wait on the given queue; a queue order violation after insert; destroy with waiters without `ABORT_WAITERS`. Release builds shall return `EMB_EPERM` for context misuse, `EMB_EINVAL` for invalid arguments, false for a losing wake, or `EMB_EBUSY` for refused destruction, as SPEC-001 \u00a75 and SPEC-004 \u00a79 specify.",
    "status": "Accepted 2026-10-07",
    "title": "Checked-build diagnostics",
    "trace": "SPEC-004 \u00a79; SPEC-001 \u00a75.3; KRN-IRQ-001, 021, 035; ADR-035",
    "verification": "Test: `misuse/wait_*` in checked and release configurations (TEST-010)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WAIT.md",
    "evidence": "not evaluated",
    "group": "KRN-WAIT",
    "id": "KRN-WAIT-022",
    "links": [
      "KRN-WAIT-007"
    ],
    "rationale": "Fixes what \"explored\" means so that KRN-WAIT-007 is checkable.",
    "statement": "The reference model shall exhaustively explore all enabled section-granularity interleavings of each declared finite scenario within its recorded state budget, including scenarios of up to 3 threads, 2 objects, and one armed timeout per thread over the operations block, wake, expire, cancel, suspend, resume, flush, set-priority, interrupt entry and exit, scheduler lock and unlock, and yield; and by randomized stateful testing beyond those bounds with a committed seed corpus.",
    "status": "Accepted 2026-10-07",
    "title": "Exploration coverage",
    "trace": "SPEC-004 \u00a713; KRN-WAIT-007; TEST-008",
    "verification": "Analysis: the exploration tool reports the state count and the bounds reached; CI fails if the bounds are lowered."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WQ.md",
    "evidence": "not evaluated",
    "group": "KRN-WQ",
    "id": "KRN-WQ-001",
    "links": [],
    "rationale": "A bottom half is submitted from interrupts; it must cost one push and one bit set.",
    "statement": "Work items shall be intrusive and statically allocatable; submission shall be ISR-safe and O(1).",
    "status": "Accepted 2026-10-07",
    "title": "Intrusive, static, ISR-safe submit",
    "trace": "SPEC-006 \u00a74.3",
    "verification": "Test: `wq/submit_from_isr`; Analysis: no allocation and no list walk in `emb_work_submit`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WQ.md",
    "evidence": "not evaluated",
    "group": "KRN-WQ",
    "id": "KRN-WQ-002",
    "links": [],
    "rationale": "Deterministic order; handlers may use thread-only API.",
    "statement": "Work executes in FIFO order per queue in thread context.",
    "status": "Accepted 2026-10-07",
    "title": "FIFO per queue in thread context",
    "trace": "SPEC-006 \u00a74.3",
    "verification": "Test: `wq/fifo_order`, `wq/handler_may_block`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WQ.md",
    "evidence": "not evaluated",
    "group": "KRN-WQ",
    "id": "KRN-WQ-003",
    "links": [],
    "rationale": "One timeout structure (ADR-010); one set of accuracy rules.",
    "statement": "Delayed work shall be implemented over software timers, not a separate timing mechanism.",
    "status": "Accepted 2026-10-07",
    "title": "Delayed work over software timers",
    "trace": "SPEC-006 \u00a74.1, \u00a74.3; SPEC-003 \u00a77",
    "verification": "Analysis: `emb_dwork_t` embeds `emb_timer_storage_t`; no other timing code in `kernel/work/`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WQ.md",
    "evidence": "not evaluated",
    "group": "KRN-WQ",
    "id": "KRN-WQ-004",
    "links": [],
    "rationale": "The caller must know whether a handler may still run.",
    "statement": "Cancellation shall report whether the item was pending, running, or idle.",
    "status": "Accepted 2026-10-07",
    "title": "Cancellation reports the state",
    "trace": "SPEC-006 \u00a74.3",
    "verification": "Test: `wq/cancel_pending`, `wq/cancel_running`, `wq/cancel_idle`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WQ.md",
    "evidence": "not evaluated",
    "group": "KRN-WQ",
    "id": "KRN-WQ-005",
    "links": [],
    "rationale": "Idempotent submission without lost re-submissions and without handler re-entrancy (Zephyr's v2 rule, R-001 \u00a76).",
    "statement": "Submitting a queued item shall return `EMB_EEXIST` and change nothing; submitting an item running on the same queue shall return `EMB_OK` and re-append it after its handler returns; submitting an item running on another queue shall return `EMB_EBUSY`; an item shall never run concurrently with itself.",
    "status": "Accepted 2026-10-07",
    "title": "Submit outcomes",
    "trace": "SPEC-006 \u00a74.3, \u00a712.5",
    "verification": "Test: `wq/submit_queued_eexist`, `wq/resubmit_while_running_runs_again`, `wq/submit_other_queue_ebusy`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WQ.md",
    "evidence": "not evaluated",
    "group": "KRN-WQ",
    "id": "KRN-WQ-006",
    "links": [],
    "rationale": "Teardown needs a point after which no handler touches the caller's state.",
    "statement": "`cancel_sync` shall wait until a running handler has returned; `flush` shall return when every item queued before the call has run; calling either from the queue's own thread shall be misuse.",
    "status": "Accepted 2026-10-07",
    "title": "Synchronous cancel and flush",
    "trace": "SPEC-006 \u00a74.3, \u00a76",
    "verification": "Test: `wq/cancel_sync_waits`, `wq/flush`, `misuse/wq_flush_from_handler`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WQ.md",
    "evidence": "not evaluated",
    "group": "KRN-WQ",
    "id": "KRN-WQ-007",
    "links": [],
    "rationale": "One queue hop per delayed item; deterministic re-arm semantics.",
    "statement": "`dwork_schedule` on a pending item shall return `EMB_EEXIST` and change nothing; `reschedule` shall replace a pending delay; cancel shall stop an armed timer or remove a queued item and report `PENDING` for both; the timer's expiry shall submit the item in O(1) from the expiry path.",
    "status": "Accepted 2026-10-07",
    "title": "Delayed work scheduling",
    "trace": "SPEC-006 \u00a74.3, \u00a712.6, \u00a712.7",
    "verification": "Test: `wq/dwork_schedule_pending`, `wq/dwork_reschedule`, `wq/dwork_cancel_states`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WQ.md",
    "evidence": "not evaluated",
    "group": "KRN-WQ",
    "id": "KRN-WQ-008",
    "links": [],
    "rationale": "Timer callbacks need a thread; the tiny profile cannot afford one by default.",
    "statement": "With `CONFIG_EMB_SYSTEM_WORKQ` the system work queue shall exist from kernel start at `CONFIG_EMB_SYSTEM_WORKQ_PRIO` with `CONFIG_EMB_SYSTEM_WORKQ_STACK`; it shall be the default queue of software timers; the tiny profile shall default to no system queue.",
    "status": "Accepted 2026-10-07",
    "title": "System work queue",
    "trace": "SPEC-006 \u00a74.3, \u00a78; SPEC-003 \u00a77.3; ADR-019",
    "verification": "Test: `wq/system_queue_exists`; footprint test of the tiny profile without it."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WQ.md",
    "evidence": "not evaluated",
    "group": "KRN-WQ",
    "id": "KRN-WQ-009",
    "links": [],
    "rationale": "Fixes the implementation shape so that latency is the thread's dispatch latency plus the handlers ahead.",
    "statement": "A work queue's thread shall wait on the `K_WORK` notification bit, drain the FIFO one item at a time with the item marked `RUNNING` outside the critical section, and run handlers at the queue's priority.",
    "status": "Accepted 2026-10-07",
    "title": "Work queue thread",
    "trace": "SPEC-006 \u00a74.1, \u00a74.3, \u00a74.4",
    "verification": "Analysis: `kernel/work/` review; Test: `wq/latency_measured` with the trace events."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WQ.md",
    "evidence": "not evaluated",
    "group": "KRN-WQ",
    "id": "KRN-WQ-010",
    "links": [],
    "rationale": "Each would leave work or locks in an undefined owner.",
    "statement": "Destroying a queue with queued or running items, flushing or synchronously cancelling from the queue's own thread, and returning from a handler while owning a mutex shall be misuse per SPEC-001 \u00a75.3.",
    "status": "Accepted 2026-10-07",
    "title": "Lifecycle misuse",
    "trace": "SPEC-006 \u00a76",
    "verification": "Test: `misuse/wq_*` in checked and release configurations (TEST-010)."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/KRN-WQ.md",
    "evidence": "not evaluated",
    "group": "KRN-WQ",
    "id": "KRN-WQ-011",
    "links": [
      "OBS-005"
    ],
    "rationale": "Work queue latency is the latency of every timer callback and bottom half.",
    "statement": "Submit, start with submit-to-start latency, end with duration, cancel, and delayed scheduling shall be trace events; maximum FIFO length, worst latency, and longest handler with its address shall be optional statistics per queue.",
    "status": "Accepted 2026-10-07",
    "title": "Trace and statistics",
    "trace": "SPEC-006 \u00a77; OBS-005",
    "verification": "Test: trace decoder; statistics API test."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-001",
    "links": [],
    "rationale": "ADR-009: logging cheap enough to leave on in production.",
    "statement": "Logging shall support deferred formatting with string interning in a non-loaded section, decodable from the ELF.",
    "status": "Accepted 2026-10-07",
    "title": "Deferred-format logging",
    "trace": "SPEC-015 \u00a72",
    "verification": "Test: `obs/log_deferred_roundtrip` decodes a stream with `tools/logdec`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-002",
    "links": [],
    "rationale": "Zero cost for excluded levels; control in the field for the rest.",
    "statement": "Log severity shall be filterable at compile time per module and at runtime per module.",
    "status": "Accepted 2026-10-07",
    "title": "Compile-time and runtime filtering",
    "trace": "SPEC-015 \u00a72.1",
    "verification": "Footprint test (excluded calls absent); runtime filter test."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-003",
    "links": [],
    "rationale": "A log call must never change timing by blocking.",
    "statement": "ISR logging shall be non-blocking and bounded; drops shall be counted, not hidden.",
    "status": "Accepted 2026-10-07",
    "title": "ISR logging bounded, drops counted",
    "trace": "SPEC-015 \u00a72.3",
    "verification": "Test: `obs/log_isr_drop_counter` under ring overflow."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-004",
    "links": [],
    "rationale": "Products differ in what is wired.",
    "statement": "Log transports shall include UART, SWO/ITM, RTT-like memory channel, USB, retained RAM ring, and network, selected by configuration.",
    "status": "Accepted 2026-10-07",
    "title": "Transports",
    "trace": "SPEC-015 \u00a77",
    "verification": "Transport tests per reference board."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-005",
    "links": [],
    "rationale": "Zero-cost opt-out; no unbounded buffers.",
    "statement": "Trace points shall compile to nothing when disabled and to a bounded store when enabled.",
    "status": "Accepted 2026-10-07",
    "title": "Trace points compile to nothing when off",
    "trace": "SPEC-015 \u00a73.2",
    "verification": "Footprint test with trace classes off; overflow test with `events_discarded`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-006",
    "links": [],
    "rationale": "ADR-021.",
    "statement": "Trace output shall be CTF with generated metadata; EmbDebug shall not be required to decode it.",
    "status": "Accepted 2026-10-07",
    "title": "CTF with generated metadata",
    "trace": "SPEC-015 \u00a73",
    "verification": "Babeltrace 2 reads a captured stream in CI."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-007",
    "links": [],
    "rationale": "Live analysis and post-mortem need both.",
    "statement": "Trace shall support streaming (probe, UART, network) and snapshot (ring buffer dumped on fault or demand) modes.",
    "status": "Accepted 2026-10-07",
    "title": "Streaming and snapshot",
    "trace": "SPEC-015 \u00a73.3",
    "verification": "Test: streaming over the memory channel; snapshot dump through the descriptor."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-008",
    "links": [],
    "rationale": "ADR-011.",
    "statement": "The image shall export a versioned debug descriptor sufficient to enumerate threads, states, priorities, stacks, owned locks, partitions, and devices without knowledge of private struct layout.",
    "status": "Accepted 2026-10-07",
    "title": "Debug descriptor",
    "trace": "SPEC-015 \u00a75",
    "verification": "`tools/descriptor` enumerates everything from a memory dump of the conformance run on each port."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-009",
    "links": [],
    "rationale": "ADR-034.",
    "statement": "Worst-case interrupt-masked and scheduler-locked intervals shall be recorded per CPU and per thread with the address of the opener, as a compile-time option.",
    "status": "Accepted 2026-10-07",
    "title": "Worst-case monitors with opener address",
    "trace": "SPEC-015 \u00a76",
    "verification": "Test: `obs/monitor_records_pc` with a deliberately long critical section."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-010",
    "links": [],
    "rationale": "Field-detectable latency violations.",
    "statement": "Thresholds per monitored category shall be configurable to trace, notify, or fault.",
    "status": "Accepted 2026-10-07",
    "title": "Monitor thresholds",
    "trace": "SPEC-015 \u00a76",
    "verification": "Test: each action triggered by threshold crossing."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-011",
    "links": [],
    "rationale": "Tools and applications read the same numbers.",
    "statement": "Monitor state shall be exported through the debug descriptor and the statistics API.",
    "status": "Accepted 2026-10-07",
    "title": "Monitor export",
    "trace": "SPEC-015 \u00a75, \u00a76",
    "verification": "Descriptor consumer test; `emb_monitor_get` test."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-012",
    "links": [],
    "rationale": "R-003 \u00a74: targets become baselines.",
    "statement": "Benchmark results of a release shall be compared with the previous release's baseline on the same board and configuration; a regression beyond the configured threshold shall fail the release.",
    "status": "Accepted 2026-10-07",
    "title": "Benchmark baseline regression",
    "trace": "SPEC-015 \u00a78; TEST-012",
    "verification": "Release pipeline test with an injected regression."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-013",
    "links": [],
    "rationale": "Smallest records, host-side formatting, mid-stream resynchronization.",
    "statement": "A log record shall be `id timestamp args` with the identifier being the address of the call site's metadata object in a `NOLOAD` dummy region (16 bits when it fits, else 32), typed arguments per the metadata signature, bounded string copies, an in-band `dropped(count)` record, and a periodic synchronization marker; the plain-text backend shall share the call sites.",
    "status": "Accepted 2026-10-07",
    "title": "Log record format",
    "trace": "SPEC-015 \u00a72.2 to \u00a72.5",
    "verification": "Decoder tests including mid-stream join and drop records; AVR plain-text test."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-014",
    "links": [],
    "rationale": "One catalogue keeps every specification's events decodable by one tool.",
    "statement": "The 1.0 trace event set shall be the catalogue of SPEC-015 \u00a73.1 defined in `trace_events.yaml`; emitters, enum, and CTF metadata shall be generated from it; events shall be fixed-size with handles as index and generation and threads as index; rings shall be per-CPU CTF streams with 1 KB packets by default and `events_discarded` on overflow; classes shall be selectable at compile time and masked at run time.",
    "status": "Accepted 2026-10-07",
    "title": "Trace event catalogue and emission",
    "trace": "SPEC-015 \u00a73.1, \u00a73.2",
    "verification": "Generator golden test; Babeltrace reads every event class."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-015",
    "links": [],
    "rationale": "Tools convert to time without guesswork.",
    "statement": "Event timestamps shall be 32-bit trace clock ticks with the 64-bit value in packet headers and a CTF clock class declaring the frequency from the hardware description; the tiny profile may use the kernel tick.",
    "status": "Accepted 2026-10-07",
    "title": "Trace clock",
    "trace": "SPEC-015 \u00a73.4",
    "verification": "Metadata check; Trace Compass displays absolute times."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-016",
    "links": [],
    "rationale": "FLT-001 made concrete and decodable by `tools/crashdec`.",
    "statement": "The crash record shall follow the v1 layout of SPEC-015 \u00a74 (header, build id, uptime, reset reason, fault fields, status and general registers with counts, flight recorder tail, CRC-32), written before any recovery action to the retained section or `.noinit`; a v2 small variant shall serve AVR; partition mini-records shall go to a retained ring when enabled; formats shall be versioned and append-only; the kernel shall expose get and clear on the next boot.",
    "status": "Accepted 2026-10-07",
    "title": "Crash record format",
    "trace": "SPEC-015 \u00a74",
    "verification": "Fault-injection test: record written, survives reset, decodes and symbolizes."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-017",
    "links": [],
    "rationale": "OBS-008 made exact.",
    "statement": "The descriptor shall contain the sections of SPEC-015 \u00a75 (header, types, thread, scheduler, objects, partitions, rings, monitors, arch), be exported at `emb_debug_descriptor`, carry the magic `\"EMBD\"`, and be versioned so that one generic plugin serves every kernel version.",
    "status": "Accepted 2026-10-07",
    "title": "Descriptor contents and discovery",
    "trace": "SPEC-015 \u00a75",
    "verification": "`tools/descriptor` test on every reference configuration; version compatibility test."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-018",
    "links": [],
    "rationale": "04 \u00a77.5; ADR-034.",
    "statement": "The kernel shall offer `emb_stats_cpu_get`, `emb_stats_thread_get`, `emb_stats_object_get`, `emb_monitor_get`, `emb_monitor_set_threshold`, and `emb_stats_reset`, with monitor categories `IRQ_LOCK`, `SCHED_LOCK`, `ISR(vector)`, `THREAD_RUN`, `WORK_HANDLER`; all shall compile out with their options.",
    "status": "Accepted 2026-10-07",
    "title": "Statistics API and monitor categories",
    "trace": "SPEC-015 \u00a76",
    "verification": "API tests; footprint with statistics off."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-019",
    "links": [],
    "rationale": "One framing for every stream; probe tooling reuse.",
    "statement": "Byte-stream transports shall carry COBS frames with a channel byte and CRC-16 (channels 0 log, 1 trace, 2 crash, 3 shell, 4 to 15 application); the memory channel shall export a control block at `emb_memchan` with an optional RTT-compatible layout.",
    "status": "Accepted 2026-10-07",
    "title": "Framing and memory channel",
    "trace": "SPEC-015 \u00a77",
    "verification": "Decoder resynchronization test; RTT-compatible read by an existing probe tool."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-020",
    "links": [],
    "rationale": "The decoders are part of the product.",
    "statement": "`tools/logdec`, `tools/tracedec`, `tools/crashdec`, and `tools/descriptor` shall ship with the kernel, refuse streams whose build id mismatches the ELF, and accept every format version they know.",
    "status": "Accepted 2026-10-07",
    "title": "Host tools and build-id checks",
    "trace": "SPEC-015 \u00a710",
    "verification": "Tool tests including a mismatched build id."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/OBS.md",
    "evidence": "not evaluated",
    "group": "OBS",
    "id": "OBS-021",
    "links": [],
    "rationale": "Footprint where it matters, evidence everywhere.",
    "statement": "Observability defaults per profile shall be those of SPEC-015 \u00a79: plain-text log and small crash record on tiny, deferred log and snapshot trace on base, streaming trace and partition records on isolated and multicore, host pipe decoding on native; the descriptor shall be present in every profile.",
    "status": "Accepted 2026-10-07",
    "title": "Profile defaults",
    "trace": "SPEC-015 \u00a79",
    "verification": "Configuration review; footprint tests."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT-ABI",
    "id": "PORT-ABI-001",
    "links": [],
    "rationale": "GCC and Clang builds are first-class (ADR-023).",
    "statement": "The public kernel API shall not require an EmbCC-specific language extension.",
    "status": "Accepted 2026-10-07",
    "title": "No EmbCC-specific extension in the public API",
    "trace": "SPEC-011 \u00a715; SPEC-001 \u00a710; v0.1 \u00a721.5",
    "verification": "Build matrix: public headers compile with `-std=c11 -pedantic` on GCC and Clang."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT-ABI",
    "id": "PORT-ABI-002",
    "links": [],
    "rationale": "No compiler conditionals scattered through generic code (v0.1 \u00a721.2).",
    "statement": "Compiler-specific attributes and builtins shall be isolated behind portability interfaces.",
    "status": "Accepted 2026-10-07",
    "title": "Portability layer for attributes and builtins",
    "trace": "SPEC-011 \u00a715; SPEC-001 \u00a710",
    "verification": "Analysis: CI grep rejects `__attribute__` and `__builtin_` outside `include/emb/compiler/` and `arch/`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT-ABI",
    "id": "PORT-ABI-003",
    "links": [],
    "rationale": "Support is stated per architecture and version, not claimed globally (v0.1 \u00a721.3).",
    "statement": "Supported compiler and version combinations shall be documented and continuously tested where infrastructure permits.",
    "status": "Accepted 2026-10-07",
    "title": "Documented and tested compiler matrix",
    "trace": "09 \u00a711; 05 \u00a72",
    "verification": "Analysis: the matrix of 09 \u00a711 is generated from CI results each release."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT-ABI",
    "id": "PORT-ABI-004",
    "links": [],
    "rationale": "A refused configuration beats a wrong image.",
    "statement": "The build shall detect incompatible architecture, ABI, and configuration combinations as early as practical.",
    "status": "Accepted 2026-10-07",
    "title": "Early detection of incompatible combinations",
    "trace": "SPEC-011 \u00a72; BLD-007",
    "verification": "Build tests: hard-float and soft-float mix, a kernel feature the port manifest lacks, a profile the port cannot support, each fails at configuration."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT-ABI",
    "id": "PORT-ABI-005",
    "links": [],
    "rationale": "One conformance suite across compilers and optimization levels.",
    "statement": "Toolchain-specific optimizations may improve performance but shall not change documented kernel semantics.",
    "status": "Accepted 2026-10-07",
    "title": "Optimizations never change semantics",
    "trace": "05 \u00a74; 09 \u00a77",
    "verification": "The conformance suite runs at `-O0`, `-Os`, and `-O2` on every compiler of the matrix."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT",
    "id": "PORT-001",
    "links": [],
    "rationale": "The contract is checkable data, not folklore.",
    "statement": "Every port shall declare its properties and feature flags in `arch/<arch>/arch.yaml` (word size, endianness, stack rules, nesting, zero-latency class, compare-and-swap, interrupt stack, hardware stack limit, protection model, lazy FPU, cycle counter, tickless, SMP, trap kind, fault entry, TCB extension); the configuration shall derive `EMB_ARCH_HAS_*` from it and refuse kernel features the port cannot support.",
    "status": "Accepted 2026-10-07",
    "title": "Port manifest",
    "trace": "SPEC-011 \u00a72",
    "verification": "Schema validation of every manifest; configuration tests for refused combinations."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT",
    "id": "PORT-002",
    "links": [],
    "rationale": "Smallest TCB; kernel layout independent of the register set.",
    "statement": "A thread's register context shall be saved on its own stack; the TCB shall hold only the saved stack pointer and the port's declared extension bytes.",
    "status": "Accepted 2026-10-07",
    "title": "Context on the thread stack",
    "trace": "SPEC-011 \u00a73",
    "verification": "Analysis: `emb_arch_tcb_t` definition per port; footprint test."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT",
    "id": "PORT-003",
    "links": [],
    "rationale": "SoC startup and the kernel need fixed hooks.",
    "statement": "A port shall provide `emb_arch_early_init`, `emb_arch_init`, and a non-returning `emb_arch_kernel_start` with the responsibilities of SPEC-011 \u00a74, following the startup form of 09 \u00a78 for its target.",
    "status": "Accepted 2026-10-07",
    "title": "Startup entry points",
    "trace": "SPEC-011 \u00a74",
    "verification": "Test: `arch/boot_sequence` on each port."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT",
    "id": "PORT-004",
    "links": [],
    "rationale": "KRN-THR-005, KRN-MM-002, SPEC-002 \u00a76.",
    "statement": "`emb_arch_context_init` shall build a frame that enters `embk_thread_launch(entry, arg)`, which calls the entry and exits with code 0; `emb_arch_switch_final` shall switch without saving the terminating context; `emb_arch_switch_out_done` shall prevent reuse until switch-out completes; `emb_arch_switch_to` shall save callee-saved state, exchange stack pointers, and resume; each architecture shall have exactly one switch path serving P1 and P2; the switch shall be a full memory barrier.",
    "status": "Accepted 2026-10-07",
    "title": "Context init and single switch path",
    "trace": "SPEC-011 \u00a75",
    "verification": "Test: `arch/context_init_launch`, `arch/switch_roundtrip`, `arch/switch_from_isr_and_thread_interoperate`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT",
    "id": "PORT-005",
    "links": [],
    "rationale": "SPEC-002 made these the kernel's expectations.",
    "statement": "A port shall implement the kernel-aware entry and exit sequence of SPEC-002 \u00a76, `EMB_ISR` and `EMB_ISR_RAW`, the key-based critical-section primitives as always-inline functions with a memory clobber, `emb_arch_in_isr`, and the controller operations `enable`, `disable`, `set_level` (generic numbering), `clear_pending`, `pend_soft`, `is_enabled`, routing platform controllers from the generated tables.",
    "status": "Accepted 2026-10-07",
    "title": "Interrupt entry, exit, and controller operations",
    "trace": "SPEC-011 \u00a76; SPEC-002",
    "verification": "`tests/arch/irq_*`; KRN-IRQ tests on each port."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT",
    "id": "PORT-006",
    "links": [],
    "rationale": "KRN-TIM-020, 036.",
    "statement": "A port shall implement the architecture timer contract of SPEC-003 \u00a74 plus `emb_arch_timer_start_periodic`, `emb_arch_timer_set_latency_ticks`, `emb_arch_cycles`, and `emb_arch_cycles_hz`, and shall measure its arming latency at init unless the hardware description declares it.",
    "status": "Accepted 2026-10-07",
    "title": "Timer and cycle counter contract",
    "trace": "SPEC-011 \u00a77; SPEC-003 \u00a74",
    "verification": "`tests/arch/timer_*`: accuracy, MAX_INTERVAL hop, latency measurement, cycle monotonicity."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT",
    "id": "PORT-007",
    "links": [],
    "rationale": "One source for EmbCC, GCC, and Clang (09 \u00a75, \u00a76).",
    "statement": "Kernel atomics shall be C11 atomics through the portability layer; a port shall provide only barriers and its `cas` manifest flag, from which the wait protocol selects its transition implementation.",
    "status": "Accepted 2026-10-07",
    "title": "Atomics through the portability layer",
    "trace": "SPEC-011 \u00a78; SPEC-004 \u00a712; SPEC-005 \u00a79",
    "verification": "Analysis: no hand-written exclusive-access asm in `arch/`; the wait-protocol tests pass with both transition forms."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT",
    "id": "PORT-008",
    "links": [],
    "rationale": "A lost wake-up in idle is an unbounded latency.",
    "statement": "`emb_arch_idle` shall enable interrupts and wait for one without a window in which a wake-up can be lost; `emb_arch_sleep` shall enter the power core's mapped state.",
    "status": "Accepted 2026-10-07",
    "title": "Atomic idle",
    "trace": "SPEC-011 \u00a79",
    "verification": "Test: `arch/idle_no_lost_wakeup` with an interrupt pending at idle entry."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT",
    "id": "PORT-009",
    "links": [],
    "rationale": "KRN-MEM-009 to 011, KRN-THR-023.",
    "statement": "A port shall declare stack alignment, minimum, and growth; implement the switch-out stack check and the hardware limit register where present; install or document the interrupt stack per SPEC-002 \u00a77.2; and document handler and context frame sizes.",
    "status": "Accepted 2026-10-07",
    "title": "Stack rules and checks",
    "trace": "SPEC-011 \u00a710",
    "verification": "Test: `arch/stack_guard_detects_overflow`; documentation review."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT",
    "id": "PORT-010",
    "links": [],
    "rationale": "SPEC-002 \u00a79; the crash record needs the decode.",
    "statement": "A port with fault hardware shall route every synchronous fault to `emb_arch_fault_entry`, decode the architecture state into `emb_fault_info_t`, classify the faulting context, call `embk_fault_dispatch`, and never return except through a recoverable-fault hook; a port without fault hardware shall say so in its manifest and documentation.",
    "status": "Accepted 2026-10-07",
    "title": "Fault entry and decode",
    "trace": "SPEC-011 \u00a711",
    "verification": "Test: `arch/fault_decode` by injection on each fault class."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT",
    "id": "PORT-011",
    "links": [],
    "rationale": "Isolation mechanics belong to the port; policy to the kernel and generator.",
    "statement": "A port with protection hardware shall implement `emb_arch_mpu_init`, `emb_arch_mpu_apply`, `emb_arch_mpu_guard_set`, `emb_arch_user_access_ok`, `emb_arch_syscall_enter`, and `emb_arch_syscall_return` with the semantics of SPEC-010 \u00a74 and \u00a75; the region set encoding shall be the port's and opaque to the kernel.",
    "status": "Accepted 2026-10-07",
    "title": "Protection and trap hooks",
    "trace": "SPEC-011 \u00a712; SPEC-010",
    "verification": "Isolated-profile tests on each MPU port; `arch/syscall_roundtrip`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT",
    "id": "PORT-012",
    "links": [
      "OBS-008"
    ],
    "rationale": "ADR-011 needs architecture facts a debugger cannot infer.",
    "statement": "A port shall contribute the context frame layout, TCB extension layout, fault register layout, interrupt stack bounds, and its name and variant to the debug descriptor, and shall provide `emb_arch_breakpoint` and `emb_arch_trace_timestamp`.",
    "status": "Accepted 2026-10-07",
    "title": "Debug descriptor contribution",
    "trace": "SPEC-011 \u00a714; OBS-008",
    "verification": "Descriptor consumer test on each port."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT",
    "id": "PORT-013",
    "links": [],
    "rationale": "One source for three compilers (09 \u00a75, \u00a77).",
    "statement": "Port code shall follow the rules of SPEC-011 \u00a715: `naked` functions or `.S` files for multi-block assembly, no labels in inline asm, no callee-saved registers in templates, always-inline critical sections with a memory clobber, no LTO, PIC, stack protector, or short enums, generated linker inputs, bracketed sections for registration, and documented workarounds for instruction vocabulary gaps.",
    "status": "Accepted 2026-10-07",
    "title": "Toolchain rules for port code",
    "trace": "SPEC-011 \u00a715; 09",
    "verification": "Build on EmbCC, GCC, and Clang for each port; CI grep for forbidden constructs."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/PORT.md",
    "evidence": "not evaluated",
    "group": "PORT",
    "id": "PORT-014",
    "links": [],
    "rationale": "A port without its evidence is not a port (01 \u00a76).",
    "statement": "A port shall be complete only with its manifest, headers and sources, `docs/ports/<arch>.md` (frame layout, stack rules, latency figures, timer sources, fault classes, protection model, toolchain gaps), the `tests/arch/` group green, and the full kernel conformance suite green on the port.",
    "status": "Accepted 2026-10-07",
    "title": "Port deliverables",
    "trace": "SPEC-011 \u00a716",
    "verification": "Release checklist; CI gates."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/SIM.md",
    "evidence": "not evaluated",
    "group": "SIM",
    "id": "SIM-001",
    "links": [],
    "rationale": "It is a real port, not a mock (02 \u00a78).",
    "statement": "The native port shall pass the full kernel conformance suite.",
    "status": "Accepted 2026-10-07",
    "title": "Native port passes the conformance suite",
    "trace": "SPEC-013 \u00a71, \u00a711, \u00a712",
    "verification": "CI: `ctest` on the native port for the tiny, base, and isolated configurations."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/SIM.md",
    "evidence": "not evaluated",
    "group": "SIM",
    "id": "SIM-002",
    "links": [],
    "rationale": "Real port code under an emulator catches what the native port cannot.",
    "statement": "Each supported architecture shall have at least one emulated target in CI.",
    "status": "Accepted 2026-10-07",
    "title": "One emulated target per architecture",
    "trace": "04 \u00a79; 09 \u00a79",
    "verification": "CI matrix: QEMU AVR and EmbSIM's Arduino Uno (`avr-uno-embsim`), QEMU or Renode Cortex-M, QEMU RISC-V."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/SIM.md",
    "evidence": "not evaluated",
    "group": "SIM",
    "id": "SIM-003",
    "links": [],
    "rationale": "Only hardware tells the truth about time.",
    "statement": "Emulated results shall never be published as timing evidence.",
    "status": "Accepted 2026-10-07",
    "title": "Emulated results are not timing evidence",
    "trace": "SPEC-013 \u00a71; 05 \u00a74.4",
    "verification": "Release checklist; harness metadata records the source of every number."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/SIM.md",
    "evidence": "not evaluated",
    "group": "SIM",
    "id": "SIM-004",
    "links": [],
    "rationale": "A race that cannot be reproduced cannot be fixed.",
    "statement": "In deterministic mode the native port shall deliver interrupts only at gate crossings, advance time only in idle, and reproduce the same trace from the same binary, configuration, and event schedule; the harness shall record every run's schedule and replay a given one.",
    "status": "Accepted 2026-10-07",
    "title": "Deterministic, replayable runs",
    "trace": "SPEC-013 \u00a75, \u00a76, \u00a79",
    "verification": "Test: two runs with the same schedule produce byte-identical traces; replay of a recorded failing schedule reproduces the failure."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/SIM.md",
    "evidence": "not evaluated",
    "group": "SIM",
    "id": "SIM-005",
    "links": [],
    "rationale": "Host scheduling must not leak into kernel semantics.",
    "statement": "Exactly one simulated thread of a simulated CPU shall execute at any time; the kernel's dispatch decisions shall be the only source of thread interleaving; a run with no runnable thread, no deadline, and no pending event shall be reported as finished or deadlocked.",
    "status": "Accepted 2026-10-07",
    "title": "Exact scheduling through the gate",
    "trace": "SPEC-013 \u00a74, \u00a76",
    "verification": "Test: running-thread counter never exceeds one; deadlock report test."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/SIM.md",
    "evidence": "not evaluated",
    "group": "SIM",
    "id": "SIM-006",
    "links": [],
    "rationale": "Exercises critical-section discipline the way hardware does.",
    "statement": "An asynchronous delivery mode shall interrupt the running simulated thread at arbitrary host instructions and shall run with the invariant checker enabled.",
    "status": "Accepted 2026-10-07",
    "title": "Asynchronous stress mode",
    "trace": "SPEC-013 \u00a75, \u00a77",
    "verification": "CI stress leg with sanitizers."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/SIM.md",
    "evidence": "not evaluated",
    "group": "SIM",
    "id": "SIM-007",
    "links": [],
    "rationale": "The supervisor path and the validation logic are tested before the MPU ports exist.",
    "statement": "The native port shall route host faults to the kernel fault path, inject partition faults on request at gate crossings, and implement `emb_arch_user_access_ok` over the generated region sets so that marshaller validation returns real statuses.",
    "status": "Accepted 2026-10-07",
    "title": "Fault injection and software region checks",
    "trace": "SPEC-013 \u00a77",
    "verification": "Test: `arch/native/fault_inject`, `part/validate_*` on native."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/SIM.md",
    "evidence": "not evaluated",
    "group": "SIM",
    "id": "SIM-008",
    "links": [],
    "rationale": "TEST-008: the model is the oracle for the kernel on every port.",
    "statement": "The native port shall emit kernel trace events to a host pipe; `tools/model/bridge.py` shall replay them into the reference model and compare results, queue order, priorities, and mutex ownership after every event; a divergence shall fail the test naming the first diverging event; the bridge shall also accept CTF traces from hardware runs.",
    "status": "Accepted 2026-10-07",
    "title": "Differential bridge to the reference model",
    "trace": "SPEC-013 \u00a78; SPEC-004 \u00a713; TEST-008",
    "verification": "Test: the catalogue scenarios of `tools/model/tests/scenarios.py` as conformance tests with bridge agreement; a deliberately wrong kernel build diverges."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/SIM.md",
    "evidence": "not evaluated",
    "group": "SIM",
    "id": "SIM-009",
    "links": [],
    "rationale": "05 \u00a74; R-003 T14.",
    "statement": "CI shall run the native conformance suite under AddressSanitizer, UndefinedBehaviorSanitizer, and ThreadSanitizer on GCC and Clang and under EmbCC's `-fsanitize=undefined`; coverage shall feed the traceability matrix; fuzz harnesses shall drive the public API and the marshallers with the invariant checker after every call.",
    "status": "Accepted 2026-10-07",
    "title": "Sanitizers, coverage, fuzzing",
    "trace": "SPEC-013 \u00a77, \u00a711",
    "verification": "CI legs present and green; coverage report generated."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/SIM.md",
    "evidence": "not evaluated",
    "group": "SIM",
    "id": "SIM-010",
    "links": [],
    "rationale": "Non-POSIX hosts stay possible (02 \u00a78).",
    "statement": "The native port shall depend only on the `embh_*` host layer (threads, mutex, condition variable, monotonic clock, sleep, signal or suspend, fault hook) with POSIX and Win32 backends.",
    "status": "Accepted 2026-10-07",
    "title": "Host portability of the port",
    "trace": "SPEC-013 \u00a73",
    "verification": "Build on Linux, macOS, and Windows; CI grep for direct host API use outside `embh_*`."
  },
  {
    "design_status": "Accepted",
    "document": "requirements/SIM.md",
    "evidence": "not evaluated",
    "group": "SIM",
    "id": "SIM-011",
    "links": [],
    "rationale": "ADR-012; keeps the SMP model and the SMP port comparable.",
    "statement": "The gate design shall extend to N simulated CPUs with IPI events at gate crossings for the SMP work, without changing the single-CPU interface.",
    "status": "Accepted 2026-10-07 (FUTURE)",
    "title": "Multi-CPU reservation",
    "trace": "SPEC-013 \u00a710",
    "verification": "Design review at SMP specification time."
  }
]
