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:
@@ -39,7 +39,69 @@ public enum FieldValue<Value: Sendable & Equatable>: Sendable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
/// One **lenient** field that had no sensible reading and fell back to its default — the coerce
|
||||
/// tier's observability record (01-storage-format.md § Frontmatter, ruled 2026-07-29: "A
|
||||
/// no-sensible-reading fallback logs: field, path, and raw text, carried as coerce-tier entries in the
|
||||
/// integrity service's Defect stream").
|
||||
///
|
||||
/// **Two of the three facts, because this layer only has two.** `FrontmatterFields` is a pure reading
|
||||
/// of one document's bytes and has no idea which file it came from, so the *path* is attached by the
|
||||
/// loader, which does (`CoercedFrontmatter`). Threading a path down here to satisfy the record's shape
|
||||
/// would put filesystem context into the one layer that is deliberately free of it.
|
||||
public struct CoercedField: Sendable, Equatable {
|
||||
/// The frontmatter key, as the schema spells it.
|
||||
public let key: String
|
||||
/// The value exactly as written — the raw source span, which is the only form worth recording:
|
||||
/// this exists so that a shape observed in the wild can later be promoted to a heuristic heal, and
|
||||
/// a normalized rendering of a value nobody could read would defeat that.
|
||||
public let raw: String
|
||||
|
||||
public init(key: String, raw: String) {
|
||||
self.key = key
|
||||
self.raw = raw
|
||||
}
|
||||
}
|
||||
|
||||
extension FrontmatterDocument {
|
||||
|
||||
// MARK: - The coerce tier's own report
|
||||
|
||||
/// Every **lenient** field in this document that had no sensible reading, in schema order — the
|
||||
/// coerce tier's whole observability contribution (01-storage-format.md § Frontmatter, ruled
|
||||
/// 2026-07-29: "the family posture: every silent recovery leaves a trace").
|
||||
///
|
||||
/// **Read-side only, and nothing branches on it.** The values still render as their defaults —
|
||||
/// untitled placeholder, width 1, no color, no icon, no timestamp — the bytes on disk are still
|
||||
/// preserved verbatim, and no banner is raised. The list exists so the fallback is *visible*: it is
|
||||
/// "the one place where an observed-in-the-wild shape can later be promoted to a heuristic heal or
|
||||
/// a notice".
|
||||
///
|
||||
/// **The strict fields are absent, and so is `deleted`.** `schema` and `order` are the *refuse*
|
||||
/// tier — a malformed one fails the load loudly (`IntegrityRules.validatedSchema`/`validatedOrder`),
|
||||
/// so there is no silent recovery to leave a trace of. `deleted` is the odd one out on purpose: its
|
||||
/// rule is *presence, not validity* (a malformed `deleted` still deletes — `Lane`/`Card.isDeleted`),
|
||||
/// so nothing falls back to a default and the migration reports it under its own defect anyway.
|
||||
///
|
||||
/// A document whose fields all read cleanly answers `[]`, which is the overwhelmingly common case
|
||||
/// and costs one pass over the lenient fields.
|
||||
public var coercedFields: [CoercedField] {
|
||||
var found: [CoercedField] = []
|
||||
func record(_ key: String, _ field: FieldValue<some Sendable & Equatable>) {
|
||||
guard let raw = field.rawText else { return }
|
||||
found.append(CoercedField(key: key, raw: raw))
|
||||
}
|
||||
record(FrontmatterKeys.title, title)
|
||||
record(FrontmatterKeys.width, width)
|
||||
record(FrontmatterKeys.created, created)
|
||||
record(FrontmatterKeys.modified, modified)
|
||||
record(FrontmatterKeys.modifiedBy, modifiedBy)
|
||||
record(FrontmatterKeys.background, background)
|
||||
record(FrontmatterKeys.icon, icon)
|
||||
record(FrontmatterKeys.iconColor, iconColor)
|
||||
record(FrontmatterKeys.kind, kind)
|
||||
return found
|
||||
}
|
||||
|
||||
// MARK: - Strict (structure — the loader fails fast on `.malformed`)
|
||||
|
||||
public var schema: FieldValue<Int> {
|
||||
|
||||
Reference in New Issue
Block a user