Register inverse operations at the Writer boundary

The store is the Writer boundary, so it computes and registers
inverses: a weak history sink bound at session composition, one
HistoryStep per gesture at exactly the brackets that were already one
performWrite each — multi-card moves, style batches, width pairs, and
multi-row restores each undo as one plurally-titled step, and the Edit
session registers once at the flip from the bytes disk held before its
first landed write, debounce ticks registering nothing. Crossings run
through performWrite, so an undo brackets the watcher, echoes through
the reload, and reaches every window; every closure captures values,
never snapshots. The inventory follows 13 exactly: moves return to
origin lane and order, renames restore or remove the title key,
restyles and resizes restore field values or absence, tombstones and
restores swap with captured timestamps, and an undone create is a real
removal — no trace — with redo re-materializing the same UUID from
bytes captured at gesture time. Purge, attachments, repair,
bookkeeping, checkbox flips, raw Apply, and the whole arrival family
register nothing, each exclusion documented where it lives. Step names
speak 06's verb vocabulary through the new HistoryPhrase.

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
2026-07-28 14:24:31 -04:00
parent 93fad2ef1e
commit 2148ebb379
8 changed files with 1732 additions and 64 deletions
+6
View File
@@ -413,6 +413,12 @@ struct CardWindowHost: View {
guard let store else { return .vanished }
return store.writeCardBody(inCard: cardID, body: text)
}
// The session's one undo step, at the EditPreview flip (13-native-undo.md Rules). Weakly,
// `save`'s rule: a session ending after the board window has gone registers nothing rather
// than resurrecting a released store and the board's stack died with it anyway.
session.body.registerUndo = { [weak store] priorBody, newBody in
store?.registerBodyEdit(inCard: cardID, priorBody: priorBody, newBody: newBody)
}
bodyPresentation.flushEdits = { [session] in
session.body.endEditSession()
}