# Änderungsverlauf Alle nennenswerten Änderungen an dieser Anwendung stehen hier, neueste zuerst. Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), die Nummerierung [Semantic Versioning](https://semver.org/lang/de/): - **Hauptnummer** (1.0.0) — erst mit dem Abschluss der Barrierefreiheitsprüfung. Solange die Null vorn steht, ist der Funktionsumfang noch nicht vollständig. - **Nebennummer** (0.**9**.0) — neue Merkmale. - **Fehlernummer** (0.9.**1**) — nur Fehlerbehebungen. Welche Merkmale es gibt und welche fehlen, steht **nicht** hier, sondern in `docs/stand.md`. Dieses Dokument sagt, _was sich geändert hat_; jenes sagt, _wo die Software steht_. Jede veröffentlichte Fassung trägt ein Git-Etikett (`v0.9.0`) und ein Installationspaket unter `app/release/`. In der Anwendung selbst stehen Programmversion und Baustand unter „Systemzustand“ auf dem Startbildschirm; ein `+` hinter der Baukennung heißt, dass beim Bauen unversionierte Änderungen im Arbeitsbaum lagen. --- ## [Unveröffentlicht] --- ## [0.27.3] — 2026-09-03 ### Für die Öffentlichkeit - **Das Installationspaket enthält keinen Ballast mehr:** Quelltext, Testdateien und ein Prüfbericht reisten versehentlich mit. Der Programmteil ist von 14,6 auf 2,0 Megabyte geschrumpft. - **Unter jedem Gesetzestext steht jetzt die richtige Fassung.** Bei drei der sieben Gesetze nannte die Anwendung das Jahr der Neubekanntmachung statt der letzten Änderung — beim Strafgesetzbuch 1998 statt 2026; der Wortlaut selbst war immer der aktuelle. Dazu stehen die Absätze wieder in der Reihenfolge des Gesetzes, jede Gliederungsnummer nur einmal, und „Nr. 2a“ trifft die richtige Stelle. - **Im gedruckten Fehlerprotokoll steht jetzt auch, wo es keine gesetzliche Grundlage gibt** — bei 84 Fragen fehlte das. - **Kein Prüfungslauf zählt mehr doppelt**, und Verlauf, Ampel, Pensum und hartnäckige Fragen zeigen denselben Stand. - **Ihre Einstellungen wirken überall, wo sie zugesagt sind** — gemischte Antworten, Sitzungsumfang, Sprechtempo. - **Die Datenschutzerklärung nennt jetzt alle vier Sicherheitskopien**, die die Anwendung von selbst anlegt. - **Barrierefreiheit:** Sieben Rückmeldungen sind wieder hörbar, die Stimme verstummt mit dem Vorgelesenen, der Fokus geht nicht verloren, und die Kapitelwahl passt auch bei vierfacher Schriftgröße auf den Bildschirm. - **Kleinigkeiten:** Fehlt ein Inhalt, sagt die Anwendung das. Die Fachbegriffe verraten die Musterantwort nicht mehr, Strg mit der 0 des Ziffernblocks nimmt den Kopierbefehl nicht mehr weg, und neben dem Unterstützungsknopf steht eine kleine Tasse. ### Behoben - **Der Reifegrad-Verlauf übersprang Antworten, die zeitlich hinter dem jetzigen Augenblick lagen.** Die Wiedergabe brach an der ersten solchen Zeile ab und ließ sie für immer liegen; die Ampel las den Fragenstand und kannte sie. Zwei Zahlen nebeneinander, die einander widersprechen — genau das, was der Kopf von `shared/reifeverlauf.ts` ausschließt. Es braucht dafür keine verstellte Uhr: `profil-uebernehmen.ts` kopiert das Antwortprotokoll samt Zeitpunkt wörtlich aus einer fremden Datenbank. - **Und die Wiedergabe rechnete in einer anderen Reihenfolge als der Lernstand.** Sie ordnete nach Zeitpunkt, geschrieben wird nach Einfügung; bei vertauschten Zeitpunkten entstanden zwei verschiedene Ketten. Jetzt gilt in beiden die Einfügereihenfolge. - **Der Lastausgleich zählte Fragen dauerhaft abgewählter Kapitel als Last.** Er wich damit Bergen aus, die die Arbeitslast-Vorschau desselben Profils mit null ausweist — gemessen ein Tag Verschiebung auf eine Last, die es nicht gibt. Gefiltert wird jetzt über dieselbe Menge wie dort. - **Plan und Sitzung zählten „neu“ verschieden** — der Plan über die FSRS-Stabilität, die Sitzung über die Versuche. Bei einem Lernstand aus der Zeit vor der FSRS-Umstellung meldete der Plan neue Fragen, die die Sitzung nicht vorlegte, obwohl `einfuehrungsrate` zusichert: „Anzeige und Sitzung sind dieselbe Rechnung.“ **Betroffen ist heute niemand** — keine ausgelieferte Fassung hat je eine Datenbank auf Schema 2 geschrieben —, aber das Projekt pflegt und prüft diesen Migrationsweg, und die Zusage war so, wie sie dastand, falsch. - **Ein Prüfungslauf wird genau einmal gewertet.** `bogenPruefen` nahm eine Antwortliste ungeprüft an, sobald kein Bogen bekannt war — gedacht für den Neustart mitten im Lauf. Diesen Fall gibt es dort längst nicht mehr: `offenerBogen()` füllt den Merkposten beim Fortsetzen wieder. Erreicht wurde der Zweig praktisch nur noch **nach** einer Auswertung, weil der Merkposten danach gelöscht wurde. Gemessen an einem Bogen mit 80 Fragen: `versuche` 80 → 160, Verlaufseinträge 1 → 2, und der zweite trug das Profil aus dem Auftrag des Renderers — „fehlerpunkte“ mit 80 Fragen, obwohl dieses Profil 75 vorsieht. Der Bogen wird jetzt als **verbraucht vermerkt** statt vergessen; `sichern()` hatte gegen dieselbe Verdopplung zwei Riegel, `auswerten` keinen. - **Über die Oberfläche war der Fall nicht erreichbar** — `usePruefung` hält einen `abgegeben`-Riegel, der beide Wege deckt. Der Kern soll sich darauf aber nicht verlassen; die Leitlinie dieses Moduls lautet „Der Renderer wird nicht geglaubt“. - **Eine Wache versprach im Titel das Gegenteil dessen, was sie prüfte:** „nimmt den passenden Bogen an und wertet ihn genau einmal aus“ prüfte für den zweiten Aufruf `not.toThrow()`. Sie prüft jetzt, was ihr Name sagt. - **Fünf von sechs Wegen mit fester Fragenliste bekamen `optionenMischen`, der sechste nicht.** `sitzungStarten` sagt zu, die Einstellung „hier anzuhängen deckt alle sechs Wege auf einmal“; `ausSucheUeben` baute seinen Auftrag daneben selbst, weil er als Einziger `ausSuche` mitzugeben hat, und ließ die Einstellung dabei liegen. Auch der Typkommentar in `lernen/typen.ts` führt „jeder aus der Suche gestarteten Sitzung“ seit 0.24.1 als erledigt auf. Der Weg geht jetzt durch `sitzungStarten`, das den Wert entgegennimmt. - **Der Reifegrad-Verlauf auf dem Startbildschirm veraltete stumm.** `useReifeverlauf` bietet `neuLaden` an — gerufen hat es niemand. Der Startbildschirm bleibt bei „Neu anfangen“, beim Einspielen einer Sicherung und beim Kapitelschalter stehen; `lernstand.neuLaden()` ändert die Profil-ID ausdrücklich nicht, der Effekt lief also nicht nach. Gemessen: Ampel auf null, darunter weiterhin „von 12 auf 48 von 575 Fragen gestiegen“. Beim Kapitelschalter war es schlimmer — `fragenGesamt` kommt aus dem Lernstand, `belegt` aus dem Verlauf, der Satz mischte frischen Nenner mit altem Zähler. Lernstand und Verlauf werden jetzt an denselben drei Stellen zusammen gelesen. - **Der einstellbare Sitzungsumfang erreichte drei Stellen nicht.** Unter „Weiterlernen“ stand fest „20 Fragen“, die Kapitelwahl sagte „bis zu 20 Fragen“, und `Suchansicht` rechnete mit der Konstanten `SITZUNGSUMFANG` — dort hingen Beschriftung **und** Fragenliste daran, „alle Treffer üben“ deckelte also auch bei eingestellten fünfzig auf zwanzig. Die vorhandene Wache dazu maß dieselbe Konstante und konnte es nicht sehen. Der Satz der Kapitelwahl nennt jetzt zusätzlich den Unterschied, der vorher unter den Tisch fiel: Ein Thema ist eine feste Fragenliste und kommt vollständig. - **Die Gesetzesansicht stellte jeder Gliederungsnummer dieselbe noch einmal voran.** Gemessen an `content/normtexte.json`: 231 von 231 markierten Blöcken beginnen bereits mit ihrer eigenen Marke, `Normstelle.tsx` setzt sie deshalb seit jeher nicht davor. Unter einer Überschrift, die den amtlichen Wortlaut „unverändert“ zusagt, stand „Abschnitt 1 Abschnitt 1:“. - **Die Aktiv-Regel der Gesetzeauswahl setzte genau die zwei Werte, die `.knopf` ohnehin trägt.** Zwischen dem gewählten Gesetz und den sechs anderen war kein Bildpunkt Unterschied; getragen wurde die Auskunft allein von `aria-current`, also nur für Bildschirmleser. Jetzt: Akzentgrund, Fettung und ein Unterstrich, der auch unter erzwungenen Farben bleibt. - **Die Regel `.bericht__meldung:empty` blendete die Live-Region aus und tat damit das Gegenteil des Kommentars darüber** („sie bleibt trotzdem im DOM, sonst verschluckt der Screenreader die erste Meldung“). Betroffen war allein die Ausgabe des Lernberichts; Fehlerprotokoll und Fragenliste entgingen dem nur zufällig, weil ihr Meldungsblock immer eine `nur-screenreader`-Zeile trägt. - **`useHartnaeckige` hing allein an der Profilnummer, `useLernplan` ebenso.** Beide ändern sich beim Zurücksetzen nicht. Lernstand, Plan, Verlauf und hartnäckige Fragen gehen jetzt an drei Stellen denselben Weg. - **`uebernehmen` in der Sicherungskarte holte den Fokus in keinem der beiden Zweige zurück** – Sichern, Prüfen und Einspielen tun es seit jeher. - **Zwei Knöpfe der Lernsitzung entfernen sich mit dem Klick selbst.** Der Sprung muss deshalb nach dem Neuaufbau geschehen; gezählt statt geschaltet, weil ein Zähler in der Abhängigkeitsliste der Weg ist, den React dafür vorsieht. - **`useZoomtasten` prüfte den Tastencode `Numpad0`.** Bei ausgeschaltetem NumLock meldet Chromium dafür `key: 'Insert'` – Strg+Einfg, der Kopierbefehl. Jetzt entscheidet allein die Taste selbst; NumpadAdd und NumpadSubtract sind vom NumLock-Zustand nicht betroffen und bleiben. - **`useEinstellungen` führt jetzt `gesichert` neben `werte`.** `werte` trägt die Änderung sofort, gleich ob das Sichern gelingt – wer einen Zwischenspeicher füllt, der beim nächsten Start als Startwert gilt, darf nur den bestätigten Stand nehmen. Dieselbe Regel hält `useThema` seit jeher ein. - **Die Live-Region der Anwendung hat nur noch eine Quelle.** Der Rückfall auf die Themenansage, sobald eine Menümeldung geleert wurde, sprach die nie zurückgenommene Farbschema-Ansage ein zweites Mal. - **Der Umfangssatz der Druckausgaben spricht über `aria-live` und nicht über eine zweite `role="status"`** – zwei Knoten mit derselben Rolle in einer Ansicht waren hier schon einmal ein Fund der Wachen. - **`Sitzungsauftrag` und `SitzungsBilanz` tragen jetzt `ausWiederholung`.** Der Kommentar am Sitzungsende nannte beide Fälle, gebaut war nur der Suchfall. - **Das Raster der Kapitelwahl sprengte bei 320 CSS-Pixeln die Seite.** `repeat(auto-fill, minmax(20rem, 1fr))` – eine feste Mindestspur schrumpft nicht mit. Gemessen im echten Fenster: 336 Pixel Dokumentbreite bei 316 Pixeln Fenster. Das ist eine Regression aus 0.27.1: Die Kartenanordnung kam **nach** der Messung, die `docs/stand.md` als Beleg für 1.4.10 führt, und der Reflow-Lauf kannte diese Ansicht nicht. Jetzt `minmax(min(20rem, 100%), 1fr)`, und der Lauf misst zwei Ansichten mehr – Kapitelwahl und „Über diese Software“ mit aufgeklappter Datenschutzerklärung. - **Vier weitere Live-Regionen trugen `:empty { display: none }`** – Neu anfangen, Profilverwaltung, Fehlermeldeblock, Datensicherung. Dieselbe Sache, die einen Absatz weiter oben an `.bericht__meldung` behoben ist; die Geschwister sind damals nicht gesucht worden. Beim Fehlermeldeblock traf es jeden Kopierversuch, nicht nur den ersten. Die Wache prüft jetzt nicht mehr eine Klasse, sondern **jede**, die im Markup an einem Knoten mit `role="status"`, `role="alert"` oder `aria-live` steht. - **Die Sprachausgabe des Prüfungsbogens hing allein an der Fragennummer.** Mit der Abgabe verschwindet der Frageblock samt Vorlesetaste, `Lauf` bleibt aber stehen, solange die Nachbewertung läuft – der Aufräumer griff nicht. Die Kennung trägt jetzt die Phase mit. - **Die Restzeitregion entstand zusammen mit ihrer ersten Meldung.** Sie steht jetzt dauerhaft im Baum und spricht über `aria-live` statt über eine zweite `role="status"` – die alte Begründung („stünde nur als zweiter status daneben“) war richtig, die Antwort darauf die falsche. - **`ThemaWahl` löste seinen Fokuswunsch in einem Effekt ohne Abhängigkeitsliste ein.** Wählt man die bereits aktive Option, bricht React ohne Render ab, der Merkwert bleibt stehen, und der nächste beliebige Neuaufbau riss den Fokus aus dem Nachbarelement zurück. Der Ref ist fort; fokussiert wird unmittelbar im Tastenhandler, was geht, weil alle vier Schaltflächen dauerhaft im Baum stehen. - **Vier Ansichten hängen an `katalogIndex !== null` und rendern ohne ihn nichts.** Über das Anwendungsmenü und über „Simulation starten“ landete man darin: kein `h1` im ganzen Dokument, kein Fokusanker. Neu ist `OhneKatalog` – eine Überschrift, ein Satz, ein Rückweg. - **Zwei Überschriftensprünge**, die `e2e/ueberschriften.spec.ts` beide prüft und beide nie zu sehen bekam: Die Arbeitslastvorschau erscheint erst mit einem eingetragenen Prüfungstermin, die Auswertung steht nicht in seiner Ansichtenliste. Beide Fälle sind jetzt als Wache in jsdom nachgestellt. - **Der `catch`-Zweig von `einspielen` holte den Fokus nicht zurück** – als einziger der vier Wege der Sicherungskarte. - **Der Kommentar über der Datenschutztabelle versprach einen waagerecht rollenden Rahmen mit `role="region"` und `tabIndex={0}`.** Nichts davon stand im Stilblatt oder im Markup – und nichts davon ist nötig: Die Tabelle läuft mit `table-layout: fixed` auf voller Breite, lange Wörter bricht `overflow-wrap` um, und die Ansicht ist jetzt bei 320 CSS-Pixeln gemessen. Ein Tabstopp auf einem Rahmen ohne Rollbereich wäre seinerseits ein Fehler gewesen; berichtigt ist deshalb der Kommentar, nicht der Code. - **`terminSetzen` meldet jetzt, ob gespeichert wurde.** Der Entwurf im Datumsfeld fiel bisher auch dann, wenn nichts gesichert wurde, und die Meldung erschien als „Hinweis“ ohne Live-Region. - **Die Datenschutzerklärung kannte nur drei der vier selbsttätigen Kopien.** `Lernstand-vor-dem-Verwerfen` entsteht vor „Neu anfangen“ und vor dem Löschen eines Profils; Abschnitt 4.4 sagte „in drei Fällen“ und zählte drei Muster auf, Abschnitt 7 nannte die vierte nicht. Wer der Löschanleitung folgte, ließ vollständige Kopien seines Lernstands liegen. Die Erklärung steht jetzt auf Fassung 1.8; die neue Wache liest die Dateivorsätze aus `src/main` und verlangt jeden davon in beiden Abschnitten — eine fünfte Kopienart ist damit mitbewacht. - **Die als vollständig ausgewiesene Aufzählung des Einstellungsinhalts ließ den Sitzungsumfang aus** — eingeführt in 0.26.6, in der Erklärung nie nachgetragen. - **`kennzahlenLesen` filterte die reinen Historienzeilen aus der Zahl, aber nicht aus dem Datum daneben.** Ein Profil, das nur eine abgelaufene Simulation hinter sich hat, zeigte in der Gegenüberstellung „0 Antworten … zuletzt gelernt am ⟨Prüfungstag⟩“ — zwei Zahlen, die einander widersprechen, direkt vor einem nicht rücknehmbaren Schritt. Betroffen war auch die Zeile je Profil. - **`profilUebernehmen` zählte für seine Erfolgsmeldung die eingefügten Zeilen.** Das ist etwas anderes, als die Meldung sagt: `antwort_log` enthält auch Zeilen mit `nur_historie = 1`, die die Auswahlliste davor ausdrücklich ausfiltert, und eine Zeile in `frage_stand` entsteht schon beim bloßen Merken. Gezählt wird jetzt getrennt vom Einfügen — mitgenommen wird unverändert alles. - **Ein abgebrochenes Schreiben ließ `⟨ziel⟩.teil` liegen.** Aufgeräumt wurde nur im Zweig mit abgelehnter Gegenprobe; warf `VACUUM INTO` oder der schreibende Zugriff, blieb der Rest dauerhaft stehen — der Zielname trägt die Sekunde, und die drei Aufräumwege filtern auf `.wsklernstand`. Auf einem vollen Datenträger belegte er genau den Platz, der beim nächsten Versuch fehlte. - **Ein verwaister Doku-Block:** „Ersetzt den Lernstand“ stand unmittelbar über der Funktion, die ausdrücklich nichts ersetzt. - **Der Zähler im Namen der Sicherheitskopie wurde damit begründet, dass `VACUUM INTO` sich weigere, ein vorhandenes Ziel zu überschreiben.** Das trifft auf den Zielnamen nicht mehr zu: Geschrieben wird nach `.teil` und danach umbenannt. Der Zähler bleibt — die Begründung ist berichtigt. - **Die README nannte zehn Migrationsschritte** (gezählt: neun, Fassung 1 ist das Grundschema) **und schickte zum Öffnen der Datenbank in eine Datei, die nur `:memory:` öffnet.** - **`docs/stand.md` führte den Katalogabgleich beim Dazunehmen eines einzelnen Profils als offen** — gebaut ist er seit 0.26.7. - **Migration 7 verspricht mehr, als sie halten kann**, und sagt es jetzt: Auf einer Datenbank vor Schemafassung 3 gibt es keine Stabilität, und ohne sie zählt die Ampel den nachgebildeten Beleg nicht — der nachgerechnete Verlauf dagegen schon. Gemessen 0 gegen 109. Betroffen ist niemand: Die erste veröffentlichte Fassung stand bereits auf Schemafassung 4. - **Der Druckweg verlor `ohneFundstelleGrund`.** Gemessen an `content/erklaerungen.json`: 84 der 575 Erklärungen haben keine Fundstelle, und **alle 84** tragen den Satz, der sagt, warum. `shared/erklaerungen.ts` begründet das Feld: „Dieses Feld verlangt, das auszusprechen – die Alternative wäre, eine Fundstelle zu erfinden.“ Bildschirm, Sprachausgabe und Glossar zeigen ihn; `erklaerungenFuer` kopierte ihn nicht, und `Frageerklaerung` kannte ihn gar nicht. Auf dem Papier — dem einzigen Erzeugnis, das die Anwendung aus der Hand gibt — stand damit eine Begründung ohne Beleg unter einem Vorspann, der „die Fundstellen im Gesetz“ zu jeder Frage zusagt. - **„Fragen im Katalog“ nannte den Lernumfang des Profils.** Mit abgewähltem Kapitel IV stand dort 486 unter einer Überschrift, die 575 behauptet. - **Ein verstrichener Prüfungstermin ergab „noch -33 Tage“.** Die Oberfläche hat für den Fall längst einen eigenen Satz, das Papier hatte keinen. - **Die Simulationstabelle verschwieg Zeitstufe und unbeantwortete Fragen** — genau die beiden Felder, deren Doku-Kommentare ihre eigene Existenz damit begründen, dass ohne sie unvergleichbare Läufe nebeneinanderstehen. - **Vier Dateien nannten für dieselben Dokumente unvereinbare „gemessene“ Seitenzahlen** — die Fragenliste über den ganzen Katalog mit 162 gegen 120, das Fehlerprotokoll über 150 Fragen kurz mit 70 gegen 51; und `umfang.ts` widersprach sich selbst mit 539 in der Tabelle und 508 im Absatz darunter. Die Stützstellen stehen jetzt an genau einer Stelle; zwei neue Wachen halten das fest und rechnen die Schätzung gegen die Messung nach. - **Die Hilfe nannte als schlimmsten Fall „fast tausend Seiten“** — die Anwendung sagt dort 1206 an; die 982 gehören zu 486 Fragen, nicht zum ganzen Katalog. - **Der Tabellenkopf entschied nach der Spaltennummer statt nach dem Merkmal `zahl`.** In zwei der vier Tabellen des Lernberichts stand die Überschrift am gegenüberliegenden Rand ihrer Spalte. - **`app/README.md` nannte 41 IPC-Kanäle; gezählt sind es 44.** Die Zahl beziffert die Größe der einzigen Grenze zwischen Oberfläche und Anwendungskern — wer die Angriffsfläche über das README abschätzte, unterschätzte sie. Für `app/README.md` gab es bis dahin überhaupt keine Wache; jetzt zählt eine die Kanäle nach und hält zusätzlich Vertrag und Handler deckungsgleich. - **Die Adresse des Quelltextarchivs stand in zwei Schreibweisen da.** Die Übersichtsseite ist von der Abfrageform `?page=code&repo=waffensachkunde` auf den Pfad `/quelltext/waffensachkunde` umgestellt worden; `README.md` trug die neue, `docs/fernarchiv.md`, `docs/stand.md` und `docs/store-eintrag.md` noch die alte. Eine Adresse in zwei Formen ist immer eine zu viel — eine davon ist falsch, und niemand merkt welche. `dokumentation.test.ts` hält jetzt beide Formen auseinander und vergleicht auch die Klonadresse quer über die Dokumente. - **`docs/stand.md` führte drei erledigte Dinge weiter als offen — darunter zwei in der Liste, die abgearbeitet wird.** Abschnitt 8.2 Punkt 8 nannte den Weg in den Store „der einzige Punkt dieser Liste, an dem heute etwas **nicht absendbar** ist“ und führte als ersten Sperrgrund das MSIX-Paket: „`electron-builder.yml` baut nur NSIS.“ Der Bauplan trägt seit 0.22.0 einen vollständigen `appx`-Block, `app/package.json` das Skript `dist:store`, zwei Store-Pakete sind gebaut, und eingereicht ist zweimal worden. Abschnitt 8.3 sagte „**versendet ist er nicht**“ über den BVA-Brief, der am 29.08.2026 hinausgegangen ist — verdeckt war damit der Punkt, der wirklich offen ist: die Wiedervorlage am 10.10.2026. Und ein Nebenbefund („ihr Quelltext ist offen“) stand als Store-Hindernis, obwohl er am 30.08.2026 behoben wurde. Wer die Liste abarbeitet, sucht sonst Arbeit, die getan ist. - **Dreizehn weitere Stellen der Unterlagen beschrieben einen anderen Stand als den heutigen.** Der Sitzungsumfang stand als „nur im Kern“, obwohl er seit 0.26.6 auf dem Startbildschirm einstellbar ist; „Auf einen Blick“ nannte 0.24.1 als zuletzt gebautes Paket; Abschnitt 5.1 rechnete mit 87 Glossareinträgen (118); die Datenschutzerklärung mit Fassung 1.6 (1.8); vier Kleinigkeiten in Punkt 9 waren erledigt; `fernarchiv.md` sagte, axe messe nur ein Farbschema (es messen alle drei); die Notiz zur Katalogaktualität führte zwei gebaute Aufgaben als offen; der Prüfplan beschrieb O7 als „vorgesehene Umsetzung“, obwohl alle vier Schritte stehen, und zählte die axe-Suite mit 15/17/47 statt 16 Prüfstücken und 50 Prüfungen; `app/README.md` sagte, es würden nur zwei Prüfungen übersprungen (es sind zwanzig); und die Sprachausgabe-Notiz stützte ein Argument auf ein fehlendes Archiv, das es seit dem 01.09.2026 gibt. - **`PLAN.md` führte einen eigenen Umsetzungsstand — und einen überholten.** „Phase 2 (Lern-Kern) ist in Arbeit“, während `docs/stand.md` P1 bis P7 als fertig führt; nach CLAUDE.md ist `docs/stand.md` die einzige Stelle dafür, also steht jetzt dort ein Verweis statt einer zweiten Zählung. Dazu vier Stellen, an denen der Plan etwas anderes beschreibt als das Gebaute: die Bibliothek `zustand` (nie eingezogen), „eine Datei je Profil“ (gebaut ist eine gemeinsame Datenbank mit `profil_id`), ein vierter Fragetyp `freitext_teilfragen` (gibt es nicht) und 18 Bilder (gezählt 17). - **Fünf Zahlen im Verzeichnisbaum von `app/README.md` waren am Bestand falsch** (`main/` 31 statt 32, `lernen/` 38 statt 40, `ueber/` 3 statt 4, `hooks/` 26 statt 29, `tests/` 72 statt 79) — und der Kopf derselben Datei verwies das Datenbankschema in einen anderen Arbeitsstrang, während der Baum vier Absätze weiter `src/main/schema.ts` auflistet. Die Zusage „einmal pro Theme“ hing an `barrierefreiheit.spec.ts`, die genau ein Thema setzt; je Farbschema messen tut `barrierefreiheit-ansichten.spec.ts`. - **Das ausgelieferte `app.asar` enthielt den ganzen Quelltext, alle Tests und den Abdeckungsbericht des letzten Gate-Laufs.** Zwei Zeilen über der Liste `files:` in `electron-builder.yml` steht: „Nur die gebauten Bundles paketieren – die Quellen bleiben draußen.“ Gemessen am Paket der Fassung 0.27.2 — derselben, die die Store-Prüfung bestanden hat — lagen darin 592 Dateien: neben den fünf aus `out/` der vollständige TypeScript-Quelltext (`src/`, 200 Dateien), alle Unit- und E2E-Tests (81 und 26), `tools/`, sechs tsconfig-Dateien, die Konfigurationen von ESLint, Prettier, Playwright und Vitest, `README.md`, ein liegengebliebenes `v2-frage.png` — und `coverage/` mit 217 Dateien und 8.967.480 Byte. Der Inhalt des Pakets hing damit vom Zustand des Entwicklerrechners ab: Wer vorher keinen Abdeckungslauf gefahren hatte, lieferte ein anderes Paket aus. Ursache ist eine Falle von electron-builder: Eine plattformeigene `files:`-Liste **ersetzt** die oberste, statt sie zu ergänzen — und besteht sie ausschließlich aus Ausschlussmustern, stellt die Bibliothek ihr `**/*` voran (`containsOnlyIgnore` in `app-builder-lib/out/fileMatcher.js`). Genau so waren die Blöcke `win:` und `mac:` geschrieben: je ein `!`-Muster für die fremden Fertigteile von better-sqlite3. Dass es nicht auffiel, lag daran, dass ausgerechnet diese Ausschlüsse über einen getrennten Matcher weiter griffen — das Paket sah an der Stelle richtig aus, an der zuletzt jemand nachgesehen hatte. Beide Plattformblöcke führen jetzt die vollständige Liste. `tests/paketstand.test.ts` hält die drei Listen deckungsgleich und schlägt an, sobald eine wieder nur aus Ausschlüssen besteht; `e2e/gepackt.spec.ts` liest das Inhaltsverzeichnis des gebauten Archivs und verlangt dort genau `out/`, `node_modules/` und `package.json`. Nachgemessen am neu gebauten Paket: 50 statt 592 Dateien, `app.asar` 1.962.296 statt 14.571.535 Byte. - **Der Rahmen des Updateberichts bestritt das öffentliche Quelltextarchiv, das derselbe Bericht zwei Absätze vorher meldet.** „auf Anfrage erhältlich; ein öffentliches Archiv gibt es bislang nicht“ stand im hand geschriebenen Schluss, während der erzeugte Mittelteil und `README.md` die Adresse längst nennen. Das ist das eine Dokument, das mit der Installationsdatei weitergegeben wird, und bei der EUPL ist die Verfügbarkeit des Quelltextes kein Nebensatz. - **Der dokumentierte Ort der Freigabebefehle stimmte für keinen von ihnen.** `docs/veroeffentlichen.md` sagte „Alle Befehle laufen in `app/`“; aus `app/` heraus bricht jeder der acht Python-Aufrufe mit „No such file or directory“ ab, und die drei npm-Aufrufe tragen ihr `cd app &&` selbst. - **Sieben weitere Zahlen waren abgeschrieben statt gezählt:** die fünf fremden Fertigteile von better-sqlite3 (sechs, 13.003.904 Byte), die siebzehn Prüfungen aus `gepackt.spec.ts` (vierzehn — die 17 waren die Summe mit `fensterlage.spec.ts`), die dreizehn Abnahmebilder (vierzehn), die 23 Fehlerarten des Erklärungs-Selbsttests in `gate.yml` (31), die sechs Schritte des CI-Jobs (sieben, davon fünf Python-Läufe), „119 bestanden / 110 bestanden“ im Gate-Stempel (203 und 183) und „ein Dutzend Größen“ des Programmsymbols (zehn, dazu eine für macOS). - **`docs/stand.md` führte einen CI-Schritt als offen, der längst dasteht:** der Selbsttest von `pruefe_erklaerungen.py` in `.github/workflows/gate.yml`. - **Der Modulkopf von `datenschutz_anwendung.py` führte einen „geschlossenen Tagvorrat“ auf, in dem sechs der erzeugten Tags fehlten:** `table`, `thead`, `tbody`, `tr`, `th`, `td`. Der Kopf legte damit nahe, eine Tabelle in `docs/datenschutz.md` löse einen Abbruch aus; angenommen wird sie sehr wohl, und sie macht den aufwendigsten Zweig des Umsetzers aus. - **Der Commit-Haken versprach, was die Projektregel verbietet.** `.githooks/pre-commit` schrieb „`git commit --no-verify` bleibt möglich und soll es bleiben“, während CLAUDE.md „Kein `--no-verify`“ sagt und `.claude/settings.json` den Aufruf sperrt. Dazu zwei Zeitangaben, die nie gemessen waren: „rund 73 Sekunden“ für die Vollstufe (gemessen 243 s) und „rund 40 s“ für die Schnellstufe (gemessen 98 s). - **Der Änderungsstand war bei drei von sieben Gesetzen die falsche Angabe.** Das amtliche XML führt die Standangabe je nach Gesetz ein- oder zweimal: Wer seit seiner Neufassung geändert wurde, trägt zuerst einen Eintrag vom Typ `Neuf` und danach den vom Typ `Stand`. `gesetze_index.py` las mit `standangabe/standkommentar` blind den ersten. Unter dem Wortlaut stand dadurch bei StGB, SprengG und 1. SprengV — zusammen 40 der 148 ausgelieferten Normen — die Bekanntmachung statt der letzten Änderung, beim StGB die vom 13.11.1998 statt der vom 20.03.2026. Schwerer wog die zweite Wirkung: Der Freigabeschritt „Gesetzesstand ansehen“ vergleicht diese Zeichenkette mit gesetze-im-internet.de, und eine Neufassungs-Bekanntmachung ändert sich durch keine Gesetzesänderung — für diese drei Gesetze konnte der Schritt nie anschlagen. Der falsche Wert stand in `content/gesetze/index.json`, `content/normtexte.json`, `content/erklaerungen.json` und `content/glossar.json`. - **Die Prüfung der Antwortmöglichkeiten hielt Buchstaben aus Gesetzeszitaten für Nennungen einer Antwort.** „§ 12 Abs. 1 Nr. 3 Buchstabe d WaffG“ und „(§ 38 Abs. 1 Nr. 1 Buchst. e)“ lieferten „d“ und „e“ als angeblich genannte Optionsbuchstaben. Der Buchstabenzweig ist der erste und stärkste Ausgang der Prüfung; ein Zitatbuchstabe konnte eine Antwortmöglichkeit als behandelt ausweisen, die im Text gar nicht vorkam. Nachgemessen: 130 statt 121 Erklärungen galten als „nennt alle Optionsbuchstaben“, neun allein wegen eines Zitats. Im heutigen Bestand richtete das keinen Schaden an — die Sicherung war aber unbegründet stumm. Gezählt kommen 123 solche Wendungen vor, und keine einzige bezeichnet eine Antwort. - **Der dokumentierte Aufruf des Nachschlagewerkzeugs suchte nicht.** `gesetz.py --suche "…" --gesetz WaffG` stand so im Kopf der Datei; es gibt keine Option `--gesetz`, und `argparse` löste sie als Abkürzung von `--gesetze` auf. Ausgegeben wurde eine Liste aller Gesetze, Exit-Code 0, kein Hinweis. CLAUDE.md macht das Nachschlagen mit diesem Werkzeug zur Pflicht — wer der Anleitung folgte, hielt ein leeres Suchergebnis für ein Ergebnis. Der Kopf nennt jetzt die richtige Form, und `allow_abbrev=False` lässt einen unbekannten Optionsnamen abbrechen statt stumm etwas anderes tun. - **Sechs Zahlenangaben über den eigenen Bestand waren abgeschrieben statt gezählt.** `docs/stand.md` nannte an vier Stellen 1853 Fundstellen (gezählt 1854 — Zeile 74 derselben Datei sagte das bereits), dazu „588 von 632“, „43 der 44“, „2137“ und „503 KiB“; `normtexte_bauen.py` und der Kopf von `tests/normtexte.test.ts` trugen dieselben Zahlen weiter. Gemessen mit `auszugBilden` über den echten Bestand: 1444 von 1444 Absatzzitaten und 580 von 632 Anlagenzitaten treffen genau, von den 52 übrigen nennen 32 eine Abbildung, insgesamt 2138 Fundstellen, 500 KiB. - **Der Modulkopf von `parse_catalog.py` beschrieb ein anderes Layout, als der Code liest.** Er nannte die Antwortspalte 292–505 und die Kästchenspalte 505–524; der Code arbeitet mit 292–540 und 500, das Handbuch mit 292–540 und 503–529. Gemessen an der Vorlage laufen Wörter der Antwortspalte bis x = 531,8, und alle 1430 Kästchen liegen zwischen 503,1 und 528,8 bei 10,32 pt Kantenlänge. Dazu behauptete er, ein Kästchen markiere den Beginn einer Antwortoption — genau die Annahme, deren Beseitigung in `docs/stand.md` 7.12 als Behebung steht. - **Die Bildzahlen, die die Reihenfolge der beiden Zuordnungsregeln begründen, ließen sich nicht nachmessen.** Sie entscheiden, an welcher Antwortmöglichkeit ein Prüfzeichen hängt. Der Kopf nannte 43 Bilder in Antwortspalten, 38 ohne Label im Rechteck und „die übrigen 5 gehören sämtlich zu I.3-05“. Gezählt sind es 44; zwei davon gehören zu Fragen ohne Antwortmöglichkeiten und erreichen die Methode gar nicht, 42 tun es, 38 ohne Label, und die vier bei I.3-05 ordnen dreimal gleich zu, einmal widersprüchlich — nicht viermal und einmal. - **Zwei Zahlen über die Prüfwerkzeuge selbst:** `data-pipeline/README.md` nannte „jede der 22 Fehlerarten“ seit Fassung 0.21.1 unverändert, gefahren werden 31 plus zwei Gegenproben; `themen_bauen.py` begründete seine Gliederung mit „Zwölf Gruppen für 92 Fragen“, gezählt sind es elf für die 92 Fragen des Kapitels II und 29 für 230 Fragen insgesamt. Die Zahl im Handbuch war genau der Fehler, den `pruefe_erklaerungen.py` in seinem eigenen Zähler schon einmal behoben hatte — eine Datei weiter stand er unbemerkt weiter. - **Neben der Beschriftung des Unterstützungsknopfes steht jetzt ein Zeichen.** Gezeichnet in `currentColor` und in `em` bemessen: Es folgt den drei Themen und dem Modus mit erzwungenen Systemfarben und wächst bis zur vierfachen Schriftgröße mit. `aria-hidden`, damit der zugängliche Name des Knopfes allein die sichtbare Beschriftung bleibt (WCAG 2.5.3). Eine Bilddatei mit Text darin wäre beides nicht und verstieße gegen WCAG 1.4.5. - **Ein verwaister Doku-Block im IPC-Vertrag:** Die Begründung, warum das Antwortmischen ab Werk aus ist — die einzige Stelle im Vertrag, die auf `docs/entscheidung-antwortreihenfolge.md` verweist —, stand über `zuschnittGefragt` statt über `optionenMischen` und hing damit an nichts. - **`Object.entries` sortierte die Absätze um.** Ganzzahlige Schlüssel kommen zuerst, die übrigen danach: Ein Paragraf mit 1, 2, 2a, 3 erschien als 1, 2, 3, 2a. Nachgemessen an `content/normtexte.json`: acht Normen betroffen. Die Gesetzesansicht sagt zu, der Wortlaut werde „nicht gekürzt, nicht zusammengesetzt und **nicht umsortiert**“. - **Das Muster für „Nr. …“ las nur Ziffern und Punkte.** Aus „Nr. 2a“ wurde die Zahl 2, und gesucht wurde der Block mit der Marke „2“ – die Überschrift eine Ebene darüber. Acht Zitate nennen einen Buchstabenzusatz, und kein einziger Block im Bestand trägt eine Marke mit Buchstaben. Nachgemessen ändern sich damit auch die Zahlen im Modulkopf: 580 von 632 Anlagenzitaten lösen sich eindeutig auf, von den 52 übrigen nennen 32 eine Abbildung. Der Kopf nannte „588 von 632“ und „43 von 44 Abbildungen“ — die zweite Zahl war schon vorher falsch, zwölf der 44 waren gewöhnliche Nummern. - **Die Fachbegriffe wurden auch in der Musterantwort gesucht** — vor dem Beantworten. Bei den 104 offenen Fragen ist sie die Lösung, und ihre Begriffe standen in der Zusammenfassung des Aufklappers: als Zahl für alle, im zugänglichen Namen namentlich für Bildschirmleser. Nach dem Bestätigen wird sie weiterhin mitgesucht. - **Die Glossaransicht prüfte auf `null`, der Lader liefert einen leeren Bestand.** Bei fehlender oder kaputter `glossar.json` gelingt der Kanal, und die Ansicht zeigte Suchfeld, „0 Einträge“ und „Zu dieser Eingabe gibt es keinen Eintrag“. `useGlossar` führt jetzt ein Feld `vorhanden` — dasselbe, das `useNormtexte` seit jeher hat. - **Das Zerlegungsangebot der Suche rechnete mit dem ungefilterten Text.** Ein Punkt am Satzende genügte: „Hiebwaffen.“ versprach eine Frage, der eigene Klick zeigte drei; bei „Reizstoffwaffe?“ fiel das Angebot ganz weg. Randzeichen werden jetzt in `zerlegung` selbst abgeschnitten, also auf jedem Weg dorthin. - **Vier Zahlen waren geschätzt statt gezählt:** 3.648 Wortformen des Katalogs (gezählt 3.579), „rund 1,5 MB JSON“ (gemessen 880.466 Byte), 1853 Fundstellen in `docs/stand.md` (gezählt 1854) und eine Überschriftenebene, die die Prüfungsauswertung seit 0.24.1 nicht mehr benutzt. ### Für die Werkbank - **Drei Befunde aus der Prüfrunde `/fehlersuche` zum Anwendungskern**, jeder mit einer Wache, die ohne die Behebung rot ist, und jeder einzeln durch eine Gegenprüfung geschickt, die ihn kippen sollte — alle drei haben gehalten. - **Zwei Kandidaten habe ich selbst verworfen:** Die Tagesbildung der hartnäckigen Fragen rechnet richtig (nachgemessen: 23:30 UTC wird zum Folgetag, wie in Node), und die Messtabelle im Kopf von `shared/reife.ts` ließ sich auf drei Stellen nachrechnen — 0,766 / 0,802 / 0,857 und 372 / 390 / 416 von 486. - **Eine eigene Begründung war falsch und ist berichtigt:** Ich hatte für die Zukunftszeilen Zeitzonenwechsel verantwortlich gemacht. Der Zeitpunkt wird als UTC geschrieben; da verschiebt sich nichts. Tragend ist die Profilübernahme. - **Vier Befunde aus der Prüfrunde `/fehlersuche` zu Lernsitzung und Oberfläche**, jeder mit einer Wache, die ohne die Behebung rot ist, und jeder einzeln durch eine Gegenprüfung geschickt, die ihn kippen sollte — alle vier haben gehalten. **Ein Kandidat ist dabei gekippt:** `brauchtLernstand` kennt `nurHartnaeckige` nicht, aber kein Weg der Oberfläche schickt diesen Filter über `lernen:sitzung` — die hartnäckigen Fragen laufen als feste Liste. Latent, nicht wirksam, und ohne roten Test am laufenden Programm. - **Der erste Durchlauf hat den Bereich nicht ausgeschöpft.** Geprüft waren die Lernschleife (`useSitzung`, `Lernsitzung`), `App.tsx`, die Suchansicht und alles, was mit 0.27.0 bis 0.27.2 neu dazukam. - **Der zweite Durchlauf hat den Rest aufgeteilt** – Sicherung und Profile, Druckausgabe, Lernplanung, Nachschlagewerke, die Bauteile der Frageseite, das Sitzungsende, die Anzeige-Haken, Suche und Sprachausgabe. Aus 36 Kandidaten sind **22 durch die Gegenprüfung gekommen**, 14 sind dort gefallen; nach Abzug zweier Dubletten und eigener Nachmessung bleiben **20 Befunde**, alle behoben. Das sind fünf mehr, als die Prüfroutine je Durchlauf vorsieht – weggelassen wurde keiner, weil alle zwanzig belegt sind. - **Drei Behebungen sind Kommentare, keine Zeilen Programm:** die Zusammenlegung der Druckkarten geschah in 0.21.0 und nicht in 0.20.0 (nachgesehen am Anlegedatum von `Druckkarte.tsx`), „Aufbewahrung“ hat zwölf Buchstaben und nicht dreizehn, und `useReifeverlauf` beschreibt jetzt, wann wirklich gerechnet wird. Für diese drei gibt es keine Wache – ein Test über einen Kommentar wäre keiner. - **Eine Wache hat zunächst nicht gebissen** und ist nachgeschärft worden: Der Vergleich der Stilregeln sah `border-width` gegen die Kurzform `border` an und fand deshalb einen Unterschied, den es nicht gab. Sie löst die Kurzform jetzt auf. - **Bereich 4 der Prüfrunde – Barrierefreiheit – ist abgearbeitet.** Der Zuschnitt war ein anderer als in den Bereichen davor: axe-core läuft in diesem Projekt bereits über jede Ansicht, in jsdom und im echten Fenster, und Kontrast, Zielgrößen und der Umbruch bei 320 Punkten sind maschinell belegt. Gesucht wurde deshalb ausdrücklich das, was keine Regelmaschine sieht: Fokusziele nach jeder Aktion, Ansagezeitpunkte, Überschriftenebenen, Zustände, die im eigenen Hochkontrast-Thema zusammenfallen, und Zusagen in Kommentaren. Aus 32 Kandidaten sind 14 durch die Gegenprüfung gekommen, 18 sind gefallen; nach Abzug zweier Dubletten bleiben **elf Befunde**, alle behoben. **Keiner von ihnen wäre von axe zu finden gewesen.** - **Ausgeschlossen blieb, was `docs/stand.md` 8.3 als offen führt:** der Durchlauf mit NVDA, JAWS oder VoiceOver (Hilfsmittelmatrix H1–H15, alle fünfzehn Zeilen leer), die Sichtprüfung H8 und der Lauf auf einem Mac. Die Gegenprüfung hatte ausdrücklich den Auftrag, einen Befund zu kippen, der in Wahrheit einen dieser Punkte beschreibt. - **Bereich 5 der Prüfrunde – Datenhaltung, Sicherung, Wiederherstellung – ist abgearbeitet.** Aus 27 Kandidaten sind 12 durch die Gegenprüfung gekommen, 15 sind gefallen; alle zwölf sind behoben. Sieben davon sind Zusagen, die der Code nicht hält — darunter die veröffentlichte Datenschutzerklärung, zwei Zeilen der README und eine Zeile in `docs/stand.md`. **Datenverlust hat der Durchlauf keinen gefunden:** Die behaupteten Fälle — der Rückweg, der angeblich löscht, bevor der Ersatz dasteht, die liegenbleibende Prüfkopie, die Wochenkopie beim Öffnen statt beim Beenden — sind sämtlich in der Gegenprüfung gefallen. - **Ein eigener Fehlgriff dabei:** `prettier --write` aus `app/` heraus auf `../docs/datenschutz.md` angewandt — die Ignoreliste des Projekts greift von dort nicht, und die Formatierung hat die doppelte Trennlinie zerlegt, an der der Umsetzer den Betreibervorspann erkennt. Der Umsetzer hat das gemeldet und abgebrochen, statt den Vorspann mitzuveröffentlichen; die Datei ist zurückgesetzt und der Inhalt erneut eingetragen worden. **`docs/` gehört nicht in einen Prettier-Lauf aus `app/`.** - **Bereich 11 der Prüfrunde – Dokumentation – ist abgearbeitet, und damit die ganze Runde.** Aus 24 Kandidaten sind 20 belegt geblieben; alle sind behoben. Der Fächer ist zweimal an Serverfehlern (529/500) zerbrochen: 21 von 55 Agenten starben, darunter die gesamte Handbuch-Suche und beide Widerleger zweier Gruppen — zehn Befunde landeten dadurch nur scheinbar als „gekippt“. Nachgeprüft habe ich jeden von Hand am Bestand; die Handbuch-Gruppe ebenso, sie ergab keinen Befund (die Zahlen 104, 26/25/7/5/5, 5, 118 und die beiden Beispiel-Fragennummern stimmen). Neue Wachen: `dokumentation.test.ts` zählt jetzt den Verzeichnisbaum von `app/README.md` nach und hält drei Widersprüche zwischen Dokumenten fest (BVA-Brief, appx-Block, Store-Einreichung) sowie die Adresse des Quelltextarchivs quer über vier Dokumente; `hilfe-zahlen.test.ts` zählt die Glossarzahl des Handbuchs. **Damit ist die Runde über alle elf Bereiche abgeschlossen:** 226 Kandidaten durch die Gegenprüfung, 121 belegte Befunde behoben, jeder mit einer Wache, die ohne die Behebung rot ist. Drei davon trugen Schwere A und wären in eine Veröffentlichung gegangen: die umsortierten Gesetzesabsätze, die Fassungsangabe von 1998 unter dem Strafgesetzbuch und das Paket, das Quelltext und einen Abdeckungsbericht mitführte. - **Bereich 10 der Prüfrunde – Bau, Paket, Werkzeuge – ist abgearbeitet.** Aus 21 Kandidaten sind 10 durch die Gegenprüfung gekommen, 11 sind gefallen; alle zehn sind behoben, dazu drei Befunde des Vollständigkeitskritikers. Der schwerste betraf das ausgelieferte Paket selbst und war an keiner bestehenden Wache zu sehen: `paketstand.mjs` vergleicht Zeitstempel, `gepackt.spec.ts` prüft, dass Inhalte laden — in das Archiv sah keine der beiden je hinein. Sie tut es jetzt. - **Bereich 9 der Prüfrunde – Katalog, Erklärungen, Glossar, Themen und die Pipeline – ist abgearbeitet.** Aus 21 Kandidaten sind 10 durch die Gegenprüfung gekommen, 11 sind gefallen; alle zehn sind behoben. Sechs betrafen Zahlen, die in Kommentaren und Dokumenten standen, ohne gezählt zu sein — deshalb ist die Behebung in vier Fällen keine Berichtigung, sondern eine Wache: `pruefe_erklaerungen.py`, `themen_bauen.py` und `parse_catalog.py` rechnen ihre eigenen Handbuchzahlen bei jedem Lauf nach und brechen ab, wenn sie nicht mehr stimmen; `tests/normtexte.test.ts` misst die Auflösungsquote am echten Bestand und hält `docs/stand.md` und den Kopf von `shared/normtexte.ts` dagegen. Die vier Inhaltsprüfer und der Selbsttest der Themengliederung liefen vorher und nachher grün. - **Bereich 8 der Prüfrunde – Suche, Glossar, Normtexte, Erklärungen – ist abgearbeitet.** Aus 22 Kandidaten sind 10 durch die Gegenprüfung gekommen, 12 sind gefallen; alle zehn sind behoben. **Zwei davon standen im amtlichen Wortlaut selbst** — die umsortierten Absätze und die Fundstelle mit Buchstabenzusatz. Beide waren nur am echten Bestand unter `content/` zu sehen: `Object.entries` verrät seine Umsortierung an keiner Attrappe mit lauter ganzzahligen Schlüsseln, und „Nr. 2a“ kommt in keinem Prüfstand vor. - **Bereich 7 der Prüfrunde – Electron-Sicherheit und IPC – ist abgearbeitet, und das Sicherheitsmodell hat gehalten.** Aus 20 Kandidaten sind 3 durch die Gegenprüfung gekommen, 17 sind gefallen; zwei der drei beschrieben dieselbe Sache, es bleiben **zwei Befunde, beide Dokumentation**. Gefallen sind unter anderem: die behauptete Lücke über `ELECTRON_RENDERER_URL` (setzt einen Akteur voraus, der ohnehin im Benutzerkonto Code ausführt, und die Datenschutzerklärung nennt genau den in Abschnitt 9 als außerhalb der Zusicherung), die angeblich nur an der Standardsitzung hängenden Berechtigungssperren, `shell.openExternal` und vier Angriffe auf die Eingabeprüfung. **Den Suchern war ausdrücklich gesagt, dass das Modell nicht gelockert wird** — gesucht waren Lücken, nicht Ausnahmen; die Gegenprüfung hatte den Auftrag, jeden Befund zu kippen, dessen Behebung einen Schalter, die CSP oder eine Navigationssperre aufweichen würde. - **Bereich 6 der Prüfrunde – Druck und PDF – ist abgearbeitet.** Aus 24 Kandidaten sind 13 durch die Gegenprüfung gekommen, 11 sind gefallen; drei der dreizehn beschrieben dieselbe Sache aus verschiedenen Blickwinkeln, es bleiben **sieben Befunde**, alle behoben. Der schwerste ist der einzige A-Befund dieser ganzen Prüfrunde: Er trifft den Lerninhalt selbst, auf dem Papier, und genau das Feld, das eigens dafür angelegt wurde, keine Fundstelle zu erfinden. - **Zwei Wachen sind neu und verhindern eine ganze Fehlerklasse:** Seitenzahlen dürfen nur noch in `umfang.ts` stehen, und die dortigen Stützstellen werden gegen den Schätzer nachgerechnet — bei Normalgröße auf fünf Prozent genau, im Großdruck mit der ausdrücklich gewollten Spanne nach oben. - **Eine eigene Wache hat zweimal nicht gebissen und ist zweimal nachgeschärft worden:** Der Prüfstand von `ThemaWahl` hatte kein zweites Bedienelement – genau deshalb ist der stehengebliebene Fokuswunsch nie aufgefallen. Und die Wache zum Verstummen nach der Abgabe zählte einen Abbruch mit, den `sprich()` selbst auslöst; sie zählt jetzt erst ab der Abgabe und braucht einen Bogen **mit** offener Frage, weil nur dann die Nachbewertung folgt und die Ansicht stehen bleibt. ## [0.27.2] — 2026-09-01 Der Quelltext ist öffentlich — und sechs Stellen der Unterlagen sagten noch das Gegenteil. ### Für die Öffentlichkeit - **Der Quelltext dieser Software ist jetzt öffentlich einsehbar.** Jede Aussage der Datenschutzerklärung lässt sich damit ohne Konto und ohne Anfrage selbst nachprüfen. Die Adresse steht in der Erklärung und in der Liesmich-Datei. ### Geändert - **Der gruppierende Rahmen der Kapitelwahl wirkt über die Farbe statt über die Breite.** Neues Token `--farbe-rahmen-stark` in allen fünf Schema-Blöcken. ### Für die Werkbank - **Das Fernarchiv ist zur Hälfte erledigt.** Nachgemessen am 01.09.2026: `git ls-remote` liefert die Etiketten bis `v0.27.1`, und der veröffentlichte Baum ist eine **exakte Teilmenge** dieses Arbeitsstands — 422 von 463 verfolgten Dateien, **keine einzige mit abweichendem Inhalt**. Weggelassen sind die internen Arbeitsunterlagen. Die vier Belegdateien, die Abschnitt 2 der Datenschutzerklärung namentlich nennt, liegen alle im Archiv. - **Offen bleiben zwei Dinge, und sie stehen jetzt so da:** Als Sicherung deckt das Archiv die Software, nicht den Projektstand — die 41 nicht veröffentlichten Dateien liegen weiterhin nur auf einer Platte. Und `.github/workflows/gate.yml` beschreibt GitHub Actions, während das Archiv auf eigenem Webspace liegt: Was fehlt, ist kein Ort mehr, sondern ein Runner. Sechs Stellen in `stand.md`, `veroeffentlichen.md` und `fernarchiv.md` behaupteten noch das Gegenteil. - **Die Warnung vor der Absenderadresse ist gegenstandslos.** `stand.md` Punkt 5 hielt fest, mit dem Fernarchiv werde die Commit-Adresse öffentlich. Nachgesehen im Archiv: Autor und Committer tragen genau die Adresse, die auch in Impressum und Datenschutzerklärung steht. - **Die Datenschutzerklärung steht auf Fassung 1.7** und nennt das Archiv; `content/datenschutz.json` ist nachgezogen. ## [0.27.1] — 2026-09-01 Zwei Fehler in der Kapitelwahl, beide aus 0.27.0 und beide am Bildschirm aufgefallen — nicht in einem Test. ### Für die Öffentlichkeit - **Die Kapitelwahl ist wieder aufgeräumt.** Seit die Ansicht den Lernstand je Auswahl zeigt, standen die Schaltflächen ineinandergeschoben und ein leerer hoher Kasten dazwischen. Jede Auswahl hat jetzt ihre eigene Zeile. - **Der Lernstand steht jetzt an jeder Auswahl.** Vorher erschien er nur bei den Abschnitten des ersten Kapitels — bei „Ganzes Kapitel üben“ und bei allen Themen der Kapitel II bis IV fehlte er. ### Behoben - **Die Anordnung.** Die Schaltflächen standen in einer umbrechenden Reihe. Das war richtig, solange es Schaltflächen waren; seit jede Auswahl Satz und Balken darunter trägt, zogen sich die Elemente gegenseitig auf die Höhe des höchsten. Jetzt ein Raster mit einer Spalte je 20 rem — bei 400 Prozent Anzeigegröße genau eine, ohne von Hand gepflegte Bruchstelle. - **Die fehlenden Ampeln.** Der amtliche Katalog gliedert **nur** Kapitel I in Abschnitte; die Bereichsliste führt deshalb `I.1` bis `I.5`, aber kein `I`, und für II bis IV das Kapitel selbst. Die 29 Themengruppen stehen seit 0.27.0 in einem eigenen Feld, das die Kapitelwahl nicht bekam. Beides ist jetzt verdrahtet. ### Für die Werkbank - **`bereicheZusammenfassen` ist exakt, nicht ungefähr.** Der Reifegrad ist ein Mittelwert über Fragen; über disjunkte Bereiche ist das gewichtete Mittel derselbe Wert. Eine Wache rechnet beide Wege gegeneinander und verlangt Gleichheit auf zwölf Stellen — sonst stünden am Kapitelknopf und in der Übersicht zwei Zahlen, die einander widersprechen. - **`.kapitelwahl__bereich` hatte keine einzige CSS-Regel.** Der Umschlag kam in 0.27.0 dazu und wurde nie gestaltet; als Flex-Element in einer umbrechenden Reihe ergab das genau das Bild, das aufgefallen ist. - **Von der Ansicht gab es kein Bildschirmfoto.** Deshalb ist es niemandem aufgefallen — nicht einmal mir beim Bauen. `bildschirmfotos.spec.ts` legt jetzt `14-kapitelwahl.png` ab. - Zahlen: **1851 Vitest-Tests in 79 Dateien** (0.27.0: 1843). ## [0.27.0] — 2026-09-01 Sechs Lücken der Stand-der-Technik-Runde gebaut — und damit endet, was sich am Quelltext erreichen lässt: Was jetzt noch offen ist, braucht einen Menschen mit einem Bildschirmleser. Die Runde begann als zweite Gegenprüfung: zwölf Befunde am Quelltext nachgeprüft, wieder mit dem Auftrag, sie zu **widerlegen** — **zwei fielen dabei**. ### Für die Öffentlichkeit - **Ein übernommenes Lernprofil warnt jetzt vor einem anderen Fragenkatalog.** - **Die Antwortmöglichkeiten haben jetzt dieselbe Zeilenlänge wie jeder andere Text.** - **Die selbsttätige Sicherheitskopie entsteht jetzt auch beim Öffnen.** - **Ihre Einstellungen reisen jetzt mit der Sicherung mit** — Farbschema, Anzeigegröße, Textabstand, Vorlesen, Sprechtempo, Zifferntasten und Sitzungsumfang. Wer 400 Prozent Anzeigegröße braucht, musste sie auf dem zweiten Rechner bisher ohne sie einstellen. - **In der Kapitelwahl steht jetzt neben jedem Abschnitt, wie reif er ist** — bisher nur auf dem Startbildschirm. - **Die beiden Tabellen der Datenschutzerklärung sind in der Anwendung jetzt Tabellen** und nicht mehr Aufzählungen. - **Die Aufschlüsselung des Lernstands nennt jetzt 29 Themengruppen.** „Kapitel IV, 61 von 88“ sagte nicht, was zu üben ist; „Notwehr und Notstand“ sagt es. - **Der Lernstand zeigt jetzt, wie er sich entwickelt hat** — als Satz, als Linie und als Tabelle Tag für Tag. Nachgerechnet aus Ihren bisherigen Antworten, reicht er so weit zurück, wie Sie schon lernen. - **Sie können jetzt in den Gesetzen blättern und suchen.** Waffengesetz, Beschussgesetz, Sprengstoffgesetz und die Verordnungen dazu liegen bei; bisher kam man an sie nur über eine Frage heran. - **Wiederholungen weichen jetzt vollen Tagen aus.** Wer an einem Abend vierzig Fragen beantwortet, bekommt sie nicht alle am selben Tag zurück. ### Behoben - **Die Datenschutzerklärung in der Anwendung ließ sich nicht mehr erzeugen.** Beide Fassungen — die veröffentlichte HTML-Seite und die in der Anwendung — entstehen aus **derselben** Umsetzung. Als die HTML-Fassung Tabellen lernte, brach der Erzeuger für die Anwendung an ihnen ab. Weil die Quelle sich dabei nicht änderte, blieb die Quellprüfsumme richtig und keine Wache wurde rot: Die Anwendung zeigte Aufzählungen, die Webseite Tabellen. Der Erzeuger kennt Tabellen jetzt, die Anwendung zeigt sie als Tabellen mit Spalten- bzw. Zeilenköpfen, und eine neue Wache zählt die Bauformen beider Erzeugnisse gegeneinander — die Lücke, die keine Prüfsumme schließt. - **Beim Übernehmen eines Profils wurde der Katalogstand nicht abgeglichen.** Beim Katalogwechsel auf dem eigenen Rechner meldet der Lernstand seit jeher, was verwaist; für ein fremdes Profil gab es diese Prüfung nicht. Gemeldet wird nur, wenn der Stand bekannt **und** ein anderer ist — sonst stünde bei jeder Übernahme eine Zeile, die nichts sagt. - **Die Antwortmöglichkeiten waren die einzige ungedeckelte Lesefläche.** `--textbreite-max` deckelt jeden Absatz; dort galt sie nicht. Lange Zeilen sind an der Bildschirmlupe und bei Lesestörungen eine bekannte Hürde: Wer am Zeilenende ansetzt, findet den Anfang der nächsten nicht wieder. - **Die Wochenkopie entstand nur beim geordneten Beenden.** Bei einem Absturz entstand sie nie — und genau dann ist sie am ehesten etwas wert. ### Für die Werkbank - **Zwei Befunde sind widerlegt.** Die gemessene Behaltensquote steht seit 0.22.0 neben der Zielquote des Planers (Befund M26), und die weitergehende Verrechnung ist in `entscheidung-reifegrad.md` begründet abgelehnt. Der Fall „sicher und falsch“ ist auf drei Wegen abgedeckt — selbsttätig aufgeklappte Erklärungstafel nur bei Fehlern, eigener Vorlese-Schalter dafür, Wiedereinreihung in derselben Sitzung und Verlust des Reife-Belegs. - **Die Kopie beim Öffnen kostet nichts.** Gerufen wird dieselbe, über `istFaellig` gedrosselte Funktion; ist die letzte Kopie jünger als eine Woche, kehrt sie ohne Schreiben um. Es entsteht keine zweite Kopie je Lauf, sondern dieselbe eine — nur früher. - **Ein Merker verhindert, dass sie hundertfach erwogen wird:** `lernstand()` läuft bei jedem IPC-Kanal. - **Drei Wachen lesen wieder den Quelltext von `ipc.ts`** — für die IPC-Schicht gibt es keinen Prüfstand. Gegengeprobt: Ohne den Aufruf wird die Zusicherung rot. - **Der Begründungsschritt vor der Auflösung wird nicht gebaut** — nach einer Recherche, die eigens dafür gemacht wurde. Die Quellenlage trägt ihn für diese Anwendung nicht; die Begründung steht in `docs/entscheidung-selbsterklaerung.md`. - **Die Liste der Entscheidungsnotizen sagte „elf“ und meinte zwölf** — `handbuchbilder` fehlte darin. Berichtigt, und mit der neuen sind es dreizehn. - **Vier Felder reisen ausdrücklich nicht mit** — `profilId`, `fenster`, `letzteSicherung` und `zuschnittGefragt`. Die Auswahl gilt beim Schreiben **und** beim Lesen: Eine von Hand veränderte Sicherungsdatei brächte sonst eine Profilnummer des fremden Rechners mit. - **Ein Signal statt dreier durchgereichter Rückrufe.** Drei Hooks lesen die Einstellungsdatei getrennt; nach dem Einspielen müssen alle drei neu lesen. `einstellungssignal.ts` steht neben ihnen statt zwischen ihnen. - **Gelesen wird die Form, nicht der Wert.** Gereinigt wird weiter allein in `einstellungenBereinigen` — eine zweite Prüfung wären zwei Wahrheiten darüber, was gilt. Der Rückgabetyp benennt nur die erlaubten Schlüssel; festgehalten, damit ihn niemand für eine Zusicherung hält. - **Die Datenschutzerklärung steht auf Fassung 1.6** (Abschnitt 4.3 nennt jetzt die mitreisenden Einstellungen und die vier Felder, die bleiben). **Sie ist mit der Veröffentlichung erneut hochzuladen** — Abschnitt 12 sagt zu, unter der Adresse stehe die jeweils geltende Fassung. - **Die Themengruppen hängen nicht an einer Reihenfolge.** Der erste Entwurf paarte Reifezeilen und Kennungen über den Index; eine Gegenprobe mit absichtlich verschobenem Index blieb grün — die Wache trug nicht. Statt sie zu verschärfen ist die Kopplung weg: `reifefragenMitKennung` führt die Kennung neben der Zeile. Dieselbe Gegenprobe färbt jetzt vier von fünf Zusicherungen rot. - **Der Verlauf wird nachgerechnet, nicht mitgeschrieben.** Eine Schnappschusstabelle finge beim Einbau an und wäre für jeden bestehenden Lernstand leer. `shared/reifeverlauf.ts` spielt stattdessen `antwort_log` durch — mit denselben Bausteinen wie der laufende Lernstand. Die Wache dazu ist die einzige, auf die es ankommt: Der letzte Punkt **muss** die Zahl der Ampel sein. Gegengeprobt — eine verdrehte Belegregel färbt sie rot. - **`FSRS_GRAD` ist nach `shared/fsrs.ts` gewandert.** Zweimal dieselbe Zuordnung wären zwei Wahrheiten gewesen, an denen Verlauf und Ampel auseinanderlaufen, ohne dass es jemand merkt. - **Zwei Namenskollisionen abgewendet.** `verlauf__tabelle` und `verlauf__rahmen` trägt seit 0.20.0 die Liste früherer Simulationen; die neue Anzeige heißt deshalb `reifeverlauf__*`. - **Kein Scrollkasten um die neuen Tabellen.** Der erste Entwurf hatte einen, und axe hat ihn zu Recht abgelehnt: In einer Tabelle steht nichts Fokussierbares, der Kasten wäre nur mit der Maus erreichbar gewesen. Die Tabellen brechen jetzt um — was 1.4.10 ohnehin verlangt. - **Der Lastausgleich ist eine Verfeinerung der Streuung, keine Ablösung.** Er nimmt genau ihr Fenster (höchstens 15 Prozent, gedeckelt auf sieben Tage, erst ab drei Tagen Intervall) und wählt darin den leersten Tag; bei Gleichstand entscheidet weiterhin der gestreute Wert. Bei leerem Kalender kommt deshalb Zahl für Zahl dasselbe heraus wie bisher — das ist zugesichert und gegengeprobt. - **Die erste Wache dazu trug nicht.** Sie legte den Berg sechs Tage hinter das Fenster und blieb ohne die Behebung grün. Jetzt misst sie zweimal: einmal mit leerem Kalender, dann mit einem Berg auf genau dem so ermittelten Tag. Ohne die Behebung: „expected 116 not to be 116“. - **Die Gesetzesansicht ist die elfte Ansicht** — die Zusagen, die eine Zahl nannten (`App.tsx`, `menue.ts`), sind nachgezogen; ebenso die gemessenen Tabulatorhalte des Startbildschirms (12 statt 11 bis zum Sprungziel, 26 statt 24 ohne Leiste). - **Die Suche über die Normen steht in `shared/gesetzesuche.ts`**, nicht in der Ansicht: Was gefunden wird und in welcher Reihenfolge, ist eine Aussage über den Inhalt und wird gegen die echte `content/normtexte.json` geprüft. - **Sechs Paragrafen der 1. SprengV tragen keine Überschrift** — nachgesehen im amtlichen XML. Die Anzeige zeigt dann die Bezeichnung allein, und die Wache zählt die sechs namentlich auf, damit eine siebte auffällt. - **Die neue Ansicht steht in beiden E2E-Prüfungen je Ansicht** (axe in drei Farbschemata, Überschriftenhierarchie). - **Der Gesetzesstand ist nachgesehen, nicht angenommen.** Drei Abzüge gegen gesetze-im-internet.de gehalten, darunter der älteste (Beschussgesetz, aus dem Jahr 2020) und der meistzitierte: alle drei Standangaben Wort für Wort identisch mit dem, was im Paket liegt. Kein Neuladen nötig. - **Die Nummer ist 0.27.0 und nicht 0.26.8.** Sechs neue Merkmale sind keine Fehlerbehebung; die Regel dazu steht in `docs/veroeffentlichen.md` und galt auch, als ich zuerst die kleinere Nummer vorgeschlagen hatte. - Zahlen: **1843 Vitest-Tests in 79 Dateien** (vorher 1778), 50 axe-Prüfungen über 16 Zustände in drei Farbschemata (vorher 47 über 15). ## [0.26.7] — 2026-09-01 Der letzte offene Befund der Stand-der-Technik-Runde, der sich bauen ließ. ### Für die Öffentlichkeit - **Ein Knopf führt jetzt zu den selbsttätigen Sicherheitskopien.** Bisher erzählte die Karte von ihnen, ohne dass ein Weg hinführte — wer eine Kopie im Ernstfall brauchte, musste den Pfad kennen. „Ordner der Sicherheitskopien öffnen“ steht unter „Lernstand sichern und übertragen“. ### Behoben - **Der Weg zu den Sicherheitskopien fehlte vollständig.** Kein Kanal listete den Ordner, kein Dateidialog zeigte hin, und der Ordnername kam in der ganzen Oberfläche nicht vor. Gibt es den Ordner noch nicht — er entsteht mit der ersten Kopie —, sagt die Karte das, statt so zu tun, als sei etwas geschehen. ### Für die Werkbank - **Der neue Kanal `sicherung:ordner-zeigen` nimmt kein Argument.** Welcher Ordner gemeint ist, entscheidet der Hauptprozess. Ein Kanal, der einen Pfad entgegennähme, wäre ein Weg, beliebige Ordner des Rechners zu öffnen — und der Renderer hat in diesem Projekt keinen Node-Zugriff, gerade damit es solche Wege nicht gibt. - **`ordnerZeigen` ist das Gegenstück zu `dateiZeigen`.** Jenes nimmt ausschließlich eine Kennung entgegen, weil aus dem Renderer nie ein Pfad kommen darf; dieses nimmt einen Pfad, weil er aus dem Hauptprozess selbst stammt. Der Unterschied steht an beiden Funktionen. - **Der volle Weg nach Hausregel:** Eintrag in `IpcVertrag` und `IPC_KANAELE`, Handler über `behandeln()`, Methode in `LernAppBridge` und im Preload-Skript. - **Drei Wachen, gegengeprobt:** der geöffnete Ordner, der noch nicht vorhandene, und der fehlende Kanal. Ohne den Knopf sind alle drei rot. - Zahlen: **1778 Vitest-Tests in 77 Dateien** (vorher 1775). ## [0.26.6] — 2026-09-01 Die Befundliste der Stand-der-Technik-Runde wird abgearbeitet. Dreizehn Befunde sind am Quelltext gegengeprüft worden, mit dem ausdrücklichen Auftrag, sie zu **widerlegen** — **vier davon fielen dabei**. Gebaut ist, was standgehalten hat. ### Für die Öffentlichkeit - **Wie viele Fragen eine Lernsitzung umfasst, lässt sich jetzt einstellen** — fünf bis fünfzig statt der festen zwanzig. Eine beendete kurze Sitzung ist mehr wert als eine liegengelassene lange. - **Haben Sie viel nachzuholen, kommt zuerst, was Sie am ehesten vergessen haben.** Bisher entschied der Zufall, welche der fälligen Fragen in eine Sitzung kamen. - **Gleich bewertete Fragen desselben Tages bekommen nicht mehr denselben Termin.** Die Wiederholungen verteilen sich, statt sich zu Bergen zu türmen. - **Fragen aus einem Bereich mit besonderer Fehlergrenze kommen häufiger.** In Notwehr und Notstand lassen manche Prüfungsstellen nur wenige Fehler zu; die Wiederholung berücksichtigt das jetzt so wie die Reifeanzeige. - **Die Restzeit lässt sich in der Simulation ansagen** — auf die Sekunde genau, ohne dass die Anzeige unruhig wird. - **Auch im Prüfungsbogen lässt sich eine Frage merken.** Für den Fall, den die Auswertung nicht kennt: geraten und richtig getroffen. - **Vor „Neu anfangen“ und vor dem Löschen eines Profils entsteht eine Sicherheitskopie**, und die Sicherungskarte sagt jetzt, wo die selbsttätigen Kopien liegen. ### Behoben - **Der Gesetzesabzug sagt jetzt, wann er gezogen wurde.** `content/gesetze/index.json` führte die amtliche Standangabe jedes Gesetzes, aber nirgends stand, wann jemand zuletzt nachgesehen hat, ob es dabei geblieben ist. Zwischen dem ältesten Abzug (Beschussgesetz, 09.09.2020) und dem jüngsten (Sprengstoffgesetz, 23.07.2026) liegen fast **sechs Jahre**; alle 1854 Fundstellen werden gegen genau diesen Bestand geprüft. `docs/veroeffentlichen.md` hat dafür jetzt einen Schritt, vier Wachen halten ihn fest. - **Der Planer kennt jetzt die K.-o.-Bereiche.** Die Reifeampel deckelt ihr Gesamturteil seit 0.22.0 am schwächsten Bereich mit K.-o.-Kriterium — wer insgesamt gut dasteht und in Notwehr zurückliegt, bekommt kein „Prüfungsreif“. Die Wiedervorlage wusste davon nichts und terminierte die **43** Fragen aus I.5 wie jede andere. Sie hält dort jetzt eine Zielquote von mindestens 0,95. - **Bei Rückstand entscheidet nicht mehr das Los.** Standen 100 Fragen fällig und die Sitzung fasste 20, wurde die fällige Gruppe gemischt und abgeschnitten. Vorgelegt wird jetzt zuerst, was am wahrscheinlichsten schon vergessen ist. ### Für die Werkbank - **Vier Befunde sind widerlegt worden**, jeder mit Belegstelle: die behauptete Uneinigkeit zwischen Fälligkeit (24-Stunden-Blöcke) und Vorschau (Kalendertage) ist die **Behebung** von Befund H5 und kein Versehen; `setAccessibilitySupportEnabled` fehlt, aber die Anwendung **liest** den Zustand über `system:hilfsmittel` und richtet die Zeichenkürzel danach aus; das Anhalten der Simulation ist über das Schließen des Fensters samt Rückfrage, stehender Uhr und Wiederaufnahme gebaut; und eine bestätigte Auswahlantwort lässt sich sehr wohl zurücknehmen, solange die Buchung aussteht. - **Warum 0,95 und nicht 0,97 für die K.-o.-Bereiche.** Nachgerechnet mit den Parametern dieses Projekts: Bei einer Stabilität von 60 Tagen ergibt 0,90 ein Intervall von **62** Tagen, 0,95 eines von **25**, 0,97 eines von 13. Die Terminquote dauerhaft anzulegen hieße, diese Fragen viereinhalbmal so oft vorzulegen — auch ein Jahr vor der Prüfung. Sobald der Termin naht, steigt die allgemeine Quote ohnehin darüber. - **Sortiert wird nach Abrufwahrscheinlichkeit, nicht nach Überfälligkeit.** Eine Frage mit kleiner Stabilität ist nach einem Tag schon weg, eine gefestigte nach dreißig noch da; die Überfälligkeit allein misst das Falsche. `abrufwahrscheinlichkeit` war bereits gebaut. - **Eine Wache bestand ihre Gegenprobe zunächst nicht.** Der erste Entwurf war auch ohne die Behebung grün: Fisher-Yates mit einer Zufallsquelle, die stets 0 liefert, **kehrt ein Zweierfeld um** — und sortierte die schwache Frage zufällig richtig ein. Mit 0,99 bleibt die Katalogfolge stehen, und die alte Fassung fällt nachweislich durch. Ohne die Gegenprobe wäre eine wertlose Zusicherung eingezogen. - **Bewusst keine Altersprüfung des Gesetzesabzugs.** Ein Test, der allein durch Zeitablauf rot wird, meldet an seinem Tag keinen Befund, sondern eine Störung — dieselbe Bauart, die in `selbstsicherung.test.ts` heute früh zugeschlagen hat. Geprüft wird, dass die Angabe **da** ist; hinsehen muss die Veröffentlichungsliste. - **Die Streuung stammt aus der Frage-Kennung, nicht aus einer Zufallsquelle.** Der erste Entwurf nahm `this.zufall` des Lernstands und fiel sofort auf: Zwei fremde Zusicherungen wurden dadurch **zufällig**, eine davon ohne jede Berührung. Ein Verfahren, das reproduzierbare Zahlen liefert, darf nicht an einer Quelle hängen, die es nicht kennt. - **Die Streuung wirkt in die Rechnung zurück** — wie bei Anki: Der tatsächliche Abstand ist der gestreute, und er geht in den nächsten Gedächtnisstand ein. Vier Zusicherungen in `lernstand.test.ts` messen deshalb andere Zahlen als vorher; sie messen den **Termin**. Das reine Verfahren bleibt gepinnt, wo es hingehört: `fsrs.test.ts` gegen py-fsrs und `lernplan.test.ts` an `wiedervorlageBerechnen`, beide unverändert grün. - **Höchstens 15 Prozent, gedeckelt auf sieben Tage, erst ab drei Tagen.** Darunter wäre ein Tag Versatz keine Streuung mehr, sondern eine andere Antwort: Bei Intervall 1 hieße „ein Tag früher“ noch heute. - **Die Kopie vor dem Verwerfen unterscheidet sich in drei Punkten von der Wochenkopie:** Sie ist **ungedrosselt** (die Wochenkopie schweigt, wenn die letzte noch frisch ist – genau das wäre hier der Ausfall), sie führt einen **eigenen Vorsatz und ein eigenes Kontingent** (sonst räumten die Wege sich gegenseitig ab), und sie **wirft**. Beim Beenden ist die Kopie eine Zugabe; vor einem Schritt, der Daten vernichtet, ist sie die Bedingung. - **Auch die Verdrahtung ist bewacht.** Für die IPC-Schicht gibt es in diesem Projekt keinen Prüfstand; drei Zusicherungen lesen deshalb den Quelltext – wie `sicherheit.test.ts` es mit dem Sicherheitsmodell tut – und prüfen, dass der Aufruf **vor** dem zerstörenden Schritt steht und dass sein Fehlschlag **nicht** abgefangen wird. Gegengeprobt: Ohne den Aufruf wird die Zusicherung rot. - **Der Merkknopf im Bogen holt seinen Zustand nach.** Anders als `SitzungsFrage` bringt `Pruefungsfrage` ihn nicht mit: Der Bogen entsteht im Renderer aus dem Katalog (`bogenAusKatalog`) und kennt den Lernstand nicht. Geholt wird er über `lernen:fragestand`, sobald die Frage erscheint — einmal je Frage, gemerkt in einem `useRef` und nicht im Zustand, weil das Bild sich davon nicht ändert und `setState` im Effekt die Projektregel verletzte. - **Die Ansage hängt an ihrer Frage**, nicht an einem Zeitgeber: `ansage` wird in diesem Haken abgeleitet und nicht gesetzt, und ein „Frage gemerkt“, das beim Blättern stehen bliebe, wäre eine Falschaussage. - **Misslingt das Speichern, verschwindet das Merkzeichen wieder.** Eines, das nach dem Lauf fehlt, wäre schlimmer als eines, das gar nicht erst erscheint. - **Die Restzeit wird auf die Sekunde genau angesagt, die Anzeige bleibt bei Minuten.** Zwei Fragen innerhalb derselben Minute müssen zwei verschiedene Sätze ergeben – in einer Live-Region, in der zweimal dasselbe steht, meldet sich beim zweiten Mal nichts, und der Knopf wirkte kaputt. Dafür gibt es `restzeitGenau` neben `restzeitText`. - **Die zweite Live-Region erscheint erst, wenn etwas darin steht.** Sonst fanden zwei bestehende Zusicherungen zwei Knoten mit `role="status"` – ein Fund der Wachen, kein Zufall. - **Der Sitzungsumfang wird im Hauptprozess geprüft, nicht in der Oberfläche.** `main/einstellungen.ts` nimmt 1 bis 1000 an, dieselbe Spanne wie `Lernstand.sitzung`; ein von Hand verstellter Wert in der Datei schlägt damit nicht durch, und eine Einstellung, die der Kern danach zurückwiese, wäre eine Falle. - **Nicht gebaut: ein Knopf, der den Sicherungsordner öffnet.** Der Kanal `system:datei-zeigen` könnte es, verlangt aber eine Kennung aus `main/dateizugriff.ts` – und der Weg, sie in die Oberfläche zu bekommen, wäre ein neuer IPC-Kanal. Die Gegenprüfung hatte hier ausdrücklich den kleinen Eingriff empfohlen; er ist gemacht, der große bleibt offen. - Zahlen: **1775 Vitest-Tests in 77 Dateien** (vorher 1746). ### Offen aus derselben Liste Ein bestätigter Befund ist noch nicht gebaut: Vor „Neu anfangen“ und vor dem Löschen eines Profils entsteht keine Sicherheitskopie, obwohl beide Einspielwege selbstverständlich eine anlegen. Dazu fünf Befunde, die die Gegenprüfung als **teilweise** zutreffend einstuft. ## [0.26.5] — 2026-09-01 Der angekündigte Durchgang über die Antwortkommentare — mit einem anderen Ergebnis als erwartet. Der Befund, der ihn ausgelöst hat, war ein Messfehler. ### Für die Öffentlichkeit - **Zwei Erklärungen sagen jetzt auch, warum die übrige Antwortmöglichkeit nicht stimmt.** Bei der Geltungsdauer eines Voreintrags und beim Mindestalter für Sportschützen stand bisher nur, was gilt — nicht, woran die naheliegende Verwechslung scheitert. ### Behoben - **Der Befund „224 von 471 Erklärungen benennen keine einzige Antwortmöglichkeit“ war falsch.** Er zählte allein die Schreibweise „a)“. Der Hausstil kennt aber mehrere: „Antwort b“, „Zu c“, „Buchstabe d“ — und vor allem den Weg über den Gegenstand statt über den Buchstaben („die Armbrust scheitert am Lauf“). - **Zwei Erklärungen ergänzt**, bei denen eine Möglichkeit tatsächlich unbehandelt blieb: I.1-74 („6 Monate“ — das Gesetz nennt diese Frist an keiner Stelle, § 10 Abs. 1 Satz 3 kennt nur das Jahr) und I.2-23 („durch ein fachärztliches Gutachten“ — das gehört nach § 6 Abs. 2 zur persönlichen Eignung, und das Mindestalter des § 14 Abs. 1 ist keine Eignungsfrage). ### Für die Werkbank - **Die Messkette, Schritt für Schritt:** 224 → 220 (eigene Nachzählung der Buchstabenform) → 111 (Optionen, die auch dem Gegenstand nach fehlen) → 33 (mit Buchstabenformen des Hausstils) → 8 (mit Wortstamm statt Wortgleichheit) → **0** (von Hand nachgesehen: alle acht waren angesprochen, unter anderem mit „Keine.“, „Nein.“, „Zulässig“ und „über Bord geworfen“). Übrig blieben nach der geschärften Prüfung genau **zwei** echte Fälle. - **Jede Zwischenstufe war ein Fehler in meiner Messung, nicht im Bestand.** „WBK“ gegen „Waffenbesitzkarte“, „Leuchtpunktvisiere“ gegen „Leuchtpunktvisier“, „Armbrust“ gegen „Armbrüste“, „Monats“ gegen „Monat“, „werfen“ gegen „geworfen“. Wer eine Textmenge mit Wortgleichheit misst, misst die eigene Wortliste. - **Neue Prüfung `optionen_pruefen` in `pruefe_erklaerungen.py`.** Sie verlangt, dass jede Antwortmöglichkeit vorkommt — mit ihrem Buchstaben **oder** mit ihrem Gegenstand. Umlaute werden gefaltet, Wortstämme statt Wortgleichheit verglichen, und eine Möglichkeit, die aus nichts als „Nein“ besteht, gilt als behandelt, sobald die Kurzfassung ein Urteil spricht: Sie ist die Verneinung der ganzen Frage, und ein Satz „Antwort c ist falsch“ brächte dort nichts, was nicht schon dastünde. - **Gegengeprobt in beide Richtungen:** Mit den zwei Ergänzungen meldet die Prüfung nichts; wird eine davon wieder herausgenommen, meldet sie genau diese Möglichkeit. 1854 Fundstellen, alle nachgewiesen. - **Warum der Weg über den Gegenstand der bessere ist.** Wer sich die Erklärung vorlesen lässt, hört bei „zu a)“ nichts, woran er sich erinnern könnte — der Buchstabe steht auf dem Bildschirm, nicht im Ohr. 341 der 471 Erklärungen gehen deshalb über die Sache. Eine Umstellung auf Buchstaben wäre eine Verschlechterung gewesen. - **`docs/stand.md` trug die falsche Zahl seit 0.26.4** und ist berichtigt. - Zahlen: **1742 Vitest-Tests in 77 Dateien**, 1854 Fundstellen (vorher 1853), ESLint ohne Warnung. ## [0.26.4] — 2026-09-01 Die ersten Befunde aus der Prüfung, ob diese Software dem Stand der Technik entspricht. Acht Felder wurden gegen die heutige Fachliteratur und den Wettbewerb gehalten; hier stehen der eine echte Defekt und die drei Lücken mit dem besten Verhältnis von Nutzen zu Aufwand. ### Für die Öffentlichkeit - **Ein abgewähltes Kapitel bleibt auch auf dem zweiten Rechner abgewählt.** Wer seinen Lernstand auf ein anderes Gerät überträgt, bekam dort bisher stillschweigend alle Kapitel zurück — auch die, die er für seine Prüfung gar nicht braucht. Die Prüfungsreife-Anzeige fiel dadurch um zwei Stufen, ohne dass etwas darauf hinwies. - **Der Vergleich zweier Simulationen sagt jetzt, wann ein Unterschied nichts bedeutet.** Ein Bogen zieht seine Fragen aus dem gesamten Bestand; zwei Läufe fallen deshalb schon durch die Ziehung auseinander, auch wenn sich am Wissen nichts geändert hat. Liegt der Unterschied darunter, steht das jetzt dabei — mit der Zahl der Fragen, um die es tatsächlich geht. - **Das Handbuch erklärt, wie man eine frei zu formulierende Antwort aufbaut.** 104 der 575 Fragen verlangen eine eigene Antwort, und sie werden von Menschen bewertet. Woran man erkennt, was verlangt ist, steht jetzt im Kapitel zur Lernsitzung. - **Und es sagt, dass ein Nachteilsausgleich beantragt werden muss.** Die Anwendung bietet die verlängerte Zeit zum Üben an. In der Prüfung ist sie kein Selbstläufer: Wer sie braucht, muss sie bei der Stelle beantragen, die seine Prüfung abnimmt. Das Kapitel zur Simulation sagt jetzt, wen man fragt und wonach. ### Behoben - **Die Kapitelabwahl reiste beim Übernehmen eines Profils nicht mit.** `profil-uebernehmen.ts` las aus der Quelle nur `name` und `pruefungstermin`; `kapitel_ausschluss` steht als Spalte am Profil und nicht in einer Kindtabelle, wurde von der Schleife über `KINDTABELLEN` also nicht erfasst und fiel auf den Vorgabewert `'[]'` zurück. Die Folge ist in `shared/verlust.ts` seit jeher ausgerechnet: derselbe Bestand von **85,0 auf 71,9 Prozent**, zwei Ampelstufen. Kein Test sah hin. - **Der Laufvergleich meldete Rauschen als Fortschritt.** „5 Prozentpunkte besser“ sind bei einem Bogen von 80 Fragen vier Fragen — weniger, als zwei Ziehungen aus demselben Bestand ohnehin auseinanderliegen. ### Für die Werkbank - **Der Defekt saß im Weg, den das Handbuch selbst empfiehlt.** Zwei Geräte über die Sicherungsdatei zu verbinden ist die dokumentierte Lösung; genau dort ging die Abwahl verloren. Die neue Wache setzt in der Quelle `kapitel_ausschluss = '["IV"]'` und prüft es am Ziel nach. - **Die Abfrage greift nur, wenn die Quelle die Spalte kennt.** Eine Sicherung von vor 0.20.0 hat sie nicht; dort ist „nichts abgewählt“ die richtige Annahme. Der vorhandene Test über ältere Quellen bleibt grün. - **Warum die binomiale Streuung hier trägt, obwohl der Reifegrad sie ausschlägt.** `entscheidung-reifegrad.md` Abschnitt 5 lehnt eine Bestehenswahrscheinlichkeit ab, weil die Trefferchancen je Frage zweigipflig verteilt sind. Das trifft eine **Prognose**. Beim bereits gezogenen Bogen hebt sich die Zweigipfligkeit auf: Eine zufällig gezogene Frage zu beantworten ist selbst ein Bernoulli-Versuch mit der mittleren Trefferchance. Mit **200 000 Läufen** gegen die in der Notiz beschriebene Verteilung nachgerechnet — bei 85, 70 und 50 Prozent gefestigter Fragen lag die gemessene Streuung jedes Mal **unter** der binomialen (11,63 zu 12,51 · 15,36 zu 16,87 · 16,97 zu 18,73). Die Endlichkeitskorrektur bliebe zusätzlich draußen. Die Schätzung ist also die vorsichtige Seite. - **Ein bestehender Test musste seine Erwartung ändern, und das ist der Befund.** `verlaufsvergleich.test.ts` prüfte mit `toEqual([])`, dass es keine Vorbehalte gibt — an Werten, die selbst ein Rauschfall sind: 80 Fragen, 75 gegen 80 Prozent. Die Zusicherung war zu weit gefasst; sie prüft jetzt, was ihr Name verspricht. - **Die Zahlen im Handbuch sind an den Katalog gebunden.** `tests/hilfe-zahlen.test.ts` zählt die 104 offenen Fragen und ihre Anfangswörter (26 „Was“, 25 „Welche“, 7 „Wie“, je 5 „Wann“ und „Nennen Sie“) bei jedem Lauf nach und liest die Zahlen aus dem Handbuchtext selbst, nicht aus einer zweiten Liste daneben. Gegengeprobt: eine verstellte Ziffer macht ihn rot. - **Der Entwurf zum Handbuch war zuerst falsch.** Er nannte „Erläutern Sie …“ als Beispiel einer Fragestellung — nachgezählt kommt das Wort im ganzen Katalog nicht vor. Und die Regel „zählen Sie, wie viele Punkte gefragt sind“ galt nur für **5 von 104** Fragen. Beides steht jetzt so da, wie es gemessen ist. - **Nachteilsausgleich: nachgeschlagen statt behauptet.** `data-pipeline/gesetz.py --suche` findet das Wort in keinem der beigelegten Gesetze. Genannt sind deshalb nur belegte Stellen: § 2 Absatz 1 AWaffV (die zuständige Behörde bildet die Prüfungsausschüsse), § 3 Absatz 5 (schießsportliche Vereine dürfen für ihre Mitglieder prüfen), § 2 Absatz 3 (theoretischer **und** praktischer Teil) und § 2 Absatz 5 (Wiederholung, Frist möglich). - Zahlen: **1742 Vitest-Tests in 77 Dateien** (vorher 1734), ESLint ohne Warnung. --- Fruehere Fassungen sind in dieser Ausgabe nicht einzeln aufgefuehrt. Die Entwicklung bis zum 31.08.2026 ist im Ausgangs-Commit dieses Archivs zusammengefasst.