The shell's version cards (shell/node-versions-source.ts):
- a version's change and undo target are the state it replaced, the
History entry right before its first copy, not the card before it: after
a restore those differ, and undo went to the wrong version (and not
where restore_version steps_back=1 goes)
- a card restores the newest copy of its content, as restore_version
does, so page settings the user changed (a "user" copy) are kept
- a blank page after a drawing is a clear of the canvas, a version of its
own; only the blank page before any drawing is hidden
- numbers and changes are keyed by content, not by the first copy's id,
so a version keeps them when its first copy drops out of the server's
20-entry buffer; the caches start over for another server state (the
process restarted: entry ids name other content)
The server's History (src/history.ts):
- firstCopyIds compares each entry with the first of every group only: a
bare model matches any page name, so "same content" is not transitive,
and a card could show one document and restore another
- the time and pages fields had no reader; pages parsed every XML once
more on every write
Reading History (src/http-server.ts, shell/mcp-sync-core.ts):
- GET /api/state and a push's answer carry a History key (entry count,
newest id, the entry on the canvas); the shell reads History again only
when it changes, so a hand edit no longer downloads every entry's XML and
thumbnail
- a failed History read is told again at the next poll
- a History list from a state the poll has not seen yet is dropped
The shell's VersionsSource (shell/node-versions-source.ts) reads GET
/api/history through the sync and shows one version per distinct content
(a restore's copy folds into the entry it copies; the blank page is none),
numbered as they first appeared, with what changed since the one before.
The entry the server says is on the canvas marks the version; undo and
redo of the newest version restore the one before it, or it again, through
POST /api/restore, so hand edits stay as versions of their own. The cards
sit in a panel beside the canvas (toggle in the header); the strip and
Compare come from the shared canvas components. The sync tells listeners
once per server version, and when History changed without one, so the
list is read again only then.