Commit Graph
92 Commits
Author SHA1 Message Date
rzen 27158a06cd Resolve the second-pass review findings — comments undo via .trash recursion, search reach, refuse-don't-degrade paste
Thirteen findings cleared with the user (Redesign board: 3 Contradictions + 3 Gaps + 7 Minors → Resolved):

- User template store re-homes to the shared App Group container (09/02) — templates cross editions; App Group implementation card annotated mid-flight.
- Comment delete = move into comments/.trash/ (01/05/13) — the materialized-trash pattern one level down; no byte capture returns on any edition; purge at window close, copies strip it; 13's absolutes stay true.
- Find & search: card-window ⌘F covers the focused comments pane; board search re-ruled to all meaningful card content — comment bodies via a search-owned transient index when comments ship, attributes as they activate (04/01/05); scope options = WISHLIST #10.
- Comments pane visibility = one persisted app-wide bit, à la Show Trash — content-derived auto-show retired (05/11).
- Comment attachments author in-window: composer/inline-edit drop carve-outs + paperclip (05).
- Item-level copies sever remote/remote-state at every level; whole-board forks exempt (01).
- Paste refuses loudly, never degrades — degraded embedded-index.md fallback and its loss row retired; Finder's whole-or-nothing invariant adopted (04/12/02).
- Escape: composer moves focus out (never discards a draft); inline comment edit = Cancel (05/11).
- Minors: 05 three-pane changes bullet, 01 comments-UI parenthetical, 07 TOFU store naming, WISHLIST item 3 trash wording, README deferred-list now points at the findings board.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 21:46:01 -04:00
rzen a99e1a52f0 Comments card-window UI designed — three componentized panes and the .draft composer
Designed with the user 2026-07-29, closing Redesign card 82e2de6c (both halves). The card window recomposes as three componentized panes — body, comments, attributes — with a layout option (side-by-side default, body-over-comments for narrow displays; app-wide) and the thread visible through body Edit in both mounts. The column auto-shows when the thread is non-empty; sort direction flips at the header; the composer sits at the newest end. The composer edits comments/.draft/ — the user's idea, replacing any app-side draft store: one draft per card, ordinary comment schema with attachments, excluded from the thread, riding git/copies/trash, joining the claimed names; slow save cadence composing "Draft comment on 'X'"; posting renames to a fresh UUID and restamps created/modified in one bracket. Inline edits are body-edit sessions in miniature; no prompts anywhere. All editions ship comments — only tracker sync is Teams (matrix updated). A11y shapes in 10; menu, grammar, context-menu, and configuration rows in 11.

Board: Redesign card 82e2de6c → Resolved; Implementation card "Build comments" filed on Backlog (post-2.0).

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 18:48:08 -04:00
rzen 68fa503250 Comments storage schema specified — fractal folders, chronological, window-scoped
Designed with the user 2026-07-29 (Redesign card 82e2de6c, storage half; UI half remains open). A comment is a UUID folder under comments/ holding index.md + optional attachments/ — a card's anatomy one level down, every fractal rule applying verbatim. Field table: kind: comment, lenient self-reported author (content, not overlay — survives app writes), created/modified; no title, no order. Threads sort chronologically by created (ranks rejected: independent clocks across machines and trackers), flat this iteration with nesting deferred. Comment defects never refuse the board — stray posture at worst. Delete skips the trash, undoable without confirm. Copies carry the thread, reminted, stripping remote/remote-state so two local comments never claim one remote object. Comments are window-scoped, outside the board snapshot — the walk stays O(cards); the committer already protects them via whole-root staging, and composer/announcer describe foreign comment changes by path shape. Count chip on faces filed as WISHLIST #9. Schema edition-blind.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 18:17:51 -04:00
rzen f153e79156 The dedupe universe includes .trash/ — and the container boundary is the first tie-break
Stated 2026-07-29: when duplicate occurrences straddle live and trashed, the live one keeps the identity regardless of age — a restore done as a copy must never see the restored card withheld in favor of its trash ghost; the silent heal remints the trashed occurrence. Uniform across content duplicates, case-twins, and trashed lanes sharing a live lane's UUID.

Board: Minor card 94086f7b → Resolved. Minor lane now holds only tombstoned sweep cards.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 18:00:58 -04:00
rzen 61c31c0c5d Restore the trash marquee full-height clause the rewrites dropped
The below-last-row rubber-band ruling (Resolved card 4ff6537d) survived two trash-section rewrites in code but not in prose; 04's origin clause now states the extent — full column height, card and lane rows alike, no dead zone.

Board: Minor card c9c4de2f → Resolved.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 17:59:58 -04:00
rzen 05331b4a87 Retire Tombstone from 11's ⌫ row; give Select All its trash clause
Two stale rows left by the trash rewrites: the ⌫ grammar row now names Delete staged by place instead of the retired tombstone model, and Select All carries 04's container-boundary rule.

Board: Minor card cb3bc015 → Resolved.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 17:59:23 -04:00
rzen 115409b553 Fail-fast is healer-gated — refusal is the last resort and no longer a dead end
User-ruled doctrine: a defect with a reliable heal heals and moves on (non-blocking notice at most); only an unhealable defect blocks, and blocking means a decision surface — load pauses, the user chooses the fix, the fix applies, the load proceeds. The loader collects every fail-fast defect in the walk rather than stopping at the first; one aggregated surface, never a modal chain. The surface's design (decision vocabulary, aggregation, reconciliation with the welcome failure row and the loading state) is filed as its own design pass — Redesign card a82a19f1 atop Issues to Resolve.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 17:58:46 -04:00
rzen b1db43137a Delete Immediately joins card and lane context menus as Delete's ⌥-alternate
10's inventory claim was right; 11 gains the rows Finder-style — hold ⌥ and Delete becomes Delete Immediately, surfacing as its own VO custom action per 10's cut. The trash needs no alternate since its Delete is already permanent.

Board: Minor card a69e5985 → Resolved.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 17:57:28 -04:00
rzen 683c3bfb76 03's toolbar Undo/Redo disable is edition-aware — no undo provider in the running edition
The parenthetical predated the edition split and read as base never having working Undo/Redo. Now conditioned on the provider: Pro disables on no-git and repo-nested boards; base's native stack serves every board, disabling only under locks and empty stacks.

Board: Minor card 7e43562e → Resolved.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 17:56:31 -04:00
rzen feae6d07d6 Copies are transactions; coerce-tier fallbacks log — and the leniency doctrine is stated
Two rulings (2026-07-29). Copy flows that stamp descendants preflight the whole subtree and refuse loudly naming the offender — the nested-uneditable silent skip is reversed; nothing partial ever lands, and post-preflight failures clean up wholesale per the construct-then-clean precedent; whole-board forks stamp nothing and stay exempt. No-sensible-reading fallbacks now log field, path, and raw text as coerce-tier Defect-stream entries — the one silent-and-unlogged recovery joins the family posture, and the stream is where real-world shapes get promoted to heuristic heals. The doctrine both rulings flow from is now stated in the taxonomy preamble: leniency recovers recoverable issues through reliable service-owned heuristics, never accepts loss that could surprise the user, and "proceed partially, lose a little" is never a verdict.

Board: Minor cards 70b3e4ba + fcc5a70b → Resolved. Code realign queued: stampCopiedDescendant leniency → subtree preflight; FrontmatterFields fallbacks → Defect stream.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 17:55:42 -04:00
rzen f80f838620 Both editions installed is a supported steady state — handler, races, clipboard ruled
Ruled 2026-07-29, new block in 12: Pro claims the .kanban default on first launch once (the purchase is the consent; a manual reassignment back is respected; base never claims). The same board open in both apps is the designed foreign-writer story — base has no git so there is no committer contention, no board-level lock (files-first stays absolute), no gate; open-now flags go per-edition on the shared record so restoration stays edition-local, and the popover gains a pid-liveness-checked "Also open in Lanework Pro" line. The clipboard staging store homes in the App Group container, making cross-edition copy/paste full-fidelity; the degraded fallback remains for genuinely missing snapshots.

Board: Gap card 7a244f9f → Resolved (Gaps lane now empty); App Group Implementation card gains the flags/staging/handler bullets.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 17:43:27 -04:00
rzen 480336bc69 Heal commits are transparent to undo — the bounce is bounded to one, post-relaunch only
Ruled 2026-07-29: heal-class commits (known in-session by heal-marked EchoLedger receipts) never become undo steps — the stack pointer passes over them and restores exclude heal-owned paths, so ⌘Z never reverts a repair and never re-arms the scheduler; naive acceptance would trap a ⌘Z run on an ever-renewing heal commit, and suppression would create standing invalid states. Post-relaunch reseed stays sidecar-free, so old heal commits bounce once — restore plus fresh heal commit, the fresh one transparent, the run continuing past it. Accepted family-wide; the agent-guide quirk becomes the rule's oldest case.

Board: Gap card b444bc5c → Resolved. Pro-era implementation (pro-m1).

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 17:35:03 -04:00
rzen 4c9528f158 Every open passes through a pre-snapshot loading state — the window appears immediately
Ruled 2026-07-29: board windows exist before their first snapshot. Immediate window at the saved frame with registry-cached chrome, quiet spinner after a 200ms grace (no skeletons), first snapshot snaps in, ⌘W cancels the walk as an ordinary close. Restoration goes parallel — all flagged windows at once, walks independent, slow volumes never serialize the launch. Failures keep the settled welcome row surface; the loading window retires rather than morphing into an error display. No info row — the loading state is the surface.

Board: Gap card 4d95f269 → Resolved.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 17:32:24 -04:00
rzen abadf11929 Displacement is level-uniform — a file squatting attachments heals like one squatting .trash
Extends the claimed-names displacement to a card's reserved child names: a wrong-kind node on attachments displaces by the same ladder, scheduled class, and notice, retiring the imports-fail-one-gesture-at-a-time mode one level down; the displaced file then rides the loose-file relocation into the real attachments/ — the heals compose. comments stays a tolerated stray until the tracker era consumes the name, per the load-bearing-now timing principle.

Board: Gap card 64a1c409 → Resolved.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 17:18:16 -04:00
rzen c42e2e5447 App-side state crosses editions through a shared App Group — homed there from day one
Ruled 2026-07-29: every edition declares group.dev.rzen.indie.Kanban, and the board registry plus its Application Support peers home in the group container from base 2.0 onward — no migration, no ordering dependency, and the entitlement ships in base's first build since base ships first. A paying upgrader launches Pro onto their full recents. Stated caveat: security-scoped bookmarks never cross sandboxes, so the list transfers while access re-grants per board — per-edition grant slots on the shared record, open panel pre-anchored at the recorded path. Teams joins the same team-scoped group later with zero ceremony. Clipboard staging store stays put pending the both-editions-installed clipboard ruling.

Board: Gap card a925e530 → Resolved; Implementation card a647aba2 filed atop Backlog (before-base-ships constraint).

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 17:16:52 -04:00
rzen 176c8520fc Reliably healable repairs run silently — the user-gated Repair banner retires
General ruling (2026-07-29): app-initiated covers every reliably healable repair — unambiguous, content-lossless — because heals are auditable: Pro's separate heal commit is the durable trail, base happens quietly, and a heal that changes user content announces with a warning-tone notice, never a consent gate. The user-gated class stays defined but has no current members. Duplicate-id healing goes silent under Lanework-owns-the-board (free to re-mint UUIDs at will): no condition banner, no Repair button — a scheduled heal remints withheld occurrences (memo-guarded, disk re-verified, no-op on vanished duplicates) and posts "Repaired duplicate id — 'Fix login'". Winner rule unchanged: earlier commit on git boards, filesystem birth date then traversal order without history. 06 keeps the Repair verb as the heal commit's name; 13 moves the remint outside undo with all heals. Dissolves the Repair-has-no-Nexus-row contradiction — no command, no row owed.

Board: Contradictions card ce5e7f60 → Resolved (lane now empty); Implementation card 50ed2b5d (Active) retitled "Dedupe duplicate ids and heal them silently" and realigned mid-flight.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 17:10:29 -04:00
rzen 1d1796a7f1 Moves don't stamp — order-only rewrites leave modified and modified-by alone
The rule 01 ▸ Deletion and 03 ▸ Trash cited is now stated (ruled 2026-07-29): order is logically the container's property, stored as an attribute in each member's file for implementation convenience, so reorders, cross-lane moves, and renumber rescales rewrite index.md without touching content — no modified stamp, no modified-by clear. The trash move is the genuine exception: deletion is an edit to the item's story, stamping and clearing both, feeding the future age-based auto-purge. Considered and declined: stamping the container's own modified on reorder — fair reading, pragmatically risky to enforce, nothing reads it.

Board: Contradictions card 30c8f207 → Resolved. Code realign (Writer stamp suppression, agent guide v7) queues for the session-end realign card.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 16:45:45 -04:00
rzen 0e4fc525e0 Purge the lanes-in-trash residue — 11's Delete rows, 06/07's card-only phrasing, 02's counts
The 2026-07-29 lanes-trash-too ruling never swept the docs last touched 07-28. 11 ▸ Delete drops "lanes delete physically" for the card-or-lane move (freight-counting confirms in the trash); Delete Immediately widens to any card or lane selection; 06's recoverability exception covers both kinds and drops the retired 13-native-undo citation; 07 reads card and lane deletes; 02's welcome-counts exclusion restates as items in .trash/ (trashed lane subtracts from the lane count, its nested cards from the card count — the sibling Minor's ruling folded in). Context-menu row "Trash cards" renamed "Trash selection" on the same basis.

Board: Contradictions card 89a625bf + Minor card 488dc2c2 → Resolved.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 16:37:29 -04:00
rzen 62c47a2209 Claimed-name squatters heal by displacement — Lanework owns the board
User ruling on the squatted-.trash gap: a wrong-typed node on an app-claimed
name (a file or symlink squatting .trash, a directory or symlink squatting
CLAUDE.md) is an invalid artifact, not a resident — a scheduled heal moves
it aside via the Finder-style rename ladder, preserved verbatim, with the
relocation-style notice. Upgrades the agent guide's untouchable-skip to
displace-then-write; the CLAUDE.user.md-taken skip stands (destinations
don't cascade-displace). Until the heal lands the loader keeps the
empty-trash read and a racing delete fails as a one-shot — a one-reload
window, not a standing state.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 14:24:07 -04:00
rzen bf559bbbb8 Healing mutations commit separately — the heal class of the two-commit split
User ruling on the integrity pass: a scheduled heal's batch never folds into
a commit carrying anyone else's work. The committer's two-commit split gains
a heal class keyed by heal-marked EchoLedger receipts; the composer stays a
pure diff reader and names heal commits from their own diff shape. On-touch
heals ride their host write's commit (the backfilled kind joins the
bookkeeping no-event class), inline heals batch with their gesture, and the
user-gated Repair already commits alone.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 14:09:28 -04:00
rzen a2bde31290 Promote kind to the common schema — written at creation of every object
User addendum to the integrity pass: kind moves from the lane table to the
common frontmatter table — board/lane/card at creation, comment reserved;
value-trusted where consulted, consequential only inside .trash/ today,
carried everywhere for consistency. A missing kind backfills on touch via
the integrity service. Guide v6 teaches kind on every object.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 14:05:16 -04:00
rzen 1b02f6e063 Formalize the integrity taxonomy and service — the validator design pass
01 gains Validation and healing (five verdicts: refuse / refuse-writes /
tolerate / coerce / heal; heal axes consent x timing incl. the inline mode;
write discipline decided by the existing stamp rule; disk re-verify, memo
discipline, defer-under-lock). kind re-ruled: any object may carry it, the
value names the kind, trusted where consulted, no stripping; backfill is the
service's on-touch heal, on-touch only. 02 gains IntegrityRules +
HealScheduler components — rules and policy consolidate, enforcement stays
with loader/writer.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 13:59:46 -04:00
rzen 1c263b9f2e 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
2026-07-29 12:42:49 -04:00
rzen 065c6f0678 Rule the EchoLedger into base pre-release
User-ruled 2026-07-29: the ledger's construction slot returns to base
("right first") rather than riding with pro-m1's auto-committer. 10 now
pins that the announcer consumes per-file facts on every reload origin —
reconciling reloads' receipt-less changes classify foreign and announce
(the launch-catch-up doctrine applied to speech), closing both interim
holes: debounce-window absorption and reconcile silence.

Implementation filed as "Build the EchoLedger" (order 65920) on the
Backlog; pro-m1's auto-commit card annotated to consume, not construct.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 11:33:25 -04:00
rzen 95f00211c1 Resolve the 2026-07-29 design-review findings into the DESIGN docs
Settles the m11-accessibility findings and two undo-doc findings from the
Redesign board (rationale per card in its Resolved lane):

- 13: permanent delete stays non-undoable — the trash-section clause
  contradicting Rules is amended; staleness validation reads disk, not
  the snapshot (blessing the implemented false-skip fix).
- 10: VO-Space toggles on any selectable element; the digest covers the
  trash while shown; a vanished head with surviving co-selection is
  still named (naming and recovery are independent axes); banner-row
  buttons are literal FKA Tab stops; lane-title landmark+heading
  doubling accepted; trash visibility wording pinned; the custom-action
  cut confirmed; banner transitions are origin-independent; the AA
  obligation binds the primary label tier.
- 03: the palette AA claim rewritten to the real mechanism — one
  ink-selection code path for palette names and hex, pinned by
  PaletteContrastTests in both appearances.

Code-conformance residue filed as "Realign code with the 2026-07-29
accessibility rulings" atop the Implementation Backlog.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-29 11:10:59 -04:00
rzen 16c10d61c3 Pivot the trash to a materialized .trash — cards only, no Put Back
The tombstone model is retired wholesale: deletion is a move into the reserved
<root>/.trash/, always entering at the top (rank minting — no deleted: key, no
timestamp sort), with modified stamped for the future age-based purge. Lanes
are never trashed — lane delete is physical, native undo in-session the net.
Put Back is gone: restore is drag-out or cut+paste (⌘X now enabled in the
trash as the keyboard restore path). Trash cards are ordinary cards — search,
selection, clipboard, and rendering uniform — and one container boundary
replaces the effective-liveness, ancestor-walk, and kind-homogeneity machinery
across 02 and 04. Delete stages by place (board moves, trash deletes
permanently under the recoverability confirm); legacy deleted: keys migrate
without destroying (cards relocate, lanes return live, notices). Templates
exclude .trash; Duplicate carries it; the agent guide teaches delete-as-move.
Materialized reserved lanes are named as a pattern — .archive is WISHLIST #8,
and the backed-out release-presentation question is marked open in 03.

Ruling: Redesign board Resolved card e8f1a6c2; 19 mooted tombstone-era rulings
moved to the board's new Mooted lane.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-28 16:02:08 -04:00
rzen 7be9bb2345 Note the trash-drop ruling as shipped in DESIGN/04
The bullet's scheduling sentence predates the implementation landing;
it now records the shipped refusal semantics instead.

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
2026-07-28 08:13:12 -04:00
rzen 88364b20c0 Resolve the second design-review batch and drop the face carousel
Rulings written in place: the drop settle yields to the system drag session
(fly-to-slot deferred to WISHLIST #7) and the held proposal's home is the
app-wide DragSession — rendering the arrangement means rendering the card at
release (03, 02); folder drops refuse at hover with loss-row reporting, created
cards land positionally, N shadows, header resolves topmost, shadow-only
feedback (04); the banner vocabulary gains the warning-tone loss row class
(02); all user-initiated creation clears the search (04); loose files beside a
card's index.md relocate into attachments/ with notice — files-only carve-out,
paste normalizes at the boundary, the agent guide teaches it (01, 04, 08);
dropping a card on the shown trash deletes it, shadow pinned topmost (04);
query-emptied lanes keep their slot, the out-transition stays reachable, an
open rename survives the filter, pasteboard staleness accepted (04).

The face carousel does not carry over: the pathfinder's selection-keyed dual
presentation proved undesirable — one presentation per card, selection changes
styling never geometry; the attachment chip and the card window are the whole
media story (03, 01, 10, 11; the same-day carousel settlements superseded on
their Resolved cards).

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-28 07:22:48 -04:00
rzen cacd48cb0f Ratify the edition split and the 2026-07-28 design-review resolutions
Edition split follow-through: 12-editions.md and 13-native-undo.md join the
corpus; git-era docs (06, 07) are Pro-scoped and cross-references realigned.

Resolution session rulings written in place: caret chords yield to any focused
text control (04, 11); the drop settle holds its proposal as overlay state and
02 gains the overlays family; Duplicate gets the save-panel fallback and a
cancellable copy walk (03); Finder open is a standard document open (02);
failed first opens record before loading with the folder name provisional (02);
trash pointer ranges skip by kind, full-height marquee surface, Select All by
kind, rows-only trashed universe (02, 04); Empty Trash counts entries (03);
create handoff reads as one arrival (02); range-anchor lifecycle, board-
background click grammar, jump landing cards, lane-domain shift-arrows (04);
Reduce Motion restated per voice (10).

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
2026-07-27 20:29:32 -04:00
rzen 61e18c3dfa Second Minor batch — eight implementation-session follow-ups ratified
- 02: failed create discards the placeholder; a second creation is a
  click-away for the open draft (replace-with-discard, ⌘N unreachable);
  unwritable-lock banner names volume vs permissions; WriteOperation
  vocabulary grows with rename/body-save surfaces; one bookmark per open
  board threads through the open flow; in-progress banner class ratified
  newest-first; signpost lifecycle is the dismissable untimed one-shot
- 01: folder-name tie-breaks compare the canonical lowercase spelling
  everywhere (Ranks and trash sort)

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 21:21:35 -04:00
rzen 3245060822 Symmetric writability probe; loader dedupes case-spelled identity twins
Two follow-ups to this session's decisions: the reconciling reload's
writability re-probe now raises the unwritable lock as well as clearing it
(fail loudly once, not per gesture), and under the shape-only identity
predicate the loader deterministically dedupes case-spelled sibling twins
on case-sensitive volumes (lowercase spelling wins, else lexicographic
first; loser takes the stray posture) so a snapshot never carries
duplicate ids.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 21:18:48 -04:00
rzen 8cf954a8c0 Ratify the unquoted-colon rescue — read-side recovery of the classic slip
Researched against the Frontmatter implementation: the duplicate-key
rescue's retry-loop pattern (compose a placeholder-patched copy, derive
spans from original lines) extends directly. Ratified: a top-level key
line whose plain unquoted remainder trips "mapping values are not allowed"
reads as everything after the first ": "; quoted/flow remainders and
nested shapes stay fail-fast; bytes preserved, fully editable, heals on
first app write of the key; silent with a log line. Test obligation named
(no hostile-YAML case covers the shape today).

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 21:17:30 -04:00
rzen adfe87fdec Batch of eleven Minor design-review fixes across the corpus
- 02: welcome counts are live items only; failed first opens still record;
  duplicate-identity registry records merge silently (newest wins);
  BoardStore's FolderWatcher pointer reads "below"
- 11: lane-header new-card button inventoried (click names its target lane,
  overriding 04's ⌘N rule — cross-referenced there); attachments quiet-add
  affordance listed as a twin; Undo/Redo and Pull/Push rows gain the
  abnormal-state pause, read-only lock, and unresolvable-remote conditions;
  welcome scope added to Reveal in Finder
- 03/11: one lane context menu (header or empty space) with the full
  inventory, replacing the split rows
- 09: instantiated boards are never in git mode — actual mode follows
  detection at the destination (repo-nested possible)
- 08: the app never writes an existing CLAUDE.user.md; one-time rescue
  creation stated as the exception
- README: pathfinder path corrected to ../../Kanban

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 21:09:23 -04:00
rzen 23e761120f Give transient UI state an explicit home in the store
TransientBoardState, one per store, holds state by how a reload treats
it: item-referencing sets (selection, drag membership, pending cut)
share one shape and one constraint rule — members must exist in the
current universe — applied in two directions by one primitive, so the
search filter's hidden-cards rule and reload survival are one rule
expressed once; derived state is stored as its inputs only (the query,
never its result set); and the new-card placeholder is a lane-anchored
overlay with no UUID until commit, discarded when its lane vanishes or
tombstones, handed off when the created card's UUID appears. Trash
visibility rides along per-open, never persisted. The decision is
written back into DESIGN/02 § Changes from Kanban — the TBD is closed.

Full suite 352 tests in 64 suites green. Two findings filed.

Claude-Session: https://claude.ai/code/session_018BjQRYBR6jQja3jCRi5S3A
2026-07-26 21:06:26 -04:00
rzen 8285e19497 Define how non-snapshot files commit — whole-root staging, path-shaped events
The composer was a pure snapshot diff while the repo tracked files outside
the model (agent guide, strays, .gitignore), leaving stray-only windows
uncommittable and the guide's own subject underivable. Settled: the
committer stages the whole root with the tree as its commit condition; the
composer also receives the changed-path list, composing "Update agent
guide (vN)" (version from the marker line) and "Update '<path>'" events
that ride as body bullets under model-event subjects; attribution falls
out of the path-keyed EchoLedger.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 21:05:04 -04:00
rzen 3a0a5b5e7c Pause the remote half of the git surface in abnormal repo states
The detached-HEAD/mid-merge pause named auto-commit, Undo/Redo, and branch
controls but left Pull, Push, and push-on-commit live — against a dirty
tree whose clean-by-pull-time invariant the held auto-commit had falsified.
Settled: the whole surface pauses; the ahead/behind badge keeps counting
since a fetch is a read.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 21:03:17 -04:00
rzen e618658bda Cede ⇧⌘T to Show Tab Bar — window tabbing stays enabled, Show Trash unchorded
Show Trash's ⇧⌘T collided with the Show Tab Bar item macOS injects into
multi-window apps. Settled: tabbing is kept as a system affordance (each
tab a full board window, per-board frames applying when standalone) and
Show Trash ships with no default chord, assignable via the remap path.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 21:02:07 -04:00
rzen fdec965700 Give the card window's title field its Escape abandon
The field's exits were commit-only, silently diverging from the board
rename's Escape-abandons rule, and Escape was ambiguous with the body in
Edit mode. Settled: Escape reverts to the on-disk title and focuses the
body; the collision resolves by focus per 06's first-responder routing.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 20:58:45 -04:00
rzen c145cfb35a Add Restore and Permanently delete to the commit-message vocabulary
The trash trio had no verbs — tombstoning and purging both composed
"Delete card 'X'", erasing the moved-to-trash vs gone-forever distinction
the docs ask users to learn. Settled by diff shape alone: deleted:
appearing = Delete, clearing = Restore, item leaving the tree =
Permanently delete; plural folding keeps Empty Trash distinct from a
multi-select delete.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 20:57:28 -04:00
rzen 2ee88a6015 Stop ⇧-arrow extension at the trash's liveness and kind boundaries
The rubber-band had its boundary sentence; the keyboard extend gesture had
none. Settled: a ⇧-arrow that would cross live↔trash or card↔lane-entry is
inert — never move-and-replace — keeping the homogeneity invariants
unbreakable by keyboard while plain arrows still walk across.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 20:56:15 -04:00
rzen fd0f826c3e Tombstoned selections never anchor paste — the ⌘N rule returned to its precedent
Paste's anchor rules never accounted for a tombstoned selection, and a
literal reading filed a pasted lane beside a trashed card's on-disk lane.
Settled: ⌘V stays enabled and behaves as with nothing selected (card
payload to the last-active lane, lane payload to the board's right end).

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 20:55:22 -04:00
rzen c26a6e3deb Settle search-field keys — stock field, swallowed Return, Tab out, staged Escape
The fixed grammar keys were formally live over the board while the search
field had focus, letting a reflexive Return fire rename/create and destroy
the query. Settled: every key acts on the field (no pass-throughs), Return
no-ops, Tab moves focus to the filtered board with the query intact, and
Escape stages — clear query, then exit field, with board-focus Escape
clearing an active search before its clear-selection meaning.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 20:54:21 -04:00
rzen 1d7449e49a Give lane selection its keyboard entry — ⌥↑ escalates; header clicks select
Every lane command keyed off "a selected lane" with no drag-free way to
create one. Settled: ⌥↑ with the lane's first card selected selects the
lane (↓/⌥↓ descend back; ⌥↑ then inert), an empty selection seeds at the
first lane's first card, and a plain click on the lane title bar selects
with the drag surface engaging only on movement.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 20:45:10 -04:00
rzen 71e7f85328 Registry-cache the welcome row's title and icon with live write-through
The row's name and icon implicitly required reading each recent board's
root index.md at welcome time — the hang the counts rule was written to
avoid. Settled: title/icon/iconColor live in the registry record; they
refresh whenever an open board's reload changes them (in-app renames land
instantly, foreign renames of open boards ride along), with closed-board
renames stale until next open like the counts.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 20:42:31 -04:00
rzen dea77c3459 Place Duplicate and Save as Template in the read-only lock's scope
Both whole-board copies were absent from the lock's command enumeration,
staying enabled while the source tree was gone, unknown, or unwritable and
while the lock suppressed their required close flush. Settled: Duplicate
disables in every lock state; Save as Template disables except under the
unwritable-location lock, where reading the board into Application Support
is a legitimate copy-out with a vacuous flush precondition.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 20:40:40 -04:00
rzen ce1d618117 Rank info rows in the banner precedence — in-progress pinned, signpost last
The stacking order covered only error classes, letting an in-progress row
collapse behind "+N more" — the sole explanation of a bracket's write lock
and a deferred close. Settled: in-progress rows pin above everything,
exempt from and uncounted by the collapse; the passive remote-change
signpost ranks below all error classes and may collapse.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 20:30:21 -04:00
rzen c3e919be37 Make the trash sort deterministic — tie-break and unknown-date rule
The trash's newest-first order is load-bearing for keyboard input, but
same-second multi-deletes and 01's blessed-unparseable timestamps had no
ordering. Settled: ties break by folder name ascending; date-unknown
entries sort as oldest, after all dated entries; lane entries interleave
by their own stamp.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 20:28:48 -04:00
rzen 764a4d4a59 Define the identity predicate as shape-only — lowercase v4 is emission, not the gate
01 said "lowercase UUIDv4" without defining the test, and the strict
reading made every uppercase uuidgen/UUID().uuidString folder a silently
skipped stray. Settled: 8-4-4-4-12 hex in any case and any version is an
identity; comparison is UUID-value equality (case-spellings are one
identity, matching default-APFS behavior); the app emits lowercase v4
only and never renames to canonicalize.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 20:27:07 -04:00
rzen e012147476 Settle launch restoration on a live open-now registry flag
The registry recorded recency but not which boards were open at quit.
Settled: each record carries an open-now flag set on open and cleared on
user-initiated close only — quit teardown leaves it standing, so there is
no at-quit write and crash recovery falls out for free. Restoration
reopens flagged records by lastOpened order; the preference only gates
consulting the set.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 20:22:07 -04:00
rzen 110ef1e623 Settle vanished-focus recovery when the focused card's lane vanished
10 recovered focus "to the card's lane" even in its own lane-tombstone
case, where that lane renders nowhere. Settled: recovery walks up then
sideways — the lane at the vanished lane's position (next by order, else
previous), board container only when no lanes remain, never into the
hidden trash; the announcement names the lane, not the card.

Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb
2026-07-26 20:20:00 -04:00