The board's live title+body filter per 04-interactions.md § Search:
- SearchFilter — a pure value folding the query once (case- and
diacritic-insensitive substring, locale-stable); title OR body matches,
attachment filenames never searched; only the literal empty string is
inactive.
- One universe: the filter threads through SelectionGrammar's order lists
as a defaulted parameter, so ranges, Select All, arrow navigation, the
marquee, drop zones, count badges, and the shown trash all read the same
filtered set by construction; lanes are deliberately never filtered out
(an emptied lane keeps its slot with a 0 badge). Hidden cards leave the
selection through the existing constrain primitive, run on every query
change and as the last line of the reload resolve; the delete successor
is filtered so ⌫ never selects a hidden neighbour.
- The field: an NSSearchField-backed toolbar item (the toolbar's sole
default item); Edit ▸ Find ⌘F focuses it through a focused-value
presentation; stock field-editor dispatch — Return swallowed, Tab is the
keep-filter path to the board, board commands stay enabled except the
caret-chord pair, now one shared caretChordsYield expression.
- Escape is staged: clear the non-empty query (focus stays), hand an empty
field back to the board, clear an active search from board focus —
before Escape's clear-selection meaning.
- Creating a card clears the search (the placeholder funnel); a rename
deliberately gets no carve-out; filter reflow rides the content spring
keyed narrowly on the query.
903 unit tests (24 new).
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
⌘X/⌘C/⌘V for cards and lanes per 04-interactions.md § Clipboard:
- ClipboardStore stages full folder snapshots eagerly at the gesture into
Application Support (at most the current copy; sweep at launch and on
each copy purges what the pasteboard no longer references; a copy made
before quitting pastes whole after restart) and writes the pasteboard a
JSON manifest — every entry embedding its index.md, lane entries their
cards' too — plus plain-text titles.
- Cut is Finder-style deferred: items dim in place off pendingCut, void on
pasteboard takeover (changeCount, no timers), source-board close, or
per-item external tombstoning; the first armed paste moves the surviving
originals whole (tombstoned interior cards land in the destination's
trash), a second paste materializes copies from staging.
- Paste anchors by the shared flatten-order rule (NewCardTarget's anchor,
extracted); a tombstoned selection never anchors; lane paste reaches the
right end and stays enabled on a zero-lane board; paste into the source
board is the within-board lane duplicate; copies keep created, take
fresh GUIDs, and strip tombstoned cards; trash-sourced copies strip
deleted: at materialization; ⌘X is disabled on the trash side.
- A degraded paste is loud, never silent: staging gone → the embedded
index.md fallback lands content-intact, attachments absent, and a
BannerCenter-phrased row names what was lost.
- The standard Edit items validate through conditionally-attached
onCommand handlers, so AppKit's enablement mirrors the availability
predicates; text fields keep their own clipboard while focused.
879 unit tests (68 new).
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
The board's fixed grammar keys and the menu-backed chords of
04-interactions.md § Keyboard, per the Command Nexus inventory:
- Spatial arrow navigation (NavigationMath.nearest over the marquee
registry's frames — one geometry source), walking across interior
masonry columns, lanes, and into the shown trash; ⇧-arrows extend via
the same range function as ⇧-click and go inert at the liveness and
kind boundaries; ⌥-jumps with the ⌥↑ lane-domain escalation and ↓
descent; the empty selection seeds at the first lane's first card;
selection scrolls into view.
- selectionHead — the navigation cursor beside the anchor, set by every
click, moved by every arrow, dropped by the reload vanish rule.
- Board ▸ Open Card ⌘↩ (the one command enabled mid-edit: commits the
placeholder or rename and opens), Move Up/Move Down ⌥⌘↑/⌥⌘↓
(within-lane sort, gather-then-step, rank-permuting writes in one
bracket), Move Left/Move Right ⌘←/⌘→ (sole lane, one slot, never the
trash) — all validating and acting off one shared answer.
- Delete now selects the Finder-style successor sibling from the
pre-write snapshot, so repeated ⌫ walks down a lane; external
vanishing still only shrinks the selection.
- handleReturn rejects modified Returns; the trash column renders
eagerly so every row stays registered for navigation and the marquee.
686 unit tests (27 new).
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
The full pointer grammar of 04-interactions.md § Selection, stated once
as a pure function (SelectionGrammar) and reached through one store
funnel from every click surface — card face, lane header, lane empty
space, trash row:
- Plain click replaces and anchors; the lane surfaces (header and empty
space alike, per the settled one-lane-click-behavior rule) toggle off
on a sole-membership repeat.
- ⌘-click toggles within a homogeneous set; crossing any axis — cards
XOR lanes, live XOR trashed, card entries XOR lane entries in the
trash — degrades to a replace, so no click can produce a mixed
selection.
- ⇧-click ranges from the anchor in the (side, kind) order list: flatten
order for cards, lane order for lanes, the trash's deterministic sort
filtered to kind — the pointer twin of the keyboard's boundary rule
(the keyboard goes inert, the pointer skips).
- The rubber band (MarqueeSession/MarqueeMath) arms from lane empty
space, the board backdrop, and the trash column; side frozen at the
origin, trash bands homogeneous by topmost kind, frames self-registered
in strip space, geometric begin guard, never animated.
- Fast plain double-click opens the card window (⌘↩'s pointer twin);
Select All answers the standard Edit menu item via the responder
chain, trash- and kind-respecting.
- The range anchor lives in TransientBoardState beside the selection and
obeys the same reload vanish rule.
659 unit tests (28 new in SelectionGrammarTests).
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY