FinDataHub
54626a69fb
refactor(client): 同步状态收敛为 SyncSession 值类型,修掉 reset 漏字段
## 问题
PythonProcessManager 上 20 个各自独立的 @Published 散落着,带来两个实际问题:
1. 重置靠逐个赋值。旧 reset() 实际漏了 6 个字段——syncRate / successCount /
failCount / currentTableProgress / currentTableStocksDone /
currentTableStocksTotal。症状是「第二轮同步一开始就显示上一轮的速率与成功率」,
不报错、不崩溃,只能靠肉眼在界面上发现。
2. 每个字段各自触发一次 objectWillChange,一次状态推进可能连发数次刷新。
## 改动
新增 Models/SyncSession.swift(值类型,20 字段 + 默认值)。manager 上改为:
@Published private(set) var session = SyncSession()
private(set) var progress: Double { get { session.progress } set { … } }
… 共 20 个同名转发属性
- View 层零改动:对外仍是同名属性,90+ 处读取照旧
- reset() 改为一条 `session = SyncSession()`,新增字段自动被重置
- setter 收为 private(set):外部只能读,写入口全收在类内(拆文件的必要前提)
- 未纳入 session 的两个字段:state(带 didSet 副作用,语义是状态机)、
consecutiveFailureWarning(UI 横幅状态)
## 必须记住的坑
编译报 `failed to produce diagnostic for expression`,位置在 DashboardView /
SyncProgressView 的**最后一行**。真正原因是 #Preview 固件里在直接
`pm.progress = 0.45`,而 setter 已收为 private(set)——Swift 对大 body 的类型检查
失败会把错误位置退化到文件末行,看不出真正的出错点。
解法不是放开 setter,而是给预览/测试一个显式缝 replaceSession(_:),
注释写明「业务代码不要用:它绕过节流刷新、日志缓冲与状态机既有路径」。
另外 reset() 从 private 放宽到 internal,仅为了让回归测试能直接调用。
## 证伪
把 reset() 改回逐字段赋值(漏 6 个字段)后,testResetClearsAllSessionFields
精确报出 6 条失败,形如:
XCTAssertEqual failed: ("3999") is not equal to ("0") - successCount 未被重置
恢复后 47 tests 全绿,grep 证伪实验 无残留。
## 回归
SyncSessionTests 5 条(默认值中性 / 值语义 / replaceSession 往返 /
重置覆盖全字段 / 保留 queuedTasks)。Swift 42 → 47。
2026-10-27 23:22:57 +08:00
..
2026-08-03 08:08:01 +08:00
2026-10-27 23:22:57 +08:00