Skip to content

Redesign branching UX: auto-branch on edit-in-past, tags, unified timeline graph - #6

Merged
cjroth merged 6 commits into
mainfrom
claude/branching-ux-redesign-0rcsey
Jul 6, 2026
Merged

cjroth merged 6 commits into
mainfrom
claude/branching-ux-redesign-0rcsey

Conversation

@cjroth

@cjroth cjroth commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Branching is now implicit and the history timeline IS the network graph.

Behaviour

  • Time travel is editable. Editing while scrubbed into the past auto-forks a new
    branch AT that instant (checkout + land the edit there); main is never touched.
    No manual "create branch" step — a non-blocking banner names the new branch.
  • Tags: name any moment on the timeline (synced Kind::Tag log rows, reconciled
    last-writer-wins like branch records). Tag flags render on the timeline and
    jump the playhead when clicked — find/return to points among thousands of edits.
  • The bottom history timeline became the network graph: one lane per branch,
    fork edges where a branch diverged, events positioned by time (distance = time),
    keeping zoom, pan and the playhead slider. The branch dropdown + the separate
    network-graph modal are removed; a branch pill + clickable lane labels replace them.

Backend (asp-core / wasm / desktop engine / Tauri)

  • New Kind::Tag + tag.rs (Tag record, derive_id, reconcile_tags); create_tag /
    tags / delete_tag on both the native (SqliteEngine) and wasm (MemEngine) engines,
    a log_kind_tag partial index, and the graph now carries tags on their lane.
  • MemEngine gains history / file_at / restore_file_at so the web build has real
    time travel + fork-on-edit-in-the-past (previously desktop-only), and wasm
    now_unix() uses the browser clock so web timestamps aren't epoch 0.
  • HistEvent carries branch_id for lane placement.

Perf ("Loading your vaults…")

  • capture_rescan/scan_disk report (done, total, phase) progress; the shell emits
    vault-scan-progress and the connect screen shows a determinate progress bar
    instead of an indeterminate spinner on a large (28k-file) reconcile.

Tests

  • asp-core: tag reconcile LWW/order-invariance, engine tag lifecycle + reopen,
    scan-progress callback, MemEngine tag/history/PITR parity.
  • frontend: timeline layout unit tests, auto-branch + tag + editable-time-travel
    integration tests, progress-bar test. Full suites green (482 FE, 91+ core).
  • Verified end-to-end in a real headed browser (chromium/Xvfb) on the real wasm
    engine: create vault, edit, tag, time-travel, auto-branch, branch lanes, switch.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01D5zbJaE8dCFXiBRNRZhqbE

claude added 6 commits July 1, 2026 06:51
…eline graph

Branching is now implicit and the history timeline IS the network graph.

Behaviour
- Time travel is editable. Editing while scrubbed into the past auto-forks a new
  branch AT that instant (checkout + land the edit there); main is never touched.
  No manual "create branch" step — a non-blocking banner names the new branch.
- Tags: name any moment on the timeline (synced Kind::Tag log rows, reconciled
  last-writer-wins like branch records). Tag flags render on the timeline and
  jump the playhead when clicked — find/return to points among thousands of edits.
- The bottom history timeline became the network graph: one lane per branch,
  fork edges where a branch diverged, events positioned by time (distance = time),
  keeping zoom, pan and the playhead slider. The branch dropdown + the separate
  network-graph modal are removed; a branch pill + clickable lane labels replace them.

Backend (asp-core / wasm / desktop engine / Tauri)
- New Kind::Tag + tag.rs (Tag record, derive_id, reconcile_tags); create_tag /
  tags / delete_tag on both the native (SqliteEngine) and wasm (MemEngine) engines,
  a log_kind_tag partial index, and the graph now carries tags on their lane.
- MemEngine gains history / file_at / restore_file_at so the web build has real
  time travel + fork-on-edit-in-the-past (previously desktop-only), and wasm
  now_unix() uses the browser clock so web timestamps aren't epoch 0.
- HistEvent carries branch_id for lane placement.

Perf ("Loading your vaults…")
- capture_rescan/scan_disk report (done, total, phase) progress; the shell emits
  vault-scan-progress and the connect screen shows a determinate progress bar
  instead of an indeterminate spinner on a large (28k-file) reconcile.

Tests
- asp-core: tag reconcile LWW/order-invariance, engine tag lifecycle + reopen,
  scan-progress callback, MemEngine tag/history/PITR parity.
- frontend: timeline layout unit tests, auto-branch + tag + editable-time-travel
  integration tests, progress-bar test. Full suites green (482 FE, 91+ core).
- Verified end-to-end in a real headed browser (chromium/Xvfb) on the real wasm
  engine: create vault, edit, tag, time-travel, auto-branch, branch lanes, switch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D5zbJaE8dCFXiBRNRZhqbE
Drives the REAL desktop Tauri app (native SqliteEngine, real Tauri IPC) headed
under Xvfb to verify the redesign end-to-end: open a pre-registered vault, the
timeline network graph, tagging, jump-to-tag time travel, auto-branch on
edit-in-the-past, and branch lanes. Complements the web (wasm) browser drive.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D5zbJaE8dCFXiBRNRZhqbE
capture_rescan_progress calls scan_disk_progress directly; the old parameterless
scan_disk wrapper had no callers. Removes the `method is never used` warning.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D5zbJaE8dCFXiBRNRZhqbE
Timeline
- A connecting line runs through each lane's dots, so history reads as one
  continuous strand per branch.
- Clicking a dot opens a diff popup showing exactly what changed at that point
  (before/after via a tiny line diff), and scrubs the playhead there.
- Branch labels moved to the RIGHT, anchored next to each lane's most-recent dot
  instead of far-left aligned.
- New Time/Edits toggle: space dots by wall-clock time (default) or evenly by
  edit order (a clean, uniform view when edits cluster in time).
- The status bar shows the vault's file count after the fingerprint.

Tags
- Deleting a tag now asks for confirmation.
- Clicking outside the tag-name input closes it.

Perf: instant branch switching
- checkout used to blow away the fold cache and do a full O(all-rows) refold every
  time. Added a small per-branch FoldState LRU (native Engine) / materialized-files
  LRU (wasm MemEngine): the outgoing branch's fold is parked and the target's
  restored if cached, so switching among a few branches is near-instant. Remote
  integrates invalidate the cache. Correctness pinned by a warm-vs-cold-fold test.

Clone hardening (desktop → web)
- The browser clone had no read timeout: a stalled relay left "Receiving notes…"
  hanging forever. Added a per-frame idle timeout so a stall surfaces as an error,
  and the connect dialog now shows clone failures instead of silently resetting.

Also: openVault fetches vault status immediately so the status bar (file count) is
populated on a freshly opened/created vault.

Tests: diffLines unit tests; checkout warm/cold parity; browser drive extended to
18 checks (connecting line, diff popup, file count, layout toggle, tag confirm +
outside-click) — all green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D5zbJaE8dCFXiBRNRZhqbE
… harness

- Reduce catch-up chunk size 4 MiB/512 rows → 1 MiB/256 rows. The browser can only
  reach a listener over a relay (no direct UDP), where one large frame streams
  slowly and stalls "Receiving notes…". Smaller frames keep bytes flowing, advance
  progress smoothly, and stay under the connector's new per-frame idle timeout.
  Verified: a 6,000-file catch-up over real iroh loopback converges, 0 failures.
- Document the real-engine computer-use drives (web wasm via Playwright/chromium,
  desktop Tauri via tauri-driver/WebKitWebDriver) in desktop/e2e/README.md so the
  verification process is reproducible.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D5zbJaE8dCFXiBRNRZhqbE
Reproduces the browser clone's receive path hermetically (no relay needed): a
source authors N files; a fresh MemEngine (the wasm engine) integrates the
catch-up in 256-row pages under batch — exactly what iroh_wasm::drive does — folds
once, then round-trips through export_state/import_state (the OPFS save/load).
Confirms the receiver is O(N), not O(N²), and that a large state survives save→load
byte-identically. Ran at 28,000 files locally (~8s, no OOM); committed at 4,000 for
CI speed. This isolates the earlier "Receiving notes…" hang to the relay transport
(addressed separately by smaller frames + a per-frame idle timeout), not the engine.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D5zbJaE8dCFXiBRNRZhqbE
@cjroth
cjroth merged commit 73b0b7e into main Jul 6, 2026
4 of 6 checks passed
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.

2 participants