docs(wiki): log-storm hardening + reset drift guard (2026-07-07 incident)
Build desktop / desktop (push) Successful in 4m37s
CI / check (push) Successful in 42s
Build & push images / images (push) Successful in 2m51s

button-light-indicator: failure backoff + rate-limited logging rationale;
app-logs: storm coalescing invariant + --diagnostics wipe; local-dev-workflow
and appliance-provisioning §7d: new reset flag table + drift guard; log entry
tying all three layers to the ENETUNREACH incident.

Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
2026-07-10 08:29:59 +02:00
parent ba5b4b1f4e
commit 22544ecf63
5 changed files with 56 additions and 7 deletions
+14 -3
View File
@@ -2,7 +2,7 @@
type: concept
tags: [parking, device, indicator, radar, camera, aux-output, barrier-not-a-door, event-relay]
sources: []
updated: 2026-06-28
updated: 2026-07-08
status: settled
---
@@ -72,6 +72,16 @@ aux-output** capability.
re-converges to the latest desired state. So the **final state is always authoritative** and a
lost/stale packet self-corrects. This also de-dupes (it skips a send when `confirmedOn === desiredOn`),
so the input stream never spams the controller.
- **Failure backoff + rate-limited logging (2026-07-08).** The first serialized-worker cut re-pumped
*immediately* after a FAILED send (`confirmedOn` unchanged → converge again) — correct for a lost
packet, but an **unreachable controller** (`ENETUNREACH`, rejects instantly) turned it into a hot
loop: hundreds of identical error lines per minute into stdout AND [[app-logs]] (field incident
2026-07-07, park-buzi). Now a failed send arms a **retry backoff — 1 s doubling to a 30 s cap,
reset on success**; during the window `desiredOn` keeps tracking the truth table and the armed
retry converges to whatever it says when it fires (`#finalOff` waives the backoff for the one-shot
last-gasp OFF). Logging: only the **first** failure of a streak is logged, then **one summary per
minute** (`still failing (attempt N…)`), and a single `info` on recovery. The app_logs sink
additionally coalesces identical rows (see [[app-logs]]) as defense in depth.
- **Hot-reloads the config (no restart).** The lamp map is reconciled against the live device config
at start AND before each event (mirroring [[device-status-monitoring|DeviceMonitor]], which re-reads
the device set each tick) — adding/updating/dropping lamps. So a button light added or re-pointed in
@@ -102,7 +112,8 @@ Built 2026-06-24 for the first booth (button I1, radar I2, lamp on a spare relay
a `radarAlert` event-relay (carrying its own `triggerInput`), so the operator can add arbitrary
event-driven blinkers (e.g. R4) without code changes; the 3-state machine itself is unchanged.
Covered by `apps/server/src/button-light.test.ts` (the truth table, blink toggling asserted on the
device's *confirmed* state, fail-OFF, de-dupe, lamp-added-after-start reconcile, and two independent
alert relays on one controller).
device's *confirmed* state, fail-OFF, de-dupe, lamp-added-after-start reconcile, two independent
alert relays on one controller, and — since 2026-07-08 — backoff cadence on an unreachable
controller, log rate-limiting, and single-recovery-line + backoff-reset after success).
Related: [[hikvision-radar]], [[entry-double-press]], [[lpr-camera]], [[dingtian-relay]],
[[entry-exit-points]], [[barrier-not-a-door]].