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
This commit is contained in:
2026-07-28 07:22:48 -04:00
parent bf18512abc
commit 88364b20c0
8 changed files with 19 additions and 14 deletions
+2 -2
View File
@@ -31,7 +31,7 @@ MyBoard.kanban/ ← board = the document
- `index.md` = YAML frontmatter between `---` delimiters, then Markdown body.
- **Reserved child names** at card level: `attachments/` (specified below) and `comments/` (enhanced schema — see below). Never levels themselves, never identity (identity-bearing siblings are UUIDs).
- **Name shape gates level detection** (settled): only folders passing the identity predicate (the shape-only rule above — 8-4-4-4-12 hex, any case, any version) are lane/card candidates. Anything else — even with an `index.md` inside — is a stray: skipped with a log warning, preserved verbatim, never rendered. A hand-made `notes/` folder or a board nested inside another can never brick a load; the cost — a hand-authored lane named `todo/` doesn't render — is what the warning and the agent guide exist for.
- A UUID-named folder below the root **lacking `index.md` is skipped with a log warning**, not an error — an interrupted two-step create must not brick the board. **Stray tolerance is uniform at every level**: non-reserved files and folders at board, lane, or card level are ignored by the loader, preserved verbatim, never rendered (inside a card, only `index.md` and the reserved child names mean anything — anything else is not the app's business). **Three board-root names are app-claimed, not strays** — the one scope on the verbatim promise: `CLAUDE.md` is app-owned and rewritten on guide version bumps, with a markerless user-authored `CLAUDE.md` relocated to `CLAUDE.user.md` (08-agent-integration.md ▸ The agent guide — that name is claimed too), and adding git seeds `.gitignore` (06-history-undo.md ▸ Repository hygiene; seeded once, then the user's to edit). Agents and hand-editors should treat these names as the app's at board root; everything else is untouched.
- A UUID-named folder below the root **lacking `index.md` is skipped with a log warning**, not an error — an interrupted two-step create must not brick the board. **Stray tolerance is uniform at every level**: non-reserved files and folders at board, lane, or card level are ignored by the loader, preserved verbatim, never rendered (inside a card, only `index.md` and the reserved child names mean anything). **One carve-out — loose *files* in a card folder are relocated, not tolerated** (settled 2026-07-28, Lanework-owns-the-board): a regular file sitting beside a card's `index.md` (not `attachments/`, not a reserved name) belongs in `attachments/`, and the app moves it there — Finder-style rename on collision — surfacing a graceful warning-tone notice naming the card and files ("Moved 'notes.txt' into attachments — 'Fix login'"; plurals fold). Detection stays read-only in the loader (the Repair precedent); the relocation runs through the Writer as an app-mediated write, commits normally on git boards, and waits out any read-only lock (strays stay tolerated until it clears). The carve-out is exactly that narrow: stray *folders* in a card (a nested clone, a hand-made subfolder), symlinks (never touched, above), and everything at board or lane level keep the verbatim posture — relocating a directory into the flat attachment model would be wrong, and board/lane-level strays (`CLAUDE.user.md`, a `notes/` folder) are legitimate residents. The agent guide teaches the rule (08-agent-integration.md): card files belong in `attachments/`. **Three board-root names are app-claimed, not strays** — the one scope on the verbatim promise: `CLAUDE.md` is app-owned and rewritten on guide version bumps, with a markerless user-authored `CLAUDE.md` relocated to `CLAUDE.user.md` (08-agent-integration.md ▸ The agent guide — that name is claimed too), and adding git seeds `.gitignore` (06-history-undo.md ▸ Repository hygiene; seeded once, then the user's to edit). Agents and hand-editors should treat these names as the app's at board root; everything else is untouched.
- **Symlinks are never traversed** (settled): the loader and the watcher treat any symbolic link in the board tree — identity-shaped name or not — as a stray: skipped with a log warning, preserved verbatim, never rendered, never followed. A link passing the identity predicate would otherwise render bytes living outside the board that FSEvents never reports — the silently-stale board 02-architecture.md structurally excludes — and a link cycle would make the tree walk non-terminating. Copy flows copy the link itself, never its target: Duplicate, Save as Template, instantiation, cross-board copies, and clipboard staging preserve the link verbatim as they do any stray.
- **Atomic writes**: temp file, rename over `index.md`.
- **Unknown frontmatter keys and their order are preserved verbatim** on every rewrite. This is load-bearing for agent overlays (`project:`, `sphere:`, custom tags) — see 08-agent-integration.md.
@@ -106,7 +106,7 @@ Carried over unchanged — gapped fractional ranks:
## Attachments
- `attachments/` under a card folder holds the card's files. The app's attachment surfaces (the card window's sidebar section and import — 05-card-window.md; the face carousel — 03-board-ui.md ▸ Card face) are **flat**: top-level files only. Their listing order is **Finder order** (settled — `localizedStandardCompare`): one shared enumeration between loader and Writer, so the carousel and the sidebar can never disagree.
- `attachments/` under a card folder holds the card's files. The app's attachment surface (the card window's sidebar section and import — 05-card-window.md; the board face shows only the attachment chip — 03-board-ui.md ▸ Card face, the no-carousel resettlement) is **flat**: top-level files only. Its listing order is **Finder order** (settled — `localizedStandardCompare`): one shared enumeration between loader and Writer, so every consumer of the listing agrees.
- **Import collisions auto-rename, Finder-style** (`shot.png``shot 2.png`): an import never overwrites an existing file and never refuses the drop. Never-refuses is policy, not an I/O guarantee — a failed copy (source unreadable, destination full) surfaces per 02-architecture.md ▸ Write-failure surfacing, with any partial file removed.
- **Subfolders are tolerated, preserved verbatim, never created by the app, and not surfaced** in those surfaces. Their contents stay reachable via Reveal in Finder, and body-embedded relative paths into them (`![](attachments/sub/x.png)`) still render — preview resolves against the card folder.