Realign search, clipboard, and lane-hover code with the second batch

Creation now clears the search by mechanism, not gesture: one seam
(noteUserCreation) states 04's rule once, called from the placeholder
funnel, paste — cards and lanes, after the staleness guard so a stale
paste clears nothing — and Finder file-drop creation; the attach path
deliberately doesn't clear, and cross-board arrivals and New Lane stay
outside the seam (a transfer isn't creation; a lane can't be born
invisible). An open inline rename now survives the filter hiding its
card: the model already kept the editor, but the field renders in the
card's slot, so renderedCards keeps the renaming card's slot exactly as
long as the editor is open — the query stands throughout, and commit or
Escape lets the predicate apply in the same pass. Verified conformant
and newly pinned: query-emptied lanes keep their slot with a 0 badge,
pasteboard staleness (takeover before paste and mid-staging both no-op),
out-transition reachability and the strip pre-divide hold by
construction with comments citing their rulings.

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
2026-07-28 08:45:12 -04:00
parent 524488122f
commit 5c0c0e5619
9 changed files with 423 additions and 21 deletions
+11
View File
@@ -311,6 +311,15 @@ public final class ClipboardStore {
/// **The armed cut is tried first and consumed on success** "first armed paste MOVES the
/// surviving originals a second paste materializes copies from staging" and everything else
/// is the copy path, which is also where a voided cut lands.
///
/// **A paste is a user-initiated creation, so it clears the destination's search**
/// (04-interactions.md § Search, stated by mechanism "N, Return-creation, the header button,
/// empty-space double-click, paste, and Finder file drops alike"). Cards and lanes alike the
/// clipboard holds one or the other, and either arrives as an item the query may well not match.
/// Unqualified, too: 04 names the *mechanism*, so the armed cut's move clears exactly as the copy
/// does rather than earning a sub-rule for the one case where the items were already on this
/// board. It is cleared here rather than at V so the two staleness guards keep their meaning: a
/// paste the pasteboard moved under lands nothing, and so clears nothing.
private func perform(_ manifest: ClipboardManifest, plan: Plan, into store: BoardStore) {
refresh()
// The pasteboard moved under this paste (another app copied while the chain settled): the
@@ -318,6 +327,8 @@ public final class ClipboardStore {
// doing nothing.
guard payload?.copyID == manifest.copyID else { return }
store.transient.noteUserCreation()
if let move = armedMove(for: manifest) {
let sources = move.folders.map(BoardStore.ItemSource.folder)
switch plan {