Nachtrag zu B4: die Aufraeumung lief nie -- .changes an der falschen Stelle

WAS PASSIERT IST

Der Commit 60802170 ist um 23:33 ausgeliefert worden. Im Protokoll des
Servers stand danach:

    [workspace] undefined zurueckgenommene Nachrichten endgueltig entfernt.
    [workspace] 4 blaue Herzen auf babyblau umgestellt

Die zweite Zeile stimmt. Die erste ist der Befund: `undefined` statt
einer Zahl. Nachgesehen in der Live-Datenbank -- die fuenf
zurueckgenommenen Zeilen waren noch da.

URSACHE: `d.prepare("DELETE ...").changes` statt `.run().changes` --
also die Eigenschaft der vorbereiteten ANWEISUNG, nicht die des Laufs.
Die Anweisung wurde vorbereitet und nie ausgefuehrt. Nichts stuerzte
ab, nichts war rot, kein Fehler im Protokoll.

NEBENFOLGE, die es schlimmer gemacht haette: Die Sicherung wird VOR
dem Loeschen geschrieben. Da nie geloescht wurde, blieb die Bedingung
erfuellt -- bei JEDEM Neustart waere eine weitere Sicherungsdatei
entstanden. Genau das, wovor der Kommentar zwei Zeilen darueber warnt.
Ein Kommentar, der vor einem Fehler warnt, verhindert ihn nicht.

WAS JETZT ANDERS IST

Behoben, und die Umstellung ist eine exportierte Funktion geworden:
`loeschspurenAufraeumen(d, dbPfad)`. Nicht aus Ordnungsliebe -- eine
Umstellung, die tief im Hochfahren steckt, kann keine Pruefung
aufrufen. Eine Funktion schon.

pruef-loeschen.mjs (20 -> 25): stellt den alten Zustand her (Text leer,
weg_am gesetzt), ruft die Funktion und misst
  * dass sie eine ZAHL meldet (`typeof === "number"`) -- genau hier
    stand undefined, und 0 sieht in einer Meldung fast so aus,
  * dass die Zeile wirklich verschwindet,
  * und dass beim zweiten Aufruf nichts mehr passiert und nichts
    gesichert wird.

Ohne den ersten dieser drei Haken waere der Fehler auch beim naechsten
Mal durchgegangen: Eine Meldung mit `undefined` ist gruen, solange
niemand sie liest.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-22 23:36:02 +02:00
co-authored by Claude Opus 5
parent 60802170a1
commit 73facb7ce9
2 changed files with 134 additions and 55 deletions
+54
View File
@@ -286,6 +286,60 @@ ok(/Nachricht zurückgenommen/.test(chatJs),
"Gegenprobe: der Satz kommt in den Kommentaren durchaus vor —"
+ " die Suche oben unterscheidet also wirklich");
/* =====================================================================
6. DIE UMSTELLUNG RAEUMT WIRKLICH AUF
ENTSTANDEN AUS EINEM FEHLER, DER SCHON LIVE WAR (22.09.2026, 23:33).
In der ersten Fassung stand `d.prepare("DELETE ...").changes` statt
`.run().changes` -- die Eigenschaft der vorbereiteten ANWEISUNG,
nicht die des Laufs. Die Anweisung wurde vorbereitet und nie
ausgefuehrt.
NICHTS STUERZTE AB, NICHTS WAR ROT. Der einzige Hinweis war ein Wort
im Protokoll: "undefined zurueckgenommene Nachrichten endgueltig
entfernt". Haette dort niemand hingesehen, waeren die fuenf Zeilen
liegen geblieben -- und weil die Sicherung VOR dem Loeschen
geschrieben wird, waere bei jedem Neustart eine weitere
Sicherungsdatei entstanden.
DESHALB WIRD HIER DIE ZAHL GEPRUEFT, nicht nur das Ergebnis. `0`
und `undefined` sehen in einer Meldung fast gleich aus; in einer
Bedingung nicht.
===================================================================== */
console.log("");
console.log("--- Die Umstellung fuer alte Zeilen ---");
{
const { loeschspurenAufraeumen } = await import("./workspace.js");
const idAlt = await schreiben(keksModi, "Aus einer alten Fassung");
/* Den alten Zustand von Hand herstellen: Text leer, weg_am gesetzt.
Genau so sahen die fuenf Zeilen in der echten Datenbank aus. */
d.prepare("UPDATE chat_nachrichten SET text = '', weg_am = ? WHERE id = ?")
.run(new Date().toISOString(), idAlt);
const davor = d.prepare(
"SELECT COUNT(*) AS n FROM chat_nachrichten WHERE weg_am IS NOT NULL AND text = ''").get().n;
ok(davor === 1, `eine alte zurueckgenommene Zeile steht da (${davor})`);
/* OHNE PFAD: Dann schreibt die Funktion keine Sicherung -- hier wird
das Aufraeumen gemessen, nicht das Sichern. */
const erg = loeschspurenAufraeumen(d, null);
ok(typeof erg.entfernt === "number",
`sie meldet eine ZAHL (${typeof erg.entfernt}: ${erg.entfernt})`
+ " — genau hier stand vorher undefined");
ok(erg.entfernt === 1, `und zwar die richtige (${erg.entfernt})`);
const danach = d.prepare(
"SELECT COUNT(*) AS n FROM chat_nachrichten WHERE weg_am IS NOT NULL AND text = ''").get().n;
ok(danach === 0, `die Zeile ist wirklich weg (${danach} uebrig)`);
/* WIEDERHOLBAR: Beim zweiten Mal gibt es nichts zu tun, und es wird
auch nichts gesichert. Ohne diese Zeile waere nicht bewiesen, dass
bei jedem Neustart nicht doch wieder etwas passiert. */
const nochmal = loeschspurenAufraeumen(d, null);
ok(nochmal.entfernt === 0 && nochmal.gesichert === null,
`beim zweiten Mal passiert nichts (${nochmal.entfernt}, Sicherung ${nochmal.gesichert})`);
}
/* ---------- Ende ------------------------------------------------------ */
d.close();
try { rmSync(ordner, { recursive: true, force: true }); } catch { /* Windows haelt manchmal */ }