Trägt ein @name mehr als die Hälfte der offenen Arbeit des günstigsten
Pfads (Marginalkosten-Maß, D69) und tragen mindestens zwei Personen Last
auf der offenen Front, meldet die zeilenlose Warnung assigneeOverload die
mögliche Engstelle; die Pillen der Person wechseln an offenen Pfad-Knoten
auf die Warnfarbe. Knoten ohne Tags erben für die Rechnung vom nächsten
getaggten Vorfahren, mehrere Tags teilen sich den Beitrag.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- #ed.path.cost: Cost model, a size prices its subtree
Die D66-Schätzung war status-blind: Ein größenloses Paket mit [x] (L) und
[ ] (S) wurde als L geschätzt, obwohl nur S offen ist. Erledigte Kinder
fallen jetzt heraus, eine erledigte realisierte Alternative stellt ihre
Gruppe fertig, und sind alle benannten Kinder erledigt, gilt XS (der eigene
Rest — M-Rückfall erhöhte den Preis beim Fertigwerden). Angegebene Größen
bleiben unangetastet (D69).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die fast transparente Füllung mit mattgrauer Glyphe verschwand auf den
acht Status-Pastelltönen. Nur Farben geändert; line-height und Padding
bleiben (23-px-Geometrie).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der Preis eines Knotens ist seine angegebene (oder D66-geschätzte) Größe;
die frühere Rekursion (eigene Größe plus Summe/Minimum der Kinder) zählte
doppelt und bestrafte sorgfältig zerlegte Pakete — eine zerlegte
S-Alternative verlor gegen ein grobes L. Das Vereinigungs-Maß der
Closure-Suche (D42) zählt je Knoten nur noch die Marge über seine nötigen
Teilpakete hinaus. Mitgelieferter Plan wählt identisch (per Vergleich
gemessen); SPEC §9 und llms.md nachgezogen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Erkannt nur alleinstehend angesetzt (wie #id und :#…) — damit greifen die
Zitier-Konventionen "(L)" und ((L)) von selbst, und Backend(L) bleibt
Label. Das letzte Token gewinnt statt des ersten: Die Größe steht hinter
dem Titel, frühere Vorkommen sind Text. SPEC §1/§5 und llms.md nachgezogen;
mitgelieferte Beispiele unverändert (Parse-Vergleich alt/neu).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Vor dem `:#…`-Token prüfte depIdAt nur Space/Tab, der Parser jedes \s —
vor einem geschützten Leerzeichen war das Token damit eine Abhängigkeit,
auf die Strg+Klick nichts tat. Test mit echtem NBSP; Gegenprobe: die alte
Prüfung lässt genau ihn fallen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- #ed.jump.dep: Ctrl+click follows a dependency to its id
Strg/Cmd+Klick auf eine Abhängigkeits-ID im Textfeld — auch jede ID der
Liste und die Kopf-Form #auth:#db — markiert die Zeile, die die ID vergibt;
Tastatur-Pendant Strg+Enter. Erste Vergabe gewinnt (D36/D39), unbekannte IDs
tun still nichts. Headless als depIdAt/idLine in autocomplete.js, 16 Tests;
Legenden-Zeile hint_jump in allen neun Sprachen erweitert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- #ed.path.est: Missing size estimated from the sub-packages (S) %% see D66
`#ed.path.est` neu als [x]; das überholte „missing size counts as M" aus
Label und Beschreibung von `#ed.path.cost` entfernt. Der neue S-Knoten
kippte die Größenprüfung von `#ed.path` — ehrlich nachgezogen auf (XL).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mindestens die größte Größe der zählenden Kinder, ab drei Kindern dieser
Größe eine Stufe mehr (Deckel XXL); disjunktiv die kleinste Alternative,
rekursiv über größenlose Kinder, Blatt bleibt M. Badge, Tooltip und
aria-label zeigen die geschätzte Größe („mindestens {size} angenommen").
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Lange Titel zogen das Diagramm zu breit. Ein Parameter in wrapLabel(),
der 32ch-Rückhalt im CSS und SPEC §9 ziehen mit; Balance-Regel und
Erste-Zeile-Verankerung unverändert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Zwei Geometrie-Fehler bei Gruppen mit wenigen Kindern: :only-child schaltete
die Leiste ab, obwohl Stub (50 %) und Abzweig (23 px) seit dem 20-px-
Zusatzabstand nicht mehr zusammenfallen (6,6–15,8 px Lücke); und bei einem
großen Teilbaum im letzten Kind endete die Leiste über dem Stub (bis 98 px).
Fix: CSS-Verbinder 23px→50 % am Einzelkind, alignVRails() + --vrail-ext für
das letzte Kind. Export und Kompakt-Modus waren nie betroffen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- #ed.render.wrap: Long titles wrap into balanced lines (S) %% max ~40 chars, see D64
- #ed.depcomplete: Typing :# suggests the known ids (S) %% arrows choose, Enter inserts
Der High-Risk-Status fehlte seit Juli in der Chip-Reihe der Legende;
hint_break nennt jetzt die Größen-Prüfung (D62), in allen neun Sprachen.
llms.md: Alignment-Marker an beiden Tabellen, die Größen-Bereiche als eigene
bündige Tabelle statt Prosa — inhaltlich war die Agenten-Fassung auf Stand
(Fortsetzungszeilen, ID-als-Titel, Größen-Konflikt, angefangene Zugaben).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Lange Knotentitel brechen bei ~40 Zeichen um, gleichmäßig auf die Zeilen
verteilt — vom Renderer (wrapLabel, headless getestet) statt text-wrap:balance,
damit der Kasten auf die längste balancierte Zeile schrumpft. Der
23-px-Abzweig ankert an der ersten Zeile; der Optional-Kreis sitzt fest auf
der Abzweighöhe. Der Grafikexport misst die gerenderten Zeilen (labelLines)
und gibt je Zeile ein <text> aus. Dazu: die eingeblendete ID (D56) steht in
einer eigenen Zeile über dem Titel, und das Falt-Zeichen ist ein gerahmter
19×16-px-Chip mit gedeckelter Höhe. Plan: #ed.render.wrap, #ed.render M→L
(D62-Prüfung schlug korrekt an).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wer :# tippt, bekommt die vergebenen IDs als Liste an der Schreibmarke:
Präfix- vor Teilstring-Treffern, Knotentitel als Kontext, schon gelistete
und die eigene ID ausgenommen. ↑/↓ wählt, Enter/Tab übernimmt (undo-fähig),
Esc schließt; Live-Region für Screenreader. Eingabehilfe wie die Kurzform
(D55) — der Parser sieht nie etwas davon. Regeln headless in autocomplete.js
(20 Tests), app.js verdrahtet Popup, Tasten und Einfügen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Liegt der Knoten der Cursor-Zeile in einem eingeklappten Teilbaum, hebt
nodeOfLine() den nächsten sichtbaren Vorfahren hervor — Cursor-Mitlaufen,
Alt+Klick, Alt+Enter und der Mobil-Umschalter erben es über die eine
Auflösungsstelle. Ausgeblendete verworfene Elemente heben weiterhin nichts
hervor (SPEC §9). Zeilen-Map als lineTargets() headless in model.js, 5 neue
Tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- #not.sizes: Size conflict — sub-packages must fit the given size (S) %% ranges, XXL open-ended, see D62
Größen zählen für diese eine Prüfung als Bereiche (Untergrenzen verdoppeln
sich, XXL nach oben offen); Konflikt erst, wenn selbst die günstigste Lesart
der Kinder die großzügigste des Elternknotens erreicht. Warnung sizeConflict
an der Elternzeile, Badge in --warn, Grund in Tooltip und aria-label. Nichts
wird automatisch korrigiert. Nebenbefund behoben: der Grafikexport zeichnete
das Größen-Badge mit festen Farben — das invertierte implizite M stand seit
jeher gefüllt im Bild. Die acht berechtigten Konflikte im eigenen Plan sind
nachgezogen. 372 Tests, 16 neue.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`node_modules/.vite/vitest/.../results.json` lag seit a8c5e54 versehentlich
im Repo: Die .gitignore deckte nur `frontend/node_modules/` ab, nicht das
`node_modules/` in der Wurzel. Die Datei ändert sich bei jedem Testlauf und
rutschte dadurch still in fremde Commits.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Basis-Kanten lagen schon richtig; „drüber gemalt" wurde allein die
Hervorhebung des ausgewählten Knotens (`svg.dep-front`, z-index 4). Eine
durchgezogene Linie quer über einen fremden Knoten durchstreicht dessen
Titel — und beim Tippen wechselt die Hervorhebung mit jeder Zeile.
`dep-front` entfällt; hervorgehobene Kanten hängen zuletzt in derselben
hinteren Ebene, liegen damit über den übrigen Kanten und unter jedem
Knoten. Export und Druck waren nie betroffen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- #ed.path.started: Started work is on the path, extras included (S) %% see D61
`#.kc` wird jetzt aufgelöst, sobald ein Doppelpunkt die ID abschließt —
beim Tippen des Doppelpunkts ebenso wie beim nächsten Tastendruck in
einer Zeile, die ihn schon trägt. Ohne Doppelpunkt bleibt es beim
Verlassen der Zeile.
Der Cursor allein löst weiterhin nichts aus: Angefasst wird nur die
Zeile, in der auch getippt wurde (D55/D27).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Stiel aus dem Elternknoten sitzt bei 50 % der Gruppe, der Stiel zum
Kind bei `--stem-x` (der gemessenen Knotenmitte, Nachtrag 2). Für
`li:only-child` ist die waagerechte Sammelleiste abgeschaltet — richtig,
solange beide zusammenfallen, und das tun sie nur, solange der Knoten in
seiner Zelle zentriert steht. Bei einer Treppe darunter sind es gemessen
8,5 px Versatz, bei einem `li.has-or` als einzigem Kind 41,8 px.
Jetzt verbindet ein Leiterstück genau zwischen 50 % und `--stem-x` die
beiden — dieselbe L-Form wie bei einem äußeren Kind einer größeren
Gruppe; ohne `--stem-x` ist es 0 px breit und unsichtbar.
Dabei aufgefallen: `:only-child::after{border-left}` stand vor
`:last-child::after{border:0 none}` und war bei gleicher Spezifität seit
jeher wirkungslos. Der ganze Block steht nun dahinter.
Kein Rückschritt von D61 — mit ausgeschaltetem Pfad derselbe Versatz;
die Zugabe steht seither nur in voller Farbe statt blass da. Der
Grafikexport war nie betroffen (die Leiste schließt dort die Elternmitte
ein).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eine Zugabe (`+`) fällt aus dem günstigsten Pfad — außer sie ist
realisiert und noch nicht erledigt (`[~]`/`[/]`). Angefangene Arbeit ist
die offene Front, und seit D46 zeigt der Pfad genau die; bisher führte
der Von-Station-zu-Station-Knopf nie dorthin, wo gearbeitet wird.
Erledigte Zugaben bleiben draußen: dort ist nichts mehr zu tun, und was
darunter offen blieb, ist mit ihnen zusammen entbehrlich (§3).
Dabei die fehlende Hälfte von D46 gefunden: SPEC §9 sagt seit jeher
„eine bereits realisierte Alternative gewinnt", umgesetzt war das aber
nur über die Kosten — und die sind allein bei `[x]`/`[^]` null. Ein
`[~]`-Zweig verlor damit gegen eine unangetastete billigere, obwohl die
XOR-Regel gerade ihn als die realisierte Alternative ausweist.
`chosenPool()` schränkt die Wahlmenge auf die realisierten ein; unter
mehreren entscheiden wieder die Kosten. Nebengewinn: eine entschiedene
Gruppe ist keine freie Variable mehr und verkleinert die Suche (D42).
10 neue Tests; Gegenprobe geführt (jede Regel einzeln herausgenommen
lässt genau die nach ihr benannten Zusicherungen fallen). Der
mitgelieferte Plan ändert sich nicht — er hat keine angefangene Zugabe.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`- #US-123` ergab bisher nichts — leeres Label, Zeile ignoriert, ID nicht
vergeben. Wo die Kennung schon der Name ist (Ticket-Referenzen, §11), war das
verkehrt herum: Wer den Titel nicht danebenschrieb, verlor den ganzen Knoten.
Jetzt wird `#id` das Label, mit Doppelpunkt geschrieben wie ohne.
Das `#` bleibt im Label — es sagt „hier steht die Adresse, weil es keinen
Titel gibt". Der `#`-Umschalter setzt bei so einem Knoten nichts davor
(sonst `#US-123: #US-123`), und Tooltip wie aria-label lassen die ID weg, die
schon im Titel steht.
Verhaltensänderung: Die ID ist damit vergeben — `- #auth` gefolgt von
`- [ ] Echt #auth` gibt jetzt zwei Knoten und eine duplicateId-Warnung.
SPEC §1, llms.md, D60; 6 neue Tests, der alte auf die neue Regel umgeschrieben.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- #not.cont: A trailing backslash continues the line (XS) %% space before it is required
Eine Zeile trägt alles auf einmal — im mitgelieferten Plan ist die längste
122 Zeichen lang, und seit das Textfeld nicht mehr umbricht (D49) muss man
dafür schieben. Ein `\` am Zeilenende verteilt sie jetzt auf mehrere
Textzeilen, ohne dass ein neuer Knoten entsteht.
Leerraum davor ist Pflicht (`… \`, nicht `…\`) — bewusst gegen die
Shell-Gewohnheit: Ohne die Regel verschluckt ein Label wie `C:\temp\` stumm
den folgenden Knoten, mit ihr bekommt man nur keine Fortsetzung, was man
sofort sieht. Der laute Fehler ist der bessere.
Umgesetzt als Vor-Durchlauf `logicalLines()`: Die Folgezeile ist Teil der
Zeile, bevor irgendetwas aus ihr gelesen wird — die Extraktionsreihenfolge
aus §1 bleibt unangetastet. Alles gehört zur ersten Zeile: Einrückung,
Warnungs-Zeilennummer, Rückschreiber; der Cursor in der Fortsetzung wählt
ihren Knoten aus, wie bei Beschreibungszeilen.
SPEC §1/§9, llms.md, Legende in neun Sprachen, D59; 20 neue Tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Wer die Oberfläche auf Japanisch stehen hat, sah einen japanischen Rahmen um
englische Sätze — das kann man für eine fehlende Übersetzung halten. Ein Satz
oben im Popup sagt jetzt, dass es Absicht ist, in allen neun Sprachen; klein
und grau, damit er hinter dem Inhalt zurücksteht, zu dem er gehört. Bei
englischer Oberfläche entfällt er.
SPEC §9 und D58-Nachtrag.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- #ed.tipwindow: The same window at the pointer and on keyboard focus (XS) %% a title has no paragraphs and never shows on focus
- #ed.shortid: Type #.kc under #prod-stage, get #prod-stage.kc (XS) %% an input aid, not notation
- #ed.showids: A # button shows the ids before the titles (XS) %% written as in the text, with a colon
- #ed.fresh.news: A star in the header, with the last few days (S) %% see D58
Der „Was ist neu?"-Knopf stand im Diagramm-Kopf und war verborgen, solange es
nichts gab — er konnte also nur etwas über das offene Dokument sagen, und
meistens sagte er gar nichts. Jetzt steht er permanent in der oberen
Bedienleiste und öffnet ein Popup mit der Chronik der letzten Tage; je Tag
führt ein Link die betroffenen Knoten im Diagramm vor (dieselbe gelbe
Kranz-Ansicht wie D28, nur mit einer anderen Frage).
Zwei Quellen, jede in ihrer Rolle: docs/CHANGELOG.md sagt, WAS geschehen ist
(englisch — das Popup ist Oberfläche in neun Sprachen, die Commit-Betreffs
sind deutsch); die git-Historie des mitgelieferten Plans sagt, WELCHE Knoten
sich bewegt haben. Beides wird zur Bauzeit eingelesen (Vite-Plugin), zur
Laufzeit lädt Werkbaum weiterhin nichts nach.
Bernstein heißt ungesehen, Petrol heißt „wird gerade vorgeführt". Der
Besuchsvergleich (D28) steht als abgesetzter Abschnitt zuoberst im Popup und
trägt den „gesehen"-Knopf, den vorher der Knopf selbst war.
SPEC §9 (Neuigkeiten) und D58; 20 neue Tests, davon einer auf der
ausgelieferten CHANGELOG.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Das `?` von `cursor:help` sagte nur „hier gibt es etwas zu lesen". Über der
orange gefärbten Zahl einer Warn-Zeile steht jetzt dasselbe ⚠, das im
Warnungsbereich vor jeder Meldung steht — der Zeiger sagt dieselbe Sache wie
das Ziel, auf das er zeigt.
Der Pfeil bleibt daneben stehen (sonst zeigte der Zeiger auf nichts), Spitze
auf dem Brennpunkt; als data:-URI im Stylesheet, `help` als Rückfall.
SPEC §9 (Zeilennummern) und D33-Nachtrag 2.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Das Fenster aus D52 war für Touch gebaut — damit standen zwei Darstellungen
desselben Inhalts nebeneinander, und ausgerechnet die schlechtere bekam der
Zeiger. Jetzt zeigt es überall: am Zeiger nach 350 ms beim Überfahren, bei
Tastaturfokus sofort, auf Touch unverändert beim Tipp.
Was ein `title` prinzipiell nicht kann:
- keine Absätze (die Beschreibungen im Plan brechen bei ~76 Zeichen, das sah
ausgefranst aus),
- keine Linie (der Trennstrich war aus 24 `─` GEMALT, D40-Nachtrag),
- nichts bei Tastaturfokus — wer mit Tab durch das Diagramm geht, sah bisher
keine Beschreibung. Nachgemessen mit ECHTEM Tastendruck: Fokus von
#not.line auf #not.status, Fenster folgt, 10 px unter dem Knoten, Ring am
fokussierten Knoten.
- Inhalt zieht von `title` nach `data-tip` (sonst zeigte der Browser seinen
eigenen zusätzlich) — dasselbe Attribut unter anderem Namen, keine
Verdopplung der 20 kB DOM-Text.
- Die letzten drei nativen Tooltips IN Knoten mussten weichen: Das
Warndreieck war redundant (Statusname steht in den Fakten), die Annahme
„Größe fehlt, gilt als M" wandert in die Faktenzeile. Nachgemessen: 0 von
161 Knoten und 0 Kinder tragen noch einen `title`.
- Absicht-Erkennung: 350 ms Verzögerung, beim Wechsel zwischen Knoten ohne
Warten, 120 ms Nachfrist beim Verlassen (der Weg ins Fenster führt über
einen Zwischenraum).
- `aria-hidden` am Fenster: Der Inhalt steht schon im aria-label, sonst würde
er doppelt vorgelesen; × und ↗ deshalb `tabindex="-1"`.
Werkzeuggrenze notiert: `element.focus()` feuert ohne Fensterfokus keine
Fokus-Ereignisse (`document.hasFocus()` false) — der erste Prüflauf zeigte
fälschlich „öffnet nichts".
SPEC §9 + D57; Plan: #ed.tipwindow [x] (161 Knoten, 0 Warnungen).
293 Tests grün, 5 Snapshots/Zusicherungen auf `data-tip` nachgezogen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die ID ist die Adresse eines Knotens — Ziel der Abhängigkeiten, Schlüssel der
Beschreibungsblöcke —, stand im Diagramm aber nur im Tooltip (D36). Jetzt
umschaltbar und geschrieben wie im Text: `#some.id: Titel`.
- Als RENDERER-Option, nicht per CSS versteckt: `diagramToSvg()` zieht den
Knotentext aus `textContent`, ein `display:none` hätte die IDs trotzdem in
jeden Export geschrieben. Nachgemessen im SVG: `>#not.line: Line format<`
mit Umschalter, `>Line format<` ohne.
- Zurückgenommen dargestellt (Mono wie im Textfeld, --muted), `aria-hidden` —
der Screenreader bekommt die ID über a11yId (D36). Zustand persistiert.
Das zehnte Bedienelement hat die Kopfzeile gekippt, zweimal dieselbe Rechnung
wie D17-Nachtrag 5:
- Schreibtisch: 738 nötig, 728 da -> 82 statt 49 px. Nicht die Knöpfe (566 px
für elf Elemente), sondern zehn Lücken à 14 px = 140 px. `gap:10` gibt
40 px zurück; danach 698 von 728 und wieder 49 px mit UND ohne Knopf.
- Telefon (375 px): alle Ziele schon auf 29 px, Lücken auf 6 — ein zehntes
passt arithmetisch nicht (386 gegen 359). D50s Umbruch-Schwelle wandert von
360 auf 440 px. Greift nur mit dem „Was ist neu?"-Knopf: mit allen zehn
78 px/zwei Reihen, ohne ihn 49 px/eine Reihe.
SPEC §9 + D56; Plan: #ed.showids [x] (160 Knoten, 0 Warnungen).
293 Tests grün (288+5); i18n `idsTooltip` in 9 Sprachen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Gefragt war, ob `#.kc` unter `#prod-stage` als Notation `#prod-stage.kc`
bedeuten könnte. Als Notation wäre es falsch, und das zeigt der eigene Plan:
181 IDs im Baumteil, davon 50 (28 %), deren gepunktetes Präfix gar nicht die
Eltern-ID ist (`#ed.parser` hängt unter `#ed.live`) — die Punkte benennen den
BEREICH, nicht den Pfad, genau wie D48 es vorsieht. Dazu: der
Beschreibungsteil hinter `---` hat keinen Baum (zwei Schreibweisen für eine
ID), Einrücken änderte die Identität und bräche `:#…`-Verweise, und aus einer
Konvention würde Grammatik. Gewinn wären 802 Zeichen in 40 kB.
Also als Eingabehilfe: getippt wird `#.kc`, beim Verlassen der Zeile steht
`#prod-stage.kc` im Text — derselbe Griff, mit dem das Umklappen im Diagramm
seine Faltmarke zurückschreibt (D38-Nachtrag 2). Die Datei bleibt eindeutig,
durchsuchbar und umsortierbar; llms.md ist unberührt, weil sich an der
Notation nichts ändert.
- parser.js: `expandShortIds(text)` neben `setFoldMark`, 17 Tests.
- app.js: löst beim Zeilenwechsel auf, aber nur in der Zeile, in der auch
getippt wurde — ein bloß durchgeklicktes fremdes Dokument bleibt
zeichengenau stehen (sonst fiele es aus dem Nachziehen, D27).
Falle, zum zweiten Mal dieselbe: `execCommand` verweigert re-entrant im
`input`-Ereignis den Dienst, `replaceTextUndoable` fällt dann auf
`src.value =` zurück und löscht die Undo-Historie. Gemessen: erstes
Rückgängig ohne Wirkung, jedes weitere `false`. Jetzt einen Zug später
(`setTimeout 0`) und nur mit Fokus im Textfeld; danach nimmt ein Rückgängig
genau die Auflösung zurück.
SPEC §9 + D55; Plan: #ed.shortid [x] (159 Knoten, 0 Warnungen).
288 Tests grün (271+17).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- #ed.snaps.manual: Save a state by hand, before a larger change (XS) %% ten minutes is the wrong beat for that moment
Gemeldet: „I took a manual snapshot ... List is empty." Nachgestellt und
bestätigt — schlimmste Bauart: nichts gespeichert, Knopf bestätigte
trotzdem.
Ursache ist der Denkfehler aus D54-Nachtrag 1: `snapshotNow()` vergleicht
bei leerer Liste gegen `snapBase`, den Text beim Öffnen des Dokuments. Für
den Takt richtig (bloßes Ansehen sammelt nichts), für den Knopf falsch. Die
Begründung „bei unverändertem Text steht er schon oben in der Liste" gilt
eben nicht, wenn die Liste leer ist — und das ist genau der Anlass des
Knopfes: öffnen, sichern, DANN ändern. Die frühere Messung begann mit einer
Eingabe und prüfte damit die Wirkung, nicht den Anlass.
- `snapshotNow(manuell)`: Die snapBase-Sperre gilt nur noch für den Takt;
der Knopf vergleicht allein gegen den letzten Eintrag.
- `loadSnapshot()` sagt jetzt ebenfalls `true` — bewusstes Wegleg-Ereignis.
- `setInterval(() => snapshotNow(), …)`: Ein durchgereichtes Argument wäre
wahr und hebelte die Sperre aus (dieselbe Falle wie D17-Nachtrag 4).
Nachgemessen — Knopf: 10 Zeilen, Klick ohne jede Eingabe -> [10]; nach einer
Änderung -> [10,11]; ältesten laden -> zurück auf 10, kein Doppel-Eintrag.
Takt (2 s für die Prüfung): nur angesehen, 3 Takte -> 0; nach Änderung -> 1;
weitere Takte -> 1.
D54-Nachtrag 2. 243 Tests grün (die Stände selbst sind nicht test-gedeckt,
sie leben in app.js — Lücke benannt).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zehn Minuten sind der falsche Takt für den einen Moment, in dem man einen
Stand wirklich will: unmittelbar vor einer größeren Änderung. Dann ist der
letzte selbsttätige Stand im Zweifel neun Minuten alt.
- Kamera statt Plus: Ein `+` neben dem Dokument-Namen läse sich als „neues
Dokument“, ein Lesezeichen als „Favorit“. Gegen Uhr (Verlauf) und Caret
(Dokumentwahl) ist die Kamera eindeutig.
- Die Rückmeldung kommt IMMER, auch wenn nichts angelegt wurde: Der Knopf
verspricht „dein Stand ist gesichert“, nicht „ein Eintrag wurde erzeugt“.
Bei unverändertem Text steht er schon oben in der Liste — einen doppelten
Eintrag zu erzwingen kostete nur einen der 20 Plätze.
- Gezeigt per vorhandenem Haus-Idiom (`flashBtn`, 1,5 s Haken); dafür nur
`.copybtn.done .ic-copy` um `.ic-main` erweitert.
- Pad-Fall folgt von selbst: beide Knöpfe in EINER Zuweisung versteckt.
- i18n `snapAddTooltip` in 9 Sprachen; der Leer-Text des Menüs nennt jetzt
beide Wege.
Nachgemessen: 0 -> Klick -> 1 (Haken sichtbar, nach 1,7 s wieder Kamera);
zweiter Klick ohne Änderung -> weiterhin 1, Rückmeldung trotzdem; nach einer
Änderung -> 2. Im schmalen Layout kostet der Knopf nichts (Kopfhöhe 44 px
und Zeilenzahl mit und ohne ihn identisch).
D54-Nachtrag; Plan: #ed.snaps.manual [x] (158 Knoten, 0 Warnungen).
243 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- #not.llms.index: llms.txt, the signpost that points at it (XS) %% the convention wants an index, not the content
- #ed.lineno.tip: The warning is the tooltip of its number (XS) %% no hunting in the list
Die Spaltentrenner beider Tabellen (Gate, Statusbox) stehen jetzt
untereinander; nachgemessen liegen die Pipes in jeder Zeile auf denselben
Spalten (7/27/79 bzw. 8/27/70).
Stolperstein: In der Gate-Tabelle ist `\|` ein Wert, kein Spaltentrenner.
Ein Splitter, der stumpf an jedem `|` trennt, zerlegt die Zeile in vier
Spalten und schiebt "any of" in die dritte — passiert und zurückgenommen;
getrennt wird an `(?<!\\)\|`. Reine Quelltextformatierung, das gerenderte
Markdown ist unverändert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Anlass war die Frage, ob `llms.md` ein guter Name ist. Zwei Befunde:
1. Der Zweck der Konvention ist ein anderer, als D43 annahm. llmstxt.org
über die eigene Datei: „a markdown file that provides brief background
information and guidance, along with links to markdown files providing
more detailed information“ — ein Index, kein Inhalt. Der 211-Zeilen-
Leitfaden ist genau eine jener verlinkten Dateien; `llms.md` ist damit
der richtige Name, es fehlte der Wegweiser davor.
2. `llms.md` kam auf der stabilen Instanz falsch kodiert an: Apache kennt
`.md` nicht und sendet GAR KEINEN Content-Type, der Browser rät
windows-1252. Gemessen: characterSet=windows-1252, aus „notation —
guide“ wurde „notation â€" guide“, 31 Zeilen betroffen. GitHub Pages
liefert dieselbe Datei korrekt als text/markdown; charset=utf-8 aus.
- frontend/public/llms.txt: Index nach der Konvention (Titel, Blockquote,
Notation in Kurzform, ## Docs, ## Optional). Rein ASCII — er ist die
Datei, die ein fremder Agent ungefragt abruft, und soll auch dort
ankommen, wo ein Server die Kodierung verschweigt. Alle 5 Links: 200.
- scripts/prod.htaccess: AddType für .md/.txt/.werkbaum, von
deploy-prod.sh als .htaccess gespiegelt. Nicht in public/ — dort landete
es wirkungslos im Pages-Artefakt. Rückweg bei 500 steht in der Datei.
- Beide Deploy-Wege kopieren llms.txt mit.
SPEC §13 + D43-Nachtrag 2 (mit Richtigstellung der D43-Annahme);
Plan: #not.llms.index [x]. 243 Tests grün, Plan 157 Knoten, 0 Warnungen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Streifen sagte bisher nur, DASS eine Zeile eine Warnung hat; welche,
stand allein unter dem Diagramm — man sah die orange Zahl und suchte dann
in der Liste die passende Zeilennummer.
- warnings.js: `warningText()` neben `formatWarning()`, beide aus demselben
`switch` (`build(w, t, esc)`) — der Warnungsbereich ist HTML, ein `title`
ist Klartext. Ohne die Trennung stünde dort „Drag & Drop“.
- app.js: `lineNoWarn` ist jetzt Map Zeile -> Text; mehrere Warnungen einer
Zeile stehen im Tooltip untereinander. Titel verschwinden mit der Warnung.
- style.css: Der Kasten der Warn-Zahl reicht über die ganze Streifenbreite
(Ziffern bleiben punktgenau stehen, nachgemessen 21,14 px), `cursor:help`.
Nachgemessen (4 Warnungen in 3 Zeilen): Tooltips wortgleich mit dem
Warnungsbereich, `&`/`"` unverfälscht, keine Zahl ohne Warnung mit `title`;
nach dem Beheben verschwinden Klasse und Titel mit. Werkbaum-Plan: 0.
SPEC §9 (Zeilennummern) + D33-Nachtrag; Plan: #ed.lineno.tip [x].
243 Tests grün (3 neue).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- #ed.mobile.tip: A tap on a node opens its tooltip as a window (XS) %% no pointer, no tooltip
- #ed.snaps: Earlier states of a document, every ten minutes (S) %% only when something changed
Alle 10 Minuten wird der Text des aktiven Dokuments weggelegt — aber nur,
wenn er sich seit dem letzten Stand geändert hat. Aufgehoben werden die
letzten 20 je Dokument (Nutzer-Entscheidung; rund 3,5 Stunden, max. ~800
kB beim größten Dokument). Angeboten werden sie über einen Knopf rechts
neben dem Dokumenten-Wähler, neueste zuoberst, je mit Uhrzeit und
Zeilenzahl.
„Nur bei Änderung" heißt: gegen den letzten Stand, und solange es keinen
gibt, gegen den Text beim Aktivieren des Dokuments. Ohne das legte der
erste Takt nach dem Öffnen auch ein unverändertes Dokument weg.
Die Dokumente sind wichtiger als ihre Stände: Beide teilen sich den
localStorage, also wirft persistSnaps() bei Überlauf den jeweils
ältesten Stand weg, bis es passt, notfalls alle — statt das Speichern
der Dokumente zu gefährden. Ein gelöschtes Dokument nimmt seine Stände
mit. Pad-Dokumente (D31) sammeln keine: Ihr Feld ist schreibgeschützt,
ein alter Stand ließe sich dort nicht einsetzen.
Zurückgeholt wird undo-fähig (replaceTextUndoable, D53) — ein Griff
daneben kostet ein Strg+Z, keine Rückfrage. Vorher wird der aktuelle
Stand weggelegt, sonst wäre gerade er das Einzige, was das Zurückholen
verlöre.
Beim Bauen korrigiert: Das Menü war an der Gruppe ausgerichtet
(right:0) und begann 190 px weiter links, also außerhalb des Panels
(gemessen: linke Kante bei -65 px). Bezug ist jetzt der Knopf.
Nachgemessen (Takt für die Prüfung auf 2 s verkürzt, danach
zurückgestellt): ohne Eingabe kein Eintrag, nach einer Eingabe genau
einer, ohne weitere keiner dazu; nach 29 Änderungen 20 (gedeckelt,
Zeitstempel aufsteigend). Klick auf einen älteren Eintrag lädt ihn
(36 -> 32 Zeilen), Diagramm zeichnet neu, undo holt den vorherigen Stand
zurück. Plan: 155 Knoten, 0 Warnungen. 240 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zwei gemeldete Fehler, eine Zeile:
src.value = value.slice(0, s) + ' ' + value.slice(eEnd);
1. Sie schneidet den markierten Bereich heraus — mehrere markierte
Zeilen wurden also durch zwei Leerzeichen ERSETZT. Ohne Auswahl fügt
derselbe Ausdruck nur ein, deshalb fiel es nie auf.
2. `src.value =` löscht die Undo-Historie des Textfelds vollständig
(D38-Nachtrag 2 hatte das gemessen, aber nur beim Zurückschreiben der
Faltung beherzigt). Betroffen war damit alles davor Getippte. Erneut
gemessen, alte Zeile nachgestellt: erstes `undo` ändert nichts,
zweites liefert `false` — Stapel leer. Das ist die Antwort auf „wann
geht Undo kaputt": bei jedem Tab-Druck. Die übrigen drei
`src.value =` laden ein anderes Dokument, dorthin gibt es nichts
zurückzunehmen.
Neue Regel: ohne Auswahl zwei Leerzeichen an der Marke (Shift+Tab nimmt
sie zurück und zieht die Marke mit), mit Auswahl wird jede berührte
ZEILE ein-/ausgerückt. Verworfen war die VS-Code-Feinregel „nur bei
mehrzeiliger Auswahl einrücken": Wer eine ganze Zeile markiert, meint
auch dann Einrücken, und die einfache Regel kann nie Text löschen.
Geschrieben wird über execCommand('insertText') — ein Undo-Schritt.
Nebenbefund mitbehoben: Tab war eine Tastenfalle (WCAG 2.1.2). Esc hebt
sie für den nächsten Tastendruck auf.
Nachgemessen mit echten Tastendrücken: drei markierte Zeilen, Tab -> alle
drei von 2 auf 4 Leerzeichen, nichts gelöscht, Block bleibt ausgewählt;
Shift+Tab zurück; tippen + Tab + zweimal undo -> erst der Einzug, dann
das Getippte. Werkzeuggrenze notiert: synthetisches ctrl+z löst kein
natives Undo aus, geprüft wird mit execCommand('undo').
240 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Werkbaum soll installierbar werden. Im mitgelieferten Plan als
`#bld.pwa` (M) unter „Build and delivery", mit drei Kindern: Manifest
(XS), Service Worker (S) und die Frage, was aus der Update-Anzeige wird
(S) — je mit Beschreibungsblock nach D48. Status `[ ]`: beschlossen,
nichts investiert.
Die Vorarbeit ist getan und steht in den Beschreibungen: Der Build
liefert eine einzige Datei mit inlinten Schriften, Stilen und Modulen
(D19/D20), es gibt also genau ein Objekt zu cachen, und die Dokumente
liegen ohnehin lokal (D22). Offen ist das Zusammenspiel mit D45: Sitzt
ein Worker vor der Seite, entscheidet er, was ausgeliefert wird — „der
laufende Build gegen den, den der Server schickt" ist dann nicht mehr
dieselbe Aussage. Texte aus ?sourceUrl=/?etherpad= bleiben naturgemäß
online.
Dazu ein Eintrag unter „Kleinere Ideen" in der ROADMAP, der auf
`#bld.pwa` verweist.
Nachgemessen: 154 Knoten (150 + 4), 0 Warnungen, alle IDs eindeutig,
kein Knoten ohne Beschreibung, Stationen 24 -> 27 (die drei neuen
Blätter sind offene Pfadarbeit). 240 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein `title` braucht einen Zeiger — auf dem Telefon war die Beschreibung
(D40) damit gar nicht zu sehen, und seit D48 hängt an jedem der 172
Plan-Knoten eine. Der einfache Tipp zeigt jetzt denselben Inhalt als
Fenster.
Die eine echte Frage war der Link: Ein Knoten mit URL belegt den
einfachen Klick vollständig (SPEC §6), ein Tipp kann nicht beides tun.
Entschieden: Auf Touch öffnet der Tipp immer das Fenster, der Link steht
darin als Knopf. Damit hat die Geste dort eine Bedeutung, und die
Tooltips sind auf allen Knoten erreichbar. SPEC §6 bekommt dafür eine
Touch-Ausnahme.
Es hängt an den Touch-Ereignissen, nicht an einer Media Query — ein
Gerät mit beidem verhält sich dadurch ohne Sonderfall richtig: Finger
öffnet das Fenster, Maus öffnet den Link und zeigt den Tooltip.
Die drei Touch-Gesten unterscheiden sich am vorhandenen Zustand, ohne
neues Merkerfeld (armedEl gesetzt ⇒ Sprung, Timer läuft ⇒ Tipp, beides
weg ⇒ gescrollt). Ausgenommen ist das Falt-Zeichen: Das Fenster braucht
preventDefault(), das sonst den Falt-Klick verschluckt.
Das Fenster nutzt, was ein `title` nicht kann: echte Trennlinie statt 24
`─` (der title wird an genau diesem Strich zerlegt, TIP_RULE exportiert
— ein zweites data-Attribut hätte 20 kB DOM-Text verdoppelt), Absätze
aus Leerzeilen statt harter Quell-Umbrüche, Knöpfe. Der Sprung-Hinweis
nennt hier den langen Druck (neuer i18n-Schlüssel jumpHintTouch, plus
tipClose und tipOpenLink, je 9 Sprachen).
position:fixed auf <body>: in #out erbte es dessen zoom und würde von
dessen overflow beschnitten (D50). Zu macht es alles, was seine Aussage
hinfällig macht — Tipp daneben, zweiter Tipp, Esc, ×, Diagramm-Scroll,
Bereichswechsel, Sprung in den Text, render().
Nachgemessen (375x812): Wurzelknoten 336x220 px ganz im Bild, ein Absatz
ohne harte Umbrüche, Fakten mit Langdruck-Hinweis, Link-Knopf, Ring am
Knoten, URL nicht geöffnet; Knoten ohne Beschreibung 39 px ohne
Trennstrich; Spitze 0 px von der Knotenmitte. Echte Wischgeste
(scrollLeft 0 -> 300) schließt. Schreibtisch unverändert: Klick öffnet
den Link, Fenster bleibt zu. Plan: 150 Knoten, 0 Warnungen, 24
Stationen. 240 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Gemeldet: manche Knoten in Produktion werden grau dargestellt, etwa
`#ed.fresh`. Ursache war nicht der Status, sondern die Pfad-Inversion:
Der Knoten ist eine Zugabe (`+`) und liegt damit per D29 nie auf dem
günstigsten Pfad — `.cheap-on .node:not(.cheap)` blasste ihn aus
(Deckkraft 0,32, Sättigung 0,4; Pastellblau liest sich so als Grau).
D46 hatte „erledigt tritt nicht zurück" bereits entschieden, die Regel
hing aber an `cheapCls()` und griff nur für Knoten AUF dem Pfad. Durch
das Raster fielen die fertige Zugabe und die fertige, nicht gewählte
Alternative. Jetzt gilt sie unabhängig vom Pfad; Blässe heißt damit
einheitlich „hier ist nichts getan und wird auch nichts getan".
Umgesetzt als eigene Klasse `done` per `isDone(n)` in render.js, nicht
über `st-fertig`/`st-prod`: Die Statusklasse trägt den EFFEKTIVEN Status
(D39), die Ausnahme muss dem intrinsischen folgen — dieselbe Linie wie
bei D35, D28 und der Kostenrechnung aus D46. Gefärbt wird unverändert
nach dem effektiven Status.
Nachgemessen (Werkbaum-Plan, 149 sichtbare Knoten, Pfad an): vorher
blass und fertig waren genau drei Knoten (#ed.fresh, #ed.export.print,
#ed.closure.greedy) — jetzt alle drei opacity 1, filter none, Füllung
rgb(219,234,248) wie die fertigen Knoten auf dem Pfad. Weiterhin blass:
31 Knoten, darunter kein einziger fertiger. Der Grafikexport hatte den
Fehler nie (er liest backgroundColor, nicht opacity).
240 Tests grün (4 neue in tests/frontier.test.js).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- #ed.path.front: Only the open front: what is done costs nothing (S) %% see D46
- #ed.path.step: Step from station to station, one button (S) %% see D47
„+ Neu" legte das Dokument unter „Unbenannt" an und setzte den Cursor ins
leere Textfeld; das Umbenennen war ein eigener, zweiter Gang durchs Menü — und
wurde entsprechend oft nicht gemacht. Jetzt öffnet sich unmittelbar das
Inline-Umbenennen (D22) mit ausgewähltem Vorschlag: tippen ersetzt ihn, Enter
bestätigt.
Das Dokument existiert vorher: angelegt, gespeichert und aktiviert wie bisher,
nur der Fokus geht ins Namensfeld statt ins Textfeld. Ein Abbruch verwirft
nichts — Esc behält den Vorschlag. Der Gegenentwurf (erst benennen, dann
anlegen) hätte ein Dokument im Schwebezustand gebraucht.
Nach dem Benennen geht es im Textfeld weiter — Anlegen heißt schreiben wollen.
Der Merker `renameIsNew` unterscheidet diesen Fall vom gewöhnlichen Umbenennen
aus dem Menü, das unverändert bleibt (Menü bleibt offen, Fokus wandert nicht);
`closeDocMenu()` setzt ihn mit zurück, sonst trüge ein abgebrochener Vorgang
seine Sonderbehandlung in den nächsten hinein.
Nachgemessen: Nach „+ Neu" hat das Eingabefeld den Fokus und der Vorschlag ist
vollständig markiert. Enter mit „Sprint 15" -> Titelzeile, `werkbaum-docs` und
Fokus im leeren Textfeld stimmen. Esc -> Vorschlag bleibt, Menü zu, Fokus im
Text. Bestehendes Dokument umbenennen -> Menü bleibt offen, Fokus bleibt.
236 Tests grün.
Grenze der Prüfung, benannt: Der Fokusverlust ließ sich nur als zugestelltes
Ereignis prüfen, nicht als echter Fokuswechsel — ein synthetisches `.blur()`
löst im Automaten keinen aus. Gegenprobe am unveränderten Pfad zeigt dasselbe,
es ist also die Werkzeuggrenze und keine Regression (Lehre aus D25).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Gemeldet: „Dokumente aufklappen/auswählen funktioniert in Mobilansicht nicht."
Regression aus D47, einen Tag alt.
Ursache: Das dort eingeführte `overflow-x:auto` macht aus der Titelzeile einen
Scroll-Container — und beide Aufklapp-Menüs hängen als absolut positionierte
Kinder genau darin (`#docMenu` im Editor-Kopf, `.dlmenu` im Diagramm-Kopf).
Übersehen war dabei eine CSS-Regel: `overflow-x` auf etwas anderes als
`visible` hebt ein `visible` der ANDEREN Achse auf `auto`. Geklippt wurde also
nicht seitlich, sondern nach unten — dorthin, wo die Menüs aufklappen. Und ein
Scroll-Container klippt, ob er überläuft oder nicht: Der Fehler traf jede
Mobilbreite, nicht nur die schmalen, für die die Regel gedacht war.
Nachgestellt bei 375 px: Das Dokumenten-Menü ist 153 px hoch und beginnt
156 px unterhalb der Kopfunterkante (clientHeight 43, scrollHeight 200);
`elementFromPoint` an seiner Stelle liefert das Textfeld. Beim Download-Menü
dasselbe. Das Menü war also nicht schwer zu treffen, sondern gar nicht da.
Behoben durch Wegnahme: kein `overflow` mehr an der Zeile. An seine Stelle
tritt Umbrechen, aber nur unter 360 px, wo neun Fingerziele arithmetisch nicht
nebeneinander passen; darüber bleibt `nowrap`. Erwogen und verworfen war,
die Menüs per `position:fixed` aus dem Container zu heben — JS-Geometrie für
etwas, das CSS allein konnte, und der Preis stand in keinem Verhältnis: Das
`overflow` diente nur Breiten unter 360 px, kaputt waren die Menüs überall.
`flex:0 0 auto` gegen den zerdrückten Modus-Wähler bleibt.
Nachgemessen — und zwar die Bedienung, nicht die Geometrie, denn genau darin
war der Fehler unsichtbar (die Zeile war weiter 49 px hoch, alle Knöpfe an
ihrem Platz): Bei 375 px und 320 px trifft `elementFromPoint` im geöffneten
Menü `.docitem` bzw. `.dlmenu`, und ein Klick wechselt das Dokument wirklich
(Werkbaum -> Example: Titel, `werkbaum-active`, neu gebauter Baum). Kopfzeile
375 px eine Reihe zu 49 px, 320 px zwei Reihen zu 78 px mit allen neun
Elementen vollständig sichtbar. Desktop unverändert. 236 Tests grün.
D47 bekommt den Verweis, dass sein `overflow` zurückgenommen ist; gelöscht
wird dort nichts. frontend/CLAUDE.md warnt jetzt vor `overflow` an Leisten,
die Menüs tragen — samt dem Hinweis, dass man das nicht an Maßen sieht.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Gewünscht — und damit die ausdrückliche Umkehrung der D33-Abwägung
(„Verworfen: wrap=off … der Umbruch ist die wichtigere Eigenschaft"). Der dort
notierte Preis bleibt richtig; nicht bedacht war die andere Seite: Ein weicher
Umbruch zerstört die Einrückung, und die trägt in dieser Notation die
Hierarchie. Die Fortsetzung einer umbrochenen Zeile beginnt am linken Rand und
sieht aus wie ein Wurzelknoten — betroffen sind genau die langen Zeilen, also
die mit ID, Größe und Kommentar, seit D48 praktisch jede Zeile des Plans.
Umgesetzt als `wrap="off"` am Element (Eigenschaft des Feldes, nicht seiner
Gestaltung), `overflow:auto` daneben im Stylesheet.
Der Spiegel musste mit: `syncMirror()` maß mit `white-space:pre-wrap` und
fester Breite — genau die Kombination, die im Spiegel Zeilen umbräche, die im
Textfeld ungebrochen stehen; alles darunter läge zu tief und die
Zeilennummern wanderten weg. Jetzt `pre` und ohne Breitenvorgabe. Gemessen
wird trotzdem weiter statt `Zeilenhöhe × n` zu rechnen: Die Schriftgröße
unterscheidet sich zwischen Telefon und Schreibtisch, die Messung stimmt in
beiden Fällen von selbst.
Der Sprung setzt `scrollLeft` zurück. `jumpToLine()` markiert die ganze Zeile,
woraufhin der Browser von sich aus an deren Ende scrollt — man landete am
rechten Rand, ohne Einrückung, Zeichen und Statusbox zu sehen. Der Sprung
zeigt auf eine Zeile, nicht auf ihr Ende.
Nachgemessen am Plan (903 Zeilen, längste 122 Zeichen): 903 Bildzeilen zu 903
logischen Zeilen in beiden Ansichten; Schiebeweg 211 px am Schreibtisch, 432 px
auf 375 px Breite; der Zeilennummern-Streifen bleibt beim waagerechten
Verschieben stehen (linke Kante unverändert bei 180 px Versatz); Abweichung
der Zahlen am Dateiende 2 px auf 903 Zeilen (Rundung von `offsetTop`, sammelt
sich nicht auf). 236 Tests grün.
SPEC §9 (Zeilennummern) und D49 halten es fest; die D33-Stelle bekommt einen
Verweis, dass die Abwägung umgekehrt wurde — gelöscht wird dort nichts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der mitgelieferte Plan ist Vorzeigedokument und Projektübersicht zugleich —
und war für Fremde weitgehend stumm. „Stay greedy, but say so" oder „Cycles
are legal" sagt jemandem, der die DECISIONS nicht gelesen hat, nichts. Jetzt
trägt jeder der 172 Knoten eine ID und einen erläuternden Block.
Langform hinter dem `---`-Trenner statt `"`-Zeilen: Bei 172 Knoten
verdreifachte die Kurzform die Höhe des Baumteils und machte ihn unlesbar —
gerade das, was der Plan zeigen soll. Genau der Fall, für den die Langform
gebaut wurde (D40). Die eine vorhandene `"`-Zeile an „Collaborating" bleibt
stehen und führt die Kurzform weiter vor; beide Formen zum selben Knoten
hängen sich planmäßig aneinander.
ID-Schema `#bereich.task`, dritte Stufe nur wo nötig: acht Bereiche mit kurzen
Kürzeln (not, ed, bld, be, col, mmd, idea, trk), Wurzel `#wb`. Vier bereits
vergebene IDs sind ins Schema gewandert (`#closure` -> `#ed.closure`,
`#scaffold` -> `#be.scaffold`, `#docs` -> `#be.docs`, `#resolve` ->
`#trk.resolve`), die fünf `:#…`-Verweise darauf mit.
Englisch wie der Plan, ein bis zwei Sätze je Knoten: was es ist und warum es
im Plan steht.
Nachgemessen: 172 Knoten, 172 eindeutige IDs, kein Knoten ohne Beschreibung,
0 Warnungen, Pfad weiterhin exakt mit 24 Stationen. Im Editor tragen alle 149
sichtbaren Knoten die ”-Marke, der Tooltip zeigt Text, Trennstrich und
Kurz-Fakten; der Cursor in einem Block wählt den beschriebenen Knoten aus
(D40-Nachtrag 2, auf Kopf- und Textzeile geprüft, der Trenner selbst wählt
nichts). Datei 189 -> 902 Zeilen, Bundle 443 -> 506 kB (gzip 247 -> 270 kB).
236 Tests grün.
CLAUDE.md hält fest, dass neue Knoten immer zu zweit anzulegen sind: Zeile im
Baum und Block unten.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
Der Plan war zuletzt bei be72923 angefasst worden; seither sind vier
Funktionen dazugekommen, die er nicht kannte. Nachgetragen als vier Knoten:
- Faltung: „Fold and unfold in the diagram" sagte noch „independently of the
text" — das stimmt seit D38-Nachtrag 2 nicht mehr und ist korrigiert; dazu
zwei neue Kinder für das Zurückschreiben der Marke und den Falt-Umschalter
(D44).
- Günstigster Pfad: „Only the open front: what is done costs nothing" (D46).
- Build und Auslieferung: „Says when a new build is out" (D45).
Status nach D30 vergeben, nicht pauschal: Was im deployten Stand f1ac57c
enthalten ist, ist auf werkbaum.javagil.de wirklich live und bekommt `[^]` —
Zurückschreiben der Faltmarke, Falt-Umschalter und die Update-Prüfung. Allein
der status-bewusste Pfad (c793bf0) ist noch nicht deployt und steht auf `[x]`;
der nächste Prod-Deploy befördert ihn und lässt ihn als neu aufleuchten.
Bugfixes bekommen keine Knoten (vertikale Sammelleiste, Mobil-Titelzeile,
Bildschirmtastatur, Zeichenebenen, einzelne Station) — der Plan ist eine
Funktionsübersicht, kein Änderungsprotokoll.
Nachgemessen: 171 Knoten, 0 Warnungen, Pfad exakt gerechnet, 24 Stationen
(unverändert — die neuen Knoten sind erledigt und kosten nichts). Im Editor
neu eingespielt: der `[x]`-Knoten steht grün und ohne Stationspunkt auf dem
Pfad, die beiden `[^]`-Knoten tragen den gelben Kranz.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
Gemeldet: In der vertikalen Ansicht liegt der Abzweig rechts vom Knoten zu
dicht am Knoten, das Größen-Badge rendert in die senkrechte Linie hinein und
die verschwindet dort.
Nachgemessen im Werkbaum-Plan: Das Badge sitzt per `right:-9px` an der
Knotenecke und endet 8 px hinter der Knotenkante, die Sammelleiste beginnt bei
9 px — **1 px Luft**. Dazu trägt das Badge einen 1,5 px breiten Rand in
Kartenfarbe, der die verbleibende Trennung optisch auffrisst; dieselbe Enge
gilt für die Tag-Pillen unten rechts.
Behoben wie vorgeschlagen: Der Stub aus dem Elternknoten wird länger, die
Leiste rückt von 9 auf 20 px. Umgesetzt über eine Variable `--rail` auf der
`ul.and` — Leiste, Abzweig und Zellen-Innenabstand lesen sie gemeinsam, der
21-px-Ast zum Kind bleibt unverändert. Damit trifft die Änderung nur den
vertikalen Rechts-Fächer; **kompakt** teilt sich zwar die Basisregeln, behält
aber 9 px (dort läuft all-of nach unten, Badge und Leiste begegnen sich nie).
Nachgemessen nach der Änderung: 12 px Luft, alle 122 Abzweige treffen weiter
die Knotenmitte (0 daneben), alle 69 Stationspunkte des günstigsten Pfads
liegen exakt auf ihren Blattknoten (Abweichung 0 px, in vertikal wie
horizontal). Kompakt: `--rail` 9 px, Innenabstand 30 px — unverändert.
222 Tests grün.
SPEC §9 (Geometrie-Invarianten) hält die Regel fest.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der Hinweis erschien oft für genau die Fassung, die gerade geladen war. Zwei
Fehler mit derselben Wurzel — die Prüfung verglich nie mit dem laufenden Stand:
- Relais statt Vergleich: der abgerufene Inhalts-Hash wurde gegen den ZULETZT
ABGERUFENEN gehalten (localStorage), nicht gegen den laufenden. Beim Deploy
antworten CDN-Knoten unterschiedlich; jeder Wechsel schlug an, und der
Schlüssel wird von allen Tabs geteilt.
- Klebendes Flag: `werkbaum-update-available` entfernte nur „Jetzt laden".
Nach F5 oder „Später" blieb es stehen, und der Load-Check zeigte das Banner
bei jedem weiteren Laden erneut.
Verglichen wird jetzt der Commit aus dem Footer-Versionslink der laufenden
Seite gegen den der abgerufenen HTML (D16 spritzt ihn in beiden Deploy-Wegen
ein). Kein localStorage dazwischen; beim Laden wird nichts gemeldet, die
Prüfung zwei Sekunden später holt es nach. Eine spätere „aktuell"-Meldung
sammelt Banner und Footer-Symbol wieder ein. Rückfall auf den Inhalts-Hash
für Builds ohne Marker (Dev-Server), Vergleichsstand dort der erste Abruf
der Seiten-Sitzung.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mit dem achten Knopf (Falt-Umschalter, D44) ging die Zeile auf drei Reihen
und 86 statt 49 px — und fraß die Fläche, für die es den Ein-Bereich-Modus
gibt. Die Knöpfe waren nicht das Problem: Ihre Breiten summieren sich bei
375 px auf 243 px. Die Abstände brachten den Rest — gap:14px mal sieben plus
2×16 px Innenabstand sind mehr als ein Drittel des Bildschirms.
Auf Mobil deshalb gap:8px und padding-inline:10px, dazu flex-wrap:nowrap als
Riegel: Ohne ihn wäre der Umbruch nur hinausgeschoben und käme beim nächsten
Knopf unbemerkt zurück. Die Knöpfe selbst bleiben bei 29 px (Fingergröße).
Nachgemessen mit allen acht Bedienelementen — der freshBtn ist der, der die
Zeile kippen ließ, weil er nur bei fremden Dokumenten mit Neuigkeiten
erscheint: bei 375 px eine Reihe (49 px), bei 320 px eine Reihe mit 10 px
Luft. Desktop bleibt bei 14 px unverändert.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Statt eines Aufklapp-Menüs mit zwei Einträgen jetzt ein Umschalter neben
„verworfene einblenden" und „günstigster Pfad". Die beiden Einträge waren nie
unabhängige Befehle, sondern die zwei Stellungen einer Sache — jeder
beschreibt einen vollständigen Faltzustand, zusammen decken sie ihn ab.
Die Schwelle schließt M jetzt ein (atMostM statt belowM): Ein M-Paket ist
selbst noch die Einheit, die man als Ganzes plant, seine Zerlegung ist schon
das Innere. Offen bleiben L, XL, XXL — und Knoten ohne Größenangabe.
Der Zustand des Knopfes wird bei jedem Rendern am Baum abgelesen, nicht
gemerkt: Klappt jemand danach einen Knoten von Hand um, springt er von selbst
heraus, statt etwas zu behaupten, das nicht mehr stimmt. Deshalb auch nicht
persistiert — der Faltzustand steht im Text.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ein Menü mit zwei Einträgen: alle aufklappen, unter Größe M zuklappen.
Das Kriterium ist die Größe, nicht die Tiefe. Die Ebene ist eine Eigenschaft
der Schreibweise — ein fein zerlegter Zweig verschwände bei derselben Zahl
früher als ein grob notierter. Die T-Shirt-Größe sagt etwas über die Arbeit,
und ab M muss ohnehin zerlegt sein (SPEC §5): „unter M" ist genau die Menge,
die keine Zerlegung mehr braucht.
Ohne Größenangabe wird nicht zugeklappt. Der günstigste Pfad wertet fehlende
Größen als M (D18), aber das ist eine Kostenannahme, keine Aussage des Autors.
Beide Einträge beschreiben einen vollständigen Zustand — sonst hinge die
Wirkung vom Vorzustand ab. Rückgängig nimmt den ganzen Vorgang in einem
Schritt zurück.
Umgesetzt über denselben Weg wie das einzelne Umklappen; der Voll-Rewrite ist
dafür aus writeFoldToText() in writeAllFoldMarks() gewandert. Die
Rückfall-Kette gilt unverändert: Im Werkbaum-Plan ist der Zustand wegen einer
Fokusmarke nicht in Marken ausdrückbar, dort trägt die Sitzungs-Überlagerung.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der aktive Knoten deckte seinen eigenen Stationspunkt zu. Ursache ist der
z-index:3 der Cursor-Zeile (D25-Nachtrag 1) — dort richtig begründet, aber
mit einer zweiten Wirkung, die nicht mitgedacht wurde: Er hebt den Knoten
über jede Ebene ohne eigene Stapelposition, und svg.cheap-front hatte keine.
Betroffen war nicht nur die Cursor-Zeile: Die Strahlenkränze tragen aus
demselben Grund z-index:2 (D28/D32), und svg.dep-front hing mit dran — die
hervorgehobenen Abhängigkeits-Kanten gehören zum ausgewählten Knoten und
endeten deshalb unter ihm.
Behoben an der Ebene, nicht am Knoten: dep-front 4, cheap-front 5. Die
hinteren Ebenen bleiben ohne z-index, dort trägt die DOM-Reihenfolge.
Export und Druck waren nie betroffen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
drawCheapPath() stieg bei weniger als zwei Stationen ganz aus. Solange ein
eingeklappter Knoten nur einen Zweig vertrat, fiel das nicht auf; klappt man
den Wurzelknoten zu, bleibt genau eine sichtbare Station — und damit
verschwand neben der Linie (richtig) auch der Stationspunkt (falsch), also
der Pfad genau dort, wo die Faltung ihn am nötigsten vertreten muss.
Die Zwei-Punkte-Schranke gehört an die Linie, nicht an die Zeichenfunktion;
im Grafikexport dieselbe Trennung.
Dabei gefunden: Der zugeklappte Wurzelknoten des Werkbaum-Plans ließ sich
nicht wieder aufklappen. Dort ist der Zustand nicht in Marken ausdrückbar
(das `<` in Zeile 160 holt seinen Teilbaum hervor), liegt also in der
Sitzungs-Überlagerung. Beim Aufklappen ergab das einen unveränderten Text —
replaceTextUndoable() meldete Erfolg, ohne Textänderung feuert aber kein
input-Ereignis, also lief kein render(). Jetzt meldet sie „nichts
geschrieben", und der Aufrufer zeichnet selbst neu.
Außerdem: Faltmarken-Stellung auch in den Schreibregeln von llms.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`- > [x] Backend` wird zu `- [x] > Backend`. Die alte Stellung verschob die
Statusbox um genau eine Einrückungsstufe — die Box einer gefalteten Zeile
stand damit in der Spalte der Boxen ihrer eigenen Kinder. Vor dem Label
kostet die Verschiebung nichts, weil Labels ohnehin ausgefranst sind.
Nebengewinn: Die Regel wird einfacher. Statt „zwischen Zeichen und Statusbox,
bei Wurzelknoten am Zeilenanfang" heißt sie jetzt ausnahmslos „unmittelbar
vor dem Label"; für Zeilen ohne Statusbox ändert sich nichts.
Die alte Stellung wird weiter gelesen (Pads und ?sourceUrl=-Quellen lassen
sich nicht migrieren), aber nie mehr geschrieben — setFoldMark() löst sie in
die neue auf. SPEC §1 hält zusätzlich fest, dass `<` gelesen, aber nie
erzeugt wird.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Erster Schritt der Schreibrichtung Diagramm -> Text. Damit ist der Text auch für
die Faltung die eine Quelle der Wahrheit (D14): Was man sieht, steht
geschrieben, und ein Neuladen stellt es wieder her. Kehrt die bisherige
Festlegung aus D34/D38 um („die Marken bestimmen nur den Anfangszustand").
Verfahren: minimal patchen, dann nachrechnen. Die Ableitung Text -> Zustand ist
nicht umkehrbar — mehrere Markensätze ergeben denselben Zustand, und `<` faltet
Knoten, die gar keine Marke tragen. Statt zu invertieren wird der Kandidat
befragt: `>` an die eine Zeile, initialCollapsed() darauf, mit dem Soll
vergleichen. Passt es, bleibt alles andere unangetastet — so überleben von Hand
gesetzte `<`. Passt es nicht, werden alle Marken neu gesetzt (das `<` löst sich
dabei auf). Passt auch das nicht (ein `!!!` holt seinen Knoten immer wieder
hervor), wird gar nicht geschrieben: Ein Text, der etwas anderes sagt als das
Bild, wäre schlimmer als eine fehlende Marke. initialCollapsed() bleibt die
einzige Stelle, die die Marken versteht.
Undo-fähig über execCommand('insertText') — gemessen: value= UND setRangeText
machen Strg+Z wirkungslos, wer tippt und dann faltet käme an sein Getipptes
nicht mehr heran. Falten ist damit ein eigener Undo-Schritt (geprüft: einmal
Strg+Z nimmt die Faltung, ein zweites das Getippte).
Zwei gemessene Fallen: Ein Textfeld mit display:none-Vorfahr nimmt kein
execCommand an (liefert false, obwohl activeElement es meldet) — auf Mobil ist
der Editor beim Falten genau das, deshalb schaltet ihn `writing-fold` für die
Dauer des synchronen Schreibens aus dem Bild heraus sichtbar. Und der nötige
Fokus zöge dort die Tastatur hoch, dagegen inputmode="none" wie beim Sprung
(D25); danach geht der Fokus an den Knoten zurück.
Bei schreibgeschütztem Text (Pad, D31) wird nicht geschrieben — dort trägt
weiter die Sitzungs-Überlagerung. Schreibmarke und Scrollstand bleiben erhalten.
Im Browser geprüft: `<` bleibt stehen, wenn es noch stimmt, und löst sich auf,
wenn nicht; Falten bei verborgenem Editor auf Mobil; Pad-Fall sitzungsweise;
Hin- und Herklappen führt zeichengenau zum Ausgangstext zurück.
7 neue Tests für setFoldMark (215 gesamt). SPEC §1/§9, D38 (Nachtrag 2) und
frontend/CLAUDE.md nachgezogen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
D38 hielt fest, ein eingeklappter Zweig dürfe Pfadknoten verbergen, „die
Inversion an den sichtbaren Knoten bleibt richtig". Zu kurz gedacht: Die LINIE
blieb eben nicht richtig. Sie fädelt durch die cheap-leaf-Knoten im DOM; ein
eingeklappter Pfadknoten ist zwar `cheap`, aber kein Blatt (seine Pfad-Kinder
existieren im Modell) — also bekam er keine Station, und die Linie umging den
ganzen Zweig.
Im Beispiel nachgemessen: „Concept" war `node cheap folded`, verbarg zwei
Pfadknoten, trug keinen Punkt; die Linie begann erst bei „PWA". Das Bild
behauptete damit, in diesem Zweig sei nichts zu tun — eine Aussage über den
Plan, nicht über die Ansicht. Genau die Grenze, die D38 sonst zieht.
Regel: Eingeklappt überspringt cheapCls() die Blatt-Prüfung und fragt den
Teilbaum (hidesCheap). Liegt darin etwas auf dem Pfad, ist der Knoten dessen
tiefste noch sichtbare Station. Beim Aufklappen geben die Kinder sie zurück —
gemessen 6 -> 7 -> 6 Stationen beim Hin- und Herklappen.
Auch ohne eigene Pfad-Mitgliedschaft: Ein per :#… gezogenes Ziel kann unter
einem +-Knoten liegen, der selbst nicht gebraucht wird (D42). Eingeklappt ist
dieser der einzige sichtbare Griff auf nötige Arbeit — er wird Station und
zählt als cheap, tritt also nicht zurück. Ihn auszublassen wäre die Lüge.
4 neue Tests (208 gesamt). SPEC §9, D38 (Nachtrag) und frontend/CLAUDE.md
nachgezogen; die alte „hinnehmbar"-Stelle in D38 ist als falsch markiert statt
gelöscht.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die eigentliche Ursache der Meldung — meine erste Diagnose (Titelzeilen-Tipp im
alten Splitter-Modell) war für 1.1.39 richtig, aber nicht das, was der Nutzer
auf dem Pages-Build sah.
setAppHeight() schreibt visualViewport.height nach --app-height, und
body{height:var(--app-height)} macht daraus die Höhe der ganzen Seite. Genau
diesen Wert verkleinert die Bildschirmtastatur — dafür ist visualViewport
gemacht. Nachgemessen linear: Textfeldhöhe = --app-height minus ~206 px feste
Aufbauten. 812 px -> 606 px Text, 440 -> 234, 260 -> 54 px, also drei Zeilen.
Das ist das gemeldete „komplett zusammengeklappt".
Sichtbar ausschließlich auf echten Geräten: In der Emulation gibt es keine
Tastatur, deshalb liefen alle drei Reproduktionsversuche vorher ins Leere.
Unterschieden wird am Fokus, nicht an der Größe: Tastatur und überlagernde
Browserleiste (Brave, der ursprüngliche Anlass des Mechanismus) erzeugen
dieselbe Signatur — vv.height fällt, innerHeight bleibt. Die Tastatur steht
aber nur, wenn ein editierbares Feld den Fokus hat. Solange das so ist, bleibt
die letzte tastaturfreie Höhe stehen; die Seite behält ihre Größe und der
Browser schiebt den Ausschnitt zur Schreibmarke.
Mit nachgebildetem visualViewport geprüft: mit Fokus im Textfeld 812/606 px
(unverändert), ohne Fokus 440/234 px — die Brave-Leiste wirkt also weiter.
orientationchange durchbricht die Sperre (sonst behielte die Seite beim Drehen
während des Tippens das alte Hochformat); der focusout-Timer ruft
() => setAppHeight(), sonst reichte er ein wahres `force` durch.
D17 (Nachtrag 4) und frontend/CLAUDE.md nachgezogen, samt der Lehre: Ein
„nicht reproduzierbar" aus dem Emulator ist bei geräteabhängigen Meldungen
kein Befund (vgl. D25 zu synthetischen TouchEvents).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Zum gemeldeten Fehler „Cursor in den Text setzen klappt den Editor zusammen":
Auf der deployten Instanz (1.1.39, noch das alte Splitter-Modell) nachgestellt —
ein Tipp auf die Titelzeile des Diagramms, ein 49-px-Streifen unmittelbar über
dem Text, schrumpfte den Editor von 594 px auf 44 px. Beim Zielen auf die oberen
Textzeilen leicht zu treffen. Das Ein-Bereich-Modell nimmt dem die Grundlage:
kein Splitter, kein Titelzeilen-Tippen, den Bereich wechselt allein der
Umschalter. Im aktuellen Stand nicht mehr auslösbar (Maus, emulierter Touch und
synthetische Touch-Folge je ohne Bereichswechsel).
Der zweite Teil der Meldung deckte eine echte Lücke auf: Für Text -> Diagramm
gibt es nur Alt+Klick/Alt+Enter — und Alt gibt es auf dem Telefon nicht. Die
Gegenrichtung hat dort ihren langen Druck, diese hatte nichts.
Ein langer Druck IM TEXTFELD verbietet sich allerdings: Dort gehört er dem
Betriebssystem (Wort markieren, Auswahlgriffe). D25 konnte sich die Geste im
Diagramm nehmen, weil es da nichts zu markieren gibt; in einem editierbaren Feld
ist sie die Bedien-Grundlage zum Bearbeiten — sie zu überschreiben löste ein
Navigationsproblem auf Kosten des Bearbeitens, in einer Meldung, deren Kern
gerade lautet, dass Bearbeiten nicht bestraft werden darf.
Stattdessen trägt der Umschalter die Geste nebenbei: Wer aus dem Text ins
Diagramm wechselt, will bei dem nachsehen, woran er geschrieben hat — der Knopf
wird in genau diesem Moment ohnehin gedrückt. Er zentriert und markiert den
Knoten der Cursor-Zeile (focusNodeOfCaret, identisch zum Alt+Klick am
Schreibtisch); auf einer Zeile ohne Knoten wird nur umgeschaltet.
SPEC §9 und D17 (Nachtrag 3) nachgezogen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bisher fiel die Hervorhebung weg, sobald der Cursor von der Knotenzeile auf die
`"`-Zeile darunter rückte: Die trägt keinen Knoten, also fand die Zeilensuche
nichts. Falsche Auskunft — sie trägt keinen EIGENEN Knoten, gehört aber zu
einem, und wer in ihr schreibt, arbeitet an genau diesem.
Gilt für beide Formen, nicht nur die Kurzform: Die Zuordnung entsteht an
derselben Stelle im Parser, an der auch die `---`-Blöcke landen, und dort trägt
die Begründung sogar weiter — der Langtext steht am Dateiende, weit weg von
seinem Knoten. Zugeordnet werden Textzeilen, Block-Kopfzeile (sie nennt den
Knoten) und Leerzeilen innerhalb eines Blocks; nicht der `---`-Trenner und
nichts unter unbekannter ID.
`node.descLines` entsteht im Parser, der Renderer gibt sie als
`data-desc-lines="3 4 5"` aus, app.js trifft sie per `[data-desc-lines~="N"]`.
Bewusst getrennt von `descLines` (dem Text): Dort fallen Leerzeilen zu einem
Absatztrenner zusammen und Blocktext unter unbekannter ID kommt gar nicht an.
Beide Richtungen gehen jetzt über eine Auflösung (`nodeOfLine()`) — sonst wäre
der ausdrückliche Alt+Klick aus einer Beschreibung heraus stumm geblieben, und
das ist gerade der Ort, an dem man ihn braucht.
5 neue Tests (204 gesamt). SPEC §9 und D40 (Nachtrag 2) nachgezogen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bisher hing alles an derselben ` · `-Aufzählung: Auf die letzte Zeile des
Fließtexts folgte unmittelbar `· #cms · geplant · Alt+Klick: …`. Der Übergang
war nicht zu sehen, obwohl dort die Art der Aussage wechselt — vorn ein Satz,
den jemand geschrieben hat, hinten Metadaten, die das Werkzeug kennt.
Jetzt: Leerzeile plus Trennstrich dazwischen. Der Strich ist aus `─` (U+2500)
gebaut, nicht aus Bindestrichen — das Box-Drawing-Zeichen stößt gapless
aneinander und liest sich als Linie, `---` liest sich als Text; mehr kann ein
`title` nicht, dort gibt es kein Markup.
Zwei Randbedingungen: Der Strich steht nur, wenn beide Teile da sind (ohne
Beschreibung bleibt der Tooltip unverändert), und mit 24 Zeichen ist er
schmaler als die Fakten-Zeile mit dem Sprung-Hinweis — er verbreitert den
Tooltip also nie.
Nicht in den aria-label: Ein Screenreader läse vierundzwanzig Striche einzeln
vor, und die Kommaliste dort ist ohnehin schon gegliedert.
2 neue Tests (199 gesamt), der bestehende Tooltip-Test nachgezogen.
SPEC §9 und D40 (Nachtrag) ebenso.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Debug-Panel: Ein Klick entfernte es bisher ganz — was nichts half, weil der
15-Sekunden-Takt es sofort wieder aufbaute; auf dem Telefon verdeckte es damit
dauerhaft die untere rechte Ecke. Jetzt schaltet der Klick zwischen Kasten und
einem 26-px-Icon (⟳) unten rechts um. Der Zustand liegt im localStorage, nicht
am Element: Das Panel wird bei jedem Takt neu bespielt, ein Zustand am DOM-Knoten
wäre beim nächsten Tick weg. Über einen echten Intervall-Durchlauf geprüft.
Der aufgeklappte Kasten bekommt white-space:pre-wrap — die mit \n gefügten
Zeilen liefen bisher zu einem Absatz zusammen.
Mobil ~25 % kleiner: MOBILE_ZOOM=0.75 als Faktor AUF den Nutzer-Zoom, nicht als
neuer Anfangswert — sonst wäre die Verkleinerung nach dem ersten Zoomen weg und
„Zurücksetzen" führte auf eine Größe, die auf dem Telefon zu groß ist. Die
Anzeige nennt den effektiven Wert (75 %), sie soll beschreiben was man sieht.
Die drei Messstellen rechnen jetzt effZoom() zurück; nachgemessen bei 0,75
liegen alle fünf Stationspunkte exakt auf ihren Blattknoten (0 px).
Der Text kann kein zoom bekommen — Zeilennummern-Streifen und Spiegel messen am
Textfeld (D33) und die Streifenbreite rechnet in ch. Also font-size .64rem an
Textfeld und Streifen gemeinsam, Innenabstand im selben Verhältnis mit.
27 statt 19 Zeilen im Bild.
Dabei aufgefallen: Der Grafikexport war schon immer zoom-abhängig falsch — die
SVG-Schriftgrößen sind feste Zahlen, die Kästen gemessen. Fiel nie auf, weil
100 % der Normalfall war; mit dem Mobil-Faktor wäre es der Regelfall geworden.
diagramToSvg() stellt den Zoom für die Messung jetzt kurz auf 1 (Knoten auf dem
Schirm 143 px, im SVG 189,7 px — die unskalierte Größe).
Desktop unverändert nachgeprüft (Zoom 1, 100 %, 13,6 px). Prod-Build enthält das
Debug-Panel weiterhin gar nicht. SPEC §9, D17 (Nachtrag 2) und
frontend/CLAUDE.md nachgezogen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Auf 375 px ist für zwei Bereiche kein Platz. Die stufenlose Aufteilung (D17)
hat das nur verwaltet: Jede Stellung war ein Kompromiss, in dem beide Bereiche
zu klein waren, und sinnvoll waren praktisch nur die Extreme — also genau das,
was ein Umschalter direkt anbietet. Der Splitter kostete dabei dauerhaft eine
zweite Titelzeile plus Griff.
Jetzt: Diagramm ODER Text über die ganze Fläche, oben links ein Knopf zum
Umschalten. Er zeigt das Ziel, nicht den Zustand — anders als der Modus-Wähler
daneben, der drei Zustände hat; hier sieht man am ganzen Bildschirm, welcher
gilt. Umgesetzt als zwei feste Knöpfe, je einer pro Titelzeile, die daher kein
Icon wechseln müssen. Der Bereichstitel „DIAGRAMM" entfällt, der
Dokumenten-Wähler steht neben dem Umschalter (er gehört zum Textbereich, D22),
die übrigen Aktions-Knöpfe werden mitgeschaltet und bleiben komprimiert.
Falle beim Bauen: Ein display:none-Panel misst sich zu null, und render() läuft
bei jedem Tastendruck im Textbereich. Gemessen nach einer Eingabe bei
verborgenem Diagramm: Pfad-Linie weg, null Stationspunkte, kein --stem-x.
setMobilePane() zeichnet deshalb beim Umschalten neu (zum Diagramm dieselben
vier Schritte wie applyLayout, zum Text renderLineNos) — danach wieder 48 px
Pfadlänge, 5 Punkte, --stem-x 67,4px.
Die Sprünge (D25) holen den nötigen Bereich selbst nach vorn. Zustand in
werkbaum-ui gemerkt. Entfallen: --drow auf Mobil, --pmin-d/-e, syncPanelMins,
setMobileDrow, Titelzeilen-Tippen. Desktop unverändert (nachgeprüft).
SPEC §9, D17 (Nachtrag) und frontend/CLAUDE.md nachgezogen; paneToText/
paneToDiagram in allen neun Sprachen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Übliche Schreibweise ist jetzt `#auth: Backend` — die ID benennt den Knoten,
der Titel erläutert sie; vorn hat sie eine feste Stelle, an der das Auge sie
sucht. Der Doppelpunkt ist optional und reines Trennzeichen: Er gehört weder
zur ID noch zum Label und fällt beim Parsen weg, sonst wären `#auth` und
`#auth:` zwei verschiedene Adressen.
Geschluckt wird er nur mit folgendem Leerraum oder Zeilenende (Leerraum-Regel
wie bei `=`, `>`/`<`, `"`). Damit bleibt `#auth:#db` ID plus Abhängigkeit, und
ein Doppelpunkt im Titel bleibt stehen. Die ID-Erkennung selbst ist unverändert
— die Doppelpunkt-Gruppe ist optional; ein verlangtes `(?=\s|$)` hinter der ID
hätte bestehende Zeilen umgedeutet. Der Block-Kopf im Beschreibungsteil nimmt
den Doppelpunkt ebenfalls an.
Alle mitgelieferten Beispiele umgestellt (docs/examples/, INITIAL, llms.md);
SPEC §10 hat keine IDs. Legenden-Zeile hint_id in allen neun Sprachen.
Dazu: Alt+Klick im Textfeld zeigt jetzt dieselbe Hervorhebung wie der
Zeilenwechsel, Puls eingeschlossen — bisher unterdrückte focusNodeOfCaret()
ihn, um doppeltes Scrollen zu vermeiden, und ausgerechnet die ausdrückliche
Geste kam stiller an als das beiläufige Tippen. Getrennt über den neuen
Parameter highlightCurrentNode(moved, scroll): 'nearest' | 'center' | false.
7 neue Parser-Tests (197 gesamt). SPEC §1, D36 (Nachtrag), D25 (Nachtrag 2)
und llms.md nachgezogen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die Hervorhebung der Cursor-Zeile (D25) war zu leise. Sie benutzte denselben
Kanal, den schon jeder Knoten belegt — jeder Status hat einen Rahmen (SPEC §4);
ein weiterer Ring darunter ist ein Unterschied im Grad, nicht in der Art.
Dazu kommt jetzt Tiefe: Schlagschatten + scale(1.04). Der einzige Kanal, den im
Diagramm noch nichts belegt, also ohne Konflikt mit einer Farbcodierung. Um die
Mitte skaliert, damit die Knotenmitte erhalten bleibt (alignStems, Stationspunkte
messen genau die — nachgemessen dx=dy=0). Beim Zeilenwechsel meldet sie sich
zusätzlich mit einem einmaligen Puls (Hüpfer + auslaufender Ring auf ::after);
kein Blinken, prefers-reduced-motion schaltet ihn ab.
Behoben dabei: Die Pfad-Inversion (D18) blasste den Ring auf 0,32 aus — die
Ausnahme, die .fresh (D28) und .focusmark (D32) längst haben, fehlte für
.current als einziger, obwohl der Fall der häufigste ist (Umschalter default an,
im Beispiel 7 von 18 Knoten betroffen).
diagramToSvg() muss die Erhebung abschalten (Klasse `exporting`): Der Export
zieht die Live-Geometrie per getBoundingClientRect() nach, anders als beim
box-shadow schlägt eine Vergrößerung dort durch. Nachgemessen: 155,6 statt
161,9 px. Im Druck fällt beides ebenso weg.
SPEC §9 und D25 (Nachtrag) nachgezogen; llms.md unberührt (Notation, keine
Editor-UI, D43).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- llms.md, the notation explained to AI agents
Taiga schreibt #US-123 für eine User Story, Jira #ABC-123 — die frühere
Heuristik „rein numerisch = Ticket" trägt nicht. Als Ticket-Link erkannt
wird künftig, was dem konfigurierbaren Muster des angebundenen Trackers
entspricht (Festlegung beim Taiga-Spike); die Zeichenmenge der Knoten-ID
deckt solche Kennungen schon ab, am Parser ändert sich nichts. SPEC
§1/§11, llms.md und Plan nachgezogen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
.md ist die zum Inhalt ehrliche Endung (es IST Markdown); Link rückt zur
Werkzeug-Ecke des Footers. Pipelines, SPEC §13, CLAUDE.md und Plan
nachgezogen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Englische Markdown-Kurzfassung der Notation (Syntax + Semantik: Gates,
Status, Ränge, Extraktionsreihenfolge, Abhängigkeits- und
Beschreibungsregeln, Schreib-Faustregeln, vollständiges Beispiel), damit
Agenten Werkbaum lesen und schreiben können. Name und Ort folgen der
llms.txt-Konvention; Quelle in frontend/public/ (Dev-Server und dist/
gratis), Pages-Workflow und deploy-prod.sh kopieren sie mit je einer
Zeile, Footer verlinkt den Dateinamen (keine i18n nötig, Tooltip DE·EN).
Die SPEC bleibt normativ — Hausregel jetzt: SPEC zuerst, dann Code, dann
llms.txt nachziehen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ganz versteckt war der Eintrag nicht auffindbar (Nutzer: „ich sehe
keinen Reset-Button") — jetzt erscheint er, sobald Example oder Werkbaum
aktiv ist, und ist nur ausgegraut, solange das Dokument dem
Auslieferungsstand entspricht.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- Restore a shipped document from the menu
Auf der Prod-Instanz gab es keinen Weg, ein bearbeitetes mitgeliefertes
Dokument wieder auf den Auslieferungsstand zu bringen — der Reset ist ein
Debug-Knopf, und das Fingerabdruck-Nachziehen (D27) fasst bearbeitete
Texte nie an. Stilles Überschreiben beim Laden wäre überraschender
Datenverlust (verworfen); stattdessen ein Menü-Eintrag, sichtbar nur für
mitgelieferte Dokumente und nur bei Abweichung vom Auslieferungsstand,
mit Rückfrage. Stellt Text und Name wieder her, verwirft Falt-Eingriffe.
i18n in allen 9 Sprachen; im Browser durchgespielt (erscheint nach Edit,
stellt her, verschwindet wieder).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):
- Node IDs (#auth) (S) %% often just the ticket number, see SPEC §11
- Dependencies across the tree, (:#auth,#api)
- They constrain the status, not when work may start
- Effective status: intrinsic, plus what it depends on
- Cycles are legal — they mean "finished together"
- An id with no node behind it is a warning
- XOR, = — exactly one alternative, not at least one
- Node descriptions, shown as a tooltip
- A short text right at the node (S) %% a " line below the node
- A long block at the end, addressed by its id (S) %% behind a --- separator
- Cross links for dependencies
- Visually secondary — the tree carries the message
- Highlight what a selected node needs and feeds
- Count the whole dependency closure #closure
- Shared dependencies counted only once
- The cheapest alternative is no longer the local one (M) %% see D34, D42
- Search exactly, the trees are small enough
- Enumerate the coupled any-of choices
- Cost is the size of the union
- Stay greedy, but say so (XS) %% built as the named fallback
- Line numbers in the text editor (XS) %% the warnings name them
- Collapsible subtrees
- Initial state from the text: > collapses, < re-opens
- Fold and unfold in the diagram, independently of the text
Der Rename example-werkbaum.werkbaum → werkbaum.werkbaum (82f34b2) hatte
das Skript nicht erreicht — der Deploy brach mit „Plan nicht gefunden"
ab. Dazu die Statusbox-Erkennung um das =-Gate und die Faltmarken >/<
erweitert (SPEC §1), damit auch `- > [x] …`-Zeilen befördert werden.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Das gefüllte Dreieck stach als einziger satter Fleck aus der gepunkteten
grauen Linie heraus. Jetzt ein offener Winkel aus zwei dünnen Strichen
im selben Grau und Gewicht wie die Linie; die Fokus-Hervorhebung bekommt
denselben Winkel in Tinte. Export identisch.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Das mitgelieferte „Example" führt jetzt alles vor: eingeklapptes
Concept-Kapitel (>) mit "-Hinweis am Wurzelknoten, Knoten-ID #cms mit
Langbeschreibung hinter ---, eine Abhängigkeit samt bewusster Diskrepanz
(Landing page [x], effektiv geplant — Farbe + [x]-Marke + gepunktete
Kante), eine Zugabe (+ Dark mode) und die Hosting-Wahl als =-Gruppe.
Damit Bestandsnutzer die neue Fassung sehen, zieht seedShippedDocs das
Beispiel jetzt wie das Werkbaum-Dokument per Fingerabdruck nach
(werkbaum-seeded-example, D27-Nachtrag) — nur bei unverändertem Text,
der Reset setzt beide Merker. 21 Knoten, 0 Warnungen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Nutzer-Feedback: Die durchgezogene Kurve konkurrierte trotz Blässe noch
mit dem Baum. Basis-Kanten jetzt gepunktet (runde Punkte, .1/5) — damit
dreifach von den Baumlinien unterschieden (Krümmung, Blässe,
Punktierung). Der D29-Einwand gegen einen dritten Linienstil galt den
Baum-Abzweigen im kompakten Modus, nicht der eigenen gekrümmten Ebene.
Die Fokus-Hervorhebung bleibt durchgezogen in Tinte; Export identisch.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
IDs (#scaffold, #docs, #resolve, #closure) und sechs echte
Abhängigkeiten — alles Serverseitige zeigt auf :#scaffold und
demonstriert damit die geteilte Closure; die Tracker-Wahl ist jetzt eine
=-Gruppe (genau einer), 'Update by itself' und das IntelliJ-Kapitel
starten per > eingeklappt, < holt die Zweiter-Parser-Warnung hervor;
eine "-Kurzbeschreibung am Collaboration-Knoten und zwei Langtexte
(#closure, #scaffold) hinter ---. Die in D40-D42 gebauten Knoten stehen
auf [x]. Parst mit 165 Knoten ohne Warnung, Pfad exakt, keine
Status-Diskrepanzen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>