Quellcode durchsuchen

docs: add pro runtime hardening concept

tags/v0.9.0
Jan Svabenik vor 1 Monat
Ursprung
Commit
9c70795fe2
1 geänderte Dateien mit 831 neuen und 0 gelöschten Zeilen
  1. +831
    -0
      fm-rds-tx_pro_runtime_hardening_concept.json

+ 831
- 0
fm-rds-tx_pro_runtime_hardening_concept.json Datei anzeigen

@@ -0,0 +1,831 @@
{
"document_type": "technical_concept",
"language": "de",
"audience": [
"AI-Entwicklerteam",
"Reviewer",
"Maintainer"
],
"project": {
"name": "fm-rds-tx",
"goal": "Aus dem bestehenden FM-Stereo/RDS-TX-System ein technisch sauberes, deterministisches, messbares und betriebsfestes Pro-Level-System machen.",
"primary_priority": "Technische Perfektion",
"secondary_priority": "Sinnvolle Umsetzungsreihenfolge mit maximalem Risikoabbau zuerst"
},
"executive_summary": {
"current_strengths": [
"Saubere Modultrennung zwischen Generator, DSP, Control, Audio, Backend und Plattform.",
"Persistenter DSP-Zustand ist bereits vorhanden, insbesondere im Generator und im FM-Upsampler.",
"Live-Updates werden bereits über atomare Snapshots bzw. Pointer modelliert.",
"Es existieren bereits viele Unit-Tests sowie spektrale Blackbox-Tests für 19 kHz, 38 kHz und 57 kHz."
],
"current_limitations": [
"Der TX-Pfad in internal/app/engine.go ist noch ein einzelner synchroner Generate/Upsample/Write-Loop ohne entkoppelten Echtzeitpuffer.",
"Die Runtime-Recovery ist schwach: bei Fehlern wird nur gezählt, geloggt und gewartet; es gibt keinen expliziten Fault-State mit deterministischem Fallback.",
"Die Control-Plane in internal/control/control.go ist funktional, aber nicht hart genug: keine Authentisierung, keine Transporthärtung, keine Request-Limits, keine Timeouts, keine Audit-Trails.",
"Validation und Runtime-Semantik sind nicht überall deckungsgleich; Beispiel: fm.outputDrive wird in config.Validate() bis 10 akzeptiert, in Engine.UpdateConfig() aber nur bis 3.",
"Device-Abstraktion ist brauchbar, aber noch nicht streng genug capability- und kalibrierungsgetrieben.",
"Observability ist noch zu schwach für echten Dauerbetrieb und reproduzierbare Fehleranalyse."
],
"core_statement": "Der DSP-Kern ist nah an ernsthaft brauchbar. Der Abstand zu Pro-Level liegt primär in Betriebssicherheit, Observability, Hardwarevalidierung und strenger Runtime-Kontrolle."
},
"repo_grounding": {
"confirmed_code_touchpoints": [
{
"path": "internal/app/engine.go",
"observation": "TX läuft aktuell in einer einzelnen Goroutine als synchroner Zyklus: GenerateFrame -> optional FMUpsampler.Process -> driver.Write. Kein echter Producer/Consumer-Puffer zwischen Generator und Hardwarewriter."
},
{
"path": "internal/offline/generator.go",
"observation": "Generator hat bereits persistenten Zustand, LiveParams per atomic.Pointer und sinnvolle DSP-Kette inklusive optionalem BS.412-Limiter."
},
{
"path": "internal/control/control.go",
"observation": "HTTP-Control existiert bereits, aber ohne sichtbare Authentisierung, ohne Server-Timeout-Konfiguration und ohne harte API-Grenzen."
},
{
"path": "internal/config/config.go",
"observation": "Validation ist vorhanden, aber semantisch nicht überall konsistent mit Laufzeitregeln."
},
{
"path": "internal/platform/soapy.go",
"observation": "Capabilities und RuntimeStats existieren als Ansatz, reichen aber noch nicht für eine wirklich harte device-aware Steuerung."
},
{
"path": "internal/audio/stream.go",
"observation": "Lock-freier SPSC-Ringbuffer für Live-Audio ist bereits vorhanden und kann als Referenz für deterministische Buffer-Designs dienen."
}
],
"confirmed_inconsistencies": [
{
"id": "CFG-SEM-001",
"description": "fm.outputDrive wird in Config.Validate() bis 10 akzeptiert, die Fehlermeldung spricht aber von 0..3, und Engine.UpdateConfig() erzwingt tatsächlich 0..3."
},
{
"id": "CTL-UX-001",
"description": "handleAudioStream() nennt in der Fehlermeldung '--audio-http', im CLI ist dieser Schalter nicht als gleichwertiger offensichtlicher Bedienpfad bestätigt."
}
]
},
"design_principles": [
"Kein verstecktes Glück: Jeder relevante Echtzeit- oder RF-Pfad muss deterministisch, messbar und reproduzierbar sein.",
"Fail-safe statt fail-weird: Bei Unsicherheit oder Überlast lieber definiert muten oder faulten als kaputt weiterzusenden.",
"Eine Runtime-Wahrheit: Konfiguration, Live-State und tatsächlich angewandte Hardware-/DSP-Parameter dürfen nicht auseinanderlaufen.",
"Hardware ist Wahrheit: IQ-Dateien und Unit-Tests reichen nicht; es braucht Hardware-in-the-loop und externe Decoder-/Messvalidierung.",
"Observability ist Pflicht, nicht Luxus: Kein Pro-Level ohne Metriken, strukturierte Logs, Fault-Telemetrie und reproduzierbare Regressionen.",
"Keine implizite Semantik: Alle Parameter müssen in Config, API, Runtime und Telemetrie exakt dasselbe bedeuten."
],
"priority_model": {
"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"
},
"workstreams": [
{
"id": "WS-01",
"priority": "P0",
"title": "Deterministische Echtzeit-TX-Pipeline mit entkoppeltem Writer",
"why": "Der aktuelle Single-Loop ist elegant, aber anfällig gegen Write-Spikes, Scheduling-Jitter und hardwarebedingte Blockaden. Pro-Level verlangt Entkopplung zwischen Erzeugung und Ausgabe.",
"objective": "Generator/Upsampler und Hardwarewriter werden als getrennte Stufen mit kleinem, kontrolliertem Frame-Puffer betrieben. Der Writer darf kurzfristige Timing-Jitter absorbieren, ohne sofort den gesamten TX-Zyklus zu ruinieren.",
"target_architecture": {
"pipeline": [
"control-plane",
"runtime supervisor",
"generator worker",
"optional upsampler worker",
"bounded frame queue",
"writer worker",
"driver"
],
"queue_policy": {
"type": "bounded ring queue",
"capacity_frames": 3,
"default_behavior": "Producer füllt vor, Writer sendet in Echtzeit, Supervisor überwacht Queue-Füllstand",
"allowed_strategies": [
"block producer kurzzeitig",
"repeat last safe frame im Fault-Recovery-Modus",
"mute frame im Sicherheitsmodus"
],
"forbidden_strategies": [
"unbounded buffering",
"still und heimlich alte Frames verwerfen ohne Counter/Log",
"dynamisches Verhalten ohne Telemetrie"
]
}
},
"implementation_tasks": [
{
"id": "WS-01-T1",
"title": "FrameQueue einführen",
"details": [
"Neue interne Queue-Struktur für CompositeFrame oder DeviceFrame einführen.",
"Explizit festlegen, ob vor oder nach FMUpsampler gepuffert wird. Empfehlung: Puffern auf Device-Frame-Ebene, damit der Writer nur noch sendet.",
"FrameQueue muss feste Kapazität, Füllstand, High-Watermark, Low-Watermark und Drop-/Mute-/Repeat-Counter liefern."
]
},
{
"id": "WS-01-T2",
"title": "Writer-Worker einführen",
"details": [
"Writer läuft in eigener Goroutine und besitzt alleinige Ownership über driver.Write().",
"Nur der Writer darf Write- und Tune-nahe Timinginteraktionen mit dem Treiber koordinieren.",
"Write-Dauer, Blockzeiten und Late-Events werden pro Frame gemessen."
]
},
{
"id": "WS-01-T3",
"title": "Supervisor-Schicht einführen",
"details": [
"Supervisor bewertet Queue-Füllstand, Late-Rate, Fehlerhäufigkeit und entscheidet über Normal/Fault/Recovery.",
"Supervisor ist nicht nur Logik, sondern Runtime-State-Maschine."
]
}
],
"acceptance_criteria": [
"Keine direkte synchrone Generate->Write-Kopplung mehr im Hauptpfad.",
"Queue-Füllstand und Write-Latenz sind live sichtbar.",
"Kurzzeitige Write-Spikes führen nicht sofort zu hörbaren Aussetzern oder unkontrolliertem Timing-Kollaps.",
"Langlauf mit 6h Testdauer zeigt keine wachsende Drift im Kontrollpfad und keine ungebremste Fehlereskalation."
],
"affected_files": [
"internal/app/engine.go",
"internal/output/backend.go",
"internal/platform/soapy.go"
],
"example_interfaces": {
"frame_queue_contract": "type FrameQueue interface { Push(frame *output.CompositeFrame) error; Pop(ctx context.Context) (*output.CompositeFrame, error); FillLevel() float64; Depth() int; Capacity() int; Stats() QueueStats }",
"queue_stats_example": {
"capacity": 3,
"depth": 2,
"fillLevel": 0.6667,
"pushTimeouts": 0,
"popTimeouts": 0,
"droppedFrames": 0,
"repeatedFrames": 0,
"mutedFrames": 0
}
}
},
{
"id": "WS-02",
"priority": "P0",
"title": "Explizite Runtime-State-Maschine und Fault-Handling",
"why": "Aktuell existieren im Engine-State nur idle, running, stopping. Das reicht nicht für professionelles Fehlermanagement im Sendebetrieb.",
"objective": "Einführen eines klaren Betriebsmodells mit Fault-, Recovery- und Muted-Zuständen. Jeder kritische Fehlerpfad endet in definiertem Verhalten.",
"target_state_machine": {
"states": [
"idle",
"arming",
"prebuffering",
"running",
"degraded",
"muted",
"faulted",
"stopping"
],
"transition_examples": [
{
"from": "idle",
"to": "arming",
"trigger": "StartTX angefordert und Grundvalidierung erfolgreich"
},
{
"from": "arming",
"to": "prebuffering",
"trigger": "Driver gestartet, Queue erstellt, Generator bereit"
},
{
"from": "prebuffering",
"to": "running",
"trigger": "Queue-Minimum erreicht"
},
{
"from": "running",
"to": "degraded",
"trigger": "Late-Rate oberhalb Schwellwert oder Queue-Füllstand wiederholt kritisch"
},
{
"from": "degraded",
"to": "muted",
"trigger": "Writer kann keine sichere Ausgabe mehr garantieren"
},
{
"from": "muted",
"to": "faulted",
"trigger": "Persistenter Treiberfehler oder Recovery gescheitert"
},
{
"from": "muted",
"to": "running",
"trigger": "Queue und Treiber wieder stabil"
}
]
},
"implementation_tasks": [
{
"id": "WS-02-T1",
"title": "Fault-Klassifikation definieren",
"details": [
"Treiberfehler",
"Write-Time-Budget überschritten",
"Queue leer",
"Queue permanent überfüllt",
"Signal-Selbsttest fehlgeschlagen",
"unerlaubte Live-Konfigurationsänderung"
]
},
{
"id": "WS-02-T2",
"title": "Reaktionsstrategie pro Fehlerklasse definieren",
"details": [
"Warnen ohne Zustandswechsel",
"degraded mit Countern",
"muted mit stiller Trägerstrategie oder kompletter TX-Stille",
"faulted mit manueller oder automatischer Recovery"
]
},
{
"id": "WS-02-T3",
"title": "Event-Log und Fault-Historie einführen",
"details": [
"Jeder Zustandswechsel ist auditierbar.",
"Faults enthalten Ursache, Timestamp, Metriken und letzten bekannten Runtime-Kontext."
]
}
],
"acceptance_criteria": [
"Jede kritische Fehlersituation führt in einen expliziten Zustand statt in implizites Weiterlaufen.",
"Der aktuelle Runtime-State ist über API und Telemetrie jederzeit sichtbar.",
"Degraded/Muted/Faulted lassen sich in Tests gezielt triggern und verifizieren."
],
"affected_files": [
"internal/app/engine.go",
"internal/control/control.go"
],
"example_fault_policy": {
"late_buffer_threshold_per_60s": 10,
"queue_critical_fill_below": 0.1,
"writer_error_burst": 3,
"policy": [
"Bei 1-2 Einzelereignissen nur Counter erhöhen.",
"Ab Burstschwelle auf degraded schalten.",
"Wenn degraded > 5s anhält oder Write wiederholt fehlschlägt -> muted.",
"Wenn muted nicht innerhalb definierter Frist stabilisiert werden kann -> faulted."
]
}
},
{
"id": "WS-03",
"priority": "P0",
"title": "Semantische Korrektheit und harte Config-/Runtime-Konsistenz",
"why": "Technische Perfektion scheitert oft nicht am DSP, sondern an stillen Semantikabweichungen zwischen Config, API, Live-Update und tatsächlicher Laufzeit.",
"objective": "Ein einziger, eindeutig definierter Parameterraum. Jeder Wert hat exakt eine Bedeutung und identische Constraints in Config, HTTP-API, Runtime und Telemetrie.",
"implementation_tasks": [
{
"id": "WS-03-T1",
"title": "Parameterinventar erstellen",
"details": [
"Alle öffentlich und intern verwendeten Parameter inventarisieren.",
"Für jeden Parameter: Typ, Einheit, Bereich, Default, Hot-Reload-Fähigkeit, Safety-Relevanz, Telemetrie-Name."
]
},
{
"id": "WS-03-T2",
"title": "Validation vereinheitlichen",
"details": [
"Config.Validate(), Engine.UpdateConfig() und API-Patch-Validierung dürfen nicht divergieren.",
"Beispiel: outputDrive muss an allen Stellen denselben Bereich haben."
]
},
{
"id": "WS-03-T3",
"title": "AppliedConfig einführen",
"details": [
"Neben DesiredConfig muss es eine AppliedConfig geben.",
"API-Antworten sollen nicht nur sagen, was gewünscht wurde, sondern was tatsächlich übernommen wurde."
]
}
],
"acceptance_criteria": [
"Kein Parameter hat an zwei Stellen unterschiedliche Grenzwerte oder Einheiten.",
"API kann DesiredConfig und AppliedConfig getrennt zurückgeben.",
"Ungültige Hot-Updates werden deterministisch abgelehnt und nicht teilweise angewandt."
],
"affected_files": [
"internal/config/config.go",
"internal/app/engine.go",
"internal/control/control.go"
],
"example_parameter_schema": {
"name": "fm.outputDrive",
"unit": "logical composite drive factor",
"type": "float64",
"range": {
"min": 0.0,
"max": 3.0
},
"default": 1.0,
"hot_reloadable": true,
"safety_class": "medium",
"notes": "Darf nicht mit hardware gain oder RF gain verwechselt werden."
}
},
{
"id": "WS-04",
"priority": "P1",
"title": "Observability, Telemetrie und Diagnosefähigkeit",
"why": "Ohne harte Telemetrie bleibt jedes Timing- oder RF-Problem ratenbasiert. Pro-Level braucht Metriken, strukturierte Logs und Diagnostik-Endpunkte.",
"objective": "Vollständige Sichtbarkeit auf Runtime, Queue, Writer, Generator, RF-Selbsttests und API-Aktivität schaffen.",
"implementation_tasks": [
{
"id": "WS-04-T1",
"title": "Strukturiertes Logging einführen",
"details": [
"Einheitliches Logging-Backend nutzen.",
"Keine verstreuten Printf-only Pfade als primäre Diagnose.",
"Jeder Fault, State-Change und API-Eingriff wird strukturiert geloggt."
]
},
{
"id": "WS-04-T2",
"title": "Prometheus-kompatible Metriken einführen",
"details": [
"Engine-Metriken",
"Writer-Metriken",
"Queue-Metriken",
"RDS-/Pilot-Selbsttest-Metriken",
"Audio-Stream-Metriken",
"Control-Plane-Metriken"
]
},
{
"id": "WS-04-T3",
"title": "Debug- und Profiling-Endpunkte",
"details": [
"pprof optional aktivierbar",
"Build-Info, Git-Commit, Build-Tags, Backend, Plattform und Runtime-Version ausgeben"
]
}
],
"acceptance_criteria": [
"Jeder relevante Betriebsaspekt ist per Runtime-Endpunkt oder Metrics-Endpunkt sichtbar.",
"Fehlerfälle sind anhand von Logs und Countern nachvollziehbar, ohne den Code erneut zu lesen.",
"Langlaufprobleme lassen sich zeitlich korrelieren."
],
"example_metrics": [
"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"
],
"affected_files": [
"internal/app/engine.go",
"internal/control/control.go",
"internal/platform/soapy.go",
"internal/audio/stream.go"
]
},
{
"id": "WS-05",
"priority": "P1",
"title": "Sichere und erwachsene Control-Plane",
"why": "Sobald TX start/stop, Frequenz, RDS-Text oder Live-Audio per HTTP steuerbar sind, ist die Control-Plane ein sicherheitsrelevanter Teil des Systems.",
"objective": "API transport- und anwendungsseitig härten, state-aware machen und auditierbar gestalten.",
"implementation_tasks": [
{
"id": "WS-05-T1",
"title": "Auth und Deploy-Modi definieren",
"details": [
"Mindestens Token-Auth für Remote-Betrieb.",
"Optionale mTLS-Unterstützung für geschützte Infrastrukturen.",
"Explizite Betriebsmodi: localhost-only, trusted-lan, secured-remote."
]
},
{
"id": "WS-05-T2",
"title": "HTTP-Server härten",
"details": [
"ReadTimeout",
"WriteTimeout",
"IdleTimeout",
"ReadHeaderTimeout",
"Body-Size-Limits",
"Content-Type-Validierung",
"Method enforcement"
]
},
{
"id": "WS-05-T3",
"title": "API semantisch aufräumen",
"details": [
"DesiredConfig vs AppliedConfig vs RuntimeState",
"Idempotente Start/Stop-Endpunkte",
"Transaktionsartige Apply-/Reject-Antworten für Patches",
"Audit-Log pro wirksamem Eingriff"
]
}
],
"acceptance_criteria": [
"Kein ungeschützter Remote-TX-Betrieb im Standardmodus.",
"API liefert deterministische und vollständige Antworten.",
"Große oder falsche Requests können das System nicht unkontrolliert stressen."
],
"affected_files": [
"internal/control/control.go",
"cmd/fmrtx/main.go"
],
"example_patch_response": {
"ok": true,
"requestedChangeId": "cfg-2026-04-05T12:00:00Z-0001",
"desired": {
"frequencyMHz": 100.2,
"ps": "JAN FM"
},
"applied": {
"frequencyMHz": 100.2,
"ps": "JAN FM"
},
"state": "running",
"warnings": []
}
},
{
"id": "WS-06",
"priority": "P2",
"title": "Hardware-in-the-loop und externe RF-Wahrheitsprüfung",
"why": "Ein DSP-System ist erst dann pro-tauglich, wenn es auf echter Hardware und mit externem Decoder/Messergebnis wiederholt korrekt ist.",
"objective": "Nightly- oder manuell triggerbare Hardware-Regressionen etablieren, die nicht nur intern, sondern extern prüfen, was tatsächlich gesendet wird.",
"implementation_tasks": [
{
"id": "WS-06-T1",
"title": "Loopback-/Capture-Setup definieren",
"details": [
"Referenz-SDR oder definierter externer Empfänger als Capture-Seite.",
"Leistungsschutz und Dummy-Load-Konzept klar dokumentieren.",
"Standard-Testfrequenz, Standard-Device-Rate und Standard-Testdauer festlegen."
]
},
{
"id": "WS-06-T2",
"title": "Automatisierte Analyse bauen",
"details": [
"Pilotenergie 19 kHz",
"Stereoenergie 38 kHz",
"RDS-Energie 57 kHz",
"Deviation/Composite-Level",
"Trägergenauigkeit",
"RDS-Decodierbarkeit und Fehlerrate",
"Langlaufdrift"
]
},
{
"id": "WS-06-T3",
"title": "Externen Decoder in Regression einbinden",
"details": [
"PS und RT müssen extern decodierbar und stabil sein.",
"Nicht nur intern erzeugte Bits prüfen."
]
}
],
"acceptance_criteria": [
"Definierte Testsignale werden extern reproduzierbar korrekt empfangen.",
"Pilot-, Stereo- und RDS-Komponenten liegen mit stabilen Pegeln an den erwarteten Frequenzen.",
"Langlauftests zeigen keine schleichende Entwertung der Sendekette."
],
"affected_files": [
"internal/offline/spectral_test.go",
"internal/platform/soapy.go",
"scripts/*"
],
"example_hil_report": {
"device": "pluto",
"testDurationMinutes": 30,
"pilot19kDetected": true,
"stereo38kDetected": true,
"rds57kDetected": true,
"rdsDecodeSuccessRate": 0.998,
"maxCarrierErrorHz": 12.0,
"maxLateBuffers": 0,
"result": "pass"
}
},
{
"id": "WS-07",
"priority": "P2",
"title": "Device-aware Capability- und Kalibrierungsmodell",
"why": "Ein generisches Backend-Modell reicht nicht, wenn unterschiedliche SDRs unterschiedliche Raten, Gains, Latenzen und Abweichungen haben.",
"objective": "Pro Gerät bzw. Gerätetyp bekannte Fähigkeiten und Kalibrierungen explizit abbilden.",
"implementation_tasks": [
{
"id": "WS-07-T1",
"title": "Capabilities ausbauen",
"details": [
"Sample-Rate-Sets oder Bereiche",
"Gain-Semantik",
"Frequenzraster",
"MTU-/Buffer-Empfehlungen",
"Minimale stabile Chunkgrößen",
"Tune-Latenzverhalten"
]
},
{
"id": "WS-07-T2",
"title": "Kalibrierungsprofil einführen",
"details": [
"frequencyOffsetHz",
"deviationScale",
"mpxGainCalibration",
"driverChunkRecommendation",
"safeDefaultGain"
]
},
{
"id": "WS-07-T3",
"title": "Device-aware Validation",
"details": [
"Config nicht nur gegen generische Regeln validieren, sondern gegen bekannte Device-Fähigkeiten.",
"Nicht unterstützte Raten oder gefährliche Kombinationen früh blockieren."
]
}
],
"acceptance_criteria": [
"Treiber und Runtime wissen explizit, was das konkrete Device sicher kann.",
"Kalibrierte Geräte liefern reproduzierbarere RF-Ergebnisse.",
"Fehlkonfigurationen werden vor TX-Beginn erkannt."
],
"affected_files": [
"internal/platform/soapy.go",
"internal/config/config.go"
],
"example_calibration_profile": {
"deviceId": "pluto-serial-1234",
"sampleRateHz": 1000000,
"frequencyOffsetHz": -18.0,
"deviationScale": 0.97,
"mpxGainCalibration": 1.03,
"safeDefaultGainDb": -20.0,
"preferredChunkMs": 50
}
},
{
"id": "WS-08",
"priority": "P2",
"title": "Signal-Selbstüberwachung im Betrieb",
"why": "Nur Post-mortem-Messungen reichen nicht. Das System soll im Betrieb merken, wenn Pilot, RDS oder Composite auffällig werden.",
"objective": "Leichtgewichtige In-Band-Selbsttests auf Chunk-Basis oder in Intervallen ausführen und in Fault-Logik einspeisen.",
"implementation_tasks": [
{
"id": "WS-08-T1",
"title": "Chunk-basierte RF-Checks definieren",
"details": [
"Goertzel oder kleine FFT für 19 kHz, 38 kHz und 57 kHz",
"Composite-Clipping- und Pegelindikatoren",
"Optional Deviation-Schätzer"
]
},
{
"id": "WS-08-T2",
"title": "Anomalieerkennung definieren",
"details": [
"Pilot fehlt",
"RDS ungewöhnlich schwach",
"unerwartete Composite-Energieverteilung",
"langsame Drift"
]
}
],
"acceptance_criteria": [
"Runtime kann relevante RF-Anomalien erkennen und melden.",
"Selbsttests sind ausreichend billig, um die Echtzeitfähigkeit nicht zu gefährden."
],
"affected_files": [
"internal/dsp/goertzel.go",
"internal/offline/generator.go",
"internal/app/engine.go"
]
},
{
"id": "WS-09",
"priority": "P3",
"title": "Teststrategie von Unit-Tests zu echter Qualitätsabsicherung erweitern",
"why": "Viele Tests sind gut. Die richtigen Testklassen sind besser. Pro-Level verlangt deterministische Regressionen, Fuzzing und Concurrency-Tests.",
"objective": "Testpyramide so ausbauen, dass Signal, Runtime und API gleichermaßen abgesichert sind.",
"implementation_tasks": [
{
"id": "WS-09-T1",
"title": "Golden-Vector-Tests",
"details": [
"Definierte Inputsignale und erwartete Analysewerte festschreiben.",
"Nicht nur boolsche Pass/Fail-Aussagen, sondern tolerierte numerische Fenster."
]
},
{
"id": "WS-09-T2",
"title": "Long-run Regressionen",
"details": [
"Tausende Chunks durchlaufen lassen.",
"Boundary-Continuity, Drift, Queue-Stabilität, Writer-Stabilität prüfen."
]
},
{
"id": "WS-09-T3",
"title": "Race Detector, Fuzzing und API-Mutation-Tests",
"details": [
"Konfigurationspatches",
"RDS-Texte",
"Audio-Ingest",
"Start/Stop-Rennen",
"gleichzeitige Live-Updates"
]
}
],
"acceptance_criteria": [
"Es gibt Regressionen für DSP, Runtime, API und HIL.",
"Race Detector und Fuzzing finden keine bekannten kritischen Pfade mehr.",
"Nightly-Regressions geben maschinenlesbare Berichte aus."
]
},
{
"id": "WS-10",
"priority": "P4",
"title": "Service-Reife, Packaging und Reproduzierbarkeit",
"why": "Ein System ist nicht professionell, wenn nur der Autor es zuverlässig starten kann.",
"objective": "Saubere Build-, Release- und Betriebsartefakte bereitstellen.",
"implementation_tasks": [
{
"id": "WS-10-T1",
"title": "Reproduzierbare Builds",
"details": [
"Build-Flags, Version, Commit und Tags ins Binary schreiben.",
"Artefakte pro Zielplattform konsistent erzeugen."
]
},
{
"id": "WS-10-T2",
"title": "Service-Units und Beispiel-Deployments",
"details": [
"systemd unit",
"EnvironmentFile-Unterstützung",
"Beispielkonfigurationen pro Backend"
]
},
{
"id": "WS-10-T3",
"title": "Migrations- und Schema-Versionierung",
"details": [
"Config-Versionen einführen.",
"Klare Migrationsstrategie für ältere JSON-Konfigurationen."
]
}
],
"acceptance_criteria": [
"Standardisierte Start- und Betriebswege existieren.",
"Build- und Runtime-Version sind eindeutig sichtbar.",
"Alte Konfigurationen können kontrolliert migriert werden."
]
}
],
"implementation_sequence": [
{
"order": 1,
"workstreams": [
"WS-03",
"WS-01",
"WS-02"
],
"reason": "Erst muss die Semantik stimmen, dann die deterministische Pipeline, dann das Fault-Modell. Sonst baut man saubere Infrastruktur auf falschen Annahmen."
},
{
"order": 2,
"workstreams": [
"WS-04",
"WS-05"
],
"reason": "Sobald Runtime-Struktur sauber ist, müssen Sichtbarkeit und sichere Steuerung folgen. Sonst ist der neue Kern schwer überprüfbar und riskant bedienbar."
},
{
"order": 3,
"workstreams": [
"WS-06",
"WS-07",
"WS-08"
],
"reason": "Jetzt wird die Hardware-Wahrheit und RF-Qualität fest verdrahtet: HIL, Kalibrierung und laufende Signalkontrolle."
},
{
"order": 4,
"workstreams": [
"WS-09",
"WS-10"
],
"reason": "Zum Schluss werden Regressionstiefe, Packaging und Service-Reife maximal professionalisiert."
}
],
"cross_cutting_rules": {
"musts": [
"Jeder neue Runtime-Zustand muss per API und Telemetrie sichtbar sein.",
"Jede neue Recovery- oder Drop-/Mute-Strategie braucht Counter, Logs und Tests.",
"Keine neue Konfigurationsoption 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."
]
},
"concrete_examples": {
"example_runtime_status": {
"state": "degraded",
"substate": "writer_backpressure",
"engine": {
"chunksProduced": 128443,
"lateBuffers": 7,
"underruns": 0,
"maxCycleMs": 51.12,
"maxWriteMs": 49.91
},
"queue": {
"capacity": 3,
"depth": 1,
"fillLevel": 0.3333,
"droppedFrames": 0,
"repeatedFrames": 2,
"mutedFrames": 0
},
"driver": {
"txEnabled": true,
"streamActive": true,
"samplesWritten": 64221500,
"slowWrites": 4
},
"lastFault": {
"code": "WRITER-LATE-BURST",
"at": "2026-04-05T12:34:56Z",
"message": "Write-Latenz wiederholt über Chunk-Budget"
}
},
"example_fault_event": {
"eventId": "fault-000184",
"severity": "error",
"stateBefore": "running",
"stateAfter": "muted",
"code": "QUEUE-EMPTY-RECOVERY-FAILED",
"message": "Queue blieb trotz Recovery leer; Ausgang wurde auf Mute gesetzt",
"metrics": {
"queueFillLevel": 0.0,
"lateBuffersLast60s": 14,
"writerErrorsLast60s": 3
}
},
"example_rollout_plan": {
"milestone_1": "Semantik und State-Maschine stabil",
"milestone_2": "Entkoppelter Writer mit Telemetrie",
"milestone_3": "Sichere API und Audit-Log",
"milestone_4": "HIL-Regression und Kalibrierung",
"milestone_5": "Nightly-Qualitätsgates und reproduzierbare Releases"
}
},
"definition_of_done": {
"technical": [
"TX-Pfad ist deterministisch entkoppelt und fault-tolerant.",
"DesiredConfig, AppliedConfig und RuntimeState sind sauber getrennt.",
"Alle kritischen Fehler führen in explizite Zustände.",
"RF-Signalqualität ist intern und extern nachweisbar.",
"Metriken, strukturierte Logs und Diagnosepfade sind vollständig."
],
"operational": [
"System läuft im Langlauftest stabil.",
"Remote-Bedienung ist gehärtet und auditierbar.",
"Gerätespezifische Fähigkeiten und Kalibrierungen sind modelliert.",
"Builds und Deployments sind reproduzierbar."
],
"quality_gates": [
"Unit- und Integrationssuite grün",
"Race Detector grün",
"Fuzzing ohne kritische Findings",
"HIL-Regression grün",
"Soak-Test grün"
]
},
"final_instruction_to_ai_team": {
"summary": "Nicht blind Features ergänzen. Zuerst die Semantik und den Runtime-Kern hart machen. Dann Observability und sichere Steuerung. Danach Hardware-Wahrheit, Kalibrierung und Nightly-Regressions. Alles, was nicht deterministisch, messbar und fault-beherrscht ist, ist noch nicht pro-level.",
"first_step_now": [
"WS-03 beginnen: Parameterinventar und semantische Vereinheitlichung.",
"Danach direkt WS-01 und WS-02 in einem Architektur-Branch umsetzen."
]
}
}

Laden…
Abbrechen
Speichern