Files
Deploymentcenter/docs/ROADMAP_MIGRATION.md
T
Deploymentcenter BotandClaude Opus 5 c9bad697e5 feat(roadmap): Roadmap des Deploymentcenters uebernommen (I9)
61 Eintraege aus docs/ROADMAP.md stehen jetzt als Items im Deploymentcenter:
17 offen, 24 erledigt, 7 zurueckgestellt, 13 verworfen. Keine Waisen, jedes
Item mit doc_anchor. Der Abgleich laeuft ohne Befund durch.

Die Datei behaelt, was eine Tabellenzelle nicht traegt: die Begruendungen.
Der Zustand steht zwischen dc:roadmap-Markern und wird erzeugt.

  - scripts/roadmap_import.py: wertet die Datei aus und uebertraegt sie.
    Wiederholbar ueber client_ref, legt fehlende Themenbereiche an, wartet
    bei Drosselung. Die Prioritaet liest es aus dem Abschnitt "Als
    Naechstes" - solange die Datei die Quelle ist, soll auch die Prioritaet
    von dort kommen.
  - docs/ROADMAP.md: Statustabellen raus, erzeugter Block rein,
    21 Ueberschriften und 14 Querverweise auf Item-Nummern umgestellt,
    Abschnitt H mit Item-Nummern versehen.

WAS DIE UEBERNAHME ZUTAGE FOERDERTE

  - G8 war zweimal vergeben: einmal offen, einmal erledigt. Genau die
    Kollision handvergebener Kennungen, gegen die der Entwurf argumentiert.
    Beide sind eigene Items.
  - Bereich H fehlte in roadmap_epics - Migration 016 hatte nur A-G und I
    gesetzt. Die Waisenerkennung meldete es. Das Importskript legt fehlende
    Bereiche jetzt an, ueberschreibt aber keine vorhandenen: Ein
    Uebernahmeskript darf anlegen, kuratierte Angaben nicht ueberschreiben.
  - "Item #42" stand als erfundenes Beispiel im Rueckkanal-Absatz - und #42
    gibt es wirklich, in predictalytics. Der Abgleich hat es gemeldet, ein
    Mensch haette es nie bemerkt.
  - Vier Marker waren veraltet (E1, E2, I8, D1).

BEHOBEN: spliceBlock() zerstoerte Dateien, die den Marker erwaehnen

strpos() nahm die erste Fundstelle von "<!-- dc:roadmap". Erwaehnt eine Datei
den Marker im Fliesstext - und die Einleitung einer ordentlichen Roadmap tut
genau das - setzte der Splice dort an und ueberschrieb den halben Dateikopf.
check() klammerte aus demselben Grund Prosa aus statt des Blocks.

Es trifft also ausgerechnet die Dateien, die das Verfahren beschreiben. Der
echte Block wird jetzt am Zeilenanfang samt "stand=" erkannt; das Blockende
wird ab dem Anfang gesucht, nicht ab Dateibeginn.

BEHOBEN: IPv6-Erkennung im Testlauf war launisch

erreichbar() prueft seit jeher IPv6 mit einem blossen connect(). Auf dieser
Strecke gelingt der Verbindungsaufbau zeitweise, waehrend danach nichts mehr
fliesst - der Lauf blieb dann auf IPv6 und jede Anfrage lief 21 Sekunden in
einen Timeout. Weil es launisch war, sah es mal nach einem Haenger und mal
nach einem sauberen Lauf aus. Geprueft wird jetzt bis zur Antwort:
TLS-Handschlag und ein HTTP-HEAD.

WebUI: Verweise im Inhalt hatten keine Farbregel und erschienen im
Browservorgabeblau auf schwarzem Grund. Der Bereichsverweis der Roadmap
springt ausserdem auf die Liste statt auf die Uebersicht - dort wirkt der
Filter, den er setzt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 00:10:32 +02:00

330 lines
12 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 ins Deploymentcenter übernehmen
**Für Agenten und Entwickler in den angebundenen Projekten.** Diese Anleitung
beschreibt, wie eine vorhandene `ROADMAP.md`, `TODO.md`, `PLAN.md` oder eine
Sammlung von Entwurfsdokumenten in das Roadmap-System des Deploymentcenters
überführt wird — einmalig, pro Projekt.
Verfügbar ab **2.7.0**. Voraussetzung: Migration `016_roadmap.sql` ist auf dem
Server gelaufen.
---
## Warum überhaupt
Vorhaben lagen bisher in Markdown-Dateien: Status, Reihenfolge und
Zuständigkeit von Hand gepflegt, neben einem Bugtracker, der genau diese drei
Dinge bereits führt. Zwei Pfleger für dasselbe Feld — Drift war keine
Möglichkeit, sondern eine Frage der Zeit.
Konkret ging dabei verloren:
- Ein Punkt stand als offen in der Datei, obwohl der Code ihn längst erledigt
hatte. Wer die Datei las, arbeitete an etwas Fertigem.
- Zwei Agenten nahmen sich dasselbe Vorhaben vor, weil die Datei nicht sagen
kann, dass jemand daran sitzt.
- Ein verworfener Vorschlag kam nach drei Monaten wieder, weil die Begründung
in einem Entwurfsdokument stand, das niemand mehr aufschlug.
## Die Arbeitsteilung
**Kein Feld hat zwei Pfleger.** Das ist die ganze Regel; alles Weitere folgt
daraus.
| | Wahrheit | Die andere Seite hält |
|---|---|---|
| Status, Reihenfolge, Zielfassung, Bearbeiter | **Deploymentcenter** | eine maschinell erzeugte Kopie zwischen Markern |
| Begründung, Auslöser, Verworfenes, Herleitung | **Die Datei** | nur einen Verweis (`doc_anchor`) |
Die Datei verschwindet also **nicht**. Sie verliert nur die Hälfte, die sie
ohnehin nie zuverlässig getragen hat.
## Die Kennung
Handvergebene Kennungen (`A12`, `TODO-7`) sind der Grund für die schlimmste
Fehlerart: Beide Seiten sind für sich stimmig und meinen Verschiedenes, weil
die Kennung nach einer Löschung neu vergeben wurde. Niemand bemerkt das.
Deshalb ist die Kennung die **Item-ID** aus dem Deploymentcenter.
AUTO_INCREMENT vergibt nie zweimal dieselbe Nummer; eine gelöschte Zeile
hinterlässt eine hängende Referenz, und die *meldet* der Abgleich, statt sie
stillschweigend umzudeuten.
Der Themenbuchstabe bleibt — aber nur als Gruppe:
```markdown
### [A] #142 — Symbol-Upload und dc_symbolicate
```
---
## Übernahme in sechs Schritten
### 1. Bestandsaufnahme
Sortiere jeden Eintrag deiner Datei in genau eine der vier Kisten:
| Kiste | Kennzeichen | Wohin |
|---|---|---|
| **Vorhaben** | hat einen Zustand, jemand könnte es übernehmen | Item im DC |
| **Zurückgestellt** | bewusst nicht jetzt, mit benanntem Anlass | Item (`deferred`) + Absatz |
| **Verworfen** | geprüft und abgelehnt, mit Begründung | Item (`rejected`) + Absatz |
| **Erledigt** | schon ausgeliefert | Item (`resolved`) — oder ersatzlos streichen |
Was in keine Kiste passt, ist meist ein Gedanke und kein Vorhaben. Der gehört
in die Prosa, nicht in die Datenbank. **Faustregel:** Wenn niemand es
übernehmen kann, ist es kein Item.
### 2. Themenbereiche anlegen
Die Abschnitte deiner Datei werden Themenbereiche. Kurzes Kürzel, sprechender
Titel:
```bash
curl -X POST "https://dc.mhdf.de/api/bugtracker/v1/roadmap.php?action=epic" \
-H "Authorization: Bearer $DC_TOKEN" -H "Content-Type: application/json" \
-d '{"project_slug":"meinprojekt","epic":"A","title":"Handelslogik","sort_order":10}'
```
Oder im WebUI unter **Roadmap → Themenbereiche**.
Halte die Zahl klein. Fünf bis zehn Bereiche sind übersichtlich, zwanzig sind
eine zweite Ablage, die selbst wieder sortiert werden will.
### Abkürzung: Schritte 2–4 als Skript
Für eine Datei im Format dieses Projekts — Bereichstabellen mit
`| A4 | Titel | 📋 |`, Auslöser als `**Auslöser:** …` — nimmt
[scripts/roadmap_import.py](../scripts/roadmap_import.py) die drei Schritte ab:
```bash
python scripts/roadmap_import.py --lesen
```
Zeigt, was es gefunden hat, ohne etwas zu senden. **Immer zuerst.** Dabei fällt
auf, was die Datei falsch behauptet — bei der Übernahme hier waren drei
Einträge längst erledigt und einer doppelt vergeben.
```bash
python scripts/roadmap_import.py --uebernehmen
```
`DC_TOKEN` muss dabei ein Werkbank-Token des Projekts sein. Das Skript legt die
Themenbereiche mit an, ist über `client_ref` wiederholbar und wartet bei
Drosselung, statt abzubrechen: `/report` lässt 60 Meldungen je Minute zu, und
eine Roadmap mit mehr Einträgen liegt darüber.
Die Prioritätsreihenfolge liest es aus dem Abschnitt „Als Nächstes" der Datei —
solange die Datei die Quelle ist, soll auch die Priorität von dort kommen und
nicht aus einer zweiten Liste daneben.
Für eine Datei in anderem Format ist das Skript die Vorlage, nicht das
Werkzeug: Die Auswertung steht in `auswerten()` und ist auf etwa achtzig Zeilen
angepasst.
### 3. Vorhaben anlegen
Jedes Vorhaben wird ein Item. Mit MCP-Adapter:
```
dc_report(title: "Symbol-Upload und dc_symbolicate",
type: "feature_request",
description: "…",
client_ref: "roadmap-a4")
```
`client_ref` immer setzen: Ein wiederholter Lauf legt dann kein Duplikat an —
und bei einer Übernahme von zwanzig Einträgen läuft irgendetwas immer zweimal.
Ohne MCP:
```bash
curl -X POST "https://dc.mhdf.de/api/bugtracker/v1/report" \
-H "Authorization: Bearer $DC_TOKEN" -H "Content-Type: application/json" \
-d '{"project_slug":"meinprojekt","type":"feature_request",
"title":"…","description":"…","client_ref":"roadmap-a4"}'
```
### 4. Auf die Roadmap heben
Ein Vorhaben steht auf der Roadmap, **sobald es einen Themenbereich hat**. Das
ist das einzige Kennzeichen — ein zweites Flag daneben gäbe es zwei Angaben,
die dasselbe behaupten und auseinanderlaufen können.
```
dc_roadmap_set(id: 142, epic: "A", roadmap_rank: 10, target_build: "2.7.0",
doc_anchor: "docs/ROADMAP.md#142-symbol-upload")
```
Zur Reihenfolge: **Zehnerschritte.** Die Lücken sind Absicht — ein Eintrag
lässt sich später auf Rang 15 dazwischenschieben, ohne dass alle folgenden neu
nummeriert werden müssen.
Zurückgestelltes braucht den Auslöser, sonst wird der Aufruf abgelehnt:
```
dc_roadmap_set(id: 147, epic: "A", status: "deferred",
defer_trigger: "sobald Logauszüge strukturiert hereinkommen")
```
Ohne benannten Anlass ist ein Vorhaben nicht zurückgestellt, sondern vergessen.
Genau deshalb ist das Feld Pflicht und nicht bloß empfohlen.
### 5. Die Datei umbauen
Drei Änderungen:
**a) Zustandstabellen raus.** Jede von Hand gepflegte Tabelle mit Status-Spalte
wird ersatzlos gelöscht. Sie kommt gleich erzeugt zurück.
**b) Überschriften auf Item-IDs umstellen.**
```markdown
### [A] #142 — Symbol-Upload und dc_symbolicate
Der Packager lädt beim `publish` die PDB mit hoch, verknüpft mit `commit_sha`.
Ausgeliefert wird ein gestripptes Binary. …
```
Kein Status in der Überschrift, kein Häkchen, keine Zielfassung — das steht
alles im erzeugten Block und wäre hier eine zweite Wahrheit.
**c) Den Block einsetzen.** Beim ersten Lauf wird er ans Dateiende gehängt;
verschiebe ihn samt Markern dorthin, wo er stehen soll. Künftige Läufe finden
ihn dort wieder.
```bash
php cli/roadmap.php --write --project=meinprojekt --file=/pfad/zu/ROADMAP.md
```
Liegt das Projekt auf einer anderen Maschine als das Deploymentcenter, holst du
den Block über die API:
```bash
curl -s "https://dc.mhdf.de/api/bugtracker/v1/roadmap.php?action=render&project_slug=meinprojekt" \
-H "Authorization: Bearer $DC_TOKEN" | jq -r .markdown
```
### 6. Abgleich einrichten
```bash
php cli/roadmap.php --check --project=meinprojekt --file=/pfad/zu/ROADMAP.md
```
Was geprüft wird — nur die **Prosa**, denn der erzeugte Block kann nicht
abweichen:
| Befund | Bedeutung | Grad |
|---|---|---|
| `unknown_item` | Absatz nennt `#142`, das Item gibt es nicht | Fehler |
| `foreign_item` | `#142` gehört einem anderen Projekt | Fehler |
| `not_on_roadmap` | Absatz vorhanden, aber kein Themenbereich gesetzt | Warnung |
| `title_drift` | Überschrift und Item-Titel haben nichts mehr gemeinsam | Warnung |
| `decision_undocumented` | zurückgestellt/verworfen, aber keine Begründung in der Datei | Warnung |
Rückgabewert 0 heißt in Ordnung (Warnungen erlaubt), 1 heißt Fehler. Damit
lässt sich der Aufruf in einen Deploy-Schritt oder Pre-Commit-Hook hängen.
Ein Item **ohne** Absatz ist bewusst kein Befund: Nicht jedes Vorhaben braucht
eine Herleitung, die meisten sind eine Zeile wert und mehr nicht.
---
## Nach der Übernahme: die Regeln im Alltag
**Ein Vorhaben entsteht immer im DC, nie in der Datei.** `dc_report` legt das
Item an → `--write` schreibt die Zeile → *danach* schreibst du die Begründung
darunter. So kann ein Eintrag, der nur in der Datei steht, gar nicht erst
entstehen — und damit auch kein offener Punkt, den niemand angeht.
**Die Arbeitsschlange ist die Wahrheit über Arbeit.** Was nicht über
`?action=next` ausgegeben wird, macht niemand — unabhängig davon, wie es in
einer Datei markiert ist. Ein Eintrag, der etwas werden soll, muss ein Item
sein.
**Vor dem Anfangen `dc_roadmap` aufrufen.** Es beantwortet „was ist als
Nächstes dran" und „arbeitet schon jemand daran". Beides, bevor du beginnst.
**Vor dem Wiedervorschlagen die Begründung lesen.** Steht ein Vorhaben auf
`rejected` oder `deferred`, führt `doc_anchor` zu dem Absatz, der sagt warum.
Ein erneuter Vorschlag braucht ein Argument, das dort noch nicht steht.
**Der erzeugte Block darf altern.** Er ist eine Kopie, und Kopien altern. Der
Live-Stand kommt aus `dc_roadmap`; der Block ist für Menschen, die die Datei
aufschlagen. `--check` weist auf einen Block hin, der älter als ein Tag ist.
---
## Was nicht ins DC gehört
Der Umzug ist keine Einladung, alles in die Datenbank zu kippen.
- **Architekturentscheidungen mit Herleitung** bleiben in der Datei. Ein
Absatz, der eine Abwägung erklärt, überlebt keine Tabellenzelle.
- **Verworfenes mit Begründung** bleibt in der Datei. Der Wert des Eintrags ist
die Begründung, nicht die Ablehnung. Im DC steht nur der Status daneben.
- **Lose Gedanken** gehören weder hierhin noch dorthin. Wenn niemand sie
übernehmen kann, sind sie kein Vorhaben — im Zweifel als Notiz ins Archiv.
- **Alte Entwurfsdokumente** nach `docs/archiv/` verschieben, nicht löschen.
Sie enthalten die ausführliche Begründung, aber keinen gültigen Stand mehr.
Ein Hinweis darauf gehört an den Kopf der Roadmap-Datei.
---
## Werkzeuge im Überblick
| Werkzeug | Wofür |
|---|---|
| `dc_roadmap` | lesen: was ist dran, wer sitzt dran (MCP) |
| `dc_roadmap_set` | Bereich, Rang, Zielfassung, Anker setzen (MCP) |
| `GET /api/bugtracker/v1/roadmap.php?action=list` | dasselbe über REST |
| `?action=render` | den Markdown-Block holen |
| `?action=check` | Abgleich mit mitgeschickter Datei (`content`) |
| `php cli/roadmap.php --write\|--check\|--list` | von der DC-Maschine aus |
| WebUI → **Roadmap** | Übersicht, Filter, Reihenfolge, Aufnahmeliste |
Token braucht `bugtracker:read` zum Lesen und `bugtracker:manage` zum
Schreiben. Ein Werkbank-Token (`dev_agent`) hat beides.
---
## Beispiel: eine Datei vorher und nachher
**Vorher** — Zustand und Begründung durcheinander, beides von Hand:
```markdown
## A — Supervisor
| | Vorhaben | Stand |
|---|---|---|
| A4 | Symbol-Upload | 📋 geplant für 2.7.0 |
| A5 | Logzeilen-Schablonen | 🧊 später |
### A4 — Symbol-Upload
Der Packager lädt die PDB mit hoch…
```
**Nachher** — Zustand erzeugt, Begründung von Hand, verbunden über die ID:
```markdown
<!-- dc:roadmap stand=2026-08-29T14:02Z items=7 projekt=deploymentcenter -->
### A — Supervisor und Befunde
| | Vorhaben | Stand | Ziel |
|---|---|---|---|
| #142 | Symbol-Upload und dc_symbolicate | 📋 Offen | `2.7.0` |
| #143 | novel.log_template | 🧊 Zurückgestellt — Auslöser: sobald Logauszüge strukturiert hereinkommen | — |
<!-- /dc:roadmap -->
## Begründungen
### [A] #142 — Symbol-Upload
Der Packager lädt die PDB mit hoch, verknüpft mit `commit_sha`. Ausgeliefert
wird ein gestripptes Binary. Der Kunde bekommt `at 0x4a2f`, du bekommst
`UserAuthService.cs:42` — ohne dass Quelltext das Haus verlässt.
```
Die Statuszeile stimmt jetzt, weil sie niemand mehr pflegt.