Vigilant Inference Governor

03 — Modulare Zielarchitektur bis zum Maximalausbau

Status: Entwurf. Alle neuen Modul- und API-Namen sind Vorschläge, keine bereits existierenden Crates, CLI-Befehle oder Zusagen. Der erste produktive Ausbau benötigt nicht alle hier beschriebenen Module.

1. Ein Produkt, klar getrennte Verantwortungen

Anwendung / optional ROS- oder Holoscan-Integration
                  |
         OIP-Gateway oder lokales SDK
                  |
          Authentisierung + Vertragsgrenzen
                  |
       vig-runtime: ein Besitzer je Ressourcendomäne
       | Payload-Leases, Ausführungswissen, Lifecycle |
       |                                            |
       +------ vig-core: deterministische Policy ---+
       |          ^            ^                    |
       |          |            +-- gültige Prognosesicht
       |          +-- versionierte Zustandsereignisse
       |
       +-- Triton-Executor ------ Triton ------ TRT / ORT / ...
       +-- TensorRT-Executor ---- Contexts / Streams / CUDA Events
       +-- weitere Executor-Adapter (nur nach Bedarf)
                  |
       optionale Ausführungsmechanismen:
       kooperative Grenze / Green Contexts / XSched

Außerhalb des Hot Paths:
Telemetrie -> State Resolver -> Profilkatalog / Kalibrierung
                             -> experimenteller Ressourcenregler
Trace + Verbraucherfeedback -> Evaluation / Vertragsmonitor

Der Governor bleibt eine Policy- und Koordinationsschicht. Kein Modellcompiler, kein allgemeines Robotik-Weltmodell und kein Ersatz für den Sicherheitsregler.

2. Modulzuschnitt und Abhängigkeiten

Modul Verantwortet Darf ausdrücklich nicht
vig-core (bestehend) Zeit-/Vertragstypen, Queue- und Dispatchentscheidungen, begrenzte Zustandssichten SDKs laden, Sensoren abfragen, Hardware verstellen
vig-runtime (neu) Actor, Ressourcendomänen, Ausführungs-/Payload-Leases, Wiederanlauf und Ereignisordnung stillschweigend fachliche Verträge lockern
vig-backend-api (neu, klein) Executor-Capabilities, Tickets, Wissenszustände, Payload-Handles OIP- oder CUDA-Typen als universellen Vertrag erzwingen
Executor-Adapter Backendaufruf, Datenpfad, eigene Objekte, Completion-/Fehlernachweis Modelle oder Qualität außerhalb des Dispatchplans wählen
vig-profiles (neu) Profilmanifest, Domänenabgleich, Samplingprovenienz, kompakte Prognosesichten produktive Anforderungen aus Messungen ableiten
vig-platform (neu, optionale Adapter) Beobachtung und getrennte privilegierte Aktuation Rootrechte an den Netzwerk-Gateway vererben
Gateway / SDK (bestehend + Erweiterung) Anwendungsmetadaten, Autorisierung, Protokolltreue Ressourcenfreigabe aus Clientabbruch ableiten
Simulator / Bench / CLI (bestehend) Replay, Kalibrierung, Qualifikation, Diagnose synthetische Daten als Hardwarequalifikation ausgeben

Logische Module müssen nicht sofort je ein eigenes Crate werden. Extrahiert wird erst, wenn ein zweiter Nutzer oder eine klare Abhängigkeitsgrenze entsteht. Kein Vorrat an leeren Adapter-Crates. Abhängigkeiten fließen von Runtime und Adaptern zu Core/API, niemals zurück vom Core zu Plattformbibliotheken.

3. Was eine Ressourcendomäne bedeutet

Eine Domäne ist der Bereich gemeinsam verwalteter Ausführungskapazität: zunächst eine physische GPU, später beispielsweise eine qualifizierte Partition. Zwei Triton-Server auf derselben GPU sind nicht automatisch zwei Domänen.

Pro Domäne gibt es genau einen logischen Kapazitätsbesitzer. Er kann einen eingebetteten Prozess oder mehrere kontrollierte Worker koordinieren. Mehrere unkoordinierte SDK-Instanzen bekommen keine domänenweite QoS-Zusage.

Jede Domäne beschreibt:

GPU-Prozentzahlen sind keine universelle Kapazitätseinheit. SM-Anzahl, Speicherbytes, Copy-Engines und Ausführungscredits sind unterschiedliche Dinge. Unbekannte Fremdlast reduziert die Nachweisstufe; sie wird nicht als null erfasst.

4. Executor-Schnittstelle: Wissen statt Hoffnung

Konzeptioneller Vertrag:

describe() -> Capabilities + ExecutionIdentity
prepare(EngineManifest) -> PreparedEngineHandle
submit(DispatchPlan, PayloadLease) -> ExecutionTicket | ProvenNotStarted
observe(ticket) -> CompletionEvidence | ExecutionUnknown | StillRunning
request_cancel(ticket) -> CancelRequested | Unsupported
reconcile(domain_generation) -> ReconciliationEvidence

Das ist API-Pseudocode. observe muss nicht pollen; ein Adapter kann Events liefern. Asynchrone Fehler gehören nicht in einen einzigen Zustand Failed.

Ereignis Client Ausführungscredit / Speicher
Nachweislich vor Übergabe abgelehnt terminaler Fehler freigeben
Dispatch angenommen wartet bleibt gebunden
Client-Timeout / Clientabbruch terminal bzw. Empfänger weg keine automatische Freigabe
RPC nach Dispatch verloren Fehler, falls noch offen Unknown, gebunden halten
GPU-/Backendende bestätigt Ergebnis oder Fehler nach Nutzung der Outputs freigeben
Qualifiziertes Fencing beendet alte Generation Fehler / Wiederanlauf alte Leases nach Nachweis auflösen
Nur Zeit verstrichen oder Health-Ping erfolgreich keine neue Erkenntnis nicht freigeben

CompletionEvidence enthält Ticket, Generation, Zeitpunkt, Quelle und Beweisart. Ein generischer gRPC-Status reicht nur dann als Endnachweis, wenn der konkrete Backendvertrag das tatsächlich zusagt.

Ressourcenreconciliation bedeutet nicht automatisch GPU-Reset: Ein Reset kann fremde Arbeit treffen und benötigt eine vorher vereinbarte Betriebsbefugnis. Ohne Nachweismöglichkeit bleibt die Domäne nicht bereit; der Betreiber erhält einen konkreten Recovery-Grund. Ein Neustart nur des Gateways ist kein Fencing des weiterhin laufenden Backends.

5. Zwei Lebenszyklen, nicht einer

Client:       waiting --------------------------> terminal
Execution:    reserved -> submitted -> running -> confirmed_finished
                                  \-> unknown -> reconciliation
PayloadLease: ================================ bis letzte Nutzung =====

Clientantwort und Ausführungsende werden jeweils genau einmal verbucht. Verspätete oder doppelte Events sind anhand Ticket und Generation idempotent. Ein alter Completion-Event darf keine neue Slotbelegung freigeben.

Die Payload-Lease umfasst Host-/Devicebytes und Shared-Memory-Referenzen. Ein Registrierungsname darf nicht auf anderen Speicher umgebogen werden, während laufende Requests ihn referenzieren. Unregister wird verzögert oder explizit abgelehnt. CUDA-Pointer werden nicht als unkontrollierte Netzwerkwerte akzeptiert. Für das lokale SDK gelten dokumentierte Speicher- und Streambesitzer.

OIP-Felder bleiben im Triton-Pfad unverändert erhalten. Ein backendprivater, typisierter Payload-Handle vermeidet, dass das Runtime-Interface beliebige OIP-Erweiterungen verlustbehaftet in eine neue Universal-Tensornachricht presst. Der Core sieht weiterhin nur Referenzen und deklarierte Größen.

6. Fähigkeiten werden qualifiziert, nicht geraten

Ein Capability-Datensatz enthält Version und Nachweisstatus, unter anderem:

cancel_scope: none | queued_only | cooperative | executing
preemption_boundary: none | request | token | kernel | graph | device_specific
completion_evidence: backend_final | cuda_event | fenced_generation
memory_accounting: declared | measured | enforced
resource_partition: none | sm_subset | other_qualified_partition
supported_shapes, tensor_schema_id, streaming_mode
resume_semantics, checkpoint_cost, measured_blocking_envelope

Eine behauptete Fähigkeit ohne Hardware-/Treiberqualifikation erhält keinen verlässlichen Status. Eine Präemption ist erst wirksam, wenn das Backend sie bestätigt; bis dahin bleiben Credits belegt. Graph- und Tokenunterbrechung sind unterschiedliche Fähigkeiten. Unterschiedliche Capabilities dürfen in derselben Produktinstallation nebeneinander existieren.

7. Zustand: statische Identität und dynamische Beobachtung trennen

ExecutionIdentity identifiziert Modell-/Enginehash, Präzision, Shape/Batch, Vor-/Nachverarbeitung, Runtime, Provider, Serverkonfiguration, Gerät, Treiber, CUDA-/Bibliotheksversionen und gewählten Datenpfad. Ein kryptographischer Artefakthash dient Integrität; der alte FNV-Metadatenfingerprint bleibt als Legacy-Indikator erhalten, nicht als Sicherheitsnachweis.

StateSnapshot enthält tatsächliche statt nur angeforderte Clock-Werte, Power-Mode, Temperatur-/Throttlingzustand, aktuelle Ressourcenzuordnung, Co-Tenant-Identitäten, warm/cold und optional Fortschrittsklassen.

Jedes Feld trägt Quelle, Messzeit, Einheit, Gültigkeitsdauer und Qualität: known, unsupported, stale oder unknown. Nicht verfügbare EMC-Telemetrie auf einer Plattform ist kein Wert von 0 MHz. Remote-Triton braucht für Hardwarewissen einen vertrauenswürdigen Agenten oder ein begrenztes, deklariertes Betriebsprofil; der Governor kann es nicht aus Metadaten erraten.

Nur entscheidungsrelevante Änderungen erhöhen die Zustandsversion. Quantisierte Temperaturklassen und Hysterese vermeiden ein anderes Profil für jede Sensorabweichung. Hardwarezustand wird als Event aufgezeichnet; ein Replay liest keine aktuelle GPU und reproduziert trotzdem die getroffene Entscheidung.

8. Profilkatalog und Predictor

Kein riesiges neuronales Modell als erste Implementierung. Ein sparsamer Katalog enthält qualifizierte Betriebspunkte; der bestehende Quantilschätzer bleibt der Basispfad. Neue Zellen werden gezielt für beobachtete Kundenlasten gemessen, nicht als vollständiges kartesisches Produkt aller Zustände.

Eine Prognose ist ein strukturiertes Ergebnis:

Prediction {
  planning_cost, optimistic_cost,
  measurement_boundary,
  profile_id, state_version, resource_layout_version,
  applicability: exact_cell | validated_envelope | fallback | unknown,
  evidence: synthetic | empirical | qualified | analytical,
  sample_count, independent_run_count, validated_domain,
  risk_bound: optional, method_and_assumptions: optional
}

Ein hoher Quantilwert ist keine automatisch kalibrierte risk_bound. Schätzungen außerhalb der gültigen Domäne geben unknown oder einen ausdrücklich qualifizierten Rückfall zurück. Keine stillschweigende Interpolation über Runtime-, Clock-, Präzisions- oder Enginegrenzen.

Schwere Auswertung und Profilbau laufen außerhalb des Actors. Der Core bekommt eine begrenzte, versionierte Lookup-Sicht; Updates werden atomar als Event sichtbar. Zwischen Prognose und Dispatch wird der Snapshot nochmals geprüft. Veränderte Ressourcen oder abgelaufene Telemetrie erfordern Neuplanung.

9. Mehrere Regelkreise mit klarer Rangordnung

Regelkreis Eingabe / Aufgabe Beschränkung
Schneller Dispatch aktuelle Aufträge, gültige Prognosen keine blockierenden Sensor-/SDK-Abfragen
Vertragsmonitor Verbraucherzyklen, Lücken, Miss-Bursts misst Anforderungen; setzt sie nicht neu
Profilanpassung Beobachtungen und Drift begrenzte Updates, keine verdeckte Optimismussteigerung
Ressourcen-/Energieregler längerfristige Last, Kosten und Stellverzögerung optional, Mindestverweildauer, exklusiver Stellgrößenbesitzer
Anwendungssemantik autorisierte Hinweise und Gültigkeit bleibt innerhalb freigegebener Vertragsgrenzen

Priorität: Betriebssicherheit/Plattformlimits vor Vertragsgrenzen, danach Ausführungswahl, danach Energieoptimierung. Der Energieregler darf nicht gleichzeitig mit einem unabhängigen Regler dieselben Clocks gegeneinander verstellen. Überlast, Variantenwahl und Taktänderungen benötigen gemeinsame Hysterese-/Stabilitätstests und ein definiertes Zustandswechselbudget.

Aktuationszustände: requested -> pending -> observed_stable, alternativ failed/overridden. Planung verwendet bis zur bestätigten Wirkung den alten oder einen konservativen Übergangszustand. Thermal-Schutz wird niemals ausgeschaltet. Read-only-Telemetrie ist Standard; Aktuation ist opt-in.

10. Native TensorRT-Stufen

Erste Stufe: feste Shapes, vorgebaute vertrauenswürdige Engines, ein Context je tatsächlicher gleichzeitiger Ausführung, begrenzte Buffers, kein zusätzlicher Enqueue-Vorrat (pipelining_depth = 0), Completion per geeignetem CUDA-Event. Enginebau und Warm-up finden vor Admission statt. Ausgabe- und Kopierkosten gehören je nach Messgrenze zum Vertrag.

Weitere Stufen: mehrere qualifizierte Varianten, feste Context-/Stream-Pools, Graph-Cache mit begrenztem Speicher und expliziten Shape-/Adressschlüsseln, danach kontrollierte Nebenläufigkeit und optionale Partitionierung.

Native Bindings werden in einem kleinen, separat geprüften FFI-Bereich gekapselt. Das unsafe_code = forbid des Scheduling-Cores bleibt erhalten. Keine globale Lockerung der Workspace-Regeln nur für bequemere CUDA-Aufrufe.

Engines sind vertrauenswürdige ausführbare Artefakte, keine beliebigen Nutzerdaten. Native Fehler können Prozessgrenzen relevant machen; siehe NVIDIA zu TensorRT-Lebensdauer, Engine-Vertrauen und CUDA-Fehlern. Ein Worker-Prozess kann den Fehlerumfang begrenzen, garantiert aber allein keine vollständige GPU-Isolation. Datenpfad und Fencing müssen dazu passen.

11. Maximalausbau ohne Pflichtabhängigkeiten

12. Migration und Rückfall

  1. Lebenszyklusinvarianten auf dem alten Pfad absichern.
  2. Legacy-Prognose und alte Konfiguration über Kompatibilitätsadapter erhalten.
  3. Actor herauslösen, ohne außen OIP oder CLI aufzubrechen.
  4. Neue Zustände zunächst nur protokollieren, neue Policy im Shadow-Modus berechnen. Shadow führt keine zusätzliche GPU-Arbeit aus.
  5. Gültige neue Profile opt-in aktivieren; pro Profil und Domäne zurückschaltbar.
  6. TensorRT Direct separat bauen/aktivieren. Triton-Installation benötigt keine CUDA-Entwicklungsbibliotheken zum Bauen des Standardprodukts.
  7. Jede Forschungsoption hat Capability-Test, Abschalter und dokumentierten Rückfall. Fehlende Option verhindert nicht den Basisbetrieb.

Alte YAML-Dateien bleiben lesbar. Neue Funktionen bekommen explizite Versionierung; unbekannte Felder bleiben Fehler. Ein alter Binary muss eine neue, nicht unterstützte Konfiguration ablehnen statt sie teilweise auszuführen. Neue Metriken stehen neben alten Namen mit dokumentierter Messsemantik.

13. Unverhandelbare Invarianten