Design: Silence-Eskalation & Outbox-Verwahrung
Version: v0.1
Stand: 22. September 2026
Status: WORKING DESIGN â Architektur-Kante, keine Runtime-Invariante
Ort: Ansible-Crumbforest / docs
Anlass: Brand-/Ausfallfall im Container & Stockwerk â âwer ist bei den Warnings, wenn es brennt?"
Bezug: COUNTABILITY_AT_PASSKANTEN_v0.2, PRUEFLISTE-SENSOR-NODE-PERSISTENZ-AUDIT-2026-09-21,
Memory: was-nicht-antwortet-ist-nicht-da, brueckenmitte-outbox-durability, omc-rz-topologie-und-grenze
TEIL 1 â Silence-Eskalation
1.1 Die Frage, die das Design trÀgt
âWenn das Stockwerk oder der Container brennt â wer ist bei den Warnings oder Alarmen?"
Antwort: niemand Lokales. Genau deshalb darf die Sicherheits-Eigenschaft nicht auf dem
Node leben, der brennt oder die Verbindung verliert.
1.2 Zwei Pfade â presence-driven und absence-driven
Normalpfad (presence-driven). Der Sensor erkennt etwas und funkt aktiv:
Sensor erkennt â warning an lokale Crew (#mqtt #mesh #sms #signal) â Resonanz-Ticket
â nicht bestĂ€tigt in 1/2/3 min â Eskalation in die Queue OZMâcrumbforest â CRITICAL
Das ist richtig und bleibt. Vorab-Ereignisse (Rauchmelder, panische Bewegung, realer Crew-Alarm
im Raum) werden hier als warning #notfall interpretiert.
Grenzfall (absence-driven). Der Brandfall invertiert den Normalpfad: der Node, der âich brenne"
funken soll, ist derselbe, der abbrennt oder abreiĂt. Auf ihn ist im schlimmsten Moment kein Verlass.
Darum die tragende Regel (Memory: was-nicht-antwortet-ist-nicht-da):
Die Stille ist das Signal. Ein erwarteter Heartbeat eines Life-Safety-Nodes, der ausbleibt
UND nicht erreichbar ist, ist selbst eine Eskalation â nicht eine stille LĂŒcke.
remote check â container/stockwerk â UNKNOWN â keine Verbindung darf nicht in Ruhe zerfallen.
1.3 UNKNOWN muss zum Alarm hin fehlschlagen, nicht zur Ruhe hin
UNKNOWN ist ein gĂŒltiger Zustand (OZMAI-Manifest). Aber UNKNOWN ĂŒber einen Node, an dem Menschen
sind, ist fail-toward-alarm, nicht fail-toward-silence. Das ist der Dead-man's-switch:
erwarteter Heartbeat (Life-Safety-Node)
fehlt fĂŒr > T_miss UND Node nicht erreichbar
â UNKNOWN_LIFE_SAFETY
â behandelt wie eine unbestĂ€tigte warning: eskaliert nach 1/2/3 min â CRITICAL
Ein Node, der âich brenne" senden kann, ist nice-to-have. Ein Node, dessen Schweigen anderswo
Alarm auslöst, ist die eigentliche Sicherheits-Eigenschaft.
1.4 Warum zwei MQTTs eine Sicherheits-Eigenschaft sind, keine Bequemlichkeit
Brennt der Node, verbrennt sein lokaler Broker mit. BestÀtigung und Eskalation können deshalb
nicht dort liegen. Sie mĂŒssen auf dem Broker des anderen Cores leben.
Core A (crumbforest) OZMâcrumbforest-Queue Core B (onezeromore)
eigene NetBox (die eine Eskalations-Kante) eigene NetBox
eigener MQTT âââââ heartbeat / warning / critical âââââ eigener MQTT
eigene Pipeline eigene Pipeline
- Zwei Cores, jeder eigenstÀndig fail-closed. FÀllt einer, fÀllt der andere nicht (kein shared fate).
- Jeder Core watcht den Heartbeat des anderen. Geht Core A dunkel, eskaliert Core B das Schweigen â und umgekehrt.
- Getrennte Trust-Domains (eigenes OZM-WG-VPN nach den getesteten Basis-Regeln). Der Eskalations-Kanal ĂŒberquert genau eine Kante: die OZMâcrumbforest-Queue.
Der Monitoring-Kanal trĂ€gt Liveness, nicht Payload â âBaum steht / Baum gefallen", nie
âwas der Baum gesehen hat". Sonst wird aus gegenseitigem Wachen ein zweiter Verwahrungspfad
ĂŒber die VPN-Kante (verletzt PRUEFLISTE §6).
1.5 Die Grenze, die nicht verschoben wird
Der Mesh-Layer ist ein zusÀtzlicher Interpretations- und Eskalations-Layer. Er ersetzt nicht
die zertifizierte Brandmeldeanlage / den Rauchmelder-Pfad (Memory: omc-rz â Wald liest & rendert
Atmo, aktuiert KEINE Safety).
Seine Aufgabe ist âeinem Menschen sagen" und âSchweigen bemerken" â nie âich regel das selbst".
Er scheitert immer Richtung Mensch.
1.6 Verschraubbare Parameter (Sollstand, kein Runtime-Zwang)
T_hb Heartbeat-Intervall je Life-Safety-Node (z. B. 30 s)
T_miss fehlende Heartbeats bis UNKNOWN_LIFE_SAFETY (z. B. 3 Ă T_hb)
T_esc Eskalationsstufen unbestĂ€tigt â CRITICAL 1 / 2 / 3 min
watch_pairs welcher Core welchen Node/Core ĂŒberwacht (analog wg_route_pairs)
NetBox-Sichtbarkeit: life_safety: true und heartbeat_watched_by: <core> an der Rolle â
damit die Silence-Eskalation eine belegte Eigenschaft ist, keine stille Annahme.
TEIL 2 â Borgmatic als Outbox-Verwahrung
2.1 Borgmatic spaltet sich an der Verwahrungsgrenze
Backup ist strukturell eine Outbox: einseitig, runter, durable, weitergereicht. FĂŒr körpernahe
Sensorik spaltet es sich in zwei völlig verschiedene Aussagen:
- Als Klasse-A-Pfad: verboten. Ein Sensor-Node im Backup-Scope spiegelt Roh-Frames /
Keypoints off-site (PRUEFLISTE §5).backup_scope: excludedbleibt positiv gesetzt. - Als Klasse-B-Outbox: legitim â durable Verwahrung dessen, was einen eigenen Vertrag hat
(Count, Alert, msg_id). Aber nur mit Vertrag: was / wozu / wie lange / IdentitÀt ja-nein /
Leser / Löschung (COUNTABILITY v0.2 §3).
2.2 Die Durability-Kante: genau eine Wirkung, auch nach Restore
Eine Outbox mit Read-once/Wirkung braucht DURABLE_LOCAL-Dedup, sonst erzeugt ein Restore
eine zweite Zustellung (Memory: brueckenmitte-outbox-durability).
Borgmatic ist von Natur aus append-only und chunk-dedupliziert â das ist die halbe Miete gegen
Speicher-Redundanz, aber nicht dasselbe wie Zustell-Idempotenz. Die offene Frage:
Wenn ein Alert ĂŒber die Outbox getragen und dabei ge-backupt wird â ĂŒberquert er die Kante
genau einmal, oder erzeugt der Restore eine zweite Wirkung?
Die Antwort gehört in den Vertrag der Klasse-B-Zeile, nicht in borgmatic:
delivery_id stabiler, deduplizierbarer Identifier je Outbox-Ereignis (msg_id-Idiom)
effect_once EmpfÀnger verwirft delivery_id, den er schon gesehen hat (DURABLE_LOCAL)
restore_is_read Restore eines Outbox-Records ist LESEN, nie erneutes ZUSTELLEN
2.3 PrĂŒfpunkte (ErgĂ€nzung zur PRUEFLISTE §5/§8)
# EnthÀlt der Backup-Scope irgendeinen Klasse-A-Pfad? (muss leer sein)
grep -rn "<sensor-node>\|<pipeline-workdir>" /etc/borgmatic* 2>/dev/null
# Hat jeder ge-backupte Klasse-B-Store einen Vertrag mit delivery_id / effect_once?
# -> PrĂŒfung gegen die Vertragsliste, nicht gegen borgmatic
PASS: kein Klasse-A im Backup; jeder ge-backupte Klasse-B-Store trÀgt einen Vertrag mit
delivery_id + effect_once; ein Restore ist als LESEN definiert, nicht als erneute Zustellung.
NetBox: je Klasse-B-Outbox-Store ein Eintrag mit Zweck, Retention und effect_once: true.
Kurzform
Sensor misst, Raum deutet, Policy begrenzt, Mensch entscheidet.
Warning geht raus; unbestÀtigt eskaliert sie.
Und die Stille eskaliert auch â der ĂŒberlebende Baum bezeugt das Schweigen des toten.
Zwei Cores, zwei NetBoxen, zwei Broker: der Survivor trĂ€gt den Alarm ĂŒber den Toten.
Der Mesh scheitert immer Richtung Mensch, nie Richtung Handlung.
Backup ist Outbox: Klasse A nie, Klasse B nur mit Vertrag â und genau eine Wirkung, auch nach Restore.
niefertig
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com