Skip to content

Reviewer ​

reviewer ist die Persona, die jede mutierende Operation gegenzeichnet. Im Gegensatz zu den anderen Workern wird sie nie vom coordinator gespawnt — der Katalog schließt sie absichtlich aus. Der einzige Spawner ist der ReviewGate-Decorator, der jedes Tool umhüllt, dessen Class "write" oder "destructive" ist.

Der reviewer ist die Antwort auf eine Frage: „wer beobachtet den Beobachter?"

Nicht deaktivieren.

Der reviewer ist das, was Ongrid überhaupt sicher macht, host_restart_service oder execute_skill zu geben. Das Überspringen des Gates ist eine explizite Konfigurationsentscheidung und erscheint im Audit-Trail. Wenn Sie die Persona zu „always approve" forken, zeigt das Audit-Log jede Entscheidung — Auditoren werden es bemerken.

Der ReviewGate-Decorator ​

Position in der Tool-Decorator-Chain (chain.go):

text
tenant_bind → REVIEW_GATE → timeout → audit → ratelimit → metric → <inner tool>

Warum genau diese Reihenfolge:

  • Außerhalb von timeout. Der reviewer ist selbst ein graph.Invoke mit eigenem Turn-Budget. Ihn innerhalb des 15s-Timeouts des inneren Tools zu wickeln, würde den reviewer zwingen, in 15s fertig zu werden — unrealistisch. Das Gate trägt seine eigene unabhängige 60s-Decke (DefaultReviewerTimeout).
  • Außerhalb von audit. Ablehnungen sollten keine synthetische Ausführungszeile schreiben. Das Gate schreibt stattdessen eine chat_mutating_proposals-Zeile. Audit loggt nur die Ausführung des inneren Tools, was nur bei Genehmigung passiert.
  • Innerhalb von tenant_bind. Die Vorschlags-Payload enthält den Operator user_id, den tenant_bind aus dem ctx auflöst — das Gate muss nachdem tenant_bind ihn aufgefüllt hat, laufen.

Auslösebedingung ​

Der Decorator inspiziert die Class des umhüllten Tools:

ClassGate-Verhalten
"read"Durchlassen. Inneres Tool läuft.
"write"Abfangen. reviewer spawnen. Inneres läuft nur bei Genehmigung.
"destructive"Gleich wie "write". Beide Classes durchlaufen das Gate.

Konkrete Class: "write"-Tools heute in der Tasche:

  • host_restart_service — das kanonische mutierende Skill.
  • execute_skill — der Marketplace-Shim, der jedes marketplace-installierte Skill ausführt (das Gate kann den Skill-Body nicht zur Klassifizierung lesen, also gatet es sie alle).
  • AgentTool — ja, das Dispatch-Primitive selbst ist "write", weil es einen Worker spawnt und daher Ressourcen committet. Der reviewer gatet AgentTool-Aufrufe in der Praxis allerdings selten — siehe die Persona-Allowlist unten.

Die Vorschlags-Payload ​

Beim Abfangen baut das Gate:

json
{
  "action": "host_restart_service",
  "target": {"device_id": 7, "service": "nginx"},
  "reason": "User reported 502; nginx error log shows OOM",
  "blast_radius": "single_device",
  "operator": "user_42",
  "context_summary": "<coordinator's running summary of the conversation>"
}

blast_radius ist einer von single_device | cluster | tenant_wide, abgeleitet aus den Metadaten des Tools. Der reviewer verwendet ihn, um die „ist das vernünftig"-Entscheidung zu gewichten — eine tenant_wide-Aktion sieht höherer Prüfung gegenüber als eine single_device.

Die Reviewer-Persona ​

Frontmatter-Highlights (wörtlich aus agents/reviewer.md):

yaml
name: reviewer
description: SOP 二审 reviewer worker,对 mutating / destructive 提案做静态审查
permission_mode: read-only
max_turns: 5
model: anthropic/claude-opus-4-7   # 关键路径用最强
background: true                   # async: spawn returns immediately

tools:
  - get_incident_detail
  - get_edge_summary
  - query_promql
  - query_logql
  - get_sop_text                   # planned (HLD-003 PR-D)

disallowed_tools:
  - "*_skill"                      # wildcard — no skill execution
  - run_shell
  - execute_skill
  - host_restart_service           # explicitly: reviewer cannot itself act
  - kill_process

critical_reminder: |
  你是高危操作二审 reviewer。reject 是默认选项,approve 必须三条都满足:
    1. 找得到对应 SOP 且明确覆盖此场景
    2. 当前没有并行的同类操作(看告警 / 看运维窗口)
    3. 回滚路径已知

Schlüsselbeobachtungen:

  • max_turns: 5. Reviewer reden nicht um den heißen Brei. Fünf Turns zum Entscheiden; das Persona-Prompt sagt explizit „看不清就 reject".
  • model: anthropic/claude-opus-4-7. Der Critical-Path-Aufruf bekommt das stärkste Modell, unabhängig vom Default der Org. Reviews sollten nicht auf ein schnelles Modell heruntergestuft werden — die Kosten einer falschen Genehmigung überwiegen die Kosten eines langsamen Reviews bei weitem.
  • background: true. Reviewer läuft asynchron. Die UI des coordinators blockiert nicht auf dem Review; die task_notification des Reviews postet zurück, wenn fertig. (In der aktuellen Verdrahtung blockiert das innere Tool bis der reviewer zurückkehrt — aber die UI nicht, sodass der Benutzer „Review ausstehend" sieht, während es läuft.)
  • disallowed_tools-Wildcard *_skill. Der reviewer kann kein Skill ausführen. Er kann Kontext lesen (get_incident_detail, get_edge_summary, Telemetrie-Abfragen), aber nie handeln.
  • Kein run_shell, kein host_restart_service, kein kill_process. Selbst wenn der Persona-Body es ihm sagen würde, entfernt der Runtime-Filter diese Tools. Defense in Depth.

Der 5-Schritte-Workflow ​

Aus dem Persona-Body läuft der reviewer:

  1. Das SOP finden. get_sop_text(action) für die offizielle Prozedur. Kein SOP → reject mit "no SOP for action <X>".
  2. Zielzustand prüfen. get_edge_summary(device_id). Device offline / in Restart-Loop / letzte mutierende Aktion innerhalb von 5min → reject.
  3. Parallele Operationen prüfen. query_logql für audit:-Einträge, die dasselbe Ziel in den letzten 10 Minuten berühren. Parallele Aktion → reject mit "parallel operation detected; wait for X to complete".
  4. Den Grund gegen Alarme validieren. get_incident_detail für den referenzierten Incident. Grund widerspricht dem Alarminhalt → reject („Operator hat das Symptom möglicherweise falsch gelesen").
  5. Entscheiden.
    • Genehmigen, wenn alle drei Kern-Gates passieren. Ausgabe {decision: approve, sop_id, rollback_path, gates_passed}.
    • Ablehnen andernfalls. Ausgabe {decision: reject, reason, missing_gates}.

Die Three-of-Three-Regel ​

Der Critical Reminder ist explizit:

reject 是默认选项,approve 必须三条都满足:

  1. 找得到对应 SOP 且明确覆盖此场景
  2. 当前没有并行的同类操作(看告警 / 看运维窗口)
  3. 回滚路径已知

„Nicht sicher" ist äquivalent zu „reject". Dies ist eine bewusste Kalibrierung — die Kostenasymmetrie zwischen einer falschen Genehmigung (Produktionsschaden) und einer falschen Ablehnung (ein zusätzlicher Round-Trip) begünstigt letztere stark.

Ausgabeformat ​

Die endgültige Antwort des reviewers (zurückgepostet an den coordinator via <task-notification>):

markdown
**Decision: approve | reject**

**Gates**
- ✓ SOP-007 covers restart nginx
- ✓ node-01 status online; last mutating 17min ago
- ✓ No parallel operation
- ✓ Rollback: `systemctl start nginx`

**Notes**
{1-2 sentence risk note; included even on approve.}

Der Decorator parst auf Decision: approve (Groß-/Kleinschreibung egal, muss in der ersten nicht-leeren Zeile der Antwort erscheinen). Alles andere — einschließlich mehrdeutiger Formulierungen wie „approve with caveats" — wird als reject behandelt.

Was bei Genehmigung passiert ​

Der Decorator:

  1. Schreibt eine chat_mutating_proposals-Zeile mit status=approved, dem Entscheidungstext des reviewers und der SOP-ID.
  2. Lässt den Aufruf zum inneren Tool durchfallen.
  3. Der Audit-Decorator (Downstream in der Chain) schreibt die Ausführungszeile.
  4. Das innere Tool gibt sein normales Ergebnis an das coordinator-LLM zurück.

Das coordinator-LLM sieht ein normales Tool-Ergebnis und fährt fort.

Was bei Ablehnung passiert ​

Der Decorator:

  1. Schreibt eine chat_mutating_proposals-Zeile mit status=rejected, dem Grund des reviewers und den fehlenden Gates.
  2. Gibt ErrReviewRejected zurück, das den Grund des reviewers umhüllt.
  3. Der Audit-Decorator schreibt keine Ausführungszeile (keine Ausführung erfolgte).

Das coordinator-LLM sieht eine Fehlermeldung — review rejected: <reviewer reason> — und soll die Situation dem Benutzer erklären. Es sollte denselben Tool-Aufruf nicht wiederholen; der Dedupe-Schutz plus ein kurzfristiges LRU auf Ablehnungsgründe halten das LLM vom Loopen ab.

Edge Cases ​

Was, wenn der Benutzer der Operator und Admin ist? ​

Der reviewer läuft trotzdem. Es gibt kein „Review überspringen, weil du Admin bist"-Flag. Auditierbarkeit ist der Punkt — die Entscheidungszeile des reviewers ist die Papierspur, die sagt „diese Aktion wurde gegen SOP-X mit Rollback Y zur Zeit T genehmigt". Admin-Override würde die Spur löschen.

Was, wenn kein get_sop_text-SOP existiert? ​

Heute ist der SOP-Korpus dünn — get_sop_text ist ein geplantes Tool (HLD-003 PR-D). Im aktuellen MVP verwendet der reviewer einen Platzhalter und fällt auf eine Heuristik zurück: kritische Aktionen auf produktionstagged Devices brauchen explizites force_approve_no_sop: true im Vorschlagskontext, was der coordinator nur nach expliziter Nutzerbestätigung setzen kann. Dies wird durch den SOP-Korpus ersetzt, sobald er gefüllt ist.

Was, wenn der reviewer timeout? ​

Der 60s-Gate-Timeout feuert. Der Decorator gibt ErrReviewTimeout zurück. Das coordinator-LLM sieht einen Timeout-Fehler und soll ihn dem Benutzer berichten — nicht wiederholen. Anhaltende reviewer-Timeouts sind ein Manager-seitiges Problem (wahrscheinlich Modell-Latenz); das Audit-Log lässt den SRE das Muster sehen.

Was ist mit Read-Only-Worker-Tools? ​

Read-Only-Tool-Aufrufe der Workers (query_promql, get_host_load, etc.) haben Class: "read" und triggern das Gate nie. Nur "write" / "destructive"-Tools tun das. Der reviewer selbst trägt nur Class: "read"-Tools, sodass ein Reviewer-Worker selbst kein verschachteltes ReviewGate triggern kann.

Das Gate anpassen ​

Dinge, die Sie in einem Fork ändern könnten:

  • Das Reviewer-Modell. Wenn Ihre Org keinen Anthropic-Zugang hat, schreiben Sie das Frontmatter-model: auf das stärkste Modell, das Sie haben. Das Gate verwendet das, was die Persona deklariert.
  • Die 60s-Decke. Überschreiben Sie über die ReviewGate-Konstruktor-Option, wenn Ihr reviewer regelmäßig länger braucht. Gehen Sie nicht unter 30s; der reviewer braucht Raum für 5 Turns × LLM + Tool-Round-Trips.
  • Den Reviewer-Persona-Body. Fügen Sie teamspezifische Checklisten hinzu (PCI-Scope, Change-Freeze-Fenster, On-Call-Kalender). Das Gate kümmert sich nicht um den Body, solange die endgültige Entscheidungszeile parsebar ist.

Dinge, die Sie nicht ändern dürfen:

  • Den name: reviewer — das Gate sucht ihn per Name nach (DefaultReviewerAgent).
  • Den disallowed_tools-Wildcard *_skill — der reviewer darf selbst keine Aktionen ausführen; Defense in Depth sagt, dass der Runtime-Filter dies erzwingt, nicht der Prompt.

Für einen pro-Tool-benutzerdefinierten reviewer (z. B. einen DB-spezifischen) akzeptiert der Decorator-Konstruktor einen reviewerAgent-Override, sodass verschiedene Tools zu verschiedenen Reviewer-Personas geroutet werden können. Verwenden Sie es sparsam — mehrere reviewer fragmentieren den Audit-Trail.