Vigilant Inference Governor

Vig-Edge-Pilot — der interne Referenzpilot

Stand: 11.09.2026 · Abnahmekriterien festgelegt vor der ersten Messung. Wer dieses Dokument nach einer Messung ändert, schreibt dazu, was und warum.

Warum ein eigener Pilot

Es gibt keinen Entwicklungspartner (NV-19). Ohne einen benannten Lastfall ist jede weitere Zahl eine Vermutung darüber, was ein Kunde braucht. Dieser Pilot bildet den Fall nach, für den der Governor gebaut ist: ein Edge-Wahrnehmungsknoten mit mehreren Kameras, einem schnellen, geschützten Alarmpfad und einem langsameren semantischen Berichtspfad auf derselben GPU — mit der Zusage, dass der Bericht den Alarm nie blockiert.

Er ersetzt keinen Kundennachweis. Er ist die ehrlichste Näherung, die ohne einen Kunden möglich ist: echte Modelle, echte annotierte Aufnahmen, eine fachliche Kennzahl — und Kriterien, die vor der Messung feststehen.

Der Aufbau

4 Kameras ─▶ Detektor (RF-DETR, 23 Klassen) ─▶ Alarm         protected
                                      │
Lagebericht ◀── Qwen3-0.6B (vLLM) ◀───┘                       best_effort
Detektor ein interner RF-DETR-Detektor mit 23 Klassen, Eingang 768×768, als Kopie in einem eigenen Triton-Modellverzeichnis (edge_detector). Nicht im Repository und nicht öffentlich.
Zielklassen die Alarmklassen dieses Detektors; das Werkzeug prüft im Referenzdurchlauf, auf welche Klassen er bei annotierten Alarmobjekten tatsächlich antwortet
Berichtspfad Qwen3-0.6B über das vLLM-Backend, eigener Tritonprozess, best_effort, kooperative Zerlegung wie in WP26; der Prompt nennt, was die Kameras zuletzt geliefert haben
Kameras vier Wiedergabelisten aus Clips zweier Objektklassen und Clips ohne Alarmobjekt, in Echtzeit abgespielt
Maschine RTX 3070 Laptop (8 GB), Treiber 580.178.04, Triton 2.70

Nicht Teil dieses Stands: eine zusätzliche Erkennungsstufe (high) auf Ausschnitten des Detektors. Sie wäre die naheliegende Erweiterung; der Pilot beantwortet zuerst die Frage des Alarmpfads.

Die Daten

Primär: ein öffentlicher, Bild für Bild annotierter Videodatensatz mit Clips zweier Objektklassen und Clips ohne Alarmobjekt, Annotationen im COCO-Format. Name und Quelle stehen im lokalen Aufbereitungsskript, nicht im Repository.

Lizenz: CC BY-NC 3.0. Nur für diesen internen Test, keine Weitergabe von Bildern, Annotationen oder daraus abgeleiteten Dateien. Alles Abgeleitete liegt außerhalb des Repositorys; der Pfad zum Datensatz wird dem Aufbereitungsskript übergeben.

Was bei der Aufbereitung geprüft wurde, und was daraus folgt:

Optional: MOT16 (MOTChallenge, CC BY-NC-SA 3.0), vier Sequenzen mit Fußgängern, drei feste Kameras und eine bewegte — ein Personenszenario mit demselben Detektor (Klasse person, IoU 0,5; nur Personen, die mindestens halb sichtbar und 20 von 512 px hoch sind). Aufbereitet mit tools/pilot/prepare-data.sh; kein Teil der Abnahme. Für den 768er-Detektor mit SIZE=768 aufbereiten.

Die Arme

Arm Was er ist
Referenz Jedes Frame einzeln, ohne Konkurrenz, gegen denselben Detektor. Keine Wartezeit — die Obergrenze, gegen die beide anderen gemessen werden.
Triton direkt Kameras sprechen direkt mit dem Detektor-Triton, der Bericht direkt mit dem vLLM-Triton: zwei Prozesse, die GPU verteilt der Treiber.
Vigilant Dieselben Kameras, derselbe Bericht, dieselben Bilder zu denselben Zeitpunkten — über den Governor.
Vigilant ohne Bericht Wie Vigilant, ohne Berichtspfad — die Gegenprobe für K5.

Welche Bilder eine Kamera sendet, bestimmt allein die Uhr seit Laufbeginn. Alle Arme sehen dieselbe Folge. Jeder Arm wird mit den Client-Puffertiefen 1 und 4 gefahren, je Arm zählt die bessere (Spec 19.1): niedrigere p95-Alarmlatenz, bei Gleichstand weniger verpasste Ereignisse.

Lastpunkte

Nach serialisierter Auslastung des Detektors, nicht nach fester Rate: die Rate ergibt sich aus dem im Referenzdurchlauf gemessenen Median, Rate = Auslastung / (Kameras × Median), höchstens 25 Hz (die native Rate). Eine feste Rate hieße bei einem 40-ms-Detektor 80 % auf dem einen und 400 % auf dem anderen Punkt — keine vergleichbaren Punkte.

Punkt Kameras Auslastung des Detektors Bericht
A 2 50 % ein Bericht nach dem anderen, Mindestabstand 2 s
B 4 90 % ebenso
C 4 125 % ebenso
D 4 200 % ebenso

Rate und effektive Auslastung stehen im Protokoll jedes Laufs. Die Last des Sprachmodells kommt zur Detektorauslastung hinzu. 60 s je Lauf, drei Wiederholungen; berichtet werden Median und Spannweite.

Die Kennzahlen

Warum IoU 0,3 und nicht 0,5. Bei rund 24 px großen Boxen kostet ein Versatz von zwei Pixeln bereits über 0,15 IoU. 0,5 würde die Lokalisierungsgenauigkeit des Detektors messen, nicht die Frische. Die Schwelle gilt für alle Arme gleich; das Personenszenario nutzt 0,5.

Der Detektor wird nicht bewertet. Auf so kleinen Objekten ist seine Trefferquote auch ohne jede Konkurrenz unvollständig. Alle Arme werden relativ zur Referenz beurteilt: gemessen wird, was sie gegenüber dem unbelasteten Detektor verlieren.

Abnahmekriterien

Zwei Gruppen, seit dem 12.09.2026. Die ursprünglichen Kriterien K1–K7, festgelegt am 11.09. vor der ersten Messung, maßen zwei Dinge in einem Urteil: was der Governor entscheidet, und was Detektor, Datensatz und Bildrate überhaupt hergeben. Der erste vollständige Lauf verfehlte K1 (Alarm ≤ 300 ms) und K4 (Trefferquote) um ein Vielfaches — und die Referenz ohne jede Konkurrenz ebenso. Ein Kriterium, das die Referenz selbst nicht erfüllt, kann kein Urteil über die Planung tragen. Das war ein Fehler im Entwurf der Kriterien, und so ist er korrigiert:

Beide Gruppen stehen getrennt im Bericht und in summary.json; K8 kommt weiter aus shm-latency.

Gruppe Planung

# früher Kriterium Bestanden, wenn
P1 K2 Alarm unter Last (C, D) Vigilants p95-Alarmlatenz ist mindestens 30 % kürzer als die des Backends direkt, oder das Backend direkt erfüllt A1 selbst — dann gibt es dort nichts zu gewinnen. Anwendbar, solange der Vergleichsarm mindestens 500 ‰ der Perioden versorgt
P2 K3 Kein Schaden ohne Last (A) Vigilants p95 höchstens 5 % oder 10 ms schlechter als direkt (Spec 19.8), das Größere von beiden
P3 neu Aufgabenqualität unter Last (C, D) Vigilants Trefferquote höchstens 2 % schlechter als die des Backends direkt
P4 neu Versorgung unter Last (C, D) Abdeckung des Alarmpfads höchstens 2 % schlechter und längste Lücke höchstens 10 % (oder 10 ms) länger als direkt
P5 K5 Entkopplung (alle Punkte) Der Berichtspfad verschlechtert Vigilants Alarmlatenz nicht: p95 mit Bericht höchstens 10 % (oder 5 ms) über dem Lauf ohne Bericht
P6 K6 Der Bericht lebt (A, B) mindestens zwei fertige Lageberichte je Minute

P3 und P4 sind neu, weil die Trennung sie verlangt: Die absoluten Schwellen wandern in die andere Gruppe, und ohne sie stünde für Trefferquote und Versorgung gar kein Maß mehr da. Ihr Maßstab ist derselbe Lauf auf derselben Karte, nur ohne Governor.

P1 braucht einen Vergleichsarm, der die Aufgabe noch erfüllt

Der Lauf unter XSched vom 12.09. zeigt eine Lücke im Entwurf von P1. Bei den Lastpunkten C und D liefert der Arm „Backend direkt" gar keine Versorgung mehr: 0 ‰ Abdeckung, längste Lücke 45 s, Trefferquote 0 ‰. Seine Alarmzeit ist dann die Zeit bis zu einem zufälligen Treffer und kein Maßstab. An ihr gemessen verfehlt Vigilant die 30-Prozent-Schwelle (1778 gegen 2317 ms, also 23 % kürzer) — obwohl es der einzige Arm ist, der die Aufgabe überhaupt noch erfüllt.

Ein relatives Kriterium braucht einen Vergleichsarm, der die Aufgabe noch erfüllt. Seit dem 14.09. gilt P1 deshalb nur, solange der Vergleichsarm mindestens 500 ‰ der Perioden versorgt; darunter steht es als nicht anwendbar im Bericht, und P3 und P4 tragen das Urteil.

Woher die 500 ‰ kommen. Nicht aus den Messwerten: Die Grenze ist dieselbe wie bei A2 und aus demselben Grund gewählt. Versorgt ein Arm weniger als die Hälfte der Perioden mit einem frischen Ergebnis, misst seine Alarmzeit nicht mehr seine Latenz, sondern die Zeit bis zu einem zufälligen Treffer. Ein Arm, der die Aufgabe nicht mehr erfüllt, ist kein Maßstab dafür, wie gut sie erfüllt wird. Die Schwelle steht damit vor der nächsten Messung fest und wurde nicht an einen vorhandenen Lauf angepasst.

Der Lauf vom 12.09. wird nicht umgewertet. Er bleibt „Planung verfehlt". Zur Einordnung, was die neue Fassung dort geändert hätte: Der Vergleichsarm lag bei C und D bei 0 ‰ Abdeckung, P1 wäre also nicht anwendbar gewesen, und das Urteil hätte auf P3 und P4 beruht — die er an beiden Punkten bestanden hat. Das ist eine Aussage über das Kriterium, kein neues Ergebnis: Gemessen wurde nichts neu, und die Zahlen des Laufs stehen unverändert im Messbericht.

Gruppe Anwendung

# früher Kriterium Bestanden, wenn Anwendbar, wenn
A1 K1 Alarm unter Last (C, D) p95 ≤ 300 ms und nie alarmierte Ereignisse höchstens Referenz + 2 Prozentpunkte die Referenz ohne Konkurrenz selbst ≤ 300 ms liegt
A2 K4 Lagebild (C, D) Trefferquote mindestens 90 % der Referenzquote die Referenzquote mindestens 500 ‰ der annotierten Objekte erreicht
A3 K7 Keine erfundenen Alarme Fehlalarmquote höchstens Referenz + 1 Prozentpunkt immer
K8 K8 Datenpfad das Budgeturteil aus docs/datapath-budgets.md auf derselben Maschine: bestanden immer

Die Anwendbarkeitsschwelle von A2 (500 ‰) ist eine Setzung mit einem Grund: Ein Detektor, der auf diesem Datensatz nur ein Fünftel der annotierten Objekte überhaupt findet, trägt keine absolute Qualitätsaussage — die Zahl beschreibt dann ihn und nicht die Planung.

Was das Werkzeug daraus macht

Das Binary druckt beide Gruppen getrennt und setzt den Exitcode allein nach der Gruppe Planung: 0 bestanden, 1 sauber gelaufen und Planung verfehlt, 2 Aufbau oder Lauf kaputt, 3 kein Urteil (keine auswertbare Zelle). Eine verfehlte oder nicht anwendbare Anwendungsgruppe steht im Bericht und in summary.json, macht aber keinen Fehlschlag daraus.

Das Freigabeurteil: fünf getrennte Fragen

Ein bestandener Planungsstatus ist keine Abnahme. Er sagt nur: auf den gemessenen Zellen entschied der Governor besser als das Backend direkt. Bis zum 14.09. lieferte ein Lauf ohne jedes auswertbare Kriterium Exitcode 0 und sah damit aus wie ein bestandener; das war der Befund R05 des Reviews. Seit dem 14.09. steht deshalb neben dem Status ein Freigabeurteil aus fünf Feldern, in der Ausgabe und in summary.json unter freigabe:

Feld Werte Woher
ablauf vollständig, unvollständig, kaputt gemessene gegen geplante Zellen
planung bestanden, verfehlt, kein_urteil Gruppe P
anwendung bestanden, verfehlt, kein_urteil Gruppe A, nur anwendbare Kriterien
qualifikation immer nicht_bewertet Hardware und Backend; ein Messlauf stellt das nicht über sich selbst fest
freigabe empfohlen, nicht_empfohlen nur wenn alle vier darüber bestätigt sind

Weil qualifikation aus eigener Kraft nie „bestätigt" lautet, kann dieses Binary keine Freigabe aussprechen — es kann sie nur verweigern und den Grund nennen. Eine Teilmatrix, eine nicht anwendbare Anwendungsgruppe oder ein abgebrochener Lauf erzeugen nie ein positives Gesamturteil.

# Kriterium Bestanden, wenn
K1 Alarm unter Last (Punkte C und D) Vigilant: p95 der Alarmlatenz ≤ 300 ms und nie alarmierte Ereignisse höchstens Referenz + 2 Prozentpunkte
K2 Vorteil unter Last (C, D) Vigilants p95-Alarmlatenz ist mindestens 30 % kürzer als die von Triton direkt, oder Triton direkt erfüllt K1 selbst — dann gibt es auf diesem Punkt nichts zu gewinnen, und das steht so im Bericht
K3 Kein Schaden ohne Last (A) Vigilants p95-Alarmlatenz höchstens 5 % oder 10 ms schlechter als Triton direkt (Spec 19.8), das Größere von beiden
K4 Lagebild (C, D) Vigilants Trefferquote mindestens 90 % der Referenzquote
K5 Entkopplung (alle Punkte) Der Berichtspfad verschlechtert Vigilants Alarmlatenz nicht: p95 mit Bericht höchstens 10 % (oder 5 ms) über dem Lauf ohne Bericht
K6 Der Bericht lebt (A, B) mindestens zwei fertige Lageberichte je Minute
K7 Keine erfundenen Alarme Fehlalarmquote auf Vigilant höchstens Referenz + 1 Prozentpunkt
K8 Datenpfad das Budgeturteil aus docs/datapath-budgets.md auf derselben Maschine: bestanden

Was als Scheitern der Produktaussage zählt. Jedes verfehlte Kriterium der Gruppe Planung: P1 oder P3 oder P4 verfehlt heißt, der Governor liefert unter Last weder schnellere Alarme noch bessere Aufgabenqualität als das Backend direkt; P2 verfehlt heißt, er schadet dort, wo nichts zu schützen ist. Das steht dann in STATUS und README, nicht in einer Fußnote.

Was kein Scheitern ist. Eine schwache Referenz-Trefferquote auf 24-px- Objekten — sie ist eine Aussage über den Detektor und macht A2 unanwendbar, nicht den Governor schlecht. Ebenso P6 auf den Punkten C und D: wenn der Detektor die Karte auslastet, soll der Bericht warten, das ist die Entkopplung und nicht ihr Versagen. Deshalb wird P6 nur auf A und B geprüft.

Erster vollständiger Lauf, 12.09.2026: verfehlt

Vier Lastpunkte, drei Wiederholungen, 60 s je Zelle, RTX 3070 Laptop, Stand 49f3639; Exitcode 1, also sauber gelaufen und fachlich verfehlt. Zahlen und Einordnung: messkette-2026-09-12.md.

Reproduzieren

# Daten (einmalig; SRC zeigt auf den entpackten Datensatz)
# Das Aufbereitungsskript liegt lokal neben den Daten, nicht im Repository.
SRC=/pfad/zum/datensatz SIZE=768 "$VIG_PILOT_DIR/prepare-alarm.sh" "$VIG_PILOT_DIR/alarm"

# Detektor-Triton (eigener Port, eigenes Modellverzeichnis `edge_detector`)
docker run -d --name edge-pilot-triton --device nvidia.com/gpu=all \
  -p 8201:8000 -p 8202:8001 -p 8203:8002 --ipc=host \
  -v "$VIG_PILOT_DIR/models:/models:ro" nvcr.io/nvidia/tritonserver:26.06-py3 \
  tritonserver --model-repository=/models --allow-client-shm=true

# Berichts-Triton (wie WP26)
docker run -d --name onetimer-vllm --device nvidia.com/gpu=all \
  -p 8010:8000 -p 8011:8001 -v "$LLM_MODELS:/models:ro" --ipc=host \
  nvcr.io/nvidia/tritonserver:26.06-vllm-python-py3 \
  tritonserver --model-repository=/models

cargo build --release -p vig-bench
VIG_PILOT_DIR=… taskset -c 8-15 target/release/edge-pilot --smoke   # Funktionsprobe, ~2 min
VIG_PILOT_DIR=… taskset -c 8-15 target/release/edge-pilot           # alles, ~80 min

Optionen: --scenario A,C, --seconds, --repeats, --caps 1,4, --no-llm, --triton HOST:PORT, --model NAME, --llm HOST:PORT, --dataset mot, --out DIR, --fresh.

Matrix und Dauer

Ein Lauf ist eine Matrix: Lastpunkte × Wiederholungen × Arme × Puffertiefen, jede Zelle --seconds lang. Voreinstellung: 4 × 3 × 3 × 2 = 72 Zellen à 60 s, dazu rund 3 s je Zelle für Gatewaystart und Nachlauf und der Referenzdurchlauf (1–2 min): rund 80 Minuten. Das Werkzeug druckt die Schätzung vor dem Start und nach dem Referenzdurchlauf. Die Wiederholungen stecken schon in der Matrix; ein äußerer Runner fährt den Lauf einmal und gibt ihm mindestens 100 Minuten Frist. Bis zum 11.09. brach die Messkette ihn nach 30 Minuten ab und wiederholte ihn dreimal (Review R07).

Kleiner geht es mit --scenario, --repeats, --seconds und --caps; eine verkleinerte Matrix beurteilt nur die Kriterien, deren Lastpunkte sie enthält.

Ablage und Wiederaufnahme

--out (Voreinstellung $VIG_PILOT_DIR/results/edge-pilot) enthält:

Datei Inhalt
manifest.json der Aufbau (Datensatz, Detektor, Sprachmodell, Sekunden je Zelle) und die Referenzwerte des ersten Starts
cells.jsonl je Zelle eine Zeile, sofort geschrieben: Schlüssel, Gültigkeit, Kennzahlen, gesendet/geliefert/abgewiesen, erschöpfte und gesperrte Puffer
summary.json Status, Exitcode, jedes Kriterium mit Ergebnis

Ein erneuter Start mit derselben Ablage überspringt gültige Zellen und rechnet Raten und Profile mit den Referenzwerten des ersten Starts, damit spätere Zellen mit früheren vergleichbar bleiben. Ein anderer Aufbau in derselben Ablage wird abgelehnt; --fresh verwirft sie. Eine Zelle ohne eine einzige Lieferung gilt als Aufbaufehler: sie wird als ungültig abgelegt, der Lauf endet, und ein Neustart misst sie neu.

Exitcode

Code Bedeutung
0 jedes ausgewertete Kriterium erfüllt, oder keines auswertbar (Teilmatrix)
1 sauber gelaufen, mindestens ein Kriterium verfehlt — ein negatives Ergebnis, kein Fehler
2 Aufbau oder Lauf kaputt: Backend nicht erreichbar, Zelle ohne Lieferung, Ablage nicht beschreibbar, Panik

Die Funktionsprobe (--smoke) kennt nur 0 und 2: zwölf Sekunden sind keine Abnahme.

Die Bildpuffer

Jede Kamera hat so viele Shared-Memory-Puffer wie die größte Puffertiefe plus eins. Ein Puffer wird verliehen, reist mit dem Auftrag und kommt erst zurück, wenn sein Leser sicher fertig ist: bei einer Antwort, einer Ablehnung vor der Weitergabe oder einem Fehler, den das Backend selbst meldet. Nach einem Timeout oder einem unbekannten Ausgang bleibt er gesperrt. Ist kein Puffer frei, wird das Frame nicht gesendet (buffers_exhausted), statt eines zu überschreiben, das noch gelesen wird. Bis zum 11.09. wurde der Puffer reihum gewählt, und ein langsamer Leser konnte sein Bild verlieren (Review R03).

Auf ruhiger Maschine, nicht neben einem Build. Ein weiterer Triton daneben belegt GPU-Speicher; für die Messung besser beenden. Die Ergebnisse gehören in docs/pilot/edge-pilot-ergebnis.md, mit dem Stand und dem Taktmitschnitt; Rohprotokolle bleiben außerhalb des Repositorys.