Files
Deploymentcenter/docs/ROADMAP.md
T
Deploymentcenter BotandClaude Opus 5 1d5ac92051 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>
2026-08-29 21:59:20 +02:00

619 lines
30 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Roadmap
Der eine Ort für alles Geplante, Zurückgestellte und bewusst Verworfene.
Bis 2.6.0 lagen diese Angaben über mehrere Entwurfsdokumente verstreut — mit
der Folge, dass eine Liste offener Punkte noch als offen galt, obwohl der Code
sie längst erledigt hatte. Deshalb: **Was hier steht, gilt. Wer etwas umsetzt,
zieht den Eintrag hier nach.**
Die abgelösten Entwürfe liegen unter [archiv/](./archiv/) — sie enthalten die
ausführliche Begründung, aber keinen gültigen Stand mehr.
---
## Status-Kennzeichnung
| | Bedeutung |
|---|---|
| ✅ | Erledigt und ausgeliefert |
| 🔨 | In Arbeit |
| 📋 | Geplant, als Nächstes dran |
| 🧊 | **Zurückgestellt** — bewusst nicht jetzt, Auslöser genannt |
| ❌ | **Verworfen** — mit Begründung, nicht erneut vorschlagen |
| ⚙️ | Betriebsaufgabe, kein Code |
---
## Als Nächstes
1. **[I8] Migration 016 ausführen** — ohne sie steht das Roadmap-Modul, das
2.7.0 mitbringt, vor leeren Spalten
2. **[I9] Diese Datei selbst übernehmen** — das Verfahren einmal hier
durchlaufen, bevor die anderen Projekte es aus der Anleitung bekommen
3. **[B1] Befunde in der Oberfläche** — sie sind derzeit nur über API und MCP
erreichbar. Ohne Sicht auf die Befunde ist alles Weitere blind
4. **[G5] `dc-testkit findings`** — dasselbe von der Test-VM aus, und
Voraussetzung für G8
5. **[G8] Testartefakt oder echter Befund?** — die Frage, an der sich
entscheidet, ob Befunde aus Testläufen etwas wert sind
6. **[A4] Symbol-Upload und `dc_symbolicate`** — Stacktraces aus gestrippten
Binaries auflösen, ohne dass Quelltext das Haus verlässt
Davor stehen die Betriebsaufgaben ⚙️ aus Abschnitt E — ohne sie laufen zwei
der fünf serverseitigen Detektoren gar nicht.
**Diese Liste ist die letzte ihrer Art.** Ab I9 ergibt sie sich aus Reihenfolge
und Status und wird erzeugt, statt hier fortgeschrieben zu werden — sie ist
genau die Sorte Angabe, die von Hand zuverlässig veraltet.
Nicht mehr auf der Liste: der Supervisor im ausgelieferten Programm. Verworfen,
siehe H.
---
## A — Supervisor und Befunde
Der Supervisor beantwortet die Frage „ist das ungewöhnlich?". Die Frage „ist
das schlimm?" beantwortet das Deploymentcenter, wo Verlauf, Flotte und
Quelltext bekannt sind. Diese Trennung ist die Grundentscheidung des ganzen
Entwurfs — siehe [archiv/SUPERVISOR_MCP_DESIGN.md](./archiv/SUPERVISOR_MCP_DESIGN.md),
Abschnitt 0.
> **Der Supervisor lebt nur noch auf der Serverseite.** Ein Beobachter im
> ausgelieferten Programm ist verworfen (H) — er hätte zu viele Baustellen
> aufgemacht und wäre den Mehraufwand nicht wert gewesen. Was bleibt:
>
> - die **serverseitigen Detektoren**, die auf ohnehin eingehenden Daten
> arbeiten und nichts in den Anwendungen brauchen
> - der Eingang `POST /api/supervisor/v1/observe` für alles, was von außen
> meldet — heute Prüfwerkzeuge und Testläufe
> - der **Katalog** als gemeinsame Sprache für Befundnamen
>
> Der Zweck, den ein Client-Beobachter erfüllt hätte, ist bei
> **Error-Reporting und Bugtracker** besser aufgehoben. Die werden
> weiterentwickelt.
| | Vorhaben | Stand |
|---|---|---|
| A1 | Detektor-Katalog mit stabilen Namen (`Modules/Supervisor/Catalog.php`) | ✅ 2.6.0 |
| A2 | Fünf serverseitige Detektoren im Tick: `novel.error_signature`, `silence.heartbeat`, `deviation.self`, `deviation.fleet`, `regression.build` | ✅ 2.6.0 |
| A3 | ~~Supervisor-Client für .NET und PHP~~ | ❌ verworfen, siehe H |
| A4 | **Symbol-Upload und `dc_symbolicate`** | 📋 |
| A5 | `novel.log_template` — Logzeilen-Schablonen, die noch nie auftraten | 🧊 |
| A6 | Längsschnitt für `regression.build` | 🧊 |
| A7 | Schwellen der serverseitigen Detektoren an echten Daten nachprüfen | 📋 |
### A4 — Symbol-Upload und `dc_symbolicate` 📋
Der Packager lädt beim `publish` die PDB bzw. Sourcemap mit hoch, verknüpft mit
`commit_sha`. Ausgeliefert wird ein gestripptes Binary. Der Kunde bekommt
`at 0x4a2f`, du bekommst `UserAuthService.cs:42`.
Der Gewinn: Berichte werden so gut wie mit einem Debug-Build, **ohne dass
Quelltext das Haus verlässt**. Das ist der Hebel, der den größten Nutzen pro
Aufwand bringt — und die Voraussetzung dafür, dass ein Diagnose-Agent mit einer
Fehlermeldung überhaupt etwas anfangen kann.
Betroffen: `client-dotnet/Deploymentcenter.Packager`, ein Ablageort für
Symboldateien, `dc_symbolicate` im MCP-Adapter.
### A5 — `novel.log_template` 🧊
**Auslöser:** sobald Logauszüge strukturiert hereinkommen. Heute liefert nichts
sie in einer Form, aus der sich Schablonen bilden ließen.
### A6 — Längsschnitt für `regression.build` 🧊
`regression.build` vergleicht heute die beiden höchsten Fassungen im Feld im
**Querschnitt** — verschiedene Maschinen zur selben Zeit, nicht dieselbe
Maschine vor und nach dem Update. Bei gemischten Kohorten kann ein Unterschied
deshalb auch von der Maschine kommen statt von der Fassung.
**Auslöser:** wenn Fehlzuordnungen auffallen. Nötig wäre eine Historie der
`app_version` je Monitor; das Feld wird heute überschrieben.
### A7 — Schwellen nachprüfen 📋
Die serverseitigen Detektoren rechnen mit gesetzten, aber nirgends
nachgeprüften Werten: `SIGMA = 3.0` für `deviation.self` und `deviation.fleet`,
`MIN_COHORT = 5`, `REGRESSION_RATIO = 1.25`, `NOVEL_WINDOW_MIN = 120` — alle in
`ServerDetectors`.
Beurteilbar erst, wenn eine Weile echte Daten durchgelaufen sind. Die Frage
lautet für jeden Wert gleich: Wie viele der erzeugten Befunde hat jemand als
brauchbar eingestuft? Der Status `ignored` an den Befunden beantwortet das von
selbst, sobald gesichtet wird.
---
## B — Oberfläche
| | Vorhaben | Stand |
|---|---|---|
| B1 | **Befunde im WebUI: Liste, Filter nach Detektor, Einstufen** | 📋 |
| B2 | Fremdmeldungen sichtbar (`triage_external` in Filter, Abzeichen, Bearbeiten) | ✅ 2.6.0 |
| B3 | Monitoren ein Projekt zuweisen | 📋 |
### B1 — Befunde im WebUI 📋
Befunde sind heute nur über `/api/supervisor/v1/findings` und die MCP-Werkzeuge
erreichbar. Für die Sichtung durch einen Menschen fehlt die Ansicht — und damit
auch der einzige Weg, `supervisor:manage` sinnvoll zu nutzen.
Gebraucht wird: Zählung je Detektor als Einstieg, dahinter die Einzelbefunde
mit `observed`/`baseline`, und die Statuswechsel (`acknowledged`, `promoted`,
`resolved`, `ignored`). Beim Übernehmen in ein Bugtracker-Item die Verknüpfung
über `supervisor_findings.bug_item_id` setzen — die Spalte gibt es bereits.
### B3 — Monitoren ein Projekt zuweisen 📋
`watchdog_monitors.project_slug` wird administrativ gesetzt, nicht vom Agenten
gemeldet. Dafür fehlt das Bedienelement in der Monitor-Verwaltung. Bis dahin
nur per SQL — siehe E1.
---
## C — Projektlandschaft
| | Vorhaben | Stand |
|---|---|---|
| C1 | Projektübergreifend melden (`dev_agent`, `evidence`, `triage_external`, `affects`) | ✅ 2.6.0 |
| C2 | Beziehungen zwischen Projekten (`dc_project_links`, `integrated_version`) | ✅ 2.6.0 |
| C3 | **Rückkanal: „was du gemeldet hast, ist behoben"** | ✅ 2.6.1 — als Arbeitsschlange, nicht als Benachrichtigung |
| C4 | Agent-Prompt-Vorlage in den Projekten durch MCP ablösen | 📋 |
### C3 — Rückkanal ✅
Wird ein Item behoben, das ein anderes Projekt gemeldet hat, erfährt dieses
Projekt heute nichts davon. Folge: Es meldet denselben Punkt in drei Monaten
erneut und baut seinen Workaround nie zurück.
`GET /api/updateservice/v1/changelog?since=…` liefert bereits `action_items`.
Zu ergänzen ist der Abgleich über `bugtracker_item_affects`: „Item #42, das du
gemeldet hast, ist in 2.7.0 erledigt."
Das schließt den Kreis, den C1 geöffnet hat. Ohne ihn ist der Meldeweg ein
Briefkasten ohne Leerung.
**Gelöst in 2.6.1 — aber anders als hier ursprünglich gedacht.** Der Entwurf
sah eine Benachrichtigung vor. Gebaut wurde stattdessen eine Arbeitsschlange,
und das ist die bessere Antwort auf dieselbe Frage:
- **Passiv:** Wer erneut meldet, bekommt die Auskunft von selbst. Der
Report-Endpunkt vergleicht `build_version` gegen `resolved_in_build` und
antwortet mit `known_fixed_in`, statt ein Regressionsitem anzulegen.
- **Aktiv:** Ein veröffentlichter Fix stellt sein Item auf
`awaiting_verification`. Damit steht es in `?action=next` — auch beim
meldenden Fremdprojekt, über `bugtracker_item_affects`. Der Melder wird also
gefragt, ob der Fix bei ihm wirkt.
**Warum keine Zustellstrecke.** Agenten fragen ohnehin nach Arbeit. Ein Status,
der in der Warteschlangenabfrage vorkommt, *ist* die Zustellung — ohne
Speicher, ohne Entstörung, ohne Quittungen. Der Workaround-Fall, der die ganze
Diskussion trug, ist damit erledigt: Er brauchte keinen Push, sondern einen
Anlass, noch einmal hinzusehen.
Was bleibt: Wer einen Workaround gebaut hat, muss den Prüfauftrag auch
annehmen. Nimmt ihn niemand an, wird nach 30 Tagen ungeprüft geschlossen — mit
einem Vermerk, der das ausdrücklich sagt.
### C4 — Prompt-Vorlage entlasten 📋
[AGENT_PROMPT_TEMPLATE.md](./AGENT_PROMPT_TEMPLATE.md) ist in jedes Projekt
einkopiert, samt der von Hand gepflegten Versionszeile.
**Der Zuschnitt hat sich mit 2.6.1 geändert.** Ursprünglich stand hier
„durch MCP ablösen". Inzwischen gibt es drei Wege zum Deploymentcenter, und
keiner löst die anderen ab:
| Wo der Agent arbeitet | Weg | Was er braucht |
|---|---|---|
| Projektverzeichnis mit `.mcp.json` | MCP-Adapter | keine Vorlage |
| Linux-Test-VM | `dc-testkit` | Kurzfassung, kein `curl` |
| alles Übrige | REST direkt | die volle Vorlage |
Die Vorlage bleibt also — sie ist der Rückfallweg und beschreibt zugleich, was
`dc-testkit` tut. Zu tun ist trotzdem etwas: In Projekten **mit** eingerichtetem
Adapter kann sie auf die Kurzfassung schrumpfen, und die handgepflegte
Versionszeile ersetzt in allen Fällen `dc_link_project`.
Das ist der Punkt, an dem es sich lohnt, die Vorlage in drei Bausteine zu
zerlegen statt in einen Block: Grundlagen, „mit MCP", „auf der Test-VM". Heute
trägt jedes Projekt alles mit.
---
## D — Werkzeuganbindung (MCP)
| | Vorhaben | Stand |
|---|---|---|
| D1 | stdio-Adapter mit 13 Werkzeugen, ohne Fremdabhängigkeiten | ✅ 2.6.0 |
| D2 | Fremddaten im Werkzeugergebnis abgegrenzt kennzeichnen | ✅ 2.6.0 |
| D3 | Abgleich: Werkzeugliste gegen `openapi.php` | 📋 |
| D4 | Entfernter MCP-Server unter `/mcp` mit OAuth | 🧊 |
| D5 | `dc_roadmap` und `dc_roadmap_set` — Planungsstand als Werkzeug | ✅ 2.7.0 (siehe I) |
### D3 — Abgleich Werkzeugliste ↔ OpenAPI 📋
Adapter und OpenAPI beschreiben dieselben Endpunkte. Ohne Abgleich laufen sie
auseinander, und es fällt erst auf, wenn ein Werkzeug ins Leere greift.
Das Projekt hat **keine CI-Strecke**. Als Erstes reicht deshalb ein Skript, das
von Hand oder aus `deploy.py` heraus läuft. Eine echte Pipeline wäre ein
eigenes Vorhaben und lohnt erst, wenn es mehr zu prüfen gibt als diese eine
Zusage.
### D4 — Entfernter Server 🧊
**Auslöser:** wenn mehrere Maschinen oder Personen dranhängen. Dann aber mit
OAuth statt Bearer-Token in einer Konfigurationsdatei — sonst liegt dasselbe
Token auf jeder Maschine. Solange der stdio-Adapter je Projekt reicht, lohnt
der Aufwand nicht.
---
## E — Betrieb
Kein Code, aber Voraussetzung dafür, dass Gebautes wirkt.
| | Aufgabe | Stand |
|---|---|---|
| E1 | Migrationen 013 und 014 auf dem Server ausführen | ⚙️ |
| E2 | PHP-Seite von 2.6.0 prüfen — auf der Entwicklungsmaschine lief kein Lint | ⚙️ |
| E3 | Monitoren ein Projekt zuordnen (`watchdog_monitors.project_slug`) | ⚙️ |
| E4 | Je Projekt ein Werkbank-Token (`dev_agent`) anlegen | ⚙️ |
| E5 | Supervisor-Vorbereitungen in den Projekten zurückbauen | ⚙️ |
**E3 ist Voraussetzung für `deviation.fleet` und `regression.build`.** Ohne
Zuordnung überspringen beide Detektoren die betroffenen Monitore; die übrigen
drei laufen weiter.
**E4 vor E5.** Ohne Werkbank-Token laufen `dc_link_project` und `dc_report` aus
den Projekten heraus ins Leere.
**E2 gehört auf die Test-VM.** Die gesamte PHP-Seite von 2.6.0 — Migrationen
013 und 014, der Supervisor-Endpunkt, das projektübergreifende Melden — wurde
auf einer Maschine ohne PHP geschrieben. Weder Lint noch ein Lauf haben sie je
gesehen. Seit 2.6.1 gibt es die geteilte Test-VM (Abschnitt G); dort gehört das
geprüft, bevor es auf den Produktivserver geht. Mindestens:
```bash
find src public cli -name '*.php' -print0 | xargs -0 -n1 php -l
php cli/migrate.php
php cli/tick.php # ohne --quiet: zeigt den Detektorlauf
```
**E5 ist reiner Rückbau geworden.** In mehreren Projekten wurden
Vorbereitungen für einen lokalen Supervisor begonnen — UI-Steuerelemente,
teilweise ein KI-Agent. Da der Client-Supervisor verworfen ist (H), fällt das
ersatzlos weg; nichts tritt an seine Stelle. Was an den Vorbereitungen wertvoll
ist, ist die Überlegung, **worauf** zu achten wäre — die gehört als Prüfung in
die Testläufe oder als Fehlermeldung in den Bugtracker, nicht in ein
Beobachterteil.
Der Auftrag zum Einfügen steht in
[SUPERVISOR_INTEGRATION_GUIDE.md](./SUPERVISOR_INTEGRATION_GUIDE.md).
---
## F — Quelltext-Zugriff für die Diagnose
Die Software bleibt geschlossen. Es gibt keine öffentliche Stelle, an der
Quelltext zu sehen ist. Drei Stufen, in aufsteigender Preisgabe:
| | Stufe | Stand |
|---|---|---|
| F1 | **Stufe 0** — Diagnose-Agent läuft auf eigener Maschine mit lokalem Checkout | ✅ Der gegenwärtige Weg |
| F2 | **Stufe 1** — Quelltext-Index im DC, nur Ausschnitte | 🧊 |
| F3 | **Stufe 2** — nur Metadaten: Signaturen, Aufrufgraph, keine Rümpfe | 🧊 |
### F2 — Quelltext-Index Stufe 1 🧊
**Auslöser:** wenn ein Agent autonom rund um die Uhr laufen soll, ohne dass
eine eigene Maschine läuft. Solange Claude Code den Checkout ohnehin lokal hat,
wäre das zusätzliche Angriffsfläche ohne Gegenwert.
Falls es kommt, dann als 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`, nie an Client-Token, verschlüsselt abgelegt, Budget
je Token und Tag, jeder Abruf im Prüfprotokoll. Der Unterschied zwischen „darf
nachschlagen" und „darf mitnehmen".
### F3 — Stufe 2 🧊
**Auslöser:** falls selbst Ausschnitte zu viel sind. Signaturen, Aufrufgraph
und Doc-Kommentare ohne Methodenkörper reichen zur Triage, aber nicht zum
Nachbauen.
---
## G — Testumgebung und Selbstbedienung
Die geteilte Linux-Test-VM. Anleitung: **[TESTUMGEBUNG.md](./TESTUMGEBUNG.md)** — dort
steht auch, was auf der Maschine belegt ist.
| | Vorhaben | Stand |
|---|---|---|
| G1 | **Kopfloser Installationsmodus fuer den `update-agent`** | 📋 |
| G2 | DEV-Lizenzschluessel zur Selbstbedienung (`POST /api/license/v1/dev-key`, Scope `license:dev`) | ✅ 2.6.1 |
| G3 | `dc-testkit` — ein Weg fuer Lizenz, Auslieferung und Meldung | ✅ 2.6.1 |
| G4 | Werkbank-Token je Projekt auf der Test-VM hinterlegen | ⚙️ |
| G5 | **`dc-testkit supervisor` — prüfen, ob eine Anbindung wirklich meldet** | 📋 |
| G6 | Test-Monitore aus dem Flottenvergleich heraushalten | 📋 |
| G7 | Befunde tragen die Umgebung, ausserhalb `production` eine Stufe niedriger | ✅ 2.6.1 |
| G8 | **Testartefakt oder echter Befund? — die offene Frage** | 📋 |
| G8 | Nachpruefung als Arbeitsschlange (`awaiting_verification`, `in_verification`, `fix_insufficient`) | ✅ 2.6.1 |
| G9 | Auswertung über `meta_json`: wie oft fällt ein Fix durch die Prüfung? | 🧊 |
### G1 — Kopfloser Installationsmodus 📋
`update-agent --action install` ist ein Dialog mit Auswahllisten und Passwortabfrage. Ein
Agent kann ihn nicht treiben: Auswahllisten brauchen Pfeiltasten an einem echten Terminal,
und ein Agent darf grundsaetzlich kein Passwort eingeben.
Folge: `dc-testkit install` prueft die **Auslieferung** in ein leeres Verzeichnis — denselben
Pfad, den der Installer intern nimmt, mit Download, SHA256, Signatur, Staging und Rollback.
Ungeprueft bleiben damit die Aufloesung von `setup.json` und das Schreiben der Konfiguration.
Das ist genau der Teil, der je Anwendung anders aussieht und deshalb am ehesten bricht.
Gebraucht wird `--action install --answers antworten.json`: dieselben Felder, die der Dialog
erfragt, aus einer Datei. Fehlt ein Pflichtfeld, bricht der Lauf ab, statt zu fragen. Das
Installationskonto bliebe dabei aussen vor — mit einem DEV-Lizenzschluessel kommt der Agent
ohnehin an die Release-Ablage.
Betroffen: `client-dotnet/Deploymentcenter.UpdateAgent/Installation.cs`.
### G5 — `dc-testkit findings` 📋
Die Nahtstelle zwischen Testumgebung und Supervisor, die heute fehlt.
Ein Testlauf erzeugt Befunde — teils durch `novel.error_signature` aus den
gemeldeten Fehlern, teils künftig direkt über `observe`. Sehen kann man sie von
der VM aus nicht: `dc-testkit` kennt `doctor`, `license`, `install`, `update`,
`run`, `projects` und `report`, aber nichts zum Supervisor.
Gebraucht wird wenig:
```
dc-testkit findings # was hat dieser Lauf ausgelöst?
dc-testkit findings --env all # auch das, was in production auffiel
```
Dahinter `GET /api/supervisor/v1/findings?project_slug=…`. Derselbe Zuschnitt
wie `dc_findings` im MCP-Adapter — die Abfrage existiert, es fehlt nur der Weg
dorthin von der VM aus.
Das ist zugleich die Voraussetzung für G8: Ohne Sicht auf die eigenen Befunde
kann niemand entscheiden, ob einer ein Artefakt des Prüfstands war.
Das Token braucht dafür zusätzlich `supervisor:read`; heute trägt es auf der
VM nur `bugtracker:manage` und `license:dev` (§4.2 der Anleitung).
### G6 — Test-Monitore aus dem Flottenvergleich 📋
`deviation.fleet` bildet Kohorten aus (Projekt, `app_version`) und meldet, wer
daraus ausschert. `watchdog_monitors` hat **kein** Feld für die Umgebung.
Bekommt die Test-VM einen Monitor mit demselben Projekt und derselben Fassung
wie die Produktivinstallationen, landet sie in deren Kohorte — und fällt dort
zwangsläufig auf: andere Maschine, andere Last, andere Plattenbelegung. Das
Ergebnis wären Befunde, die nichts über die Software aussagen, dafür aber die
Kohortenwerte verschieben und damit echte Ausreißer verdecken.
Zwei Wege, beide vertretbar:
- ein Feld `environment` an `watchdog_monitors`, und `deviation.fleet` sowie
`regression.build` sehen nur `production` an
- oder eine Kennzeichnung über `group_key`, ohne Schemaänderung
Solange auf der VM kein Monitor mit Produktivfassung läuft, ist nichts kaputt.
Es fällt nur genau dann auf, wenn es zu spät ist — deshalb hier vermerkt.
### G7 — Umgebung am Befund ✅ 2.6.1
Testläufe **sollen** Befunde erzeugen — ein Lauf, der einen Fehler auslöst, den
es vorher nicht gab, hat genau das getan, wofür er da ist. Die Detektoren
laufen deshalb in jeder Umgebung.
Unterschieden wird zweifach: über `environment` am Befund, und über den
Schweregradhinweis. Was außerhalb von `production` auffällt, ist eine Stufe
niedriger eingestuft — nicht weil es unwichtig wäre, sondern weil dort
systematisch mehr Rauschen entsteht. Wer beides gleich hoch einstuft, liest
bald keines von beiden mehr.
### G8 — Testartefakt oder echter Befund? 📋
**Die eigentlich schwierige Frage.** Ein Testlauf meldet „API-Aufruf
fehlgeschlagen". Liegt das daran, dass auf der VM keine Live-Zugangsdaten
liegen — oder wäre es beim Kunden genauso passiert?
Vollständig automatisch ist das nicht zu beantworten. Vier Ansätze, die
zusammen den Aufwand aber klein halten:
**1. Der Prüfstand sagt, was ihm fehlt.**
Die Testumgebung weiß, was sie *nicht* hat: keine Zahlungs-API, kein echter
SMTP, DEV-Lizenz statt Kundenlizenz. Wird das einmal als Liste hinterlegt und
bei jeder Meldung mitgeschickt, lässt sich ein Befund, der eine bekannte Lücke
berührt, sofort als `environment_limited` kennzeichnen. Das ist der billigste
Schritt und nutzt Wissen, das ohnehin vorhanden und stabil ist.
**2. Die Umkehrung: nicht das Scheitern zählt, sondern der Umgang damit.**
Der wichtigste Gedanke hier. Fehlende Zugangsdaten sind ein Artefakt — *wie die
Software darauf reagiert*, ist es nicht. Läuft sie in eine endlose
Wiederholung? Schluckt sie den Fehler? Bleibt Zustand halb geschrieben zurück?
Landet das Passwort im Protokoll?
Das sind Produktionsbefunde, auch wenn der Auslöser künstlich war — denn in
Produktion laufen Zugangsdaten ab, werden rotiert, fällt eine Gegenstelle aus.
**Der Prüfstand ist damit kein Störfaktor, sondern eine billige
Fehlereinspeisung.** Ein `retry.storm`, ausgelöst durch fehlende Zugangsdaten,
ist ein echter Befund.
**3. Vergleich über Umgebungen statt Beurteilung des Einzelfalls.**
Feuert derselbe Detektor mit demselben `subject` auch in `production`, ist die
Frage beantwortet. Feuert er ausschließlich in `development`, ist er
verdächtig. Das ist dieselbe Mechanik wie bei `deviation.fleet`, nur über
Umgebungen statt über Installationen — Populationen vergleichen, nicht
Einzelbefunde deuten.
**4. Einmal entscheiden, nicht jedes Mal.**
Was übrig bleibt, entscheidet ein Mensch oder ein Agent — aber **je Signatur,
nicht je Vorkommnis**. Dafür gibt es das Vorbild bereits: `IgnoreRules` im
Bugtracker (Muster, Begründung, Trefferzähler). Ein Befund, der einmal als
Artefakt eingestuft wurde, bleibt es für seine Signatur und zählt trotzdem
weiter hoch — fällt er plötzlich häufiger an, sieht man es.
Die Kosten sind damit eine Entscheidung je neuer Signatur, nicht je Lauf. Das
ist tragbar; alles darüber hinaus wäre Rätselraten mit mehr Schritten.
**Reihenfolge:** 1 und 4 zuerst — beide klein und sofort wirksam. 3 ergibt sich
fast von selbst, sobald Befunde aus beiden Umgebungen nebeneinander liegen. 2
ist keine Umsetzung, sondern eine Lesehaltung: beim Sichten nicht fragen
„warum ist das fehlgeschlagen", sondern „wie hat sich die Software dabei
verhalten".
### G9 — Auswertung der Statuswechsel 🧊
**Auslöser:** wenn die Frage „wie oft trägt ein Fix nicht?" tatsächlich gestellt
wird. Seit 2.6.1 schreibt jeder Statuswechsel strukturiertes `meta_json`
(`from`, `to`, `actor`, `since`) in `bugtracker_comments`. Damit lassen sich
Verweildauern und Durchläufe auswerten, **ohne** eine Historientabelle daneben.
Eine eigene Tabelle verdient sich erst bei Fragen über Items hinweg — Median der
Prüfdauer, Quote durchgefallener Fixes je Projekt. Vorher wäre sie eine zweite
Wahrheit über denselben Vorgang.
### G4 — Werkbank-Token auf der Test-VM ⚙️
Ohne das Token laufen `dc-testkit license` und `dc-testkit report` ins Leere. Je Projekt eines
anlegen (Besitzerart `dev_agent`, Rechte `bugtracker:manage` und `license:dev`), auf der VM
unter `~/.config/dc-testkit/` hinterlegen und in der Belegungsliste vermerken. Deckt sich mit
E4 — dasselbe Token traegt beides.
---
## I — Roadmap im Deploymentcenter
Diese Datei war bis 2.6.1 der einzige Ort für Planung — und pflegte damit
Status, Reihenfolge und Zuständigkeit von Hand, neben einem Bugtracker, der
genau diese drei Dinge bereits führt. Zwei Pfleger für dasselbe Feld.
Ab 2.7.0 gilt die Arbeitsteilung: **Zustand im DC, Begründung hier.**
| | Vorhaben | Stand |
|---|---|---|
| I1 | Migration 016: `epic`, `roadmap_rank`, `target_build`, `defer_trigger`, `doc_anchor`, Status `deferred`, Tabelle `roadmap_epics` | ✅ 2.7.0 |
| I2 | `Modules/Bugtracker/Roadmap.php` — Sicht, Reihenfolge, Erzeugung, Abgleich | ✅ 2.7.0 |
| I3 | `/api/bugtracker/v1/roadmap.php` — list, epics, next, active, render, check, set, move, reorder, epic | ✅ 2.7.0 |
| I4 | WebUI-Modul **Roadmap**: Übersicht, Liste, Aufnahmeliste, Themenbereiche | ✅ 2.7.0 |
| I5 | `cli/roadmap.php --write/--check/--list` | ✅ 2.7.0 |
| I6 | `dc_roadmap`, `dc_roadmap_set` im MCP-Adapter | ✅ 2.7.0 |
| I7 | Übernahmeleitfaden für die anderen Projekte | ✅ 2.7.0 — [ROADMAP_MIGRATION.md](./ROADMAP_MIGRATION.md) |
| I8 | **Migration 016 auf dem Server ausführen** | ⚙️ |
| I9 | **Diese Datei selbst übernehmen** — Einträge A1–H als Items anlegen, Kennungen auf Item-IDs umstellen | 📋 |
| I10 | Die anderen Projekte übernehmen (myapp, polytrader, predictalytics) | 📋 |
| I11 | `--check` in `scripts/deploy.py` einhängen | 📋 |
| I12 | Auswertung: wie lange steht ein Vorhaben in welcher Lage? | 🧊 |
### I1–I7 — der gebaute Teil ✅
Kein neues Modul und keine Roadmap-Tabelle: Ein Roadmap-Eintrag **ist** ein
`bugtracker_item`. Es fehlten nur vier Angaben, die ein Backlog nicht braucht
und eine Planung schon — Themenbereich, Reihenfolge, Zielfassung und der
Auslöser für Zurückgestelltes.
**Die Zugehörigkeit ist ein Feld.** Ein Item steht auf der Roadmap, wenn es ein
`epic` hat. Ein zweites Kennzeichen daneben wären zwei Angaben, die dasselbe
behaupten und auseinanderlaufen können.
**Die Kennung ist die Item-ID.** Handvergebene Kürzel (`A12`) erzeugen die
schlimmste Fehlerart: Beide Seiten sind für sich stimmig und meinen
Verschiedenes, weil die Kennung nach einer Löschung neu vergeben wurde.
AUTO_INCREMENT vergibt nie zweimal dieselbe Nummer — eine gelöschte Zeile
hinterlässt eine hängende Referenz, und die *meldet* der Abgleich.
**Zurückstellen verlangt einen Auslöser.** `status = deferred` ohne
`defer_trigger` wird abgelehnt, in Repository, API und Oberfläche gleichermaßen.
Ohne benannten Anlass ist ein Vorhaben nicht zurückgestellt, sondern vergessen —
und die Regel gehört an die Stelle, an der geschrieben wird, nicht nur in ein
Formular.
### I9 — diese Datei übernehmen 📋
Die Einträge A1–G9 stehen noch als handvergebene Kürzel hier. Sie werden Items;
die Abschnitte werden Themenbereiche (in Migration 016 bereits angelegt).
Danach ersetzt ein erzeugter Block die Statustabellen, und die Prosa bleibt.
**Reihenfolge:** erst I8 (Migration), dann I9, dann I11 (Abgleich im Deploy).
I10 kommt zuletzt — die anderen Projekte bekommen ein Verfahren, das hier
einmal durchlaufen ist, nicht eines aus der Anleitung.
Bis dahin gilt diese Datei unverändert weiter. Sie ist erst abgelöst, wenn der
Block darin steht.
### I12 — Verweildauern 🧊
**Auslöser:** wenn die Frage „warum dauert das so lange?" tatsächlich gestellt
wird. `status_changed_at` und das strukturierte `meta_json` aus 2.6.1 tragen
die Antwort bereits; eine Auswertung daneben lohnt erst, wenn jemand sie liest.
---
## H — Verworfen
Diese Punkte sind geprüft und abgelehnt. **Nicht erneut vorschlagen** — und
falls doch, dann nur mit einem Argument, das hier noch nicht steht.
| Vorschlag | Warum nicht |
|---|---|
| ❌ **Supervisor-Beobachter im ausgelieferten Programm** (auch regelbasiert, ohne Sprachmodell) | Zu viele Baustellen für den Ertrag. Er hätte in jeder Anwendung Einbau, Rückbau bestehender Vorbereitungen, eigenen Zustand auf Kundenhardware, ein weiteres Token im Binary und eine zweite Fassungspflege gebraucht — und dabei überwiegend das gemeldet, was Error-Reporting und Bugtracker ohnehin abdecken. Der Code war fertig und ist am 29.08.2026 wieder entfernt worden; er liegt in der Historie, falls die Abwägung je anders ausfällt. **Stattdessen:** Error-Reporting und Bugtracker weiterentwickeln, Befunde serverseitig ermitteln |
| ❌ Sprachmodell-Supervisor auf der Kundenmaschine | API-Schlüssel läge auf fremder Hardware; Kontext im Speicher fremder Maschinen; kann nicht im Minutentakt hinsehen; hat keinen Verlauf und sieht die Flotte nicht; antwortet zweimal verschieden auf dieselbe Lage |
| ❌ Quelltext mit dem Client ausliefern, auch verschlüsselt | Der Client muss entschlüsseln können, also kann es der Kunde auch |
| ❌ Deploy-Key oder Repo-Token im Client | Dekompiliert in Minuten |
| ❌ Obfuskation als Schutz einplanen | Verzögert, verhindert nicht |
| ❌ MCP-Werkzeuge 1:1 aus OpenAPI erzeugen | 24 Endpunkte; Werkzeugdefinitionen liegen dauerhaft im Kontextfenster. Ein aufgeblähter Adapter wäre schlechter als die Prompt-Vorlage, die er ersetzt |
| ❌ `publish`, `provision`, `deactivate` als MCP-Werkzeug | Ein Release gehört in die CI, nicht an ein Werkzeug, das ein Modell im Zweifel „hilfreich" auslöst |
| ❌ Befunde puffern, wenn das DC ausfällt | Eine wachsende Warteschlange in einer ohnehin auffälligen Anwendung ist genau der Schaden, den der Supervisor verhindern soll |
| ❌ Benachrichtigung je Befund | Ein Befund behauptet nicht, dass etwas kaputt ist. Wer bei jeder Auffälligkeit alarmiert, hat nach einer Woche einen Kanal, den niemand mehr liest |
| ❌ Lokale Befund-Oberfläche in den Anwendungen | Zweite Wahrheit, die nur den eigenen Ausschnitt kennt. Der Client hält keine Historie vor |
| ❌ `enforceProject()` pauschal für `dev_agent` öffnen | Hätte auch `publish` und `setup` in fremden Projekten erlaubt. Die Ausnahme wird je Aufrufstelle gesetzt |
| ❌ Feste Schwellwerte je Kennzahl als Hauptweg | Finden nur, woran vorher jemand gedacht hat. Die tragenden Detektoren vergleichen gegen eigenen Verlauf, Vorversion oder Flotte |
---
## Pflege dieser Datei
**Bis I9 abgeschlossen ist**, gilt weiterhin von Hand:
- Ein Vorhaben umgesetzt? Zeile auf ✅ setzen und die Fassung dazuschreiben.
- Etwas verworfen? Nach H, **mit Begründung**. Die Begründung ist der Wert des
Eintrags, nicht die Ablehnung.
- Etwas zurückgestellt? Nach 🧊, **mit Auslöser**. Ohne Auslöser ist es nicht
zurückgestellt, sondern vergessen.
- Ausführliche Herleitungen gehören ins Archiv, nicht hierher. Diese Datei soll
lesbar bleiben.
**Danach** gilt die Arbeitsteilung aus Abschnitt I:
| | Wahrheit | Die andere Seite hält |
|---|---|---|
| Status, Reihenfolge, Zielfassung, Bearbeiter | **Deploymentcenter** | den erzeugten Block zwischen `<!-- dc:roadmap -->`-Markern |
| Begründung, Auslöser, Verworfenes | **diese Datei**, außerhalb der Marker | den Verweis `doc_anchor` am Item |
- Ein Vorhaben entsteht **immer im DC**, nie hier. `dc_report` legt es an,
`dc_roadmap_set` hebt es auf die Roadmap, dann erst kommt die Prosa dazu.
So kann ein Punkt, der nur in einer Datei steht und den niemand angeht, gar
nicht erst entstehen.
- Zwischen den Markern **nichts von Hand ändern**. `php cli/roadmap.php --write`
überschreibt es beim nächsten Lauf.
- Vor dem Ausliefern `php cli/roadmap.php --check --project=deploymentcenter`.
Rückgabewert 1 heißt: Ein Absatz verweist auf ein Item, das es nicht gibt.
- 🧊 und ❌ behalten ihren Absatz hier. Der Statuswert allein sagt nicht, warum —
und ohne das Warum schlägt es der nächste Agent wieder vor.