feat(2.7.0): Roadmap im DC, Testinstanz mit Testtor, Supervisor und MCP

Sammelcommit fuer den ueber mehrere Sitzungen gewachsenen, bisher nicht
eingecheckten Stand. Getrennte Commits waeren ehrlicher gewesen, sind es
nachtraeglich aber nicht mehr: BugRepo, changelog.json und die Doku tragen
Aenderungen aus allen Straengen gleichzeitig, und keine Zwischenstufe waere
lauffaehig.

ROADMAP IM DEPLOYMENTCENTER (2.7.0)

Planungsstand, Reihenfolge und Zustaendigkeit lagen in handgepflegten
Markdown-Dateien neben einem Bugtracker, der genau diese drei Dinge bereits
fuehrt. Zwei Pfleger fuer dasselbe Feld - Drift war eine Frage der Zeit.

Ab jetzt: Zustand im DC, Begruendung in der Datei. Kein Feld hat zwei Pfleger.

  - Migration 016: epic, roadmap_rank, target_build, defer_trigger,
    doc_anchor, Status "deferred", Tabelle roadmap_epics.
    KEINE Roadmap-Tabelle - ein Eintrag ist ein bugtracker_item.
  - Zugehoerigkeit ist ein Feld: Ein Item steht auf der Roadmap, wenn es ein
    epic hat. Ein zweites Kennzeichen daneben koennte auseinanderlaufen.
  - Kennung ist die Item-ID. Handvergebene Kuerzel ("A12") erzeugen die
    schlimmste Fehlerart: Beide Seiten stimmig, Verschiedenes gemeint, weil
    die Kennung nach einer Loeschung neu vergeben wurde.
  - Zurueckstellen verlangt defer_trigger. Ohne benannten Anlass ist ein
    Vorhaben nicht zurueckgestellt, sondern vergessen. Die Regel sitzt im
    Repository, damit sie auf allen drei Schreibwegen gleich greift.
  - Modules/Bugtracker/Roadmap.php, /api/bugtracker/v1/roadmap.php,
    WebUI-Modul mit Filtern, cli/roadmap.php --write/--check,
    dc_roadmap und dc_roadmap_set im MCP-Adapter.
  - cli/roadmap.php --write ERZEUGT den Zustandsteil der Markdown-Datei;
    --check prueft nur die Prosa. Was erzeugt wird, kann nicht driften.
  - docs/ROADMAP_MIGRATION.md: Uebernahme fuer die anderen Projekte.

TESTINSTANZ UND TESTTOR

  - dc-dev.mhdf.de: zweite Installation, eigene DB, eigene Schluessel,
    Basic-Auth davor, Rocket.Chat aus.
  - 124 Testfaelle in tests/e2e gegen API, Rechte, Migrationen, Sperre.
  - scripts/deploy.py bringt vor jedem Upload erst den anstehenden Stand auf
    die Testinstanz und laesst dann den Testlauf laufen. Erst bei
    Rueckgabewert 0 geht etwas auf die Produktion (--ohne-test als Notausgang).
    Andersherum prueft der Lauf aelteren Code als den, der gleich hochgeht.
  - tests/ ist aus dem Produktiv-Deploy ausgeschlossen; testctl.php kann
    nicht versehentlich auf dc.mhdf.de landen.
  - Ein Lauf mit mehr uebersprungenen als geprueften Faellen endet mit
    Rueckgabewert 2 statt 0. Nichts ist kaputt, geprueft wurde es aber auch
    nicht - der Unterschied darf nicht am Rueckgabewert verschwinden.

SUPERVISOR, PROJEKTLANDSCHAFT, NACHPRUEFUNG (2.6.0/2.6.1)

  - Migration 013: projektuebergreifend melden (dev_agent, evidence,
    triage_external, affects).
  - Migration 014: supervisor_findings, Katalog, fuenf serverseitige
    Detektoren im Tick.
  - Migration 015: Nachpruefung als Arbeitsschlange statt Benachrichtigung.
  - DEV-Lizenzschluessel zur Selbstbedienung, dc-testkit fuer die Test-VM.
  - MCP-Adapter: 15 Werkzeuge, ohne Fremdabhaengigkeiten, mit Abgrenzung
    von Fremddaten gegen Prompt-Injektion.

BEHOBEN

  - observe und status im Supervisor legten den Zustand des Befundes als
    "status" in die Antwort. Http::ok() merged ['status' => 'success']
    darunter, also gewann der Befundzustand - eine angenommene Meldung kam
    als status="open" an. Heisst jetzt finding_status. War Item #59.

Migrationen 013-016 sind auf dem Produktivserver noch NICHT ausgefuehrt.
Ohne sie bricht das WebUI, weil die Roadmap-Ansicht bei jedem Seitenaufruf
gegen bugtracker_items.epic abfragt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Deploymentcenter Bot
2026-08-29 21:59:20 +02:00
co-authored by Claude Opus 5
parent 9d0261306c
commit 1d5ac92051
52 changed files with 15261 additions and 103 deletions
+185
View File
@@ -0,0 +1,185 @@
# Supervisor — Befunde und Rückbau
Der Supervisor sieht nach, ob etwas ungewöhnlich ist, und legt Befunde ab.
Er beantwortet die Frage **„ist das ungewöhnlich?"** — nicht „ist das
schlimm?". Die zweite Frage beantwortet ein Mensch oder ein Agent bei der
Sichtung, mit Verlauf, Flotte und Quelltext vor Augen.
Gültiger Stand aller Vorhaben: **[ROADMAP.md](ROADMAP.md)**<br>
Ausführliche Begründung (archiviert): [archiv/SUPERVISOR_MCP_DESIGN.md](archiv/SUPERVISOR_MCP_DESIGN.md)
---
## Wichtig: es gibt nichts einzubauen
> **Ein Supervisor im ausgelieferten Programm ist verworfen.** Er hätte in
> jeder Anwendung Einbau, Rückbau, eigenen Zustand auf Kundenhardware, ein
> weiteres Token im Binary und eine zweite Fassungspflege gebraucht — und dabei
> überwiegend gemeldet, was Error-Reporting und Bugtracker ohnehin abdecken.
>
> **Für Anwendungen ändert sich damit nichts.** Wer Fehler an den Bugtracker
> meldet, ist fertig. Die Detektoren laufen im Deploymentcenter auf den Daten,
> die dadurch ohnehin hereinkommen.
Diese Anleitung beschreibt deshalb zweierlei: **was der Supervisor findet und
wie man es ansieht** — und **wie begonnene Vorbereitungen zurückgebaut werden.**
---
## Woher Befunde kommen
**Serverseitig, von selbst.** Fünf Detektoren laufen im minütlichen Tick
(gedrosselt auf zehn Minuten) und brauchen keine Änderung an irgendeiner
Anwendung:
| Detektor | Findet |
|---|---|
| `novel.error_signature` | Fehlersignatur, die es in dieser Fassung noch nie gab |
| `silence.heartbeat` | Instanz meldet sich nicht mehr |
| `deviation.self` | Abweichung vom eigenen Verlauf der letzten Tage |
| `deviation.fleet` | Ausreißer gegenüber anderen Installationen derselben Fassung |
| `regression.build` | Kennzahl verschiebt sich nach einem Update |
Keiner davon muss den gesuchten Fehler vorher kennen. Der Maßstab kommt nicht
aus einem Kopf, sondern aus dem eigenen Verlauf, aus der Vorversion oder aus
den anderen Installationen — deshalb finden sie Dinge, an die niemand gedacht
hat.
**Von außen eingeliefert**, über `POST /api/supervisor/v1/observe` mit dem
Scope `supervisor:report`. Heute nutzen das Prüfwerkzeuge und Testläufe. Der
[Katalog](../src/Modules/Supervisor/Catalog.php) legt die Namen fest, unter
denen gemeldet wird — abrufbar über `GET /api/supervisor/v1/catalog`.
Dass die Namen stabil sind, ist der ganze Zweck: Befunde aus verschiedenen
Projekten müssen vergleichbar bleiben. Ein umbenannter Detektor zerreißt jede
Auswertung, die über den Zeitpunkt der Umbenennung hinausgeht.
---
## Befunde ansehen
Über MCP in Claude Code:
```
dc_finding_summary → Zählung je Detektor
dc_findings detector: "deviation" → die Einzelbefunde
dc_metrics source: "app-01" metric: … → der Verlauf dahinter
```
Ohne MCP:
```
GET /api/supervisor/v1/summary
GET /api/supervisor/v1/findings?detector=deviation&status=active
GET /api/supervisor/v1/catalog
```
Befunde tragen ihre Umgebung. Was außerhalb von `production` auffällt, ist eine
Stufe niedriger eingestuft — nicht weil es unwichtig wäre, sondern weil auf
Testmaschinen systematisch mehr Rauschen entsteht.
**Ob ein Befund aus einem Testlauf ein Artefakt des Prüfstands ist oder auch
beim Kunden aufträte, ist die schwierige Frage.** Sie ist offen; die Ansätze
stehen in der [Roadmap unter G8](ROADMAP.md). Der brauchbarste Gedanke daraus:
Fehlende Zugangsdaten sind ein Artefakt — *wie die Software darauf reagiert*,
ist keines. Ein Wiederholungssturm, ausgelöst durch fehlende Zugangsdaten, ist
ein echter Befund, denn auch beim Kunden laufen Zugangsdaten ab.
---
## Vorbereitungen in den Projekten zurückbauen
In mehreren Projekten wurde bereits von Hand etwas in Richtung Supervisor
begonnen — UI-Steuerelemente, teilweise ein lokaler KI-Agent. Das fällt
**ersatzlos** weg; es tritt nichts an seine Stelle.
### Erkennen
```bash
grep -rniE "supervisor|healthcheck|selfcheck|anomal" --include=*.cs --include=*.php .
```
Typisch: eine eigene Timer-Schleife, ein Verzeichnis mit Zählern, ein eigener
`HttpClient`-Aufruf gegen das Deploymentcenter, eine JSON-Datei mit Zustand,
eine Klasse namens `HealthCheck` oder ähnlich.
### Was verschwindet
- **Lokal laufender KI-Agent** samt API-Schlüssel. Der Schlüssel läge auf
Kundenhardware, der Kontext im Speicher fremder Maschinen.
- **UI-Listen, -Tabellen und -Schaltflächen für Befunde.** Es gibt lokal keine
Befundhistorie anzuzeigen, und Abhaken wäre `supervisor:manage` — ein Recht,
das kein Laufzeit-Token trägt.
- **Eigene Warteschlangen** für nicht zugestellte Meldungen. Eine wachsende
Warteschlange in einer ohnehin auffälligen Anwendung ist genau der Schaden,
den man vermeiden wollte.
- **Eigene Alarmierung** je Auffälligkeit. Wer bei jeder Kleinigkeit alarmiert,
hat nach einer Woche einen Kanal, den niemand mehr liest.
- **Feste Schwellwerte je Kennzahl.** Die tragenden Detektoren vergleichen
gegen eigenen Verlauf, Vorversion oder Flotte. Ein Schwellwert findet nur,
woran vorher jemand gedacht hat.
- **Timer-Schleifen, Zustandsdateien, eigene POSTs** an das Deploymentcenter.
Was bleiben darf, wenn es schon gebaut ist: eine **einzelne Statuszeile** im
Administrationsbereich — meldet die Anwendung Fehler, wann zuletzt. Das ist die
einzige lokal beantwortbare Frage.
### Was übrig bleibt und wertvoll ist
Wo in der Vorbereitung schon überlegt wurde, **worauf** zu achten wäre, ist
diese Überlegung das Wertvollste am ganzen Bestand. Sie wandert nicht ins
Nichts, sondern:
| Überlegung | Neuer Ort |
|---|---|
| „Hier darf nie ein negativer Saldo entstehen" | Prüfung im Testlauf |
| „Dieser `catch` verschluckt etwas Wichtiges" | Fehlermeldung an den Bugtracker, statt zu schlucken |
| „Diese Warteschlange kann volllaufen" | Kennzahl im Heartbeat — `deviation.self` sieht den Rest |
| „Dieser Job stirbt manchmal still" | Heartbeat-Monitor — `silence.heartbeat` sieht den Rest |
Die letzten beiden sind der Punkt: Was als Kennzahl im Heartbeat landet, wird
serverseitig ohnehin überwacht. Dafür braucht es keinen Beobachter im Programm,
nur einen Wert mehr im Ping.
### Auftrag für den Agenten im Projektverzeichnis
Zum Einfügen in eine frische Sitzung im jeweiligen Projekt:
```text
In diesem Projekt wurde eine Supervisor-Vorbereitung begonnen. Sie wird
ersatzlos zurückgebaut — ein Supervisor im ausgelieferten Programm ist
verworfen. Es tritt nichts an seine Stelle.
1. Bestandsaufnahme. Suche:
grep -rniE "supervisor|healthcheck|selfcheck|anomal" .
Berichte, was du findest, bevor du etwas änderst.
2. Ersatzlos entfernen:
- lokal laufender KI-Agent samt API-Schlüssel
- UI-Listen, -Tabellen und -Schaltflächen für Befunde
- eigene Warteschlangen, eigene Alarmierung, feste Schwellwerte
- eigener POST ans Deploymentcenter, eigene Zustandsdatei
- eigene Timer-/Hintergrundschleife
Behalten: höchstens eine Statuszeile im Administrationsbereich.
3. Die Überlegungen retten. Wo jemand notiert hat, WORAUF zu achten wäre,
überführe das:
- fachliche Zusicherung -> Prüfung im Testlauf
- verschluckter Fehler -> Fehlermeldung an den Bugtracker statt Schlucken
- Wert, der volllaufen kann -> Kennzahl im Heartbeat
4. Sicherstellen, dass Fehler gemeldet werden: globaler Exception-Handler an
POST /api/errors/v1/report, mit build_version. Ohne diese Angabe kann der
Tracker eine Regression nicht von einem veralteten Prüfstand unterscheiden.
5. Fassung festhalten: dc_link_project mit to_slug "deploymentcenter",
integrated_version "2.6.1". Ohne MCP: POST /api/bugtracker/v1/projects.
Fällt dir dabei ein Fehler im Deploymentcenter selbst auf, melde ihn mit
dc_report gegen project_slug "deploymentcenter" samt evidence.
```
Schritt 4 ist der wichtigste. Er ersetzt den ganzen verworfenen Beobachter:
Kommen Fehler mit Fassungsangabe herein, arbeiten die serverseitigen Detektoren
darauf — ohne eine Zeile Beobachtercode in der Anwendung.