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>
26 KiB
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 ü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:
- ein Supervisor, der in jeder Anwendung laufend nachsieht, ob etwas schieflaeuft, und Befunde meldet
- ein Detektor-Katalog, der festlegt, wonach er sucht — in allen Projekten unter denselben Namen
- 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
{
"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
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:
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_refueber Neustarts stabil bleibt - Zaehler werden gebuendelt gemeldet, nicht je Vorfall
- gemeldet wird nur bei Zustandswechsel oder nach Ablauf eines Ruhefensters
429 rate_limitedverdoppelt 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
.NETinclient-dotnet/Deploymentcenter.Client/Supervisor.csPHPinsrc/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.highundcriticalvergibt 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:readplus gezieltcomment, nichtbugtracker:managemit 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_versionbugtracker_items— neue Spaltenreported_from,evidencebugtracker_item_affects— betroffene Projekte je Itembugtracker_items.status— Werttriage_externalergaenzt
Erledigt — sql/migrations/014_supervisor_findings.sql (Etappe 2):
supervisor_findings— Befunde nach dem Format aus Abschnitt 2watchdog_monitors.project_slug— Kohortenbildung fuer den Flottenvergleich- Taktgeber
supervisor_detectorsinwatchdog_cron_jobs
Scopes in TokenManager::KNOWN_SCOPES, ergaenzt:
supervisor:report— Befunde einliefernsupervisor:read— Befunde lesensupervisor:manage— Befunde sichten und einstufensource: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, alsMIN_COHORTinServerDetectors. Darunter ist die Streuung so grob geschaetzt, dass jeder zweite Wert als Ausreisser durchginge. probe.slowist ein eigener Detektor geblieben. Er vergleicht gegen das gleitende Mittel der Probe selbst und nur ueber erfolgreiche Laeufe -deviation.selfhaette dafuer den falschen Massstab.
Weiterhin offen:
novel.log_templateaus Abschnitt 1.1 - dafuer muessten erst Logauszuege strukturiert hereinkommen.- Ein Laengsschnitt fuer
regression.build. Braucht eine Historie derapp_versionje 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.