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

vercelBot commented Jul 24, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
specBuildingBuildingPreview, CommentJul 24, 2026 3:02pm

Request Review

@github-actionsgithub-actionsBot 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
ContributorAuthor

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).

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

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@os-zhuang