perf: fast large files in debug builds; migrate game modules, paint review, deterministic game, map and video (#112)

* perf: make saving and opening a large file fast in a debug build

Saving eight megabytes took three and a half seconds in a debug build and
opening them two and a half, and a large image took a second more to reach
its editor. Three things were running unoptimised:

- Vault is generic over its store, so sealing and opening a chunk were
  compiled into whichever crate used the vault, at that crate's opt-level.
  They are methods on ContentKey now, compiled once in be-store, and
  be-store, the cipher and hash crates and the websocket crates are built
  at opt-level 2 in the dev profile.
- Byte fields in be-protocol and the plugin protocol were serialised one
  element at a time. serde_bytes writes the same bytes, as a length and a
  copy.

Saving eight megabytes now takes 0.3 seconds, opening them 0.13, and
encoding them for a plugin 14 milliseconds rather than half a second.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016D2MXiSb7TrGBEdVe69fBM

* feat: migrate game modules, paint snapshots and paint reviews

A game module and a paint snapshot are Blobs, with a source name and a
path and hash for headers, and a paint review is a be-model document whose
approvals are a Map from path to the hash and snapshot approved. The review
references its snapshots, and deleting or replacing one forgets or repoints
its approval through the child bridge. The old blocks are emptied, and
PaintSnapshot keeps its fingerprint.

The game module editor replaces its file with replace_content, the
deterministic game reads the module it plays through content_of, and the
paint review writes an approved snapshot as a new block's content or
replaces an existing one's. The deterministic game itself stays on the old
stack: it records the account behind each move, which the old server stamps
and the new stack has no way to vouch for yet.

ContentProjection::loaded is a signal for a view that must tell an empty
block from one that has not arrived. ContentHarness keeps its content in a
ContentStore a test fixture can share, which also takes the content an
editor seeds or replaces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016D2MXiSb7TrGBEdVe69fBM

* feat: migrate the deterministic game and the map

The deterministic game is a be-model document: the module it plays and a
list of moves, each the account that made it and the action. The account
is whatever the sender says; nothing vouches for it yet, and the guide says
why signing operations would not be enough.

The map is a be-model document of places, each a register for the block it
shows, its position and its colour, and a register for the preview region.
Positions and regions are normalised when written, and adding, deleting or
replacing a child places, drops or repoints its points. The map's value
types move into be-block, and block_client re-exports them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016D2MXiSb7TrGBEdVe69fBM

* feat: migrate the video

The video is a be-model document whose clips form a tree: a clip attached
to another is an object in that clip's list, carrying its offset, block,
length and effects. Reattaching is a move, which the model refuses when it
would make a cycle, and removing a clip takes what is attached to it, so
the old cycle checks and rippling removal are gone. The editor keeps
speaking VideoOperation, which VideoProject::edit_for turns into an edit
against the content shown, and reads a flattened Video for its timeline.

The drop target memo read the video before subscribing to anything, so a
target computed before the content arrived was never computed again; it
subscribes first now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016D2MXiSb7TrGBEdVe69fBM

---------

Co-authored-by: Claude <noreply@anthropic.com>
5e48898db6pfg committed on 9/24/2026, 5:00:15 PM· committed by GitHubparent54aa0cc
64 files changedLine totals unavailable