Files
qinglong/docs/adr/ADR-0267-machine-verifiable-workspace-package-boundary-ledger.md
T

6.2 KiB
Raw Blame History

ADR-0267:机器可验证的 Workspace Package 边界账本

  • 状态:Accepted
  • 日期:2026-08-03
  • 关联:RFC D-02、D-06、D-85、D-207、D-240、D-248ADR-0087、ADR-0185、ADR-0217、ADR-0243

背景

QingLong 3.0 已从 32 个 workspace package 逐步收敛为 19 个。当前仍有一个只有单个 TypeScript 源文件的 local-command-file,以及三个文件的 local-profilelocal-adopted-profile。文件数只能触发评审,不能回答 package 是否合理:机械合并 adopted profile 会让基础 Edge 路由器安装 local-admin 接管写栅栏;机械保留所有概念包 又会继续扩大 lockfile、构建、SBOM 和维护面。

此前保留理由主要散落在多份 ADR 和审计脚本的 hard-coded allowlist 中。它们可以发现 依赖变化,却不能直接回答“新增或保留这个 package 的独立价值是什么”,也不能阻止新增 一个没有部署、权限、依赖隔离、适配器或共享价值的薄包。

决策

  1. docs/ql3-package-boundaries.json 是 QL3 workspace package 边界的唯一机器可读决策账本。 它精确登记当前 19 个 package 的路径、名称、生产消费者、Profile、保留条件与理由。
  2. 每个 package 至少证明以下一项:独立 deployable/binary/artifact、独立 authority、 外部生产依赖隔离、可替换 adapter,或至少两个 production consumer 复用的 shared leaf。
  3. 一文件 package 必须额外证明 deployable、authority 或 shared leaf;“代码以后可能增加” 和“概念名称不同”都不构成理由。
  4. 账本 schema v2 必须精确登记每个 src/ 根文件及其职责,且只允许 public_exportbinary_entryshared_infrastructure。前两类必须由 manifest 的 exports/main/bin 直接证明;共享基础设施不得冒充公开入口,并且只允许存在于已经按领域 下沉、有具体保留理由的 package。
  5. 全部源码仍位于 src/ 根层的 package 必须声明 shallowSourceLayoutpublic_entrypoints 只适用于独立 deployable/artifact 的公开产品入口;shared_protocol 必须同时证明 shared leaf、 至少两个 production consumer、零生产依赖。package 一旦出现嵌套实现,旧浅层例外立即视为 stale。
  6. scripts/ql3-package-boundary-audit.cjs 从实际 manifest 反向计算生产消费者、源码体量、根文件集合 和 manifest target,拒绝未登记或已消失的 package、消费者/根职责漂移、伪造入口、缺失或过期 浅层证据、未知 workspace dependency、以及超过 19 的 hard cap。
  7. 账本不替代 dependency/source/artifact/RSS 审计。package 数不是运行性能指标;低配设备 仍以最终 artifact closure、loaded modules、RSS、I/O 和常驻资源为准。

当前裁决

  • local-command-file 继续保留:它零生产依赖,被 application、Owner CLI 和 maintenance 三个不同生命周期闭包直接复用;合入任一 owner 都会迫使其他消费者携带更大的闭包。
  • local-profilelocal-adopted-profile 继续分包:后者独占 legacy source write fence 和 local-admin 依赖,并形成独立 adopted artifact;合并会扩大 storage-only 路由器制品。
  • runtime-corelocal-sqlitecluster-postgres 等大包不因 LOC 再拆 workspace package 领域内聚继续使用目录和显式 subpath,避免重现“一概念一 package”。

后续实施计划:包内源码拓扑收敛

该工作排在 CloudNativePG/Barman continuous WAL、latest restore、PITR 与 cert-manager 证书 轮换实证之后,避免大规模文件移动干扰当前生产灾备 Gate。它只整理 package 内部物理布局, 不改变本 ADR 接受的 workspace 边界。

  • 首批评审 runtime-corecluster-adminaicluster-controllocal-sqlitecluster-postgresworker-runtime;小型且单一职责的 package 保持平铺。
  • 以稳定业务能力建立目录,不以 class/interface/单文件建立目录,也不因目录形成新的 workspace package。
  • 外部 package.json#exports subpath、消费者 import、依赖树、部署 Profile、数据库 role、 migration 顺序和最终 artifact closure 必须保持兼容。
  • SQLite/PostgreSQL adapter 的领域目录尽量与 runtime-core port 对齐;管理包内部将同一能力的 CLI、HTTP、transport、client、process 和 Kubernetes adapter 放在同一能力目录。
  • 每次只处理一个 package,并先使用 GitNexus 评估 upstream blast radius;移动后必须通过该包 contract、dependency/source boundary、packlist/artifact、Edge import/RSS 与全量回归。
  • 若整理需要改变公共 API、authority、依赖、schema、运行资源或第 20 个 workspace package 必须停止并另立 ADR,不能伪装成目录重构。

验证

  • 当前 workspace 精确 19 个 package,账本与实际目录一一对应;
  • 实际 manifest 反向计算的所有 production consumer 与账本一致;
  • 唯一一文件 package 是 @qinglong/local-command-file,并满足三个 production consumer 的 shared-leaf 证明;
  • local-command-filelocal-profilelocal-adopted-profile 是显式浅层源码例外;前者为 shared_protocol,后两者为 public_entrypoints
  • 测试覆盖未登记 package、stale decision、consumer drift、根文件增长/角色漂移、伪造 binary、 缺失/过期/证据不足的浅层例外和无理由薄包的失败关闭;
  • 该变更不新增 workspace package、生产依赖、运行进程、listener、timer、数据库连接或 任何 Edge/Standalone/Cluster/Worker 制品内容。

不采用方案

合并 local-profilelocal-adopted-profile

拒绝。npm production dependency 是 package 级,不是 subpath 级;基础 storage-only Profile 会因此安装接管管理 authority,与低配设备最小闭包目标相反。

按 LOC 或文件数自动合并

拒绝。文件数看不到 deployment、credential、database role、destructive authority 或 第三方依赖边界。

只保留文档约定

拒绝。没有与实际 manifest/consumer graph 对账的 prose 会在后续依赖变更时静默失真。