Skip to content

feat(core): init 阶段取服务的声明契约改为强制 — check:init-service-contract 门禁 (#4471) - #4631

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-4471-init-service-declared-enforced
Aug 2, 2026
Merged

feat(core): init 阶段取服务的声明契约改为强制 — check:init-service-contract 门禁 (#4471)#4631
os-zhuang merged 1 commit into
mainfrom
claude/issue-4471-init-service-declared-enforced

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#4471

问题

ADR-0116 / packages/core/src/plugin-order.ts 的顺序契约机制是完备的(dependencies 硬依赖、optionalDependencies 有则排前、requiresServices + assertInitServiceRequirements 具名报错),但所有声明都是自愿的:一个插件在 init()getService('X') 却什么都不声明,没有任何一层会指出来——只会在某个组合顺序下静默拿不到服务,而 miss 又通常藏在 best-effort 的 try/catch + warn 里。#4085#4420 都是这么发生的,后者的代价是数据一致性级别(每次重启丢光在途审批)。

方案(issue 期望的方向一:静态 check:* 门禁)

scripts/check-init-service-contract.mjs — 用 TypeScript AST 扫描 packages/ 下所有插件单元(class 形态与对象字面量形态都覆盖),规则:

接入:根 package.jsoncheck:init-service-contract + lint.yml 新步骤;plugin-order.ts 头注释补充"声明不是自愿的"一段,指向该门禁。

门禁在现有代码上的初次收获(修复前全树 11 处未声明,全部在本 PR 补上声明)

首次运行即抓出 11 处未声明的 init 期消费——正是 issue 说的"少数漏网的那个最贵":

消费方init 期消费补上的声明
@objectstack/metadata MetadataPluginmanifestoptionalDependencies: [objectql]
@objectstack/rest rest-api-pluginmanifest(注册 sys_import_job)同上
@objectstack/cli serve.ts 两个内联插件http.server/http-serveroptionalDependencies: [com.objectstack.server.hono]
service-analyticsdata(auto-bridge 探测)optionalDependencies: [objectql]
service-datasource adminmanifest(Setup 导航)同上
service-jobmanifest + clusteroptionalDependencies: [objectql, service.cluster]
service-knowledgeobjectql(RLS 复查)optionalDependencies: [objectql]
service-queue / service-settings / service-storagemanifest(注册 sys 表)同上

每一处都保持原有的"缺 provider 时按设计降级"语义不变——变化只是:两者同时组合时,内核现在确定性地把 provider 排在前面,不再靠注册顺序的运气。

验证

范围外

issue 里"另外值得单独定一条"的日志级别约定(best-effort 降级导致"看起来正常、实则不持久"时不应是 warn)未在本 PR 实现,已另开 issue 跟踪(见 PR 评论关联)。

🤖 Generated with Claude Code

https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5


Generated by Claude Code

…ate (#4471)
ADR-0116's ordering contract (dependencies / optionalDependencies /
requiresServices / providesServices) was complete but voluntary: a plugin
resolving getService('X') during init() while declaring nothing was invisible
to every check, failing only under unlucky composition orders — the #4085 and
#4420 failure class, the latter at data-consistency cost.
- scripts/check-init-service-contract.mjs: AST scan of every plugin unit
(classes and object literals) under packages/. Walks the init() call graph
transitively (same-class methods, same-file functions — the #4420 call sat
in a private helper), skips deferred callbacks (hooks) and start(), and
errors on any init-reachable getService of a workspace-provided service not
covered by a declaration. 12-case --self-test pins the #4420 pre-fix shape
caught, all declared shapes passing, and the start()/hook shapes exempt.
- Wired as check:init-service-contract in root package.json and lint.yml.
- Declares the 11 previously undeclared init-time consumers the gate found
(metadata, rest, two cli serve plugins, analytics, datasource-admin, job,
knowledge, queue, settings, storage) via optionalDependencies on their
providers — declared tolerance in the plugin, never a checker-side ledger.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5
@vercel

vercelBot commented Aug 2, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 2, 2026 12:20pm

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation ci/cd dependencies Pull requests that update a dependency file tooling size/l labels Aug 2, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 11 package(s): @objectstack/cli, @objectstack/core, @objectstack/metadata, @objectstack/rest, @objectstack/service-analytics, @objectstack/service-datasource, @objectstack/service-job, @objectstack/service-knowledge, @objectstack/service-queue, @objectstack/service-settings, @objectstack/service-storage.

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

  • content/docs/ai/actions-as-tools.mdx(via @objectstack/core)
  • content/docs/ai/connect-mcp.mdx(via @objectstack/rest)
  • content/docs/ai/knowledge-rag.mdx(via @objectstack/core, @objectstack/service-knowledge)
  • content/docs/ai/natural-language-queries.mdx(via @objectstack/core)
  • content/docs/ai/skills-reference.mdx(via packages/cli)
  • content/docs/api/client-sdk.mdx(via @objectstack/cli)
  • content/docs/api/data-api.mdx(via @objectstack/service-analytics)
  • content/docs/api/data-flow.mdx(via @objectstack/cli)
  • content/docs/api/environment-routing.mdx(via @objectstack/cli)
  • content/docs/api/error-catalog.mdx(via @objectstack/cli)
  • content/docs/api/error-handling-server.mdx(via @objectstack/rest)
  • content/docs/api/index.mdx(via @objectstack/rest, @objectstack/service-analytics)
  • content/docs/api/plugin-endpoints.mdx(via @objectstack/service-storage)
  • content/docs/automation/hook-bodies.mdx(via packages/cli)
  • content/docs/automation/webhooks.mdx(via @objectstack/core)
  • content/docs/concepts/metadata-lifecycle.mdx(via @objectstack/metadata)
  • content/docs/concepts/north-star.mdx(via packages/core)
  • content/docs/deployment/backup-restore.mdx(via @objectstack/cli)
  • content/docs/deployment/cli.mdx(via @objectstack/cli)
  • content/docs/deployment/migration-from-objectql.mdx(via @objectstack/core)
  • content/docs/deployment/self-hosting.mdx(via @objectstack/cli)
  • content/docs/deployment/validating-metadata.mdx(via packages/cli)
  • content/docs/getting-started/your-first-project.mdx(via @objectstack/cli)
  • content/docs/kernel/cluster.mdx(via packages/metadata)
  • content/docs/kernel/contracts/index.mdx(via @objectstack/core)
  • content/docs/kernel/runtime-services/audit-service.mdx(via packages/services/service-settings)
  • content/docs/kernel/runtime-services/data-service.mdx(via packages/cli)
  • content/docs/kernel/runtime-services/examples.mdx(via @objectstack/core)
  • content/docs/kernel/runtime-services/index.mdx(via packages/cli, packages/services/service-settings)
  • content/docs/kernel/runtime-services/settings-service.mdx(via packages/services/service-settings)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/core, @objectstack/metadata, @objectstack/service-analytics, @objectstack/service-job, @objectstack/service-queue, @objectstack/service-storage)
  • content/docs/kernel/services.mdx(via @objectstack/core)
  • content/docs/permissions/authentication.mdx(via @objectstack/cli, @objectstack/core, @objectstack/rest)
  • content/docs/permissions/authorization.mdx(via packages/core)
  • content/docs/permissions/sharing-rules.mdx(via @objectstack/service-analytics)
  • content/docs/plugins/anatomy.mdx(via @objectstack/core)
  • content/docs/plugins/development.mdx(via @objectstack/core)
  • content/docs/plugins/index.mdx(via @objectstack/cli, @objectstack/core, @objectstack/rest)
  • content/docs/plugins/packages.mdx(via @objectstack/cli, @objectstack/core, @objectstack/metadata, @objectstack/rest, @objectstack/service-analytics, @objectstack/service-job, @objectstack/service-queue, @objectstack/service-settings, @objectstack/service-storage)
  • content/docs/protocol/kernel/config-resolution.mdx(via @objectstack/core)
  • content/docs/protocol/kernel/i18n-standard.mdx(via packages/rest)
  • content/docs/protocol/kernel/index.mdx(via @objectstack/core)
  • content/docs/protocol/kernel/lifecycle.mdx(via @objectstack/core)
  • content/docs/protocol/kernel/metadata-service.mdx(via @objectstack/metadata)
  • content/docs/protocol/kernel/plugin-spec.mdx(via @objectstack/cli, @objectstack/core)
  • content/docs/protocol/kernel/realtime-protocol.mdx(via @objectstack/cli)
  • content/docs/protocol/knowledge.mdx(via @objectstack/service-knowledge)
  • content/docs/releases/implementation-status.mdx(via @objectstack/cli, @objectstack/core, @objectstack/rest, @objectstack/service-analytics, @objectstack/service-job, @objectstack/service-knowledge, @objectstack/service-queue, @objectstack/service-settings, @objectstack/service-storage)
  • content/docs/releases/v12.mdx(via @objectstack/core, @objectstack/metadata, @objectstack/rest)
  • content/docs/releases/v15.mdx(via @objectstack/core)
  • content/docs/releases/v16.mdx(via @objectstack/cli)
  • content/docs/releases/v17.mdx(via @objectstack/rest, @objectstack/service-analytics)
  • content/docs/releases/v9.mdx(via @objectstack/metadata, @objectstack/service-analytics, @objectstack/service-settings)

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
os-zhuang marked this pull request as ready for review August 2, 2026 12:37
@os-zhuang
os-zhuang added this pull request to the merge queueAug 2, 2026
Merged via the queue into main with commit 9fd9ae7Aug 2, 2026
22 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-4471-init-service-declared-enforced branch August 2, 2026 12:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cddependenciesPull requests that update a dependency filedocumentationImprovements or additions to documentationsize/ltooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[core/ADR-0116] init 阶段取服务的顺序契约是自愿声明的——不声明就没人拦,#4085 与 #4420 都是这么发生的

2 participants

@os-zhuang@claude