Comments, phase 1 — storage, writer primitives, and the undo inventory
The kind: comment field table lands in IntegrityRules (the per-kind hook's first exercise), CommentThread reads one card's thread window-scoped (the board walk stays O(cards)), and CommentWriter gains the five gestures: draft save, post (rename .draft to a fresh UUID, created/modified restamped in the bracket), edit, delete into comments/.trash/, and the purge with its crash-residue memo. Post and delete register move-based undo steps; draft saves, edits, and the purge deliberately register nothing (13's no-capture rule). Copy boundaries strip comments/.trash, carry .draft verbatim, and remint threads; comments graduates to a displacing claimed name, with .draft, .trash, and a comment's attachments claimed one level down. CommentPath classifies changed paths into the 06 verb family for later announcer/composer wiring. One stated narrowing pending a ruling (filed on the findings board): the copy transaction's refuse-whole preflight stays cards-and-lanes — an unstampable copied comment copies verbatim with a log line, because comment defects never refuse. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -848,6 +848,31 @@ public final class BannerCenter {
|
||||
// The buffer is still on screen: the banner says the app could not put those bytes on
|
||||
// disk, not that they are gone.
|
||||
if let title { "Couldn't apply source changes to '\(title)'" } else { "Couldn't apply the source changes" }
|
||||
|
||||
// **The comment family names the card, because that is the title these operations carry** —
|
||||
// a comment has none of its own (01-storage-format.md § Enhanced schema: "No `title`, no
|
||||
// `order`"), and the card is the thing on the window in front of them. Each sentence is the
|
||||
// gesture's own word, the vocabulary's standing rule: they pressed ⌘↩, or Delete, or nothing
|
||||
// at all in the draft's case.
|
||||
case let .saveCommentDraft(title):
|
||||
// **"draft", never "save the comment"**: nothing has been posted, and a banner claiming a
|
||||
// comment could not be saved would name one that does not exist yet. The typed text is
|
||||
// still in the composer — this says the app could not put it on disk.
|
||||
if let title { "Couldn't save your draft comment on '\(title)'" } else { "Couldn't save your draft comment" }
|
||||
case let .postComment(title):
|
||||
// The Comment button's own word (05-card-window.md ▸ The comments column, "⌘↩ posts").
|
||||
// The draft is untouched on disk, which is what makes this a retry rather than a loss.
|
||||
if let title { "Couldn't post your comment on '\(title)'" } else { "Couldn't post your comment" }
|
||||
case let .editComment(title):
|
||||
if let title { "Couldn't save your edit to a comment on '\(title)'" } else { "Couldn't save your edit to the comment" }
|
||||
case let .deleteComment(title):
|
||||
if let title { "Couldn't delete a comment on '\(title)'" } else { "Couldn't delete the comment" }
|
||||
case .purgeCommentTrash:
|
||||
// No title, and no mention of a trash the user has never seen: `comments/.trash/` is
|
||||
// "never a UI surface", so the sentence is about the *card's* files being tidied — the
|
||||
// agent guide's posture, one level down. Nothing is lost either way; the next window
|
||||
// open sweeps again.
|
||||
"Couldn't tidy up deleted comments"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user