Drei Agenten haben von aussen gemeldet, und fast jeder Befund hat dieselbe Form: Irgendwo sprang ein Vorgabewert ein, obwohl die richtige Antwort bekannt war - meist das Projekt, an das der Aufrufer ohnehin gebunden ist. #351 manage?action=next antwortete durchgaengig mit HTTP 500. In BugRepo::buildFilter() stand :project_scope zweimal in derselben Anweisung; mit ATTR_EMULATE_PREPARES=false bindet PDO jeden Namen genau einmal - zwei Marker, ein Wert, SQLSTATE[HY093]. Getroffen war nur "next", weil nur dort der Rueckkanal-Filter gesetzt wird. Damit gab es keine exklusive Uebernahme. Es ist der VIERTE Fall dieser Bauart, deshalb prueft scripts/pruefe_platzhalter.py das jetzt mechanisch vor jedem Ausliefern. #382 Meldungen ohne project_slug landeten im Scheinprojekt "default" - #387 ohne dc_projects-Zeile, also project_id NULL. Die Antwort sah wie ein #397 Erfolg aus, und danach sperrte dieselbe Token-Bindung den Zugriff (403 project_forbidden). Der Rueckfall aufs Heimatprojekt war an !isWorkbench gebunden; ein Werkbank-Token ohne Slug bekam gar keinen Vorgabewert. Jetzt: genannter Slug, sonst Heimatprojekt, sonst 400. Ein unbekanntes Projekt wird abgewiesen statt still angelegt. #364 Ohne project_slug lieferten list, stats und die Roadmap ALLE #176 Projekte statt des eigenen, weil die Vorgabe auf "all" stand und ein Werkbank-Token beim Lesen absichtlich nicht unter die Schranke faellt. Gemessen: 393 Items, davon 28 eigene. Ausgerechnet der erste Aufruf jeder Sitzung. Die Roadmap antwortet ausserdem schmal - 55 Felder je Eintrag waren 628.392 Zeichen und fuellten das Kontextfenster. #404 Watchdog-Monitore bekamen nie ein Projekt: upsertHeartbeat() wurde keines uebergeben, obwohl authorizeSource() die Token-Bindung liest. Befunde erbten dadurch "default" - dc_findings(project_slug=...) war fuer eine laufende, meldende Instanz leer. #131 Wo der Leseweg richtig verengte, sagte er es nicht: HTTP 200 mit dem umgeschriebenen Filter sieht aus wie eine Auskunft ueber das angefragte Projekt. Ein Agent, der vor dem Melden dc_search fragt, legt so das Duplikat an. Jetzt scoped_to und scope_note im Umschlag - nur bei tatsaechlicher Verengung. #354 dc-testkit 1.1.0 wurde zweimal mit verschiedenem Inhalt ausgeliefert (1898 und 1930 Zeilen), 1.0.0 davor ebenso. Der Absatz ueber DC_TESTKIT_VERSION stand die ganze Zeit im Skript und hat nicht getragen. Jetzt 1.1.1 plus ein Riegel in deploy.py, der abbricht, wenn sich der Inhalt aendert und die Nummer nicht. Warum die Testsuite all das nicht sah: Ihr Master-Token ist an kein Projekt gebunden und nimmt deshalb ueberall den anderen Zweig. Es gab sogar einen Testfall fuer action=next - er lief gruen, waehrend der Aufruf in der Praxis ausnahmslos scheiterte. Die neuen Faelle benutzen ausdruecklich projektgebundene Token; testctl kann dafuer jetzt owner_type und scopes waehlen. Ausserdem: Die Agentenvorlage nennt fuer die SDK-Fassung dc_link_project statt einer abgeschriebenen Zahl - "SDK 2.5.1" stand dort als Beispiel und wurde als Wert uebernommen. Nicht enthalten: die 20 Altlasten in "default". Sie sind ueber die API nicht erreichbar; sql/wartung/2026-08-31_default-projekt-aufraeumen.sql liegt dafuer bereit (alle 20 haben einen titelgleichen Zwilling im richtigen Projekt). 156 e2e-Faelle gruen, davon 9 neue. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
180 lines
7.3 KiB
SQL
180 lines
7.3 KiB
SQL
-- ===========================================================================
|
|
-- Die Leichen im Scheinprojekt "default" aufraeumen
|
|
--
|
|
-- Bugtracker #382 / #387. Bis 2.8.0 legte POST /report eine Meldung ohne
|
|
-- project_slug im Projekt "default" ab. Das ist kein Projekt: Es hat keine
|
|
-- Zeile in dc_projects, also blieb project_id NULL. Die Items sind seitdem
|
|
--
|
|
-- * in keiner Projektansicht sichtbar (die Auswahl kennt nur echte Projekte),
|
|
-- * ueber die API nicht mehr erreichbar - dasselbe Token, das sie angelegt
|
|
-- hat, bekommt 403 project_forbidden, weil es an sein eigenes Projekt
|
|
-- gebunden ist,
|
|
-- * und aus dem WebUI nicht loeschbar, weil es dort keine Loeschfunktion
|
|
-- fuer Items gibt.
|
|
--
|
|
-- Ab 2.8.1 entsteht nichts Neues mehr dieser Art: Ohne Slug gilt das
|
|
-- Heimatprojekt des Tokens, und ohne beides gibt es eine Absage statt eines
|
|
-- Ratens. Dieses Skript raeumt nur den Altbestand.
|
|
--
|
|
-- ---------------------------------------------------------------------------
|
|
-- NICHT AUTOMATISCH AUSGEFUEHRT. Es liegt bewusst NICHT in sql/migrations/ -
|
|
-- dort wird jede .sql beim Start angewendet (siehe Core\Migrator), und ein
|
|
-- DELETE gehoert nicht in einen Vorgang, der ungefragt laeuft.
|
|
--
|
|
-- Von Hand, Abschnitt fuer Abschnitt, und Abschnitt 1 zuerst.
|
|
-- ---------------------------------------------------------------------------
|
|
--
|
|
-- Achtung beim Loeschen: bugtracker_comments und bugtracker_item_affects
|
|
-- haengen mit ON DELETE CASCADE an den Items. Was hier faellt, nimmt seine
|
|
-- Kommentare und Betroffenenvermerke mit.
|
|
-- ===========================================================================
|
|
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- 1. ANSEHEN. Was liegt ueberhaupt dort?
|
|
-- ---------------------------------------------------------------------------
|
|
-- created_by ist die einzige verlaessliche Spur, wem ein Item gehoert:
|
|
-- reported_from blieb bei genau diesen Meldungen leer. Grund war die
|
|
-- Reihenfolge im alten Code - "Fremdmeldung?" wurde am mitgeschickten Slug
|
|
-- entschieden, und der fehlte ja gerade. Deshalb griff weder die
|
|
-- Begruendungspflicht noch der Fremdmeldungs-Eingang.
|
|
|
|
SELECT
|
|
id,
|
|
created_by,
|
|
reported_from,
|
|
type,
|
|
severity,
|
|
status,
|
|
build_version,
|
|
created_at,
|
|
LEFT(title, 70) AS titel
|
|
FROM bugtracker_items
|
|
WHERE project_slug = 'default'
|
|
ORDER BY id;
|
|
|
|
|
|
-- Wer hat wie viel dort abgelegt? Das ist die Grundlage fuer Abschnitt 2:
|
|
-- Ein created_by, das eindeutig zu einem Projekt gehoert, laesst sich
|
|
-- umhaengen. Ein gemischtes nicht.
|
|
|
|
SELECT
|
|
created_by,
|
|
COUNT(*) AS anzahl,
|
|
MIN(id) AS von,
|
|
MAX(id) AS bis
|
|
FROM bugtracker_items
|
|
WHERE project_slug = 'default'
|
|
GROUP BY created_by
|
|
ORDER BY anzahl DESC;
|
|
|
|
|
|
-- Gegenprobe: Gibt es "default" womoeglich doch als Projekt? Wenn diese
|
|
-- Abfrage eine Zeile liefert, ist die Lage eine andere als hier beschrieben -
|
|
-- dann bitte erst klaeren, wer es wann angelegt hat.
|
|
|
|
SELECT * FROM dc_projects WHERE slug = 'default';
|
|
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- BEFUND VOM 31.08.2026 - der Bestand ist aufgenommen
|
|
-- ---------------------------------------------------------------------------
|
|
-- Es sind 20 Items. created_by ordnet sie eindeutig zu, und JEDES hat einen
|
|
-- titelgleichen Zwilling im richtigen Projekt:
|
|
--
|
|
-- clawddotnet 352, 353, 365, 366, 368, 369, 370 -> #373-#379
|
|
-- ibkrtrader 355, 356, 357, 358, 359, 360,
|
|
-- 361, 362, 367 -> #388-#396
|
|
-- polytrader 371, 372, 380, 381 -> #383-#386
|
|
--
|
|
-- An jedem Original haengt genau EIN Kommentar: der automatische
|
|
-- Erfassungsvermerk ("Bug im System erfasst."). Es gibt also keine Historie,
|
|
-- die beim Loeschen verlorenginge - der Abgleich in Abschnitt 1 sollte das
|
|
-- vor dem Loeschen trotzdem noch einmal bestaetigen, denn seither kann
|
|
-- jemand kommentiert haben.
|
|
--
|
|
-- Deshalb ist Abschnitt 3 (loeschen) hier der richtige Weg und Abschnitt 2
|
|
-- (umhaengen) nur die Rueckfallebene, falls der Abgleich etwas anderes zeigt.
|
|
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- 2. UMHAENGEN statt loeschen - die Rueckfallebene.
|
|
-- ---------------------------------------------------------------------------
|
|
-- Zu benutzen, wenn an einem Item doch etwas haengt, das in der Neuablage
|
|
-- fehlt. Dann waere allerdings der Zwilling zu loeschen, sonst steht derselbe
|
|
-- Befund zweimal im Projekt.
|
|
|
|
-- UPDATE bugtracker_items
|
|
-- SET project_slug = 'clawddotnet',
|
|
-- project_id = (SELECT id FROM dc_projects WHERE slug = 'clawddotnet')
|
|
-- WHERE project_slug = 'default'
|
|
-- AND id IN (352, 353, 365, 366, 368, 369, 370);
|
|
|
|
-- UPDATE bugtracker_items
|
|
-- SET project_slug = 'ibkrtrader',
|
|
-- project_id = (SELECT id FROM dc_projects WHERE slug = 'ibkrtrader')
|
|
-- WHERE project_slug = 'default'
|
|
-- AND id IN (355, 356, 357, 358, 359, 360, 361, 362, 367);
|
|
|
|
-- UPDATE bugtracker_items
|
|
-- SET project_slug = 'polytrader',
|
|
-- project_id = (SELECT id FROM dc_projects WHERE slug = 'polytrader')
|
|
-- WHERE project_slug = 'default'
|
|
-- AND id IN (371, 372, 380, 381);
|
|
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- 3. LOESCHEN - der vorgesehene Weg.
|
|
-- ---------------------------------------------------------------------------
|
|
-- Der Inhalt steht vollstaendig im jeweils richtigen Projekt (siehe Befund
|
|
-- oben). Die Altablage ist reiner Ballast: unsichtbar, unerreichbar, und sie
|
|
-- verfaelscht jede Zaehlung ueber alle Projekte.
|
|
--
|
|
-- Erst zaehlen. Kommt hier nicht 20 heraus, hat sich der Bestand seit dem
|
|
-- 31.08.2026 geaendert - dann zurueck zu Abschnitt 1.
|
|
|
|
-- SELECT COUNT(*) AS wird_geloescht
|
|
-- FROM bugtracker_items
|
|
-- WHERE project_slug = 'default'
|
|
-- AND id IN (352, 353, 355, 356, 357, 358, 359, 360, 361, 362,
|
|
-- 365, 366, 367, 368, 369, 370, 371, 372, 380, 381);
|
|
|
|
-- Sicherungskopie, falls die Zuordnung spaeter doch noch gebraucht wird.
|
|
-- Kostet nichts und macht den Schritt umkehrbar.
|
|
-- CREATE TABLE bugtracker_items_default_backup_20260831 AS
|
|
-- SELECT * FROM bugtracker_items WHERE project_slug = 'default';
|
|
|
|
-- DELETE FROM bugtracker_items
|
|
-- WHERE project_slug = 'default'
|
|
-- AND id IN (352, 353, 355, 356, 357, 358, 359, 360, 361, 362,
|
|
-- 365, 366, 367, 368, 369, 370, 371, 372, 380, 381);
|
|
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- 4. NACHSEHEN. Sollte 0 liefern, wenn alles umgehaengt oder geloescht ist.
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
-- SELECT COUNT(*) AS noch_in_default
|
|
-- FROM bugtracker_items
|
|
-- WHERE project_slug = 'default';
|
|
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- 5. Gibt es weitere verwaiste Slugs?
|
|
-- ---------------------------------------------------------------------------
|
|
-- "default" war die haeufigste Falltuer, aber nicht die einzige moegliche:
|
|
-- Ein Tippfehler im project_slug wurde bis 2.8.0 ebenso klaglos angenommen.
|
|
-- Ab 2.8.1 weist der Endpunkt ein unbekanntes Projekt mit 400 unknown_project
|
|
-- ab; der Altbestand bleibt davon unberuehrt.
|
|
|
|
SELECT
|
|
b.project_slug,
|
|
COUNT(*) AS anzahl,
|
|
MIN(b.created_at) AS aeltestes,
|
|
MAX(b.created_at) AS juengstes
|
|
FROM bugtracker_items b
|
|
LEFT JOIN dc_projects p ON p.slug = b.project_slug
|
|
WHERE p.id IS NULL
|
|
GROUP BY b.project_slug
|
|
ORDER BY anzahl DESC;
|