KI & Werkzeuge

100 Prozent Abdeckung — und ein Siebtel fehlte

Schaubild: zwei Kennzahlen desselben Speichers. Links meldet die Notiz-Abdeckung 100 Prozent bei 891 von 891 Notizen, rechts sind 14,6 Prozent des Inhalts nie eingebettet, 1,28 von 8,77 Millionen Zeichen. Ein Balken zeigt eine Notiz von 200.794 Zeichen, davon nur die ersten 45.000 eingebettet. Ein Zitat aus dem eingebetteten Teil landet auf Rang 1, eines aus dem abgeschnittenen auf Rang 3.
Beide Zahlen messen denselben Speicher — nur zählt die eine Dateien und die andere Zeichen.

Während ich diesen Text schrieb, meldete die Suche über meinen Wissensspeicher eine Abdeckung von 100 Prozent. Sie stimmte auch. Sie zählte Notizen, und jede Notiz war erfasst. Nur waren von den 8,77 Millionen Zeichen im Speicher 1,28 Millionen nie eingebettet worden — 14,6 Prozent, lautlos abgeschnitten. Betroffen waren unter anderem die beiden Dateien, die meine Agenten als Gedächtnis lesen.

Das ist kein peinlicher Einzelfall, den ich hier einräume. Es ist das Thema. Ein Speicher, der sich selbst pflegt, fällt leise aus, und die Kennzahl, die ihn überwacht, ist oft genau die, die den Ausfall verdeckt.

Was drinliegt, wenn man ihn aufmacht

891 Markdown-Dateien, zusammen 8.773.809 Zeichen. Geteilt ist der Speicher nach Zweck, nicht nach Thema: ein Eingangskorb für Rohes, ein kuratierter Baum für Geprüftes, dazu eine Linksammlung, Themenkarten und ein paar Vorlagen. Jede Notiz beginnt mit einem Kopfdatenblock und trägt ihre Identität mit — Titel, Typ, verwandte Notizen —, damit ein Abschnitt aus der Mitte eines langen Dossiers noch weiß, wovon er handelt.

Gelesen wird auf drei Wegen: ein Nachschlagen vor jeder Anfrage, ein Übergabe-Board morgens und abends, und eine Web-Ansicht zum Blättern, die alle dreißig Minuten neu gebaut wird. Sie baut in ein Nebenverzeichnis und tauscht erst bei geglücktem Bau, weil eine einzige kaputte Notiz sonst den ganzen Lauf abbrechen lässt — und einer ausgelieferten Seite sieht man nicht an, von wann sie ist.

Acht Takte, die für sich genommen nichts beweisen

BausteinTaktWoran ich sehe, dass er lief
Abgleich in die Versionsverwaltungalle 15 MinutenZeitstempel des letzten Eintrags gegen heute
Neuindizierung der Suchealle 15 MinutenByte-Abdeckung, nicht Notizzahl
Aufräumdienst und Befundalle 5 MinutenStatusdatei mit eigenem Zeitstempel
Wächter über den Schreibdienstalle 2 Minuten671 Läufe an einem Tag
Spiegel auf zwei Datenträgeralle 30 Minuten365 gute Läufe, Prüfsummenvergleich
Verschlüsselte Auslagerungtäglichentschlüsseln und Dateiliste prüfen
Gesundheitsbericht, nur lesendtäglichErgebnisdatei mit Datum
Web-Ansichtalle 30 MinutenSeitenzahl und Dauer

Die dritte Spalte ist die eigentliche Arbeit. Kein Dienst beweist mit seinem Rückgabewert, dass er getan hat, wofür er da ist. Er beweist, dass er nicht abgestürzt ist. Das ist etwas anderes, und der Unterschied hat mich in den letzten Wochen mehrfach Wochen gekostet.

Der Fund von heute Vormittag

Der Indexbauer zerlegt lange Notizen in Stücke, weil das Einbettungsmodell eine Obergrenze hat. Die Zeile, um die es geht, ist diese:

chunks = [text[i:i + body_room] for i in range(0, len(text), body_room)][:_MAX_CHUNKS]

Der Schnitt am Ende ist ein stummes Abschneiden. Kein Fehler, keine Ausnahme, kein Rückgabewert ungleich null. Die Notiz bekommt Vektoren, zählt als eingebettet, erscheint in der Abdeckung. Nur ihr Schwanz existiert für die Suche nicht.

Ein Stück fasst 4000 Zeichen, aber jedes trägt den Identitätskopf der Notiz mit, damit ein Abschnitt aus der Mitte noch weiß, wovon er handelt — für den Text bleiben rund 3750. Bei zwölf Stücken liegt die Decke also bei 45.000 Zeichen. Fünfzehn Notizen lagen darüber. Zwei davon sind das Übergabe-Board (200.794 Zeichen) und das Betriebsprotokoll (175.995) — genau die Dateien, die jede Sitzung als erstes liest. Ihr jüngerer Teil stand außerhalb der Suche.

Dass das wehtut, ist nicht behauptet, sondern gemessen. Ein wörtliches Zitat aus dem eingebetteten Teil des Boards holt die Notiz auf Rang 1 mit Ähnlichkeit 0,7212. Ein wörtliches Zitat aus dem abgeschnittenen Teil derselben Notiz kommt auf Rang 3 mit 0,5777 — geschlagen von einer fremden Notiz. Positivkontrolle und Schadensnachweis in einem Lauf.

Das Bittere daran: der Bauer meldet Lücken sehr wohl. Im Quelltext steht wörtlich „Gaps must be a report, not a surprise: name every degraded/dropped note“, und darunter benennt er jede Notiz, die beim Einbetten scheiterte oder nur noch über ihren Titel auffindbar ist. Diese Disziplin ist richtig und sie funktioniert. Sie greift nur nicht, weil ein abgeschnittener Schwanz kein Scheitern ist. Er sieht wie Erfolg aus.

Repariert ist beides. Die Decke steht jetzt bei 64 Stücken, also 240.000 Zeichen: Board und Protokoll fassen vollständig, übrig bleiben zwei importierte Normtexte von 337.805 und 304.437 Zeichen — Nachschlagematerial, kein Gedächtnis. Für null Verlust bräuchte es 96 Stücke je Notiz, was den Index bläht und jede Abfrage verlangsamt, weil beim Suchen alle Stücke bewertet werden. Wichtiger als die Zahl ist die zweite Änderung: das Abschneiden wird jetzt gezählt, jede betroffene Notiz mit Namen und verlorenen Zeichen genannt, und neben die Notiz-Abdeckung tritt eine Byte-Abdeckung. Die Notizzahl kann 100 Prozent melden, während ein Siebtel des Inhalts fehlt. Die Bytezahl kann das nicht.

Vierzehn Tage, in denen jede Erfolgsmeldung stimmte

Der Dienst, der den Speicher alle fünfzehn Minuten in die Versionsverwaltung schreibt, lag auf einem Rechner, der bei einem Umzug abgeschaltet wurde. Auf dem neuen lagen die Dateien bereit, eingetragen und nie eingeschaltet. Zwischen dem sechsten und dem neunzehnten August entstand kein einziger Eintrag. Der Nachholeintrag umfasste dann 463 Dateien und 17.384 eingefügte Zeilen.

Am selben Tag und aus derselben Ursache starb die Neuindizierung. Die Suche antwortete weiter — sie sah 489 von 707 Notizen, also 31 Prozent nicht, ohne eine einzige Fehlerzeile. Gefunden wurde die Lücke nicht von einem Wächter, sondern durch Hinsehen: den Zeitstempel des letzten Eintrags gegen das heutige Datum halten. Das ist der ganze Test, er dauert zehn Sekunden, und er ist der einzige, der hier angeschlagen hätte.

Ein Backup misst man an der Frische seines Inhalts, nicht am Rückgabewert seines Auftrags. Und eine Suche, die antwortet, beweist nicht, dass sie alles sieht.

Ein Wächter, der Gesundes neu startete

Ein anderer Wächter prüft alle zwei Minuten, ob der Schreibdienst antwortet. Er fragte ihn falsch. Der Endpunkt schickt seine Erfolgszeile und hält die Verbindung dann offen — bei ihm der Normalfall. Das Abfragewerkzeug druckte also den Erfolgscode und lief danach in die Zeitüberschreitung, und meine Auswertung las das als Fehler.

Dienst laeuft, antwortet aber nicht — starte neu
WEITERHIN TOT — braucht einen Menschen

Vierzehnmal hintereinander, innerhalb von 28 Minuten, gegen einen vollkommen gesunden Dienst. Vermutlich hat er dabei genau die Verbindungen zerrissen, die er schützen sollte. Seit der Korrektur hat er echte Ausfälle geheilt und danach geschwiegen — eine Aussage, die überhaupt nur etwas wert ist, weil er in dieser Zeit rund 671 Mal am Tag lief. Ein Wächter, der schweigt, sagt nichts, solange man nicht weiß, wie oft er hingesehen hat.

Vierzig Prozent der Vorschläge waren falsch

Ein selbstgebautes Werkzeug schlägt fehlende Querverweise zwischen Notizen vor. Beim scharfen Durchgang wurden aus 470 Rohvorschlägen 283 Verweise. Die 187 abgelehnten waren keine Geschmacksfrage, unter anderem diese:

  • 72 standen in einer Überschrift, 62 davon in der ersten — und die ist hier der Titel der Notiz.
  • 68 standen in einer Tabellenzeile.
  • 26 zeigten auf ein Allerweltswort: einen Projektnamen, der zufällig auch ein gewöhnliches Substantiv ist. Von seinen Treffern meinte praktisch keiner das Projekt.

Geprüft wurde das Ergebnis nicht über die Zahl der geänderten Dateien — die hätte gelogen, ein Werkzeug kann eine Datei anfassen, ohne etwas zu ändern — sondern über die Differenz der Verweise im ganzen Speicher: exakt 283 mehr, und die Zahl toter Verweise vorher wie nachher unverändert. Ein Vorschlagswerkzeug ist erst dann ein Werkzeug, wenn jemand seine Fehlerquote kennt.

Was offen bleibt

Der Eingangskorb füllt sich schneller, als etwas ihn leert. Sein Höchststand lag bei 239 Notizen, heute sind es 135. Der Abbau steht in keinem Protokoll: 128 Notizen wanderten an einem Nachmittag in den kuratierten Baum, weil jemand es entschied, nicht weil ein Dienst es tat — in derselben Zeit kamen gut zwei Dutzend neue dazu, deshalb steht der Korb heute bei 135 und nicht bei 111. Das ist Absicht — der Aufräumdienst repariert, was verlustfrei entscheidbar ist, und befördert nichts. „Byteweise identisch“ ist entscheidbar. „Gehört diese Notiz zu den Projekten?“ ist es nicht.

Zwei importierte Normtexte werden weiterhin abgeschnitten. Sie erscheinen jetzt namentlich im Bericht jedes Laufs, mit der Zahl der verlorenen Zeichen. Das ist keine Lösung, aber es ist der Unterschied zwischen einem bekannten und einem unbekannten Loch.

Und das Muster, das ich aus alldem mitnehme, ist kleiner, als es klingt. Es ist kein Werkzeug und keine Architektur. Es ist die Angewohnheit, bei jeder Null und jeder grünen Zahl zu fragen, ob sie überhaupt in der Lage wäre, etwas anderes anzuzeigen. Ein Test, der nicht anschlagen kann, sieht genauso aus wie ein bestandener.