diff --git a/DESIGN/01-storage-format.md b/DESIGN/01-storage-format.md index 971155c..59de3c4 100644 --- a/DESIGN/01-storage-format.md +++ b/DESIGN/01-storage-format.md @@ -96,7 +96,7 @@ Carried over unchanged — gapped fractional ranks: - New items append at `max + 1024`; insert at head = `min − 1024`; insert between two = midpoint. - A reorder rewrites **only the moved item's** `index.md`. -- Midpoint precision exhausted → renumber that one lane's cards (or the board's lanes) to whole multiples of 1024. Rare, local — and **the one exception to the only-the-moved-item rule**: a renumber rewrites every sibling's `index.md` in that lane. On a remote-shared board the burst is conflict-prone in principle but benign in practice: each rewritten file changes only its `order`, the local-wins rebase (07-sync-collab.md) resolves per file, orders stay valid floats, and deterministic tie-breaking keeps rendering stable even if two machines' renumbers interleave. It commits as one app-mediated "Renumber lane 'X'" (06-history-undo.md), not N separate edits. +- Midpoint precision exhausted → renumber that one lane's cards (or the board's lanes) to whole multiples of 1024. Rare, local — and **the one exception to the only-the-moved-item rule**: a renumber rewrites every sibling's `index.md` in that lane. On a remote-shared board the burst is conflict-prone in principle but benign in practice: each rewritten file changes only its `order`, the local-wins rebase (07-sync-collab.md) resolves per file, orders stay valid floats, and deterministic tie-breaking keeps rendering stable even if two machines' renumbers interleave. It lands inside the triggering operation's single commit (06-history-undo.md): the renumber batches with the insert or move that exhausted the midpoint, and its sequence-preserving `order` rewrites are bookkeeping to the message composer — the commit reads as the triggering event ("Move card 'Fix login' to Doing"), never as N separate edits or a standalone renumber. - Ties broken by folder name (lexicographic) for deterministic rendering. ## Attachments diff --git a/DESIGN/06-history-undo.md b/DESIGN/06-history-undo.md index c5853c4..58f9696 100644 --- a/DESIGN/06-history-undo.md +++ b/DESIGN/06-history-undo.md @@ -22,7 +22,7 @@ Git is the undo substrate — on boards that have git. **Git is opt-in per board The pathfinder's message engine carries over as the model — it is what earns the "semantic" in semantic commit messages, and it stays a pure, testable function: -- **Pure snapshot diff, no write-site tagging.** Messages compose at commit time from a structural diff of two board snapshots (last-committed vs. current) — never by intercepting operations. Items match by id across the *whole* board, so a lane change is distinguishable from delete+add and a cross-lane move reads as a move. Bookkeeping — `order` renumbering, `modified`/`created` — produces no events: a diff touching only those composes nothing. +- **Pure snapshot diff, no write-site tagging.** Messages compose at commit time from a structural diff of two board snapshots (last-committed vs. current) — never by intercepting operations. Items match by id across the *whole* board, so a lane change is distinguishable from delete+add and a cross-lane move reads as a move. Bookkeeping — `order` changes that preserve sibling sequence (a renumber's rescale — 01-storage-format.md), `modified`/`created` — produces no events: a diff touching only those composes nothing. Sequence is what the diff compares, not raw `order` values: an order change that *repositions* an item among its siblings composes Reorder, so a foreign writer's single-file reorder still reads as one. A midpoint-exhaustion renumber batches with the insert or move that triggered it, so its commit reads as that event. - **Vocabulary**: Add / Delete / Move / Rename / Edit / Restyle / Resize / Reorder over cards, lanes, and the board, plus Attach / Remove for attachment files ("Move card 'Fix login' to Doing", "Rename lane 'Todo' → 'Doing'"). One commit per window: a single event is the subject (with a detail body where one helps); several events of one kind fold into a plural subject, with shared destinations preserved ("Move 3 cards to Done"); genuinely mixed windows fall back to "Update board" — always with a bulleted body naming every event, so the oneline log stays scannable and the full message stays complete. - **Implied events don't steal the subject**: deleting a lane with five cards reads "Delete lane 'X'" with the card deletions as body bullets — not "Update board". - **Titles truncate in subjects only** (~40 chars, keeping `git log --oneline` sane); body lines carry full titles. An untitled item reads "(untitled)" — never a bare `""` (a pathfinder edge fixed, not carried). Undo/redo restores commit as "Undo: ⟨subject⟩" / "Redo: ⟨subject⟩"; the undo-menu labels are the *crossed* commit's subject, so labels never nest.