274ccd9ff5dac87d4407cbc811706ade4f04272e
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
274ccd9ff5 |
Realign code with the 2026-07-31 findings-resolution rulings
The full bullet list from Implementation card bf080d9a — both ruling batches, including the three appended mid-session by |
||
|
|
8014bde7c6 |
Lanes delete into the trash — storage, loader, writer, and undo
Phase 1 of the lanes-in-trash card (2026-07-29 ruling, docs led the
code): lane delete is a move into .trash/ with the subtree intact,
arriving at top trash rank — no destructive delete remains outside
the trash.
TrashedLane opaque unit (id/schema/title/order/heldCards) beside
trash cards — deliberately not a Lane, so no card-shaped surface can
believe an empty subtree. Loader's trash walk trusts the kind VALUE
(lane → opaque unit w/ held-card count counted at the loader's own
unit; card → ordinary card; absent/unrecognized → UUID-children
shape, empty-kindless falls to card per 01's honest limit). Writer:
moveIntoTrash generalized with kind passed never derived (an empty
lane would re-derive as card), deleteLaneToTrash mints against the
whole-container rank ladder. Retired: migrateTombstonedLane (lane
deleted: now ignored — loads live, bytes inert, tolerate-tier
warning), removeLane, captureSubtree/recreateSubtree and the
subtree-snapshot machinery. Undo inverse = move back to captured
strip position, redo replays at captured trash rank. Purge walks
lane subtrees; TrashModel.Freight phrases confirms with lane freight
("…and its 5 cards"). ItemPath gains .trashLane; resolve interleaves
the trash by rank; SearchFilter matches lane rows by title only.
Trashed-lane card windows dismiss and pending cuts void via the
ordinary vanish rule — no new plumbing.
Phase 2 (rendering, selection grammar, drag, a11y, agent guide)
follows. Both schemes 1858 tests / 318 suites green.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
|
||
|
|
0463540aea |
Dedupe duplicate ids and heal them silently
The crash-class gap the integrity design pass found (DESIGN/01 - Fractal layout rules; 02 - Live-reload resilience): the loader had no board-wide dedupe at all, so two hand-copied folders sharing a UUID put two equal ItemIDs into one snapshot - which SwiftUI's ForEach does not tolerate. Built to the day's re-rulings, both landing mid-flight: the user-gated Repair banner retired ( |
||
|
|
af1860debf |
Relocate loose card files into attachments
01's Lanework-owns-the-board carve-out: a regular file beside a card's index.md belongs in attachments/, and the app moves it there. The loader detects read-only — a new LoadResult.looseCardFiles channel, separate from the stray-tolerance warnings because it says the opposite thing — skipping directories, symlinks, hidden entries, and the reserved names compared case-insensitively (on APFS, Index.md IS the index). The relocation rides one performWrite bracket at the tail of every successful reload, which makes lock deferral free: the reload that lifts a read-only lock is the reload that relocates. A lane/card/filename memo keeps a failing relocation from hot-looping — one one-shot, then silence until disk changes. The notice rides the loss-row class, phrasing folded by BannerCenter (one file, one card's files, a multi-card sweep), naming original filenames per the importAttachment rule. Paste normalizes at the import boundary: staged snapshots' loose files land in the pasted card's attachments silently, every arrival path declaring its side via an explicit normalizingLooseFiles parameter — drag paths decline and fall back to the destination's own carve-out. checkIsCardFolder closes the hole where a lane's notes.txt would have been relocated: card depth is exact, UUID under UUID. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY |
||
|
|
b4c90838b4 |
Build card faces with edge-accent styling
The card face becomes real: leading SF Symbol (card default doc.text, tinted by a valid hand-written iconColor — schema yes, control no), title or the quiet untitled placeholder, and a quiet paperclip when the card has attachments — title-only by design, no body excerpt. Color is the settled K1 edge accent, not a fill: background paints a 4pt stripe down the left edge, resolved through the ported pathfinder palette (12 icon tints + 12 backgrounds carried over verbatim, plus raw #RRGGBB[AA]); anything unresolvable paints nothing and stays on disk exactly as written. The snapshot now carries each card's flat attachment names — the loader's one read inside a card folder, shared with the Writer's listing so the m5 carousel and m6 sidebar can never disagree on order (Finder order, the Writer's existing comparator). The face keeps its top-aligned structure so the sole-selection carousel can expand inside the card without moving masonry neighbors. 18 new tests. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY |
||
|
|
7470255886 |
Write the loader fixture suite, valid and malformed
18 golden fixture boards as real on-disk trees under Fixtures/ — ten valid/tolerated cases (rich board, interrupted create, non-UUID strays, stray files, tombstones, tie-breaks, unknown-key order, coercion, last-wins duplicates, board-level deleted) and eight fail-fast cases, each pinned to its exact error reason and path; the rich board's whole tree round-trips byte-identically. Pins two contract subtleties now recorded in the design: tombstone flags are not inherited (renderers walk ancestors) and last-wins resolves before order strictness. README gains the storage-foundation feature entry. 146 tests total. Claude-Session: https://claude.ai/code/session_018BjQRYBR6jQja3jCRi5S3A |