Lanes delete into the trash — the design pass

User-proposed and ruled 2026-07-29, retiring the design's sole
destructive delete: lane delete becomes a move into .trash/, exactly as
cards move. Full rationale on the Redesign board's Resolved card;
implementation is post-m12 ("Lanes delete into the trash" on the
Backlog) — the docs deliberately lead the code until then.

- 01: kind: lane always present on lane frontmatter (created with the
  lane, healed on touch, never stripped) — discriminates lane from card
  in the flat .trash/, where an empty lane is shape-identical to a
  card; legacy deleted: on lanes is now simply ignored (no migration,
  no notice — backward compatibility deliberately not funded).
- 03: trashed lane = opaque dimmed row with card count, restores whole
  or purges whole; confirms count lane freight; fixed 03's own copy of
  the "native undo restores a permanent delete" contradiction.
- 04: delete staged by place for lanes too (board→trash no dialog,
  trash→permanent confirmed); lane drop on shown trash deletes;
  kind-homogeneous trash selections, ranges skip by kind; ⌘X/⌘V restore
  rides the existing lane-paste rule.
- 10: trashed lane is one flattened element, never a container.
- 13: lane delete inverse = ordinary move back; recreate-from-capture
  retires — no destructive delete remains outside the trash.
- 08: agent guide v6 — lanes trash by move, kind: lane taught.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
2026-07-29 12:42:49 -04:00
parent 89d4d983e6
commit 1c263b9f2e
6 changed files with 26 additions and 24 deletions
+5 -4
View File
@@ -73,6 +73,7 @@ Body: board description (free Markdown).
|---|---|---|---|
| `order` | number | yes | Rank among lanes, ascending = left-to-right |
| `width` | integer | no | Width multiplier ≥ 1 (default 1); no cap |
| `kind` | string | no | Always `lane` (ruled 2026-07-29) — written at lane creation, healed on touch when absent, never stripped. Redundant with depth on the live board; load-bearing inside `.trash/`, where it discriminates a trashed lane from a card (Deletion below). Cards never carry it. |
Body: lane description / WIP policy / notes.
@@ -113,12 +114,12 @@ Carried over unchanged — gapped fractional ranks:
The tombstone model is **retired** — no `deleted:` key, no in-place flags, no ancestor-walked hiding. Deletion is a **move**:
- **Deleting a card moves its folder into `<board-root>/.trash/`** — a reserved, app-claimed name at board root (joining `CLAUDE.md` and the seeded `.gitignore` on the claimed list; agents and hand-editors should treat it as the app's). `.trash/` holds card folders directly — same shape as a lane's children, no `index.md` of its own. Every arrival lands at the **top**: the move mints an `order` rank above the current topmost, so the trash sorts newest-first by ordinary ranks — no timestamp sort, no tie-break rules. The move **stamps `modified`** (deletion is an edit to the card's story — the deliberate exception to moves-don't-stamp), which is what a future age-based auto-purge will read (deliberate follow-up, not in the initial release).
- **Deleting a lane is physical** — the folder and its contents are removed. There is no lane trash; the recovery net is native undo in-session (13-native-undo.md) and git history on git boards (06-history-undo.md's delete-never-forgets).
- **Restore is a move out**: any move of a card folder from `.trash/` into a lane — drag, or cut+paste — is an ordinary move; there is no restore-specific machinery and no Put Back. Position and lane are chosen at restore time.
- **Deleting a card or a lane moves its folder into `<board-root>/.trash/`** (lanes joined 2026-07-29 — retiring the design's sole destructive delete) — a reserved, app-claimed name at board root (joining `CLAUDE.md` and the seeded `.gitignore` on the claimed list; agents and hand-editors should treat it as the app's). `.trash/` holds card and lane folders interleaved directly, no `index.md` of its own. Every arrival lands at the **top** regardless of kind: the move mints an `order` rank above the current topmost, so the trash sorts newest-first by ordinary ranks — no timestamp sort, no tie-break rules. The move **stamps `modified`** (deletion is an edit to the item's story — the deliberate exception to moves-don't-stamp), which is what a future age-based auto-purge will read (deliberate follow-up, not in the initial release). A trashed lane keeps its subtree untouched — its cards ride along and come back with it.
- **`kind:` discriminates inside `.trash/`** (ruled 2026-07-29): depth defines meaning *on the live board*, but the trash is flat, and an empty lane folder is shape-identical to a card folder (`<uuid>/index.md` both). Lane `index.md` frontmatter therefore carries **`kind: lane` at all times** — written at lane creation, healed on touch when absent (minimum: the trash move stamps it; the fuller healing posture is the validation-service design, tracked on the Redesign board), never stripped (restore stays a pure move; the key is inert on the live board where depth wins). Cards never carry the key — absent means card. The trash reader's rule: `kind: lane` → lane; no key but UUID-shaped children with their own `index.md` → lane (self-heal the key); neither → card.
- **Restore is a move out**: any move of a card folder from `.trash/` into a lane, or of a lane folder to board level — drag, or cut+paste — is an ordinary move; there is no restore-specific machinery and no Put Back. Position (and, for cards, lane) are chosen at restore time.
- A folder that disappears entirely (Finder deletion) is also a delete; the app reflects it — such items are gone, they never enter the trash.
- Physical removal in-app is the trash's **Delete / Delete Immediately / Empty Trash** (03-board-ui.md).
- **Legacy `deleted:` keys migrate on load-and-write, never destroy** (settled): a card carrying `deleted:` is relocated into `.trash/` (key removed — the loose-file relocation posture: detection read-only in the loader, the fix through the Writer, a graceful warning-tone notice, deferred under any read-only lock); a lane carrying `deleted:` returns **live** with the key removed and a notice — resurrection is the safe direction, nothing is destroyed by migration. A `deleted:` key at board level remains meaningless — ignored and logged, preserved verbatim.
- **Legacy `deleted:` keys: cards migrate, lanes ignore** (lane clause re-ruled 2026-07-29): a card carrying `deleted:` is relocated into `.trash/` (key removed — the loose-file relocation posture: detection read-only in the loader, the fix through the Writer, a graceful warning-tone notice, deferred under any read-only lock); a lane carrying `deleted:` simply **loads live with the key ignored** — no migration machinery, no key-strip write, no notice (backward compatibility deliberately not funded: old tombstoned lanes reappearing is accepted; the key is inert, preserved verbatim like any unhandled key, logged). The app never writes `deleted:`. A `deleted:` key at board level remains meaningless — ignored and logged, preserved verbatim.
## Malformed input — fail fast