Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Generated by Scripts/regenerate-codex-parser-hash.sh. Do not edit by hand.

enum CodexParserHash {
static let value = "4169e0ab9fbb53c2"
static let value = "5caa3e1eda239d03"
}
21 changes: 15 additions & 6 deletions Sources/CodexBarCore/Providers/Codex/CodexLineageLedger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -374,17 +374,26 @@ enum CodexLineageLedger {
}

private static func hasAncestryCycle(_ documents: [Document]) -> Bool {
let owners = Set(documents.map { Self.canonicalIdentity($0.ownerID) })
let metadataOwners = Dictionary(grouping: documents.compactMap { document in
document.metadataSessionID.map { ($0, document.ownerID) }
Self.nonEmpty(document.metadataSessionID).map {
(Self.canonicalIdentity($0), Self.canonicalIdentity(document.ownerID))
}
}, by: \.0).mapValues { Set($0.map(\.1)) }
var parents: [String: Set<String>] = [:]
for document in documents {
guard let parent = Self.nonEmpty(document.parentSessionID) else { continue }
var targets = metadataOwners[parent] ?? [parent]
if parent != document.ownerID {
targets.remove(document.ownerID)
let owner = Self.canonicalIdentity(document.ownerID)
let canonicalParent = Self.canonicalIdentity(parent)
// Prefer an exact physical owner. A metadata alias may establish an edge only when it
// identifies one physical owner; retained aliases shared by fork siblings are ambiguous.
if owners.contains(canonicalParent) {
parents[owner, default: []].insert(canonicalParent)
} else if let targets = metadataOwners[canonicalParent], targets.count == 1,
let target = targets.first
{
parents[owner, default: []].insert(target)
}
parents[document.ownerID, default: []].formUnion(targets)
}
var visiting: Set<String> = []
var visited: Set<String> = []
Expand All @@ -403,7 +412,7 @@ enum CodexLineageLedger {
visited.insert(owner)
return false
}
return Set(documents.map(\.ownerID)).contains(where: visit)
return owners.contains(where: visit)
}

/// Duplicate copies can carry different model evidence. Keep the earliest physical copy,
Expand Down
11 changes: 9 additions & 2 deletions Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2829,8 +2829,11 @@ enum CostUsageScanner {
let documents = family.descriptors.compactMap { descriptor ->
CodexLineageAccountingSelector.ContainedDocument? in
guard let days = cache.files[descriptor.fileURL.path]?.days else { return nil }
let identity = descriptor.scopeID + "\u{0}"
+ (descriptor.metadataSessionID ?? descriptor.ownerID).lowercased()
// Active/archive copies share the filename owner. Fork children can retain an
// ancestor metadata ID, so metadata is not a safe physical-copy identity here.
let identity = Self.codexContainedDocumentIdentity(
scopeID: descriptor.scopeID,
ownerID: descriptor.ownerID)
return .init(identity: identity, days: days)
}
guard documents.count == family.descriptors.count else { return nil }
Expand Down Expand Up @@ -2881,6 +2884,10 @@ enum CostUsageScanner {
}
}

static func codexContainedDocumentIdentity(scopeID: String, ownerID: String) -> String {
scopeID + "\u{0}" + (UUID(uuidString: ownerID)?.uuidString.lowercased() ?? ownerID)
}

private static func codexFileScanContext(
range: CostUsageDayRange,
options: Options,
Expand Down
15 changes: 15 additions & 0 deletions Tests/CodexBarTests/CodexLineageAccountingSelectorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,21 @@ struct CodexLineageAccountingSelectorTests {
#expect(selection.days["2026-07-09"]?["gpt-5.4"]?[0] == 50)
}

@Test
func `containment copy identity follows physical owner rather than retained metadata`() {
let first = CostUsageScanner.codexContainedDocumentIdentity(
scopeID: "home",
ownerID: "00000000-0000-4000-8000-000000000001")
let sibling = CostUsageScanner.codexContainedDocumentIdentity(
scopeID: "home",
ownerID: "00000000-0000-4000-8000-000000000002")

#expect(first != sibling)
#expect(first == CostUsageScanner.codexContainedDocumentIdentity(
scopeID: "home",
ownerID: "00000000-0000-4000-8000-000000000001"))
}

@Test
func `mode cache suffixes are schema scoped and distinct`() {
#expect(CodexLineageAccountingMode.defaultMode == .legacy)
Expand Down
45 changes: 45 additions & 0 deletions Tests/CodexBarTests/CodexLineageLedgerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,51 @@ struct CodexLineageLedgerTests {
#expect(report.families.first?.quality == .primary)
}

@Test
func `retained metadata across multiple fork generations does not create sibling cycles`() throws {
let observation = Self.observation(timestamp: "2026-07-09T12:00:00Z", input: 100, totalInput: 100)
let root = Self.document(owner: "root", metadata: "root", observations: [observation])
let firstFork = Self.document(
owner: "first-fork",
metadata: "root",
parent: "root",
observations: [observation])
let secondFork = Self.document(
owner: "second-fork",
metadata: "root",
parent: "first-fork",
observations: [observation])

let report = try CodexLineageLedger.reconcileConservatively(
documents: [root, firstFork, secondFork],
localTimeZone: .gmt)

#expect(report.primary.utcDays["2026-07-09"]?.input == 100)
#expect(report.families.first?.quality == .primary)
}

@Test
func `unique metadata aliases still reveal physical ancestry cycles`() throws {
let observation = Self.observation(timestamp: "2026-07-09T12:00:00Z", input: 100, totalInput: 100)
let first = Self.document(
owner: "first-owner",
metadata: "first-alias",
parent: "second-alias",
observations: [observation])
let second = Self.document(
owner: "second-owner",
metadata: "second-alias",
parent: "first-alias",
observations: [observation])

let report = try CodexLineageLedger.reconcileConservatively(
documents: [first, second],
localTimeZone: .gmt)

#expect(report.primary.utcDays.isEmpty)
#expect(report.families.first?.quality == .contained([.ancestryCycle]))
}

@Test
func `unrelated owners sharing an ungrounded metadata identity are contained`() throws {
let first = Self.document(
Expand Down
Loading