Skip to content

Preserve canvas input state across live updates - #166

Merged
0101 merged 9 commits into
mainfrom
input-clear
Aug 14, 2026
Merged

Preserve canvas input state across live updates#166
0101 merged 9 commits into
mainfrom
input-clear

Conversation

@0101

@0101 0101 commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Problem

  • Live AgentDoc updates use Idiomorph, which resynchronizes form values from authored HTML and can erase text a user is still editing.
  • Mounted canvas iframes need catch-up refreshes only when their loaded content differs from disk. Treating visit history as iframe residency can miss delayed or closed-pane updates, refresh fresh mounts unnecessarily, and mishandle content reverts.
  • Unscoped morph-complete messages can be attributed to the wrong document and repeatedly persist an unchanged viewed hash.

Fix

  • Snapshot dirty <input> and <textarea> values before a morph, then restore their values, focus, and selection afterward. Untouched controls still receive new authored defaults.
  • Track the loaded content hash for each actually mounted AgentDoc iframe and compare it with the current disk hash. Fresh mounts seed the current hash; surviving iframes keep their loaded hash across tab switches and pane collapse.
  • Centralize tab, card, pane-reopen, and archive reveal paths so stale mounted documents morph before being marked viewed, while synchronized documents preserve all document-owned state.
  • Scope morph requests and completions by worktree, filename, and content hash; accept completion only from the matching active iframe, coalesce duplicate in-flight requests, and skip redundant viewed-hash writes.
  • Update the canvas specifications and add unit and browser regressions for delayed updates, pane closure, worktree switches, content reverts, hidden-frame forgery, and real tab switch-back behavior.

Tests

  • npm run build
  • npm run test:extension — 48 passed
  • dotnet test src\Tests\Tests.fsproj --no-build --filter "Category=Fast" — 1,901 passed
  • Canvas pane and injection browser suite — 39 passed

0101 and others added 6 commits July 13, 2026 11:31
Switching back to a previously-viewed canvas doc unconditionally fired a
morph that re-fetched the on-disk HTML; idiomorph then resynced form
fields to that (empty) markup, wiping any in-progress user input.

Track AgentDocs whose on-disk content changed while hidden in a new
StaleHiddenDocs set and morph on switch-back only for those, clearing the
mark on morph. An ordinary tab switch with no on-disk change now morphs
nothing, so the mounted iframe's live form input survives.
Addresses focused-review findings F1-F6, all clustered on the new
StaleHiddenDocs mechanism leaving marks that later drive a spurious
switch-back morph and wipe in-progress form input.

- src/Client/CanvasState.fs — add pure helpers markStale (only mark
  currently mounted-but-hidden docs) and pruneStaleToMounted (GC marks
  whose iframe has unmounted); single owner for the invariant (F2)
- src/Client/App.fs:226 — restrict DataLoaded population to mounted-hidden
  docs via markStale and always GC via pruneStaleToMounted (F1)
- src/Client/CanvasUpdate.fs:84 — clear the selected doc's stale mark on
  every reveal, not only when morphing; covers first-open and LRU-remount
  (F4, F3)
- src/Client/CanvasUpdate.fs:135 — prune StaleHiddenDocs in the archive
  success branch so an orphan mark can't poison a same-name regen (F5)
- src/Tests/CanvasAwarenessTests.fs:1213 — replace mutable ResizeArray test
  helper with a scoped let mutable accumulator (F6); add regression tests
  for markStale, pruneStaleToMounted, first-open clearing, and archive prune

Copilot-Session: d7c38d3c-d16c-4790-bb19-59d3c3caee33
# Conflicts:
#	src/Tests/CanvasAwarenessTests.fs
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 87093918-b9f2-4be7-a1de-d7bc8d212aac
- src/Client/App.fs:214 — preserve delayed hidden-document hash changes
- src/Client/App.fs:323 — synchronize mounted iframes across pane closure
- src/Client/App.fs:325 — separate iframe synchronization from notification freshness
- src/Client/CanvasState.fs:89 — model actual mounted iframe hashes
- src/Client/CanvasState.fs:89 — centralize mounted-state lookup
- src/Client/CanvasState.fs:102 — cancel stale state when content reverts
- src/Client/CanvasUpdate.fs:72 — use stale-aware open-document reveals
- src/Client/CanvasUpdate.fs:75 — remove the unreachable AgentDoc guard
- src/Client/CanvasUpdate.fs:89 — scope morph completion and retain failed work
- src/Client/CanvasUpdate.fs:133 — centralize every canvas reveal transition
- src/Client/CanvasUpdate.fs:432 — reject forged hidden-frame morph completion
- src/Tests/CanvasAwarenessTests.fs:1430 — share the command-message collector
- src/Tests/CanvasAwarenessTests.fs:1432 — replace accumulator iteration with recursion
- src/Tests/CanvasPaneTests.fs:242 — exercise a real hidden-iframe switch-back

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 67c3e514-599b-47a8-9fde-e007873118bd
Copilot AI balanced review requested due to automatic review settings August 12, 2026 17:19

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Preserves AgentDoc iframe state during live updates and avoids unnecessary morphs.

Changes:

  • Restores dirty form values, focus, and selection after morphing.
  • Tracks mounted iframe hashes and scopes morph messaging.
  • Adds unit/E2E coverage and updates canvas specifications.
Show a summary per file
File Description
src/Tests/CanvasPaneTests.fs Tests iframe persistence and message scoping.
src/Tests/CanvasAwarenessTests.fs Tests mounted-hash lifecycle and synchronization.
src/Tests/CanvasAuthoringDxE2ETests.fs Tests form-state restoration.
src/Extension/canvas-morph.test.mjs Adds morph state unit tests.
src/Extension/canvas-morph.js Implements state restoration and scoped morph completion.
src/Client/CanvasUpdate.fs Centralizes reveal and morph synchronization.
src/Client/CanvasTypes.fs Defines scoped morph identity.
src/Client/CanvasState.fs Tracks mounted iframe hashes.
src/Client/CanvasPane.fs Adds iframe identity and validates completions.
src/Client/AppTypes.fs Adds payloads to morph messages.
src/Client/App.fs Integrates hash reconciliation and synchronization.
docs/spec/future/canvas-roadmap.md Updates the preservation roadmap.
docs/spec/canvas-pane.md Documents the new synchronization model.

Review details

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 13/13 changed files
  • Comments generated: 4
  • Review effort level: Balanced

Comment thread src/Extension/canvas-morph.js
Comment thread src/Extension/canvas-morph.js Outdated
Comment thread src/Client/CanvasPane.fs Outdated
Comment thread src/Extension/canvas-morph.js
0101 and others added 2 commits August 13, 2026 12:43
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 14d12947-ef74-43cd-84e3-1a1ab93cc174
@0101
0101 enabled auto-merge (squash) August 13, 2026 11:25
@0101
0101 merged commit 5c40244 into main Aug 14, 2026
1 check 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