10 KiB
ADR-0184:本机 Plugin Package 离线隔离与能力撤出
- 状态:Accepted
- 日期:2026-07-28
- 关联:RFC D-133、D-149、D-150、D-169、D-170、D-171、D-172、D-173、 D-174;ADR-0149、ADR-0150、ADR-0179、ADR-0180、ADR-0181、ADR-0182、 ADR-0183
背景
ADR-0183 在 compromise proposal durable 后阻断目标 signer 的新 catalog publication 和 queued stage,并在确认后删除 trust key、保存受影响 lock 集合。它刻意没有声称 已撤下 active Package:
- install head 的
activeLockDigest仍可指向旧 lock; - Package Task 已成为独立、不可变 TaskDefinition revision 和 current head;
- Tool 已进入 Project active-vector snapshot;
- 已批准的历史 Run/Tool invocation 可能绑定旧 revision/snapshot。
因此只给 install state 增加 quarantined,或只让 source query 忽略一个 lock,都无法
关闭完整执行面。热卸载还会与正在执行的脚本、进程和 Tool adapter 竞态。本机模型应
先停 application,再由短生命周期 Owner authority 原子撤出耐久能力。
提议决策
1. 使用永久 quarantine overlay,不改写安装历史
不扩展 queued|staged|activating|active|failed 的既有 install event history。新增本机
SQLite capability v35,以 append-only QingLong3PluginPackageQuarantineEvents、
immutable QingLong3PluginPackageWithdrawalReceipts 和逐 Task
QingLong3PluginPackageWithdrawalTasks 覆盖目标
projectId/packageName/installationId/lockDigest。quarantine target 通过
project/package/installation/lock/install record digest 复合外键冻结到原安装事实,
不另建可变 quarantine head。
plugin-package.quarantine.apply 只接受受管 trust root 中 ADR-0183 的 exact
revocation receipt,不接受调用方自报 lock 集合。命令必须绑定 receipt/proposal/
impact digest、当前 install head、Owner、mutation、SecurityAudit 和数据库时间。
quarantine 是永久 tombstone;恢复只能安装由非撤销 key 签名的新 lock,不能把旧
head 改回 active。
对 queued|staged|activating head,overlay 使 recovery source 不再选中目标 lock,
且既有精确安装事实不能被改写;不新增伪造的 install settled enum。对 active head,
overlay 进入同一事务的 capability withdrawal。
2. Active withdrawal 必须同时处理 Task、Tool 与准入
一个 BEGIN IMMEDIATE 事务固定执行:
- 复验 target lock 仍是 install head 或 head 的 active lock;
- 插入 exact quarantine event,目标与 mutation 都唯一,重复 mutation 只允许 exact replay;
- 对仍由该 Package/generation 拥有的 current Task 追加
enabled=falserevision, 不删除旧 revision、Run 或审计; - 从 Project Tool active vector 排除该 lock,按 Profile 基于其余最多 edge 4 个、 standalone 16 个 active source 生成 immutable snapshot;空 vector 是合法 snapshot;
- 写 withdrawal receipt,绑定 quarantine、Task revision 列表、新 Tool snapshot、 原/新 active-vector digest 和计数;
- 在事务取得写锁后、提交前执行授权 callback;callback 以同一连接复验 credential 未失效、确认者仍是 current Owner,dual-control 时提案者也仍是 current Owner;
- 提交前再次复验 install、Task、未受影响 source vector 和授权 fence。
任一步冲突或越界整体 rollback。Task/Tool 数据继续使用现有表和 pure planner;仅为 quarantine event/receipt/task 明细只增加三张事实表,不复制一套 Package 安装状态机。
3. 历史 revision 仍可读,但所有新 start 必须事务内失败关闭
仅更新 current Task head 或 current Tool snapshot 不足以阻止一个已经绑定历史事实的 新 start。下列本机 transaction 必须读取同一 quarantine head:
- Run
dispatching/runningCAS:若 Task reconciliation generation 能回溯到已 quarantine 的 lock,在推进 Run 前拒绝; - Tool execution start barrier:从绑定 snapshot 的 source 找到 Package lock,若已 quarantine,在写 barrier/调用 adapter 前拒绝;
- Package stage/activation/recovery:queued/staged/activating 的精确目标被 recovery source 排除,外键与 tombstone 阻止安装事实变体重写。
已持久进入 running 的 Run 或已经创建 start barrier 的 Tool invocation 保留原
completion/recovery 语义,不能删除或改写历史来伪造“从未执行”。D-173 的
stop_required 仍是撤出前的操作前置条件;本 ADR 不承诺从 SQLite 证明宿主进程已
被操作系统停止,也不实现任意脚本的安全热杀。
4. Crash recovery 与启动门
quarantine、Task disable、Tool snapshot 和 withdrawal receipt 在同一 SQLite 事务,
所以进程崩溃只能看到全部旧事实或完整新事实。COMMIT response loss 由 mutation/
receipt digest exact replay 返回 existing。
application startup 在 Package recovery 前执行 capability v35 readiness relation probe:
- quarantine event 必须精确对应一张 withdrawal receipt;
- Task 明细数量、内容 digest、Project/time 与 receipt 必须一致;
- active withdrawal 的新 snapshot retained source 数量必须一致,且不得再包含目标 lock;
- probe 使用
LIMIT 1找出首个损坏关系并失败关闭,不把全表物化进路由设备内存; - readiness 通过后,Package recovery、Task/Tool source 和后续 Run/Tool start 仍各自 执行 transaction fence。
不增加 timer、watcher、poller 或自动 GC。一次 Owner command 的 edge/standalone 目标 lock 上限为 4/16,每个 active withdrawal 的 source 上限也为 4/16,单 receipt 最多 128 个 Task;超限要求人工拆分或停机处置,不允许无界事务。
5. 包边界
继续复用:
@qinglong/runtime-core的显式 quarantine/withdrawal contract subpath;@qinglong/local-sqlite的 migration、repository 和 start fence;@qinglong/local-owner-cli的现有 Package command binary;@qinglong/local-application的 startup recovery composition。
不新增 workspace package 或第三方生产依赖。owner-cli 对 runtime-core 的既有源码 导入从 devDependency 纠正为 production dependency,并由 lockfile/源码边界门精确 允许。Cluster 对等能力必须在 PostgreSQL advisory lock、multi-replica admission、admin/runtime ACL 和 HA promotion 门全部实现 后单独接受,不能把本机 SQLite command 暴露为 Cluster transport。
已知限制与后续风险
- 当前 Run 不直接保存 Package lock provenance,start fence 通过 immutable Task reconciliation item/generation 回溯;未来应把 lock provenance 提升为 Run 建单事实;
- quarantine 与随后 replacement install 的 previous-active/rollback 语义需要独立 恢复 ADR;
- 本轮
SIGKILL覆盖 SQLite transaction window,但真实设备断电、ENOSPC、文件系统 损坏和完整 application 停机仍需要实机演练; - 本 ADR 只接受本机 SQLite 能力;PostgreSQL HA 门通过不代表 Cluster 已具备 quarantine adapter、ACL 或多副本管理 transport。
接受门禁
- pure contract:exact replay/conflict、永久 tombstone、bounded withdrawal receipt;
- SQLite migration/readiness/schema audit 与 capability v35;
- queued/staged/activating 三状态不再被 recovery source 选中;
- active Package 的 Task 全部 disabled、Tool source 全部排除,事务失败零部分事实;
- 历史 Task revision/Tool snapshot 可读,但新 Run/Tool start 在写前被 fence;
- application readiness 在 withdrawal relation incomplete/tampered 时失败关闭;
- 非 Owner、identity drift、impact/receipt 漂移和超限全部在可见变更前拒绝;
- Edge/Standalone
DELETE/FULL、WAL/FULL的 pre-COMMIT/post-COMMITSIGKILLmatrix 和integrity_check=ok; - 22-package dependency/edge import、application artifact/RSS 预算不回归;
- 实现触及 Cluster 时重跑 PostgreSQL 18 physical HA Docker 门,否则不声明 Cluster 能力。
验收结果
@qinglong/runtime-core/plugin-package-quarantine已提供 event/receipt schema、 exact replay/conflict、永久 tombstone、128 Task receipt 上限和确定性 mutation ID; runtime-core 349/349 通过;- reviewed migration
0069-plugin-package-quarantine和0070-capability-v35已落地,contract v35、62 张 owned table、migration checksum、 typed schema 和 readiness relation probe 一致; @qinglong/local-sqlite/plugin-package-quarantine在一个BEGIN IMMEDIATE中完成 exact install validation、Task consecutive disable、Tool snapshot、event/receipt/ task facts以及提交前授权 callback;exact replay 在返回前再次复验 durable facts;- Package recovery source、Task/Tool current source、Run CAS 与 Tool start barrier 均已读取 quarantine overlay;历史 revision/snapshot 仍可读;
ql3-package-trust revoke-confirm从 ADR-0183 receipt 的 impacted lock 导出目标, 在 trust snapshot 前逐项 quarantine;新建、已有 receipt 和已完成 snapshot 的精确 重放都会先执行该 hook,关闭“receipt 已存在却跳过撤出”的恢复窗口;- credential/Owner 的完整认证在事务外完成,事务内再以同连接执行当前 credential、 confirmer Owner 和 proposer Owner fence,避免共享 authority transaction 的重入 死锁;
- crash matrix 覆盖 edge
DELETE/FULL、standaloneWAL/FULL,在 Task disable 后、 event 后、receipt 后、COMMIT 前和 COMMIT 后各SIGKILL,共 10/10;8 个 pre-COMMIT 场景完整 rollback 后恢复为created,2 个 post-COMMIT 场景完整保留并重放为existing,integrity_check=ok、foreign key check 通过; - 全量测试通过:runtime-core 349、local-sqlite 136、local-admin 63、 local-application 32、local-owner-cli 22;
- dependency/source boundary 无 finding,Edge import closure 为 121 modules;四种 application 产物门通过:edge 4,915,362 bytes/615 files/90 modules,standalone 4,915,506/615/90,edge+AI 5,593,183/659/89,standalone+AI 5,593,339/659/89;
- 本轮未实现 Cluster quarantine,但按授权额外重跑 PostgreSQL 18.4 physical HA
Docker contract:physical streaming、
remote_apply、partition promotion guard、 old-primary fence/pg_rewindrejoin、scheduler/credential/Run/tool-result COMMIT-response-loss convergence 和 optional AI schema promotion gate 全部通过。