修复子代理与 fork 会话的 Token 全量丢失:原判定要求 task_started 带 started_at 且不早于会话创建时间才结束回放,但子代理的 started_at 是父级 回合的开始时间,天然早于子会话文件,新版 Codex 更是完全不发该字段。改为 首个 task_started 无条件结束回放——实测 661 个真实 rollout 中没有任何一个 的 token_count 出现在它之前。本机语料 A/B:Token 13.60G → 14.53G(+6.8%), 用量记录 68997 → 73566。 其他修复: - 两个 Provider 钉到专用串行执行器,冷扫描不再占用协作线程池。把池限制 成一条线程实测,修复前并行的每秒采样在 43 秒扫描期间一次都没能推进。 - 按日期与模型聚合并定序输出,行数 701 → 272 且 id 唯一;顺带修掉冷扫描 与检查点恢复顺序不一致导致每次刷新都产生"不相等"报告的问题。 - 缓存行加剪枝,覆盖归档搬走的 rollout、删除的项目目录与旧解析命名空间; 检查点仅在末行未完时存第二份状态,Claude 事件按保留窗口裁剪。 - 复用 ISO8601 解析器,不再逐行创建。 - 数字与日期改跟随应用语言,弹窗与菜单栏共用同一套 Token 缩写。 - 窄弹窗热力图按设计尺寸铺开后横向滚动,此前被钉在面板宽度上永不溢出。 - 打开菜单栏项一并开启扫描,并为无数据状态补上悬停文案。 - 删除未被应用构造的配额 Provider、凭据读取与响应映射(约 330 行)及其 全链路管线,并清掉 37 条孤立译文 × 8 个语言文件。
39 lines
1.4 KiB
Swift
39 lines
1.4 KiB
Swift
// Copyright (C) 2026 ysicing
|
||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||
|
||
import Dispatch
|
||
import Foundation
|
||
import Testing
|
||
@testable import AIUsage
|
||
|
||
/// 两个 Provider 都把自己钉在 `ScanExecutor.shared` 上。冷启动扫描是几十秒的同步 IO,
|
||
/// 留在协作线程池里会把同池的 actor 一起卡住:把池限制成一条线程
|
||
/// (`LIBDISPATCH_COOPERATIVE_POOL_STRICT=1`)实测,去掉这个执行器后,
|
||
/// 并行的每秒采样在整段扫描期间一次都没能推进。
|
||
private actor PinnedToScanExecutor {
|
||
nonisolated var unownedExecutor: UnownedSerialExecutor {
|
||
ScanExecutor.shared.asUnownedSerialExecutor()
|
||
}
|
||
|
||
func currentQueueLabel() -> String {
|
||
String(cString: __dispatch_queue_get_label(nil))
|
||
}
|
||
}
|
||
|
||
@Suite struct ScanExecutorTests {
|
||
@Test func pinnedActorsRunOffTheCooperativePool() async {
|
||
let label = await PinnedToScanExecutor().currentQueueLabel()
|
||
#expect(label == "com.xstats.ai-usage-scan")
|
||
}
|
||
|
||
/// 串行执行器必须真的串行,否则两个 Provider 会同时抢磁盘和同一个缓存库。
|
||
@Test func workIsSerializedAcrossPinnedActors() async {
|
||
let first = PinnedToScanExecutor()
|
||
let second = PinnedToScanExecutor()
|
||
async let a = first.currentQueueLabel()
|
||
async let b = second.currentQueueLabel()
|
||
let labels = await [a, b]
|
||
#expect(labels == ["com.xstats.ai-usage-scan", "com.xstats.ai-usage-scan"])
|
||
}
|
||
}
|