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:
2026-07-30 06:49:11 -04:00
parent 5ae48de0ea
commit 69084fdff7
27 changed files with 2159 additions and 542 deletions
+150
View File
@@ -528,6 +528,156 @@ struct TemplateEngineAtomicityTests {
}
}
// MARK: - The copy contract
/// **Instantiation is a copy transaction, and it severs tracker identity** the two 2026-07-29
/// rulings applied to the flow 01 names alongside paste and the -drag duplicate (01-storage-format.md
/// § Frontmatter's compound-operations clause; § Fractal layout Rules' item-level sever).
@Suite("TemplateEngine — the copy contract")
struct TemplateEngineCopyContractTests {
/// A template carrying a readable-but-uneditable card refuses the **whole** create, naming that
/// card, and leaves nothing where the user pointed the former root-strict/descendants-lenient
/// split would have made a board from it with one silently unstamped card inside.
@Test("An uneditable card in the template refuses the create, naming it")
func anUneditableCardRefusesTheCreate() throws {
let template = try FixtureTemplate()
defer { template.tearDown() }
try template.fixture.item(
"\(FixtureTemplate.name)/\(Ident.lane1)/\(Ident.card3)",
Item.uneditable
)
let destination = template.destination()
let failure = instantiationFailure {
try TemplateEngine.instantiate(template: try template.template(), to: destination, title: "Doomed")
}
guard case let .failed(write) = failure else {
Issue.record("expected an ordinary failure, got \(String(describing: failure))")
return
}
if case .uneditableFrontmatter = write.reason {} else {
Issue.record("expected the uneditable-shape refusal, got \(write.reason)")
}
#expect(write.operation == .createBoard, "the create is what refused")
#expect(
!FileManager.default.fileExists(atPath: destination.path),
"construct-then-clean: the partial destination goes with the refusal"
)
}
/// A template whose `.trash/` holds a broken card still instantiates: the preflight runs on the
/// **destination**, after the copy applied its exclusions, so a card that was never going to be
/// copied cannot refuse the create it has nothing to do with.
@Test("An uneditable card in the template's trash refuses nothing — it is never copied")
func anUneditableTrashCardIsIrrelevant() throws {
let template = try FixtureTemplate()
defer { template.tearDown() }
try template.fixture.item("\(FixtureTemplate.name)/.trash/\(Ident.card3)", Item.uneditable)
let destination = template.destination()
try TemplateEngine.instantiate(template: try template.template(), to: destination, title: "Fine")
#expect(FileManager.default.fileExists(atPath: destination.appendingPathComponent("index.md").path))
#expect(
!FileManager.default.fileExists(atPath: destination.appendingPathComponent(".trash").path),
"and the trash was excluded, as always"
)
}
/// **The tracker sever, at every level an instantiation materializes** board root, lane, and card.
/// A template can carry the keys in from the board it was saved from (Save as Template is a fork and
/// keeps them verbatim), and the board born from it must not claim those remote objects.
@Test("Instantiation drops the reserved tracker keys at every level")
func instantiationSeversTrackerIdentity() throws {
let fixture = try WriterFixture()
defer { fixture.tearDown() }
let name = "Tracked.kanban"
try fixture.item(name, """
---
schema: 1
title: Tracked Template
template: {order: 1}
project: lanework
remote: gitea#7
---
Blurb.
""")
try fixture.item("\(name)/\(Ident.lane1)", Item.tracked(order: "1024", title: "To Do", key: "remote-state"))
try fixture.item(
"\(name)/\(Ident.lane1)/\(Ident.card1)",
Item.tracked(order: "1024", title: "Starter", key: "remote")
)
let template: BoardTemplate = switch TemplateEngine.load(templateAt: fixture.url(name), origin: .user) {
case let .success(loaded): loaded
case let .failure(error): throw error
}
let destination = fixture.url("Born.kanban")
try TemplateEngine.instantiate(template: template, to: destination, title: "Born")
let board = try FrontmatterDocument.parse(String(
decoding: Data(contentsOf: destination.appendingPathComponent("index.md")), as: UTF8.self
))
#expect(board.value(for: "remote") == nil, "the board born today claims no remote object")
#expect(board.value(for: "project") != nil, "and every other unknown key rode along")
let lanes = ((try? BoardLoader.directoryCandidates(in: destination)) ?? [])
.filter { BoardLoader.isUUIDShaped($0.lastPathComponent) }
let lane = try FrontmatterDocument.parse(String(
decoding: Data(contentsOf: try #require(lanes.first).appendingPathComponent("index.md")), as: UTF8.self
))
#expect(lane.value(for: "remote-state") == nil)
let card = try FrontmatterDocument.parse(String(
decoding: Data(contentsOf: try #require(cardFolders(under: destination).first)
.appendingPathComponent("index.md")), as: UTF8.self
))
#expect(card.value(for: "remote") == nil)
#expect(card.value(for: "project") != nil)
}
/// **Save as Template is a whole-board fork and is exempt** (01 Identity lifecycle's carve-out):
/// it "carries them verbatim", GUIDs, timestamps and tracker keys alike, because a fork is a new
/// namespace rather than a second claimant inside one board. The sever belongs to *item-level*
/// copies, and this is the line between them.
@Test("Save as Template carries the tracker keys verbatim")
func saveAsTemplateIsExempt() throws {
let fixture = try WriterFixture()
defer { fixture.tearDown() }
try fixture.item("Board.kanban", """
---
schema: 1
title: Live Board
remote: gitea#7
---
Body.
""")
try fixture.item("Board.kanban/\(Ident.lane1)", Item.tracked(order: "1024", title: "To Do", key: "remote-state"))
try fixture.item(
"Board.kanban/\(Ident.lane1)/\(Ident.card1)",
Item.tracked(order: "1024", title: "Card", key: "remote")
)
let store = fixture.url("Store")
let saved = try TemplateEngine.saveAsTemplate(
boardAt: fixture.url("Board.kanban"), titled: "Live Board", into: store
)
let board = try FrontmatterDocument.parse(String(
decoding: Data(contentsOf: saved.appendingPathComponent("index.md")), as: UTF8.self
))
#expect(board.value(for: "remote") != nil, "a fork carries them verbatim")
let lane = try FrontmatterDocument.parse(String(
decoding: Data(contentsOf: saved.appendingPathComponent(Ident.lane1).appendingPathComponent("index.md")),
as: UTF8.self
))
#expect(lane.value(for: "remote-state") != nil)
}
}
// MARK: - Shared
/// Every card folder under an instantiated board `<root>/<lane>/<card>`, by the loader's own level