mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-11 03:13:12 +00:00
fix(bar): tolerate duplicate rows in alert pruning (#1553)
Bar alert pruning tolerates duplicate rows without crashing.
This commit is contained in:
1 parent
c0409862d2
commit
84ff4d57a4
2 files changed
+33
-3
No files matched your search
@@ -758,6 +758,35 @@ do {
|
||||
check(t1.firedKeys.isEmpty, "prune collapses stale-bucket + absent-account keys (bounded)")
|
||||
}
|
||||
|
||||
// (H) Duplicate account ids from a malformed summary must not crash pruning.
|
||||
do {
|
||||
let rows = [
|
||||
BarSummaryRow(
|
||||
accountId: "dup@example.com", provider: "agy", quotaPercentage: 5, quotaStatus: "ok",
|
||||
nextReset: "2026-07-01T00:00:00Z"),
|
||||
BarSummaryRow(
|
||||
accountId: "dup@example.com", provider: "agy", quotaPercentage: 4, quotaStatus: "ok",
|
||||
nextReset: "2026-08-01T00:00:00Z"),
|
||||
]
|
||||
let prior: Set<String> = [
|
||||
"quotaRemainingBelow|agy:dup@example.com|2026-07-01T00:00:00Z|L10",
|
||||
"quotaRemainingBelow|agy:dup@example.com|2026-08-01T00:00:00Z|L10",
|
||||
"quotaRemainingBelow|agy:dup@example.com|2026-09-01T00:00:00Z|L10",
|
||||
]
|
||||
let ev = BarAlertEngine.evaluate(
|
||||
rows: rows, analytics: nil, prefs: BarAlertPrefs(quotaLevels: [10]), priorFiredKeys: prior,
|
||||
now: engineNow, calendar: utc)
|
||||
check(
|
||||
ev.firedKeys.contains("quotaRemainingBelow|agy:dup@example.com|2026-07-01T00:00:00Z|L10"),
|
||||
"duplicate ids: prune keeps first present reset bucket")
|
||||
check(
|
||||
ev.firedKeys.contains("quotaRemainingBelow|agy:dup@example.com|2026-08-01T00:00:00Z|L10"),
|
||||
"duplicate ids: prune keeps second present reset bucket")
|
||||
check(
|
||||
!ev.firedKeys.contains("quotaRemainingBelow|agy:dup@example.com|2026-09-01T00:00:00Z|L10"),
|
||||
"duplicate ids: prune drops absent reset bucket")
|
||||
}
|
||||
|
||||
// (H) Deterministic order: shuffled rows produce notifs in stable id order.
|
||||
do {
|
||||
let rows = [
|
||||
|
||||
@@ -251,8 +251,9 @@ public enum BarAlertEngine {
|
||||
// PRUNE — keep the fired set bounded so it can't grow without limit across
|
||||
// day/month/reset rollovers or account churn.
|
||||
let presentIds = Set(rows.map { $0.id })
|
||||
let presentResetBuckets: [String: String] = Dictionary(
|
||||
uniqueKeysWithValues: rows.map { ($0.id, $0.nextReset ?? "noreset") })
|
||||
let presentResetBuckets: [String: Set<String>] = rows.reduce(into: [:]) { buckets, row in
|
||||
buckets[row.id, default: []].insert(row.nextReset ?? "noreset")
|
||||
}
|
||||
fired = fired.filter { key in
|
||||
let parts = key.split(separator: "|", omittingEmptySubsequences: false).map(String.init)
|
||||
guard let kind = parts.first else { return false }
|
||||
@@ -266,7 +267,7 @@ public enum BarAlertEngine {
|
||||
// parts: [kind, accountId, bucket, "L<level>"]; bucket must equal the
|
||||
// account's CURRENT nextReset and the account must still be present.
|
||||
guard parts.count >= 3, presentIds.contains(parts[1]) else { return false }
|
||||
return presentResetBuckets[parts[1]] == parts[2]
|
||||
return presentResetBuckets[parts[1]]?.contains(parts[2]) == true
|
||||
case BarAlertKind.reauthNeeded.rawValue, BarAlertKind.accountCooldownOrPaused.rawValue:
|
||||
// parts: [kind, accountId, "on"]; keep only for still-present accounts.
|
||||
return parts.count >= 2 && presentIds.contains(parts[1])
|
||||
|
||||
Reference in new issue
Block a user