refactor(snapshots): Regeln nach snapshots.js, 28 Tests

D54-Nachtrag 2 endete mit „nicht durch Tests gedeckt ... das ist der Preis
dafür, dass die Zustandslogik im UI-Modul sitzt". Der Preis war zu hoch: Der
Fehler kam bis in Produktion, und ein Test hätte ihn in einer Zeile
gefunden.

Geschnitten nach dem Vorbild von remote.js (D31) — die entscheidbare Hälfte
heraus, die I/O bleibt:
- snapshots.js: addSnapshot (wann entsteht ein Stand), dropOldestSnap /
  persistSnaps (was fliegt bei Platzmangel), parseSnaps (was darf gelesen
  werden), snapLabel. Speicher als {setItem, removeItem} und Uhr als Zahl
  hereingereicht — genau die Abhängigkeiten, an denen die Prüfbarkeit
  vorher scheiterte.
- app.js: -63/+14 Zeilen, snapshotNow() schrumpft auf sechs.

Die Gegenprobe zählt, nicht die Zahl der Tests: Baut man exakt den
ausgelieferten Fehler wieder ein (`manual ? null : base` -> `base`), fällt
GENAU die eine Zusicherung, die nach ihm benannt ist; die übrigen 27 bleiben
grün.

Zwei bewusste Verhaltensänderungen: parseSnaps wirft formfremde Einträge weg
(Liste kein Array, t keine Zahl, text kein String), und ein Array im
Speicher ergibt {} statt eines halb benutzbaren Zustands.

Verdrahtung bleibt Browser-Sache und wurde nachgemessen: Knopf ohne Eingabe
-> 1 Stand; Takt (2 s) bei bloß angesehenem Dokument -> 0, nach Änderung
-> 1, weitere Takte -> 1.

D54-Nachtrag 3 + Faustregel in frontend/CLAUDE.md. 271 Tests grün (243+28).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-24 11:37:09 +02:00
co-authored by Claude Opus 5
parent 324ba8a806
commit e937e1bbbb
5 changed files with 383 additions and 63 deletions
+10
View File
@@ -66,6 +66,16 @@ verworfene Elemente. Quelle sind ES-Module unter `src/`; `index.html` ist der
`app.js` (DOM/Events/i18n/Persistenz/Export). Modell/Renderer bekommen UI-State
(verworfene einblenden, Pfad an/aus) als **Parameter** — keine Globals; nur
`cheapPathOn` lebt als UI-State in `app.js`. Tests: `tests/*.test.js`.
- **Was entscheidbar ist, gehört in ein eigenes Modul** — auch bei Features, die
wie reine UI aussehen: `remote.js` (Pad-URLs normalisieren, D31),
`warnings.js` (Warnung → Text), `snapshots.js` (frühere Stände: wann entsteht
ein Stand, was fliegt bei Platzmangel raus, wie sieht der Speicherinhalt aus).
Dort steht **was gilt**, in `app.js` bleibt **woher die Werte kommen und wohin
sie gehen**; Speicher (`{setItem, removeItem}`) und Uhr (`Date.now()`) werden
hereingereicht, damit der Test sie stellen kann. Anlass war ein Fehler, der bis
in Produktion kam und den ein Test in einer Zeile gefunden hätte
(D54-Nachtrag 3). Faustregel: Sobald du eine Regel im Browser „nachmisst",
gehört sie in ein Modul.
- Günstigster Pfad: `computeCheapPlan()`/`cheapestCost()`/`cheapCls()` (in
`model.js`) markieren
die nötigen Knoten (Klassen `cheap`, `cheap-leaf`); `drawCheapPath()` (app.js)