用途与实际影响
这项功能怎样使用
为什么需要它
有一批文件躺在目录里,不代表那一天所有记录都拿齐了。只按最近文件夹续跑,容易漏页、重复统计或误把残缺数据说成完整。
举个实际例子
几百页设备记录下载到一半断了。下次继续时,系统先核对已经完成的日期和页面是否仍属于同一次导出;对得上就从下一页接着来,对不上就停下说明冲突,不从头重下,也不把半成品冒充完整数据。
最后我会得到什么
已有完整历史与这次新增的原始记录都保留下来,能知道哪些日期和页面真的取齐。中断时从同一批的缺口继续;未完成当天由新记录补齐,不覆盖旧原件。
可用于当前判断
日期、页面与原始文件都能一一对上时,才把这次导出记为完整;旧完整日期与新日期衔接。
需要复核
中途断开但已保存部分仍可核对时,保留它们并从同一批未完成处继续。
本轮不可用
文件、顺序或内容身份对不上时,在再访问设备账号前停下,不换目录凑成成功。
从哪里开始
有设备更新清单中断时,要求沿这同一批继续。
需要准备什么
- 继续上次未完成设备更新的请求
- 有多批时指出要继续哪一批
从开始到拿到结果
- 1
系统核对并处理
先保存取回的原始页和运动附件,增量覆盖上次未完整的中国日起;已完整历史不反复下载。
- 2
交付与接续
逐页核对后交回完整与缺失范围;中断继续同一清单,不另猜一个文件夹或吞掉旧原件。
技术实现与依据
这里保留实现、关键条件、精确入口、历史记录和验证结果。
全字段增量、扁平历史、gzip、分页闭环与精确续跑已实现;2026-09-14全套140项离线合成测试通过,真实导入未运行关键规则与设计选择
空响应表示未观察到记录,不自动变成数值零。
每个原始页面先写文件,再更新 manifest(清单) checkpoint(续作检查点)。
完整页面可采用,额外或被篡改的 orphan(孤儿文件)会被拒绝。
失败只通过 bounded handoff 指向 exact resume manifest(清单)。
在线入口不接受临时字段子集或任意起始日期,离线查询才允许窄查。
本模块用到的名词
- Raw evidence(原始证据)
- 普通响应或gzip解压后的原JSON字节;保存前不重新序列化,压缩传输字节与保存JSON字节分别计数。原件先保全,解析结果不覆盖它。
- Manifest(运行清单)
- 一次运行唯一的计划、页面、资产、哈希、预算、状态和恢复身份。
- Resume frontier(续跑边界)
- 下一步允许继续的位置,由已完成页面和固定计划共同证明。
- Orphan adoption(孤儿采用)
- 中断后已经写入但还没进入 manifest(清单) 的连续页面,在哈希和位置完全匹配时被安全接纳。
专业定义
首次完整取得历史;以后只补上次未完整的中国日及之后全部字段。中断沿同一清单续跑,旧原件和完整历史保持不变,对不上就停止。
解决什么
解决半次导入被当完整数据、断线后全量重下、分页死循环、目录扫描误选运行和原始字节被解析结果覆盖。
当前怎样实现
- 字段 registry(登记清单) 登记 39 类 API 类型;默认 Fitbit Air capture 从中选择 google-wearables 来源家族的 21 类兼容设备字段,另取 profile 以确定历史起点,有可用运动标识时保全 TCX。
- 日常活动接口:steps、distance、active-minutes、active-zone-minutes、sedentary-period、total-calories;运动与体能接口:exercise、swim-lengths-data、vo2-max、daily-vo2-max、run-vo2-max。
- 睡眠接口 sleep 映射为 sleep.session;心率接口包括 heart-rate、daily-resting-heart-rate、heart-rate-variability、daily-heart-rate-variability。
- 其余默认接口为 oxygen-saturation、daily-oxygen-saturation、daily-respiratory-rate、respiratory-rate-sleep-summary、daily-sleep-temperature-derivations,对应血氧、呼吸与睡眠皮温变化。
- 日期窗口连续且右开;每个 raw page 记录字段、operation、窗口、page、token、bytes、count 与 SHA-256。
- _atomic_write 先写同目录临时文件再原子替换。
- manifest(清单)持续检查field/metadata/TCX回执、分页链和历史起点;history.sources用扁平日期分段引用已完成历史,当天新采集替换原未完整当天,防止重复计算。
- google_health_history.py只核验固定指针与必要manifest(清单)元数据;首次同日重复更新可没有完整历史段。响应支持gzip,解压后的原JSON字节继续原样保存并核验。离线brief合并有效历史,query只读对应字段与日期。
- OS lock 区分活进程与已退出进程;预算在 token refresh 和 manifest(清单) mutation 前验证。
- failure handoff 固定小文件,只携带稳定错误和 exact resume 路径,不含原始正文。
执行流程
- 1
首次闭合profile历史起点;后续由固定.last-capture.json核验上一完成采集,并从其尚未完整中国日起建立全字段增量计划。
- 2
逐字段、逐连续窗口请求新日期页面;已完成历史通过扁平history.sources分段引用,不重新联网读取。
- 3
普通响应或gzip解压后的原JSON按字节保存,再写页面receipt(执行回执);压缩损坏、不支持编码或解压前后任一体积超限都会失败。
- 4
更新 bounded manifest(清单) checkpoint(续作检查点)。
- 5
中断时写 failure receipt(执行回执) 和 resume frontier。
- 6
续跑前核对锁、计划、预算、哈希和 orphan。
- 7
全部字段与资产闭合后写 complete 与 success handoff。
边界
- 原始健康载荷只留在私有健康原件目录,不进入 Git 或网页。
- 页面数、字节数、记录数、请求数和 elapsed time 均有边界。
- 已完成历史不自动联网回查,因此不承诺主动发现提供方后来补写或修订到旧日期的记录;字段不因此缩减,也不另建定期回查任务。
- google-wearables 只证明来自 Google/Fitbit 追踪设备家族,不逐条证明唯一设备型号,也不证明当前配对或在线。
- connected GPS(手机协同定位)不是 Air 内置 GPS;运动 TCX 可随原件保全,但默认摘要不分析路线。
- 通用登记表另有 18 类未纳入默认 Air 采集:心率区间时长与热量、楼层、海拔、活动消耗、活动等级、每日心率区间、血糖、体脂、核心体温、身高、体重、心电图、心律不齐通知、食物目录、食物单位目录、饮水日志、饮食日志。接口有定义不代表正在采集,也不代表设备本身一概不支持。
失败与恢复
- 固定指针损坏、历史哈希不符、分段断裂或时钟回退
- 返回incremental_pointer_*、incremental_history_*或incremental_clock_rollback,保留旧原件并停止本次增量,不扫描另一份历史凑成功。
- 重复 page token 或分页链不连续
- 在下一次 fetch 前失败,保留原始页和 terminal receipt(执行回执)。
- 请求预算耗尽
- 写有界失败回执与 exact resume manifest(清单),不扩大预算或另建 run。
- raw 文件哈希变化或额外 orphan 超出 frontier
- 拒绝续跑,不刷新 token。
- 活进程仍持有 run lock
- 拒绝并发 writer;进程真实退出后才恢复。
真实入口
google_health_import.py字段registry(登记清单)、gzip传输、全字段增量、原始保全、manifest(清单)、验证、query与resume
google_health_history.py固定最近采集指针、扁平历史日期分段与去重边界
tests/test_google_health_incremental.py全字段增量、同清单续跑、gzip和离线历史合成验证
tests/test_google_health_history.py固定指针、历史分段、日期与完整性合成验证
tests/test_google_health_import.py57 项 import、分页、预算、锁、哈希、query、handoff 与 resume 回归
AGENTS.md一次前台更新、精确失败交接和不扫描目录的项目边界
Google 官方 Fitbit Air 介绍核实无屏健身手环及 Google Health 手机应用的产品关系;不证明个人当前设备在线
Google Health API 数据接口核实 API 数据类型与 google-wearables 来源家族;实际采集范围仍以本项目白名单为准
如何验证
- import 测试覆盖 609-page fixture 的 bounded checkpoint(续作检查点) 与完整 manifest(清单)
- 中断、孤儿、篡改、重复 token、请求预算和 live lock 都有 fail-closed 回归
- 本轮只运行合成测试,未读取任何真实 raw response 或 manifest(清单)
与其他模块的关系
它把一次网络采集变成可验证证据;离线 brief 只能消费这里的 complete 清单,前台刷新也只接受这里的精确 success/failure handoff。
