diff --git a/VERSION b/VERSION index 9459d4b..5625e59 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1 +1.2 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index b2aa2ae..ec109a5 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -19,7 +19,13 @@ reverse. ## 2026-09-02 -- Running the installed app and a browser tab side by side recorded as planned: documents get their own storage keys so windows stop deleting each other's work, a per-document lock finds the one real loss case, and the second window gets three exits instead of "continue anyway" — spelled out in RFC 002 before it is built +- Running the installed app and a browser tab side by side works now: text, names and earlier states live under their own storage key per document and deleting leaves a tombstone, so windows stop deleting each other's work +- A document created, renamed or deleted in another window shows up without a reload now, and a document deleted elsewhere while open here stays until you type — typing brings it back +- The modal "open more than once" dialog is gone; the one remaining loss case — the same non-shared document open in two windows — is found by a per-document lock, and the second window chooses: open another document, view only until the other window lets go, or edit anyway +- The other-window warning now names the document and says whether it is open in the app or in the browser — and stays silent when nothing collides +- Fix: in the "open in another window" dialog the list of other documents squeezed its buttons until the names ran into each other — picking one is a dropdown now, one line tall however many documents you have +- The two-window warning says "whichever change is saved last wins" now instead of "the last keystroke" — folding a branch in the diagram writes to the text too, so it joins the same race +- "View only" really is view only now: while the document is held by another window, the diagram's fold marks stay put too — folding writes to the text and used to slip past the read-only text area; the window holding the document folds as before - An MCP server for AI agents recorded as planned: it lives in the backend, runs the one JS parser through GraalJS, hands plans to Claude Code and other agents as resources and tools over streamable HTTP, and writes changes as conflict-safe line diffs — no new runtime, spelled out in an RFC before it is built ## 2026-08-28 diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index 50f35bb..6638367 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -7747,15 +7747,16 @@ Warnung den Zustand, und die Sicherungen halten den Text. Unabhängig davon kann `tools/pull-doc --git-commit` (D88) per Cron eine Git-Historie des Server-Dokuments führen — ein Netz außerhalb des Browsers. -**Nachtrag — der modale Zwei-Fenster-Dialog wird revidiert (2026-09-02).** -Das erste Netz oben ist in der Sache überholt: Es erschien auch dort, wo +**Nachtrag — der modale Zwei-Fenster-Dialog ist weg (revidiert, gebaut 2026-09-02).** +Das erste Netz oben war in der Sache überholt: Es erschien auch dort, wo nichts kollidiert (dasselbe geteilte Dokument in App und Tab — zwei Live-Clients, der Server führt zusammen), und es schützte nicht vor dem, wovor es warnte — hinter der Overlay-Schicht liefen Start, Flush und Feed -weiter. Der eigentliche Verlust zwischen zwei Fenstern liegt in den +weiter. Der eigentliche Verlust zwischen zwei Fenstern lag in den Sammel-Schlüsseln der Ablage, nicht im Dialog. Analyse, Alternativen und -Entscheidungen: **D94** und `docs/rfc/002-mehrfenster.md`. Die drei -anderen Netze (Sicherungen, Rettung, Wachhund) bleiben. +Entscheidungen: **D94** und `docs/rfc/002-mehrfenster.md`. Der Präsenz-Kanal +(Herzschlag, Timeout, Notluke) und der modale Dialog sind ersatzlos +ausgebaut; die drei anderen Netze (Sicherungen, Rettung, Wachhund) bleiben. ## D90 — Die Dokumentart steht grau hinter dem Namens-Chip Nutzerwunsch, unmittelbar aus dem D89-Vorfall: Hinter der Brotkrume @@ -8830,7 +8831,7 @@ ungepuffert durch. Fällt er durch, ist die Antwort nicht Node, sondern eine neue Frage an den Entwickler. Offen sonst nur die Prompts. Gebaut ist nichts. -## D94 — Mehr-Fenster-Betrieb: getrennte Schlüssel, Sperre je Dokument, Dialog mit Auswegen — als RFC vorgelegt, nichts gebaut +## D94 — Mehr-Fenster-Betrieb: getrennte Schlüssel, Sperre je Dokument, Dialog mit Auswegen — gebaut (2026-09-02) Gemeldet: Werkbaum als installierte App mit einem `?live=`-Dokument, dazu dieselbe Seite im Browser-Tab — der Tab stellt das zuletzt aktive (geteilte) Dokument her, und in beiden Fenstern steht sofort der modale @@ -8918,5 +8919,173 @@ Browser-Bestand (Chrome 69, Firefox 96, Safari 15.4). im Browser mit zwei Tabs — vor allem der Fall, der heute rot ist: B legt ein Dokument an, A wechselt das Dokument, B's Dokument muss überleben. Die PWA-Nachstellung selbst bleibt Handtest (D73), ebenso Firefox und -Safari. Werkzeuggrenzen wie in D79/D82/D83/D91-Nachtrag 9 benannt. Gebaut -ist nichts. +Safari. Werkzeuggrenzen wie in D79/D82/D83/D91-Nachtrag 9 benannt. + +**Gebaut (2026-09-02, vier Schritte wie im RFC §12):** + +- **Schema v3** (`docstore.js`): `readDocs` liest die Union aus Meta-, Text- + und Index-ids minus Tombstones; `writeDoc`/`writeIndexHint`/`removeDoc`/ + `expireTombstones` ersetzen den Voll-Flush — der Index schreibt sich aus + `Speicher-ids ∪ eigene Liste` und entfernt nichts. Migration + (`migrateV3`) verteilt die alten Sammel-Stände und schreibt fehlende + Meta, idempotent. Die Stände liegen je Dokument (`werkbaum-snaps:`, + `snapshots.js`); nur der Quota-Notfall fasst noch einen fremden + Schlüssel an — lesend gekürzt, nie aus dem eigenen Gedächtnis + überschrieben (§6.8). +- **Dirty-Flush** statt Voll-Flush (`app.js`): die Flush-Punkte schreiben + nur, was dieses Fenster angelegt, umbenannt oder getippt hat, plus den + Index-Hinweis. Der Tastendruck bleibt `storeDocText` — er hebt einen + Tombstone selbst (Tippen ist Absicht). +- **`docsync.js` (neu, headless, getestet)** wendet storage-Ereignisse an: + Liste, Namen, Tombstones, Stände-Cache, Reihenfolge-Hinweis; am aktiven + Dokument die drei Fälle umbenannt / anderswo gelöscht (behalten, bis + getippt wird) / fremd geschrieben. Datei-Handles werden bei `meta` neu + lazy aus IndexedDB nachgeladen bzw. bei `deleted` verworfen (§6.9). +- **Web Locks je Dokument** (`ifAvailable`, gehalten, solange aktiv): + Fällt von selbst, wartende Requests werden geweckt. Bekommt ein Fenster + die Sperre nicht, zeigt es den Dialog über dem Editor mit drei Auswegen + (anderes Dokument öffnen / nur ansehen / trotzdem bearbeiten); ohne + Locks-API warnt der storage-Rückfall ohne Dialog. Die `tabConflict`- + Warnung nennt Dokument und Fensterart (aus der eigenen Sicht gefolgert, + `display-mode: standalone`). +- Headless: 666 Tests grün, die Gegenprobe per Mutation gezogen — der + zurückgebaute Sweep lässt genau den benannten Test fallen. + +**Nachgemessen im Browser, zwei echte Tabs (2026-09-02).** Die neun Fälle +aus RFC §10, Ergebnisse dort im Einzelnen: **1 bis 8 grün** — B's neues +Dokument überlebt A's Flush (der Test für Befund 2, im Vor-v3-Build per +Worktree gegengeprüft und dort nachweislich rot), beide Kamera-Stände +bleiben nebeneinander, „anderswo gelöscht" behält den Editor und wird durch +Tippen zurückgeholt, der Chip folgt einer fremden Umbenennung, der Dialog +steht nur im zweiten Fenster und dessen „nur ansehen" wird von selbst +beschreibbar, sobald das erste wegwechselt, dasselbe `live:`-Dokument in +beiden Fenstern gibt **keinen** Dialog (das gemeldete Symptom), und bei +wirklich voller Quota weichen die Stände, während die Dokumente bleiben. + +**Fall 9 deckte eine Lücke auf — geschlossen.** `reviveGoneDoc()` schrieb +Meta und Text, aber nicht den Index-Hinweis: Ein anderswo gelöschtes und +hier durch Tippen wiederbelebtes Dokument hing bis zum nächsten Flush-Punkt +allein an seinen eigenen Schlüsseln. v3 findet es dort (`readDocs` +vereinigt Meta, Text und Index), ein **Rückbau** auf einen Build vor v3 +aber nicht — der liest nur den Index und räumt bei seinem Voll-Flush jeden +Text-Schlüssel ab, den er darin nicht findet. Also stiller Verlust, der +teuerste Fehler (SPEC §4, D59). Die Funktion schreibt den Hinweis jetzt +mit; Gegenprobe per Mutation gezogen — ohne die Zeile bleibt der Index ohne +das Dokument, während Meta und Text dastehen. Sonst heilt sich der Index +von selbst, weil `indexHint()` die Speicher-Schlüssel mitliest. + +**Nachtrag — die Auswahl im Sperr-Dialog ist ein Aufklapp-Feld +(2026-09-02).** Gemeldet aus der produktiven Instanz: „Die Buttons mit den +anderen Dokumenten überlappen sich und sind unleserlich." Die Ursache ist +nicht die Zahl der Dokumente, sondern eine Flexbox-Falle: Die Liste war ein +`flex`-Spaltenkasten mit gedeckelter Höhe (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, also 17,5 px Überstand je Knopf bei 4 px +Abstand — die Beschriftungen liefen ineinander. + +Zwei Wege standen offen: `flex-shrink: 0` (dann scrollt die Liste wirklich) +oder ein **Aufklapp-Feld**. Entschieden (Nutzer): das Aufklapp-Feld. Es ist +**eine Zeile hoch, unabhängig von der Anzahl** — und der Dialog liegt in +einem Kasten, der auf dem Telefon oder bei kleinem Editor-Panel ohnehin +knapp ist; eine Liste, die mit der Dokumentenzahl wächst, bleibt dort auch +scrollend unhandlich. Die Auswahl aus vielen gleichartigen Dingen ist +zudem genau das, wofür ein Aufklapp-Feld die vertraute Geste ist. + +Gebaut mit dem vorhandenen Vokabular: die Kopfzeile ist jetzt ein echtes +`