git.javagil.de sendete auf raw-Dateien kein Access-Control-Allow-Origin,
weshalb die ?sourceUrl=-Beispiel-Links nach dem Umzug (D95) auf dem
GitHub-Klon bleiben mussten. Der Header ist jetzt auf mih09 gesetzt:
Giteas [cors]-Abschnitt deckt nur /api/v1 ab, die Web-raw-Route bekommt
ihn im Apache davor. Die Links zeigen nun auf origin.
Nebenbei: "Werkbaum selbst" war schon vorher tot (example-werkbaum.werkbaum
existiert nicht, die Datei heisst werkbaum.werkbaum) und ist mit korrigiert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zuhause ist künftig git.javagil.de/mi/werkbaum (origin); GitHub bleibt unter
dem Remote `github` ein Klon, den scripts/push-github.sh mit `main` versorgt —
nur vorwärts, nie erzwungen.
Der Klon bleibt aus zwei gemessenen Gründen: Gitea sendet auf raw-Dateien kein
Access-Control-Allow-Origin (nachgemessen an mi/werkdock), die
?sourceUrl=-Beispiellinks der READMEs müssen also auf raw.githubusercontent.com
zeigen; und der Pages-Workflow lässt sich nicht mitnehmen.
Footer, llms.txt und llms.md zeigen jetzt auf Gitea (Repo-Seite ohne Anmeldung
lesbar, HTTP 200 geprüft); beide COMMIT_URL-Stellen (deploy-prod.sh und der
Pages-Workflow) ziehen mit. deploy-prod.sh prüft origin und github getrennt und
erinnert an das Spiegeln, statt selbst zu pushen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nutzer-Einwand, folgerichtig aus dem Vorgänger-Commit: Wenn Falten eine
Änderung ist, muss der Nur-Ansehen-Modus auch das Diagramm stillstellen —
im haltenden Fenster natürlich weiter nicht.
Es war schlimmer als eine fehlende Sperre: `readonly` hielt gar nichts auf.
`replaceTextUndoable` fällt auf `src.value = neu` zurück, wenn `execCommand`
scheitert, und eine Zuweisung an `value` schreibt auch in ein
schreibgeschütztes Feld. Nachgemessen: Ein Klick auf das Falt-Zeichen im
Nur-Ansehen-Fenster setzte `- > Ast A (M)` in Textfeld UND Speicher — der
Modus war nur eine Beschriftung.
Gesperrt wird jetzt an der Schreibstelle: eine Zeile in
`replaceTextUndoable` weist jeden programmatischen Schreibzugriff ab
(Falten, Durchschalter, „aus Taiga übernehmen", früherer Stand,
ID-Kurzform). Dazu ruhen die Gesten selbst, damit nichts still ins Leere
geht — toggleFold und der Durchschalter kehren früh um, Falt-Zeichen und
Knopf treten zurück und nehmen keinen Klick an (body.viewonly), und im
Knoten-Fenster entfallen die Aktionen, die in die Zeile schreiben.
„Nach Taiga schreiben" bleibt: Es fasst den Plan nicht an. Ansicht bleibt
Ansicht — Zoom, Modus, Pfad, Export, Sprünge unverändert bedienbar.
Nachgemessen mit zwei Fenstern: Chip, Tastatur und Durchschalter lassen im
Nur-Ansehen-Fenster Text und Speicher unangetastet; im haltenden Fenster
faltet dieselbe Geste weiter; verlässt es das Dokument, wird das andere von
selbst wieder beschreibbar und faltbar. SPEC §9, D94-Nachtrag 3 und
CHANGELOG nachgezogen; 666 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nutzer-Rückfrage: „Was für ein letzter Tastendruck?" — die Formulierung
liest sich, als zähle nur Tippen. Tut es nicht: Umklappen im Diagramm
schreibt die Faltmarke in den Text (D38-Nachtrag 2) und damit in den
Speicher, nimmt also am selben Wettlauf teil. Nachgemessen mit zwei
Fenstern: A klappt zu, im Speicher steht `- > Ast A (M)`, B's Editor und
Diagramm bleiben unverändert — und B's nächster Tastendruck überschreibt
den Speicher, A's Faltung ist weg.
Beide Texte in allen neun Sprachen umformuliert (tabConflictWarn,
docLockText); der Dialogtext nennt das Falten ausdrücklich. SPEC §9 sagt
jetzt dazu, dass das andere Fenster nichts nachzieht und dass ein
Dokumentwechsel dort nicht mitwandert — `werkbaum-active` entscheidet erst
wieder, was ein Neustart öffnet (auch das eine Nutzer-Rückfrage,
nachgemessen). D94-Nachtrag 2 und CHANGELOG nachgezogen.
Benannt, nicht behoben: Wer „trotzdem hier bearbeiten" gewählt hat, behält
die Warnung, auch wenn das andere Fenster das Dokument längst verlassen
hat — dieser Ausweg fordert die Sperre bewusst nicht mehr an.
666 Tests grün; die neuen Texte im laufenden Editor nachgesehen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Gemeldet aus der produktiven Instanz: „die Buttons mit den anderen
Dokumenten überlappen sich und sind unleserlich". Ursache ist eine
Flexbox-Falle, nicht die Zahl der Dokumente: Die Liste war ein
flex-Spaltenkasten mit max-height 9rem, und ihre Knöpfe tragen serienmäßig
flex-shrink 1 — statt zu scrollen, schrumpfte der Kasten sie unter ihre
eigene Textzeile. Nachgemessen bei acht Dokumenten: 14,5 px Kastenhöhe
gegen 32 px Inhalt, 17,5 px Überstand je Knopf bei 4 px Abstand.
Statt der naheliegenden Reparatur (flex-shrink 0, dann scrollt die Liste)
das vom Nutzer gewählte Aufklapp-Feld: eine Zeile hoch, unabhängig von der
Anzahl — der Dialog steckt im Editor-Panel und ist dort ohnehin knapp. Die
Kopfzeile ist jetzt ein echtes <label for>, der Platzhalter ein Strich,
die Auswahl schaltet sofort um (dieselbe Ein-Klick-Geste wie der Knopf).
Kein neuer i18n-Schlüssel.
Nachgemessen: Feld 36 px, kein Überstand, Karte 364 -> 256 px; Auswahl
schaltet um, Dialog schließt, Textfeld wird beschreibbar. D94-Nachtrag und
CHANGELOG nachgezogen; 666 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der 2026-09-02 trug beide Aussagen zur selben Sache: die vier Zeilen „geht
jetzt" und darunter noch „recorded as planned … before it is built" aus dem
RFC-Commit desselben Tages. Im Neuigkeiten-Popup (D58) liest sich das
widersprüchlich — der Leser sieht ein Feature, das zugleich fertig und
geplant ist. Die Planungszeile geht, weil das Gebaute mehr sagt; die
MCP-Planungszeile daneben bleibt stehen, die ist wirklich noch ungebaut.
Ein Test liest die ausgelieferte Datei (news.test.js), 666 Tests grün.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Kein Fenster schreibt mehr den Schlüssel eines anderen: Text, Meta und
frühere Stände liegen je Dokument unter eigenen Schlüsseln, der Index ist
nur noch Reihenfolge-Hinweis und löscht nie, Löschungen hinterlassen einen
Tombstone (7 Tage). Der Voll-Flush weicht dem Dirty-Flush. Damit sind
Befund 2 und 3 des RFC weg — verschiedene Dokumente in zwei Fenstern
kollidieren gar nicht mehr. docsync.js zieht Liste, Namen, Tombstones und
den Stände-Cache aus dem storage-Ereignis nach; am aktiven Dokument die
drei Fälle umbenannt / anderswo gelöscht (behalten, bis getippt wird) /
fremd geschrieben. Der modale D89-Dialog samt Präsenz-Kanal ist ersatzlos
raus; den einen Verlustfall — dasselbe nicht-`live:`-Dokument in beiden
Fenstern vorn — findet eine Sperre per Web Locks, und das zweite Fenster
bekommt drei Auswege statt „trotzdem fortfahren".
Im Browser mit zwei echten Tabs nachgemessen (RFC §10): Fälle 1–8 grün,
Fall 1 im Vor-v3-Build gegengeprüft und dort nachweislich rot. Fall 9
deckte auf, dass reviveGoneDoc() den Index-Hinweis nicht mitschrieb — ein
durch Tippen wiederbelebtes Dokument hing bis zum nächsten Flush allein an
seinen eigenen Schlüsseln und wäre bei einem Rückbau auf einen Build vor
v3 still verlorengegangen; behoben, Gegenprobe per Mutation gezogen.
Headless 666 Tests grün. Offen bleibt die Handarbeit: PWA neben Tab,
Firefox, Safari, ein Browser ohne Locks-API.
SPEC §9, D94, D89-Nachtrag, RFC (Status, §10, Revisionsgeschichte),
CHANGELOG und Plan-Knoten #ed.docs.windows nachgezogen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der modale Zwei-Fenster-Dialog (D89) verbietet den Fall, der funktioniert
(dasselbe geteilte Dokument in App und Tab), und schützt nicht vor dem,
wovor er warnt: Der Voll-Flush löscht Dokumente und Stände des anderen
Fensters. Entschieden: je Dokument eigene Schlüssel, Tombstones, Sperre je
Dokument per Web Locks, Dialog mit drei Auswegen. Nichts gebaut.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Nutzer-FYI: Node.js einzuführen ist eine Dimension schwerer als eine
Backend-Abhängigkeit und muss dem Entwickler deutlich gemacht werden —
als Regel in CLAUDE.md. Aus den nachgefragten Beweggründen folgt: kein
lokaler Prozess. Der MCP-Server lebt im Backend (Streamable HTTP,
Bearer-Token), führt die Frontend-Module per GraalJS aus, jedes Werkzeug
hat eine text- und eine document-Form; das Node-Paket ist verworfen,
seine Tool-Schicht lebt als frontend/src/inspect.js, guard.js, edit.js.
Backend-Abhängigkeiten GraalJS + Spring-AI-Starter zugestimmt; der
GraalJS-Spike steht vor allem anderen. RFC neu geschrieben (§12 hält die
drei Runden fest), Plan-Teilbaum #ai.mcp neu, D93-Nachtrag.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ein Node-Paket, das die headless-Module des Frontends unverändert
importiert (kein zweiter Parser, D14), den Plan als Ressource und Tools
anbietet (Baum, Warnungen, günstigster Pfad, Knoten-Verben) und
Änderungen als Zeilen-Diff mit Basisversion schreibt (D76); Leitplanken:
keine beschädigte Notation, kein [^] von einem Agenten. Geteiltes Dokument
und Git zugleich: nach jedem Agenten-Zug committet der Server über
pull-doc --git-commit (D88). Entscheidungen der Multiple-Choice-Runde in
RFC §11 und D93.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der einfache Klick toggelt das Fenster überall — wie der Tipp auf Touch
(D52); der Link eines Knotens ist damit auch am Zeiger der ↗-Knopf im
Fenster, Enter und Strg+Klick öffnen die URL weiterhin direkt. Tastatur-
fokus öffnet nur noch echten (:focus-visible), focusout schließt nicht in
das Fenster hinein, und die Fokus-Rückgabe nach dem Falten ruft das
Fenster ausdrücklich nie.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Eine gemeinsame flex-wrap-Aktions-Zeile für Schreiben/Übernehmen/Öffnen in
der Ticket-Box; mit Taiga-Knöpfen wird das Fenster auf 31rem breiter
(gemessen an den deutschen Labels), umgebrochen wird nur bei echtem
Platzmangel. Der Öffnen-Knopf heißt nur noch «{ref} öffnen» — «in Taiga»
sagen die Nachbarknöpfe.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein Knopf im Knoten-Fenster bindet ein bestehendes Taiga-Ticket an den
Knoten: Die eingefügte Ticket-URL trägt Slug, Typ und Nummer selbst; eine
nackte Nummer wird per Probe Story-dann-Task aufgelöst. Verknüpft wird erst
nach Anzeige des Betreffs; geschrieben werden Ref-Token und ggf.
&taiga.<slug> in einem Undo-Schritt, der geholte Stand füllt den
Ticket-Cache. Eine URL einer fremden Instanz wird benannt statt verknüpft.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Weicht der Ticket-Status von der Statusbox ab, markiert das Knoten-Fenster
die Abweichung und bietet beide Richtungen ausdrücklich an.
- „nach Taiga schreiben": Spalte des Projekts suchen (Taiga schreibt nach Id,
die Namen sind je Projekt frei) und mit der zuletzt GELESENEN `version`
patchen — hat jemand dazwischen geändert, lehnt Taiga ab und der Text steht
im Fenster, statt dass etwas überschrieben wird.
- „aus Taiga übernehmen": `setStatusBox()` schreibt die Box in die Textzeile,
undo-fähig wie jede andere Änderung.
- Schreibbar sind nur die fünf abgebildeten Zustände; `[?]`, `[!]`, `[-]` und
der neutrale Knoten lassen das Ticket unangetastet — mit Begründung im
Fenster.
- Proxy: zwei Spaltenlisten (`/taiga/{userstory,task}-statuses?slug=`) und
zwei Schreib-Endpunkte (`PATCH …/{ref}/status?slug=`); die Zielspalte wählt
der Editor, das Backend parst die Notation nicht (D14).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wo eine Ref steht und ein `&taiga.<slug>` gilt, zeigt das Knoten-Fenster
Betreff, Status und Zuständigen des Tickets; Taigas Statusname steht neben
der Statusbox der Notation (`In progress → [~]`).
- Proxy: zwei benannte Lese-Endpunkte (`GET /taiga/userstories/{ref}` und
`…/tasks/{ref}`, je `?slug=`) — das Präfix der Ref trägt den Typ, Taiga
hat getrennte `by_ref`-Endpunkte. Erst `/projects/by_slug`, dann `by_ref`
(eine Ref ist nur je Projekt eindeutig); der Slug wird kodiert angehängt.
- Die Abbildung Status → Statusbox liegt im Editor (`mapTaigaStatus`,
headless): Statuscodes sind Notation, das Backend parst sie nicht (D14).
Unbekannte Namen bleiben unabgebildet — Raten hieße, dem Knoten eine
Aussage zu geben, die niemand gemacht hat.
- Geholt wird erst nach 400 ms Verweilen und je Ticket einmal je Sitzung
(↻ holt neu); ohne Anmeldung gar nicht — der Knopf meldet erst an.
- Nichts wird geschrieben: kein Text, keine Statusbox (das bleibt
`#trk.write`).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Im Text (freistehendes #US-123/#T-1234, D67-Ausschlüsse) wie auf dem
Knoten; das Knoten-Fenster trägt an Refs einen Öffnen-Knopf — der Weg
auf Touch. Adresse aus taigaWeb (/info) + &taiga.slug-Vererbung; in
einem :#…-Token gewinnt weiter der Abhängigkeits-Sprung.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der Browser bricht eine zu breit geratene Zeile an jedem Bindestrich —
aus #US-123 wurde #US-/123 über zwei Zeilen. Eine tref-Spanne mit
white-space:nowrap hält das Token zusammen; labelLines() (Export) misst
ihre Textknoten unverändert mit.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Zwei Aktionen im Knoten-Fenster, nur wo GET /info das Feature meldet
(Lebendprobe-Muster, je Basis einmal gecacht) und nur an Knoten ohne
Ticket-Referenz — die Ref an der Zeile ist der Idempotenz-Marker.
Login-Dialog (type=password, kein window.prompt; nur das Token landet
im Browser, 401 fragt neu), Projekt-Dialog vorbelegt aus dem geerbten
&taiga.<slug>, Häkchen-Dialog nach der D91-Vorbelegung; Refs und ggf.
das Projekt-Schlagwort gehen undo-fähig als Tokens an die Zeilen
(appendToken: vor %% und vor der Fortsetzungsmarke). Regeln headless in
taiga.js (15 neue Tests); Deploy zieht TAIGA_API_URL aus der .env als
WERKBAUM_TAIGA_API_URL in die Server-Umgebung nach (Nutzerwunsch).
E2E im Browser gegen Backend + Taiga-Stub gemessen: Buttons nur ohne
Ref, Vorbelegung Kundenprojekt aus geerbtem Tag, Refs #US-/#T- an den
richtigen Zeilen, Erledigtes uebersprungen, abweichende Projektwahl
schreibt &taiga.mi-intern zurueck, Undo/Redo je Schreibzug, falsches
Passwort bleibt als Taiga-Fehlertext im Dialog.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
API First: /taiga/auth, /taiga/projects, /taiga/userstories, /taiga/tasks
in der OpenAPI-Spec; TaigaClient/TaigaProperties in
de.werkbaum.integration.taiga. Die API-URL kommt aus
WERKBAUM_TAIGA_API_URL (nie Request-Parameter — SSRF), das Token je
Aufruf im Header X-Taiga-Token (Authorization muessen OpenAPI-Werkzeuge
als Header-Parameter ignorieren) und geht als Bearer hinaus; der Server
speichert nichts und loggt keine Request-Bodies. Taiga-4xx werden samt
_error_message durchgereicht, 5xx/Netz sind 502, unkonfiguriert 503 —
und GET /info meldet das Feature (taiga). Tests gegen aufgezeichnete
Antwortformen auf einem JDK-HttpServer-Stub (statt WireMock: keine neue
Test-Abhaengigkeit, dieselbe Zusicherung); Gegenprobe: ohne den
type-Durchreich faellt genau der benannte Test. check gruen, 93 %
Coverage.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SPEC zuerst: §1 Schritt 5b samt Block und Referenz-Regex, §11 auf
'umgesetzt' umgestellt; llms.md nachgezogen. Parser extrahiert
alleinstehende &-Token als node.marks (Zitier-Konvention gilt),
taigaSlugs() in model.js vererbt das taiga.*-Schlagwort wie die
@-Tags beim Engpass. Sichtbar im Tooltip und aria-label (a11yMarks,
9 Sprachen). Plan-Labels mit &-Erwähnungen eingeklammert; 12 neue
Tests, Gegenprobe: ohne Alleinstehend-Anker fallen genau die zwei
Zitier-Tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Geplant, nicht gebaut: Ziffer 0-9 im Größen-Token (0 = Vorbedingung),
reine Autoren-Aussage ohne Aggregation; der Pfad-Knopf wird ein
Durchschalter aus -> günstigster -> lohnendster. Plan-Knoten
#not.benefit (XOR-Gruppe aufgelöst) und #ed.path.worth.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Je @Person eine Pille mit Anteil an der offenen Pfad-Arbeit (D71-Maß),
dazu ein Eintrag für Unzugewiesenes — die Anteile summieren auf 100 %.
Ein Tipp filtert das Diagramm auf die Knoten der Person: alles andere
faltet, ihre Pakete stehen als ▸ n, die Pillen färben petrol. Die Linse
ist rein Ansicht und Sitzungssache — in den Text wird nichts geschrieben,
in geteilten Dokumenten ginge der persönliche Filter sonst an alle.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die helle Umkehrung des Chips war für die dunkle Tinte-Wurzel gebaut —
seit D39 ist die Wurzel mit Status aber pastellfarben, und Weiß darauf
unsichtbar. Der Chip ist jetzt überall derselbe; desc-mark und nid
bleiben nur auf der statuslosen (dunklen) Wurzel weiß.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Die Ausnahme von der Pfad-Inversion stellte den ganzen Knoten auf volle
Stärke, weil opacity/filter den Ring mitträfen. Jetzt bleibt der Knoten
deckend und die Blässe wird nachgebildet: Papier-Wasch über der Füllung,
gefadete Text-/Rahmenfarbe, Kinder einzeln gedimmt — der Ring steht voll.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Der Verlaufs-Knopf zeigt bei Geteilten die Meilenstein-Historie des
Servers (GET /history, jetzt samt clientId/displayName); Laden ist ein
Server-Rollback (POST /restore, ROLLED_BACK — neue Version für alle,
nichts geht verloren, mit Rückfrage). Die Kamera legt einen
Server-Meilenstein an (pushLive(true), leeres Diff erlaubt); lokale
Momentaufnahmen sammelt snapshotNow() für Server-Dokumente nicht mehr —
sie enthielten fremde Arbeit und überschrieben sie beim Laden als
eigenes Diff. Dazu der Anzeigename: einmal gefragt, im Browser gemerkt,
füllt das 'geändert von' der Historie (Behauptung, kein Nachweis).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Backend: PATCH /documents/{id}/title mit expectedVersion (409 bei
veralteter Version, 400 bei leerem/zu langem Titel), neuer ChangeType
RENAMED (strukturell, immer Meilenstein), der Feed stellt den neuen Titel
im Klartext zu (ChangeEvent.title). Unter derselben Stripe-Sperre wie die
Inhalts-Patches; Owner-Vormerkung in der API-Beschreibung. Vier neue
Cucumber-Szenarien, zwei Unit-Tests.
Frontend: Der Zeilen-Stift eines Server-Dokuments benennt über den Server
um (optimistisch, 409-Retry, Rücknahme + Warnung bei Fehlschlag); fremde
Umbenennungen kommen als RENAMED über den Feed in Chip und Menü.
URL-Dokumente verlieren den Stift — ihr Name ist die URL.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1. Neu laden fragt bei URL-Dokumenten nicht mehr (F5 verwirft ohnehin
still, D23); bei Datei-Dokumenten bleibt die Rückfrage. Dabei gefunden
und behoben: Der Knopf erschien auch bei Server-Dokumenten und hätte
die JSON-Antwort der API als Text an alle gepusht.
2. Die Rückfrage beim letzten Dokument sagt, dass danach wieder das
Beispiel dasteht (docDeleteLastConfirm, 9 Sprachen).
3. Ein zweiter Tab, der in dieselbe Ablage schreibt, wird per
storage-Ereignis erkannt und gemeldet (tabConflict, isDocKey in
docstore.js) — kein Sync, aber kein stiller Verlust mehr.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Beim Anlegen einmalig vom Server geliefert, Browser hält eine Kopie, keine
Recovery auf fremdem Browser; Verwaltung bindet künftig daran, ein Admin
mit Master-Passwort kann reclaimen. Nur Plan-Eintrag, noch keine Umsetzung.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Eigene Aktion für die Geteilt-Gruppe (Server- und URL-Dokumente): Wort
(Verlassen), Icon (Tür mit Pfeil statt Papierkorb), Rückfrage (nur der
eigene Listeneintrag geht, Server bleibt) und normales statt rotem Hover.
Der Link wandert beim Verlassen in die Zwischenablage — der Listeneintrag
ist zugleich das Lesezeichen. Verhalten wie lokales Löschen
(removeDocLocally, gemeinsamer Kern); i18n in neun Sprachen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Nutzer-Wortwahl statt „Eigene"/„Quellen": Lokale leben nur in diesem
Browser, Geteilte (Server- und URL-Dokumente) erreicht man über eine
weitergegebene Adresse. In allen neun Sprachen.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
werkbaum-docs ist nur noch der Index [{id,name,source?}]; der Text jedes
Dokuments liegt unter werkbaum-doc:<id>. Damit trifft eine volle Quota nur
das eine zu große Dokument statt jeden Flush, und ein kaputter Schlüssel
kostet ein Dokument statt aller (vorher: JSON.parse-Fehler -> Rückfall auf
das Beispiel, alle Dokumente unsichtbar). Der Tastendruck schreibt direkt
den Text-Schlüssel; der Voll-Flush vergleicht vor jedem Schreiben und räumt
verwaiste Schlüssel ab. Altformat migriert beim ersten Laden; die
Spiegel-Regel aus D82 gilt nur noch dieser Migration. Schema headless in
docstore.js (+10 Tests).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
saveSrc() serialisierte bei jedem Tastendruck ALLE Dokumente in
werkbaum-docs. Jetzt schreibt der Tastendruck nur noch den Spiegel
werkbaum-src (ein Text); das volle Array schreiben die Flush-Punkte
(Wechseln/Anlegen/Löschen/Umbenennen, pagehide, verborgener Tab). Beim
Laden gewinnt der Spiegel für das aktive Dokument — zwingend VOR dem
Nachziehen mitgelieferter Fassungen, sonst dreht er sie zurück.
Und: persistDocs schluckte Speicherfehler still — bei voller Quota lief
der Editor scheinbar normal weiter, der Verlust fiel erst beim Neuladen
auf. Jetzt meldet die persistente Warnung storeFailed (9 Sprachen),
zuoberst, bis ein Schreiben wieder gelingt.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ihr Name ist Auslieferungsstand: Wiederherstellen stellt ihn mit her, der
Neu-laden-Vergleich prüft ihn, und ein umbenanntes, aber unverändertes
Beispiel bekäme weiter still neue Fassungen nachgezogen (das Nachziehen
hängt an id + Text-Fingerabdruck, nicht am Namen). Kein Stift an
mitgelieferten Zeilen; renameDoc() prüft es selbst. Löschen bleibt.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Das Zeilen-Symbol im Dokumenten-Menü konnte ein UNGEÖFFNETES mitgeliefertes
Dokument zurücksetzen — ohne zu sehen, was man verwirft (Nutzer-Einwand).
Umbenennen und Löschen bleiben je Zeile; restoreDoc() wirkt nur noch auf das
geöffnete Dokument und prüft das selbst.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Auf einer Instanz ohne eigenes Backend (GitHub Pages) endete Teilen mit
HTTP 405: Die Vorgabe "eigene Herkunft" (D76-Nachtrag 8) stimmt nur auf der
produktiven Installation. serverBaseOrAsk() prüft die Vorgabe jetzt mit
GET /api/v1/info (D77), bevor gePOSTet wird, und fragt sonst nach der
Server-Adresse; gemerkt wird nur eine Adresse, die die Probe besteht.
Von Pages aus trägt man werkbaum.javagil.de ein — CORS erlaubt es.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>