oficina / sheets Public

Undo reports nothing to undo when the newest own event fails to unseal Issue closed

Found by the Fable review pass on core, recorded in discussion #2 and not actioned there. Re-verified present on c4a3954.

Undo asks for the viewer's most recent own event:

internal/sheets/handlers_history.go:182 TabID: s.TabID, ActorID: viewer.ID, Limit: 1,

and then skips that event if it fails to unseal. Limit: 1 plus a skip returns an empty set, so the person is told there is nothing to undo while older undoable events of theirs are sitting right there in the log.

The failure shape is the bad one: it reads as a correct, calm answer about the state of their work rather than as an error. Someone who has just made a mistake is told the mistake never happened.

Fix: fetch a bounded window rather than a single row and take the newest event that actually unseals. The window needs a cap so a tab full of undecryptable events cannot turn one undo into an unbounded scan.

Test that must fail first: write two own events, corrupt the newest so it cannot unseal, then assert undo reverses the older one instead of reporting nothing to undo.

Fixed on branch fix/undo-skips-unsealable, commit 1ae7a1c, deployed to edge and verified on the process: GET /api/version returns 1ae7a1c (ten polls, ~90 seconds behind the promote this time).

Undo asks for a window now and takes the newest record that survives unsealing.

The bound is the part worth reviewing. Open-ended, a tab full of undecryptable events turns one undo into a scan of the whole log, unsealing every row on the way — so the window is capped at twenty, and the comment says outright that twenty is a judgement rather than a measurement. Far enough to cover what this exists for (an event or two under a key we no longer hold), short enough that the pathological tab costs twenty AEAD opens and stops. Past that, undo reports nothing to undo, which by then is true enough.

Two notes on the test. It corrupts a real event's payload_sealed rather than mocking the sealer, so it runs the same not-ok path a key rotation would produce. And it asserts on the cell's value afterwards, not on the notice: the notice is the thing that was wrong, so trusting it to report its own repair would be asking the defect to grade itself.

make test green including -race. Closing; not reviewed, per AGENTS.md §Review.