Parent
Part of #478 — PWA first-class excellence/hardening.
Why this can exceed native behavior
The PWA can have several independent same-origin tabs/windows/workers alive at once. That is often treated as a browser nuisance, but it can become a product advantage if WorldScript makes concurrency explicit and safe.
Browser-native primitives provide origin-wide coordination without inventing a native IPC daemon:
- Web Locks API for exclusive/shared ownership of critical resources;
- BroadcastChannel for low-latency same-origin presence/state notifications;
- Service Worker / workers as additional coordinated participants where appropriate;
- browser lifecycle semantics that release locks when a context actually dies.
The goal is not real-time collaborative editing between a user's own tabs. The goal is to make accidental or intentional multi-window usage safe, comprehensible, and useful.
Current opportunity
The repository already has sophisticated IndexedDB encryption-migration admission concepts (#338/#360 lineage), but there is no dedicated general PWA multi-tab ownership contract. Search of the current codebase did not find a generic BroadcastChannel or PWA-level navigator.locks coordination layer.
Proposed architecture
WorldScript origin
│
├── Tab / Installed window A ─┐
├── Tab / Installed window B ─┼── BroadcastChannel: presence/events
├── Worker / local-AI owner ──┤
└── Service Worker ───────────┘
│
▼
Web Locks ownership
│
▼
IndexedDB / OPFS authority
Lock classes
Define named, versioned lock namespaces rather than ad-hoc strings:
worldscript:project:<id>:writer
worldscript:project:<id>:migration
worldscript:project:<id>:backup
worldscript:local-ai:model:<id>:init
worldscript:duckdb:migration
worldscript:pwa:update-activation
Only introduce a lock when a real shared-resource race exists. Do not serialize unrelated work globally.
Project writing ownership
Recommended default:
- first context opening a project obtains the active writer lease/lock;
- a second context may open safely in read-only / observer mode rather than silently becoming another writer;
- the secondary context clearly identifies the active writer context;
- user may request Take over editing;
- takeover flushes/coordinates current dirty state before transferring ownership where possible;
- if the original tab is dead, lock loss permits deterministic recovery;
- never use wall-clock-only leases as the sole source of truth.
Do not make the entire application single-instance: multiple projects should remain usable in multiple tabs/windows if their resource ownership does not conflict.
BroadcastChannel protocol
BroadcastChannel is advisory coordination, not durable truth. Persisted state remains in IndexedDB/OPFS.
Suggested typed messages:
HELLO / GOODBYE
PROJECT_OPENED
PROJECT_WRITER_ACQUIRED
PROJECT_WRITER_RELEASED
DIRTY_GENERATION_ADVANCED
SAVE_STARTED / SAVE_COMMITTED / SAVE_FAILED
MIGRATION_STARTED / FINISHED / RECOVERY_REQUIRED
UPDATE_AVAILABLE / UPDATE_ACTIVATION_REQUESTED
LOCAL_AI_INIT_STARTED / READY / FAILED
Every message should include a protocol version, context ID, timestamp/monotonic sequence where useful, and bounded non-sensitive metadata. Never broadcast manuscript text, prompts, tokens, API keys, or encryption material merely for coordination.
Lifecycle behavior
Handle:
- normal close;
- crash/kill;
- browser discard/freeze/background;
- reload/navigation;
- installed PWA + normal browser tab simultaneously;
- service-worker replacement;
- suspend/resume where exposed;
- stale presence records.
Presence heartbeats may improve UX but must not become a correctness substitute for Web Locks / durable state.
Local-AI resource ownership
A major PWA-specific win is preventing multiple tabs from independently loading the same multi-GB local model or initializing WebGPU simultaneously.
Use per-model/per-backend locks to:
- deduplicate initialization;
- route/coordinate requests where architecture permits;
- prevent model-download duplication;
- avoid GPU-memory storms;
- allow safe cancellation/recovery if the owning context dies.
Coordinate with the dedicated PWA local-AI issue under #478.
Migration / encryption relationship
Do not replace the existing security-specific migration-admission invariants with generic UI locking.
Instead:
Failure UX
Never show a generic "database locked" error when the app can explain the situation.
Examples:
- “This project is currently being edited in another WorldScript window.”
- “A storage migration is finishing. Editing will resume when it is safe.”
- “Local model X is already loading in another WorldScript window.”
Provide safe actions: focus existing window where possible, retry, open read-only, or explicit takeover.
Testing
Automated/browser-matrix tests should cover:
- two tabs open same project concurrently;
- two tabs open different projects;
- active writer crashes;
- active writer reloads;
- dirty secondary tries takeover;
- migration starts while writer active;
- local model init from two tabs;
- installed PWA and normal browser tab coexist;
- BroadcastChannel unavailable/fails;
- Web Locks unavailable;
- background/frozen context recovers;
- service-worker update while multiple dirty clients exist.
Fallback must remain safe when a browser lacks one of the APIs; unsupported capability must not silently re-enable unsafe last-writer-wins behavior.
Acceptance criteria
Non-goals
- building Google-Docs-style collaboration between the user's own tabs;
- introducing a server requirement;
- forcing single-instance application behavior;
- using BroadcastChannel as persistence;
- weakening encryption migration locks for convenience.
Parent
Part of #478 — PWA first-class excellence/hardening.
Why this can exceed native behavior
The PWA can have several independent same-origin tabs/windows/workers alive at once. That is often treated as a browser nuisance, but it can become a product advantage if WorldScript makes concurrency explicit and safe.
Browser-native primitives provide origin-wide coordination without inventing a native IPC daemon:
The goal is not real-time collaborative editing between a user's own tabs. The goal is to make accidental or intentional multi-window usage safe, comprehensible, and useful.
Current opportunity
The repository already has sophisticated IndexedDB encryption-migration admission concepts (#338/#360 lineage), but there is no dedicated general PWA multi-tab ownership contract. Search of the current codebase did not find a generic
BroadcastChannelor PWA-levelnavigator.lockscoordination layer.Proposed architecture
Lock classes
Define named, versioned lock namespaces rather than ad-hoc strings:
Only introduce a lock when a real shared-resource race exists. Do not serialize unrelated work globally.
Project writing ownership
Recommended default:
Do not make the entire application single-instance: multiple projects should remain usable in multiple tabs/windows if their resource ownership does not conflict.
BroadcastChannel protocol
BroadcastChannel is advisory coordination, not durable truth. Persisted state remains in IndexedDB/OPFS.
Suggested typed messages:
Every message should include a protocol version, context ID, timestamp/monotonic sequence where useful, and bounded non-sensitive metadata. Never broadcast manuscript text, prompts, tokens, API keys, or encryption material merely for coordination.
Lifecycle behavior
Handle:
Presence heartbeats may improve UX but must not become a correctness substitute for Web Locks / durable state.
Local-AI resource ownership
A major PWA-specific win is preventing multiple tabs from independently loading the same multi-GB local model or initializing WebGPU simultaneously.
Use per-model/per-backend locks to:
Coordinate with the dedicated PWA local-AI issue under #478.
Migration / encryption relationship
Do not replace the existing security-specific migration-admission invariants with generic UI locking.
Instead:
Failure UX
Never show a generic "database locked" error when the app can explain the situation.
Examples:
Provide safe actions: focus existing window where possible, retry, open read-only, or explicit takeover.
Testing
Automated/browser-matrix tests should cover:
Fallback must remain safe when a browser lacks one of the APIs; unsupported capability must not silently re-enable unsafe last-writer-wins behavior.
Acceptance criteria
Non-goals