diff --git a/docs/API.md b/docs/API.md index c000124..c97206e 100644 --- a/docs/API.md +++ b/docs/API.md @@ -15,9 +15,7 @@ Health check. {"ok": true} ``` -`controlAudit` mirrors the control plane's HTTP reject counters (405/415/413/400) so runtime telemetry can spot abusive clients and the UI can keep ops aware of guardrail hits. - -`engine.state` spiegelt jetzt die Runtime-State-Maschine wider (idle, arming, prebuffering, running, degraded, muted, faulted, stopping) und bietet eine erste beobachtbare Basis für Fault-Transitions. +This endpoint is a simple liveness signal — it does not include runtime-state data or audit counters. Use it for readiness/liveness probes. --- @@ -48,7 +46,12 @@ Current transmitter status (read-only snapshot). Runtime indicator, alert, and q } ``` -`runtimeIndicator` is derived from the engine queue health plus any late buffers observed in the last 5 seconds and can be "normal", "degraded", or "queueCritical". `runtimeAlert` surfaces a short reason (e.g. "queue health low" or "late buffers") when the indicator is not "normal", but late-buffer alerts expire after a few seconds once cycle times settle so the signal doesn't stay stuck on degraded. The cumulative `lateBuffers` counter returned by `/runtime` still shows how many late cycles have occurred since start for post-mortem diagnosis. +`runtimeIndicator` is derived from the engine queue health plus any late buffers observed in the last 5 seconds and can be "normal", "degraded", or "queueCritical". + +`runtimeState` mirrors the same runtime-state machine string that `/runtime` exposes as `engine.state` when a TX controller is active, so quick health checks reuse the same terminology. + +`runtimeAlert` surfaces a short reason (e.g. "queue health low" or "late buffers") when the indicator is not "normal", but late-buffer alerts expire after a few seconds once cycle times settle so the signal doesn't stay stuck on degraded. The cumulative `lateBuffers` counter returned by `/runtime` still shows how many late cycles have occurred since start for post-mortem diagnosis. + --- @@ -117,6 +120,8 @@ Live engine and driver telemetry. Only populated when TX is active. `driver.underrunStreak` reports how many consecutive reads returned silence, and `driver.maxUnderrunStreak` captures the longest such run since the engine started. Together they help differentiate short glitches from persistent underrun storms and can be plotted alongside queue health sparkline telemetry. +`controlAudit` mirrors the control plane's HTTP reject counters (405/415/413/400). Whenever the HTTP server rejects a request (method not allowed, unsupported media type, body too large, or unexpected body), the respective counter increments — this lets runtime telemetry spot abusive clients without polluting the runtime state payload. + --- diff --git a/docs/pro-runtime-hardening-workboard.md b/docs/pro-runtime-hardening-workboard.md index 46473dc..b7ba0db 100644 --- a/docs/pro-runtime-hardening-workboard.md +++ b/docs/pro-runtime-hardening-workboard.md @@ -228,15 +228,24 @@ Generator/Upsampler und Hardwarewriter werden als getrennte Stufen mit kleinem, - 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 +- **Status:** IN PROGRESS +- **Owner:** Lead Coderaffe - **Code-Orte:** - `internal/app/engine.go` - **Ziel:** - Queue-Füllstand, Late-Rate und Fehlerhäufigkeit überwachen und in Runtime-Zustände überführen. + Queue-Füllstand, Late-Rate und Fehlerhäufigkeit überwachen und in explizite Runtime-Zustände überführen, + sodass ein degradierter Queue-Health-Pfad automatisch auf `degraded`, `muted` oder `faulted` zeigt. - **Akzeptanzpunkte:** - - State-Entscheidungen sind explizit - - kein implizites Weiterwursteln bei Schieflage + - Alle Runtime-Entscheidungen laufen über `evaluateRuntimeState`, nicht stillschweigend weiter auf `running`. + - Queue-Health, Late-Buffers und Fault-Events treiben gezielt `degraded` → `muted` → `faulted`, damit Operatoren wissen, wann Blockaden vorliegen. + - `EngineStats` und `/runtime` bringen `runtimeIndicator`, `queue`, `faultHistory`, `transitionHistory` und das `runtimeState`-Label, so Telemetrie und UI dieselben Signale sehen. +- **Nachweis:** + - `internal/app/engine.go` (Generator-/Writer-Loops) ruft `evaluateRuntimeState` auf und protokolliert Fault-Events, Transition-Historien und Counters. + - `txBridge.TXStats` (`cmd/fmrtx/main.go`) leitet die Runtime-Infos an `/status` und `/runtime`, damit die API-Layer aktuelle Fault-Zustände spiegeln. + - `internal/app/runtime_state_test.go` plus `go test ./...` sichern die erwarteten Transition-Reihenfolgen und Fault-Counter. +- **Restrisiken:** + - Queue-Schwellen für `critical`/`lateBuffers` brauchen noch Feldvalidierung und ggf. Konfiguration. + - Fault-Reset/Operator-Interaktion ist im Control-Plane-UI noch zu finalisieren. ## Offene Architekturfragen - Ist `capacity_frames = 3` ein guter Startwert oder nur Konzept-Default? @@ -298,31 +307,50 @@ Einführen eines klaren Betriebsmodells mit Fault-, Recovery- und Muted-Zuständ ## Aufgaben ### WS-02-T1 — Fault-Klassifikation definieren -- **Status:** TODO -- **Owner:** offen +- **Status:** IN PROGRESS +- **Owner:** Lead Coderaffe - **Beispiele:** - - Treiberfehler - - Write-Time-Budget überschritten - - Queue leer - - Queue dauerhaft kritisch - - Selbsttest fehlgeschlagen - - unerlaubtes Live-Update + - `queueCritical` + - `lateBuffers` + - `writeTimeout` (z. B. Driver-Timeouts) + - `queueEmpty` + - `unknown` (Catch-all für unvorhergesehene Runtime-Zustände) +- **Ziel:** + Alle relevanten Fehlertypen als `FaultReason`/`FaultSeverity` codieren, damit sie später eindeutig auf Telemetrie und Logs abgebildet werden können. +- **Nachweis:** + - `internal/app/fault.go` definiert Reasons (`queueCritical`, `lateBuffers`, `writeTimeout`, `queueEmpty`, `unknown`) und Severity-Stufen (`warn`, `degraded`, `muted`, `faulted`). + - `internal/app/engine.go` ruft `recordFault` im Queue- und Late-Buffer-Prozess auf, so dass jede Reason vom Fault-Historien-Log erfasst wird. + - `internal/app/runtime_state_test.go` und `internal/app/fault_test.go` prüfen, dass die Reason/Severity-Kombinationen korrekt geloggt und ausgewertet werden. +- **Restrisiken:** + Weitere Driver-/Hardware-Faults (z. B. Soapy-Timeouts oder Audio-Stream-Abbrüche) müssen noch explizit getriggert und klassifiziert werden. ### WS-02-T2 — Reaktionsstrategie definieren -- **Status:** TODO -- **Owner:** offen +- **Status:** IN PROGRESS +- **Owner:** Lead Coderaffe - **Ziel:** - Pro Fehlerklasse klar definieren: + Reaktionen für jede FaultSeverity klar definieren (warn → loggen, degraded → degrade state, muted → stilllegen, faulted → Reset-Hürde). - warn only - degraded - muted - faulted +- **Nachweis:** + - `evaluateRuntimeState` eskaliert queueCritical-Läufe zuerst zu `degraded`, dann `muted`, schließlich `faulted` und protokolliert die entsprechenden Severity-Labels. + - `Engine.ResetFault()` bringt `faulted` deterministisch zurück auf `degraded`, damit die Supervisor-Logik das Manual-Reset respektiert. + - Tests in `internal/app/runtime_state_test.go` prüfen, dass die Transition-Counter (`degradedTransitions`, `mutedTransitions`, `faultedTransitions`) und `faultCount` bei den richtigen Ereignissen springen. +- **Restrisiken:** + Die aktuellen Schwellen basieren auf queueCritical-Streaks; zusätzliche FaultSources (Driver, Audio-Stream, Live-Update-Rejection) brauchen eigene Severity-Strategien. ### WS-02-T3 — Fault-Historie und Event-Log einführen -- **Status:** TODO -- **Owner:** offen +- **Status:** IN PROGRESS +- **Owner:** Lead Coderaffe - **Ziel:** - Zustandswechsel und Faults auditierbar machen. + Zustandswechsel, Fault-Count und Trace-Historien auditierbar machen, damit `/runtime` und die UI eine nachvollziehbare Story liefern können. +- **Nachweis:** + - `EngineStats` enthält `faultHistory`, `transitionHistory`, `lastFault`, `faultCount` sowie `runtimeStateDurationSeconds` und Runtime-Indikatoren. + - `txBridge.TXStats` leitet diese Infos in `/runtime` und `/status` weiter, `internal/control/control_test.go` sichert, dass `faultHistory` und `transitionHistory` korrekt serialisiert werden. + - `internal/app/runtime_state_test.go` validiert die Historienkapazität, `go test ./...` deckt die API-Exposition ab. +- **Restrisiken:** + Die History-Kapazität ist auf 8 Einträge begrenzt; ein Audit-Log-Backend könnte später die Lücke auffangen. ## Offene Designfragen - Wie fein granular darf die State-Maschine werden, ohne unwartbar zu werden?