The seams unbind — the provider is always native, and the git stack compiles dead
Step 4 of strategy/01-git-excision.md, the entangled one: AppModel's makeHistoryProvider collapses to the native provider (the seam stays injectable per the reversibility posture), the session's git state and its wiring go (wireGitUndo, wireBranchSwitching, the card-session staging threading), BoardStore sheds commitSeam and the identity-history ranker (the loader's nil-safe rung now tops out at birth date — today's no-git behavior), SessionSettleGate keeps the gate and inherits the path utility it borrowed, BoardRegistry drops the persisted operation stamp (decode-safe), and the git banner family leaves BannerCenter with its announcer and accessibility phrases. One missed harvest tie severed (the narrator's root subject is its own now). Nothing outside Kanban/Git/ references the stack — proven by sweep. 2,855 tests green. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -623,96 +623,3 @@ struct GitPathHistoryTests {
|
||||
#expect(duplicate.path == "\(Ident.lane2)/\(Ident.card1)", "the newcomer is the one withheld")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Session composition
|
||||
|
||||
@MainActor
|
||||
private func makeModel() throws -> (model: AppModel, tearDown: () -> Void) {
|
||||
let folder = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent("HistoryStoreTests-\(UUID().uuidString)", isDirectory: true)
|
||||
try FileManager.default.createDirectory(at: folder, withIntermediateDirectories: true)
|
||||
let model = AppModel(
|
||||
registryStorageURL: folder.appendingPathComponent("board-registry.json"),
|
||||
clipboardStagingRoot: folder.appendingPathComponent("Clipboard", isDirectory: true)
|
||||
)
|
||||
return (model, { try? FileManager.default.removeItem(at: folder) })
|
||||
}
|
||||
|
||||
@MainActor
|
||||
@discardableResult
|
||||
private func openBoard(_ model: AppModel, at url: URL) throws -> BoardWindowRef {
|
||||
let ref = BoardWindowRef(url: url)
|
||||
let recordID = model.boardRegistry.recordOpen(of: url)
|
||||
let store = try model.storeRegistry.acquire(url)
|
||||
model.boardRegistry.setOpenNow(id: recordID)
|
||||
model.beginSession(ref: ref, store: store, recordID: recordID, access: nil)
|
||||
return ref
|
||||
}
|
||||
|
||||
@MainActor
|
||||
@Suite("Board sessions ▸ the git state they compose")
|
||||
struct BoardSessionGitTests {
|
||||
|
||||
@Test("A free-tier session composes a git state too, and detects the repository it finds")
|
||||
func freeSessionsComposeAGitStateAsWell() throws {
|
||||
let fixture = try makeBoard()
|
||||
defer { fixture.tearDown() }
|
||||
try plantGitDirectory(in: fixture)
|
||||
let (model, tearDown) = try makeModel()
|
||||
defer { tearDown() }
|
||||
|
||||
// **PIVOT 2026-08-07** (12-editions.md). The inverse of what this test used to pin: the free
|
||||
// tier carried no git state at all, reported mode `none` on this very board, and injected
|
||||
// nothing into the loader. Git left the paywall, so the session composes exactly what a Pro
|
||||
// session composes — same call, no tier in it.
|
||||
model.currentTier = { .free }
|
||||
let ref = try openBoard(model, at: fixture.root)
|
||||
let session = try #require(model.session(for: ref))
|
||||
|
||||
#expect(session.git != nil)
|
||||
#expect(session.gitMode == .git, "the mode is the disk's answer, not the tier's")
|
||||
#expect(session.store.makeIdentityHistoryRanker != nil, "and the loader's rung is wired")
|
||||
#expect(session.tier == .free, "the tier is still recorded — it just decides nothing here")
|
||||
}
|
||||
|
||||
@Test("A session on a git board composes git mode and wires the loader's ranker")
|
||||
func sessionsCarryTheDetectedMode() async throws {
|
||||
let fixture = try makeBoard()
|
||||
defer { fixture.tearDown() }
|
||||
let (model, tearDown) = try makeModel()
|
||||
defer { tearDown() }
|
||||
|
||||
// A real repository, so the ranker has something to read.
|
||||
let seed = HistoryStore.compose(boardRoot: fixture.root)
|
||||
#expect(await seed.addGit())
|
||||
|
||||
model.currentTier = { .pro }
|
||||
let ref = try openBoard(model, at: fixture.root)
|
||||
let session = try #require(model.session(for: ref))
|
||||
|
||||
#expect(session.gitMode == .git)
|
||||
let provider = try #require(session.store.makeIdentityHistoryRanker)
|
||||
let ranker = try #require(provider())
|
||||
#expect(ranker.rank("\(Ident.lane1)/\(Ident.card1)") != nil)
|
||||
|
||||
// The provider binding arrived with the undo/redo card: a session on a git board binds the
|
||||
// git substrate over exactly this mode (12-editions.md ▸ The provider seam).
|
||||
#expect(session.history is GitHistoryProvider)
|
||||
}
|
||||
|
||||
@Test("A session on a plain board is mode none and injects nothing")
|
||||
func sessionsOnPlainBoardsInjectNothing() throws {
|
||||
let fixture = try makeBoard()
|
||||
defer { fixture.tearDown() }
|
||||
let (model, tearDown) = try makeModel()
|
||||
defer { tearDown() }
|
||||
|
||||
model.currentTier = { .pro }
|
||||
let ref = try openBoard(model, at: fixture.root)
|
||||
let session = try #require(model.session(for: ref))
|
||||
|
||||
#expect(session.gitMode == .none)
|
||||
let provider = try #require(session.store.makeIdentityHistoryRanker, "the wiring is there")
|
||||
#expect(provider() == nil, "and it answers nothing on a board with no repository")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user