# 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: 1. **Code-Ort(e)** 2. **Was geändert wurde** 3. **Wie verifiziert wurde** 4. **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:** - `fm.outputDrive` - **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. - Queue-Health-Indikator (`queue.health`) liefert `critical`, `low` oder `normal` aus dem Fill-Level. EngineStats.`queue` zeigt den Status ebenfalls. - 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, Stats und den neuen Queue-Health-Indikator 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:** - `internal/app/engine.go` - **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. | | 2026-04-05 | Queue-Health-Indikator | `QueueStats.Health` gibt `critical`/`low`/`normal` zurück und `txBridge` leitet `EngineStats.Queue` ins `/runtime`-JSON. | | 2026-04-05 | Runtime-Indikator | `EngineStats.RuntimeIndicator` kombiniert `queue.health` + `lateBuffers`, `/runtime` zeigt `engine.runtimeIndicator`. | | 2026-04-05 | /status runtime indicator | `/status` reuses `txBridge.TXStats()` and now reports `runtimeIndicator` alongside the config snapshot for quick ops. | | 2026-04-05 | /status queue stats | `/status` spiegelt das `queue`-Objekt aus `txBridge.TXStats()` für schnelle Queue-Checks, API-Doku und `TestStatusReportsQueueStats` fangen den neuen Key ab. | ## WS-01 Verifikation | Datum | Fokus | Ergebnis | |---|---|---| | 2026-04-05 | FrameQueue + Engine integration | ✅ `go test ./...` (im `internal`-Modul incl. `frame_queue_test.go`) | | 2026-04-05 | Queue-Health-Indikator | go test ./... deckt `TestFrameQueueHealthIndicator` und `queue.health` ab. | | 2026-04-05 | Runtime-Indikator | OK `go test ./...` deckt `runtimeIndicator` sowie `/runtime`-Exposition von `engine.runtimeIndicator`. | | 2026-04-05 | Runtime API queue health | ✅ `/runtime` liefert jetzt `engine.queue.health` dank `txBridge.TXStats`. | | 2026-04-05 | /status runtime indicator | ✅ `/status` gibt jetzt `runtimeIndicator` aus (`control_test` deckt den neuen Key). | | 2026-04-05 | /status queue stats | ✅ `TestStatusReportsQueueStats` plus `docs/API.md` zeigen, dass `queue` korrekt durchgereicht wird. | --- # 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 - Noch leer ## WS-02 Verifikation - Noch leer --- # 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 - Noch leer ## WS-04 Verifikation - Noch leer --- # 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 - Noch leer ## WS-05 Verifikation - Noch leer --- # 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 1. **WS-03-T1 Parameterinventar erstellen** *(abgeschlossen)* 2. **bekannte Inkonsistenzen (CFG-SEM-001, CTL-UX-001) konkret verifizieren** 3. **DesiredConfig / AppliedConfig / RuntimeState Zielmodell grob skizzieren** 4. Danach Architekturarbeit an **WS-01 + WS-02** starten 5. **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 |