Skip to content

bug(platform-objects): 超预算后台 seed 时,空库自证仍可能签在尾部数据落定之前 —— 首启一次启动两套契约 #4795

Description

@os-zhuang

背景

#4769 修掉了主路径:ADR-0104 的空库自证改为等 app:seeded(inline seed 结算点)再落笔,并且先问引擎「这次启动放行过违反该契约的值吗」,被证伪的 migration id 不再自证。PR: #4794

留下一个窗口没关。

剩余窗口

AppPlugin 的 inline seed 有一个软预算(OS_INLINE_SEED_BUDGET_MS,默认 8000ms)。超预算时它会打一条 warn 然后放到后台继续跑,app:seeded 要等后台跑完才触发。而 kernel:ready 的兜底自证会先到:

  1. Phase 2:seed 超预算,转后台;
  2. Phase 3 kernel:ready:兜底自证跑,此时台账里只有已经落定的那部分的反例 —— 可能是空的;
  3. 自证写入 + invalidateDataMigrationFlags() → 本次启动转入 strict;
  4. 后台 seed 的尾部行带着不合形状的值写入 → 被拒

结果不再是 #4769 那种跨启动翻转(第二次启动的行为与第一次一致,尾行两次都写不进去,证书本身也是真的 —— 那些行从没落库),但仍然是同一次 seed 运行、同一份数据集,前半段 warn-first 后半段 strict:一次启动两套契约。

为什么 #4794 没有顺手修

要在 kernel:ready 判断「是否还有 seed 在飞」,platform-objects 得去嗅 runtime 注册的 seed-datasets 服务;而 multi-tenant(按 org 重放)与 skipSeedData(#3917 的迁移 boot)两种模式下 app:seeded 永远不会触发,一旦按「有 datasets 就等」处理,这两类部署将永不自证、长期停在 warn-first。

值得注意的是:对 multi-tenant 而言「永不在 boot 自证」很可能才是对的 —— 种子数据是在 sys_organization insert 时按 org 重放的,启动那一刻去证明一件尚未发生的事,正是 #4769 的同一个错误、只是引信更长。所以这里需要的是一个决定(multi-tenant 部署的 ADR-0104 姿态该由什么来确立),不是一个补丁。

建议

  • 方案 A:platform-objects 在 kernel:ready 检测到「seed 管线已注册但尚未结算」时不自证,交给 app:seeded;并明确 multi-tenant / skipSeedData 下的期望姿态(很可能就是「不自证,等 os migrate」)。
  • 方案 B:让 runtime 在超预算转后台时提供一个可查询的「seed 在飞」信号,platform-objects 据此推迟,避免嗅服务名。

倾向 A,因为它把 multi-tenant 那个更根本的问题一起摆到台面上;但两者都改变了部分新部署的姿态,需要维护者定夺。

复现方向

OS_INLINE_SEED_BUDGET_MS 调到很小(如 1)冷启 showcase,观察 sys_migration 行的写入时刻与后台 seed 尾部的 ERROR。


#4769 的实现过程中发现并记录(AGENTS.md Prime Directive #10),未认领。

Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions