Files
bfe-core1106-sdk/drivers/freshness/freshness.h
T
BFE EngineeringandClaude Opus 4.8 4ee4dfcf88 review: fix review findings (correctness, hardening, doc-accuracy)
First recursive code-review-harness pass over the authored SDK code (sim/,
config-lint, flowgen, drivers/{relays,freshness}, build/, ci.yml). Four parallel
dimension reviewers; all findings at every severity corrected per workspace rule.

Correctness / reliability:
- freshness.c min_budget_ms: use a `seen` flag, not `best==0`, as the empty
  sentinel — a zero-tolerance (max_stale_ms==0) binding was silently widened to a
  looser neighbour's budget. Regression test added; still 66/66 MC/DC.
- config-lint parse_reserved_ranges: match `reg` as a whole property token (ident
  boundary before, `=` after) so `reg-names` / a `region-*` label no longer
  mis-parses into a bogus reserved range.
- config-lint loader check: fail closed — flag any loader with a LOAD_ADDR that is
  not a known-safe boot component, instead of only known MCU names, so a future
  coprocessor ("Rtos"/"Bl32") can't slip past the 0x40000-brick gate.
- build-kernel.sh: sha256 verification is now mandatory (refuse to build if the pin
  is missing) and the mktemp scratch tree is removed on exit (trap), while a
  caller-provided WORK is left intact for CI artifact upload.

Test quality:
- freshness: added the age==max_stale boundary case and a clock-wraparound
  (now < last_ok) fail-safe-to-UNKNOWN test.
- relays: unsetenv(WARDEN_GPIO_ROOT) at main() so the NULL-env arm is hermetic.

Security / CI:
- ci.yml: top-level `permissions: contents: read` (badges overrides to write);
  pin taiki-e/install-action to commit SHA (v2.86.7).

Maintainability / docs:
- drivers/enforce-mcdc.sh: one shared, name-derived gate replaces the two
  copy-pasted per-driver scripts; Makefiles call ../../enforce-mcdc.sh.
- docs/architecture.md: §3/§4/§6/§7 rewritten to match reality — NPU/RGA models,
  config-lint, and the relays+freshness MC/DC harnesses are done; kernel §6 now
  reflects the 5.10->6.18.46 forward-port (ADR-0001), not the superseded plan44/6.6.
- README: status blurb + layout table corrected (kernel/, .github/; stale ci/ and
  patches/ descriptions fixed). hpmcu "8 tests" -> 7 in docs.
- freshness.{c,h}: ADR reference points at flare-edge ADR-0004 (warden-sdk's
  ADR-0004 is the CI runner — number collision).
- normalize rustfmt drift across sim/ + config-lint.

All green: sim 37 tests, config-lint 8 tests, both drivers 100% MC/DC (relays
40/40, freshness 66/66), clippy clean under -D warnings, gitleaks clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017wB8KB3MMQztRDXCMCkPrf
2026-08-25 15:48:52 -06:00

94 lines
4.5 KiB
C

/*
* The UI Freshness Contract engine (flare-edge ADR-0004) — core, LVGL-free.
*
* The panel is read on-site to judge whether hardware is healthy, so a silently
* *stale* number is worse than a missing one: a stale IP or hashrate reads as
* ground truth and sends a technician the wrong way. This engine is the only
* sanctioned way to show a live value. It guarantees a bound value is refreshed
* (a) the instant its page becomes visible, (b) periodically while visible
* within a declared max-staleness, and (c) promptly when a declared source
* changes — and it renders a value whose source cannot be evaluated as an
* explicit UNKNOWN, never as its confident last-known number.
*
* This header is deliberately LVGL-free so the engine and every producer are
* unit-testable headlessly. The LVGL label convenience lives in freshness_lv.h.
*/
#ifndef WARDEN_FRESHNESS_H
#define WARDEN_FRESHNESS_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
/* The mark shown when a value's source cannot be evaluated (em dash). The LVGL
* layer additionally dims the widget. Public so the label wrapper and tests can
* reference the same literal. */
#define WARDEN_FRESH_UNKNOWN_MARK "\xE2\x80\x94"
/* What a producer reports after being asked to produce the current value. */
typedef enum {
FRESH_OK = 0, /* wrote the current value into buf */
FRESH_UNKNOWN, /* source unavailable — no value can be produced now */
FRESH_SAME, /* source read fine; value unchanged (cheap re-render) */
} warden_fresh_result_t;
/* Produce the current value of a live datum into buf. Pure w.r.t. LVGL: a plain
* function of the model behind `ud`, which is exactly why it is the test seam. */
typedef warden_fresh_result_t (*warden_fresh_produce_cb)(char *buf, size_t n,
void *ud);
/* What the engine decided the widget should show this cycle. */
typedef enum {
FRESH_RENDER_VALUE = 0, /* show the produced/last-good value */
FRESH_RENDER_UNKNOWN, /* show the explicit-unknown mark ("—", dimmed) */
FRESH_RENDER_NOCHANGE, /* leave the widget exactly as it is */
} warden_fresh_render_t;
/* The one pure decision at the heart of the contract — no state, no I/O, no
* LVGL, so every branch is unit-testable. `showing_unknown` is whether the
* widget is currently displaying the UNKNOWN mark (so recovery from a stale
* blip re-renders the value even when the producer reports it unchanged). */
warden_fresh_render_t warden_fresh_decide(warden_fresh_result_t produced,
bool ever_ok, bool showing_unknown,
uint32_t age_ms, uint32_t max_stale_ms);
/* The widget-render seam: the engine calls this to actually update a widget.
* `buf` is valid only for FRESH_RENDER_VALUE. LVGL lives behind this callback. */
typedef void (*warden_fresh_render_cb)(void *widget, warden_fresh_render_t what,
const char *buf, void *ud);
typedef struct warden_fresh warden_fresh_t;
/* Bind a producer+widget to a page. `source` (may be NULL) is a named change
* channel for warden_fresh_invalidate. Returns NULL if the table is full. */
warden_fresh_t *warden_fresh_bind(void *page, warden_fresh_produce_cb produce,
void *ud, uint32_t max_stale_ms,
const char *source,
warden_fresh_render_cb render, void *widget);
/* A page became visible/hidden (tiles via notify_active, subnav leaves via
* on_open). Hidden pages are skipped by the periodic tick. */
void warden_fresh_set_visible(void *page, bool visible);
/* Refresh every bound value on `page` right now (the on-show guarantee). Also
* marks the page visible. */
void warden_fresh_page_show(void *page, uint32_t now_ms);
/* The shared periodic tick: refresh every currently-visible bound value. */
void warden_fresh_tick(uint32_t now_ms);
/* A producer of change fired: refresh every visible value bound to `source`. */
void warden_fresh_invalidate(const char *source, uint32_t now_ms);
/* Drop all bindings — called on a theme/screen rebuild, like the screen timers. */
void warden_fresh_reset(void);
/* Number of live bindings (introspection / tests). */
uint32_t warden_fresh_count(void);
/* Smallest max_stale_ms among visible bindings, or 0 if none — lets the LVGL
* layer size the shared tick to the tightest budget actually on screen. */
uint32_t warden_fresh_min_budget_ms(void);
#endif /* WARDEN_FRESHNESS_H */