Denial is not absence — detection learns the unverifiable answer 06 ruled for it

Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
2026-08-06 17:52:20 -04:00
parent 503ec4872c
commit 4ac012a55e
10 changed files with 484 additions and 58 deletions
+30
View File
@@ -323,6 +323,36 @@ struct HistoryStoreAddGitTests {
#expect(git.mode == .none, "a refused add-git changes nothing, mode included")
}
@Test("Create refuses a board that a fresh detection reads unverifiable — a denied ancestor")
func createRefusesUnverifiable() throws {
// **The tightened guard** (06 Rules Detection): "only a genuinely clean `.none` reading
// proceeds" a stale `.none` that has since become unverifiable is refused exactly like one
// that has since become repo-nested (`createRefusesAStaleModeNone` above).
let outer = try WriterFixture()
defer { outer.tearDown() }
let blocked = outer.root.appendingPathComponent("blocked", isDirectory: true)
let boardRoot = blocked.appendingPathComponent("board", isDirectory: true)
try FileManager.default.createDirectory(at: boardRoot, withIntermediateDirectories: true)
try Data(Item.board.utf8).write(to: boardRoot.appendingPathComponent("index.md"))
try FileManager.default.setAttributes([.posixPermissions: 0o000], ofItemAtPath: blocked.path)
defer { try? FileManager.default.setAttributes([.posixPermissions: 0o755], ofItemAtPath: blocked.path) }
#expect(BoardGitMode.detect(boardRoot: boardRoot) == .unverifiable, "the fixture is set up correctly")
let failure = GitRepository.create(at: boardRoot)
guard case .failure(let reason) = failure else {
Issue.record("initializing where detection cannot rule out a repository must be refused")
return
}
#expect(reason.operation == "Adding git to this board")
#expect(!reason.message.isEmpty)
#expect(
!FileManager.default.fileExists(atPath: boardRoot.appendingPathComponent(".git").path),
"no repository created on an unverifiable read"
)
}
@Test("A failure answers at the form when it is up, and at the banner when it is not")
@MainActor
func aFailureAnswersAtTheFormOrTheBanner() async throws {