Part of #14122 · ADR-0130 D4/D5/D7 的产出侧 。发版前平台侧最后一块:维护者要在平台功能齐全后发版,hotcrm 分拆(epic 的业务目标)在本卡之前无法开始。
事实(都在 main 上实测) 决定(维护者 2026-09-02 在 PM 会话拍板) #14242 取 B :给装配/注册态的包体一个独立声明 ;作者态 ManifestSchema.objects不加宽 (否决 C);A 的"只声明 wrapper 门"作为过渡状态随本卡终止。
要做 spec :声明装配后的包体 schema(命名由 dev 提,如 AssembledPackageBodySchema):manifest 字段 + 与 ObjectStackDefinitionSchema 相同的定义数组键(objects / apps / flows / …,键集从同一处派生,不手抄)。发布物层的 packages[] 引用它;作者态入口仍是 ArtifactPackageEntrySchema(manifest-only)。装载门从 wrapper-only 改为对装配态声明完整 parse ,artifact-packages.ts 模块头里对错配的记录同步改写。作者态形状,不发明第二种写法 :一个项目 = N 个各自合法的 defineStack(每个仍受 ADR-0019 单应用约束)+ 一个项目级 config 调 composeStacks([...], { manifest: 'preserve' })。⛔ 不放宽 validateSingleApp:组合后的项目物按 packages[] 迭代,单包路径一字不动。CLI os build / compile :loadConfig 得到的定义带 packages[] 时,对每个包 分别走今天单包的校验 / lint / lower 路径(同一套函数,不复制一份),产出一个 发布物 JSON,packages[i] 为装配后包体;os dev 同样能起它。单包输出 bit-identical (D7 pin 已有,必须保持绿)。夹具 :examples/app-multi-package/(名字 dev 定):两个包共享一个命名空间,一个 type:'app'、一个 type:'module'(无 scope 键),各一个对象,模块对象 lookup 到应用对象;pnpm build 出 packages[];dogfood 测试起服务,断言 GET /api/v1/packages 两行(feat(packages): GET /packages and GET /packages/:id rows carry the server's own writable verdict (isWritablePackage) #14430 合并后追加 writable: false 两行断言)。文档 :作者态页(content/docs/plugins/packages.mdx 或 dev 判定的正确页)加一节"项目 = 多包发布物",⛔ 不碰 content/docs/releases/。消融 :删 CLI 的 packages[] 分支 → 夹具构建断言红;删装配态 schema 门 → 错形包体不再被拒(各自预测红集、复原按字节、经 dist 的腿要重建并 preflight)。边界 ⛔ 不动 marketplace / 安装面(ADR-0019 D2/D3,发布物停在控制面)。⛔ 不做跨发布物共有权(ADR-0130 D8)。⛔ ManifestSchema.objects 不加宽。⛔ 不改 ADR;若 ADR-0130 需要补记 D4 的两阶段声明,另开 docs-only 卡给维护者。
Clause-② 预期 YES :编译的接受 / 拒绝面变了(新的装配态 schema 门、CLI 新分支、装载门从 wrapper 变完整 parse)→ 挂 needs:contract-review,PR 留 draft,PM 复审。
验收 夹具 build + boot 全绿并留 GET /api/v1/packages 原文;D7 单包 bit-identity pin 绿;packages/spec、packages/cli、packages/objectql 全量绿;dispatch-gates 联合零发现;PR 同时 Fixes #14242。changeset:@objectstack/spec minor、@objectstack/cli minor、@objectstack/objectql patch。
Part of #14122 · ADR-0130 D4/D5/D7 的产出侧。发版前平台侧最后一块:维护者要在平台功能齐全后发版,hotcrm 分拆(epic 的业务目标)在本卡之前无法开始。
事实(都在
main上实测)packages[](ADR-0130 D4) #14191(packages[]schema)、feat(spec): composeStacks gainsmanifest: 'preserve'— N package identities survive composition (ADR-0130 row 3) #14223(composeStacksmanifest:'preserve')、ADR-0130 D5+D7: register an artifact's N packages in topological order, reusing resolvePluginOrder #14240(拓扑装载)、feat(objectql): admit same-artifact co-owners at the install gate, and refuse two of them defining one object name (ADR-0130 D1+D3) #14354(D1+D3 闸)都在main。packages[]形态的发布物:packages/cli/src/commands/compile.ts(build.ts只是它的别名)对artifact.packages零处理(git grep '\.packages\b' packages/cli/src packages/core/src非测试零命中);examples/下四个例子全是单包;ArtifactPackageEntrySchema's body half cannot describe the payload the load path actually registers #14242 原文:"Nopackages[]-shaped artifact is produced anywhere yet"。objectstack.config.ts:90-190是一个defineStack({ manifest: { id, namespace: 'crm', type: 'app' }, objects: Object.values(objects), apps, flows, … })——定义体直接 import,不是 glob。CLI 侧:loadConfig(packages/cli/src/utils/config.ts)→ 校验 / lint / lower →buildRuntimeBundle(utils/build-runtime.ts)。ArtifactPackageEntrySchema.manifest = ManifestSchema,其objects是z.array(z.string())(作者态 glob);而装载侧resolveArtifactPackageOrder(packages/objectql/src/artifact-packages.ts)把每个packages[i].manifest交给ObjectQL.registerApp,后者把m.objects当定义体迭代。ADR-0130 D5+D7: register an artifact's N packages in topological order, reusing resolvePluginOrder #14240 因此只把 schema 当 wrapper 门用,并在模块头记录了这个错配。validateSingleApp(stack.zod.ts:948,在:1854由defineStack调用)对type:'app'强制单应用(ADR-0019)。composeStacks在stack.zod.ts:2451,'preserve'语义见:1907-1946。决定(维护者 2026-09-02 在 PM 会话拍板)
#14242 取 B:给装配/注册态的包体一个独立声明;作者态
ManifestSchema.objects不加宽(否决 C);A 的"只声明 wrapper 门"作为过渡状态随本卡终止。要做
AssembledPackageBodySchema):manifest 字段 + 与ObjectStackDefinitionSchema相同的定义数组键(objects/apps/flows/ …,键集从同一处派生,不手抄)。发布物层的packages[]引用它;作者态入口仍是ArtifactPackageEntrySchema(manifest-only)。装载门从 wrapper-only 改为对装配态声明完整 parse,artifact-packages.ts模块头里对错配的记录同步改写。defineStack(每个仍受 ADR-0019 单应用约束)+ 一个项目级 config 调composeStacks([...], { manifest: 'preserve' })。⛔ 不放宽validateSingleApp:组合后的项目物按packages[]迭代,单包路径一字不动。os build/compile:loadConfig得到的定义带packages[]时,对每个包分别走今天单包的校验 / lint / lower 路径(同一套函数,不复制一份),产出一个发布物 JSON,packages[i]为装配后包体;os dev同样能起它。单包输出 bit-identical(D7 pin 已有,必须保持绿)。examples/app-multi-package/(名字 dev 定):两个包共享一个命名空间,一个type:'app'、一个type:'module'(无scope键),各一个对象,模块对象 lookup 到应用对象;pnpm build出packages[];dogfood 测试起服务,断言GET /api/v1/packages两行(feat(packages): GET /packages and GET /packages/:id rows carry the server's own writable verdict (isWritablePackage) #14430 合并后追加writable: false两行断言)。content/docs/plugins/packages.mdx或 dev 判定的正确页)加一节"项目 = 多包发布物",⛔ 不碰content/docs/releases/。packages[]分支 → 夹具构建断言红;删装配态 schema 门 → 错形包体不再被拒(各自预测红集、复原按字节、经dist的腿要重建并 preflight)。边界
⛔ 不动 marketplace / 安装面(ADR-0019 D2/D3,发布物停在控制面)。⛔ 不做跨发布物共有权(ADR-0130 D8)。⛔
ManifestSchema.objects不加宽。⛔ 不改 ADR;若 ADR-0130 需要补记 D4 的两阶段声明,另开 docs-only 卡给维护者。Clause-②
预期 YES:编译的接受 / 拒绝面变了(新的装配态 schema 门、CLI 新分支、装载门从 wrapper 变完整 parse)→ 挂
needs:contract-review,PR 留 draft,PM 复审。验收
夹具 build + boot 全绿并留
GET /api/v1/packages原文;D7 单包 bit-identity pin 绿;packages/spec、packages/cli、packages/objectql全量绿;dispatch-gates联合零发现;PR 同时Fixes #14242。changeset:@objectstack/specminor、@objectstack/climinor、@objectstack/objectqlpatch。