feat(ql3): establish 3.0 incubation baseline

This commit is contained in:
whyour
2026-08-12 00:25:26 +08:00
parent 4bf92dcfeb
commit c699c32461
2817 changed files with 779642 additions and 653 deletions
@@ -0,0 +1,130 @@
# ADR-0040Profile 激活顺序与 Edge 导入隔离
- 状态:Proposed
- 日期:2026-07-19
- 关联:QL-RFC-0001、ADR-0036、ADR-0038、ADR-0039
## 上下文
独立 migration stream、schema readiness 和独立 cluster package 仍不能单独证明部署安全。两个装配错误会直接破坏 Profile 边界:
1. cluster-control 在 readiness 前创建 Repository、启动恢复 timer 或注册 admission
2. edge 虽然不执行 cluster 路径,但根 importer 或启动导入闭包仍安装、解析或加载 PostgreSQL/Drizzle bundle。
前者会让不兼容 schema 或过度授权 role 在 fail-closed 之前产生业务副作用;后者会让低性能路由设备承担无用的安装体积、native/供应链风险和启动内存。仅使用动态 `import()` 只能推迟模块求值,不能从 edge lockfile、镜像或安装树中移除依赖。
## 决策
### 1. Cluster-control 只有一个有序激活门
cluster-control 的启动顺序固定为:
1. 明确启用且 Profile 精确为 `cluster-control`
2. 执行 ADR-0039 的只读 readiness
3. readiness 成功后才创建业务 Repository 和 runtime stack
4. 先执行有界 startup recovery,并证明 `safe=true``remaining=0``failed=0`
5. 再启动 claim、recovery 等 lifecycle
6. 最后安装 admission,使 API、scheduler 或其他 producer 可以提交新工作。
禁用时不得查询数据库、创建 stack、启动 timer 或安装 admission。错误 Profile 必须在数据库探测前拒绝。readiness 成功不是自动接管信号,只有完整顺序全部完成后状态才是 active。
### 2. 失败与停止采用反向撤销
stack 创建后的任一步失败都必须:
1. 撤销已安装 admission
2. 有界停止已创建的 lifecycle/stack
3. 写低敏失败审计;
4. 保留原始激活错误,不用 cleanup 或 audit 错误覆盖根因。
正常停止同样先关闭 admission,再停止 stack。停止必须幂等;重复调用共享同一个停止结果。`installAdmission()` 必须自身具备原子安装或失败回滚语义,不能抛错后留下不可撤销的半注册入口。
数据库资源由外层 lazy bootstrap 管理:只有已启用且 Profile 为 `cluster-control` 时才调用 `openDatabase()`。readiness、assembly 或 activation 任一步失败,都在保留原错误后关闭数据库;active shutdown 必须先完成 admission/stack stop,再关闭 Pool。Pool close 失败不得跳过 stack stop,重复 stop/close 共享同一 Promise。
### 3. Readiness evidence 只授权本次装配
Repository factory 接收本次 readiness evidence,用于绑定 contract name/version、PostgreSQL major 和 migration IDs。evidence 不是永久缓存,也不能跨数据库、凭据或进程复用。连接重建、role 变化或数据库 failover 后,实际 production adapter 必须按运维策略重新证明 readiness;不得用旧 evidence 绕过检查。
### 4. Edge 根 importer 不得声明 cluster 依赖
edge/standalone 共用的根 `package.json` 在以下区段都不得声明 `pg``pg-native``drizzle-orm``drizzle-kit``@types/pg` 或 cluster package
- `dependencies`
- `devDependencies`
- `optionalDependencies`
- `peerDependencies`
PostgreSQL driver、Drizzle schema/tooling 和 cluster-control assembly 只属于 ADR-0038 定义的独立 workspace/package 与 profile-specific 产物。根包的 dynamic import、optional dependency 或 install-time feature detection 均不能替代该边界。
### 5. Edge CI 同时审计 manifest 与代表性导入闭包
CI 必须在 edge Profile 下导入代表性的:
- Profile/resource policy
- standalone/manual Primary 的轻量 bootstrap
- headless Worker application runtime。
新增模块闭包不得包含 PostgreSQL migration 实现、`pg``pg-native`、Drizzle 或 cluster package。该门禁用于尽早发现静态 value import、barrel re-export 和 bootstrap 回归;它不等同于最终产物证明。独立 importer 落地后,还必须对 edge package tarball/镜像的 lockfile、安装树、SBOM、压缩体积与冷启动 RSS 做闭环审计。
## 当前孵化状态
`next` 已实现默认不可达的 `activateClusterControlRuntime()`
- 错误 Profile 在 readiness 前拒绝;
- readiness 失败前不会调用业务 factory;
- 成功路径固定 readiness → assembly → recovery → lifecycle → admission
- unsafe/incomplete recovery 会停止 stack,且不会开放 admission
- admission-first shutdown 和重复 stop 已有契约测试。
独立 `@qinglong/cluster-control``bootstrapClusterControlRuntime()` 已把 lazy database、ADR-0039 readiness、ADR-0041 Run Repository 与激活门串联:disabled/错误 Profile 零打开,readiness 通过后才创建真实 `PostgresRunRepository` 和业务 stack,失败自动关闭,正常关闭顺序固定为 admission → stack → Pool。真实 `openDatabase()``@qinglong/cluster-postgres` 提供,组合根不读取 legacy `back/**`
同时已加入 `audit:edge-imports:ql3`
- 检查根 manifest 的四类依赖区段;
- 导入三个代表性 edge/standalone/worker 入口;
- 检查新增 `require.cache` 闭包是否触达 cluster bundle
- 纳入 Node 20/24、x64/arm64 的 QL3 CI 矩阵。
ADR-0045 已在独立 package 增加有界 HTTP application host、`/livez`、activation-backed `/readyz` 和 fail-closed `/api/v3` admission,并把 disposer 升级为可异步 drain:停止先拒绝新请求、向在途 handler 传播 Abort,真实 handler 未结束时不能继续宣称排空。公开 config 入口先解析 Profile/enable,禁用时不读取 PostgreSQL Secretapplication/config 导入闭包不含 migration DDL 或 legacy 根。
当前仍没有认证/Policy-fenced 业务 router、完整 production recovery/lifecycle stack、独立 cluster 镜像/SBOM 或 failover 演练。现有 host 是 executable application boundary,但尚不是完整可部署控制面,不能据此开启匿名或生产 cluster-control API。
## 影响
正面影响:
- schema/role 不兼容时不会提前构造可产生业务副作用的对象;
- startup recovery 与新流量之间存在可测试的硬顺序;
- edge 对 cluster 依赖的隔离从文档约束变为 CI 约束;
- 正常停止、部分启动失败和重复停止具有同一 ownership 语义。
代价与风险:
- 新 lifecycle 必须接入统一 stack,不能自行在模块加载时启动;
- readiness catalog 扫描会增加一次启动成本,需要 timeout、节流与重新证明策略;
- 代表性 CommonJS 导入审计无法发现所有 bundler、ESM tree 或容器打包错误;
- 独立 workspace 落地后,CI 还需同时证明 cluster 产物包含依赖、edge 产物排除依赖。
## 未选择的方案
1. **Repository 创建后再做 readiness**constructor、pool hook 或 timer 已可能产生副作用,拒绝。
2. **recovery 与 admission 并行启动**:新工作会扩大未收敛状态,拒绝。
3. **readiness 失败后回退 SQLite**:形成双事实源并违反 Profile 边界,拒绝。
4. **只依靠 dynamic import**:不能降低安装体积或供应链暴露,拒绝。
5. **只检查根 package.json**:无法发现 barrel/value import 回归,拒绝。
6. **只检查运行时 require cache**:无法证明未加载包不存在于 edge 产物,拒绝。
## 验证要求
- disabled 路径无数据库、factory、timer 和 admission 行为;
- disabled/错误 Profile 不调用 `openDatabase()`,也不触发 driver dynamic import
-`cluster-control` Profile 在数据库探测前失败;
- readiness 失败保持原错误,且业务 factory 调用次数为零;
- recovery unsafe、remaining 或 failed 非零时不得启动 lifecycle/admission
- lifecycle 启动失败或 admission 安装失败会反向清理;
- active stop 先同步切换 not-ready/拒绝新 admission,再异步等待在途 handler 结束,之后才停止 stackdrain timeout 显式失败且重复 stop 幂等;
- readiness/assembly/activation 失败关闭数据库;active stop 在 stack 后关闭 Poolclose 失败不覆盖更早的激活/停止错误;
- edge 根 manifest 出现任一禁止依赖时 CI 失败;
- 代表性导入闭包触达 PostgreSQL/Drizzle/cluster 路径时 CI 失败;
- 独立 package 落地后,edge tarball/镜像的 lockfile、SBOM 和安装树不包含 cluster bundle
- PostgreSQL 16/18 role integration 通过后,才允许真实 cluster factory 接入激活门。