26 Commits
Author SHA1 Message Date
mhoennigandClaude Fable 5 ecc1b632f6 feat: von Station zu Station des günstigsten Pfads (D47)
Mit dem status-bewussten Pfad (D46) zeigt das Diagramm die offene Front — im
mitgelieferten Plan 24 Stationen, verteilt über einen Baum von über 20 000 px
Breite. Sie zu sehen war damit gelöst, sie abzugehen nicht. Der neue Knopf im
Diagramm-Kopf holt sie der Reihe nach in die Mitte: erster Druck die erste
(was als Nächstes dran ist), jeder weitere die nächste, nach der letzten
wieder die erste.

Der Sprung fasst nur das Diagramm an — zentrieren, hervorheben, Tastaturfokus,
also buchstäblich die Behandlung des ausdrücklichen Alt+Klicks (D25) samt Puls
und hervorgehobenen Abhängigkeits-Kanten. In den Text führt von dort
Alt+Enter, dieselbe Geste wie überall.

Ohne eigenen Zustand: Fortgesetzt wird am gerade hervorgehobenen Knoten. Ein
gemerkter Index wäre schlechter — der Baum wird bei jedem Tastendruck neu
gebaut, die Stationsliste ändert sich unter ihm. Verborgen, solange es keine
Station gibt (Pfad aus, oder alles erledigt); der Tooltip nennt die Anzahl.
i18n `leanNextTooltip` in neun Sprachen.

Die Mobil-Kopfzeile trug den neunten Knopf nicht mehr — D17-Nachtrag 5 hatte
sie gerade erst auf acht zurechtgemessen. Nachgemessen: bei 375 px reicht es
nach Lücke 8->6 px und Innenabstand 10->8 px weiterhin (345 px Inhalt, 359 px
Platz, 14 px Luft); bei 320 px passen neun Fingerziele arithmetisch nicht, und
unter 29 px zu gehen hat D17-Nachtrag 5 abgelehnt. Die Zeile schiebt dort
deshalb (`overflow-x:auto`, Balken ausgeblendet) — 41 px Schiebeweg, Kopfhöhe
unverändert 49 px, alle neun Elemente in voller Größe erreichbar.

Dabei ein älterer, stiller Fehler gefunden: Bei Platzmangel schrumpfte der
Modus-Wähler — das einzige Element ohne feste Größe — auf einen 2-px-Strich
zusammen, während sein Icon 38 px breit darüber hinausragte; er sah aus wie
ein Trennstrich und war unbenutzbar. `flex:0 0 auto` an allen Kindern der
Zeile stellt das ab.

236 Tests grün. SPEC §9 und D47 halten es fest; der Plan bekommt den Knoten
als `[x]` (noch nicht deployt), frontend/CLAUDE.md die Kopfzeilen-Stolperfalle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 13:22:52 +02:00
mhoennigandClaude Fable 5 c793bf0038 feat: der günstigste Pfad zeigt die offene Front (D46)
Der Pfad rechnete rein aus T-Shirt-Größen — `ownCost()` war
`SIZE_RANK[size] + 1`, der Status kam in der Kostenrechnung überhaupt nicht
vor (nur `[-]` flog heraus). Folge: Längst Erledigtes wurde voll eingepreist
und lag weiter hell auf dem Pfad; im mitgelieferten Werkbaum-Plan zeichnete
die Linie damit überwiegend fertige Arbeit nach. Und in einer Alternativgruppe
hatte eine bereits realisierte Alternative keinerlei Kostenvorteil — der Pfad
empfahl die nominell billigere, obwohl die Wahl längst getroffen und bezahlt
ist.

Ab jetzt kostet Erledigtes 0. Der Pfad beantwortet damit „was ist als
Nächstes am günstigsten?" statt „was hätte der Plan von vorn gekostet?".

- Schwelle bei `[x]` fertig: die Beförderung auf `[^]` ist keine Kostenfrage
  (das tut per D30 ein eigener Commit).
- Angefangenes (`[~]`, `[/]`) zählt weiter voll — Bruchteile ordinaler Größen
  wären erfunden, und `[~]` heißt laut §4 gerade „Risiko hoch".
- Maßgeblich ist der intrinsische Status: investiert ist investiert, auch wenn
  Abhängigkeiten den Knoten effektiv zurückhalten (D39). Verhindert nebenbei
  doppeltes Zählen — die Abhängigkeit steht mit eigenen Kosten selbst da.
- Abgezogen werden nur die eigenen Kosten, nicht der Teilbaum.

Darstellung: Erledigte bleiben `cheap` und behalten ihre volle Statusfarbe
(grün/blau sagt schon „nichts mehr zu tun"), verlieren aber Stationspunkt und
implizites M-Badge — Letzteres macht eine Kostenannahme sichtbar, und an einem
erledigten Knoten wird keine getroffen. Station ist der tiefste noch OFFENE
Knoten eines Zweigs (`hidesOpenCheap()` fragt den Teilbaum statt nur die
direkten Kinder): Sind alle Kinder fertig, wird der offene Elternknoten selbst
die Station. Der eingeklappte Knoten (D38) erbt dieselbe Verschärfung.

Kein neuer Umschalter — der vorhandene ändert seine Bedeutung.

Nachgemessen am Werkbaum-Plan: 110 Knoten auf dem Pfad (unverändert),
Stationen 69 -> 24, und die 24 sind exakt die offene Front (Ticket-Referenzen,
Öffnen/Speichern, Backend-Gerüst samt REST und Persistenz, Websocket-Transport,
Text-CRDT, Mermaid-Layout, IDEA-Plugin). Linie wird weiter gezogen; Export und
Druck folgen ohne Zusatzcode, sie lesen dieselbe `.node.cheap-leaf`.

236 Tests grün, davon 14 neue (tests/frontier.test.js). Der Snapshot des
kanonischen Beispiels ändert sich um genau zwei Knoten.

SPEC §9, llms.md und ROADMAP/TASKS nachgezogen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 12:14:34 +02:00
mhoennigandClaude Fable 5 a918c75286 feat: Günstigster Pfad auf der Dependency Closure — exakt über gekoppelte Gruppen (SPEC §9, D42)
Jeder nötige Knoten zieht seine :#…-Ziele samt Realisierung in die
nötige Menge; gemeinsam Gebrauchtes zählt über die Vereinigung nur
einmal. Verfahren gewählt und benannt (D34): erschöpfende Suche, aber
nur über die GEKOPPELTEN Gruppen (Teilbaum enthält Abhängigkeiten oder
wird gebraucht) — ungekoppelte wählen lokal wie bisher, ohne
Abhängigkeiten bleibt es bei genau einer Auswertung zum alten Preis.
Lexikografischer Odometer, strikt < : bei Gleichstand die erste
Alternative. Oberhalb des Suchlimits (20 000) gierig mit zeilenloser
Warnung cheapApprox statt stillschweigender Pseudo-Optimalität.
Abhängigkeiten ziehen auch optionale und nicht gewählte Ziele (ohne
deren Vorfahren), verworfene nie. Neue API computeCheapPlan {set,exact};
markCheapest entfällt. 8 neue Tests (tests/closure.test.js).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 19:10:42 +02:00
mhoennigandClaude Fable 5 afe536e33c feat: Querverbindungen der Abhängigkeiten — gekrümmt, blassgrau, Pfeil aufs Gebrauchte (SPEC §9, D41)
Eigene Zeichenebene wie der Pfad-Spline (Overlay-SVGs, /zoom): Kanten aus
den neuen data-id/data-deps-Attributen des Renderers, dünn und blassgrau
HINTER den Knoten — das Unterscheidungsmerkmal zu den orthogonalen
Baumlinien ist die Krümmung, keine neue Farbe (die Palette ist vergeben,
Rot bewusst nicht). Pfeilspitze zeigt auf das Gebrauchte, Endpunkte auf
den Knotenkanten. Die Kanten des ausgewählten Knotens (Tastaturfokus,
sonst Cursor-Zeile) liegen hervorgehoben in Tinte auf einer vorderen
Ebene. Kanten zu verborgenen Zielen entfallen; erste ID-Vergabe gewinnt;
Selbst-Abhängigkeiten zeichnen nichts. Basis-Kanten auch im SVG-Export
(Schritt 1a) und im Druck, die Hervorhebung nicht. Browser-geprüft in
allen drei Modi; Renderer-Attribute testgedeckt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 19:05:33 +02:00
mhoennigandClaude Fable 5 a42710b38f feat: Knotenbeschreibungen — "-Zeilen und ----Beschreibungsteil (SPEC §1/§9, D40)
Parser: `"`-Zeilen (Leerraum-Regel, nur ohne Zerlegungszeichen) hängen am
vorangehenden Knoten; hinter einem `---`-Trenner eröffnen #id-Zeilen
Blöcke, deren eingerückte Zeilen der Text sind (Leerzeilen = Absätze,
weitere Trenner bedeutungslos). Freitext ohne §1-Extraktion, nur %% fällt
weiter weg. Warnungen: unknownDesc (ID ohne Knoten, Blocktext wird still
geschluckt) und descStray je verwaister Zeile — ein versehentlicher
Trenner meldet die verschluckten Knotenzeilen zeilengenau. Anzeige im
Tooltip (Text zuerst, mehrzeilig) + aria-label, ”-Marke am Knoten
(nicht im Export — eine Marke ohne Ziel wäre Rauschen). i18n in allen
9 Sprachen; SPEC-§11-Abschnitt in §1/§9 überführt; 16 neue Tests
(tests/desc.test.js).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 19:01:02 +02:00
mhoennigandClaude Fable 5 c4abd24ce8 docs: Knotenbeschreibungen entschieden — "-Zeilen und ----Beschreibungsteil (D34-Nachtrag)
Kurzform (Nutzer-Entscheidung): eine neue Zeile mit `"` unter dem Knoten
— eigenes Zeichen statt Einrückung, weil Einrückung Hierarchie bedeutet;
Leerraum-Regel wie bei =, >/<, damit "Zitat"-Labels unberührt bleiben.
Langform (Nutzer-Entscheidung): hinter einem `---`-Trenner nach
YAML-/Frontmatter-Vorbild eröffnen ID-Zeilen (#auth) Blöcke, deren
eingerückte Zeilen der Text sind — kein Schlusszaun, der vergessen werden
könnte; die Wurzelknoten-Regel endet am Trenner, darum braucht dort keine
Zeile ein Zeichen. Fehlertoleranz: verwaiste/uneingerückte Zeilen im
Beschreibungsteil warnen zeilengenau — ein versehentlicher Trenner macht
sich laut bemerkbar. SPEC §11, TASKS, ROADMAP und Plan nachgezogen; damit
ist die letzte offene Schreibweise der fünf D34-Erweiterungen fest.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 18:33:23 +02:00
mhoennigandClaude Fable 5 15c3e85e26 feat: Effektiver Status — Knotenfarbe zeigt ihn, Diskrepanz-Marke unten links (SPEC §4/§9, D39)
Jeder Status bekommt einen Fortschritts-Rang entlang der Ergebnis-Skala
(D5); effektiv ist das Minimum über die Abhängigkeits-Hülle (Fixpunkt —
Zyklen teilen ihr Minimum, wörtlich das „wird gemeinsam fertig" aus D34).
Neutral und [-] zählen als 0, [!] als 1; bei doppelter ID gilt die erste
Vergabe. Entschieden (Nutzer): Die Knotenfarbe zeigt den effektiven
Status — das Diagramm beantwortet „wie weit ist das wirklich?". Wo der
eigene Status weiter ist, sitzt unten links die eigene Statusbox als
Marke in den eigenen §4-Farben (auch im Export/Druck); Tooltip und
a11yEffective benennen beides. XOR-„realisiert" und „Was ist neu?"
bleiben bewusst intrinsisch. i18n in allen 9 Sprachen; 12 neue Tests
(tests/effective.test.js).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 17:15:04 +02:00
mhoennigandClaude Fable 5 cbe798d746 feat: Faltmarken (>/<) — Teilbäume ein-/ausklappbar (SPEC §1/§9, D38)
Parser liest die Marke zwischen Zeichen und Statusbox (Leerraum-Regel,
`- >Achtung` bleibt Label); den Anfangszustand rechnet initialCollapsed()
in model.js: `>` klappt ein, `<` (und die Fokusmarke !!!) holt seinen
Teilbaum hervor, indem die Faltung die Pfad-Ebenen hinunterwandert —
Geschwister stehen als einzelne eingeklappte Knoten da, jede Kante bleibt
eine echte. Im Diagramm: Falt-Zeichen ▾/„▸ n" vor dem Label (n = alle
verborgenen Knoten), Klick oder ←/→ am fokussierten Knoten klappt um;
Eingriffe je Label-Pfad, nur für die Sitzung, Dokumentwechsel setzt
zurück. Eingeklappte Kinder werden nicht gerendert (Export, Messungen,
Pfadlinie automatisch konsistent), ihre Warnungen aber weiter gemeldet.
Export/Druck: „▸ n" bleibt, das ▾ offener Knoten fällt weg. Legende +
a11y in allen 9 Sprachen; SPEC-§11-Abschnitt in §1/§9 überführt;
15 neue Tests (tests/fold.test.js), Snapshots aktualisiert.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 16:47:34 +02:00
mhoennigandClaude Fable 5 c778e3e267 docs: Faltmarken entschieden — hinter dem Gate, Export folgt der Faltung (D34-Nachtrag)
Stellung: `- > [x] Backend` — die Marke steht hinter dem Zerlegungszeichen,
damit die Gate-Spalte bündig bleibt (an ihr liest das Auge die Hierarchie
ab); `>` am Zeilenanfang wäre zudem die Markdown-Blockquote-Konvention.
Wurzelknoten ohne Zeichen tragen die Marke am Zeilenanfang.

Grafikexport und Druck folgen der sichtbar eingeklappten Struktur (wie der
Verworfene-Filter, SPEC §9); eingeklappte Knoten werden gekennzeichnet,
damit das Bild nicht stillschweigend Vollständigkeit behauptet — anders als
Cursor-Ring/Kranz/Fokusmarke ist die Faltung eine Aussage über das Bild,
nicht über den Betrachter. Genaue Form der Kennzeichnung beim Bauen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 16:26:40 +02:00
mhoennigandClaude Fable 5 3ba37fc5a0 feat: Abhängigkeiten (:#a,#b) parsen — unbekannte ID warnt, Zyklen zulässig (SPEC §1, D37)
Extraktionsschritt 7: alle alleinstehend angesetzten `:#a,#b`-Token —
EIN zusammenhängendes Token ohne Leerraum, mehrere je Zeile werden
zusammengeführt; eingeklammerte Erwähnungen wie `(:#auth,#api)` bleiben
Label (Zitier-Konvention wie `(#auth)`, deshalb enger als die frühere
§11-Formulierung). `deps` sind ID-Strings am Knoten; der Parser prüft
nur Existenz (Warnung unknownDep, Vorwärts-Referenzen normal), Zyklen
werden bewusst nicht einmal erkannt. Sichtbar als `→ #a, #b` im Tooltip
und als a11yDeps; Legendenzeile + Warntext in allen 9 Sprachen. Im
mitgelieferten Plan: Zyklen-legal und unknown-id-Warnung auf [x],
Abhängigkeits-Knoten auf [~]. 12 neue Tests (tests/deps.test.js).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 16:25:09 +02:00
mhoennigandClaude Fable 5 6ecf3e4c69 feat: Knoten-IDs (#auth) parsen — doppelte ID warnt (SPEC §1, D36)
Extraktionsschritt 6 (nach den Tags): das erste alleinstehend angesetzte
`#name`-Token wird die Knoten-ID (Zeichenmenge wie `@name`); weitere
`#`-Token bleiben im Label (reservierte Ticket-Referenzen), `:#a,#b`
und `C#` werden nicht gefressen. Doppelte ID → Warnung duplicateId an
der späteren Zeile mit Nennung der ersten; die spätere gilt trotzdem.
Sichtbar im Tooltip (erste Position) und als a11yId im aria-label —
noch keine eigene Diagramm-Darstellung. Legendenzeile + Warntext in
allen 9 Sprachen; die drei `#`-Erwähnungen im mitgelieferten Plan sind
eingeklammert, damit sie Erwähnungen bleiben. 12 neue Tests
(tests/ids.test.js).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 16:15:15 +02:00
mhoennigandClaude Fable 5 d276c94840 feat: XOR-Gruppen (=) — genau eine Alternative (SPEC §3, D35)
Parser erkennt `=` als disjunktives Gate (nur mit folgendem Leerraum —
`=SUMME(…)` bleibt Label); Mischungen melden mixedGate wie gehabt. Die
XOR-Regel warnt je WEITERER realisierter Alternative (xorConflict mit
Zeilennummer; realisiert = [~]/[/]/[x]/[^], siehe D35). Darstellung erbt
die komplette any-of-Geometrie (ul class="or xor"), ergänzt um eine
„1"-Plakette am Austritt der Sammelleiste — auch im Grafikexport.
Legende (+ hint_root) und Warntext in allen 9 Sprachen; SPEC §11-Eintrag
in §1/§3/§9 überführt; 13 neue Tests (tests/xor.test.js).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 16:08:37 +02:00
mhoennigandClaude Fable 5 2754fa40f6 docs: XOR-Zeichen entschieden — = statt x (D34-Nachtrag)
SPEC §11: Zeichen festgelegt (disjunktiv wie `|`, Mischung → mixedGate,
Leerraum-Regel gegen Labels wie =SUMME(…)); offen bleibt nur noch die
Kennzeichnung der Gruppe im Diagramm. D34-Nachtrag begründet die Wahl und
hält die verworfenen Kandidaten fest (x, ^, |1, /, ⊕, °).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 15:01:34 +02:00
mhoennigandClaude Fable 5 477ef6c812 docs: Schlagworte auf &tag umreserviert, #-Doppelrolle aufgelöst (D34)
Tickets haben auf `#` Vorrang (`#123` als etablierte Kurzschreibweise, oft
zugleich die natürliche Knoten-ID; notfalls Präfix wie `#t123`). Freie
Schlagworte verlassen `#` und gehen auf `&tag` — als niedrig priorisierte
Idee, ausdrücklich ungebaut: Ohne Konsumenten (Filter-Linse, Taiga-Label-Sync)
sind Tags nur Kommentare mit Extra-Syntax; gebaut erst zusammen mit dem ersten.

Zeichenwahl nach den D32-Kriterien: `&` ist auf DE- wie US-Layout eine
Shift-Taste, nie ein Dead-Key; „R&D" und „Drag & Drop" bleiben durch die
Alleinstehend-Regel (wie `!!!`) Labels. Verworfen: `~` (Dead-Key auf Mac-DE,
Zirka-Kollision), `$`, `%`, `:`, `§`, `*`.

Damit ist der offene Punkt aus D34 durch Wegfall statt Trennregel geschlossen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-22 12:15:22 +02:00
mhoennigandClaude Opus 5 90230c4dd3 docs: Geplante Erweiterungen (IDs, Abhängigkeiten, XOR, Falten, Beschreibungen)
Die fünf geplanten Notations-Erweiterungen für vollständiges Lean-Pathfinding
sind in die Doku eingearbeitet — Schreibweisen samt offener Punkte in SPEC §11,
Begründung und Folgen in D34, Aufgaben in Phase 4, und als Knoten im
mitgelieferten Werkbaum-Plan.

Drei Kollisionen mit Bestehendem sind dabei benannt statt stillschweigend
mitentschieden: `#` trägt jetzt drei Bedeutungen (Ticket, Schlagwort, Knoten-ID),
`x` für XOR liest sich neben `[x]` schlecht, und kurze Knotenbeschreibungen
können keine eingerückte Folgezeile sein, weil Einrückung Hierarchie bedeutet.

Die weitestreichende Folge betrifft D18: Mit Dependency Closure — gemeinsame
Abhängigkeiten nur einmal gezählt — ist die günstigste Alternative nicht mehr
lokal entscheidbar; die gierige Wahl je Gruppe ist nicht länger optimal.

LEAN-PATHFINDING.md schlug für Abhängigkeiten noch `→ Feature` vor (Verweis auf
den Titel, rote Linien); das ist mit `:#id` überholt und korrigiert.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 10:04:50 +02:00
mhoennigandClaude Opus 4.8 0f27bab905 frontend/ci: Build-Hinweis in die App-Quelle, env-gesteuert; Prod-Build ohne
Der Latest-Build-Hinweis wandert vom Workflow-sed in die App (app.js,
mountBuildBadge), damit ihn auch der Dev-Server zeigt — ein Post-Build-sed
erreicht den Dev-Server nicht. Logik umgekehrt: Hinweis ist der Normalfall,
nur die produktive Installation schaltet ihn ab.

Drei Zustaende ueber Vite-Env VITE_BUILD_BADGE (Auswertung in app.js):
- Dev-Server (import.meta.env.DEV) -> 🔧 "Vorschau/lokaler Entwicklungsstand"
- Default `npm run build` (Env ungesetzt) -> 🚧 "latest build"; der Pages-
  Deploy nutzt den Default und traegt den Hinweis dadurch automatisch (die
  sed-Injektion entfaellt).
- `npm run build:prod` (Vite-Modus prod, .env.prod: VITE_BUILD_BADGE=none)
  -> KEIN Badge; esbuild eliminiert den Zweig als toten Code.

Verifiziert zur Laufzeit (Dev + `vite preview` auf beiden Builds): 🔧 im Dev,
🚧 im Default-Build, gar nichts im Prod-Build (Titel sauber "Werkbaum").
34 Vitest-Tests gruen, Workflow-YAML/Shell gueltig.

Doku: D16 fortgeschrieben (quellbasiert/env statt sed, Begruendung); README
(de/en) mit Prod-Build-Anleitung inkl. LICENSE-/Versions-Caveats; frontend/
CLAUDE.md; .claude/launch.json bekommt einen frontend-dist-Preview (vite
preview, Port 8138) zum Verifizieren gebauter Dateien.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 05:56:59 +02:00
mhoennigandClaude Opus 4.8 0a8b3659ea frontend: Fehlertolerantes Parsen — unbekannte Statuszeichen melden
TASKS Phase 2 (Phase 2 abgeschlossen). Der Parser erfasst die Statusbox jetzt
als beliebiges Einzelzeichen `\[([^\]])\]` und validiert gegen STATUS_BY_CODE.
Unbekannte Codes (z. B. [z]) werden nicht mehr still ins Label geschluckt,
sondern als {type:'unknownStatus', line, code} in parse().warnings gemeldet;
der Knoten bleibt neutral, Folgezeilen unberührt. Mehrzeichige Klammern ([xyz])
sind keine Statusbox und bleiben im Label (kein Fehlalarm).

render() in app.js führt Parser- und Renderer-Warnungen zusammen (nach Zeile
sortiert) und zeigt sie via formatWarning. Neuer i18n-Key unknownStatusWarn in
allen 9 Sprachen.

Verifiziert: mehrere unbekannte Codes -> zeilensortierte, lokalisierte
Warnungen (DE/EN), Knoten neutral, keine Konsolenfehler. tests/parser.test.js
+5 (34 Tests grün). SPEC §4 + CLAUDE ergänzt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 21:16:34 +02:00
mhoennigandClaude Opus 4.8 8d3ac63574 frontend: Druck-Stylesheet — nur das Diagramm drucken
TASKS Phase 2. @media print in style.css blendet Kopfzeile, Editor-Panel,
Splitter, alle Bedienelemente des Diagramm-Kopfs, Warnungen und Footer aus; das
Diagramm füllt die Seite (App-Grid -> Block, Overflow sichtbar) und darf über
mehrere Seiten laufen. Statusfarben werden mitgedruckt (print-color-adjust:
exact), Knoten brechen nicht über den Seitenrand (break-inside: avoid), der
Günstigster-Pfad-Overlay (in #out) kommt mit.

Verifiziert per Druck-Emulation (Regeln testweise als Screen-Style angewendet):
Editor/Kopf/Splitter/Warnungen/Footer display:none, Diagramm sichtbar, 18
Knoten, Farben + Pfadlinie erhalten. SPEC §9 (Druck) ergänzt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 21:12:07 +02:00
mhoennigandClaude Opus 4.8 15699c321c frontend: Barrierefreiheit — aria-Labels, Fokusreihenfolge, Live-Region
TASKS Phase 2. Jeder Diagramm-Knoten bekommt in render.js (nodeAria) einen
sprechenden, lokalisierten aria-label: Label + Status + Aufwand (inkl.
„(angenommen)" beim impliziten M) + Zuständige + Link. Die rein visuellen
Badges (Größe, Tags, ↗) sind aria-hidden, damit der Screenreader nicht „M",
„anna", „↗" kryptisch doppelt vorliest. Neue a11y*-i18n-Keys in allen 9
Sprachen.

Alle Knoten sind fokussierbar (tabindex=0 bzw. der Link) in Dokument-/Lese-
reihenfolge; sichtbarer :focus-visible-Rahmen (Petrol). #warn ist eine
Live-Region (role=status, aria-live=polite) — neue Warnungen werden angesagt.

Verifiziert: aria-label folgt dem Sprachwechsel (DE/EN), Badges aria-hidden,
keine visuelle Regression, keine Konsolenfehler. Renderer-Snapshots
aktualisiert (29 Tests grün). SPEC §9 (Barrierefreiheit) + CLAUDE ergänzt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 21:08:41 +02:00
mhoennigandClaude Opus 4.8 32a02021ed frontend: Warnungs-Modell vereinheitlichen (strukturiert: Typ + Zeile)
TASKS Phase 1 (abgeschlossen). Warnungen sind jetzt maschinenlesbare Objekte
{type, line, ...data} statt vorformatierter Strings: der Renderer emittiert
{type:'mixedGate', line, label}; src/warnings.js `formatWarning(w, t)` macht
daraus an EINER Stelle den lokalisierten, HTML-escapten Anzeigetext. Damit sind
Typ und Zeilennummer sortier-/filter-/testbar, und Phase 2 (unbekannte
Statuszeichen -> {type:'unknownStatus', line, code}) dockt ohne Formatstreuung an.

tests/warnings.test.js + Mixed-Gate-Test im Renderer (29 Tests grün).
Ende-zu-Ende im Browser verifiziert (lokalisierte Warnung mit Zeile + Label).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 21:01:43 +02:00
mhoennigandClaude Opus 4.8 5905712aa5 frontend: Renderer + Modell headless auslagern (src/model.js, src/render.js)
TASKS Phase 1. Baum-/Kostenlogik -> model.js (gateOf, needsBreakdown,
visibleChildren, computeCheapSet, cheapCls), HTML-Erzeugung -> render.js
(renderTreeHtml). Beide sind headless: UI-State (verworfene einblenden,
günstigster Pfad) kommt als Parameter herein statt aus Globals; nur cheapPathOn
bleibt UI-State in app.js. render() in app.js ist jetzt die dünne DOM-Anbindung.

Snapshot-Tests (tests/render.test.js): Grundzustand, günstigster Pfad,
verworfene einblenden, Geister-Knoten („Untergliederung fehlt"), plus die
Zusicherung, dass der Renderer nie eine Modus-Klasse erzeugt (Modus =
CSS-Container-Klasse in app.js -> ein Snapshot deckt alle drei Modi). 24 Tests
grün. Byte-identisches Rendering im Browser verifiziert (18 Knoten, 6 Blätter,
3 Geister, Toggles ok, keine Konsolenfehler).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 20:58:47 +02:00
mhoennigandClaude Opus 4.8 7c8f216589 frontend: Parser-Unit-Tests (Vitest) gegen SPEC §10 + Randfälle
TASKS Phase 1. tests/parser.test.js mit dem kanonischen SPEC-§10-Beispiel als
Fixture und den geforderten Randfällen: URL mit @, %% am Zeilenanfang/-ende,
leere Labels, mehrere Wurzeln, Tab = 2 Leerzeichen, ungleichmäßige Einrückung,
gemischte Gates, x/X + case-insensitive Größe, Vokabular-Exporte. 18 Tests grün.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 20:51:30 +02:00
mhoennigandClaude Opus 4.8 80d05a33a2 frontend: Parser nach src/parser.js auslagern (headless)
TASKS Phase 1. `parse`, `STATUS_BY_CODE` und `SIZE_RANK` wandern unverändert
in ein eigenes, DOM-freies Modul (SPEC §1–§8 normativ); app.js importiert sie.
Vorbereitung für die Parser-Unit-Tests (nächste Checkbox) und den SVG-/Mermaid-
Renderer, die den Parser headless nutzen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 20:49:45 +02:00
mhoennigandClaude Opus 4.8 78d1000f61 frontend: Projektgerüst mit Vite — Single-HTML in ES-Module + Bündelung
Erster Schritt der Modularisierung (ROADMAP „tragfähige Codebasis",
TASKS Phase 1). Der bisher einzelne index.html-Prototyp wird zur Vite-App:

- CSS -> src/style.css, gesamtes JS -> src/app.js (noch als ein Modul;
  Parser/Renderer werden in den folgenden Checkboxen herausgelöst).
- index.html ist der Vite-Entry (<script type="module" src="/src/app.js">).
- npm run build (vite + vite-plugin-singlefile) inlint JS+CSS+Favicon (als
  data:-URI) in EINE self-contained dist/index.html -> bleibt file://-tauglich.
- Vitest als Testrunner eingerichtet (tests/, passWithNoTests bis Schritt 2/3).
- Pages-Workflow: Node + npm ci + npm test + npm run build, deployt dist/;
  Favicon-sed entfällt (inline), nur ../LICENSE + Footer-Version bleiben.
- .claude/launch.json auf Vite-Dev-Server (Port 8137) umgestellt.

Entscheidung als D19 dokumentiert (weicht D11 „kein Build-Zwang" bewusst auf,
hält aber D16 file://-Versprechen über die gebündelte Datei). README (de/en)
und frontend/CLAUDE.md um Dev-/Build-/Test-Workflow ergänzt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 20:47:23 +02:00
mhoennigandClaude Opus 4.8 fccd32190a ci: GitHub-Pages-Deployment via Actions-Workflow
Offizieller Actions-Weg (upload-pages-artifact + deploy-pages) mit
permissions pages/id-token und concurrency-Gruppe "pages"; Trigger:
Push auf main + workflow_dispatch. Vitest-Step als Platzhalter
auskommentiert (Tests folgen, TASKS.md Phase 1).

Site-Aufbau: frontend/index.html an die Wurzel-URL, dazu docs/brand/
(Favicon) und LICENSE (MIT-Link im Footer). Die ../-Pfade der Quelle
zeigten von der Wurzel aus über die Site hinaus; statt den Editor zu
aendern, zieht der Workflow sie nur auf der Site-Kopie per sed gerade
(Editor-Quelle bleibt unveraendert, lokal weiter nutzbar). backend/
und uebrige docs/ werden nicht veroeffentlicht.

Doku: README-Abschnitt "Deployment" (inkl. einmaliger Settings-
Umstellung auf Source "GitHub Actions", Repo muss oeffentlich sein),
TASKS.md-Rubrik "Deployment" abgehakt, DECISIONS D16. Hinweis: der
Auftrag nannte "D15", das war aber schon fuer den kompakten Modus
vergeben -> als D16 angelegt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 13:14:51 +02:00
Michael Hoennig ded894a4da initial, vibe-coded version, mostly frontend 2026-07-21 09:55:30 +02:00