Realign code with the 2026-07-31 findings-resolution rulings
The full bullet list from Implementation card bf080d9a — both ruling batches, including the three appended mid-session by16ef377: - Restore subjects compose the inverse, never nest: crossing "Undo: S" emits "Redo: S" and vice versa; parity, not stack depth, reads a legacy double prefix (GitHistoryProvider.restoreSubject). - Git-operation failures join the one-shot failure banner tier: BannerCenter.GitFailureBanner (undo/redo/branchSwitch/addGit), error tone at failure rank merged with write one-shots by recency; the postLoss compromise is retired at both AppModel wirings. - order/schema optional below the board root: append-at-end reading (ordered siblings first, folder-name tie-break among the order-less), schema reads 1, both coerce-tier logged; the root keeps its requirements. Ranks.resolvedOrders materializes finite ranks so models and placement math stay untouched; first Writer rewrite stamps a real rank on touch, placement against an order-less sibling stamps that sibling inline in the same bracket. Agent guide v10 teaches optional keys and zero-read filing. Hostile-YAML order shapes become coercion tests; Fixtures/Valid/optional-keys.kanban replaces the four retired Malformed boards. - .gitignore is the relocation-heal noise gate: GitignoreRules pure matcher (standard semantics, board-root file only), loader consults it once per walk so matched loose files keep the stray posture; seeded (.DS_Store + .*.lanework-*) at board creation and template instantiation, healed in when missing at open — repo-nested included; empty file honored, existing files never edited; the committer's obedience via libgit2 status is pinned by test. - Comments crash-residue sweep gates on step ownership: HistoryStep derives backing from its own undo expectations, backedContent unions both stacks, the sweep purges per-entry only what no live step owns. - Skip-purge decoupled (16ef377): a stale-skipped coarse step strands whole in NativeHistoryProvider.strandedSteps — still backing, retired only at session end; clean exits purge as before. - Coarse close step named "Changes to '<card>'"; the fine body-edit wording never leaks onto the board menu. - Branch-switch settle clears every open card window's fine stack on Save All and Discard alike; the empty fold registers no coarse step. - Close flush awaits its covering snapshot (quiesce + one generation bump, 1s bound), and an explicit flush now queues behind an in-flight one instead of skipping — the audit-caught interleaving could lose a close flush permanently when the debounce fired inside the close sequence; regression tests force both races. - Commit comment bullets sort chronologically by created, not UUID. - The production-unwired CardBodyEditSession.editSessionDidChange seam is deleted with its seam-only tests. - Composition-root pins: beginSession composes the committer with the store's own EchoLedger and binds the announcer (the miswire class). - Deliberate 06 conformance pass over every 2026-07-31-tagged sentence: fixed Change-custom-key subjects (the retired named generic was the only producer), the unbuilt Replace attachment vocabulary, heal commits now authored Lanework Integrity, the config reader scopes identity to plain [user] sections, add-git re-runs detection at create (a stale mode-none could initialize inside the user's repo), and add-git failures answer at the form or the banner. Structural residue filed on the Redesign board. 2554 tests / 439 suites green. Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
@@ -107,6 +107,11 @@ extension BoardStore {
|
||||
let named = subject ?? name
|
||||
let step = HistoryStep(
|
||||
name: name,
|
||||
// **What this step holds in a trash, read off what it already declares** — the sweep's
|
||||
// gate (`HistoryStep.backing`, ruled 2026-07-31). Derived here rather than passed by each
|
||||
// call site because the expectations *are* the claim: a step whose undo needs a folder
|
||||
// present under `comments/.trash/` is a step whose undo is the move back out of it.
|
||||
backing: HistoryStep.backing(declaredBy: undoExpects),
|
||||
retirement: retirement,
|
||||
undo: { [weak self] direction in
|
||||
BoardStore.cross(self, direction, named, undoExpects, undo)
|
||||
@@ -130,9 +135,9 @@ extension BoardStore {
|
||||
// MARK: The window close's coarse step
|
||||
|
||||
/// **Registers one card-window session as one board step** — 13-native-undo.md ▸ Rules' window
|
||||
/// close ("the session's net effect registers on the board stack as one coarse step, 'Edit card
|
||||
/// ⟨title⟩', values-based, whose undo restores the card subtree to its session-start state —
|
||||
/// deleted comments included — and whose redo reapplies the net effect").
|
||||
/// close ("the session's net effect registers on the board stack as one coarse step named
|
||||
/// 'Changes to ⟨card⟩', values-based, whose undo restores the card subtree to its session-start
|
||||
/// state — deleted comments included — and whose redo reapplies the net effect").
|
||||
///
|
||||
/// Everything about *what* the step does is `CardWindowUndo.netEffect()`'s; everything about
|
||||
/// whether there is a board to register it on is this method's:
|
||||
@@ -152,10 +157,11 @@ extension BoardStore {
|
||||
/// - **A session with no net change registers nothing**, which is `netEffect()`'s `nil`.
|
||||
///
|
||||
/// - Parameter retiring: the deferred `comments/.trash/` purge (13 ▸ Interaction with the trash).
|
||||
/// - Returns: whether the purge now has an owner — a live step holding it until the step leaves
|
||||
/// the board stack, or a substrate that declined to keep the step and therefore ran it already
|
||||
/// (`GitHistoryProvider.register`). `false` means nothing was registered and the caller still
|
||||
/// owes the purge.
|
||||
/// - Returns: whether the purge now has an owner — a live step holding it until the substrate
|
||||
/// lets the step go (which a stale skip deliberately does not do; 13's skip-purge decoupling,
|
||||
/// ruled 2026-07-31), or a substrate that declined to keep the step and therefore ran it
|
||||
/// already (`GitHistoryProvider.register`). `false` means nothing was registered and the caller
|
||||
/// still owes the purge.
|
||||
@discardableResult
|
||||
func registerCardSession(
|
||||
_ window: CardWindowUndo,
|
||||
@@ -164,9 +170,18 @@ extension BoardStore {
|
||||
) -> Bool {
|
||||
guard let target = Self.cardBodyTarget(cardID, in: snapshot) else { return false }
|
||||
guard let net = window.netEffect() else { return false }
|
||||
// **The title the step is registered with, not the one the session opened on** (the phrase is
|
||||
// 13's "Changes to '⟨card⟩'", ruled 2026-07-31). Read once and spent twice, which is the
|
||||
// reason: the menu row and the skip banner must quote *one* name for one step, and a step
|
||||
// whose row said "Changes to 'Fix login'" while its banner said "'Fix log-in' changed outside
|
||||
// Lanework" would be two names for one card. Registration time is also the honest instant —
|
||||
// the row appears in the Edit menu the moment this returns, beside a board already showing
|
||||
// this title, and a session that renamed the card is a session whose rename is *in* the net
|
||||
// effect the row is offering to walk back.
|
||||
let title = Self.cardTitle(at: target, in: snapshot)
|
||||
registerStep(
|
||||
HistoryPhrase.cardSession,
|
||||
subject: Self.cardTitle(at: target, in: snapshot),
|
||||
HistoryPhrase.cardSession(title),
|
||||
subject: title,
|
||||
retiring: retiring,
|
||||
undoExpects: net.undoExpects,
|
||||
redoExpects: net.redoExpects,
|
||||
|
||||
Reference in New Issue
Block a user