Skip to content

refactor(notebook): eliminate NotebookState as dual-write target (Phase 1.1-1.3)#544

Merged
rgbkrk merged 5 commits intomainfrom
540/eliminate-notebook-state
Mar 5, 2026
Merged

refactor(notebook): eliminate NotebookState as dual-write target (Phase 1.1-1.3)#544
rgbkrk merged 5 commits intomainfrom
540/eliminate-notebook-state

Conversation

@rgbkrk
Copy link
Member

@rgbkrk rgbkrk commented Mar 5, 2026

More progress on #540

Migrate all cell and metadata Tauri commands to use the NotebookSyncHandle as the single source of truth. Removes the dual-write to both NotebookState and Automerge that existed across ~25 call sites.

What changed

Cell mutations (update_cell_source, add_cell, delete_cell) — sync handle only, no more NotebookState write.

Cell reads (load_notebook) — reads from handle.get_cells(), falls back to NotebookState when daemon is disconnected.

Path reads (has_notebook_path, get_notebook_path, detect_pyproject, detect_pixi_toml, detect_environment_yml, detect_deno_config, and their dependency commands) — read from new context.path field instead of state.path.

All 16 metadata commands — read/write directly via sync handle get_metadata/set_metadata. Read commands fall back to NotebookState when disconnected.

Other commandsformat_cell, debug_get_local_state, get_preferred_kernelspec, get_notebook_runtime, check_formatter_available all migrated.

Receiver loop sync-back removed — the block that overwrote NotebookState cells and metadata from Automerge on every peer update is gone. notebook:updated and notebook:metadata_updated events still flow to the frontend.

WindowNotebookContext gains path and working_dir fields. notebook_state is retained for save_notebook, save_notebook_as, clone_notebook_to_path, and session persistence — those move in Phase 1.4.

New helpers

  • cell_snapshot_to_frontend — CellSnapshot → FrontendCell conversion
  • get_runtime_from_sync — reads runtime from Automerge metadata
  • get_metadata_snapshot / set_metadata_snapshot — typed read/write for metadata via sync handle
  • metadata_from_snapshot — bridges snapshot back to nbformat::v4::Metadata for extraction functions

Not in scope

save_notebook, save_notebook_as — Phase 1.4 (delegate save to daemon).
notebook_state.rs cleanup — deferred until save is migrated.

rgbkrk added 5 commits March 5, 2026 12:29
…se 1.1-1.3)

Migrate all cell and metadata Tauri commands to use the NotebookSyncHandle
as the single source of truth instead of dual-writing to both NotebookState
and Automerge.

Cell mutations (update_cell_source, add_cell, delete_cell): removed
NotebookState write, sync handle only.

Cell reads (load_notebook): read from sync handle get_cells(), fallback to
NotebookState when daemon is disconnected.

Path reads (has_notebook_path, get_notebook_path, detect_pyproject, etc.):
read from new context.path field instead of state.path.

All 16 metadata commands: migrated to read/write directly via sync handle's
get_metadata/set_metadata. Read commands have NotebookState fallback.

format_cell, debug_get_local_state, get_preferred_kernelspec,
get_notebook_runtime, check_formatter_available: migrated to sync handle.

Removed receiver loop sync-back that overwrote NotebookState cells and
metadata from Automerge on every peer update.

WindowNotebookContext gains path and working_dir fields. notebook_state
is retained for save_notebook, save_notebook_as, clone, and session
(Phase 1.4 scope).
…stale local fallback

- Remove push_metadata_to_sync call from save_notebook. Metadata
  commands now write directly to the sync handle, so pushing stale
  NotebookState metadata would revert dependency changes.

- Remove the now-dead push_metadata_to_sync function entirely (zero
  remaining callers).

- Refresh NotebookState from Automerge before the local save fallback.
  The receiver loop sync-back was removed, so NotebookState cells and
  metadata can be stale. The fallback now pulls current cells and
  metadata from the sync handle before serializing.

- Return Err when add_cell is called without a daemon connection instead
  of silently returning a ghost cell that only exists in React state.
…tion, save-as staleness

- Fix trust_signature loss: approve/verify_notebook_trust now use raw
  JSON read/write (get_raw_metadata_additional, set_raw_trust_in_metadata)
  instead of going through the typed NotebookMetadataSnapshot which
  strips unknown runt fields like trust_signature and trust_timestamp.

- Fix get_runtime_from_sync: add missing ks.language == "python" check
  and language_info fallback to match NotebookState::get_runtime()
  semantics. Custom Python kernels and language_info-only notebooks
  were being misclassified.

- Fix save_notebook_as stale cells: refresh NotebookState from Automerge
  before serializing, same pattern as save_notebook's local fallback.
  Without the receiver loop sync-back, NotebookState can have stale
  cells/metadata from peer updates.

- Document main_is_empty limitation in macOS file association handler:
  dirty flag is no longer set by cell mutations, so untitled notebooks
  with user edits may be reused. Deferred to Phase 1.4.
Add initial_metadata field to Handshake::NotebookSync so the daemon has
the kernelspec before auto-launching a kernel. Previously, new Deno
notebooks would get a Python kernel because the daemon auto-launched
from an empty Automerge doc — the metadata was pushed after connect.

The Tauri app now computes a NotebookMetadataSnapshot at connect time
and includes it in the handshake. The daemon seeds it into the Automerge
doc before the auto-launch decision, so resolve_metadata_snapshot sees
the correct kernelspec.

Backwards compatible: initial_metadata is Option with serde skip_none.
@rgbkrk rgbkrk marked this pull request as ready for review March 5, 2026 21:47
@rgbkrk rgbkrk mentioned this pull request Mar 5, 2026
45 tasks
@rgbkrk rgbkrk merged commit daf2650 into main Mar 5, 2026
14 checks passed
@rgbkrk rgbkrk deleted the 540/eliminate-notebook-state branch March 5, 2026 22:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant