|
- {
- "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."
- ]
- }
- }
|