7.2 KiB
ADR-0256:Owner-authenticated Local TaskDefinition Management
- 状态:Accepted
- 日期:2026-08-01
- 关联 RFC:QL-RFC-0001 D-85、D-175、D-207、D-239
- 关联 ADR:ADR-0074、ADR-0085、ADR-0089、ADR-0091、ADR-0092、ADR-0217
背景
Fresh Edge/Standalone 已具备版本化 TaskDefinition、内建 qinglong/command@v1
语义注册表、原子 execution revision 物化、Owner credential 和 Project Policy,但产品入口
仍只能通过测试或直接 Repository 写入 TaskDefinition。部署者无法用受支持命令完成
create/update/enable/disable/inspect/list,也就无法在 fresh 安装后建立第一个可调度任务。
这个缺口不能靠向常驻 application 暴露写 Repository 解决。路由设备不应因此增加管理 daemon、第二数据库连接、timer 或新的 workspace package;Cluster 也不能复用本机文件 credential 和 SQLite authority 来绕过 PostgreSQL/RBAC/多副本管理边界。
决策
- 在既有
@qinglong/local-owner-cli增加唯一短生命周期 binaryql3-task,只接受run --command-file /absolute/private-command.json。command file 必须位于 deployment root 内、由当前 UID 持有、模式0600、不是 symlink;不接受参数拼装的 Task spec。 - v1 只开放
task.put|task.inspect|task.list。task.put以expectedRevision=null创建,以当前 revision 更新;enabled=false|true分别表达 disable/enable 的新 revision,不提供 update-in-place 或 delete。 - 写入只接受已冻结 registry 中的 Task spec;当前 production registry 仍只有
qinglong/command@v1。CLI 不因为 envelope 支持script|workflow|agent|tool就猜测其语义。 - 每次命令建立短生命周期 SQLite connection,使用现有 Owner pepper/credential
authentication 和 Project Policy。create/update 分别要求
task.create|task.update,查询 要求task.read;principal 必须是 strong User,owner/admin/operator 可写,viewer 只读。 - 写事务在同一
BEGIN IMMEDIATE内重新验证 credential/Identity/pepper fence、Project version/status、RoleBinding version/state,并原子提交 allowed audit、Task head、immutable revision、mutation replay 与适用的 local execution revision。任何 fence、semantic、revision 或 audit replay 冲突整体回滚。 mutationId同时是 allowed audit event ID;requestId、actor、Policy fence、operation 和 immutableoccurredAtMs都属于 exact replay 语义。调用结果未知时只能原样重放 command file。复用 mutation 但改变 Task 或 audit 语义必须失败关闭。- inspect/list 使用当前 head、最多 256 条的稳定
taskIdkeyset;每页使用新的 request/audit identity。输出只包含 Project/task、revision、name、kind/schema、enabled、 content digest 与时间,不回显 spec/config/command 参数、SecretRef、credential、pepper、 数据库路径或 command-file 路径。 - 实现只增加现有
runtime-core、local-sqlite、local-admin、local-owner-cli的显式 subpath;workspace 保持 19 个 package,不新增第三方或 production dependency、migration、 daemon、timer、watcher、listener、cache、Pool 或端口。Edge/Standalone 空闲成本为零,只有 operator 发起命令时产生一个短进程和一个 SQLite connection。 ql3-task明确不支持 Cluster。Cluster TaskDefinition 管理必须后续通过 PostgreSQL 管理 repository、独立 credential/RBAC、强认证 transport、持久审计和多副本 fence 提供;不能 挂载本机 Owner credential 或把 SQLite command file 当集群管理协议。
失败与恢复
- 配置、路径、权限或 Task semantic 失败:修正后创建全新的 command identity;
- 认证、授权或 fence 失败:恢复 credential/RoleBinding 后创建新命令,不复用已改变语义的 mutation;
- revision conflict:先 inspect 当前 revision,再以新 mutation/时间提交明确更新;
- COMMIT 结果未知:保留原
0600command file 并逐字重放;existing表示 durable semantic 已存在,不重新创建 revision; - audit 与 Task replay 不一致:停止自动重试并人工检查,禁止直接 SQL 修补或删除历史。
被拒绝的替代方案
- 新建
task-adminworkspace package:没有独立部署、依赖或权限域,只会让 19 包拓扑 再次碎片化,拒绝。 - 把写入口放进常驻 local application:扩大空闲 authority 和攻击面,也让路由设备为偶发 管理持续付费,拒绝。
- 直接使用 SQLite/Repository 脚本:绕过 authentication、Policy、audit、semantic registry 和 revision fence,拒绝。
- 用
task.enable|disable修改 head bool:破坏 append-only 历史、pinned Run 解释和 exact replay,拒绝;状态变化必须是新 revision。 - 让 Cluster 复用本机 CLI:SQLite 单 authority 和本机 credential 不具备 PostgreSQL HA、 多副本竞争或集群 RBAC 语义,拒绝。
验证
ql3-task真实 SQLite 纵切面覆盖 create、exact replay、disable、inspect、keyset list、 operator allow、viewer deny、credential/Policy race rollback、Task semantic drift、audit semantic drift、私有 command file 与低敏输出;当前 5/5;@qinglong/local-owner-cli完整 dependency closure strict TypeScript 通过;- Owner CLI 83/83、local-admin 81/81、local-sqlite 189/189、backend 956 pass/2 条件 skip/0 fail;19 个 QL3 package 清理后顺序构建并完成全量测试,所有已执行 suite 零失败;
- dependency boundary 40/40 且 repository audit
findings=[],Edge import 与 local image 静态 inventory audit 均 compatible;GitNexus compare-to-develop 为 LOW、0 条受影响执行流; - PostgreSQL 18.4 arm64 physical HA 同轮重新通过
remote_apply、timeline 1→2、旧主先 fencing、pg_rewind只读同步重入、两个 fresh control replica 与全部业务 gate,gates.passed=true;测试容器、网络、卷零残留。此项只证明 Cluster 基线未回归,不把 本机ql3-task宣称为 Cluster 产品入口; - 完整 package/backend/dependency/artifact 回归是合入前门禁。
D-239 验证时曾发现 storage-only 超过 512 files、adopted assembly 漏收 local-secret,且
application 为 741 files、约 6.40 MiB、import RSS delta 约 20.2--20.35 MiB,因此本 ADR
当时没有把 Profile gate 标记为通过。后续 ADR-0257/D-240 已通过内部运行制品裁剪、精确 adopted
闭包和 eager import 收口修复该 blocker;十档门现已全部通过。D-239 没有自行放宽预算,完整
application 的 24 MiB import delta 分层也不改变 Edge 96 MiB 总物理进程预算。
后续约束
后续 ADR-0258/D-241 已完成 Trigger create/update/enable/disable/inspect/list 和 Task→Trigger→Run 的可操作 fresh 用户闭环,并在 Trigger 写入、scheduler candidate 与最终 Run commit 三处执行 Task current-head fence。下一步为 Cluster 实现 PostgreSQL/RBAC 对等管理入口。 HTTP/UI 只能调用同一服务语义,不能复制 Task/Trigger semantic、Policy、current-head fence 或 replay 规则。非 command kind 仍须各自完成 semantic、权限、编译与执行评审后才能进入 production registry。