7.8 KiB
ADR-0137:PostgreSQL Plugin Package 安装仓库与 Project Lock Authority
- 状态:Accepted(PostgreSQL 三表、完整 lock、capability v17、admin-only repository、 SECURITY DEFINER Project lock、跨 adapter 合同与物理 HA 门已完成;通用 activation coordinator、标准 OCI stage verifier、Kubernetes ConfigMap publisher、一次性 admin recovery process、exact-registry credential provider、独立镜像与最小权限 Job/RBAC/真实 Kubernetes 专项门已可组合;Approved Action 产品 consumer 与管理入口仍未开放)
- 日期:2026-07-24
- 关联 RFC:QL-RFC-0001 D-08、D-09、D-127、D-132、D-134、D-135
- 关联 ADR:ADR-0125、ADR-0129、ADR-0134、ADR-0135、ADR-0136
背景
ADR-0136 已让 edge/standalone 通过单 SQLite authority 持久化 Plugin Package installation 历史、当前 head 与 mutation replay,但 cluster 节点仍没有同一 runtime-core contract 的 PostgreSQL adapter。若集群另造状态机,SQLite 与 PostgreSQL 会在 first-create、terminal replacement、旧 mutation replay 和恢复扫描 上逐渐产生不同安全语义。
实现过程中还出现一个 PostgreSQL 特有边界:创建 installation 前必须确认 Project
为 active,并把该事实锁到 transaction 结束。普通 SELECT 不能阻止并发归档;
SELECT ... FOR SHARE 又要求调用角色拥有目标表 UPDATE privilege。仅为了取得行锁就
授予 ql3_admin 通用 Project UPDATE,会扩大数据库权限而不是表达所需能力。
决策
1. Adapter 留在既有 @qinglong/cluster-postgres
Repository 只通过
@qinglong/cluster-postgres/plugin-package-install 显式 subpath 导出,不从 root、
runtime、admin 或 worker-ingress 入口导出,不新增 workspace package和第三方依赖。
它只接受 admin Pool;默认 cluster-control、worker 与 migration composition 都不 加载该 subpath。实现存在不代表产品已暴露安装入口。
2. pg-0018 冻结三类耐久事实
pg-0018-plugin-package-installs 创建:
plugin_package_installs:每个 installation 的不可变lock_json、当前 record 和全 generation 历史;plugin_package_install_heads:每个 Project/Package 的唯一当前 authority;plugin_package_install_mutations:mutation ID/digest 与 resulting record digest。
CHECK、FK、partial recovery index、Project history index 与 mutation result index 同
typed Drizzle schema、SQL migration、migration manifest 和 readiness contract
lockstep。Repository findLock 每次重新规范化并重算 lock digest。PostgreSQL stream
由 exact pg-0017 前驱推进到 18 条 migration、
control-core capability v17、30 张受审表,并发布
"plugin_package_install":1。
runtime 与 worker-ingress 对三表没有任何 table privilege。ql3_admin 对 install/head
只有 SELECT/INSERT/UPDATE,对 mutation ledger 只有 SELECT/INSERT,所有角色均无
DELETE。
3. 用单用途 SECURITY DEFINER 表达 Project 锁能力
migration 创建
ql3.lock_active_plugin_package_project(varchar) -> boolean。函数:
- owner 固定为
ql3_migration; - 使用
SECURITY DEFINER和固定search_path=pg_catalog, ql3; - 以
FOR SHARE读取目标 Project,锁住 concurrent status update/delete; - 只返回 active 与否,不返回 Project 数据;
- 撤销 PUBLIC 默认 EXECUTE,只授予
ql3_admin; - runtime、worker-ingress 均不得执行,admin 也不因此获得 Project UPDATE。
readiness 对函数 name/signature、owner、security-definer、volatility、search path、 PUBLIC ACL 及当前角色 EXECUTE 权限进行 exact 审计。未知 ql3 function、owner 漂移、 PUBLIC execute 或角色越权都使 activation 失败关闭。
4. Repository 复用完全相同的领域合同
create/commit 使用短 SERIALIZABLE transaction,依次验证:
- active Project lock;
- exact current head 或空 head;
- runtime-core 重新计算的 create/commit command;
- installation version、record digest、mutation ID/digest CAS;
- history、head 与 mutation ledger 原子提交。
只对 PostgreSQL 40001、40P01、55P03 做最多三次 transaction retry。
连接错误、COMMIT response loss 和其他 outcome-unknown 不透明重放,必须由调用方读取
durable mutation/head 事实后裁决。exact replay 返回当前已前进 record,不倒写旧状态。
恢复只扫描当前 head 中 queued | staged | activating,使用稳定
Package/installation cursor,每页最多 64 条;旧 generation 不能重新取得 authority。
5. 两个 adapter 共享一份可执行语义合同
根级 pluginPackageInstallRepositoryContract.cjs 同时驱动 SQLite 与真实 PostgreSQL,
覆盖 create/find、exact replay、mutation drift、CAS/stale state、旧 mutation replay、
terminal head replacement 和 current-head recovery pagination。adapter-specific
测试只保留 catalog、corruption、role/entrypoint 与数据库故障行为。
6. 产品安装入口继续失败关闭
后续 ADR 已补齐标准 OCI source/stage verifier、一次性 recovery process、独立 cluster-admin image 与 namespaced ConfigMap-only Job/RBAC;这些恢复能力不等于面向 用户开放安装入口。当前仍不实现:
- 具体 Approved Action 产品 consumer 与管理入口;
- Task/Workflow/Prompt/Tool/Trigger 的原子 generation publisher;
- operator repair、旧 generation GC;
- publisher revoke/index、管理 API/CLI/UI 或自动更新;
- Runtime Extension 或动态代码加载。
因此 production cluster 可以在已存在耐久 installation 的前提下运行受限恢复门,但仍 不能通过产品入口创建安装、激活新的资源 generation 或启用动态代码。
拒绝的方案
- 新增
plugin-package-postgresworkspace package:拒绝;单一 adapter 文件和迁移属于 现有 cluster-postgres,拆包只会增加 importer/build/发布成本。 - 直接授予 admin Project UPDATE 以便行锁:拒绝;技术性锁需求不应变成通用数据修改 authority。
- 普通 SELECT 后写 installation:拒绝;Project 可在检查后并发归档。
- 在 repository 内复制 SQLite 状态机:拒绝;领域语义必须由 runtime-core 和共享合同 单点定义。
- 将 repository 加入 admin/root 默认导出:拒绝;会让短生命周期安装 authority 在无产品闭环时变成易达能力。
影响
- 集群节点获得与本机完全对等的 crash-safe installation/head/mutation authority。
- 低配 edge/standalone 制品不安装或加载 cluster-postgres,本切片不改变其常驻资源。
- workspace importer 仍为 21 个,没有新增 package 或依赖。
- PostgreSQL readiness 多审计一个单用途函数,但常驻进程不增加 timer、watcher、 sidecar 或数据库连接。
验证
- migration checksum、SQL/Drizzle/schema/function contract、三角色 readiness 与显式 subpath 隔离:21/21;
- local-sqlite 全量及共享合同:68/68;
- cluster-postgres 非数据库全量:124 pass、1 个条件 skip、0 fail;
- PostgreSQL 18 单角色真实集成:26 pass、3 个角色条件 skip、0 fail;
- PostgreSQL 18 四角色真实集成:28 pass、1 个同角色 backend termination 条件 skip、0 fail;
pnpm test:postgres-ha:ql3:21 个 HA 子门和总passed全为 true;2026-07-25 最近一次本机 arm64 证据为 fail-closed 312.866 ms、fresh activation 364.602 ms、旧主pg_rewind1,744.481 ms,0 unexpected domain side effect。
21 个 importer 的 clean build 与全量 package 聚合测试均退出 0;dependency/source
boundary、edge import 和六种 Profile artifact 门禁均通过且 findings=[]。六种制品
顺序复验的最大值为 2,849,582 bytes/439 files/78 loaded modules,最大 RSS delta
13,221,888 bytes,低于 4 MiB/512 files/16 MiB 硬门禁。production composition 与
真实 operator 安装恢复仍是后续独立 Gate。