HistoryStore.compose(boardRoot📒) returns non-optional and runs for every session — the nil the gate produced was the only nil it ever had. makeHistoryProvider is a one-axis decision: git-mode boards bind the git provider, everything else native, in every tier; Session.tier stays recorded, dormant. BoardGitSection shrinks to the four mode postures (.absent and .proPointer die, BoardGitNote and the .git probe with them); every board carries all three popover tabs (BoardInfoTab.available retired); the titlebar branch shows on any git-mode board; the settings sheet and card History section stop reading tier. InertGitTests is repurposed as UntouchedGitTests — the file layer still never opens .git, now load-bearing for mode-none boards. The accessibility audit reaches the settings sheet at last: the fixture board hosts it in every tier, so the free-fixture disabled-row test becomes an open-and-audit test. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
64 lines
3.2 KiB
Swift
64 lines
3.2 KiB
Swift
import Foundation
|
|
|
|
// MARK: - HistoryCommitSeam
|
|
|
|
/// **The three places the auto-committer touches the store's write and reload paths**
|
|
/// (06-history-undo.md ▸ Rules ▸ Auto-commit, ▸ Flush-before-overwrite).
|
|
///
|
|
/// ### Why a struct of closures rather than a reference to the committer
|
|
///
|
|
/// `BoardStore` lives in the live store and must not learn what a repository is: most boards have no
|
|
/// committer at all — git is opt-in per board (06 ▸ Rules), and since the 2026-08-07 pivot that is
|
|
/// the *only* reason a board lacks one (12-editions.md) — so the engine has to be *structurally*
|
|
/// unreachable there rather than switched off, and a store holding an optional committer would be a
|
|
/// store that knows about git.
|
|
/// One optional value, `nil` on every board that has no committer, is the same shape `watcherBrackets`
|
|
/// and `history` already take, and it keeps the three orderings — before the write, after the
|
|
/// bracket, after the landing — stated in one type instead of three properties that could drift.
|
|
///
|
|
/// It is also what makes the ordering testable without a repository: a test binds a seam that records
|
|
/// its calls and asserts that a write flushed before it landed, exactly as `CloseFlushCoordinator`'s
|
|
/// closures do for the close sequence.
|
|
@MainActor
|
|
public struct HistoryCommitSeam {
|
|
|
|
/// **Before an app write** — flush the pending auto-commit if this write could overwrite an
|
|
/// external version that is not in history yet, so "both versions exist as commits" holds.
|
|
///
|
|
/// Synchronous because `performWrite` is: an ordering guarantee *before* a synchronous write can
|
|
/// only be kept synchronously. See `GitAutoCommitter.noteWillWrite()` for the gate that keeps it
|
|
/// rare and for the costs it carries.
|
|
public var willWrite: () -> Void
|
|
|
|
/// **After a write bracket closes** — harvest the bracket's receipts and arm the debounce.
|
|
///
|
|
/// The harvest is why this is a signal of its own: receipts are consumed by the landing reload
|
|
/// that classifies them, and this is the last moment they still describe a completed write
|
|
/// (`EchoLedger.outstandingEntries`).
|
|
public var writeBracketDidClose: () -> Void
|
|
|
|
/// **After a reload lands** — arm the debounce, carrying whether the reload revealed anything the
|
|
/// ledger did not vouch for.
|
|
public var reloadDidLand: (_ sawForeignChange: Bool) -> Void
|
|
|
|
public init(
|
|
willWrite: @escaping () -> Void,
|
|
writeBracketDidClose: @escaping () -> Void,
|
|
reloadDidLand: @escaping (Bool) -> Void
|
|
) {
|
|
self.willWrite = willWrite
|
|
self.writeBracketDidClose = writeBracketDidClose
|
|
self.reloadDidLand = reloadDidLand
|
|
}
|
|
|
|
/// The seam a session binds for a board that has a committer — the one production composition,
|
|
/// kept beside the type so no call site spells the three wirings out.
|
|
public static func binding(to committer: GitAutoCommitter) -> HistoryCommitSeam {
|
|
HistoryCommitSeam(
|
|
willWrite: { [weak committer] in committer?.noteWillWrite() },
|
|
writeBracketDidClose: { [weak committer] in committer?.noteWriteBracketClosed() },
|
|
reloadDidLand: { [weak committer] saw in committer?.noteReloadLanded(sawForeignChange: saw) }
|
|
)
|
|
}
|
|
}
|