Motivation
The Desktop canvas view shows only the current content. It doesn't show who signed the current revision, and there's no way to look at an earlier one. In a channel where agents and people both edit the canvas, there's currently no in-app way to answer "who changed this, and what did it say before?"
The revisions themselves are already on the relay. KIND_CANVAS is 40100 (crates/buzz-core/src/kind.rs:434-435), which is neither replaceable (kind.rs:701-705 covers 0, 3, 41 and 10000–19999) nor parameterized-replaceable (30000–39999, kind.rs:708-713). Canvas updates take the ordinary event-insert path, so a later save doesn't supersede the earlier rows.
The attribution already crosses the IPC boundary too. get_canvas asks for limit: 1 and returns the newest event's content, author and timestamp (desktop/src-tauri/src/commands/canvas.rs:15-41), and the TS bridge normalizes those to author and updatedAt (desktop/src/shared/api/tauri.ts:410-421). But ChannelCanvas.tsx:38 reads only .content, so neither value is rendered.
Proposed solution
A read-only first slice:
- A line on the canvas showing who last updated it and when, resolving the pubkey through the existing profile batch query so people and agents render the same way
- A history view listing earlier revisions with author and timestamp
- Selecting a revision shows that content read-only, with a way back to current
Deliberately out of the first slice: diffing between revisions, and restore.
Alternatives considered
Restore-as-new-event would be the natural follow-up, since publishing an old revision's content as a new 40100 keeps the history append-only and makes the restore itself attributable. Kept separate so the read-only view isn't blocked on it.
Diffing needs a dependency decision. desktop/src/features/messages/lib/parseDiff.ts:18-34 parses an existing unified diff via react-diff-view; it doesn't generate one, and there's no text-diff generator in desktop/package.json. That's a separate conversation.
Additional context
Closest prior art: #2809 proposes surfacing the current revision's author, timestamp and event ID in the canvas panel, and explicitly lists revision browsing as a non-goal. This issue is that follow-up, so the attribution line overlaps and should probably follow whatever placement #2809 settles on. Merged PR #1755 exposes the current canvas revision id and timestamp to ACP agents, but not to users. I didn't find an open issue or PR asking for revision history itself.
Two things worth deciding if this is wanted:
- How many revisions to load by default, and whether to cap or paginate. A heavily-edited canvas could have a lot of rows.
- Whether legacy canvases are in scope. The older singleton
channels.canvas column still exists (migrations/0001_initial_schema.sql:72-80, crates/buzz-db/src/channel.rs:297-324), so canvases written through the pre-event path won't have history to show. Current kind:40100 revisions need no migration.
Happy to implement the read-only slice if the scope looks right.
Motivation
The Desktop canvas view shows only the current content. It doesn't show who signed the current revision, and there's no way to look at an earlier one. In a channel where agents and people both edit the canvas, there's currently no in-app way to answer "who changed this, and what did it say before?"
The revisions themselves are already on the relay.
KIND_CANVASis 40100 (crates/buzz-core/src/kind.rs:434-435), which is neither replaceable (kind.rs:701-705covers 0, 3, 41 and 10000–19999) nor parameterized-replaceable (30000–39999,kind.rs:708-713). Canvas updates take the ordinary event-insert path, so a later save doesn't supersede the earlier rows.The attribution already crosses the IPC boundary too.
get_canvasasks forlimit: 1and returns the newest event's content, author and timestamp (desktop/src-tauri/src/commands/canvas.rs:15-41), and the TS bridge normalizes those toauthorandupdatedAt(desktop/src/shared/api/tauri.ts:410-421). ButChannelCanvas.tsx:38reads only.content, so neither value is rendered.Proposed solution
A read-only first slice:
Deliberately out of the first slice: diffing between revisions, and restore.
Alternatives considered
Restore-as-new-event would be the natural follow-up, since publishing an old revision's content as a new 40100 keeps the history append-only and makes the restore itself attributable. Kept separate so the read-only view isn't blocked on it.
Diffing needs a dependency decision.
desktop/src/features/messages/lib/parseDiff.ts:18-34parses an existing unified diff viareact-diff-view; it doesn't generate one, and there's no text-diff generator indesktop/package.json. That's a separate conversation.Additional context
Closest prior art: #2809 proposes surfacing the current revision's author, timestamp and event ID in the canvas panel, and explicitly lists revision browsing as a non-goal. This issue is that follow-up, so the attribution line overlaps and should probably follow whatever placement #2809 settles on. Merged PR #1755 exposes the current canvas revision id and timestamp to ACP agents, but not to users. I didn't find an open issue or PR asking for revision history itself.
Two things worth deciding if this is wanted:
channels.canvascolumn still exists (migrations/0001_initial_schema.sql:72-80,crates/buzz-db/src/channel.rs:297-324), so canvases written through the pre-event path won't have history to show. Current kind:40100 revisions need no migration.Happy to implement the read-only slice if the scope looks right.