unisat

ADR-005: FDIR as advisor; mode manager as commander

Status: Accepted — 2026-04-17 Phases: 3 (FDIR advisor) + 7.3 (mode manager) Commits: 454422c, 619d980

Context

The UniSat firmware needs both fault tracking and fault response. The naive design puts them in the same module: a single fdir_tick() that detects, counts, decides, and enacts the recovery (safe-mode entry, subsystem disable, NVIC reset). This couples three independent concerns:

  1. Detection / tracking. “Has FAULT_X fired and how often?” Pure bookkeeping — reusable, testable in isolation.
  2. Recovery policy. “Given the counters, what should happen?” Configuration-driven — the fault-action table belongs in a single source of truth.
  3. Mode transition. “Actually enter safe mode / reset the core.” Runtime side effect with platform dependencies (NVIC_SystemReset, subsystem disable hooks).

Mixing all three in one file forces unit tests to pull in NVIC headers just to verify escalation arithmetic, and hides actual transitions behind mock layers that drift out of sync with production code.

Decision

Split into two modules with a clean hand-off:

Schema:

  driver detects fault
         │
         â–Ľ
   FDIR_Report(FAULT_X)            <- advisory, just counts
         │
         â–Ľ
   FDIR_GetRecommendedAction(X)    <- looks up the table
         │
         â–Ľ
   ModeManager_Tick(): worst-case  <- commanding
         │
         â–Ľ
   EnterSafe / Degraded / Reboot   <- state change + telemetry
         │
         â–Ľ
   NVIC_SystemReset (on target)    <- platform hook

Rationale

Consequences

Positive:

Negative:

Alternatives considered

Implementation

See:

Tests:

Follow-up fix

While implementing mode_manager the test suite exposed a latent bug in FDIR_GetRecommendedAction: it returned the primary action even for faults that had never been reported (recent_count == 0). That’s semantically wrong — a fault with no active report should not drive a recovery. The fix — adding a recent_count == 0 -> LOG_ONLY fast-path at the top — is part of the 619d980 commit; two pre-existing test_fdir tests were updated to match the corrected semantics.