An unopenable repository fails loudly — the standing row, the paused surface, the honest heal
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -732,6 +732,66 @@ struct AutoCommitContentionTests {
|
||||
#expect(committer.commitCount == 0)
|
||||
}
|
||||
|
||||
/// **The corrupt-`.git` loud failure's engine half** (06-history-undo.md ▸ Rules, ruled
|
||||
/// 2026-07-31): "the board itself loads and edits normally — files are the board — but the
|
||||
/// failure is loud … with the whole git surface paused", and "the banner clears when a later
|
||||
/// open or reload finds the repo readable".
|
||||
@Test("An unreadable repository holds the engine, and heals when it opens again")
|
||||
func anUnreadableRepositoryHolds() async throws {
|
||||
let (fixture, git, _) = try await makeGitBoard()
|
||||
defer { fixture.tearDown() }
|
||||
let committer = try quickCommitter(git)
|
||||
|
||||
var transitions: [Bool] = []
|
||||
committer.reportRepositoryUnreadable = { transitions.append($0) }
|
||||
|
||||
// What a half-copied or half-deleted `.git` looks like to libgit2: the layout no longer
|
||||
// validates, so the repository will not open at all. Reversible, which is what makes the
|
||||
// heal half of this test the real thing rather than a second fixture.
|
||||
let head = fixture.root.appendingPathComponent(".git/HEAD")
|
||||
let savedHead = try Data(contentsOf: head)
|
||||
try FileManager.default.removeItem(at: head)
|
||||
|
||||
try fixture.item("\(Ident.lane1)/\(Ident.card2)", plain(order: "2048", title: "Second"))
|
||||
committer.noteReloadLanded(sawForeignChange: true)
|
||||
await committer.flushNow()
|
||||
|
||||
#expect(committer.pause == .unreadable)
|
||||
#expect(committer.commitCount == 0, "nothing is attempted against a repository the app can't open")
|
||||
#expect(committer.lastFailure == nil, "a pause is not a failure")
|
||||
#expect(transitions == [true], "the banner is raised once, on the transition")
|
||||
|
||||
// "Edits keep landing on disk — files are the board — and commit as one settled batch when
|
||||
// the state clears." Mid-session, the re-read that notices is the paused engine's own.
|
||||
try fixture.item("\(Ident.lane1)/card-3", plain(order: "3072", title: "Third"))
|
||||
try savedHead.write(to: head)
|
||||
await committer.flushNow()
|
||||
|
||||
#expect(committer.pause == nil)
|
||||
#expect(committer.commitCount == 1, "one settled batch, exactly as any other pause")
|
||||
#expect(transitions == [true, false], "and the banner heals — it is a condition, not an event")
|
||||
#expect(isClean(at: fixture.root))
|
||||
}
|
||||
|
||||
@Test("The popover's own re-read learns the state without attempting anything")
|
||||
func refreshPauseLearnsTheUnreadableRepository() async throws {
|
||||
let (fixture, git, _) = try await makeGitBoard()
|
||||
defer { fixture.tearDown() }
|
||||
let committer = try quickCommitter(git)
|
||||
|
||||
let head = fixture.root.appendingPathComponent(".git/HEAD")
|
||||
let savedHead = try Data(contentsOf: head)
|
||||
try FileManager.default.removeItem(at: head)
|
||||
|
||||
await committer.refreshPause()
|
||||
#expect(committer.pause == .unreadable)
|
||||
#expect(committer.commitCount == 0)
|
||||
|
||||
try savedHead.write(to: head)
|
||||
await committer.refreshPause()
|
||||
#expect(committer.pause == nil)
|
||||
}
|
||||
|
||||
@Test("An unborn HEAD is normal — the first settled change commits the whole tree")
|
||||
func anUnbornHeadIsNormal() async throws {
|
||||
let fixture = try makeBoard()
|
||||
|
||||
Reference in New Issue
Block a user