@@ -42,6 +42,19 @@ flowchart TD
4242 D --> G["Diagnostics::Hub::flush()"]
4343```
4444
45+ The application integration contract is:
46+
47+ ``` cpp
48+ Board<FaultPolicyT, dev0, dev1, ...>
49+ ```
50+
51+ Where:
52+
53+ - ` FaultPolicyT ` is mandatory and is always the first template argument
54+ - ` dev0, dev1, ... ` are the board declarations to inscribe into the domains
55+ - the framework always owns the top-level runtime machine
56+ - the application may optionally provide a nested operational machine and/or a ` FAULT ` entry callback
57+
4558### 1.2 Registering Protections
4659
4760Protections are created through ` ProtectionEngine::create_protection(...) ` .
@@ -66,6 +79,33 @@ Available rule factories:
6679Both ` create_protection(...) ` and ` add_rule(...) ` return ` std::expected ` , so configuration errors
6780must be handled explicitly.
6881
82+ Current rule signatures are:
83+
84+ ``` cpp
85+ Rules::below (fault_threshold)
86+ Rules::below(fault_threshold, warning_threshold)
87+
88+ Rules::above(fault_threshold)
89+ Rules::above(fault_threshold, warning_threshold)
90+
91+ Rules::range(low_fault, high_fault)
92+ Rules::range(low_fault, high_fault, low_warning, high_warning)
93+
94+ Rules::equals(value)
95+ Rules::not_equals(value)
96+
97+ Rules::time_accumulation(fault_threshold, window_seconds)
98+ Rules::time_accumulation(fault_threshold, warning_threshold, window_seconds)
99+ ```
100+
101+ `Rules::time_accumulation(...)` has these semantics:
102+
103+ - it is intended for floating-point samples
104+ - it evaluates `abs(sample)`
105+ - it measures continuous active time, not an integral over samples
106+ - it resets the accumulated active time when the triggering condition clears
107+ - it uses `Scheduler::get_global_tick()`, so it does not depend on the `while (1)` iteration rate
108+
69109### 1.3 When to Register Protections
70110
71111Register protections before `Board::init()`.
@@ -78,6 +118,10 @@ The intended lifecycle is:
78118
79119After `Board::init()`, the protection registry is locked.
80120
121+ If registration code reports a fatal condition before `Board::init()`, that fatal request is still
122+ preserved across the first fault-runtime installation and its diagnostic record remains eligible for
123+ later delivery once sinks are installed.
124+
81125### 1.4 Typical Protection Example
82126
83127```cpp
@@ -135,6 +179,7 @@ Typical choices are:
135179
136180- ` Board<DefaultFaultPolicy, ...> ` when no extra fault callback is needed
137181- ` Board<FaultPolicyNoMachine<on_fault_enter>, ...> ` when only ` FAULT ` entry actions are needed
182+ - ` Board<FaultPolicy<app_machine, on_fault_enter>, ...> ` when both a nested operational machine and ` FAULT ` entry actions are needed
138183
139184If the application does use a functional state machine, it can be nested inside ` OPERATIONAL `
140185through a ` FaultPolicy ` .
@@ -176,6 +221,21 @@ Important rules:
176221 the child machine directly
177222- ` Board ` takes the fault policy type as its first template argument
178223
224+ ` on_fault_enter ` semantics:
225+
226+ - it is an optional callback owned by the global fault runtime
227+ - it runs when the global runtime enters ` FAULT `
228+ - it is the right place to perform application fault-entry actions such as disabling power stages,
229+ opening contactors, or setting status LEDs
230+ - it does not replace the fault transition itself; it is an enter action attached to the global
231+ ` FAULT ` state
232+
233+ If the application needs neither a nested machine nor a ` FAULT ` entry action, use:
234+
235+ ``` cpp
236+ using MainBoard = Board<DefaultFaultPolicy, led>;
237+ ```
238+
179239### 1.6 Runtime Diagnostics API
180240
181241The runtime diagnostic façade is:
@@ -203,10 +263,19 @@ Internally, protections and fatal runtime reporters converge on:
203263FaultController::request_fault (cause);
204264```
205265
206- This primitive is not intended to be the normal user-facing API.
266+ This primitive is not part of the normal user-facing API.
267+ In the current implementation it is an internal `FaultController` entry point, not a public
268+ application hook.
269+
207270User code should prefer `FAULT(...)` or `PANIC(...)` so the library captures consistent source
208271metadata and preserves the public runtime contract.
209272
273+ In practice:
274+
275+ - protections use `FaultController::request_fault(...)` internally
276+ - `PANIC(...)` and `FAULT(...)` use that same path internally
277+ - user application code should not call `request_fault(...)` directly
278+
210279### 1.8 Transmission Semantics
211280
212281All external reporting goes through `Diagnostics`.
@@ -226,6 +295,22 @@ Default sinks are installed during `Board::init()`:
226295
227296If a transport is not compiled in, it is simply not installed.
228297
298+ ### 1.9 Migration From the Legacy Model
299+
300+ If you are migrating from the previous architecture:
301+
302+ - stop using `ProtectionManager`
303+ - stop using the low/high protection split
304+ - stop using `Boundary` / `BoundaryInterface` as the protection integration model
305+ - stop depending on `FaultRuntime`
306+ - stop treating `STLIB::start()`, `STLIB::update()`, `STLIB_LOW::start()`, or `STLIB_HIGH::start()`
307+ as the real bootstrap path
308+ - move bootstrap to `Board::init()`
309+ - declare `Board<fault_policy, ...>` explicitly
310+ - move operational user behavior into `FaultPolicy<app_machine, on_fault_enter>` when needed
311+ - stop programming transitions to the global `FAULT`
312+ - replace legacy reporting paths with `PANIC(...)`, `FAULT(...)`, `WARNING(...)`, and `INFO(...)`
313+
229314## 2. Internal Development
230315
231316### 2.1 Architectural Overview
@@ -317,20 +402,24 @@ Important invariant:
317402
318403The fault path is valid during ` Board::init() ` .
319404
320- That is why ` Board::init() ` installs:
405+ That is why ` Board::init() ` installs, as early as possible in the bootstrap path :
321406
322407- default diagnostic sinks
323408- the global fault runtime
324409
325- before subsystem initialization that may trigger ` PANIC(...) ` .
410+ before clock/peripheral setup and before subsystem initialization that may trigger ` PANIC(...) ` .
326411
327412If a fatal request arrives before the global runtime has been started:
328413
329414- the cause is latched
330415- the runtime is rebuilt so that it starts directly in ` FAULT `
331416- the urgent fault diagnostic is still published through ` Diagnostics `
332417
333- This avoids losing early boot faults.
418+ If the diagnostic record is produced before any sink exists, it is still retained in local history.
419+ When the first sink is installed, the retained history is replayed into the pending queue so the
420+ record can still be delivered later.
421+
422+ This avoids losing early boot faults and other pre-transport diagnostics.
334423
335424### 2.5 FaultCause and Diagnostic Mapping
336425
0 commit comments