Implement create operations for board, lane, and card

createBoard fills or mints a .kanban (or extension-less) folder and
refuses to clobber an existing board; createLane/createCard mint fresh
lowercase-UUIDv4 folders and append at max+1024 among visible siblings
via the same strict scan renumber uses (extracted, shared). New files
carry schema/title?/order?/created/modified — created==modified, no
modified-by — written LF through the same atomic temp+rename path.
The editability pre-flight is now scoped to operations that rewrite
siblings: renumber refuses on an uneditable sibling, a create beside
one proceeds. Schema constant unified on BoardLoader.supportedSchema.
Info.plist declares the .kanban document type (UTI conforming to
com.apple.package) so Finder treats a board as one document.

20 new unit tests; 196 total green.

Claude-Session: https://claude.ai/code/session_018BjQRYBR6jQja3jCRi5S3A
This commit is contained in:
2026-07-26 17:01:09 -04:00
parent 19f67bdb78
commit 8c0cec06ee
4 changed files with 567 additions and 22 deletions
+5 -3
View File
@@ -30,9 +30,11 @@ import os
public enum BoardLoader: Sendable {
/// Schema version this app understands; anything higher fails fast
/// (01-storage-format.md § Malformed input). `fileprivate` rather than `private`: also
/// read by `BoardLoadError.Reason.description` below, in this same file.
fileprivate static let supportedSchema = 1
/// (01-storage-format.md § Malformed input). Internal rather than `private`: read by
/// `BoardLoadError.Reason.description` below, and it is also the version `BoardWriter`
/// stamps into files it creates one symbol, so the app can never write a file its own
/// loader would reject as newer-than-supported.
static let supportedSchema = 1
/// Board-level key for `BoardModel.template` not schema-owned in the engine's sense
/// (`FrontmatterKeys.schemaOwned`), because its value is opaque and read raw here rather