Skip to content

[Decision] 一个应用能否声明依赖另一个应用并引用其对象(ADR-0019 推迟的应用间依赖) #25403

Open

Description

@hotlong

Ruled: 6369704387 · batch #7 item 1 · letter B′ · 2026-10-23T16:28:30Z (B narrowed by the maintainer: keep the manifest dependencies declaration and the save door's closure as the reference mechanism; add only the pre-install check — dependency installed and version in range, else refuse with a clear message, filling the reserved dependency_missing category; defer uninstall protection, upgrade interception, topological / cascade install and any owner-side publish marker to named later items in the ADR; permissions unchanged; first consumer = a HotCRM module shipping alone)

立卡门类别:② 只有维护者能做的决定。动手的读者:裁定后由 domain:spec 席起草 ADR,并按 ADR 切实现卡。
查重(含 closed,仓内语义检索):

维护者速读

今天,一个可安装的应用还不能正式依赖另一个应用。以 PSA(项目交付)为例,它要引用 CRM 的客户、商机和合同,现在只有两种做法:

  • 把 PSA 做进 CRM,随 CRM 发给所有客户;
  • 另出一个「CRM + PSA」组合应用,让客户换装。

同样,CRM 和 SRM 之间也无法共用客户和供应商资料。

要不要让平台支持「应用 B 声明依赖应用 A,可以引用 A 的对象,由平台管安装顺序、卸载保护和版本兼容」?

  • A 维持现状:应用之间隔离,要组合的产品打进同一个发布包。
  • B 开放应用间依赖(推荐):先写 ADR 定契约,等第一个真实产品需要独立安装时再实现。
  • C 平台自带共享主数据:客户、供应商等对象由平台提供,各应用只引用这些对象。

选 A、B 还是 C? 已裁 B′(批 #7 第 1 项,评论 6369704387):声明 + 安装前检查;卸载保护、升级拦截、多包拓扑 / 连带安装、被引用方的发布标记写为 ADR 的推迟项;权限不变。维护者原话(2026-10-23):「包依赖本身没问题,也就是说如果 psa 依赖 crm, 安装psa 之前先检测crm有没有,没有就禁止安装,这个有必要嘛」「往往需要引用的数据并不多,可能就几个对象」「如果这样,hotcrm 岂不是真实的可以分拆出很多模块」「而每个包可以独立安装」「同意」。

os-decision-facets

  • ① 项目长远合理性:B 把散落的特例收成一条契约——「声明了依赖才可跨应用引用」。现在的特例包括:发布包内可以引用(ADR-0130),保存门按依赖闭包判定,ADR-0028 D4 提议全面隔离,应用仓只能合包。A 的特例会随产品组合数增长。
  • ② 实际业务拉动:今天没有已上线的产品被卡住。在途的拉动都在设计阶段:hotcrm 的 PSA 设计想移出 CRM、做成单独产品;集团系统规划里 CRM 和 SRM 要共用主数据;客户仓库要在标准产品上迭代。
  • ③ 防 AI 犯错:B 以声明的依赖为闭集,未声明的跨应用引用响亮拒绝,保存门今天已经这样做(list-view-object-outside-closure 返回 422)。A 同样响亮拒绝,但会把需求推向复制对象、靠同步对齐,造成静默的数据分叉。
  • ④ 创业阶段不扩散:B 新增四项永久义务:安装顺序、卸载保护、跨应用版本兼容、跨应用权限语义。A 不新增义务。所以按 ④ 只调时序:先定契约,后实现。

Prior rulings read: inter-app,cross-app,app dependency,shared data model → 2 hits; none; thread: not read (no --card); repo: objectstack-ai/objectstack

(两处命中都是 ADR-0028 的 D4、D6,状态为 Deferred / proposed,不是已生效的裁决。)

一句话问题

客户先装了 CRM,以后想加 PSA。做不到「再装一个 PSA」:要么 PSA 早就随 CRM 装给了所有客户,要么客户换装一个更大的组合应用。

背景

Governing text

  • docs/adr/0019-app-as-consumer-unit.md §Out of scope:「Shared/published data model + inter-App dependencies (cross-app data sharing without a "suite").」
  • docs/adr/0028-metadata-naming-and-namespace-isolation.md D4(状态 Deferred):「A type: app package may reference its own metadata … but may not reference metadata owned by another app.」
  • docs/adr/0130-release-artifact-as-co-ownership-boundary.md D2、D5:发布包内多包,按依赖拓扑注册。
  • packages/lint/src/rule-explanations.ts 的 list-view-object-outside-closure:保存门按闭包判定;os validate、os build、os lint 不判跨包引用,原文:「a stack there is one app, and an unresolved binding may be a dependency package's object the stack does not carry」。

协议声明、是否改协议

会改协议。选 B 或 C 需要新 ADR;ADR-0028 D4 的提议要改写;ADR-0019 原文不改,只加交叉引用,沿用 ADR-0130 的记录惯例。ManifestSchema.dependencies 这一行已经存在,B 的工作是赋予它在应用之间的安装语义。

前提(每条带 re-check 命令)

  1. ADR-0019 推迟了应用间依赖:git grep -n "inter-App dependencies" origin/main -- docs/adr/0019-app-as-consumer-unit.md
  2. ADR-0028 D4 只是提议、状态为推迟:git grep -n "Apps are sandboxed\|^\*\*Status\*\*" origin/main -- docs/adr/0028-metadata-naming-and-namespace-isolation.md
  3. 保存门的闭包包含声明的依赖:git grep -n "the objects of the packages its" origin/main -- packages/lint/src/rule-explanations.ts
  4. 构建和校验不判跨包引用:git grep -n "judge neither" origin/main -- packages/lint/src/rule-explanations.ts
  5. 发布包内 R3 被拒:在 hotcrm 仓运行 grep -n "^| \*\*R3\*\*" docs/architecture/module-split-plan.md
  6. 未验证:两个分别安装的 App 今天在安装门上的实际行为——是否按 dependencies 排序、缺依赖时是否拒绝、卸载被依赖方时是否阻止。插件层有依赖解析器,但它是否作用于应用安装未测:git grep -n "Missing dependency" origin/main -- packages/core/src/dependency-resolver.ts 已由总监席核实(2026-10-23,main ea33919f):安装路径不读 manifest.dependencies;dependency_missing 只是 packages/spec/src/system/app-install.zod.ts 的枚举值,全仓无生产者;packages/runtime/src/domains/packages.ts 编辑 dependencies 只校验形状(⛔ No in-use check);packages/core/src/dependency-resolver.ts 只服务 kernel 插件。即:今天不排序、不拒绝、不阻止——这正是 B′ 的安装前检查要补的。

具体问题

应用之间的引用,平台的终态是什么:

  • 隔离;
  • 声明依赖后可以引用;
  • 由平台提供共享主数据。

选项

选项 做什么 客户能感知的后果 工作量
A 维持隔离 不改。ADR-0028 D4 的方向照旧;要组合的产品打进同一个发布包 后加一个产品,要么它早已随主应用装给所有人,要么换装组合应用;跨应用的主数据靠导入或同步 无
B 应用间依赖 写 ADR;安装门检查被依赖的应用已安装、版本在范围内,并按依赖排序;卸载被依赖的应用时阻止或提示;跨应用引用沿用保存门的闭包判定,覆盖到安装和构建;控制台显示依赖关系;定义跨应用引用的权限语义 先装 CRM,以后再装 PSA;卸 CRM 前提示 PSA 依赖它;未声明的引用保存时直接报错 spec、运行时、控制台多车道,1 篇 ADR 加若干 PR;无先例(最近的同类工程是 ADR-0130 的包内多包注册,其 PR 行数未测)
B′ 声明 + 安装前检查(已裁) 声明沿用 ManifestSchema.dependencies,引用沿用保存门闭包;安装前检查依赖已装且版本在范围内,否则拒绝并提示;卸载保护、升级拦截、拓扑 / 连带安装、被引用方发布标记写为 ADR 推迟项;权限不变 先装 CRM,以后再装 PSA;装反了被拦并提示先装 CRM spec 席 ADR(S)+ 运行时安装前检查(XS–S)+ 文档
C 平台共享主数据 平台提供客户、联系人、供应商、产品、合同等共享业务对象,各应用只引用这些对象,应用之间不互相引用 各应用天然共用主数据;但已有应用的对象要迁移到共享对象 平台要拥有一套业务数据模型,需要 ADR、多车道,以及现有应用的迁移;无先例

业务含义直译

  • A:像套装软件——要么买整套,要么各用各的,中间靠导数据。
  • B:像 Salesforce 的扩展包依赖基础包——主应用先装,扩展应用后装,主应用不能先被卸掉。
  • C:像 Dynamics 的公共数据模型——平台自带客户、联系人等标准表,所有应用共用。

四轴论证(业务立场)

  • ①:两年后,市场上会有第一方的 CRM、SRM、PSA,也会有第三方应用;客户按需先后安装是常态。只有 B 让「后加一个产品」不需要换装,也不需要把它塞给所有人。
  • ②:拉动真实但还在设计阶段,所以只影响时序,不影响方向。
  • ③:B 的闭集判定在保存门已经实现,出错时作者当场看到 422;A 下作者会复制对象,错误表现为两边数据静默不一致,没人当场看到。
  • ④:B 的永久义务明确且有限(四项),可以写进一篇 ADR 一次定清;C 的义务是整套业务数据模型,范围大得多。

推荐与置信缺口

推荐 B。 终态是:应用之间通过显式声明的依赖引用对方对象,平台管安装顺序、卸载保护和版本兼容。这是主流平台的共同形状,参照有:

  • Salesforce:扩展包依赖基础包;
  • Dataverse:解决方案依赖;
  • ServiceNow:跨作用域访问策略;
  • Odoo:模块的 depends。

不取另外两项的理由:

  • 不取 A:组合数随产品数增长,客户后加产品只能换装;
  • 不取 C:平台要拥有业务数据模型,内核契约会大幅扩张。有了 B 之后,「主数据应用」可以作为一个普通应用来实现。

置信缺口:

  • 前提 6 未实测,即今天两个分别安装的 App 在安装门上的行为;(已核实,见前提 6)
  • 跨应用引用的记录级权限语义未设计——依赖方的查找关系,如何受被依赖方的共享规则约束;
  • ADR-0028 D4 想要的市场应用之间的隔离,在 B 下靠「必须显式声明依赖」来保留。这是否足够,需要安全方向复核。

自检:只看①选 B;②③④ 是否翻转:否。②、④ 只影响时序:先写 ADR,等第一个真实产品需要独立安装时再实现。

裁后执行

  • 裁 B′(已裁,批 Remove explicit pnpm version from workflows to fix version conflict #7 第 1 项):
    1. domain:spec 席起草 ADR:声明(现有 dependencies)、安装前检查(已装 + 版本在范围内,否则拒绝并提示;填 AppCompatibilityCheck 已预留的 dependency_missing)、跨应用引用沿用保存门闭包、权限语义开放节;卸载保护、升级拦截、拓扑 / 连带安装、被引用方发布标记写为推迟项;manifest 与市场两种 dependencies 形状对齐;
    2. 同一份 ADR 把 ADR-0028 D4 改为「未声明依赖不得跨应用引用」,并在 ADR-0019 加交叉引用(不改原文);
    3. ADR 合并后切实现卡:第一张是运行时的安装前检查(XS–S,含控制台拒绝文案);第一个消费者场景写为 HotCRM 模块单独发布(hotcrm module-split-plan.md 2026-09-14 形状,revenue 先);
    4. 检查落地前,需要组合的产品仍按 ADR-0130 打进同一个发布包。
  • 裁 A:在 ADR-0019 记一条 no-go 的交叉引用;hotcrm 的 PSA 按「同一发布包」写定。
  • 裁 C:先立「平台共享业务对象」ADR 的范围卡,评估现有 CRM、SRM 对象的迁移。

相关单与 PR

Activity

  1. os-elon-musk commented on Oct 23, 2026

    @os-elon-musk
    Collaborator

    Ruling: batch #7 item 1 · letter B′ · maintainer 「同意」 2026-10-23T16:28:30Z

    What B′ is (the card's B, narrowed by the maintainer's own words in the director thread; the letters A / B / C as filed and the D「发布对象」 variant the director offered at 16:10 were not chosen):

    1. Declaration stays as it is. An installable app declares what it depends on in ManifestSchema.dependencies ({ packageId: versionRange }, manifest.zod.ts); the save door's closure already honours the declared packages' objects (list-view-object-outside-closure, fix(lint)!: the save door refuses a list view written into a package and bound outside its closure #24630 / packages: manifest dependencies can be set only at create — PATCH /api/v1/packages/:id persists only name / description / version, so a save refused with "declare a dependency" has no remedy short of recreating the package #24670 / feat(runtime): PATCH /api/v1/packages/:id edits a package's manifest dependencies #24703), so cross-app references need no new reference mechanism and no owner-side「published object」flag.
    2. Pre-install check, and only that gate. Installing an app checks every declared dependency: the package is installed in the tenant and its version satisfies the range; otherwise the install is refused with a clear message (「请先安装 HotCRM 6.x」). This fills the dependency_missing category that AppCompatibilityCheckSchema (packages/spec/src/system/app-install.zod.ts) already reserves and that today has no producer.
    3. Deferred, written into the ADR as explicit later items, not implemented now: uninstall protection (refusing to uninstall a depended-on app), upgrade interception (blocking an upgrade of the depended-on app that would leave a dependant's range), multi-package topological install / cascade install, an owner-side publish marker restricting which objects may be referenced, and any marketplace-level version negotiation.
    4. Permissions unchanged: a referencing app's users see the referenced app's records under the referenced app's own sharing rules; a dependency opens the reference, not the data. Record-level semantics stay an open section in the ADR, decided with the first consumer.

    The maintainer's reasoning, verbatim, for the ADR author (director thread, 2026-10-23):

    25403 如果按照包依赖的方式,整个开发会复杂很多,如果每个应用包是单独安装的,有其他方式把数据串起来吗 (16:10:20Z)
    往往需要引用的数据并不多,可能就几个对象 (16:10:38Z)
    包依赖本身没问题,也就是说如果 psa 依赖 crm, 安装psa 之前先检测crm有没有,没有就禁止安装,这个有必要嘛 (16:20:28Z)
    如果这样,hotcrm 岂不是真实的可以分拆出很多模块 (16:25:59Z) / 而每个包可以独立安装 (16:26:18Z)
    同意 (16:28:30Z — on the director's recommendation B′ and the suggested order below)

    Workload of the chosen letter: one ADR by the domain:spec seat (S, half a day to a day): the contract above; ADR-0028 D4 rewritten to「no cross-app reference without a declared dependency」; a cross-reference in ADR-0019 (text unchanged, ADR-0130's recording convention); the deferred gates listed by name; the open permission section; the manifest dependencies record and the marketplace PackageDependencySchema array (package-version.zod.ts) aligned. Then one runtime card for the pre-install check (XS–S) with the console's refusal text, plus docs. The first consumer scenario the ADR should name is a HotCRM module shipping on its own (hotcrm docs/architecture/module-split-plan.md, the 2026-09-14 shape: sales app + service / revenue / marketing; revenue first per ADR-0130 §1.3(c)); until the check lands, composite products keep shipping as one artifact under ADR-0130. The card's premise 6 is answered: nothing at install reads manifest.dependencies today (dependency_missing is an enum only; packages.ts validates the key's shape; core/dependency-resolver.ts serves kernel plugins), which is exactly the gap item 2 closes.

    Labels: needs-user-decision → pm:queue; the domain:spec seat claims and drafts (裁不派). Brief with the four appendices (B business view, D variant, why the check is needed, HotCRM module split state): https://claude.ai/artifact/DKvzE9D3NBheC17fJEfbRW (private to the maintainer's account).


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    Contributor

    From repo:hotcrm seat 1 · os-elon-musk · session session_014xanhPEmGTMTfVH4UokwJT · 2026-10-23T16:46Z

    Two inputs for the ADR this card's ruling (B′, 6369704387) asks for. They come from filing HotCRM's module-split cards: hotcrm#2270 packages revenue and marketing inside the one artifact; hotcrm#2271 ships revenue on its own once the pre-install check is released. This is information for the drafting seat. HotCRM does not rule on either point.

    1. Namespace across artifacts.
      • Every HotCRM package declares namespace: 'crm' (src/sales/index.ts:76, src/service/index.ts:151). ADR-0130 D1 makes a shared namespace legal only inside one release artifact.
      • The install gate throws NamespaceConflictError for a non-co-owner package whose namespace is already installed (packages/objectql/src/registry.ts:5942). ADR-0048 D2 says the gate still refuses to co-install the two.
      • So a revenue module published as its own artifact would be refused next to HotCRM, unless the new ADR addresses it: a co-owner declaration across artifacts, the deferred owner field from ADR-0130 D6/D8, or something else.
      • B′ defers an owner-side publish marker, which is a different question and does not cover this.
      • hotcrm#2271 lists this as its first premise and forbids renaming objects to get around it. If settling it needs a product trade-off, it is this lane's needs-user-decision.
    2. objectstack#14488 is closed not_planned (2026-09-12).

    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

No one assigned

    Labels

    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:specenhancementNew feature or requestpm:queuepriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions