Skip to content

fix(seed-summary): count the marketplace rehydrate heal in the boot banner, and make the counter accumulate#3452

Closed
os-zhuang wants to merge 1 commit into
mainfrom
claude/marketplace-heal-seed-summary
Closed

fix(seed-summary): count the marketplace rehydrate heal in the boot banner, and make the counter accumulate#3452
os-zhuang wants to merge 1 commit into
mainfrom
claude/marketplace-heal-seed-summary

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

背景

#3435 刚合并,给启动 banner 加了 Seeds: 行(由 kernel 的 seed-summary 计数器驱动),并修了 showcase 项目种子的 FSM 出生态问题。但那个计数器只有 AppPlugin 的 config app 种子会写。marketplace 的 rehydrate heal(#3421,在同一个 boot-quiet 窗口把已装包的样例数据补进空库)什么都不写 —— 于是 marketplace 包 heal 出来的行、以及最关键的「装了但 0 行」空状态,在 banner 上完全不可见(而这正是这条 Seeds 行存在的意义)。showcase 实测:banner 读 130 inserted · 6 updated,而 HotCRM 在旁边静默 heal 了 162 行,一个数都没进 banner。

两个把「直接 fold-in」卡住的潜伏 bug

排查中发现 #3435 的计数器本身就不工作,只是单 config app 场景掩盖了:

  1. 读永远 undefined:它用 (ctx as any).kernel?.getService('seed-summary') 读旧值,但插件 PluginContext(packages/core/src/kernel.ts:76)根本没有 .kernel 句柄 —— 只有 getService/registerService。所以每次读都是 undefined,每次写都是盲覆盖,从不累加。
  2. 第二次 register 抛异常:registerService(name, …)(kernel.ts:195)遇到重名直接 throw 'already registered'。第二个写入方的注册抛出被 try/catch 吞掉。两者叠加,fix(showcase): seed all five projects through the FSM + surface seed outcomes in the boot banner (#3415) #3435 注释里的 "accumulates across apps" 从来没成立过 —— 谁最后写谁赢。showcase 的 130 行多阶段 FSM 种子超过 8s budget 后台晚写,正好把 marketplace 的值覆回 130·6

修复

@objectstack/types 新增共享的 accumulateSeedSummary(ctx, delta):注册一个可变计数对象一次,之后所有写入方就地 mutate 它 —— 与种子来源顺序无关、且不受 kernel getService 缓存影响,race/cache 双安全(第一个注册者赢,后来者 catch 掉 already-registered 并取回同一个对象继续 mutate)。AppPlugin 与 marketplace heal 都改用它。heal 把补进的行记为 inserted/updated;heal 落 0 行时强制 rejected≥1,让「装了但 0 行」升级成 banner 的黄色告警。

验证

showcase fresh boot 现在 banner 读 292 inserted · 6 updated(130 config + 162 HotCRM heal),不再是 130 · 6;crm_opportunity=61、crm_contact=5 实测在库。新增单测:@objectstack/types accumulateSeedSummary 6 例(含「第二写入方必须累加不被 already-registered 吞掉」「已被读取方持有的对象引用能看到后续写入」),marketplace heal 6 例(healed 计入 / 空 heal 升 rejected / loader 错误数透传 / present·purged 不动计数器 / 叠加在 config 之上)。types 32、cloud-connection 69、runtime 587 全绿。

#3435 的关系

只在 #3435 之上做加法:复用它的 seed-summary 服务与 banner 渲染(printSeedSummary 未改动),补齐它没覆盖的 marketplace 路径,并修好它那个单 config app 场景没暴露的累加 bug。

备注

发现但不在本 PR 范围:(ctx as any).kernel 的死用法在仓库里还有两处(app-plugin.ts:752marketplace-install-local-plugin.ts:887seed-datasets 注册)—— 它们的?? ctx.registerService 兜底能工作,但 prev 同样恒 undefined。多租户 per-org replay 依赖 seed-datasets,值得单独 audit(已在我的多租户时序 audit 待办里)。

🤖 Generated with Claude Code

…anner, and make the counter accumulate

The boot-banner Seeds line (#3435) was fed by a `seed-summary` kernel counter
only AppPlugin's config-app seed wrote to. The marketplace rehydrate heal
(#3421) seeds an installed package's sample data in the same boot-quiet window
but wrote nothing — so a marketplace package's healed rows, and critically its
empty "installed but 0 rows" state, were absent from the banner.

Two latent bugs blocked simply folding it in:
1. The counter read its prior total via `(ctx as any).kernel?.getService`, but
   the PluginContext has no `.kernel` handle — the read was always undefined, so
   every write was a blind overwrite, never an accumulation.
2. registerService throws on a duplicate name, so the second writer's
   registration threw and was silently dropped.

Fix: a shared accumulateSeedSummary(ctx, delta) in @objectstack/types registers
one mutable counter object and mutates it in place — race- and cache-safe
regardless of seed-source order. AppPlugin and the marketplace heal both use it.
The heal reports healed rows and forces a non-zero rejected on a zero-row heal
so "installed but 0 rows" escalates to the banner warning.

Verified on showcase: fresh boot reads "292 inserted · 6 updated" (130 config +
162 HotCRM heal) instead of "130 · 6".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Building Building Preview, Comment Jul 24, 2026 3:02pm

Request Review

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Jul 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/cloud-connection, @objectstack/runtime, @objectstack/types.

17 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/api/index.mdx (via @objectstack/runtime)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/runtime)
  • content/docs/concepts/north-star.mdx (via packages/runtime)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/runtime)
  • content/docs/permissions/authentication.mdx (via @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/runtime)
  • content/docs/plugins/packages.mdx (via @objectstack/runtime, @objectstack/types)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/runtime)
  • content/docs/releases/implementation-status.mdx (via @objectstack/runtime)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang

Copy link
Copy Markdown
Contributor Author

Superseded by #3444, which merged while this PR's CI was running. #3444 implements the same marketplace-heal boot-summary observability with a richer per-source model (recordSeedOutcome with source / marketplace / healed / emptyInstall flags) and independently applies the same fix this PR found for the counter's latent bugs — the dead (ctx as any).kernel read and registerService throwing on a duplicate name (register-once-then-mutate). Nothing here is additive over #3444, so closing.

Note: the sibling defect this PR's investigation surfaced — the SAME dead-ctx.kernel/duplicate-register pattern in the multi-tenant seed-datasets per-org replay seam — is NOT addressed by #3444 (it only touched seed-summary). That remains tracked in #3453 (app-plugin.ts:753-776 still has it on main).

@os-zhuang os-zhuang closed this Jul 24, 2026
@xuyushun441-sys
xuyushun441-sys deleted the claude/marketplace-heal-seed-summary branch July 24, 2026 15:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant