feat(editor): Mehr-Fenster-Betrieb gebaut — Ablageschema v3, Tombstones, docsync, Sperre je Dokument (RFC 002, D94)
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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
112ada4e58
commit
caaf7c15e1
+35
-20
@@ -150,31 +150,46 @@ verworfene Elemente. Quelle sind ES-Module unter `src/`; `index.html` ist der
|
||||
auseinander und die PATCH-Antwort gewinnt — wer das prüfen will, muss die
|
||||
PATCH-Antwort im Client verzögern, sonst meldet die Messung „geht doch".
|
||||
- Zustand wird im `localStorage` gehalten (Server-Dokumente ausgenommen): `werkbaum-lang`
|
||||
(Sprache), `werkbaum-docs` (JSON-Array der Dokumente `[{id,name,text}]`),
|
||||
`werkbaum-active` (id des aktiven Dokuments), `werkbaum-src` (Spiegel des
|
||||
(Sprache), `werkbaum-active` (id des aktiven Dokuments), `werkbaum-src` (Spiegel des
|
||||
aktiven Texts), `werkbaum-ui` (JSON: Modus, verworfene,
|
||||
günstigster Pfad, Split-Zustand inkl. `--col`/`--drow`, Zoom, Vollbild). Neue
|
||||
GUI-Einstellungen in `saveUI()`/`restoreState()` mitführen; `saveUI` liefert
|
||||
während `restoring===true` nichts, damit das Wiederherstellen nicht sofort
|
||||
zurückschreibt.
|
||||
**Persistenz ist geteilt (D82) und je Dokument abgelegt (D83):** Das
|
||||
Schema liegt headless in `docstore.js` — `werkbaum-docs` ist nur der
|
||||
INDEX `[{id,name,source?}]`, der Text jedes Dokuments ein eigener
|
||||
Schlüssel `werkbaum-doc:<id>`. Der Tastendruck schreibt über
|
||||
`persistActiveText()`/`storeDocText()` NUR den aktiven Text (+ Spiegel
|
||||
`werkbaum-src` als Rollback-Fallback); den Voll-Flush macht
|
||||
`persistDocs()`/`storeDocs()` an Flush-Punkten (Wechseln/Anlegen/Löschen/
|
||||
Umbenennen, `pagehide`, verborgener Tab) — mit Vergleich vor jedem
|
||||
Schreiben und Abräumen verwaister Text-Schlüssel; nie wieder eine
|
||||
Voll-Serialisierung in einen Tastendruck-Pfad hängen. Die „Spiegel
|
||||
gewinnt"-Regel in `loadDocs` gilt NUR noch der einmaligen Migration aus
|
||||
dem Altformat (Texte im Array) und muss **vor** `seedShippedDocs()`
|
||||
laufen — danach drehte der ältere Spiegel eine frisch nachgezogene
|
||||
Fassung zurück und das Dokument gälte für immer als bearbeitet. Ein
|
||||
fehlender Text-Schlüssel ergibt ein leeres Dokument, nie den Verlust der
|
||||
Liste. Scheitert ein Write (Quota), meldet die persistente Warnung
|
||||
`storeFailed` (`noteStore()`, rendert nur an der Flanke) — nie wieder
|
||||
still schlucken.
|
||||
**Persistenz ist geteilt (D82) und je Dokument abgelegt (D83, v3 nach
|
||||
RFC 002/D94):** Das Schema liegt headless in `docstore.js` — der Text
|
||||
jedes Dokuments unter `werkbaum-doc:<id>`, sein Name/Quelle/Geburtsdatum
|
||||
unter `werkbaum-meta:<id>`, seine früheren Stände unter
|
||||
`werkbaum-snaps:<id>`, eine Löschung als Tombstone `werkbaum-gone:<id>`
|
||||
(Verfall 7 Tage). `werkbaum-docs` ist nur der Reihenfolge-Hinweis
|
||||
`[{id,name,source?}]` — er **entfernt nichts mehr** und wird aus
|
||||
`Speicher-ids ∪ eigene Liste` geschrieben (`writeIndexHint`). Der
|
||||
Tastendruck schreibt über `persistActiveText()`/`storeDocText()` NUR den
|
||||
aktiven Text (+ Spiegel `werkbaum-src`); den **Dirty-Flush** macht
|
||||
`persistDocs()` an Flush-Punkten (Wechseln/Anlegen/Löschen/Umbenennen,
|
||||
`pagehide`, verborgener Tab) — er schreibt NUR, was dieses Fenster
|
||||
angelegt, umbenannt oder getippt hat (`dirtyDocs`, docsync.js), **nie**
|
||||
den Schlüssel eines anderen Fensters (der alte Orphan-Sweep des
|
||||
Voll-Flushes hat fremde Dokumente samt Text gelöscht — genau dagegen ist
|
||||
die Gegenprobe im Test). Die „Spiegel gewinnt"-Regel in `loadDocs` gilt
|
||||
NUR noch der einmaligen Migration aus dem Altformat (Texte im Array) und
|
||||
muss **vor** `seedShippedDocs()` laufen — danach drehte der ältere Spiegel
|
||||
eine frisch nachgezogene Fassung zurück und das Dokument gälte für immer
|
||||
als bearbeitet. Ein fehlender Text-Schlüssel ergibt ein leeres Dokument,
|
||||
nie den Verlust der Liste. Scheitert ein Write (Quota), meldet die
|
||||
persistente Warnung `storeFailed` (`noteStore()`, rendert nur an der
|
||||
Flanke) — nie wieder still schlucken.
|
||||
**Zwei Fenster (RFC 002/D94):** Das `storage`-Ereignis zieht Liste, Namen
|
||||
und Tombstones per `applyStorageEvent()` (docsync.js, headless getestet)
|
||||
im laufenden Fenster nach; das aktive anderswo gelöschte Dokument bleibt
|
||||
warnfarben stehen, bis getippt wird (Tippen belebt es — `storeDocText`
|
||||
hebt den Tombstone selbst). Ein zweites Fenster am selben **nicht
|
||||
geteilten** Dokument wird per Web-Locks-Sperre je Dokument erkannt
|
||||
(`syncDocLock()`/`acquireDocLock()`); der Dialog über dem Editor hat drei
|
||||
Auswege (anderes öffnen / nur ansehen `viewOnly` / trotzdem bearbeiten);
|
||||
ohne Locks-API warnt der `foreignWrite`-Rückfall. `live:`-Dokumente
|
||||
werden nie gesperrt — der Server führt zusammen. Der D89-Präsenz-Kanal
|
||||
(BroadcastChannel, Herzschlag, modaler Dialog) ist ersatzlos weg.
|
||||
- Dokumente (D22): mehrere umschaltbare Notationstexte. `loadDocs()` migriert bei
|
||||
fehlendem `werkbaum-docs` den bestehenden `werkbaum-src` (oder `INITIAL`) in
|
||||
**ein** Dokument; `initDocs()` (Aufruf **nach** `applyLang`) holt den aktiven
|
||||
|
||||
Reference in New Issue
Block a user