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>
600 lines
26 KiB
Markdown
600 lines
26 KiB
Markdown
# Supervisor, Detektor-Katalog und MCP-Server — Entwurf
|
|
|
|
> **ARCHIVIERT.** Dieses Dokument beschreibt keinen gültigen Stand mehr.
|
|
> Die Etappen 1 bis 3 sind in 2.6.0 ausgeliefert; der Etappenplan, die offenen
|
|
> Punkte und die verworfenen Ansätze sind in **[../ROADMAP.md](../ROADMAP.md)**
|
|
> übernommen. Dort steht, was gilt.
|
|
>
|
|
> Aufbewahrt wird der Entwurf wegen der Herleitung — besonders Abschnitt 0
|
|
> (warum Beobachtung und Urteil getrennt sind) und Abschnitt 7 (warum der
|
|
> Client keinen Quelltext sieht). Wer hier etwas liest, prüft es gegen die
|
|
> Roadmap, bevor er danach handelt.
|
|
|
|
Stand: 2026-08-21. Betrifft alle Projekte, nicht nur das Deploymentcenter.
|
|
|
|
Drei Vorhaben, die aneinanderhaengen und deshalb zusammen beschrieben werden:
|
|
|
|
1. ein **Supervisor**, der in jeder Anwendung laufend nachsieht, ob etwas
|
|
schieflaeuft, und Befunde meldet
|
|
2. ein **Detektor-Katalog**, der festlegt, wonach er sucht — in allen
|
|
Projekten unter denselben Namen
|
|
3. ein **MCP-Server**, ueber den Claude Code und andere Werkzeuge an
|
|
Error-Reporting, Supervisor und Bugtracker andocken
|
|
|
|
Die Reihenfolge im Dokument folgt der Sache, nicht der Umsetzung. Der Bauplan
|
|
steht am Ende unter "Etappen".
|
|
|
|
---
|
|
|
|
## 0. Die Grundentscheidung: Beobachtung und Urteil trennen
|
|
|
|
Der Supervisor ist bewusst kein einzelnes Ding. Er zerfaellt an der
|
|
Vertrauensgrenze in zwei Haelften:
|
|
|
|
| | Beobachter | Diagnostiker |
|
|
|---|---|---|
|
|
| laeuft | auf der Kundenmaschine | auf eigener Infrastruktur |
|
|
| fragt | Ist das *ungewoehnlich*? | Ist das *schlimm*? |
|
|
| Takt | dauernd, minuetlich | selten, bei Auffaelligkeit |
|
|
| Kosten je Pruefung | muessen nahe null sein | duerfen hoch sein |
|
|
| kennt Quellcode | nein | ja |
|
|
| Technik | Regeln, Zaehler, Schwellen | Agent mit Repo-Zugriff |
|
|
|
|
Zwei Gruende, warum die Trennung nicht verhandelbar ist:
|
|
|
|
**Sicherheit.** Alles, was der ausgelieferte Client lesen kann, kann auch der
|
|
Kunde lesen. Ein Token im Binary ist extrahierbar, TLS auf der eigenen Maschine
|
|
abhoerbar, .NET dekompilierbar. Duerfte der Client Quellcode abrufen, waere die
|
|
Software faktisch offen. Dagegen hilft keine Verschluesselung — der Client
|
|
muesste entschluesseln koennen, also koennte es der Kunde auch.
|
|
|
|
**Eignung.** Ein Sprachmodell ist schlecht im dauernden Hinsehen und gut im
|
|
Deuten. Es kann nicht im Minutentakt schauen, hat keinen Verlauf im Kopf, sieht
|
|
die anderen Installationen nicht und antwortet zweimal verschieden auf dieselbe
|
|
Lage. Die Aufteilung waere also auch ohne den Sicherheitsaspekt richtig.
|
|
|
|
Der Beobachter meldet **Symptome und Koordinaten** (`build`, `commit_sha`,
|
|
`file`, `line`). Der Diagnostiker loest die Koordinaten gegen den Quellcode auf.
|
|
So braucht der Client den Code nie zu sehen.
|
|
|
|
---
|
|
|
|
## 1. Detektor-Katalog
|
|
|
|
Der Katalog ist der Kern. Er legt fest, wonach gesucht wird, und zwar unter
|
|
stabilen Namen — damit Befunde aus verschiedenen Projekten vergleichbar bleiben
|
|
und `dc_findings` etwas Auswertbares liefert.
|
|
|
|
Ein Detektor-Name ist eine Zeichenkette der Form `familie.sache`. Er wandert
|
|
nie mehr; kommt etwas dazu, bekommt es einen neuen Namen.
|
|
|
|
### 1.1 Detektoren, die den Fehler nicht vorher kennen muessen
|
|
|
|
Diese Gruppe ist der eigentliche Gewinn. Sie findet Dinge, an die niemand
|
|
gedacht hat, weil der Massstab nicht aus einem Kopf kommt, sondern aus der
|
|
Wirklichkeit.
|
|
|
|
| Name | Findet | Laeuft |
|
|
|---|---|---|
|
|
| `novel.error_signature` | Fehlersignatur, die es in dieser Fassung noch nie gab | Server |
|
|
| `novel.log_template` | Logzeilen-Schablone, die noch nie auftrat | Server |
|
|
| `silence.periodic` | Bekanntes wiederkehrendes Ereignis bleibt aus (still gestorbener Hintergrundjob) | Client |
|
|
| `silence.heartbeat` | Instanz meldet sich nicht mehr | Server |
|
|
| `deviation.self` | Abweichung vom eigenen Verlauf der letzten Wochen | Server |
|
|
| `deviation.fleet` | Ausreisser gegenueber anderen Installationen derselben Fassung | Server |
|
|
| `regression.build` | Kennzahl verschiebt sich nach einem Update gegenueber der Vorgaengerfassung | Server |
|
|
|
|
`deviation.self` ist bereits vorhanden: `MetricStore::deviation()` rechnet die
|
|
Abweichung mit einem Faktor auf die Streuung. `novel.error_signature` ist
|
|
nahezu geschenkt, weil `BugRepo` mit `first_seen_at` und `occurrence_count`
|
|
schon gruppiert und zaehlt.
|
|
|
|
`deviation.fleet` ist der staerkste und bisher ungenutzte: dieselbe Fassung
|
|
laeuft auf N Installationen, eine faellt bei irgendeiner Kennzahl aus dem
|
|
Rahmen — auch bei einer, an die niemand gedacht hat.
|
|
|
|
### 1.2 Detektoren ueber die Zeitachse
|
|
|
|
Ein Unit-Test laeuft Millisekunden auf frischem Zustand, ein Kundenprozess
|
|
Wochen. Alles, was sich ansammelt, ist fuer Tests strukturell unsichtbar.
|
|
|
|
| Name | Findet | Laeuft |
|
|
|---|---|---|
|
|
| `trend.monotonic` | Kennzahl waechst ueber N Fenster nur nach oben (Speicher-, Handle-, Cache-Leck) | Client |
|
|
| `trend.saturation` | Kennzahl naehert sich einer harten Grenze (Platte, Verbindungspool, Dateihandles) | Client |
|
|
| `trend.latency` | Antwortzeiten driften ueber Tage nach oben (Index-Degradation) | Client |
|
|
|
|
### 1.3 Detektoren, mit denen die Anwendung sich selbst verpfeift
|
|
|
|
Der ergiebigste und billigste Fang: Zaehler auf die Stellen, an denen die
|
|
Software heute schon still verzeiht. Dort sitzen die Fehler, die niemand
|
|
meldet.
|
|
|
|
| Name | Findet | Laeuft |
|
|
|---|---|---|
|
|
| `swallowed.exception` | `catch`-Bloecke, die einen Fehler schlucken und weitermachen | Client |
|
|
| `fallback.usage` | Rueckfall auf den degradierten Pfad haeuft sich | Client |
|
|
| `retry.storm` | Wiederholungsversuche haeufen sich | Client |
|
|
| `probe.failed` | Registrierte Probe schlaegt fehl | Client |
|
|
| `probe.slow` | Probe antwortet, aber deutlich langsamer als ueblich | Client |
|
|
|
|
`fallback.usage` ist der unterschaetzte Eintrag: "Wir haben heute 4.000-mal den
|
|
Notfallweg genommen und es ist niemandem aufgefallen" ist ein Befund, den weder
|
|
ein Test noch ein Anwender je erzeugt.
|
|
|
|
### 1.4 Fachliche Zusicherungen
|
|
|
|
| Name | Findet | Laeuft |
|
|
|---|---|---|
|
|
| `invariant.violated` | Vom Projekt formulierte Zusicherung gegen echte Daten verletzt | Client |
|
|
|
|
Das ist die einzige Gruppe, die tatsaechlich "Unit-Test zur Laufzeit" ist — und
|
|
fuer ihren Zweck ist genau das richtig. Sie deckt die Klasse ab, die sonst
|
|
komplett durchfaellt: **semantisch falsche, aber unauffaellige Ergebnisse.** Der
|
|
Bericht zeigt eine falsche Zahl, die Rundung stimmt seit Monaten nicht, ein
|
|
Mandant sieht Daten eines anderen. Nichts stuerzt ab, keine Kennzahl weicht ab,
|
|
keine Signatur ist neu — kein anderer Detektor sieht das.
|
|
|
|
Beispiele, wie ein Projekt sie formuliert:
|
|
|
|
Supervisor.Expect("saldo.nonnegative", () => konto.Saldo >= 0);
|
|
Supervisor.Expect("beleg.balanced", () => soll == haben);
|
|
Supervisor.Expect("mandant.unique", () => satz.MandantIds.Count == 1);
|
|
|
|
### 1.5 Was der Katalog bewusst nicht abdeckt
|
|
|
|
Ehrlichkeitshalber festgehalten: Ein Fehler, der plausibel aussieht, keine
|
|
Kennzahl bewegt, keine Ausnahme wirft und gegen keine formulierte Zusicherung
|
|
verstoesst, wird hier nicht gefunden. Der einzige Hebel dagegen sind mehr und
|
|
bessere Zusicherungen aus 1.4.
|
|
|
|
---
|
|
|
|
## 2. Befund-Format
|
|
|
|
Ein Befund ist keine Fehlermeldung. Er behauptet nicht, dass etwas kaputt ist,
|
|
sondern dass etwas ungewoehnlich ist.
|
|
|
|
POST /api/supervisor/v1/observe Scope: supervisor:report
|
|
|
|
```json
|
|
{
|
|
"project_slug": "myapp",
|
|
"instance": "kunde-4711/app-01",
|
|
"detector": "trend.monotonic",
|
|
"subject": "memory.working_set",
|
|
"observed": {"slope_per_hour": 18400000, "windows": 9},
|
|
"baseline": {"median": 412000000, "stddev": 9100000},
|
|
"severity_hint": "medium",
|
|
"build": "v1.4.2",
|
|
"commit_sha": "a21536f",
|
|
"environment": "production",
|
|
"first_seen_at": "2026-08-19T04:12:00Z",
|
|
"client_ref": "myapp/trend.monotonic/memory.working_set/v1.4.2"
|
|
}
|
|
```
|
|
|
|
`client_ref` ist bewusst aus Detektor, Gegenstand und Fassung gebaut und nicht
|
|
zufaellig: derselbe Befund darf beliebig oft gemeldet werden, ohne ein Duplikat
|
|
anzulegen. Die Deduplizierung in `BugRepo::findByClientRef()` greift dann
|
|
bereits.
|
|
|
|
`severity_hint` heisst Hinweis, nicht Schweregrad. Die Einstufung entscheidet
|
|
die empfangende Seite, die den Flottenblick hat.
|
|
|
|
---
|
|
|
|
## 3. Supervisor-Client im SDK
|
|
|
|
Ein schlanker, regelbasierter Laeufer. Kein Sprachmodell, keine
|
|
Netzabhaengigkeit fuer die Erkennung selbst.
|
|
|
|
### 3.1 Schnittstelle
|
|
|
|
```csharp
|
|
public interface IHealthProbe
|
|
{
|
|
string Name { get; } // z. B. "db.reachable"
|
|
TimeSpan Interval { get; }
|
|
Task<ProbeResult> RunAsync(CancellationToken ct);
|
|
}
|
|
```
|
|
|
|
Dazu die Meldewege, die eine Anwendung an ihren heiklen Stellen einstreut:
|
|
|
|
```csharp
|
|
Supervisor.Expect(name, bedingung); // invariant.violated
|
|
Supervisor.Swallowed(name, ex); // swallowed.exception
|
|
Supervisor.Fallback(name); // fallback.usage
|
|
Supervisor.Retry(name); // retry.storm
|
|
Supervisor.Beat(name); // Bezugspunkt fuer silence.periodic
|
|
```
|
|
|
|
Alle fuenf sind absichtlich einzeilig und ohne Rueckgabewert. Was Ueberlegung
|
|
kostet, wird nicht eingebaut.
|
|
|
|
### 3.2 Verhalten
|
|
|
|
- Zustand liegt lokal, damit `client_ref` ueber Neustarts stabil bleibt
|
|
- Zaehler werden gebuendelt gemeldet, nicht je Vorfall
|
|
- gemeldet wird nur bei Zustandswechsel oder nach Ablauf eines Ruhefensters
|
|
- `429 rate_limited` verdoppelt das Intervall (wie in der Prompt-Vorlage
|
|
beschrieben)
|
|
- faellt das Deploymentcenter aus, laeuft die Anwendung unveraendert weiter;
|
|
Befunde gehen dann verloren und werden nicht gepuffert
|
|
|
|
Der letzte Punkt ist Absicht. Ein Ueberwachungsteil, das die ueberwachte
|
|
Anwendung aufhalten oder ihren Speicher fuellen kann, ist schlimmer als keines.
|
|
|
|
### 3.3 Fassungen
|
|
|
|
- `.NET` in `client-dotnet/Deploymentcenter.Client/Supervisor.cs`
|
|
- `PHP` in `src/Modules/Supervisor/` fuer die PHP-Anwendungen
|
|
|
|
---
|
|
|
|
## 4. Serverseite
|
|
|
|
### 4.1 Aufnahme
|
|
|
|
`public/api/supervisor/v1/observe.php`, Modul `src/Modules/Supervisor/` mit
|
|
`FindingRepo`. Bestaetigte Befunde koennen in ein Bugtracker-Item uebergehen;
|
|
unbestaetigte bleiben Befund.
|
|
|
|
### 4.2 Die serverseitigen Detektoren
|
|
|
|
Sie haengen in `cli/tick.php` neben `Evaluator::run()` — minuetlicher Cron mit
|
|
Ueberlappungsschutz ist dort bereits geloest.
|
|
|
|
Wichtig fuer die Reihenfolge: **Diese Detektoren brauchen keinen neuen Client.**
|
|
`novel.error_signature`, `silence.heartbeat`, `deviation.self`,
|
|
`deviation.fleet` und `regression.build` arbeiten auf Daten, die heute schon
|
|
hereinkommen — Fehlerberichte, Watchdog-Pings, Kennzahlen. Sie liefern Nutzen,
|
|
bevor eine einzige Anwendung ein neues SDK bekommen hat.
|
|
|
|
---
|
|
|
|
## 5. Projektuebergreifend arbeiten
|
|
|
|
Einige Projekte sind stark verzahnt, das Deploymentcenter am staerksten. Ein
|
|
Agent, der das SDK in Projekt X integriert und dabei einen Fehler im
|
|
Deploymentcenter findet, muss ihn dort ablegen koennen.
|
|
|
|
### 5.1 Die heutige Sperre
|
|
|
|
`ApiAuth::enforceProject()` bricht mit `403 project_forbidden` ab, sobald ein
|
|
projektgebundenes Token ein fremdes Projekt anspricht. Die Prompt-Vorlage
|
|
fordert genau das aber ein ("Faellt dir ein Fehler im Deployment Center selbst
|
|
auf, melde ihn unter `deploymentcenter`"). Die Vorlage verspricht etwas, das die
|
|
API verweigert.
|
|
|
|
### 5.2 Loesung ueber den vorhandenen Token-Typ
|
|
|
|
Die Sperre wird nicht aufgeweicht — sie ist richtig, nur zu grob. Sie
|
|
unterscheidet nicht, **wo das Token liegt**:
|
|
|
|
- **Laufzeit-Token** (im ausgelieferten Client, auf Kundenhardware): streng
|
|
projektgebunden, nur melden, nie uebergreifend. Ein extrahiertes Kundentoken
|
|
darf nicht in fremde Tracker schreiben. Hier bleibt alles wie es ist.
|
|
- **Werkbank-Token** (Claude Code, MCP, eigene Maschine): darf ueber die
|
|
Projekte hinweg.
|
|
|
|
`TokenManager::OWNER_TYPES` kennt `dev_agent` bereits. Da die Instanz
|
|
ausschliesslich eigene Projekte fuehrt und es keine geteilte Instanz fuer
|
|
Fremde geben wird, genuegt das als Unterscheidung — kein neues Feld, keine
|
|
Mandantentrennung.
|
|
|
|
`enforceProject()` bekommt eine Ausnahme: `owner_type = 'dev_agent'` darf fremde
|
|
Projekte ansprechen. Lesend breit, schreibend eng — melden und kommentieren ja,
|
|
fremde Items aufloesen oder schliessen nein.
|
|
|
|
### 5.3 Das eigentliche Risiko ist Fehlleitung
|
|
|
|
Ein Agent in Projekt X kann kaum unterscheiden, ob das Deploymentcenter kaputt
|
|
ist oder ob X das SDK falsch benutzt. Die Voreinstellung eines hilfsbereiten
|
|
Modells ist im Zweifel "melde es".
|
|
|
|
Schlimmer als der Laerm ist der Folgeschaden: Fehlmeldungen vergiften die
|
|
Statistik, und die Statistik ist die Grundlage der Detektoren aus 1.1. Ein
|
|
Detektor, der auf Fehlmeldungen kalibriert, ist wertlos.
|
|
|
|
Drei Bremsen:
|
|
|
|
- **Begruendungspflicht.** Ein Bericht gegen ein fremdes Projekt verlangt
|
|
`evidence`: was wurde beobachtet, und warum liegt die Ursache dort und nicht
|
|
hier. Etwas ausformulieren zu muessen kostet einen Reflex fast immer den Kopf.
|
|
- **Eigener Eingang.** Fremdmeldungen landen mit `status = 'triage_external'`,
|
|
nicht im offenen Backlog, und zaehlen erst nach Bestaetigung in die Statistik.
|
|
- **Gedeckelter Schweregrad.** Fremde Melder duerfen `idea`, `wishlist`, `low`,
|
|
`medium`. `high` und `critical` vergibt die empfangende Seite.
|
|
|
|
### 5.4 Herkunft und Buendelung
|
|
|
|
Jeder uebergreifende Bericht traegt `reported_from`. Das ist keine Buchhaltung,
|
|
sondern das wertvollste Signal im Vorgang: Melden drei Projekte unabhaengig
|
|
dieselbe Sache gegen das Deploymentcenter, ist das kein "low" mehr. Statt drei
|
|
Items entsteht eines mit wachsender `affects`-Liste.
|
|
|
|
Die Buendelung laeuft ueber die Signatur, nicht ueber `client_ref` — der ist nur
|
|
je Melder eindeutig.
|
|
|
|
### 5.5 Beziehungen zwischen Projekten
|
|
|
|
`dc_projects` kennt heute Slug, Name und Notiz. Es fehlt die Beziehung.
|
|
|
|
Neue Tabelle `dc_project_links` mit `from_slug`, `to_slug`, `kind`
|
|
(`uses_sdk`, `depends_on`, `shares_code`) und `integrated_version`.
|
|
|
|
Das loest nebenbei ein Wartungsproblem: Die von Hand gepflegte Zeile
|
|
"Deploymentcenter-Anbindung: SDK 2.5.1" in jeder Projekt-`CLAUDE.md` wandert
|
|
dorthin, wo sie hingehoert. Der Agent meldet die Fassung ueber MCP, wenn er die
|
|
Anbindung anfasst. Damit ist zum ersten Mal beantwortbar: **Welche meiner
|
|
Projekte sind von diesem SDK-Fehler betroffen?**
|
|
|
|
### 5.6 Rueckkanal
|
|
|
|
Wird das Item in SDK 2.6.0 behoben, muessen die meldenden Projekte das
|
|
erfahren — sonst meldet Projekt X denselben Punkt in drei Monaten erneut und
|
|
baut seinen Workaround nie zurueck.
|
|
|
|
`GET /api/updateservice/v1/changelog?since=…` liefert bereits `action_items`.
|
|
Ergaenzt um "was du gemeldet hast, ist in 2.6.0 erledigt" schliesst sich der
|
|
Kreis.
|
|
|
|
---
|
|
|
|
## 6. MCP-Server
|
|
|
|
### 6.1 Was er bringt
|
|
|
|
Der offensichtliche Teil: Anmeldung einmal statt je Projekt, Schemata statt
|
|
Prosa, kein `curl` aus dem Gedaechtnis.
|
|
|
|
Der wertvollere: **`docs/AGENT_PROMPT_TEMPLATE.md` verschwindet fast
|
|
vollstaendig.** Die Datei ist heute in jedes Projekt einkopiert, samt der Zeile
|
|
"SDK 2.5.1, integriert am …". Das ist eine Wartungslast, die je Projekt waechst
|
|
und beim ersten Vergessen schweigend veraltet. Ein MCP-Server liefert immer die
|
|
aktuelle Form — die Frage "gegen welche Fassung habe ich integriert" stellt sich
|
|
nicht mehr, weil nichts mehr einkopiert ist.
|
|
|
|
### 6.2 Der Schnitt: nicht aus OpenAPI erzeugen
|
|
|
|
Naheliegend waere, die Werkzeuge aus `public/api/openapi.php` abzuleiten. Dort
|
|
stehen 24 Endpunkte — 24 Werkzeuge sind ein Kontextfresser, denn
|
|
Werkzeugdefinitionen liegen dauerhaft im Fenster, anders als eine Doku, die man
|
|
einmal liest. Ein aufgeblaehter MCP-Server ist schlechter als die 30 Zeilen
|
|
Prompt von heute.
|
|
|
|
Kuratiert, an der Arbeitsweise entlang statt an der API:
|
|
|
|
| Werkzeug | Zweck |
|
|
|---|---|
|
|
| `dc_projects` | Projekte mit Kurzbeschreibung **und Beziehung zum aktuellen Projekt** |
|
|
| `dc_next_task` | Item uebernehmen, `409 already_claimed` intern behandelt |
|
|
| `dc_get_item` | Details, Verlauf, Kommentare |
|
|
| `dc_search` | Items filtern: Projekt, Status, Schweregrad, Build |
|
|
| `dc_report` | Melden — mit `project_slug`, `reported_from`, bei fremdem Ziel `evidence` |
|
|
| `dc_comment` | Fortschritt mit `action_taken` |
|
|
| `dc_resolve` / `dc_release` | Abschliessen bzw. zurueckgeben |
|
|
| `dc_my_reports` | Was hat dieses Projekt anderswo gemeldet, was wurde daraus |
|
|
| `dc_error_groups` | Fehlergruppen mit `occurrence_count`, `first_seen_at` |
|
|
| `dc_findings` | Supervisor-Befunde nach Detektor, Instanz, Fassung |
|
|
| `dc_metrics` | Verlauf und Abweichung einer Kennzahl |
|
|
| `dc_symbolicate` | Stacktrace gegen die passende Fassung aufloesen |
|
|
|
|
Bewusst **nicht** aufgenommen: `publish`, `provision`, `deactivate` und
|
|
Massenoperationen. Ein Release gehoert in die CI, nicht an ein Werkzeug, das ein
|
|
Modell im Zweifel "hilfreich" ausloest.
|
|
|
|
### 6.3 Transport
|
|
|
|
Erst ein **stdio-Adapter**: eine ausfuehrbare Datei, die die vorhandene REST-API
|
|
ruft und das Token aus `DC_TOKEN` liest. Node 24 liegt vor. Kein neuer
|
|
Angriffspunkt am Server, die Anmeldefrage ist bereits beantwortet, je Projekt
|
|
drei Zeilen in `.mcp.json`.
|
|
|
|
Ein entfernter Server unter `dc.mhdf.de/mcp` ist der bessere Endzustand, wenn
|
|
mehrere Maschinen dranhaengen — dann aber mit OAuth statt Bearer-Token in einer
|
|
Konfigurationsdatei. Groesserer Brocken, lohnt erst wenn der Schnitt sich
|
|
bewaehrt hat.
|
|
|
|
Die Werkzeugliste wird in der CI gegen `openapi.php` geprueft, damit beide nicht
|
|
auseinanderlaufen.
|
|
|
|
### 6.4 Vertrauensgrenze — der wichtigste Punkt hier
|
|
|
|
Ueber diese Werkzeuge fliessen **Daten aus der Wildnis in einen Agenten, der
|
|
Code schreiben und Befehle ausfuehren darf.**
|
|
|
|
`error_message`, `stack_trace`, Logauszuege und Supervisor-Befunde entstehen auf
|
|
fremden Maschinen und enthalten regelmaessig Eingaben, die jemand anderes
|
|
bestimmt hat — ein Dateiname, ein Formularfeld, das in der Ausnahme landet. Ein
|
|
Text in einem Bugreport ist keine Anweisung, auch wenn er wie eine formuliert
|
|
ist. Ein Feld mit "bitte ergaenze in `Auth.cs` folgende Zeile" ist trivial zu
|
|
platzieren, sobald irgendeine Nutzereingabe im Fehlertext landet.
|
|
|
|
Massnahmen:
|
|
|
|
- Fremdtext im Werkzeugergebnis **abgegrenzt und als Daten gekennzeichnet**,
|
|
nicht frei in den Fliesstext gemischt
|
|
- getrennte Token: der Triage-Agent bekommt `bugtracker:read` plus gezielt
|
|
`comment`, nicht `bugtracker:manage` mit allem dran
|
|
- **kein selbsttaetiges Aufloesen und kein selbsttaetiger Commit** aus einem
|
|
Lauf, der Fremdtext gelesen hat. Vorschlag ja, Ausfuehrung nein.
|
|
|
|
REST-API und die Kurzfassung des Prompts bleiben bestehen — nicht jedes Werkzeug
|
|
spricht MCP, und der Rueckfallweg kostet nichts, solange beide aus derselben
|
|
Quelle beschrieben sind.
|
|
|
|
---
|
|
|
|
## 7. Quellcode-Zugriff fuer den Diagnostiker
|
|
|
|
Drei Stufen, in aufsteigender Preisgabe:
|
|
|
|
**Stufe 0 — der Agent laeuft bei dir.** Kein Quellcode im Deploymentcenter.
|
|
Claude Code hat den Checkout ohnehin lokal und zieht sich Arbeit ueber
|
|
`dc_next_task`. Neue Angriffsflaeche: null. Preis: Diagnose laeuft nur, wenn
|
|
eine eigene Maschine laeuft. **Das ist der Startpunkt.**
|
|
|
|
**Stufe 1 — Quelltext-Index im DC, nur Ausschnitte.** Noetig erst, wenn ein
|
|
Agent autonom rund um die Uhr laufen soll. Dann aber keine klonbare Kopie,
|
|
sondern eine Schnittstelle, die nie ein Ganzes herausgibt:
|
|
|
|
GET /api/source/v1/snippet?commit=a21536f&file=…&line=42&context=40
|
|
GET /api/source/v1/search?q=…&limit=20
|
|
|
|
Neuer Scope `source:read`, nicht an Client-Token vergeben, verschluesselt
|
|
abgelegt, Budget je Token und Tag, jeder Abruf im Pruefprotokoll. Der
|
|
Unterschied zwischen "darf nachschlagen" und "darf mitnehmen".
|
|
|
|
**Stufe 2 — nur Metadaten.** Signaturen, Aufrufgraph, Doc-Kommentare, ohne
|
|
Methodenkoerper. Reicht zur Triage, reicht nicht zum Nachbauen.
|
|
|
|
### Symbol-Upload
|
|
|
|
Unabhaengig von der Stufe: Der Packager laedt beim `publish` die PDB bzw.
|
|
Sourcemap mit hoch, verknuepft mit `commit_sha`. Ausgeliefert wird ein
|
|
gestripptes Binary. Der Kunde bekommt `at 0x4a2f`, du bekommst
|
|
`UserAuthService.cs:42`. Kein Quellcode verlaesst das Haus, die Berichte werden
|
|
trotzdem so gut wie mit Debug-Build. `dc_symbolicate` haengt daran.
|
|
|
|
### Was nicht funktioniert
|
|
|
|
- Deploy-Key oder Repo-Token im Client — dekompiliert in Minuten
|
|
- Quellcode verschluesselt mitliefern — der Client muss entschluesseln koennen,
|
|
also kann es der Kunde auch
|
|
- den Sprachmodell-Supervisor auf der Kundenmaschine — dann liegt der
|
|
API-Schluessel dort, und aller Kontext im Speicher fremder Hardware
|
|
- Obfuskation als Schutz — verzoegert, verhindert nicht
|
|
|
|
---
|
|
|
|
## 8. Datenbank
|
|
|
|
**Erledigt — `sql/migrations/013_cross_project_reporting.sql`** (Etappe 1):
|
|
|
|
- `dc_project_links` — `from_slug`, `to_slug`, `kind`, `integrated_version`
|
|
- `bugtracker_items` — neue Spalten `reported_from`, `evidence`
|
|
- `bugtracker_item_affects` — betroffene Projekte je Item
|
|
- `bugtracker_items.status` — Wert `triage_external` ergaenzt
|
|
|
|
**Erledigt — `sql/migrations/014_supervisor_findings.sql`** (Etappe 2):
|
|
|
|
- `supervisor_findings` — Befunde nach dem Format aus Abschnitt 2
|
|
- `watchdog_monitors.project_slug` — Kohortenbildung fuer den Flottenvergleich
|
|
- Taktgeber `supervisor_detectors` in `watchdog_cron_jobs`
|
|
|
|
Scopes in `TokenManager::KNOWN_SCOPES`, ergaenzt:
|
|
|
|
- `supervisor:report` — Befunde einliefern
|
|
- `supervisor:read` — Befunde lesen
|
|
- `supervisor:manage` — Befunde sichten und einstufen
|
|
- `source:read` — nur fuer Stufe 1, spaeter
|
|
|
|
`IMPLIED_SCOPES` entsprechend: `supervisor:report` und `supervisor:manage`
|
|
schliessen `supervisor:read` ein. Dass Melden und Einstufen getrennt sind, ist
|
|
Absicht: ein Beobachter auf Kundenhardware darf melden, aber nicht
|
|
entscheiden, dass seine eigene Meldung erledigt ist.
|
|
|
|
Etappe 1 brauchte keinen neuen Scope: die Unterscheidung laeuft ueber
|
|
`owner_type = 'dev_agent'`, den `TokenManager::OWNER_TYPES` bereits kannte.
|
|
|
|
---
|
|
|
|
## 9. Etappen
|
|
|
|
**Etappe 1 — MCP-Adapter ueber den Bestand. ERLEDIGT.**
|
|
Werkzeuge fuer alles, was heute schon existiert: `dc_projects`, `dc_next_task`,
|
|
`dc_get_item`, `dc_search`, `dc_report`, `dc_comment`, `dc_resolve`,
|
|
`dc_release`, `dc_error_groups` — in `mcp/deploymentcenter-mcp.mjs`, ohne
|
|
Fremdabhaengigkeiten. Dazu `dev_agent` in `enforceProject()`,
|
|
`dc_project_links`, `reported_from`, `evidence`, `triage_external`.
|
|
Kein Serverumbau, sofort nutzbar, ersetzt den Grossteil der Prompt-Vorlage.
|
|
|
|
Noch offen aus dieser Etappe: ein Werkzeug, mit dem der Agent
|
|
`integrated_version` fortschreibt (`ProjectLinks::record()` ist da, der
|
|
Endpunkt fehlt), und das Zurueckziehen der Prompt-Vorlage in den Projekten.
|
|
|
|
**Etappe 2 — Katalog und serverseitige Detektoren. ERLEDIGT.**
|
|
Katalog in `src/Modules/Supervisor/Catalog.php`, Ablage in `FindingRepo`,
|
|
Detektoren in `ServerDetectors` (haengen in `cli/tick.php`, laufen alle zehn
|
|
Minuten), Schnittstelle unter `/api/supervisor/v1/`, dazu `dc_findings`,
|
|
`dc_finding_summary` und `dc_metrics` im MCP-Adapter.
|
|
**Nutzen ohne eine einzige Client-Aenderung.**
|
|
|
|
Umgesetzt sind `novel.error_signature`, `silence.heartbeat`, `deviation.self`,
|
|
`deviation.fleet` und `regression.build`. Offen aus 1.1 bleibt
|
|
`novel.log_template` — dafuer muessten erst Logauszuege strukturiert
|
|
hereinkommen.
|
|
|
|
Eine Einschraenkung, die man kennen muss: `regression.build` vergleicht die
|
|
beiden hoechsten Fassungen im Feld im **Querschnitt**, also verschiedene
|
|
Maschinen zur selben Zeit — nicht dieselbe Maschine vor und nach dem Update.
|
|
Ein echter Laengsschnitt braeuchte eine Historie der `app_version` je Monitor;
|
|
das Feld wird heute ueberschrieben.
|
|
|
|
Voraussetzung fuer `deviation.fleet` und `regression.build`: Monitore brauchen
|
|
eine Projektzuordnung (`watchdog_monitors.project_slug`, neu in Migration 014).
|
|
Sie wird administrativ gesetzt, nicht vom Agenten gemeldet — sonst braeuchte
|
|
diese Etappe doch einen Rollout. Ohne Zuordnung laufen die uebrigen Detektoren
|
|
weiter; ihre Befunde landen unter `supervisor.default_project`.
|
|
|
|
**Etappe 3 — Supervisor-Client. ERLEDIGT.**
|
|
`.NET` in `client-dotnet/Deploymentcenter.Client/Supervisor*.cs`, PHP als
|
|
einzelne Datei in `client-php/DeploymentcenterSupervisor.php`, dazu
|
|
`docs/SUPERVISOR_INTEGRATION_GUIDE.md`.
|
|
|
|
Umgesetzt sind alle clientseitigen Detektoren aus 1.2 bis 1.4:
|
|
`trend.monotonic`, `trend.saturation`, `trend.latency`,
|
|
`swallowed.exception`, `fallback.usage`, `retry.storm`, `probe.failed`,
|
|
`probe.slow`, `silence.periodic`, `invariant.violated`.
|
|
|
|
Der PHP-Entwurf weicht notwendig ab: es gibt kein dauerhaft laufendes Programm,
|
|
in dem ein Beobachter mitlaufen koennte. Der Zustand liegt deshalb in einer
|
|
Datei unter Sperre, ausgewertet wird von der ersten Anfrage nach Ablauf des
|
|
Intervalls, gesendet wird nach `fastcgi_finish_request()`. Proben laufen
|
|
dadurch in einer echten Anfrage mit und muessen billig sein - das steht so in
|
|
der Anleitung.
|
|
|
|
Ausrollen ueber die Projekte, eines nach dem anderen.
|
|
|
|
**Etappe 4 — Symbol-Upload und `dc_symbolicate`.**
|
|
Packager erweitern, Symbolisierung serverseitig.
|
|
|
|
**Etappe 5 — Quelltext-Index Stufe 1.**
|
|
Nur falls ein autonomer Agent ohne laufende eigene Maschine gebraucht wird.
|
|
Bis dahin bewusst offen gelassen.
|
|
|
|
---
|
|
|
|
## 10. Offene Punkte
|
|
|
|
**Entschieden beim Umsetzen** (standen hier vorher als offen):
|
|
|
|
- Aufbewahrung der Befunde: 30 Tage in `FindingRepo::purge()`, aufgerufen am
|
|
Ende jedes Detektorlaufs. Deutlich kuerzer als bei Bugtracker-Items, weil
|
|
Befunde um Groessenordnungen haeufiger entstehen. Entfernt werden nur
|
|
erledigte, stummgeschaltete und uebernommene - ein offener Befund, der seit
|
|
Wochen dasteht, ist eine unbeantwortete Frage und soll unbequem bleiben.
|
|
- Kohortengroesse fuer `deviation.fleet`: fuenf, als `MIN_COHORT` in
|
|
`ServerDetectors`. Darunter ist die Streuung so grob geschaetzt, dass jeder
|
|
zweite Wert als Ausreisser durchginge.
|
|
- `probe.slow` ist ein eigener Detektor geblieben. Er vergleicht gegen das
|
|
gleitende Mittel der Probe selbst und nur ueber erfolgreiche Laeufe -
|
|
`deviation.self` haette dafuer den falschen Massstab.
|
|
|
|
**Weiterhin offen:**
|
|
|
|
- `novel.log_template` aus Abschnitt 1.1 - dafuer muessten erst Logauszuege
|
|
strukturiert hereinkommen.
|
|
- Ein Laengsschnitt fuer `regression.build`. Braucht eine Historie der
|
|
`app_version` je Monitor; das Feld wird heute ueberschrieben.
|
|
- Die Schwellen der clientseitigen Trenderkennung (zehn Prozent Zuwachs ueber
|
|
sechs Fenster) sind gesetzt, aber noch an keiner echten Installation
|
|
nachgeprueft.
|
|
|
|
> Wer hier etwas ergaenzt: Beim Umsetzen bitte auch wieder herausnehmen. Diese
|
|
> Liste stand einmal auf einem Stand, den der Code laengst ueberholt hatte, und
|
|
> hat prompt zu einer Fehlmeldung gefuehrt.
|