2026-10-09 校注:文中部署目录、服务、版本和验收计数为各段标注日期的历史记录;当前可验证状态见 current-status-2026-10-09,本次未复跑历史测试或读取私有健康/对话数据。

Humon 自然五分钟槽单写 v1

暴露的问题

原逻辑在 run_once 先读 latest auto,再判断是否同槽。两个进程若同时读到同一个 previous,就可能都通过检查,再以不同 timestamp 写入同一五分钟槽。代码声明了单写,但 SQLite 没有唯一约束。

窗口隐私迁移期间恰好暴露一次真实竞态:

  • 同一槽 2 条 auto,相差 4.826 秒;
  • 两条都是 availability/activity=idle;
  • 生成 2 条 shadow decision;
  • 唯一对应的使用行累计 899 秒/3 samples,其中 300 秒/1 sample 属于重复写;
  • quality v2 因 close duplicate + duplicate bin 暂时 degraded。

没有情绪/健康/投递误判,但自然节律、使用时长和 shadow 数会被污染,必须修复。

三层防线

1. 跨进程完整周期锁

run_once 由 serialized_collection 包装,data/collection.lock 使用 Linux fcntl,将 observe → context → fuse → observations/state → usage/shadow/quality 的整个周期串行化。runtime 内部锁改为可重入,避免嵌套锁死。

2. SQLite 部分唯一索引

idx_states_v3_auto_user_slot:

UNIQUE(user, CAST(timestamp/300 AS INTEGER)) WHERE source='auto' AND model='Humon-fusion-v3'

即使有旧进程或绕过锁的调用,数据库也不会接受第二条自然 v3。

3. 冲突降级而非自然污染

save_state 使用 INSERT OR IGNORE 并返回是否成功。若 auto 写被唯一索引拒绝:

  • record.source 改为 auto-race-deduped;
  • 保留一条非自然状态供审计;
  • 不进入 AppUsage、shadow、quality snapshot 或 baseline;
  • query/history/stats 默认排除;
  • 关联 observations 因非自然 state 被质量层排除;
  • quality 暴露 sampling.race_deduped_samples。

明确 self-report 落在已占槽时仍转 manual,真值保留但不制造自然样本。

历史修正

natural_slot_unique_v1 对每个重复槽保留最早 auto,其余 demote:

  • 当前 1 条重复被改为 auto-race-deduped;
  • 删除 demoted state 的重复 shadow decision;
  • 当 date/hour/process 只匹配一个 derived usage row 时,按该进程当时看到的 prior natural gap 回退 sample seconds/count;
  • 本次唯一匹配成功:899s/3 → 599s/2;
  • 原始第一条 shadow 保留,所以该槽 shadow rows=1;
  • 然后创建部分唯一索引。

回滚点: ${HOME}/.hermes/backups/humon-v3-pre-natural-slot-unique-20260717-002907,directory 700 / DB 600。

验证证据

  • 42 项测试、Ruff、compileall 通过。
  • 合成 race 覆盖 demote、shadow delete、usage rollback、unique-index rejection。
  • run_once mock 覆盖 DB conflict → non-natural audit,且 usage/shadow 不执行。
  • 基线合成轨迹改为真实独立五分钟槽,662 natural samples 与三个 horizon 仍 ready。
  • 正式 unique index present;duplicate natural slots=0;race_deduped states=1。
  • 正式 usage correction 599s/2 samples found;race slot shadow rows=1。
  • quality=operational-collecting、operational_ready=true、race_deduped counter=1、delivery_ready=false。
  • 下一次真实自然 cron 后 natural v3=47、duplicates=0。
  • privacy_events=0、delivered=0、delivery_eligible=0、DB integrity=ok。

关联