Add the webview-facing postMessage bridge (vscode_bridge.rs): token
bootstrap via Init, OpenDocument probe-conditional push, uncapped
Snapshot flush, SaveCommitted, and UseLocal/AcceptRemote conflict
resolution. All three edge/state events (dirty-changed, sync-conflict,
opened) are emitted only from the tick observer draining SyncGate's
consumable latches; handlers only mutate the gate. Reorder mount_ck so
the bridge listener installs first, an iframe awaits Init (2s fallback),
and the 400ms pull tick starts only after the daemon sync-reset (managed:
token; direct: legacy reset moved out of index.html) completes.
Token audit (X-OpenPencil-Token attached only when url starts with
daemon_base(); public requests never carry it):
live_sync.rs get -> daemon -> attach_daemon_headers
live_sync.rs get_with_status -> daemon -> attach_daemon_headers
live_sync.rs post_json -> daemon -> attach_daemon_headers
live_sync.rs post_json_with_status -> daemon -> attach_daemon_headers
web_model_catalog.rs:21 (/api/ai/models) -> daemon -> attach_daemon_headers
web_ai_transport.rs:93 (/api/ai/stream) -> daemon -> attach_daemon_headers
iconify_web.rs:311 fetch_text (daemon brand-catalog + public Iconify CDN)
-> attach_daemon_headers with url-prefix guard: token only on the
daemon URL, never on the public api.iconify.design requests
All other daemon-talking modules route through the live_sync helpers and
inherit the token. No window.fetch / Request::new sites in the crate.