mirror of
https://github.com/storytold/figcraft.git
synced 2026-11-02 06:46:50 -06:00
20a16dfd5c8fa30f5667264b3ae6bb2b33acce18
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
94349d86b0 |
M9: live sessions per document
Live sessions are per document instead of one for the whole app.
- **Engine** (`crates/engine/src/live.rs`): `Session.live` is now `Lives`: the app-wide parts (the
installed link, the invite-link registration) plus one `Live` per session. One place resolves
"the session of this document": `Session::live()` (the active document's; status off when it
has none), `live_mut()`, `live_of(uid)`. Sync, undo, read-only checks, follow, cursor chat,
spotlight and presence all go through the session of the document they are about, so edits and
presence never cross. Sessions behind the active tab keep syncing; your presence there is empty.
- **Link** (`LiveLink`): every call takes the `SessionId` the engine picked and `poll` returns
`(SessionId, Event)`, so one link carries several sessions. The desktop link and the browser
link keep them in a shared table with one mailbox per session
(`crates/collab-net/src/sessions.rs`); each hosted document listens on its own port.
- **Commands**: `collab.*` act on the active document's session; no parameters changed.
`collab.peers` keeps its shape and gains `session` (its id, null when the document isn't in
one) and `sessions` (every session: `{session, document, status, reason, role, fileName, link,
peers}`). `collab.join` returns the new session and opens its file in a tab of its own without
touching other sessions; until then (or if it fails) it shows on the tab it was started from.
Starting a session for a document replaces only that document's own session. Closing a document
ends its session only.
- **UI** (`crates/ui-egui/src/live.rs`): the Share popover, avatars, cursors, chat, spotlight
banner, follow frame and read-only reason read the session of the tab in front, per window. What
belongs to one session in the window (cursors shown, your chat box, a report being written) is
dropped when another tab comes to the front. `ui.inspect`'s `live` gains `session` and
`sessions`. No new strings or command ids.
- **Docs**: `docs/collab-protocol.md`, `docs/mcp.md`, `docs/control-protocol.md`,
`docs/collaboration-parity.md`, `docs/gaps.md` (gap 2), `ROADMAP.md`.
|
||
|
|
1caf771e82 |
M8: comments and version history behaviour suite and fixes
A behaviour suite for comments and version history written from the public documentation (`crates/engine/src/history_behaviour_tests.rs`, 15 tests, about 80 table rows plus stepwise checks), each row with a one-line derivation; where the documentation is silent the row says so and pins today's behaviour. 4 of the 15 tests failed on the old code. Fixes, all in shared engine code: - **Live sessions: comment threads made in the session couldn't be used.** Their ids come from the creator's id space (e.g. 4294967297) and every thread command (`comment.reply`, `edit`, `react`, `resolve`, `move`, `delete`, `markRead`, `open`, `link`) refused them as "out of range". Comment ids are now parsed as ids, not small indexes. - **Restoring a version lost newer comments.** Comments are a conversation about the file, kept apart from its design history: restoring now keeps the current comments; a comment on a layer the version doesn't have stays where it was (on the nearest surviving parent, or the canvas). - **Restoring now keeps the replaced design in the history** as an autosave first, unless a version of it was just saved or restored (so work isn't only in the session's undo history). The checkpoint marker is now "none yet" for a freshly opened file and compares contents when normalising copied the document. - **A titled autosave becomes a named version** (`version.rename` clears `auto`), so it is no longer dropped when autosaves make room. - **Merging a branch adds to the main file's history:** the main file as it was (an autosave, when it changed since its last version), then `Merged “<branch>”`. - `version.restore` refuses up front for a view-only live session (nothing goes into the history). Pinned where the documentation is silent: pins go to the innermost frame under them (not to a leaf layer); copies, duplicates and duplicated pages come without comments; replying reopens a resolved thread; only authors delete their messages (no accounts); stepping past the last thread stays on it; comments show on the canvas by default; versions stay with whoever saved them in a live session. `crates/engine/src/collab_live_tests.rs`: the test `Room` is `pub(crate)` so the suite can run a live session. `crates/engine/src/cmd/props.rs`: one line reformatted by `cargo fmt` (it was unformatted on the base, which failed the fmt check). `crates/render/src/effects_behaviour_tests.rs`: the paint suite expected an offset drop shadow to grow the export on every side, but the later export suite made exports grow only where the shadow falls (40 x 50 for a shadow 10 down); the base failed the gate on it, so the expectation now says "grows" (wider or taller). No new commands. Docs: collaboration-parity, target-app-parity (area 16 85%/60% -> 85%/62%, 2-5 h -> 2-4 h; full parity ~306-595 h -> ~306-594 h; percentages unchanged at this rounding), ROADMAP (also corrects the stale area 16 row, 80%/58%/4-8 h), gaps (gap 4's landed list), mcp.md. |
||
|
|
94ff3d4df6 |
M9: collaboration: per-user undo, rejections, reconnect (#105)
* M9: collaboration: per-user undo, rejections, reconnect
Step 3 of docs/collab-protocol.md, the parts that don't need the transport:
- Per-user undo and redo (figcraft_collab::Client::{undo, redo}): each undoable batch is a step
(values before/after by target, nodes created/deleted). Others' batches ordered after the step
take its targets for good; creates invert to deletes (not when others built inside), deletes
re-create the subtree. An undo or redo waits for every earlier batch and is remade from the
confirmed state when it goes out; derived data follows as a follow-up batch.
- Rejections: refused batches leave the history (with an undo waiting on them) and queue a
Notice; the engine shows it through Session::message (the UI's toast).
- Offline queue and reconnect: Hello.resume {session, client_id, seq}; the server keeps a
bounded log and answers with the missed batches or a snapshot, plus what it did with the
client's batches (processed {last_batch, refused}); queued batches then go out.
Server::state / restore persist the session (client-id counter, log, session id).
- Presence carries editing_text {node, caret, selection}.
- Engine: documents in a live session (LiveDoc, Session::collab_*): commands, gestures and
groups sync as one step each; edit.undo / edit.redo route to the per-user history; remote
edits show under a gesture in progress. Outside a session snapshot undo is unchanged.
- Sim: dropped connections, undo/redo, and a checker that no undo reverts a change by someone
else its author had seen. New tests in undo_tests, reconnect_tests, collab_live_tests,
collab_undo_tests.
- CLAUDE.md / AGENTS.md: collab in the L2 layer list.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* M9: collaboration wording in the progress docs after per-user undo and reconnect
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* M9: protocol doc: what the engine's live-session tests cover
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|