feat(2.7.0): Roadmap im DC, Testinstanz mit Testtor, Supervisor und MCP
Sammelcommit fuer den ueber mehrere Sitzungen gewachsenen, bisher nicht
eingecheckten Stand. Getrennte Commits waeren ehrlicher gewesen, sind es
nachtraeglich aber nicht mehr: BugRepo, changelog.json und die Doku tragen
Aenderungen aus allen Straengen gleichzeitig, und keine Zwischenstufe waere
lauffaehig.
ROADMAP IM DEPLOYMENTCENTER (2.7.0)
Planungsstand, Reihenfolge und Zustaendigkeit lagen in handgepflegten
Markdown-Dateien neben einem Bugtracker, der genau diese drei Dinge bereits
fuehrt. Zwei Pfleger fuer dasselbe Feld - Drift war eine Frage der Zeit.
Ab jetzt: Zustand im DC, Begruendung in der Datei. Kein Feld hat zwei Pfleger.
- Migration 016: epic, roadmap_rank, target_build, defer_trigger,
doc_anchor, Status "deferred", Tabelle roadmap_epics.
KEINE Roadmap-Tabelle - ein Eintrag ist ein bugtracker_item.
- Zugehoerigkeit ist ein Feld: Ein Item steht auf der Roadmap, wenn es ein
epic hat. Ein zweites Kennzeichen daneben koennte auseinanderlaufen.
- Kennung ist die Item-ID. Handvergebene Kuerzel ("A12") erzeugen die
schlimmste Fehlerart: Beide Seiten stimmig, Verschiedenes gemeint, weil
die Kennung nach einer Loeschung neu vergeben wurde.
- Zurueckstellen verlangt defer_trigger. Ohne benannten Anlass ist ein
Vorhaben nicht zurueckgestellt, sondern vergessen. Die Regel sitzt im
Repository, damit sie auf allen drei Schreibwegen gleich greift.
- Modules/Bugtracker/Roadmap.php, /api/bugtracker/v1/roadmap.php,
WebUI-Modul mit Filtern, cli/roadmap.php --write/--check,
dc_roadmap und dc_roadmap_set im MCP-Adapter.
- cli/roadmap.php --write ERZEUGT den Zustandsteil der Markdown-Datei;
--check prueft nur die Prosa. Was erzeugt wird, kann nicht driften.
- docs/ROADMAP_MIGRATION.md: Uebernahme fuer die anderen Projekte.
TESTINSTANZ UND TESTTOR
- dc-dev.mhdf.de: zweite Installation, eigene DB, eigene Schluessel,
Basic-Auth davor, Rocket.Chat aus.
- 124 Testfaelle in tests/e2e gegen API, Rechte, Migrationen, Sperre.
- scripts/deploy.py bringt vor jedem Upload erst den anstehenden Stand auf
die Testinstanz und laesst dann den Testlauf laufen. Erst bei
Rueckgabewert 0 geht etwas auf die Produktion (--ohne-test als Notausgang).
Andersherum prueft der Lauf aelteren Code als den, der gleich hochgeht.
- tests/ ist aus dem Produktiv-Deploy ausgeschlossen; testctl.php kann
nicht versehentlich auf dc.mhdf.de landen.
- Ein Lauf mit mehr uebersprungenen als geprueften Faellen endet mit
Rueckgabewert 2 statt 0. Nichts ist kaputt, geprueft wurde es aber auch
nicht - der Unterschied darf nicht am Rueckgabewert verschwinden.
SUPERVISOR, PROJEKTLANDSCHAFT, NACHPRUEFUNG (2.6.0/2.6.1)
- Migration 013: projektuebergreifend melden (dev_agent, evidence,
triage_external, affects).
- Migration 014: supervisor_findings, Katalog, fuenf serverseitige
Detektoren im Tick.
- Migration 015: Nachpruefung als Arbeitsschlange statt Benachrichtigung.
- DEV-Lizenzschluessel zur Selbstbedienung, dc-testkit fuer die Test-VM.
- MCP-Adapter: 15 Werkzeuge, ohne Fremdabhaengigkeiten, mit Abgrenzung
von Fremddaten gegen Prompt-Injektion.
BEHOBEN
- observe und status im Supervisor legten den Zustand des Befundes als
"status" in die Antwort. Http::ok() merged ['status' => 'success']
darunter, also gewann der Befundzustand - eine angenommene Meldung kam
als status="open" an. Heisst jetzt finding_status. War Item #59.
Migrationen 013-016 sind auf dem Produktivserver noch NICHT ausgefuehrt.
Ohne sie bricht das WebUI, weil die Roadmap-Ansicht bei jedem Seitenaufruf
gegen bugtracker_items.epic abfragt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9d0261306c
commit
1d5ac92051
@@ -0,0 +1,99 @@
|
||||
-- Migration 013: Projektuebergreifendes Melden und Projektbeziehungen
|
||||
--
|
||||
-- Additive Migration. Der Migrator toleriert 1050/1060/1061/1062/1091
|
||||
-- ("existiert bereits"), sodass sie auf einer teilweise migrierten Datenbank
|
||||
-- durchlaeuft.
|
||||
--
|
||||
-- Hintergrund: Einige Projekte arbeiten 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.
|
||||
-- Bisher verweigerte ApiAuth::enforceProject() genau das - obwohl die
|
||||
-- Agenten-Prompt-Vorlage es ausdruecklich verlangt.
|
||||
--
|
||||
-- Siehe docs/SUPERVISOR_MCP_DESIGN.md, Abschnitt 5.
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 1. Herkunft einer Meldung
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Aus welchem Projekt heraus wurde gemeldet? Das ist keine Buchhaltung,
|
||||
-- sondern das wertvollste Signal im Vorgang: melden drei Projekte unabhaengig
|
||||
-- dieselbe Sache gegen das Deploymentcenter, ist das kein "low" mehr.
|
||||
ALTER TABLE bugtracker_items
|
||||
ADD COLUMN reported_from VARCHAR(64) NULL AFTER created_by;
|
||||
|
||||
-- Begruendungspflicht bei Fremdmeldungen: was wurde beobachtet, und warum
|
||||
-- liegt die Ursache dort und nicht hier. 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". Etwas ausformulieren zu muessen kostet einen Reflex fast immer
|
||||
-- den Kopf.
|
||||
ALTER TABLE bugtracker_items
|
||||
ADD COLUMN evidence TEXT NULL AFTER reported_from;
|
||||
|
||||
ALTER TABLE bugtracker_items
|
||||
ADD KEY ix_bt_reported_from (reported_from, status);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 2. Eigener Eingang fuer Fremdmeldungen
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Fremdmeldungen landen nicht im offenen Backlog, sondern in 'triage_external'
|
||||
-- und zaehlen erst nach Bestaetigung in die Statistik.
|
||||
--
|
||||
-- Das ist kein Misstrauen gegen den meldenden Agenten, sondern Schutz der
|
||||
-- Auswertung: die Detektoren aus dem Supervisor-Entwurf (Neuheit, Abweichung,
|
||||
-- Flottenvergleich) kalibrieren auf diesen Zahlen. Ein Detektor, der auf
|
||||
-- Fehlmeldungen kalibriert, ist wertlos.
|
||||
--
|
||||
-- 'triage_external' gilt bewusst NICHT als aktiver Status - open_items und
|
||||
-- critical_items in getProjects() bleiben dadurch unveraendert sauber.
|
||||
ALTER TABLE bugtracker_items
|
||||
MODIFY COLUMN status
|
||||
ENUM('open','planned','in_progress','resolved','closed','rejected','ignored','triage_external')
|
||||
NOT NULL DEFAULT 'open';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 3. Wer ist betroffen?
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Statt drei Items fuer denselben SDK-Fehler entsteht eines mit wachsender
|
||||
-- Betroffenenliste. Die Buendelung laeuft ueber den dedup_key des Items,
|
||||
-- nicht ueber client_ref - der ist nur je Melder eindeutig.
|
||||
CREATE TABLE IF NOT EXISTS bugtracker_item_affects (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
item_id BIGINT NOT NULL,
|
||||
project_slug VARCHAR(64) NOT NULL,
|
||||
report_count INT NOT NULL DEFAULT 1,
|
||||
first_reported_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
last_reported_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY ux_affects (item_id, project_slug),
|
||||
KEY ix_affects_project (project_slug),
|
||||
FOREIGN KEY (item_id) REFERENCES bugtracker_items(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 4. Beziehungen zwischen Projekten
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- dc_projects kannte bisher Slug, Name und Notiz - aber nicht, welches
|
||||
-- Projekt auf welchem aufsetzt. Damit war die Frage "welche meiner Projekte
|
||||
-- sind von diesem SDK-Fehler betroffen?" nicht beantwortbar.
|
||||
--
|
||||
-- integrated_version loest nebenbei ein Wartungsproblem: die von Hand
|
||||
-- gepflegte Zeile "Deploymentcenter-Anbindung: SDK 2.5.1" in jeder
|
||||
-- Projekt-CLAUDE.md wandert hierher. Sie veraltet dort schweigend, sobald
|
||||
-- jemand sie einmal vergisst.
|
||||
--
|
||||
-- Bewusst kein Fremdschluessel auf dc_projects.slug: ein Projekt darf eine
|
||||
-- Beziehung eintragen, bevor das Gegenstueck angelegt ist. Genauso haelt es
|
||||
-- bugtracker_items.project_slug.
|
||||
CREATE TABLE IF NOT EXISTS dc_project_links (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
from_slug VARCHAR(64) NOT NULL,
|
||||
to_slug VARCHAR(64) NOT NULL,
|
||||
kind ENUM('uses_sdk','depends_on','shares_code') NOT NULL DEFAULT 'uses_sdk',
|
||||
integrated_version VARCHAR(32) NULL,
|
||||
integrated_at DATETIME NULL,
|
||||
notes VARCHAR(255) NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY ux_link (from_slug, to_slug, kind),
|
||||
KEY ix_link_to (to_slug, kind)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,103 @@
|
||||
-- Migration 014: Supervisor-Befunde
|
||||
--
|
||||
-- Additive Migration. Der Migrator toleriert 1050/1060/1061/1062/1091.
|
||||
--
|
||||
-- Ein Befund ist keine Fehlermeldung. Er behauptet nicht, dass etwas kaputt
|
||||
-- ist, sondern dass etwas ungewoehnlich ist. Die Einstufung trifft die
|
||||
-- empfangende Seite, die den Flottenblick hat - deshalb heisst das Feld
|
||||
-- severity_hint und nicht severity.
|
||||
--
|
||||
-- Siehe docs/SUPERVISOR_MCP_DESIGN.md, Abschnitte 1 und 2.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS supervisor_findings (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
project_slug VARCHAR(64) NOT NULL,
|
||||
|
||||
-- Welche Installation? Bei serverseitigen Detektoren die Quelle des
|
||||
-- Monitors, bei clientseitigen die vom Beobachter gemeldete Kennung.
|
||||
instance VARCHAR(100) NOT NULL DEFAULT 'default',
|
||||
|
||||
-- Name aus dem Katalog, Form "familie.sache". Wandert nie mehr; kommt etwas
|
||||
-- dazu, bekommt es einen neuen Namen. Nur so bleiben Befunde aus
|
||||
-- verschiedenen Projekten vergleichbar.
|
||||
detector VARCHAR(64) NOT NULL,
|
||||
|
||||
-- Worauf bezieht sich der Befund - eine Metrik, ein Jobname, eine
|
||||
-- Fehlersignatur, eine Zusicherung.
|
||||
subject VARCHAR(190) NOT NULL,
|
||||
|
||||
-- Kam der Befund von einer Installation oder aus einem Detektorlauf hier?
|
||||
-- Serverseitige Detektoren arbeiten auf Daten, die ohnehin hereinkommen,
|
||||
-- und brauchen keinen neuen Client.
|
||||
origin ENUM('client','server') NOT NULL DEFAULT 'client',
|
||||
|
||||
severity_hint ENUM('idea','wishlist','low','medium','high','critical') NULL,
|
||||
|
||||
-- Was wurde gemessen, und wogegen? Bewusst als JSON: jeder Detektor bringt
|
||||
-- andere Groessen mit, und eine Spalte je Detektor waere nach dem dritten
|
||||
-- unhaltbar.
|
||||
observed_json JSON NULL,
|
||||
baseline_json JSON NULL,
|
||||
|
||||
build VARCHAR(64) NULL,
|
||||
commit_sha VARCHAR(64) NULL,
|
||||
environment ENUM('production','development','staging','testing') NOT NULL DEFAULT 'production',
|
||||
|
||||
-- open - frisch, ungesichtet
|
||||
-- acknowledged- angesehen, kein Handlungsbedarf im Moment
|
||||
-- promoted - daraus wurde ein Bugtracker-Item (siehe bug_item_id)
|
||||
-- resolved - Ursache behoben
|
||||
-- ignored - dauerhaft uninteressant, zaehlt aber weiter hoch
|
||||
status ENUM('open','acknowledged','promoted','resolved','ignored')
|
||||
NOT NULL DEFAULT 'open',
|
||||
bug_item_id BIGINT NULL,
|
||||
|
||||
occurrence_count INT NOT NULL DEFAULT 1,
|
||||
|
||||
-- Aus Detektor, Gegenstand und Fassung gebaut, nicht zufaellig: derselbe
|
||||
-- Befund darf beliebig oft gemeldet werden, ohne ein Duplikat anzulegen.
|
||||
-- Ein Beobachter, der minuetlich nachsieht, wuerde sonst 1.440 Eintraege am
|
||||
-- Tag erzeugen.
|
||||
client_ref VARCHAR(190) NOT NULL,
|
||||
|
||||
first_seen_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
last_seen_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
acknowledged_at DATETIME NULL,
|
||||
acknowledged_by VARCHAR(100) NULL,
|
||||
|
||||
UNIQUE KEY ux_finding (project_slug, client_ref),
|
||||
KEY ix_find_detector (detector, status),
|
||||
KEY ix_find_project (project_slug, status, last_seen_at),
|
||||
KEY ix_find_instance (instance, last_seen_at),
|
||||
KEY ix_find_cleanup (last_seen_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Zu welchem Projekt gehoert ein Monitor?
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Der Watchdog kannte bisher nur Quelle und Instanz. Fuer den Flottenvergleich
|
||||
-- reicht das nicht: verglichen werden darf nur, was vergleichbar ist, und
|
||||
-- "Fassung 1.0" zweier verschiedener Produkte hat nichts miteinander zu tun.
|
||||
-- Die Kohorte ist deshalb (Projekt, app_version).
|
||||
--
|
||||
-- Bewusst NICHT vom Agenten gesetzt, sondern administrativ. Sonst braeuchte
|
||||
-- diese Etappe einen Rollout neuer Agentenskripte auf jede Maschine - und der
|
||||
-- ganze Punkt der serverseitigen Detektoren ist, dass sie auf Daten arbeiten,
|
||||
-- die ohnehin schon hereinkommen.
|
||||
--
|
||||
-- Bleibt das Feld leer, laufen die monitorbezogenen Detektoren trotzdem; ihre
|
||||
-- Befunde landen dann unter dem Projekt aus supervisor.default_project.
|
||||
-- Flotten- und Regressionsvergleich setzen dagegen eine Zuordnung voraus und
|
||||
-- ueberspringen nicht zugeordnete Monitore.
|
||||
ALTER TABLE watchdog_monitors
|
||||
ADD COLUMN project_slug VARCHAR(64) NULL AFTER group_key;
|
||||
|
||||
ALTER TABLE watchdog_monitors
|
||||
ADD KEY ix_wd_project (project_slug, app_version);
|
||||
|
||||
-- Taktgeber fuer die serverseitigen Detektoren. Sie haengen im minuetlichen
|
||||
-- Cron, sollen aber nicht minuetlich laufen - ein Flottenvergleich alle zehn
|
||||
-- Minuten sagt dasselbe wie einer jede Minute und kostet ein Zehntel.
|
||||
INSERT INTO watchdog_cron_jobs (name, interval_sec, enabled)
|
||||
VALUES ('supervisor_detectors', 600, 1)
|
||||
ON DUPLICATE KEY UPDATE interval_sec = VALUES(interval_sec);
|
||||
@@ -0,0 +1,87 @@
|
||||
-- Migration 015: Verifikation als Arbeitsschlange
|
||||
--
|
||||
-- Additive Migration. Der Migrator toleriert 1050/1060/1061/1062/1091.
|
||||
--
|
||||
-- WOZU
|
||||
--
|
||||
-- Bisher endete ein Fehler mit "resolved": Ein Agent sagt, er habe ihn behoben,
|
||||
-- und damit war der Vorgang zu. Ob der Fix in einem ausgelieferten Paket
|
||||
-- tatsaechlich traegt, hat nie jemand nachgesehen - es gab keinen Ort, an dem
|
||||
-- diese Aufgabe gestanden haette.
|
||||
--
|
||||
-- Der Rueckkanal dafuer muss nichts zustellen. Er existiert bereits: Agenten
|
||||
-- fragen ueber ?action=next nach Arbeit. Ein Status, der in dieser Abfrage
|
||||
-- vorkommt, IST die Zustellung. Deshalb hier drei Zustaende statt einer
|
||||
-- Benachrichtigungsstrecke.
|
||||
--
|
||||
-- awaiting_verification Der Fix steckt in einem veroeffentlichten Build.
|
||||
-- Jemand kann jetzt nachsehen - vorher ging es nicht,
|
||||
-- weil es kein Paket gab.
|
||||
-- in_verification Jemand sieht gerade nach. Entsteht durch denselben
|
||||
-- Claim wie in_progress, damit es nur einen
|
||||
-- Uebernahmeweg gibt.
|
||||
-- fix_insufficient Gegen den Build geprueft, Fehler immer noch da. Der
|
||||
-- Fix hat nie getragen.
|
||||
--
|
||||
-- ABGRENZUNG zu "Regression": fix_insufficient bleibt am selben Item - Versuch
|
||||
-- und Fehlschlag gehoeren auf einen Strang. Eine Regression ist etwas anderes:
|
||||
-- Das Item war bestaetigt erledigt und kam spaeter zurueck. Sie bekommt
|
||||
-- weiterhin ein eigenes Item mit Verweis auf das alte.
|
||||
--
|
||||
-- WARUM KEINE HISTORIENTABELLE
|
||||
--
|
||||
-- Die Frage, fuer die der Timeout gebraucht wird, lautet "wie lange steht das
|
||||
-- schon so?". Das ist ein Zustand des Items, kein Ereignis - eine Spalte
|
||||
-- beantwortet ihn, ein Log muesste dafuer durchsucht werden. Der Verlauf
|
||||
-- selbst steht weiterhin in bugtracker_comments; ab dieser Fassung mit
|
||||
-- strukturiertem meta_json (from/to/actor), sodass er auch auswertbar ist.
|
||||
-- Eine eigene Tabelle lohnt erst fuer Fragen ueber Items hinweg ("wie oft
|
||||
-- faellt ein Fix durch die Pruefung?") - dann aber auf gefuellten meta_json
|
||||
-- aufbauend und nicht daneben.
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 1. Die drei neuen Zustaende
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Reihenfolge im ENUM bewusst am Lebenslauf entlang und hinten angehaengt:
|
||||
-- Bestehende Zeilen behalten ihren numerischen Index, ein ALTER ohne
|
||||
-- Datenbewegung.
|
||||
ALTER TABLE bugtracker_items
|
||||
MODIFY COLUMN status
|
||||
ENUM('open','planned','in_progress','resolved','closed','rejected','ignored',
|
||||
'triage_external','awaiting_verification','in_verification','fix_insufficient')
|
||||
NOT NULL DEFAULT 'open';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 2. Seit wann steht das so?
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Traegt den Timeout. Ohne diese Spalte muesste "steht seit X Tagen in diesem
|
||||
-- Status" aus Kommentartexten gelesen werden - dort steht der Statuswechsel
|
||||
-- heute als deutscher Fliesstext.
|
||||
--
|
||||
-- Vorbelegt mit updated_at bzw. created_at: Fuer bestehende Zeilen ist das die
|
||||
-- ehrlichste verfuegbare Naeherung. Ein NULL waere sauberer, macht aber jede
|
||||
-- Abfrage zu einem Sonderfall.
|
||||
ALTER TABLE bugtracker_items
|
||||
ADD COLUMN status_changed_at DATETIME NULL AFTER status;
|
||||
|
||||
UPDATE bugtracker_items
|
||||
SET status_changed_at = COALESCE(updated_at, created_at, UTC_TIMESTAMP())
|
||||
WHERE status_changed_at IS NULL;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 3. Wie oft wurde die Pruefung schon begonnen und nicht beendet?
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Gegen das Pendeln: Laeuft die Lease in der Pruefung ab, geht das Item zurueck
|
||||
-- nach awaiting_verification. Ohne Zaehler koennte es das ewig tun und dabei
|
||||
-- lebendig aussehen, waehrend nichts geschieht - genau die Schlange, die
|
||||
-- niemand leert, nur mit Zwischenschritten.
|
||||
ALTER TABLE bugtracker_items
|
||||
ADD COLUMN verification_cycles TINYINT UNSIGNED NOT NULL DEFAULT 0 AFTER status_changed_at;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 4. Index fuer die Wartungslaeufe
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Der Evaluator fragt minuetlich "welche Items stehen zu lange in welchem
|
||||
-- Status?". Ohne Index waere das ein Full Scan je Minute.
|
||||
ALTER TABLE bugtracker_items
|
||||
ADD KEY ix_bt_status_changed (status, status_changed_at);
|
||||
@@ -0,0 +1,169 @@
|
||||
-- Migration 016: Roadmap als Sicht auf den Bugtracker
|
||||
--
|
||||
-- Additive Migration. Der Migrator toleriert 1050/1060/1061/1062/1091.
|
||||
--
|
||||
-- WOZU
|
||||
--
|
||||
-- Vorhaben lagen bisher in ROADMAP.md je Projekt: Status, Reihenfolge und
|
||||
-- Zustaendigkeit von Hand gepflegt, neben einem Bugtracker, der genau diese
|
||||
-- drei Dinge bereits fuehrt. Zwei Pfleger fuer dasselbe Feld - Drift war keine
|
||||
-- Moeglichkeit, sondern eine Frage der Zeit.
|
||||
--
|
||||
-- Diese Migration legt KEINE Roadmap-Tabelle an. Ein Roadmap-Eintrag ist ein
|
||||
-- bugtracker_item; es fehlten nur vier Angaben, die ein Backlog nicht braucht
|
||||
-- und eine Roadmap schon:
|
||||
--
|
||||
-- epic Themenbereich (die Abschnitte A-H der bisherigen Datei)
|
||||
-- roadmap_rank Reihenfolge - Schweregrad ist keine Prioritaet
|
||||
-- target_build Zielfassung VOR der Umsetzung (resolved_in_build ist danach)
|
||||
-- defer_trigger Woran erkennt man, dass "spaeter" jetzt ist?
|
||||
--
|
||||
-- DIE ZUGEHOERIGKEIT
|
||||
--
|
||||
-- Ein Item steht auf der Roadmap, wenn es ein `epic` hat. Kein zweites
|
||||
-- Kennzeichen, kein is_roadmap-Flag daneben - sonst gaebe es wieder zwei
|
||||
-- Angaben, die dasselbe behaupten und auseinanderlaufen koennen. Ein Vorhaben
|
||||
-- auf die Roadmap heben heisst: ihm einen Themenbereich geben.
|
||||
--
|
||||
-- WARUM KEINE HANDVERGEBENEN KENNUNGEN MEHR
|
||||
--
|
||||
-- "A12" in der Datei und "A12" in der Datenbank sind zwei Schluessel, die
|
||||
-- dasselbe meinen sollen. Wird A12 geloescht und die Kennung spaeter neu
|
||||
-- vergeben, sind beide Seiten fuer sich stimmig und meinen Verschiedenes -
|
||||
-- eine stille Fehldeutung, die niemand bemerkt.
|
||||
--
|
||||
-- Die Kennung ist deshalb bugtracker_items.id. AUTO_INCREMENT vergibt nie
|
||||
-- zweimal dieselbe Nummer; eine geloeschte Zeile hinterlaesst eine haengende
|
||||
-- Referenz, und die MELDET der Abgleich, statt sie stillschweigend
|
||||
-- umzudeuten. Das Thema traegt weiterhin der Buchstabe, aber nur als Gruppe:
|
||||
--
|
||||
-- ### [A] #142 - Symbol-Upload und dc_symbolicate
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 1. Themenbereich
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Kurz gehalten. Der Buchstabe bzw. ein knappes Kuerzel ist die Gruppe; der
|
||||
-- Klartext dazu steht in der Datei, nicht hier. Wuerde der volle Titel des
|
||||
-- Bereichs in jeder Zeile stehen, waere er in jeder Zeile anders schreibbar.
|
||||
ALTER TABLE bugtracker_items
|
||||
ADD COLUMN epic VARCHAR(24) NULL AFTER tags;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 2. Reihenfolge
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- NICHT "rank": das ist seit MySQL 8.0 ein reserviertes Wort und muesste in
|
||||
-- jeder Abfrage gequotet werden - ein Fehler, der erst beim ersten ungequoteten
|
||||
-- Zugriff auffaellt.
|
||||
--
|
||||
-- NULL heisst "keine Meinung"; solche Eintraege sortieren hinter die
|
||||
-- gereihten. Die Luecken zwischen den Werten sind Absicht (10, 20, 30 ...):
|
||||
-- Ein Eintrag laesst sich dazwischenschieben, ohne alle folgenden neu zu
|
||||
-- nummerieren.
|
||||
ALTER TABLE bugtracker_items
|
||||
ADD COLUMN roadmap_rank INT NULL AFTER epic;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 3. Zielfassung
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Abgrenzung zu resolved_in_build: Das ist die Fassung, in der etwas
|
||||
-- TATSAECHLICH gelandet ist, gesetzt beim Abschluss. target_build ist die
|
||||
-- Absicht davor. Beide in eine Spalte zu legen hiesse, Plan und Ergebnis nicht
|
||||
-- mehr unterscheiden zu koennen - und genau diese Differenz ist die
|
||||
-- interessante Zahl.
|
||||
ALTER TABLE bugtracker_items
|
||||
ADD COLUMN target_build VARCHAR(64) NULL AFTER roadmap_rank;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 4. Der Auslöser fuer Zurueckgestelltes
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Ohne Ausloeser ist ein Vorhaben nicht zurueckgestellt, sondern vergessen.
|
||||
-- Deshalb bekommt der Status `deferred` (Punkt 6) ein Pflichtfeld an die Seite:
|
||||
-- Woran erkennt man, dass "spaeter" jetzt ist?
|
||||
ALTER TABLE bugtracker_items
|
||||
ADD COLUMN defer_trigger TEXT NULL AFTER target_build;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 5. Wo steht die Begruendung?
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Die Arbeitsteilung: Zustand hier, Herleitung in der Datei. Damit die beiden
|
||||
-- Haelften zueinander finden, traegt das Item den Ort der Prosa -
|
||||
-- "docs/ROADMAP.md#a-supervisor-und-befunde" oder ein Pfad im Projektrepo.
|
||||
--
|
||||
-- Bewusst ein freier String und keine Fremdschluesselbeziehung: Die Datei liegt
|
||||
-- in einem anderen Repository, die Datenbank kann sie nicht pruefen. Wer das
|
||||
-- prueft, ist `cli/roadmap.php --check`.
|
||||
ALTER TABLE bugtracker_items
|
||||
ADD COLUMN doc_anchor VARCHAR(190) NULL AFTER defer_trigger;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 6. Der Status "zurueckgestellt"
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Es gab bisher nur `rejected` fuer beides. Das ist ein Unterschied ums Ganze:
|
||||
-- Verworfen heisst "nicht erneut vorschlagen, hier steht warum".
|
||||
-- Zurueckgestellt heisst "jetzt nicht, aber es gibt einen Anlass, an dem es
|
||||
-- wieder ansteht". Wer beides gleich ablegt, verliert entweder die Begruendung
|
||||
-- oder den Anlass.
|
||||
--
|
||||
-- Hinten angehaengt, damit bestehende Zeilen ihren numerischen Index behalten
|
||||
-- und das ALTER ohne Datenbewegung laeuft.
|
||||
--
|
||||
-- `deferred` ist bewusst NICHT in CLAIMABLE_STATUSES: Zurueckgestelltes taucht
|
||||
-- in ?action=next nicht auf. Genau das ist der Zweck des Status.
|
||||
ALTER TABLE bugtracker_items
|
||||
MODIFY COLUMN status
|
||||
ENUM('open','planned','in_progress','resolved','closed','rejected','ignored',
|
||||
'triage_external','awaiting_verification','in_verification','fix_insufficient',
|
||||
'deferred')
|
||||
NOT NULL DEFAULT 'open';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 7. Index fuer die Roadmap-Sicht
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Die Roadmap-Ansicht fragt immer dieselbe Form: alle Items eines Projekts mit
|
||||
-- gesetztem epic, sortiert nach Bereich und Reihenfolge. Der bestehende
|
||||
-- ix_bt_proj_env passt dafuer nicht - er beginnt mit environment und type.
|
||||
ALTER TABLE bugtracker_items
|
||||
ADD KEY ix_bt_roadmap (project_slug, epic, roadmap_rank);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 8. Klartext je Themenbereich
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Die einzige neue Tabelle, und sie ist winzig. Grund: Der Bereichstitel
|
||||
-- ("A - Supervisor und Befunde") wuerde sonst in jeder Item-Zeile stehen und
|
||||
-- waere in jeder Zeile anders schreibbar - drei Tippfehler, drei Bereiche.
|
||||
--
|
||||
-- `sort_order` traegt die Reihenfolge der Bereiche untereinander, `is_closed`
|
||||
-- markiert einen Bereich, der abgeschlossen ist, ohne dass seine Items
|
||||
-- verschwinden muessen.
|
||||
CREATE TABLE IF NOT EXISTS roadmap_epics (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
project_slug VARCHAR(64) NOT NULL,
|
||||
epic VARCHAR(24) NOT NULL,
|
||||
title VARCHAR(160) NOT NULL,
|
||||
summary TEXT NULL,
|
||||
sort_order INT NOT NULL DEFAULT 100,
|
||||
is_closed TINYINT(1) NOT NULL DEFAULT 0,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY ux_roadmap_epic (project_slug, epic),
|
||||
KEY ix_roadmap_epic_order (project_slug, sort_order)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 9. Themenbereiche des Deploymentcenters
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Die Abschnitte der bisherigen docs/ROADMAP.md. Sie werden hier angelegt,
|
||||
-- damit die Uebernahme der vorhandenen Eintraege (siehe
|
||||
-- docs/ROADMAP_MIGRATION.md) nicht bei jedem Item einen Bereich erfinden muss.
|
||||
--
|
||||
-- INSERT IGNORE: Ein wiederholter Migrationslauf soll die von Hand
|
||||
-- nachgeschaerften Titel nicht ueberschreiben.
|
||||
INSERT IGNORE INTO roadmap_epics (project_slug, epic, title, summary, sort_order) VALUES
|
||||
('deploymentcenter', 'A', 'Supervisor und Befunde', 'Serverseitige Detektoren, Katalog, Symbolisierung.', 10),
|
||||
('deploymentcenter', 'B', 'Oberflaeche', 'Was im WebUI sichtbar ist - und was noch nicht.', 20),
|
||||
('deploymentcenter', 'C', 'Projektlandschaft', 'Melden ueber Projektgrenzen, Beziehungen, Rueckkanal.', 30),
|
||||
('deploymentcenter', 'D', 'Werkzeuganbindung (MCP)', 'Der stdio-Adapter und was er abdeckt.', 40),
|
||||
('deploymentcenter', 'E', 'Betrieb', 'Kein Code, aber Voraussetzung dafuer, dass Gebautes wirkt.', 50),
|
||||
('deploymentcenter', 'F', 'Quelltext-Zugriff', 'Drei Stufen der Preisgabe fuer die Diagnose.', 60),
|
||||
('deploymentcenter', 'G', 'Testumgebung', 'Die geteilte Linux-Test-VM und die Selbstbedienung.', 70),
|
||||
('deploymentcenter', 'I', 'Roadmap im Deploymentcenter', 'Diese Umstellung selbst.', 80);
|
||||
Reference in New Issue
Block a user