Realign code with the 2026-07-29 findings-resolution rulings
Nine rulings land as code. Reorders don't stamp — one container-change predicate (WriteOperation.rewritesOrderOnly): within-container reorders and the renumber rescale rewrite only order, while cross-lane, cross-board, and trash moves stamp modified and clear modified-by; no trash special case exists, and the m8 undo inverses conform through the same seam. Copies are transactions: the root-strict/nested-lenient split retires for a whole-subtree stampability preflight that refuses loudly naming the offender, and every item-level copy severs remote/remote-state at every level (whole-board forks carry them verbatim). Paste refuses, never degrades: the embedded-index.md materialization and its loss row retire; a missing staged snapshot produces nothing and posts an error-tone one-shot named from manifest metadata. Coerce-tier fallbacks log through the Defect stream with path context attached loader-side. Displacement is level-uniform: a file squatting attachments inside a card heals by the same rename ladder as board-root squatters; comments stays tolerated. Delete Immediately joins card and lane context menus as Delete's ⌥-alternate with its own VO custom action, routed through an explicit container so the menu target outranks standing selection. Agent guide v7 teaches the stamp discipline and the card-level attachments claim, and sheds two stale v6 lines (lanes trash now; kind is taught). Verified conformant, unchanged: edition-aware Undo/Redo disable, trash marquee full-height backdrop. Both schemes 1854 tests / 318 suites green; verify-editions 30/30. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -55,8 +55,16 @@ enum AgentGuide {
|
||||
/// pointer) and supersedes it on the next open. v6 adds the one-folder-at-a-time move warning:
|
||||
/// a real agent incident (2026-07-29) showed `mv <lane>/*` sweeping the lane's own `index.md`
|
||||
/// along with the cards and destroying the destination lane's identity — the guide now says
|
||||
/// *why* the named-folder form is load-bearing, not just what to type.
|
||||
static let version = 6
|
||||
/// *why* the named-folder form is load-bearing, not just what to type. v7 teaches two more
|
||||
/// things settled after v6 shipped: the refined stamp-discipline predicate
|
||||
/// (01-storage-format.md ▸ `modified`'s scope, ruled 2026-07-29, refined 2026-07-30) — a
|
||||
/// within-container reorder rewrites only `order`, while a move that changes an item's
|
||||
/// container (another lane, another board, into or out of `.trash/`) stamps `modified` and
|
||||
/// `modified-by` like any content edit, the trash move included, since it's the same rule and
|
||||
/// not a special case — and the card-level `attachments` claimed name
|
||||
/// (01-storage-format.md § Fractal layout ▸ Rules, "level-uniform"): that name belongs to the
|
||||
/// app's own folder, so a *file* by that name is a defect the app displaces on sight.
|
||||
static let version = 7
|
||||
|
||||
// MARK: - The version marker
|
||||
|
||||
@@ -325,7 +333,7 @@ enum AgentGuide {
|
||||
<board>/ this folder (the board)
|
||||
├── index.md board title + settings; body = board description
|
||||
├── CLAUDE.md this guide (app-maintained)
|
||||
├── .trash/ deleted cards (app-managed — see Deleting)
|
||||
├── .trash/ deleted cards and lanes (app-managed — see Deleting)
|
||||
├── <uuid>/ a LANE
|
||||
│ ├── index.md lane title + order; body = lane notes/policy
|
||||
│ ├── <uuid>/ a CARD
|
||||
@@ -350,7 +358,7 @@ enum AgentGuide {
|
||||
- Lane titles carry the workflow semantics (e.g. To Do → In Progress →
|
||||
Done). Read the board's and lanes' index.md bodies for descriptions and
|
||||
per-lane policy before deciding where a card belongs.
|
||||
- `.trash/` holds deleted cards; everything else at board root that isn't a
|
||||
- `.trash/` holds deleted cards and lanes; everything else at board root that isn't a
|
||||
UUID-named folder is not part of the board's content.
|
||||
|
||||
## Frontmatter
|
||||
@@ -397,6 +405,7 @@ enum AgentGuide {
|
||||
```markdown
|
||||
---
|
||||
schema: 1
|
||||
kind: card
|
||||
title: Short imperative card title
|
||||
order: 3072
|
||||
created: 2026-07-24T18:00:00Z
|
||||
@@ -406,11 +415,24 @@ enum AgentGuide {
|
||||
The card's content — any Markdown.
|
||||
```
|
||||
|
||||
Creating a lane is the same one level up (body optional; `order` ranks
|
||||
lanes left→right).
|
||||
Creating a lane is the same one level up (body optional; `kind: lane`;
|
||||
`order` ranks lanes left→right).
|
||||
|
||||
**Always write `kind`** at creation — `kind: card`, `kind: lane`,
|
||||
`kind: board` at board root. Depth already says what an item is on the
|
||||
board, but `.trash/` is flat, and there the value is the only thing that
|
||||
tells a trashed lane from a card. Omitting it is healable, never fatal: the
|
||||
app fills a missing `kind` in the next time it rewrites that file.
|
||||
|
||||
## Moving and reordering
|
||||
|
||||
- **The stamp rule**: a move that changes an item's container — another
|
||||
lane, another board, or into/out of `.trash/` — stamps `modified` and
|
||||
re-stamps `modified-by`, the same as any content edit. A reorder that
|
||||
keeps an item in the same container (a card among its lane's cards, a
|
||||
lane among the board's) rewrites only `order`; leave `modified` and
|
||||
`modified-by` alone. The trash move isn't an exception to this — it
|
||||
stamps because every container change stamps.
|
||||
- Move to another lane: `mv <laneA>/<card-uuid> <laneB>/` — the folder move
|
||||
IS the move. Then set the card's `order` to place it among the
|
||||
destination's cards, update `modified`, and re-stamp `modified-by`.
|
||||
@@ -418,28 +440,39 @@ enum AgentGuide {
|
||||
A lane folder holds its own `index.md` beside its cards, so a glob
|
||||
sweeps the lane's identity file along with them and overwrites the
|
||||
destination lane's.
|
||||
- Reorder within a lane: rewrite only that card's `order`.
|
||||
- Reorder within a lane: rewrite only that card's `order` — don't touch
|
||||
`modified` or `modified-by`.
|
||||
|
||||
## Editing and deleting
|
||||
|
||||
- Edit bodies freely; update `modified` on every write. Preserve frontmatter
|
||||
keys you don't recognize and don't reformat content you didn't change.
|
||||
- **Delete a card = move it into `<board>/.trash/`**: `mv <lane>/<card-uuid>
|
||||
<board>/.trash/` (create `.trash/` if missing). Arrivals go on top: set
|
||||
the card's `order` to the smallest `order` already in `.trash/` minus
|
||||
1024 (empty trash: any number), and update `modified`. Restore is the
|
||||
same move in reverse — into a lane, with a fresh `order`.
|
||||
- **Delete a card or a lane = move its folder into `<board>/.trash/`**:
|
||||
`mv <lane>/<card-uuid> <board>/.trash/`, or `mv <lane-uuid>
|
||||
<board>/.trash/` for a whole lane (create `.trash/` if missing). A lane
|
||||
travels with its cards inside it. Arrivals go on top: set the moved
|
||||
item's `order` to the smallest `order` already in `.trash/` minus 1024
|
||||
(empty trash: any number). It's a container change like any other move
|
||||
(Moving and reordering above): stamp `modified` and re-stamp
|
||||
`modified-by`. Restore is the same move in reverse — a card into a lane,
|
||||
a lane back to board root, with a fresh `order`, stamped the same way.
|
||||
- **Stamp `kind: lane` when you trash a lane that lacks it.** `.trash/` is
|
||||
flat, so an empty lane folder looks exactly like a card folder; the `kind`
|
||||
value is what tells them apart in there.
|
||||
- Never write a `deleted:` key — that convention is retired; the app
|
||||
migrates any it finds.
|
||||
- Remove a folder outright (`rm -r`) only when you mean permanent,
|
||||
unrecoverable deletion. Lanes have no trash: deleting a lane folder is
|
||||
permanent, so be sure.
|
||||
unrecoverable deletion — the trash is the recoverable path for both
|
||||
cards and lanes.
|
||||
|
||||
## Attachments
|
||||
|
||||
- A card's files live in `attachments/` inside the card folder, flat at its
|
||||
top level. **Put files there, never beside `index.md`** — the app
|
||||
relocates loose files into `attachments/` and tells the user it did.
|
||||
The name `attachments` itself belongs to that folder — never create a
|
||||
*file* called `attachments` in a card; the app treats one as a defect
|
||||
and displaces it on sight.
|
||||
- To attach a file: create `attachments/` if missing and copy the file in.
|
||||
If the name is taken, pick a free one Finder-style (`shot.png` →
|
||||
`shot 2.png`) — never overwrite.
|
||||
|
||||
Reference in New Issue
Block a user