Every comment-trash purge kneels to the ownership gate — the container-whole retirement retires
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -105,6 +105,21 @@ final class CardWindowSession: CardSessionFlushing {
|
||||
/// object's to run, which is also true.
|
||||
var registerSessionStep: (@MainActor (CardWindowUndo, @escaping @MainActor () -> Void) -> Bool)?
|
||||
|
||||
/// **Where the close gives up this window's ownership of its card's comment trash** —
|
||||
/// `BoardStore.cardWindowDidClose(inCard:)`, wired by the host beside `registerSessionStep`
|
||||
/// (13-native-undo.md ▸ Interaction with the trash, ruled 2026-08-06):
|
||||
///
|
||||
/// > "an open card window is itself an owner of its card's comment trash — a retirement firing
|
||||
/// > while the card's window is open defers its purge to that window's close ... the close then
|
||||
/// > settles by the same gate."
|
||||
///
|
||||
/// A seam rather than a store reference, `registerSessionStep`'s reason: this object is a
|
||||
/// lifecycle and stays testable by having no idea what a board is. `nil` — a window that never
|
||||
/// joined its board — owns nothing on any store, which is also true.
|
||||
///
|
||||
/// Its **order** is the load-bearing part, and `endSession()` is where it is spelled.
|
||||
var endCardWindowOwnership: (@MainActor () -> Void)?
|
||||
|
||||
/// The Edit buffer's dirty text, a typed-in raw-source outlet, or an inline comment edit session
|
||||
/// holding keystrokes its file has not got — see `CardSessionFlushing`.
|
||||
///
|
||||
@@ -199,6 +214,15 @@ final class CardWindowSession: CardSessionFlushing {
|
||||
// still restores comments out of it. Registering answers whether the step took the purge on —
|
||||
// and a board whose substrate keeps no steps has already run it by the time that answer comes
|
||||
// back, which is how Pro keeps purging at the close flush without a word about tiers here.
|
||||
//
|
||||
// **This window stops owning its card's comment trash first** (ruled 2026-08-06 — the
|
||||
// open-window carve-out). While the window is open the store defers every purge of this
|
||||
// card's trash, because the entries this session deleted are backed by *this* stack's fine
|
||||
// steps and the board-stack inventory cannot see them. The close is where that stops being
|
||||
// true, and it has to stop being true **before** either branch below runs: a no-step close
|
||||
// that unmarked itself afterwards would defer its own purge into a no-op, and a coarse step
|
||||
// registered here can retire in the same breath (its registration clears the redo stack).
|
||||
endCardWindowOwnership?()
|
||||
let purge: @MainActor () -> Void = { [comments] in comments.purgeTrashNow() }
|
||||
if registerSessionStep?(undo, purge) != true {
|
||||
purge()
|
||||
@@ -609,7 +633,17 @@ struct CardWindowHost: View {
|
||||
/// The pane's two window-scoped facts are set *before* the read, because both of them are things
|
||||
/// the read's results are resolved against: the folder every comment's attachments hang off, and
|
||||
/// whether the lock is on.
|
||||
///
|
||||
/// **And the window takes ownership of its card's comment trash here** (13-native-undo.md ▸
|
||||
/// Interaction with the trash, ruled 2026-08-06): "an open card window is itself an owner of its
|
||||
/// card's comment trash". From this line until `CardWindowSession.endSession` gives it back, a
|
||||
/// purge of this card's trash — a foreign step's retirement, another window's close — defers
|
||||
/// entirely, because the fine steps backing this session's deletes live on a stack the board's
|
||||
/// inventory cannot see. The sweep below is unaffected and runs as it always has: it is gated on
|
||||
/// `backedContent`, and a window that has not made a gesture yet holds nothing that gate is
|
||||
/// missing.
|
||||
private func openCommentThread(store: BoardStore) {
|
||||
store.cardWindowDidOpen(inCard: ref.cardIdentity)
|
||||
if case let .shows(placement) = Self.cardWindowFate(cardID: ref.cardID, in: store.snapshot) {
|
||||
session.comments.cardFolder = Self.cardFolder(root: store.rootURL, placement: placement)
|
||||
}
|
||||
@@ -689,6 +723,11 @@ struct CardWindowHost: View {
|
||||
session.registerSessionStep = { [weak store] undo, purge in
|
||||
store?.registerCardSession(undo, inCard: cardID, retiring: purge) ?? false
|
||||
}
|
||||
// The close half of the open-window carve-out (13 ▸ Interaction with the trash, ruled
|
||||
// 2026-08-06). Its open half is `CardWindowHost.openCommentThread`, beside the residue sweep;
|
||||
// the pair has to be wired from the two places the window already calls into the store, and
|
||||
// these are they. A released store owns nothing to give up, which is what `weak` says.
|
||||
session.endCardWindowOwnership = { [weak store] in store?.cardWindowDidClose(inCard: cardID) }
|
||||
}
|
||||
|
||||
/// Points the comments pane at its card — **the one place every comment gesture learns which card
|
||||
|
||||
Reference in New Issue
Block a user