Pro Runtime Hardening Workboard
Status: living document
Branch: feature/pro-runtime-hardening
Dieses Dokument ist das Arbeitsdokument zur schrittweisen Umsetzung des Konzepts aus fm-rds-tx_pro_runtime_hardening_concept.json.
Ziel ist nicht nur eine hübsche Roadmap, sondern ein Ort, an dem wir konkret markieren können:
- wo wir im Code stehen,
- welche Lücken bestätigt sind,
- welche Entscheidungen gefallen sind,
- welche Arbeiten offen / in Arbeit / erledigt sind,
- welche Risiken noch bestehen,
- welche Akzeptanzkriterien wirklich nachgewiesen wurden.
1. Arbeitsregeln für dieses Dokument
Statuswerte
TODO → noch nicht begonnen
IN PROGRESS → aktiv in Arbeit
BLOCKED → sinnvoll erkannt, aber blockiert
DONE → umgesetzt
VERIFIED → umgesetzt und sinnvoll geprüft
DEFERRED → bewusst nach hinten verschoben
REJECTED → bewusst verworfen
Nachweispflicht
Ein Punkt gilt erst als wirklich fertig, wenn eingetragen ist:
- Code-Ort(e)
- Was geändert wurde
- Wie verifiziert wurde
- Welche Restrisiken bleiben
Update-Regel
Wenn wir an einem Workstream arbeiten, soll dieses Dokument mitgezogen werden.
Kein „ist im Kopf klar“. Der Stand kommt hier rein.
2. Gesamtüberblick
Gesamtstatus
- Projektphase:
Umsetzung (WS-01)
- Technischer Fokus aktuell:
Entkoppelter TX-Pfad (FrameQueue + Writer)
- Nächster sinnvoller Startpunkt laut Konzept:
WS-01 Deterministische Echtzeit-TX-Pipeline mit entkoppeltem Writer
- Vorangegangene Workstreams:
WS-03 Semantische Korrektheit und konsistent angewandte Config (abgeschlossen)
Repo-bezogene bestätigte Ausgangslage
| Thema |
Status |
Notiz |
| TX-Engine aktuell als synchroner Single-Loop |
CONFIRMED |
internal/app/engine.go |
| Persistenter DSP-Zustand im Generator vorhanden |
CONFIRMED |
internal/offline/generator.go |
| HTTP-Control vorhanden |
CONFIRMED |
internal/control/control.go |
| Config-Validation vorhanden, aber nicht überall semantisch konsistent |
CONFIRMED |
internal/config/config.go + Runtime-Pfade |
| Device/Capability-Modell vorhanden, aber noch nicht streng genug |
CONFIRMED |
internal/platform/soapy.go |
| Lock-freier SPSC-Audio-Ringbuffer vorhanden |
CONFIRMED |
internal/audio/stream.go |
Bereits bekannte bestätigte Inkonsistenzen
| ID |
Status |
Beschreibung |
Ort |
| CFG-SEM-001 |
CONFIRMED |
fm.outputDrive wird in Validation und Runtime nicht konsistent behandelt |
internal/config/config.go, internal/app/engine.go |
| CTL-UX-001 |
CONFIRMED |
handleAudioStream() referenziert --audio-http, was CLI-seitig überprüft werden sollte |
internal/control/control.go |
3. Prioritätenmodell
| Priorität |
Bedeutung |
| P0 |
Technische Perfektion und Determinismus |
| P1 |
Betriebssicherheit und Fehlerbeherrschung |
| P2 |
Hardware-Wahrheit und RF-Qualität |
| P3 |
Sichere und saubere Runtime-Steuerung |
| P4 |
Deployment-, Release- und Service-Reife |
4. Umsetzungstracker nach Workstream
WS-03 — Semantische Korrektheit und harte Config-/Runtime-Konsistenz
Priorität: P0
Gesamtstatus: IN PROGRESS
Ziel
Ein einziger, eindeutig definierter Parameterraum. Jeder Wert hat exakt eine Bedeutung und identische Constraints in Config, HTTP-API, Runtime und Telemetrie.
Warum dieser Workstream zuerst
Wenn Semantik und Grenzwerte nicht sauber vereinheitlicht sind, bauen spätere Runtime- und Fault-Mechanismen auf unstabilem Fundament.
Aufgaben
WS-03-T1 — Parameterinventar erstellen
- Status: VERIFIED
- Owner: Builder A
- Code-Orte:
internal/config/config.go
internal/app/engine.go
internal/control/control.go
internal/offline/generator.go
- Ziel:
Alle öffentlich und intern verwendeten Parameter inventarisieren mit:
- Name
- Typ
- Einheit
- Bereich
- Default
- hot-reload-fähig ja/nein
- safety class
- Telemetrie-Name
- Offene Fragen:
- Wo leben heute implizite Parameter, die nicht sauber dokumentiert sind?
- Welche Runtime-Werte sind abgeleitet statt direkt konfigurierbar?
- Nachweis:
docs/ws-03-parameter-inventory.md enthält das inventarisierte Parameter-Tableau und referenziert Config/Control/Engine.
- Live-Nutzung über
internal/control/control.go → LivePatch dokumentiert.
- Restrisiken:
- versteckte Semantik in Helper-Funktionen übersehen
WS-03-T2 — Validation vereinheitlichen
- Status: VERIFIED
- Owner: Builder A
- Code-Orte:
internal/config/config.go
internal/app/engine.go
internal/app/engine_test.go
internal/control/control.go
- Ziel:
Config.Validate(), Runtime-Update-Pfade und API-Patch-Validierung dürfen nicht divergieren.
- Bereits bekannter Startpunkt:
- Nachweis:
- CFG-SEM-001:
outputDrive-Validation in Engine.UpdateConfig jetzt 0..10 (wie Config.Validate).
- Tests (
go test ./...) fangen neue Range ab und besitzen aktualisierten engine_test-Check.
- Live-Patch fließt durch
txBridge und LivePatch (control) → LiveConfigUpdate.
- Restrisiken:
- weitere Inkonsistenzen erst beim Inventar sichtbar
WS-03-T3 — DesiredConfig / AppliedConfig einführen
- Status: IN PROGRESS
- Owner: Lead Coderaffe
- Code-Orte:
internal/app/engine.go
internal/control/control.go
- ggf. Config-/Statusmodelle
- Ziel:
API und Runtime sollen trennen zwischen:
- gewünschter Konfiguration
- tatsächlich angewandter Konfiguration
- aktuellem Runtime-Zustand
- Nachweis:
internal/control/control.go wartet mit Snapshot-Updates, bis LivePatch erfolgreich war.
internal/control/control_test.go deckt ab, dass abgelehnte Live-Updates keine neue GET /config-Ansicht schreiben.
- Restrisiken:
- Die API liefert noch nicht beide Sichten gleichzeitig; weitere Workstreams müssen Desired/Applied explizit zurückgeben.
WS-03 Entscheidungslog
| Datum |
Entscheidung |
Notiz |
| 2026-04-05 |
CFG-SEM-001: fm.outputDrive |
Live-Validierung auf 0..10 angeglichen, Tests angepasst, Parameterinventar dokumentiert. |
| 2026-04-05 |
WS-03-T3: Desired/Applied-Gate |
Control-API zeigt Snapshots nur noch, wenn LivePatch erfolgreich angewendet wurde; Tests verhindern irreführende Wunschwerte. |
WS-03 Verifikation
| Datum |
Fokus |
Ergebnis |
| 2026-04-05 |
go test ./... |
✅ Bestätigt Engine.UpdateConfig, LivePatch und Parameter-Range sowie Inventar-Dokumentation. Neue Control-Tests sichern Desired/Applied-Gate. |
WS-01 — Deterministische Echtzeit-TX-Pipeline mit entkoppeltem Writer
Priorität: P0
Gesamtstatus: IN PROGRESS
Ziel
Generator/Upsampler und Hardwarewriter werden als getrennte Stufen mit kleinem, kontrolliertem Frame-Puffer betrieben.
Aktueller Stand
- Der TX-Pfad ist laut Konzept aktuell noch synchron gekoppelt:
GenerateFrame -> optional FMUpsampler.Process -> driver.Write
- Das ist elegant, aber nicht pro-level-hart gegenüber Write-Spikes und Blockaden.
Aufgaben
WS-01-T1 — FrameQueue einführen
- Status: VERIFIED
- Owner: Lead Coderaffe
- Code-Orte:
internal/output/frame_queue.go
internal/output/frame_queue_test.go
internal/app/engine.go
- Ziel:
Bounded Queue mit fester Kapazität, sichtbarem Füllstand, Counter- / Statistikzugriff und klarer Trennung zwischen Generator und Writer.
- Zu entscheiden:
- Puffern vor oder nach Upsampling → Device-Frame-Ebene (Queue lebt nach dem Upsampler) für Writer-Simplifizierung.
- Referenzkapazität:
runtime.frameQueueCapacity (default 3) bleibt konfigurierbar.
- Akzeptanzpunkte:
- Keine unbounded Queue.
- Fill-Level (High/Low) ist aus
QueueStats sichtbar.
- Drop/Repeat/Mute-Counter sind vorhanden und testbar.
- Nachweis:
FrameQueue-Implementierung (internal/output/frame_queue.go) liefert kapazitätsgesteuerte Push/Pop-Logik und Counters.
- Engine-Run nutzt Queue vor dem Writer und zeigt
QueueStats in EngineStats.
- Tests (
internal/output/frame_queue_test.go + go test ./...) decken Push/Pop, Timeout-Counters und Stats ab.
- Restrisiken:
- Die Queue wird aktuell synchron getrieben; ein dedizierter Writer-Worker fehlt noch.
- Queue-Close erwartet, dass Generator/Writer vor dem Schließen stoppen, sonst droht Panik beim Schreiben.
WS-01-T2 — Writer-Worker einführen
- Status: VERIFIED
- Owner: Lead Coderaffe
- Code-Orte:
internal/app/engine.go (run loop, writerLoop, cloneFrame, Stats)
internal/dsp/* (FMUpsampler / Resampler copy GeneratedAt für Cycle-Metriken)
- Ziel:
Generator/Upsampler liefern Frames in die FrameQueue,
driver.Write() läuft nur noch im dedizierten Writer.
- Akzeptanzpunkte:
writerLoop() ist die einzige Stelle mit driver.Write() und zieht aus der Queue.
- FrameQueue ist ein echter Puffer (Generator klont Frames, Writer poppt) und
EngineStats.Queue zeigt den Füllstand.
- Write- und Cycle-Latenzen plus
LateBuffers bleiben in EngineStats sichtbar (MaxWriteMs, LateBuffers, MaxCycleMs).
- Nachweis:
go test ./... (Engine + Queue + DSP) läuft erfolgreich.
EngineStats berichtet weiterhin über Queue-/Writer-Metriken.
- Restrisiken:
- Frame-Klonierung pro Chunk erhöht Heap-Pressure; spätere Workstreams sollten Pooling / Zero-Copy prüfen.
WS-01-T3 — Supervisor-Schicht einführen
- Status: TODO
- Owner: offen
- Code-Orte:
- Ziel:
Queue-Füllstand, Late-Rate und Fehlerhäufigkeit überwachen und in Runtime-Zustände überführen.
- Akzeptanzpunkte:
- State-Entscheidungen sind explizit
- kein implizites Weiterwursteln bei Schieflage
Offene Architekturfragen
- Ist
capacity_frames = 3 ein guter Startwert oder nur Konzept-Default?
- Sollte im Fault-Fall
repeat last safe frame erlaubt sein oder von Anfang an nur mute?
- Wie eng koppeln wir WS-01 mit WS-02, ohne Overengineering zu erzeugen?
WS-01 Entscheidungslog
| Datum |
Entscheidung |
Notiz |
| 2026-04-05 |
FrameQueue mit Engine-Integration |
Queue lebt nach dem Upsampler auf DeviceFrame-Ebene, Kapazität via runtime.frameQueueCapacity, EngineStats zeigt QueueStats, Tests decken Timeouts und Counters ab. |
WS-01 Verifikation
| Datum |
Fokus |
Ergebnis |
| 2026-04-05 |
FrameQueue + Engine integration |
✅ go test ./... (im internal-Modul incl. frame_queue_test.go) |
WS-02 — Explizite Runtime-State-Maschine und Fault-Handling
Priorität: P0
Gesamtstatus: TODO
Ziel
Einführen eines klaren Betriebsmodells mit Fault-, Recovery- und Muted-Zuständen.
Zielzustände laut Konzept
idle
arming
prebuffering
running
degraded
muted
faulted
stopping
Aufgaben
WS-02-T1 — Fault-Klassifikation definieren
- Status: TODO
- Owner: offen
- Beispiele:
- Treiberfehler
- Write-Time-Budget überschritten
- Queue leer
- Queue dauerhaft kritisch
- Selbsttest fehlgeschlagen
- unerlaubtes Live-Update
WS-02-T2 — Reaktionsstrategie definieren
- Status: TODO
- Owner: offen
- Ziel:
Pro Fehlerklasse klar definieren:
- warn only
- degraded
- muted
- faulted
WS-02-T3 — Fault-Historie und Event-Log einführen
- Status: TODO
- Owner: offen
- Ziel:
Zustandswechsel und Faults auditierbar machen.
Offene Designfragen
- Wie fein granular darf die State-Maschine werden, ohne unwartbar zu werden?
- Welche Transitionen sind wirklich produktiv relevant und welche nur „theoretisch schön“?
WS-02 Entscheidungslog
WS-02 Verifikation
WS-04 — Observability, Telemetrie und Diagnosefähigkeit
Priorität: P1
Gesamtstatus: TODO
Ziel
Vollständige Sichtbarkeit auf Runtime, Queue, Writer, Generator, RF-Selbsttests und API-Aktivität schaffen.
Aufgaben
WS-04-T1 — Strukturiertes Logging
- Status: TODO
- Owner: offen
WS-04-T2 — Prometheus-/Metrics-Schicht
- Status: TODO
- Owner: offen
WS-04-T3 — Debug-/Profiling-Endpunkte
- Status: TODO
- Owner: offen
Gewünschte Beispielmetriken
engine_chunks_generated_total
engine_late_buffers_total
engine_fault_transitions_total
writer_write_duration_seconds
queue_fill_ratio
queue_dropped_frames_total
queue_muted_frames_total
driver_write_errors_total
audio_stream_underruns_total
audio_stream_overflows_total
rf_selftest_pilot_db
rf_selftest_rds_57k_db
WS-04 Entscheidungslog
WS-04 Verifikation
WS-05 — Sichere und erwachsene Control-Plane
Priorität: P1 / P3-nah
Gesamtstatus: TODO
Ziel
API transport- und anwendungsseitig härten, state-aware machen und auditierbar gestalten.
Aufgaben
WS-05-T1 — Auth und Deploy-Modi definieren
- Status: TODO
- Owner: offen
- Zielmodi:
- localhost-only
- trusted-lan
- secured-remote
WS-05-T2 — HTTP-Server härten
- Status: TODO
- Owner: offen
- Mindestpunkte:
- ReadTimeout
- WriteTimeout
- IdleTimeout
- ReadHeaderTimeout
- Body-Size-Limits
- Content-Type-Validierung
- Method Enforcement
WS-05-T3 — API semantisch aufräumen
- Status: TODO
- Owner: offen
- Ziel:
- DesiredConfig vs AppliedConfig vs RuntimeState
- idempotente Start/Stop-Endpunkte
- transaktionsartige Apply-/Reject-Antworten
- Audit-Log pro Eingriff
Frühe Quick-Wins
Diese Punkte könnten ggf. vorgezogen werden, auch wenn WS-05 formal nach WS-01/02 kommt:
- HTTP-Timeouts
- Body-Limits
- sicherer Standard-Bind-Modus
WS-05 Entscheidungslog
WS-05 Verifikation
WS-06 — Hardware-in-the-loop und externe RF-Wahrheitsprüfung
Priorität: P2
Gesamtstatus: TODO
Ziel
Nicht nur intern richtig rechnen, sondern extern nachweisen, dass tatsächlich korrekt gesendet wird.
Status
- Konzept vorhanden
- noch kein eingetragener HIL-Arbeitsstand in diesem Dokument
Offene Kernfragen
- Welches Referenz-Setup wird verbindlich?
- Welche Testfrequenz / Standarddauer / Schutzmaßnahmen gelten?
- Welcher externe Decoder / Empfänger gilt als Referenz?
WS-07 — Device-aware Capability- und Kalibrierungsmodell
Priorität: P2
Gesamtstatus: TODO
Ziel
Fähigkeiten und Kalibrierungen nicht implizit, sondern explizit pro Device modellieren.
Noch offen
- Capability-Schema konkretisieren
- Kalibrierungsprofil definieren
- Device-aware Validation einbauen
WS-08 — Signal-Selbstüberwachung im Betrieb
Priorität: P2
Gesamtstatus: TODO
Ziel
Pilot, Stereo, RDS und Composite-Anomalien im Betrieb erkennen.
Noch offen
- Goertzel/FFT-Strategie festlegen
- Schwellwerte definieren
- in Fault-Logik einspeisen
WS-09 — Teststrategie erweitern
Priorität: P3/P4-nah
Gesamtstatus: TODO
Ziel
Von Unit-Tests zu echter Qualitätsabsicherung: Golden Vectors, Long-Run, Race, Fuzzing, API-Mutation, HIL.
Noch offen
- Testpyramide konkretisieren
- Nightly-/CI-Fähigkeit bestimmen
WS-10 — Service-Reife, Packaging und Reproduzierbarkeit
Priorität: P4
Gesamtstatus: TODO
Ziel
Build-, Release- und Betriebsartefakte reproduzierbar und teamtauglich machen.
Noch offen
- Build-Metadaten
- Service-Units
- Config-Versionierung / Migration
5. Übergreifende Regeln
Musts
- Jeder neue Runtime-Zustand muss per API und Telemetrie sichtbar sein.
- Jede Recovery-, Drop- oder Mute-Strategie braucht Counter, Logs und Tests.
- Keine neue Config-Option ohne klaren Typ, Bereich, Einheit, Default und Hot-Reload-Klassifikation.
- Hardware-nahe Änderungen brauchen mindestens Simulations- und HIL-Validierung.
- Alle Faults müssen eine maschinenlesbare Ursache und eine menschenlesbare Zusammenfassung haben.
Must Not
- Keine unbounded Queues.
- Keine stillen Fallbacks ohne Telemetrie.
- Keine teilweise angewandten Live-Config-Änderungen ohne explizite Rückmeldung.
- Keine unterschiedlichen Grenzwerte zwischen Config, API und Runtime.
- Keine sicherheitsrelevanten HTTP-Endpunkte ohne Härtung im Remote-Betrieb.
6. Aktuelle offene Entscheidungen
| ID |
Status |
Frage |
Notiz |
| DEC-001 |
RESOLVED |
Puffern wir auf CompositeFrame- oder DeviceFrame-Ebene? |
Queue lebt nach dem Upsampler (DeviceFrame-Ebene) gemäß internal/app/engine.go-Integrationsschleife. |
| DEC-002 |
OPEN |
Fault-Recovery zuerst mit mute, repeat last safe frame oder beidem? |
Muss technisch und RF-seitig sauber bewertet werden |
| DEC-003 |
OPEN |
Ziehen wir minimale WS-05-Basis-Härtungen vor? |
Timeouts/Body-Limits evtl. früher sinnvoll |
| DEC-004 |
OPEN |
Wie gross/simpel halten wir die erste State-Maschine? |
Gefahr von Overengineering |
7. Nächste sinnvolle Schritte
Empfohlener Start
- WS-03-T1 Parameterinventar erstellen (abgeschlossen)
- bekannte Inkonsistenzen (CFG-SEM-001, CTL-UX-001) konkret verifizieren
- DesiredConfig / AppliedConfig / RuntimeState Zielmodell grob skizzieren
- Danach Architekturarbeit an WS-01 + WS-02 starten
- Aktuell: WS-01-T2 Writer-Worker einführen (Queue → Driver), danach WS-01-T3 Supervisor + WS-02 Runtime-State.
Vor dem ersten grossen Umbau klären
- Was ist „minimal sinnvoll“ für Milestone 1?
- Welche Dinge sind harte Must-haves und welche nur spätere Veredelung?
- Wo wollen wir bewusst nicht sofort maximal abstrahieren?
8. Änderungsprotokoll
| Datum |
Änderung |
Person / Agent |
| 2026-04-05 |
Initiales Arbeitsdokument aus fm-rds-tx_pro_runtime_hardening_concept.json erstellt |
Alfred |