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:
TODO → noch nicht begonnenIN PROGRESS → aktiv in ArbeitBLOCKED → sinnvoll erkannt, aber blockiertDONE → umgesetztVERIFIED → umgesetzt und sinnvoll geprüftDEFERRED → bewusst nach hinten verschobenREJECTED → bewusst verworfenEin Punkt gilt erst als wirklich fertig, wenn eingetragen ist:
Wenn wir an einem Workstream arbeiten, soll dieses Dokument mitgezogen werden.
Kein „ist im Kopf klar“. Der Stand kommt hier rein.
Umsetzung (WS-01)Entkoppelter TX-Pfad (FrameQueue + Writer)WS-01 Deterministische Echtzeit-TX-Pipeline mit entkoppeltem WriterWS-03 Semantische Korrektheit und konsistent angewandte Config (abgeschlossen)| 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 |
| 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 | RESOLVED | handleAudioStream() beschreibt --audio-http; der CLI-Schalter ist nun vorhanden und setzt den Stream-Puffer für /audio/stream direkt. |
internal/control/control.go, cmd/fmrtx/main.go |
| 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 |
Priorität: P0
Gesamtstatus: IN PROGRESS
Ein einziger, eindeutig definierter Parameterraum. Jeder Wert hat exakt eine Bedeutung und identische Constraints in Config, HTTP-API, Runtime und Telemetrie.
Wenn Semantik und Grenzwerte nicht sauber vereinheitlicht sind, bauen spätere Runtime- und Fault-Mechanismen auf unstabilem Fundament.
internal/config/config.gointernal/app/engine.gointernal/control/control.gointernal/offline/generator.godocs/ws-03-parameter-inventory.md enthält das inventarisierte Parameter-Tableau und referenziert Config/Control/Engine.internal/control/control.go → LivePatch dokumentiert.internal/config/config.gointernal/app/engine.gointernal/app/engine_test.gointernal/control/control.goConfig.Validate(), Runtime-Update-Pfade und API-Patch-Validierung dürfen nicht divergieren.fm.outputDriveoutputDrive-Validation in Engine.UpdateConfig jetzt 0..10 (wie Config.Validate).go test ./...) fangen neue Range ab und besitzen aktualisierten engine_test-Check.txBridge und LivePatch (control) → LiveConfigUpdate.internal/app/engine.gointernal/control/control.gointernal/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.| 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. |
| 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. |
Priorität: P0
Gesamtstatus: IN PROGRESS
Generator/Upsampler und Hardwarewriter werden als getrennte Stufen mit kleinem, kontrolliertem Frame-Puffer betrieben.
GenerateFrame -> optional FMUpsampler.Process -> driver.Writeinternal/output/frame_queue.gointernal/output/frame_queue_test.gointernal/app/engine.goruntime.frameQueueCapacity (default 3) bleibt konfigurierbar.QueueStats sichtbar.queue.health) liefert critical, low oder normal aus dem Fill-Level. EngineStats.queue zeigt den Status ebenfalls.FrameQueue-Implementierung (internal/output/frame_queue.go) liefert kapazitätsgesteuerte Push/Pop-Logik und Counters.QueueStats in EngineStats.internal/output/frame_queue_test.go + go test ./...) decken Push/Pop, Timeout-Counters, Stats und den neuen Queue-Health-Indikator ab.internal/app/engine.go (run loop, writerLoop, cloneFrame, Stats)internal/dsp/* (FMUpsampler / Resampler copy GeneratedAt für Cycle-Metriken)driver.Write() läuft nur noch im dedizierten Writer.writerLoop() ist die einzige Stelle mit driver.Write() und zieht aus der Queue.EngineStats.Queue zeigt den Füllstand.LateBuffers bleiben in EngineStats sichtbar (MaxWriteMs, LateBuffers, MaxCycleMs).go test ./... (Engine + Queue + DSP) läuft erfolgreich.EngineStats berichtet weiterhin über Queue-/Writer-Metriken.internal/app/engine.gocapacity_frames = 3 ein guter Startwert oder nur Konzept-Default?repeat last safe frame erlaubt sein oder von Anfang an nur mute?| 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. |
| 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. |
Priorität: P0
Gesamtstatus: IN PROGRESS
Einführen eines klaren Betriebsmodells mit Fault-, Recovery- und Muted-Zuständen.
EngineStats liefert das Runtime-State-Feld (idle, arming, prebuffering, running) und reagiert nun auf Queue-Gesundheit bzw. späte Buffers, indem es bei low/critical oder späten Buffern in degraded wechselt und sonst auf running zurückkehrt.
evaluateRuntimeState escalates persistent critical queues from degraded to muted, while FaultReasonQueueCritical surfaces muted severity so the mute transition stays observable.
evaluateRuntimeState now waits for a short healthy streak before leaving muted, logging a degraded-severity recovery event once the queue settles.
Persistent queue-critical streaks while muted now escalate to faulted with FaultSeverityFaulted, keeping RuntimeStateFaulted observable.
EngineStats and txBridge now expose transition/fault counters plus lastFault, surfacing the new telemetry through /runtime.
Control-plane UI now renders those WS-02 transition counters, fault count, and last-fault summary so operators can watch runtime escalations without digging through logs.
Control-plane now exposes POST /runtime/fault/reset so operators can acknowledge faulted state; TestRuntimeFaultReset* covers the new HTTP path.
Control-plane UI now also offers a Danger Zone Reset Fault button that calls the same endpoint so operators can acknowledge faults from the dashboard.
Control-plane UI now posts an ops toast/log entry whenever the runtime state shifts so escalations and manual acknowledgements are immediately visible.
idlearmingprebufferingrunningdegradedmutedfaultedstopping| Datum | Entscheidung | Notiz |
|---|---|---|
| 2026-04-05 | Faulted escalation on persistent critical queue | muted now surfaces RuntimeStateFaulted when queue health stays critical and metrics capture every transition. |
| 2026-04-05 | Manual fault reset endpoint | Added POST /runtime/fault/reset so operators can acknowledge faulted before the supervisor re-enters recovery. |
| 2026-04-05 | Fault-reset UI shortcut | Danger Zone now hosts a Reset Fault button wired to /runtime/fault/reset so operators get an in-app acknowledgement path without manual HTTP calls. |
| 2026-04-06 | Runtime transition visibility cue | Control UI now posts toast/log entries for runtime state shifts so ops instantly sees escalations and manual reset acknowledgements. |
| Datum | Fokus | Ergebnis |
|---|---|---|
| 2026-04-05 | Faulted path + transition counters | go test ./... exercises TestEngineFaultsAfterMutedCriticalStreak and TestRuntimeTransitionCounters, while /runtime now surfaces engine.degradedTransitions, engine.mutedTransitions, engine.faultedTransitions, engine.faultCount, and the last fault via txBridge. |
| 2026-04-05 | Runtime fault reset API | go test ./... now runs TestRuntimeFaultReset*, verifying the new HTTP path and controller error scenarios. |
| 2026-04-06 | Runtime transition visibility | ✅ go test ./...; manual UI smoke verification still pending to ensure the toast/log flow shows every runtime shift. |
Priorität: P1
Gesamtstatus: TODO
Vollständige Sichtbarkeit auf Runtime, Queue, Writer, Generator, RF-Selbsttests und API-Aktivität schaffen.
engine_chunks_generated_totalengine_late_buffers_totalengine_fault_transitions_totalwriter_write_duration_secondsqueue_fill_ratioqueue_dropped_frames_totalqueue_muted_frames_totaldriver_write_errors_totalaudio_stream_underruns_totalaudio_stream_overflows_totalrf_selftest_pilot_dbrf_selftest_rds_57k_dbPriorität: P1 / P3-nah
Gesamtstatus: TODO
API transport- und anwendungsseitig härten, state-aware machen und auditierbar gestalten.
Diese Punkte könnten ggf. vorgezogen werden, auch wenn WS-05 formal nach WS-01/02 kommt:
| Datum | Fokus | Ergebnis |
|---|---|---|
| 2026-04-05 | /audio/stream rejects non-POST requests |
TestAudioStreamRejectsNonPost enforces POST-only access to /audio/stream before a stream source is configured |
Priorität: P2
Gesamtstatus: TODO
Nicht nur intern richtig rechnen, sondern extern nachweisen, dass tatsächlich korrekt gesendet wird.
Priorität: P2
Gesamtstatus: TODO
Fähigkeiten und Kalibrierungen nicht implizit, sondern explizit pro Device modellieren.
Priorität: P2
Gesamtstatus: TODO
Pilot, Stereo, RDS und Composite-Anomalien im Betrieb erkennen.
Priorität: P3/P4-nah
Gesamtstatus: TODO
Von Unit-Tests zu echter Qualitätsabsicherung: Golden Vectors, Long-Run, Race, Fuzzing, API-Mutation, HIL.
Priorität: P4
Gesamtstatus: TODO
Build-, Release- und Betriebsartefakte reproduzierbar und teamtauglich machen.
| 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 |
| Datum | Änderung | Person / Agent |
|---|---|---|
| 2026-04-05 | Initiales Arbeitsdokument aus fm-rds-tx_pro_runtime_hardening_concept.json erstellt |
Alfred |