Land the 2026-07-31 design-ruling sweep

Uncommitted ruling prose from the pro-m1 sessions, committed as found:
trash sorts newest-first by modified stamp (no rank minting); kind-blind
trash selection; native undo in every tier with the provider following
the board; session-coarsening for card-window stacks; column-major
masonry; changed-path channel (02); window-scoped comment-thread heals;
commit-message vocabulary growth; integrity commit author; signature
passed per-commit instead of repo config; repo-state validation
tightening; comments pane defaults on; draft close-failure guard;
deferred comment-trash purge; 2.0 ships only with pro-m1 (RELEASE.md).

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
2026-07-31 17:49:18 -04:00
parent b8667699ae
commit ade7d34cd8
14 changed files with 61 additions and 58 deletions
+4 -4
View File
@@ -12,7 +12,7 @@ The board window: layout, lanes, cards, and styling. Interaction mechanics (sele
Toolbars are **pure enhancement**: every function they host already has a menu item + shortcut (04-interactions.md's contract), so nothing below is anyone's only path. Both windows' toolbars are **user-customizable, macOS-native** (right-click ▸ Customize Toolbar…, drag to rearrange, system overflow and icon/text display options) — the sets below are shipped defaults, not verdicts. Toolbar item labels match their menu-item titles exactly (Show Trash, Edit Body, Raw Source, …), minus any trailing ellipsis (macOS convention: "Add Attachment…" labels as Add Attachment) — one vocabulary everywhere, and the customize palette self-documents against the menus. One exception: the Undo/Redo toolbar items keep static labels — NSUndoManager rewrites their menu titles dynamically ("Undo Move Card…", 04-interactions.md ▸ Configurable bindings), which a toolbar label doesn't track.
- **Board window default: the search field, nothing else** — trailing, the one default item; the titlebar stays clean. ⌘F always summons search: with the field removed from the toolbar, invoking it surfaces the field transiently until the search clears. **Catalog** (available via Customize): New Card, New Lane, Undo, Redo (the pair disabled on boards with no undo provider in the composed tier — under Pro, no-git and repo-nested boards, matching their menu items — 06-history-undo.md; in base, 13-native-undo.md's stack serves every board and the pair disables only under locks and empty stacks), Show Trash (toggle state matching the View menu checkmark). The board popover deliberately has **no toolbar item** — the window-title widget is its committed home (below), and a second entry would muddy it.
- **Board window default: the search field, nothing else** — trailing, the one default item; the titlebar stays clean. ⌘F always summons search: with the field removed from the toolbar, invoking it surfaces the field transiently until the search clears. **Catalog** (available via Customize): New Card, New Lane, Undo, Redo (the pair disabled only on repo-nested boards, under locks, and on empty stacks — re-ruled 2026-07-31: the provider follows the board, so gitless boards bind 13-native-undo.md's native stack in **every** tier and Pro git boards bind the git provider — 06-history-undo.md), Show Trash (toggle state matching the View menu checkmark). The board popover deliberately has **no toolbar item** — the window-title widget is its committed home (below), and a second entry would muddy it.
- **Card window default: Edit Body · Raw Source · Add Attachment** — the window's three committed functions, all discoverable from its toolbar; the catalog is the same trio. Edit Body is a **single toggle button** (on-state in Edit — mirroring the View ▸ Edit Body checkmark and the ⌘E/Return/Escape grammar; the pathfinder's segmented Preview|Edit is retired). Raw Source is likewise a toggle showing on-state; while source mode is active, Edit Body disables (Cancel/Apply own the exits — 05-card-window.md). Add Attachment stays enabled in every mode — attachment operations never touch `index.md`, so they're safe alongside a raw edit (the sidebar's feedback returns on exit).
## Lane
@@ -61,9 +61,9 @@ The window-title widget opens the **board popover** — the one board-level surf
**Resettled 2026-07-28 — the materialized trash.** The tombstone model (a `deleted:` flag on items left in place, rendered by a pure-view quasi-lane) is **retired**: it generated a standing tax of nesting rules — ancestor walks, effective liveness, entry-vs-universe splits, kind-homogeneous selection — that this design replaces wholesale. Deletion is now a **move**: deleting a card moves its folder into **`<board-root>/.trash/`**, a reserved, materialized container (01-storage-format.md). A trashed card is an ordinary card in a special place — search, selection, rendering, styling, and clipboard all treat it exactly like any other card, and `.trash/` is self-describing in Finder and to agents.
- **Lanes trash too** (re-ruled 2026-07-29, retiring "cards only" and with it the design's sole destructive delete): deleting a lane moves its folder — subtree intact — into `.trash/`, exactly as a card moves; `kind: lane` in its frontmatter is what tells a trashed lane from a card in the flat container (01-storage-format.md ▸ Deletion), stamped on the way in when absent. The no-dialog posture survives for a better reason: the move is recoverable, so nothing needs confirming. Native undo's inverse is the ordinary move back (13-native-undo.md — the capture/recreate machinery retires). **A trashed lane is an opaque unit**: one distinct dimmed row showing its title and held-card count ("Doing — 5 cards"), no styling accents, never expandable; its cards are invisible to search and not individually addressable — it restores whole or purges whole. The row matches the search filter by lane title only. Lane rows and cards interleave in the one trash column purely by trash rank.
- **Entry is always at the top** (settled): every arrival, card or lane — ⌫/⌘⌫ delete and drag-to-trash alike — lands at the trash's topmost position, minting an `order` rank above the current top. Newest-first ordering falls out of ordinary ranks by construction: **there is no `deleted:` key and no timestamp sort** — the trash sorts by `order` like any lane. The move **stamps `modified`** (a container-changing move — 01's `modified` scope; deletion is an edit to the card's story), which is what a future age-based auto-purge will read (deferred, 01-storage-format.md).
- **Rendering**: trailing (rightmost) position when shown, visually distinct — dimmed/hatched header, trash SF Symbol, count badge; no new-card button; not draggable, not resizable, excluded from lane reordering. Fixed one width unit, consumed only while shown; Show/Hide Trash is a re-divide trigger (Layout above). **Visibility**: hidden by default; View ▸ Show Trash toggles (no default chord — ⇧⌘T belongs to the system's Show Tab Bar, 11-command-nexus.md); per-open transient state, resets to hidden, never persisted. Hidden, the trash is invisible to every gesture and to search; shown, its cards participate in the filter **exactly like any other card** — the point of the pivot.
- **Lanes trash too** (re-ruled 2026-07-29, retiring "cards only" and with it the design's sole destructive delete): deleting a lane moves its folder — subtree intact — into `.trash/`, exactly as a card moves; `kind: lane` in its frontmatter is what tells a trashed lane from a card in the flat container (01-storage-format.md ▸ Deletion), stamped on the way in when absent. The no-dialog posture survives for a better reason: the move is recoverable, so nothing needs confirming. Native undo's inverse is the ordinary move back (13-native-undo.md — the capture/recreate machinery retires). **A trashed lane is an opaque unit**: one distinct dimmed row showing its title and held-card count ("Doing — 5 cards"), no styling accents, never expandable; its cards are invisible to search and not individually addressable — it restores whole or purges whole. The row matches the search filter by lane title only. **The held count is a load-time disk fact** (pinned 2026-07-31): counted from a subtree the snapshot deliberately does not hold — the model's one number not derivable from the model — refreshed by reload like every snapshot field (its changes speak in the digest, 10-accessibility.md); the freight confirm's "…and its 5 cards" is thereby the design's one confirmation counting unrendered content, honest as of the latest reload — the opaque-unit trade, deliberate. Lane rows and cards interleave in the one trash column by `modified` descending (the trash's sort — Entry below).
- **Entry is always at the top — the trash sorts by `modified` descending** (re-ruled 2026-07-31, retiring the arrival rank mint): every arrival, card or lane — ⌫/⌘⌫ delete and drag-to-trash alike — lands at the top because the move **stamps `modified`** (a container-changing move — 01's `modified` scope; deletion is an edit to the card's story), and that stamp is the position: newest-first with no `order` rewrite, no rank minting, the item's `order` key riding along untouched for its eventual restore. Ties break by title (case-insensitive), then folder name. **The merged order is one derivation** (both kinds interleaved — the column, the keyboard grammar, and the path resolver all read the same sequence; a second implementation of "the row below this one" is a bug by definition). The stamp is also what a future age-based auto-purge will read (deferred, 01-storage-format.md).
- **Rendering**: trailing (rightmost) position when shown, visually distinct — dimmed/hatched header, trash SF Symbol, count badge**the badge counts rows** (blessed 2026-07-31): its one invariant is matching what the column draws, so a trashed lane counts as one whatever its freight; card-level totals surface where consequences are decided — the freight confirm and the spoken accessibility value; no new-card button; not draggable, not resizable, excluded from lane reordering. Fixed one width unit, consumed only while shown; Show/Hide Trash is a re-divide trigger (Layout above). **Visibility**: hidden by default; View ▸ Show Trash toggles (no default chord — ⇧⌘T belongs to the system's Show Tab Bar, 11-command-nexus.md); per-open transient state, resets to hidden, never persisted. Hidden, the trash is invisible to every gesture and to search; shown, its cards participate in the filter **exactly like any other card** — the point of the pivot.
- **No Put Back** (settled): the valuable item is the card (or lane); where it goes on the way out is the user's cheap decision. Restoring is an ordinary move out: **drag** a trash card into any lane at any position — or a trashed lane row to a lane-strip slot — or **⌘X in the trash, ⌘V** — into a lane for cards, after the anchor lane for a trashed lane (04-interactions.md's lane-paste rule verbatim); the clipboard works on trash items like on any item, which is also the keyboard-native restore path (10-accessibility.md). Dropped on another board it follows the drag locality model (04-interactions.md).
- **No editing in the trash**: trash cards don't open — double-click stops at selection; move it out first — and a trashed lane row never expands. Moving a card to the trash dismisses its open card window (05-card-window.md), and an external move-in observed by reload does the same; a lane entering the trash dismisses the open card windows of every card it carries (they entered the trash with it).
- **Permanent deletion**: on a trash selection, **Delete (⌫/⌘⌫) is permanent** — one delete vocabulary, staged by place: on the board it moves to the trash, in the trash it removes the folder. **Delete Immediately is deliberately absent** (removed 2026-07-30): Finder's ⌥⌘⌫ answers disk-space pressure boards don't have, and it was the one gesture reaching unrecoverable straight from the board — permanence is only reachable inside the trash, where the staging makes the loss visible. The trash-side Delete **confirms exactly where the loss is real** (carried over): on boards without app-managed git history the alert stands between one keystroke and unrecoverable deletion; on git boards it acts immediately (delete-never-forgets). Confirms name the freight honestly — a trashed lane's alert counts its cards ("Permanently delete lane 'Doing' and its 5 cards"). **Empty Trash…** (⇧⌘⌫) confirms everywhere and purges the whole `.trash/`, lane subtrees walked, search-independent, the confirmation naming the full count ("Permanently delete 41 cards", "… 41 cards and 2 lanes containing 9 more cards" — 06-history-undo.md's plural folding); menu validation's "non-empty" reads `.trash/`, not the filtered view.