fix(core): 代码审查修复 AI 并发/隐私/解析等多处缺陷

- AIRuntime 加 actor 内串行推理闸门,封死 LLM/VL in-flight 并发解码窄口(jetsam OOM 根因)
- prepare 的 .loading 改轮询等待消除假就绪竞态;就绪判据 isReady→isComplete 防半下载崩溃
- applyReanalyzed 重新解读时 unlink 旧 Asset,消除 Vault 孤儿图片(§6 隐私承诺)
- parseReportJSON 改 extractBalancedJSON + 裸数组兜底,防 VL 多项输出被静默截断丢指标
- 临时文件改 completeUnlessOpen 修锁屏写失败;parseDate 支持多格式防归档年份错位
- TimelineEntry/DayDetailSheet 修「偏高」文案与血压箭头方向(偏低指标不再显示相反结论)
- FileVault.wipe 容错;HealthExportSheet 异常关键词排除否定句;modelTag 取实际枚举值
- 删除 B1-B5 + ArchiveFlow 死代码(含违反 §6 的 AES 加密文案)
- 补 3 个回归测试,编译 + 测试全部通过
This commit is contained in:
link2026
2026-06-01 07:43:49 +08:00
parent 32e7c25ed7
commit bff7cfd4b6
16 changed files with 185 additions and 1204 deletions

View File

@@ -86,32 +86,52 @@ struct TimelineEntry: Identifiable, Hashable {
private static func mergedBP(systolic sys: Indicator, diastolic dia: Indicator) -> TimelineEntry {
let abnormal = sys.status != .normal || dia.status != .normal
// status : /;
// ( , 85/55 )
let arrow: String
switch (sys.status, dia.status) {
case (.high, .high), (.high, .normal), (.normal, .high): arrow = ""
case (.low, .low), (.low, .normal), (.normal, .low): arrow = ""
default: arrow = ""
}
return TimelineEntry(
id: "bp-\(sys.persistentModelID)-\(dia.persistentModelID)",
kind: .indicator,
date: sys.capturedAt,
title: String(appLoc: "血压"),
subtitle: String(appLoc: "长期监测"),
trailing: "\(sys.value)/\(dia.value) mmHg" + (abnormal ? "" : ""),
trailing: "\(sys.value)/\(dia.value) mmHg" + arrow,
trailingIsAlert: abnormal,
isOngoing: false
)
}
static func from(report r: Report) -> TimelineEntry {
let abnormal = r.indicators.filter { $0.status != .normal }.count
let highCount = r.indicators.filter { $0.status == .high }.count
let lowCount = r.indicators.filter { $0.status == .low }.count
return TimelineEntry(
id: "report-\(r.persistentModelID)",
kind: .report,
date: r.reportDate,
title: r.title,
subtitle: "\(r.type.label) · " + String(appLoc: "\(r.pageCount)"),
trailing: abnormal > 0 ? String(appLoc: "\(abnormal) 项偏高") : nil,
trailingIsAlert: abnormal > 0,
trailing: abnormalSummary(high: highCount, low: lowCount),
trailingIsAlert: highCount + lowCount > 0,
isOngoing: false
)
}
/// trailing N N N nil
/// N ,(demo )
static func abnormalSummary(high: Int, low: Int) -> String? {
switch (high, low) {
case (0, 0): return nil
case (let h, 0): return String(appLoc: "\(h) 项偏高")
case (0, let l): return String(appLoc: "\(l) 项偏低")
case (let h, let l): return String(appLoc: "\(h + l) 项异常")
}
}
static func from(diary d: DiaryEntry) -> TimelineEntry {
TimelineEntry(
id: "diary-\(d.persistentModelID)",