Files
qinglong/docs/adr/ADR-0044-runtime-core-extraction-and-legacy-compatibility-exit.md

95 lines
6.0 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-0044Runtime Core 抽离与 Legacy 兼容副本退出
- 状态:Proposed
- 日期:2026-07-19
- 关联:QL-RFC-0001 D-40/D-42、ADR-0037、ADR-0040、ADR-0041、ADR-0042
## 上下文
QingLong 2.x 的根应用同时承载 Controller、Sequelize、SQLite、本机执行、Web UI 和正在孵化的 3.0 Runtime。若 cluster package 直接读取 `back/**`,新的 package 名称不会改变依赖方向,2.x 根应用仍会成为事实上的 service locator。反之,立即把全部旧调用者切到新 package,会一次触碰高风险的 Cron、App 启动和 migration 链,难以维持现有兼容性。
抽离期间还会出现 JavaScript 类型身份问题:源码相同的 Error class 在 legacy 根和 runtime-core package 中是两个 constructor。若共享 contract 固定引用其中一方,另一方会因为 `instanceof` 身份而伪失败,即使 wire code 和语义完全一致。
## 决策
### 1. 按 Vertical Slice 抽离,不做目录大搬迁
抽离顺序固定为:
1. 纯 domain、port、稳定错误和 migration/activation contract
2. 具体数据库 driver、SQL adapter 和 catalog readiness
3. Profile composition root
4. 完整 application stack 与发布产物;
5. legacy 调用者经兼容 adapter 切换,随后删除副本。
每个 slice 必须独立 build/test,且新 package 不得 deep import legacy 根。没有真实 consumer 的 placeholder export 不算完成抽离。
### 2. 兼容副本是临时迁移机制
legacy 根可以暂留 migration、activation 和 Repository 副本,以保护 2.x 调用链;但必须满足:
- 新实现的权威位置是公开 package;
- cluster integration 只测试 package 实现;
- 共享行为由 contract suite 或等价 parity test 覆盖;
- 禁止继续向根副本新增仅供 3.0 使用的能力;
- RFC 明确记录剩余调用者、切换门禁和删除条件。
### 3. Contract 不绑定实现侧 Constructor Identity
共享 Repository contract 允许 adapter 注入稳定错误 constructor 和资源上限常量。legacy adapter 使用根兼容 export3.0 adapter 使用 runtime-core export;断言相同 error code、行为和边界,而不是要求两个 module instance 是同一个对象。
这不允许随意替换错误语义。公开错误 code、分页上限、payload 上限和 CAS 行为仍是 contract 的一部分。
### 4. 旧调用链切换必须满足退出门禁
只有以下条件全部满足,才允许把 legacy 根的高风险调用者切向 package:
- edge/standalone 与 cluster-control 各自有独立 Profile artifact/entrypoint
- SQLite 与 PostgreSQL 通过同一完整 contract
- migration history、checksum 和既有日志/错误兼容已证明;
- Node 24、多架构、升级和回滚测试通过;
- GitNexus impact 对每个被切换入口重新评估并审阅;
- 切换后依赖/导入审计证明没有反向边或双实现调用。
删除兼容副本应在独立变更中完成,不能与首次生产启用、schema 升级或 release history rewrite 混在同一提交。
## 当前孵化状态
`@qinglong/runtime-core` 已独立导出 migration stream/manifest、cluster activation、异步 admission disposer、Run/RetryPolicy domain、Repository port、稳定错误和 PostgreSQL resource shape,并新增细粒度 `migration-stream`/`run-repository` 子入口,避免本机 importer 求值整个 cluster barrel`@qinglong/cluster-postgres` 已独立实现 migration、readiness、typed schema、Pool 与 RunRepository,并用受限 `runtime`/`migration` export 隔离常驻代码与 executable DDL`@qinglong/cluster-control` 已在 readiness 后创建真实 Repository 并持有 Pool 生命周期,并通过独立 `application`/`http`/`config` export 提供不读取 legacy 或 DDL 的有界启动 host。
ADR-0063 进一步抽出 `@qinglong/local-sqlite``@qinglong/local-profile``@qinglong/edge``@qinglong/standalone`。SQLite 与 PostgreSQL 已运行同一 RunRepository contractedge/standalone 的真实 production tarball closure 不再包含 legacy/cluster/ORM/native driver,常驻 SQLite runtime 也不会加载 executable migration SQL。以上 package 均可严格构建且不读取 legacy `back/**`
legacy 根副本和调用链目前仍保留。原因是 root `RunRepository` 上游涉及大量 2.x servicehistory auditor 也参与 SQLite migration/App 启动;当前阶段不以新 package 已存在为由直接切换。下一门禁是 2.x database adoption/backup/rollback、完整本机 Profile application stack、真实 PostgreSQL 矩阵成功证据和双方言更多数据域 parity 后,再逐入口迁移。
## 影响
正面影响:
- 新架构不继承 2.x Controller/Sequelize/UI 耦合;
- 小设备与 cluster 可分别安装自己的 importer
- 高风险旧调用链可以在证据完整后逐步切换;
- 双实现风险有明确退出条件,而不是永久兼容借口。
代价与风险:
- 过渡期有重复源码与两套 module identity
- 修复跨越公共契约时可能需要同步兼容副本;
- contract suite 必须覆盖 wire code、边界值和错误语义,不能只验证 happy path。
## 未选择的方案
1. **cluster-control deep import 根 `back/**`**:固化反向依赖,拒绝。
2. **一次性迁移全部 root caller**:爆炸半径过大且难以回滚,拒绝。
3. **永久保留两套实现**:会持续漂移并增加安全修复成本,拒绝。
4. **共享 contract 固定 `instanceof` 根错误类**:让 package 实现产生伪失败,拒绝。
5. **用 symlink 或构建期路径别名隐藏 deep import**:只掩盖依赖图,拒绝。
## 验证
- runtime-core 在无 `pg`、Drizzle、SQLite、Sequelize 和 legacy 根依赖下独立构建;
- cluster-postgres/cluster-control 只使用公开 package export
- exact dependency/source audit 无反向边或 package escape
- legacy SQLite 与 package PostgreSQL 都通过完整 Repository contract
- package-local fake driver 测试覆盖事务、row codec、错误映射和 payload 边界;
- Profile artifact 落地后逐入口记录 impact、parity、切换和兼容副本删除证据。