The message engine outlives its substrate — harvested to Kanban/Changes/ as the change narrator
Step 2 of strategy/01-git-excision.md: CommitMessageEngine and the composer seam relocate to a neutral module renamed away from commit vocabulary (ChangeNarrator, ChangeNarrationRequest, ChangeNarrating, SemanticChangeNarration, ChangeAuthorship), GitChangedPath extracts from GitCommitOperation as ChangedPath, and the one git tie severs — authorship's foreign case carries a display name, not a GitIdentity. The spec tests transplant as ChangeNarratorTests, alive until the journal work begins. 3,009 tests green. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -619,14 +619,14 @@ struct AutoCommitStageAroundTests {
|
||||
/// A composer that takes its time, so a test can hold a flush open and drive the close sequence into
|
||||
/// the gap. Everything else about it is the real one — this suite asserts *when* a commit exists, and
|
||||
/// a fake message would make the commits it reads back unrecognisable.
|
||||
private struct SlowComposer: CommitMessageComposing {
|
||||
private struct SlowComposer: ChangeNarrating {
|
||||
let delay: TimeInterval
|
||||
|
||||
func message(for request: CommitMessageRequest) -> String {
|
||||
func narrative(for request: ChangeNarrationRequest) -> String {
|
||||
// Blocking, deliberately: this runs on the flush's own detached task, and what the test needs
|
||||
// held open is that task rather than the actor the close sequence is running on.
|
||||
Thread.sleep(forTimeInterval: delay)
|
||||
return CommitMessageEngine.message(for: request)
|
||||
return ChangeNarrator.narrative(for: request)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1336,7 +1336,7 @@ struct AutoCommitMessageTests {
|
||||
/// its subject describes a board that has not heard about the card it is committing.
|
||||
@Test("Without the await the subject is the one the stale snapshot could compose — the defect, pinned")
|
||||
func aStaleSnapshotComposesTheShrug() async throws {
|
||||
#expect(try await flushRacingItsReload(awaitsCoverage: false) == CommitMessageEngine.unnamedSubject)
|
||||
#expect(try await flushRacingItsReload(awaitsCoverage: false) == ChangeNarrator.unnamedSubject)
|
||||
}
|
||||
|
||||
/// The bound is a bound: a board whose watcher stream never came up has no reload to wait for, and
|
||||
@@ -1345,7 +1345,7 @@ struct AutoCommitMessageTests {
|
||||
func theWaitIsBounded() async throws {
|
||||
// The generation never moves, so the wait runs to its (millisecond) deadline and composes.
|
||||
#expect(try await flushRacingItsReload(awaitsCoverage: true, landsAfterReads: .max)
|
||||
== CommitMessageEngine.unnamedSubject)
|
||||
== ChangeNarrator.unnamedSubject)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1380,8 +1380,8 @@ struct CommitAttributionRuleTests {
|
||||
try fixture.item("lane/card", stamped("Moved", by: "claude"))
|
||||
|
||||
let paths = [
|
||||
GitChangedPath(path: "old/card/index.md", isDeletion: true, isRename: true),
|
||||
GitChangedPath(path: "lane/card/index.md", isDeletion: false, isRename: true)
|
||||
ChangedPath(path: "old/card/index.md", isDeletion: true, isRename: true),
|
||||
ChangedPath(path: "lane/card/index.md", isDeletion: false, isRename: true)
|
||||
]
|
||||
// "**A folder move is not a deletion**: items match by id across the whole board."
|
||||
#expect(CommitAttribution.foreignIdentity(for: paths, under: fixture.root).name == "claude")
|
||||
@@ -1391,7 +1391,7 @@ struct CommitAttributionRuleTests {
|
||||
func departuresAloneFallBack() throws {
|
||||
let fixture = try WriterFixture()
|
||||
defer { fixture.tearDown() }
|
||||
let paths = [GitChangedPath(path: "old/card/index.md", isDeletion: true, isRename: true)]
|
||||
let paths = [ChangedPath(path: "old/card/index.md", isDeletion: true, isRename: true)]
|
||||
#expect(CommitAttribution.foreignIdentity(for: paths, under: fixture.root)
|
||||
== CommitAttribution.externalIdentity)
|
||||
}
|
||||
@@ -1417,7 +1417,7 @@ struct CommitAttributionRuleTests {
|
||||
let file = EchoLedger.key(fixture.url("lane/card").appendingPathComponent("index.md"))
|
||||
let matching = [file: HarvestedReceipt(receipt: .content(hash: EchoLedger.hash(of: text)), isHeal: false)]
|
||||
let stale = [file: HarvestedReceipt(receipt: .content(hash: EchoLedger.hash(of: "other")), isHeal: false)]
|
||||
let changed = [GitChangedPath(path: "lane/card/index.md", isDeletion: false, isRename: false)]
|
||||
let changed = [ChangedPath(path: "lane/card/index.md", isDeletion: false, isRename: false)]
|
||||
|
||||
#expect(CommitAttribution.split(changed, under: fixture.root, receipts: matching).user == changed)
|
||||
// "a foreign edit landing on an app-written path inside the same window misses the hash and
|
||||
@@ -1436,7 +1436,7 @@ struct CommitAttributionRuleTests {
|
||||
|
||||
let file = EchoLedger.key(fixture.url("lane/card").appendingPathComponent("index.md"))
|
||||
let receipts = [file: HarvestedReceipt(receipt: .content(hash: EchoLedger.hash(of: text)), isHeal: true)]
|
||||
let changed = [GitChangedPath(path: "lane/card/index.md", isDeletion: false, isRename: false)]
|
||||
let changed = [ChangedPath(path: "lane/card/index.md", isDeletion: false, isRename: false)]
|
||||
|
||||
let split = CommitAttribution.split(changed, under: fixture.root, receipts: receipts)
|
||||
#expect(split.heal == changed)
|
||||
|
||||
Reference in New Issue
Block a user