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

Activity

  1. claude commented on Aug 6, 2026

    @claude
    Contributor

    处置(2026-08-06):退回派发队列(窄修)。

    复核结论:#4794 的证书撤销机制已把最坏后果(假证书跨启动存活)兜住(engine.ts 明文把「后台 seed 收尾晚于签发」列为撤销覆盖场景);剩余伤害是一次启动两套契约的 DX 噪音。「证书必须覆盖它所声称的那批数据」已是既立不变量,恢复它不是决策。

    窄修范围:kernel:ready 时检测「seed 已注册未结算」则不自证、等 app:seeded(实现形态——runtime 提供 seed 在飞信号,或 skip 分支空发 app:seeded——由 dev 定);⛔ 不动 multiTenant/skipSeedData 姿态(彼刻空库自证为真,后续按 org 重放在 strict 下响亮拒绝,无假证书)。量级 S-M。

    经办:PM 会话 session_01GcjbQLUQKysMU9uXB34iyv;维护者 2026-08-06 审阅决策简报后授权按建议执行(否决窗口:可评论/重开推翻)。


    Generated by Claude Code

  2. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    【裁决落地】维护者 2026-08-06 批复全舰队决策箱评估报告(批复「同意」),本单裁定:

    裁 A——platform-objects 检测到「seed 已注册未结算」时不做空库自证,把签发交给 app:seeded;multi-tenant / skipSeedData 情形的 ADR-0104 姿态按「不自证、等 os migrate」写明。B(runtime 提供 seed 在飞查询信号)不单独立项,若 A 实现中自然需要该信号则作为 A 的内部件。

    派发前置:本单 08-03 立案后零核验记录——开工先刷 #4794 落地后的现状(超预算转后台的窗口是否仍如正文所述),防对着已变形的代码写修复。

    流转:摘 needs-user-decision → pm:queue,归 engine-core 车道;与 #4776/#4797 同族(「声明何时被何证据推翻」),排批时建议相邻。

    评估与落地会话:session_01N3uGFF8teXbpgtbEJ1aYXu


    Generated by Claude Code

  3. self-assigned this
    on Aug 7, 2026
  4. baozhoutao commented on Aug 7, 2026

    @baozhoutao
    Contributor

    认领(执行席 PM,engine-core 车道,第 8 轮)

    • 会话:session_019Q7oc7ASjh8yxyS3Yz78We
    • 分支:claude/issue-4795-defer-selfcert-inflight-seed
    • 工作树:../objectstack-issue-4795(worktree-first)
    • 文件面:packages/platform-objects(kernel:ready 自证入口)为主;若裁 A 实现自然需要「seed 在飞」信号,runtime 侧作为 A 的内部件一并动(裁决原文允许);测试 + changeset

    按 2026-08-06 维护者批复的裁 A 执行:「seed 已注册未结算」时不做空库自证、交给 app:seeded;multi-tenant / skipSeedData 的 ADR-0104 姿态按「不自证、等 os migrate」写明。开工先刷 #4794 落地后的现状(派发前置,防对着已变形的代码写修复)。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions