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>
145 lines
9.2 KiB
Markdown
145 lines
9.2 KiB
Markdown
# Aufgaben
|
|
|
|
Abhaken beim Erledigen; neue Aufgaben unten anfügen.
|
|
|
|
## Phase 1 — Modularisierung & Tests
|
|
- [x] Projektgerüst: `src/` (parser.js, model.js, render.js, app.js),
|
|
`tests/`, `index.html` bindet Module ein; weiterhin ohne Build nutzbar
|
|
(ES-Module) oder mit minimalem Setup (Vite) — Entscheidung dokumentieren.
|
|
→ **Vite** gewählt (D19): `src/` als ES-Module, `npm run build` bündelt zu
|
|
einer self-contained `dist/index.html` (file://-tauglich). Gerüst steht
|
|
(aktuell `src/app.js` + `src/style.css`); Parser/Renderer werden in den
|
|
folgenden Checkboxen herausgelöst.
|
|
- [x] Parser extrahieren; Verhalten exakt wie in `docs/SPEC.md` §1–§8.
|
|
→ `src/parser.js` exportiert `parse`, `STATUS_BY_CODE`, `SIZE_RANK`
|
|
(headless, kein DOM); `app.js` importiert sie.
|
|
- [x] Unit-Tests für den Parser (Vitest): kanonisches Beispiel aus SPEC §10
|
|
als Fixture; Randfälle: gemischte Gates, Tabs/ungleichmäßige Einrückung,
|
|
URL mit `@`, mehrere Wurzeln, leere Labels, `%%` am Zeilenanfang/-ende.
|
|
→ `tests/parser.test.js` (18 Tests).
|
|
- [x] Renderer extrahieren (HTML-String-Erzeugung), Snapshot-Tests für
|
|
Normal- und Vertikalmodus sowie „Untergliederung fehlt“.
|
|
→ `src/model.js` (Baum-/Kostenlogik) + `src/render.js` (`renderTreeHtml`,
|
|
headless); `app.js` reicht UI-State als Parameter herein.
|
|
`tests/render.test.js` (6 Tests, Snapshots). Anm.: der Modus
|
|
(horizontal/vertikal/kompakt) ist reine CSS-Container-Klasse und ändert
|
|
den Renderer-String nicht — ein Snapshot deckt alle drei Modi ab.
|
|
- [x] Warnungs-Modell vereinheitlichen (Zeilennummern, Typen).
|
|
→ strukturierte Objekte `{type, line, ...}` (Renderer emittiert
|
|
`mixedGate`); `src/warnings.js` `formatWarning(w, t)` macht daraus den
|
|
lokalisierten, HTML-escapten Text an einer Stelle. Vorbereitet für
|
|
Phase 2 (`unknownStatus`). `tests/warnings.test.js`.
|
|
|
|
## Phase 2 — Qualität
|
|
- [x] Barrierefreiheit: Fokusreihenfolge, aria-Labels für Status/Größe/Tags.
|
|
→ je Knoten ein sprechender `aria-label` (Label+Status+Aufwand+Zuständige+
|
|
Link, lokalisiert, neue `a11y*`-Keys in allen 9 Sprachen); visuelle Badges
|
|
`aria-hidden`; Knoten `tabindex="0"` (Fokus = Lesereihenfolge) mit
|
|
`:focus-visible`-Rahmen; `#warn` als Live-Region (`role=status`,
|
|
`aria-live=polite`). Snapshots aktualisiert.
|
|
- [x] Druck-Stylesheet (Diagramm ohne Editor-Panel).
|
|
→ `@media print` in `style.css`: blendet Kopf/Editor/Splitter/Bedien-
|
|
elemente/Warnungen/Footer aus, Diagramm füllt die Seite; Statusfarben via
|
|
`print-color-adjust:exact`, `break-inside:avoid`, Pfad-Overlay inklusive.
|
|
- [x] Fehlertolerantes Parsen weiter ausbauen (unbekannte Statuszeichen melden).
|
|
→ Parser erfasst die Statusbox als beliebiges Einzelzeichen, validiert
|
|
gegen `STATUS_BY_CODE`; unbekannte Codes → `unknownStatus`-Warnung (Zeile +
|
|
Code), Knoten neutral, Folgezeilen unberührt. `render()` führt Parser- +
|
|
Renderer-Warnungen zusammen. i18n `unknownStatusWarn` in allen 9 Sprachen.
|
|
`tests/parser.test.js` (5 neue Tests).
|
|
|
|
## Deployment
|
|
- [x] GitHub-Pages-Workflow angelegt (`.github/workflows/pages.yml`,
|
|
siehe docs/DECISIONS.md D16).
|
|
|
|
## Phase 3 — Integrationen (siehe [ROADMAP](ROADMAP.md))
|
|
- [ ] Backend-Gerüst per Spring Initializr in `backend/` anlegen
|
|
(Kotlin, Gradle Kotlin DSL, JDK 21; Konventionen: backend/CLAUDE.md).
|
|
- [ ] SVG-Renderer (Layout-Engine) als gemeinsame Basis für Export und
|
|
Mermaid-Plugin.
|
|
- [ ] Mermaid-Plugin-Spike: Detektor + Registrierung, ein Minimalbaum.
|
|
- [ ] Taiga-Spike: `#ref`-Syntax parsen, Status via REST-API auflösen
|
|
(read-only), Mapping konfigurierbar.
|
|
|
|
## Phase 4 — Vollständiges Lean-Pathfinding (siehe [ROADMAP](ROADMAP.md), D34)
|
|
Reihenfolge ist nicht beliebig: ohne IDs keine Abhängigkeiten, ohne die keinen
|
|
effektiven Status und keine Closure-Rechnung. Jeder Punkt beginnt in
|
|
[SPEC §11](SPEC.md) — die dort benannten offenen Schreibweisen sind zu
|
|
entscheiden, **bevor** Code entsteht.
|
|
- [x] `#`-Doppelrolle auflösen und in SPEC §11 festschreiben.
|
|
→ Durch Wegfall statt Trennregel: Tickets haben Vorrang (`#123`
|
|
numerisch, oft zugleich die natürliche Knoten-ID; notfalls Präfix wie
|
|
`#t123`); Schlagworte gehen auf `&tag` — niedrig priorisiert, gebaut
|
|
erst mit dem ersten Konsumenten (D34-Nachtrag).
|
|
- [x] Knoten-IDs parsen; doppelte ID → Warnung mit Zeilennummer.
|
|
→ Umgesetzt (D36): Zeichenmenge wie `@name`, nur alleinstehend angesetzt
|
|
und nur das erste Token je Zeile (`:#a,#b` und Ticket-Erwähnungen bleiben
|
|
unberührt); Warnung `duplicateId` nennt beide Zeilen; sichtbar im
|
|
Tooltip + `aria-label`; SPEC-§11-Teil nach §1 überführt;
|
|
`tests/ids.test.js`.
|
|
- [x] Abhängigkeiten `:#a,#b` parsen; unbekannte ID → Warnung, Zyklen erlaubt.
|
|
→ Umgesetzt (D37): ein zusammenhängendes Token ohne Leerraum, nur
|
|
alleinstehend angesetzt (eingeklammerte Erwähnungen bleiben Label);
|
|
`deps` als ID-Strings am Knoten, Warnung `unknownDep`, Zyklen bewusst
|
|
ungeprüft; sichtbar als `→ #a, #b` im Tooltip + `a11yDeps`;
|
|
SPEC-§11-Teil nach §1 überführt; `tests/deps.test.js`.
|
|
- [x] Effektiven Status rechnen (intrinsisch + Abhängigkeiten); Darstellung
|
|
entscheiden — die Knotenfarbe zeigt heute den intrinsischen Status.
|
|
→ Entschieden und umgesetzt (D39): Fortschritts-Rang (SPEC §4), effektiv
|
|
= Minimum über die Abhängigkeits-Hülle (Fixpunkt, Zyklen teilen ihr
|
|
Minimum); **Knotenfarbe = effektiver Status**, bei Diskrepanz die eigene
|
|
Statusbox als Marke unten links in den eigenen Farben (auch im Export);
|
|
Tooltip + `a11yEffective`; `tests/effective.test.js`.
|
|
- [x] Günstigsten Pfad auf die Dependency Closure umstellen (gemeinsame
|
|
Abhängigkeiten nur einmal zählen). Erweitert D18; die gierige Wahl je
|
|
Alternativgruppe ist damit nicht mehr optimal — Verfahren wählen und
|
|
**benennen**.
|
|
→ Umgesetzt (D42): erschöpfende Suche über die gekoppelten Gruppen
|
|
(`computeCheapPlan` in model.js), ungekoppelte wählen lokal wie bisher;
|
|
oberhalb des Suchlimits gierig mit zeilenloser Warnung `cheapApprox`.
|
|
Abhängigkeiten ziehen auch optionale/nicht gewählte Ziele, verworfene
|
|
nie; `tests/closure.test.js`.
|
|
- [x] Querverbindungen zeichnen (eigene SVG-Ebene, optisch sekundär);
|
|
bei ausgewähltem Knoten ein-/ausgehende hervorheben.
|
|
→ Umgesetzt (D41): gekrümmte blassgraue Kanten mit Pfeilspitze auf das
|
|
Gebrauchte, hinter den Knoten (`drawDepLinks`); Hervorhebung in Tinte
|
|
für Fokus-Knoten bzw. Cursor-Zeile; Basis-Kanten auch im Export/Druck.
|
|
- [x] Faltmarken `>` / `<` parsen; interaktives Auf-/Zuklappen im Diagramm.
|
|
→ Schreibweise und Export-Verhalten entschieden (D34-Nachtrag): Marke
|
|
hinter dem Zerlegungszeichen (`- > [x] …`), Export/Druck folgen der
|
|
sichtbar eingeklappten Struktur mit Kennzeichnung am Knoten.
|
|
Umgesetzt (D38): `initialCollapsed()` (`<` wandert die Faltung die
|
|
Pfad-Ebenen hinunter, `!!!` holt sich mit hervor); Falt-Zeichen ▾/„▸ n"
|
|
+ Tastatur ←/→; Eingriffe je Label-Pfad, nur für die Sitzung; Warnungen
|
|
aus eingeklappten Teilbäumen bleiben; `tests/fold.test.js`.
|
|
- [x] XOR-Gruppe (`=`) parsen (nur mit folgendem Leerraum, Mischung →
|
|
`mixedGate`), zwei realisierte Alternativen melden.
|
|
→ Zeichen entschieden: `=` statt `x` (D34-Nachtrag). Umgesetzt (D35):
|
|
„realisiert“ = `[~]`/`[/]`/`[x]`/`[^]`, Warnung `xorConflict` je weiterer
|
|
realisierter Alternative; Darstellung als any-of plus „1“-Plakette an der
|
|
Sammelleiste (auch im Grafikexport); Legende + i18n in 9 Sprachen;
|
|
`tests/xor.test.js`.
|
|
- [x] Knotenbeschreibungen: Schreibweise für kurze und lange Form festlegen
|
|
(Einrückung ist bereits Hierarchie), dann Tooltip/Pop-up.
|
|
→ Schreibweise entschieden (D34-Nachtrag): Kurzform als `"`-Zeile unter
|
|
dem Knoten (Leerraum-Regel), Langform als eingerückte ID-Blöcke hinter
|
|
einem `---`-Trenner (SPEC §11). Umgesetzt (D40): Parser (`desc` am
|
|
Knoten, Warnungen `unknownDesc`/`descStray`), Anzeige im Tooltip +
|
|
`aria-label` mit ”-Marke am Knoten; `tests/desc.test.js`.
|
|
|
|
## Phase 5 — Der Pfad zeigt, was als Nächstes dran ist
|
|
- [x] Günstigsten Pfad status-bewusst rechnen: Erledigtes (`[x]`/`[^]`) kostet
|
|
nichts mehr, hervorgehoben wird die offene Front.
|
|
→ Umgesetzt (D46): `isDone()` + `ownCost()` in model.js; Stationen sind
|
|
die tiefsten noch **offenen** Pfadknoten (`hidesOpenCheap()`), erledigte
|
|
behalten Farbe und Pfadzugehörigkeit, verlieren aber Punkt und implizites
|
|
M-Badge. Angefangenes (`[~]`/`[/]`) zählt weiter voll, maßgeblich ist der
|
|
intrinsische Status. Kein neuer Umschalter — der vorhandene ändert seine
|
|
Bedeutung. `tests/frontier.test.js`.
|
|
- [ ] Nutzen je Knoten (Gegenstück zur Kosten-Größe) — Schreibweise offen,
|
|
SPEC-first (siehe ROADMAP „Kleinere Ideen").
|
|
- [ ] Aufwands-Rollup (Größen der Kinder aggregieren) — braucht erst eine
|
|
Mapping-Konvention, Größen sind ordinal.
|
|
- [ ] Ausbaustufen: ist eine Alternativgruppe komplett realisiert, zur nächsten
|
|
per Nutzen gewählten Stufe weiterspringen. Baut auf beidem oben auf.
|