Files
qinglong/docs/adr/ADR-0106-profile-entrypoint-subpath-consolidation.md

64 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-0106Profile 构建入口 Subpath 收敛
- 状态:Accepted
- 日期:2026-07-22
- 关联 RFCQL-RFC-0001 D-05、D-14、D-35、D-40、D-62、D-85、D-86、D-89、D-105
- 关联 ADRADR-0042、ADR-0062、ADR-0063、ADR-0087、ADR-0090
- SupersedesADR-0087 中“每个 Profile 构建目标必须保留独立 workspace package”的局部决策
## 上下文
ADR-0087 已把 package-per-use-case 的 32 个 importer 收敛为 27 个,但仍保留四个只有单一入口的 Profile wrapper`@qinglong/edge``@qinglong/standalone``@qinglong/edge-adopted``@qinglong/standalone-adopted`
当前实现证明这四个 wrapper 没有独立 `bin`、platform/engine/native/第三方依赖、版本责任或生产调用方。基础 Edge/Standalone 都只依赖 `@qinglong/local-profile`,接管变体都只依赖 `@qinglong/local-adopted-profile`;每个入口仅把调用参数中的 `profile` 固定为 `edge``standalone`。它们是不同制品的构建目标,但不是不同依赖或权限边界。
继续把“制品名称”等同于“workspace package”会增加 manifest、lockfile importer、拓扑 build、漏洞 allowlist 和贡献者认知成本,也使 D-85 的“独立制品”条件过于容易被空 wrapper 满足。反过来,合并 `local-profile``local-adopted-profile` 会让普通 Edge 安装接管写栅栏和 local-admin 依赖,仍然不可接受。
## 决策
1. 删除四个 wrapper package,把固定 Profile 的入口迁入既有 package 的精确 subpath
- `@qinglong/local-profile/edge`
- `@qinglong/local-profile/standalone`
- `@qinglong/local-adopted-profile/edge`
- `@qinglong/local-adopted-profile/standalone`
2. `@qinglong/local-profile``@qinglong/local-adopted-profile` 的根入口继续保留现有通用组合 contract;根入口不聚合导出四个固定入口,制品审计必须显式 require 对应 subpath。
3. Edge、Standalone、Edge-adopted、Standalone-adopted 继续是四种独立 Deployment Profile 和制品门禁,但制品构建清单以“package 集合 + entry specifier”表达,不再要求 entry specifier 自己拥有 package manifest。
4. `local-profile``local-adopted-profile` 继续物理分包。后者独占 `local-admin/runtime` 接管写栅栏依赖,基础 Profile 的 production closure 不得安装 local-admin。
5. importer registry、lockfile、production vulnerability allowlist 与拓扑构建 hard cap 从 27 收紧为 23。已删除的四个 package 名仍作为禁止依赖保留在 source/root boundary tombstone 中,防止空 wrapper 被静默重新引入。
6. 以后只有当 Edge 与 Standalone 出现真实不同的 platform/native/第三方依赖、独立安装权限或发布节奏时,才能通过新 ADR 恢复独立 package。仅有不同配置值、制品标签或审计名称不满足 D-85。
## 被否决的替代方案
1. **继续保留四个 package 作为审计根**:构建目标可由精确 subpath 表达,空 wrapper 不应成为 package 边界,拒绝。
2. **把四个 wrapper 合成一个新 package**:仍然新增无独立依赖责任的中间 manifest,并会让基础与接管依赖方向难以表达,拒绝。
3. **合并 `local-profile` 与 `local-adopted-profile`**:会让基础 Edge/Standalone 的安装闭包取得接管与 local-admin 能力,拒绝。
4. **删除固定入口,直接让制品传任意 `profile` 字符串**:失去静态构建入口与错误配置防护,拒绝。
5. **按 LOC 自动合并其他单文件安全包**`local-command-file``local-identity``local-secret-admin` 分别拥有复用、安全或权限排除边界,文件数不是裁决标准,拒绝。
## 验收证据
1. GitNexus 对四个旧 bootstrap symbol 的 upstream impact 均为 LOW0 direct caller、0 execution flow;迁移风险集中在 exports、制品和审计配置。
2. 干净 `dist` 上根级拓扑构建精确执行 23 个 package,全部通过;`local-profile` 的 Edge/Standalone subpath 与 `local-adopted-profile` 的两个接管 subpath 行为测试共 4 项通过,两个 package 完整测试为 12/12。
3. dependency/source boundary 报告登记 23 个 importer、280 个 TypeScript source file、`findings=[]`Edge import audit 无 forbidden dependency/import。
4. 六种实际 `pnpm pack → offline install → require` 制品均通过 4 MiB、512 files、16 MiB RSS 门禁:
| Profile | Packages | Bytes | Files | Loaded modules | RSS delta sample |
| --- | ---: | ---: | ---: | ---: | ---: |
| edge | 4 | 1,662,386 | 238 | 37 | 9,109,504 |
| standalone | 4 | 1,662,434 | 238 | 37 | 9,109,504 |
| edge-adopted | 6 | 1,898,370 | 266 | 40 | 10,403,840 |
| standalone-adopted | 6 | 1,898,442 | 266 | 40 | 10,584,064 |
| edge-application | 10 | 2,211,411 | 337 | 70 | 12,206,080 |
| standalone-application | 10 | 2,211,531 | 337 | 70 | 12,288,000 |
RSS 是本机单次抽样,只证明未超过硬门禁,不用于宣称跨次性能提升。Profile package 数量包含 `croner`;基础制品仍不含 local-admin、PostgreSQL、Drizzle、Sequelize 或 sqlite3。
## 后续约束
package 数量不是路由设备性能指标。后续仍以实际 production tarball 的 bytes/files、
import closure、RSS、连接/timer 数和物理设备证据裁决资源兼容性。ADR-0218 已完成此前
要求的 Cron provider 评审:`runtime-core` 只保留显式 port,真实 Croner adapter
归现有 `local-execution`/`cluster-control` 部署 owner,基础/adopted-only 制品排除
Croner,且没有新增 package。新的六 Profile 物理 bytes/files/RSS 仍必须在锁定依赖
物化后重跑,不能用 manifest 变化代替实测。