Files
qinglong/docs/adr/ADR-0366-thin-package-boundary-ratchet.md
T

3.1 KiB
Raw Blame History

ADR-0366:薄 Package 边界 Ratchet

  • 状态:Accepted
  • 日期:2026-08-11
  • 关联:QL-RFC-0001 D-175、D-207、D-257、D-269、D-276、D-278ADR-0364

背景

Package 边界和 package 内目录边界不能混为一谈。把多个领域实现平铺在 src/ 根层会模糊 ownership;反过来,仅因文件少或目录整齐就建立 workspace package,也会增加 importer、manifest、lockfile、SBOM、构建和低配设备制品成本。

当前 17 个 QL3 package 共 1,006 个 TypeScript source,其中 989 个位于 capability/domain 子目录,src/ 根层 17 个文件全部是 manifest 证明的 public export 或 binary entry。唯一只有两个 source 的 package 是 @qinglong/local-command-file:一个 8 行公开入口和一个 161 行私有 command-file 安全协议实现。

决策

  1. src/ 根层继续只允许受审 public export 或 binary entry;实现按 capability/domain 下沉,不以 workspace package 代替目录。
  2. 薄 package 的自动复审范围从恰好 1 个 source 收紧为 1–2 个 source。它必须至少证明以下一项真实边界:
    • 独立部署制品;
    • 独立 authority
    • 被多个生产生命周期复用的稳定共享叶子。
  3. dependency_isolationreplaceable_adapter 本身不足以证明 1–2 文件 package;没有独立制品、authority 或共享消费者时,优先并入 owner package 并使用显式 subpath。
  4. 文件数只触发复审,不自动决定合并。达到 3 个 source 也不能规避 package 的既有 deployment/authority/dependency/consumer 账本。
  5. 保留 @qinglong/local-command-file。它被 Local Application、Local MCP、Local Owner CLI 和 Local Maintenance 四个不同生命周期制品使用,且集中维护 lstat → O_NOFOLLOW open → fstat、UID/mode/size/inode 复验和输入清零。合入任一 consumer 会复制安全协议,或迫使其他低权限/短生命周期制品依赖更高权限产品包。
  6. 未来本机 HTTP、AI adapter、projection、codec 或单一命令不得仅因“看起来独立”新增 package;只有独立 listener/deployment、authority、重依赖隔离或稳定多消费者 contract 能通过同一账本评审。

机器门禁

scripts/ql3-package-boundary-audit.cjs 对 12 source package 执行相同的 thin-package criteria 校验。反向 fixture 使用两文件、仅声明 replaceable adapter 的 package,必须返回 PACKAGE_BOUNDARY_THIN_PACKAGE_UNJUSTIFIED;当前 workspace 仍为 17/17、findings=[]

该门只在开发、CI 和发布检查运行,不进入 Edge、Standalone、Worker 或 Cluster 制品,不增加运行时依赖、进程、listener、timer、内存或闪存写入。

后果

  • src 平铺通过领域目录治理,workspace 碎片通过薄包证据治理,两套规则互不替代。
  • 小而安全、确有多消费者的叶子可以保留;单消费者 helper、adapter、projection 默认回到 owner package。
  • 新增 Local HTTP 产品面时,必须先证明真实部署与 authority 边界,不能把路由文件直接升级成第 18 个 package。