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
This commit is contained in:
@@ -204,6 +204,19 @@ public final class BoardStoreRegistry {
|
||||
bookmark: bookmark,
|
||||
lastKnownRoot: rootURL
|
||||
)
|
||||
|
||||
// The loose-file carve-out's first firing (01-storage-format.md § Fractal layout ▸ Rules,
|
||||
// settled 2026-07-28): files an agent or a hand-editor left beside a card's `index.md`
|
||||
// while this board was closed are relocated into `attachments/` now, with the notice.
|
||||
//
|
||||
// **Here rather than in `BoardStore.init`**, and last rather than first: the store's own
|
||||
// init is one tree walk and no writes, and a relocation written before the brackets and the
|
||||
// watcher exist would be a write nothing is watching — landing on disk with the snapshot
|
||||
// above it left one reload stale. By this line the pair is wired, so it is an ordinary
|
||||
// bracketed app write whose echo reload refreshes the board like any other. Every reload
|
||||
// thereafter re-fires it from `BoardStore.land`; this call is only the one the opening walk
|
||||
// would otherwise have no reload behind.
|
||||
store.relocateLooseCardFiles()
|
||||
return store
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user