Files
qinglong/docs/adr/ADR-0289-request-keyed-durable-package-prompt-output-recovery.md

8.0 KiB
Raw Permalink Blame History

ADR-0289:按执行 Request ID 恢复并读取 Durable Package Prompt 输出

  • 状态:Accepted
  • 日期:2026-08-08
  • 关联:D-85、D-87、D-156、D-157、D-213、D-244、D-257、ADR-0261、ADR-0263、ADR-0267、ADR-0274、ADR-0275、ADR-0276、ADR-0288

上下文

ADR-0288 允许调用方在 Prompt execute 响应丢失后,用自己持久化的 executionRequestId 精确恢复 Run 状态;但其 结果刻意排除了 Artifact identity 和正文。现有 Prompt output read 又要求调用方同时保存服务端返回的 runIdartifactIdartifactDigest。当首次 durable execute 已成功提交而 HTTP/CLI 响应丢失时,这三个事实同样无法取得, 形成“知道执行成功、却不能取回已付费输出”的产品断点。

Cluster 已定义 caller-selected Artifact read route,但显式 AI production composition 尚未装配其 read authorizer 和 capability。Local application runtime 支持 durable outputOwner CLI 却只接受 live_only。仅新增一个 Artifact reference 发现接口会把重试、权限、retention、密钥解析和解密继续留给调用者,不能构成 QingLong 3.0 的恢复闭环。

决策

  1. 新增共享结果 schema qinglong/plugin-package-prompt-execution-output-read-result@v1。输入固定为强认证 principal 与 projectId/packageName/promptId/executionRequestId;成功结果返回既有 immutable Artifact reference 和受界 GenerateResult,缺失统一返回 not_found
  2. SQLite/PostgreSQL 在现有 Prompt admission request_id 主键上精确定位,只连接 succeeded finalization、 ModelInvocation completion、Run、StepRun 和 immutable output Artifact,并要求 step.output_ref=artifact_id。 查询固定 LIMIT 2,只投影 runId/artifactId/artifactDigest,不得读取 artifact_json、ciphertext 或 key material。
  3. 定位成功后必须委托既有 PluginPackagePromptOutputReadService,保持 metadata→artifact.read Policy→retention/ tombstone→key resolve→AES-GCM decrypt→key wipe 的顺序。新服务不得直接解密、绕过 tombstone 或请求 active key。
  4. Local ql3-prompt command-file schema v1 增加 prompt.execution.output.read,权限和 allowed audit operation 均固定为 artifact.read/prompt.execution.output.read。读取只装载 SQLite、output Artifact/retention repository 和显式 promptOutputKeyringPath,不得加载 Provider authority、Provider Secret 或 Model Gateway。
  5. Local prompt.execute 接受显式 durable_artifact + retentionPolicy。只有该模式要求并装载 promptOutputKeyringPath 与 completion coordinatorlive_only 继续禁止配置 output keyring,确保默认路由设备路径 零 Artifact/key/repository 增量。exact replay 返回相同 Artifact reference,不再次调用 Provider。
  6. Cluster 显式 AI Profile 新增 GET /api/v3/projects/{projectId}/packages/{packageName}/prompts/{promptId}/executions/{executionRequestId}/output operation 为 prompt.execution.output.readpermission 为 artifact.read。生产组合仅在 Prompt output keyring opt-in 时同时装配现有 caller-selected Artifact route 和新 request-keyed route;默认 AI-free control 不注册二者。
  7. absent execution、live-only、未完成、失败、cross-target、policy deny、已 tombstone 或 GC 后 Artifact 均统一映射 not_found/HTTP 404,不暴露目标存在性。内部 shape、digest 或 identity 漂移映射 503,正文不得进入错误和审计。
  8. 本增量不新增 workspace package、生产 dependency、migration、表、索引、Pool、端口、listener、timer、watcher、 cache、队列、controller 或部署单元。三个新 AI 文件全部进入既有 prompt-output/ domainworkspace 保持 19 包且 root-file hard cap 不变。

被拒绝的方案

  • 把 Artifact reference 加入 ADR-0288 的 content-free inspection:会把 run.readartifact.read 内容边界混合, 也让所有状态轮询暴露存储与 retention 元数据。
  • 只返回 reference,不返回正文:调用者仍需拼接第二次 API、保存 digest 并处理 tombstone,响应丢失恢复仍不是一个 原子产品动作。
  • 用 request ID 计算 Artifact ID 后直接解密:无法证明 Package/Prompt、terminal completion、StepRun output_ref 和 Artifact digest 的完整绑定。
  • 把正文复制到 admission/finalization receipt:扩大热表、备份、审计和 HA 泄漏面,破坏 immutable 加密 Artifact authority。
  • 为 recovery 建 projection 表或新索引:现有 request 主键和 terminal join 已能精确定位,新增状态会产生双写和 Edge migration 成本。
  • 新增 workspace package 或常驻 recovery worker:没有独立部署或故障域收益,并增加小设备 importer、内存和运维 表面积。

当前证据

  • 共享 service 5/5、Cluster route 3/3SQLite/PostgreSQL locator 都使用 request 主键和 terminal joins,定位 SQL 不读取 Artifact envelope/ciphertext,并覆盖 malicious widened reference/result、cross-target 与 missing。
  • Local Owner CLI 定向新用例通过:显式 durable execute、exact replay、按原 execution request 读取正文、重复读取和 allowed audit 均成功;Provider generate 仅一次,读取前后 Provider load 计数不变。
  • Cluster AI/production/route 定向 19/19output opt-in 同时装配 caller-selected 和 request-keyed read,默认 AI-free composition 保持不装配。
  • AI、Local Owner CLI、Cluster Control 与 Local Application 的完整 package suites 均零失败;完整 19-package clean build/test 与 backend 1,1101,108 pass/2 skip)全绿。cluster dependency、package boundary、Edge import、Cluster deployment、CloudNativePG 与 local image 六项审计 compatible;十档 artifact/RSS 全绿,Edge 3,614,826 bytes 最大 Standalone Application AI 6,102,447 bytes,默认非 AI closure 未新增 keyring/Artifact importer。
  • package ledger 保持 19 包、singleSourcePackages=[]762 个 source 中 49 个仅为受审公开/binary/composition 根入口, 713 个实现位于领域目录。新增 AI/Cluster 实现进入既有 capability,未以恢复能力为由新增微包或根层平铺。
  • PostgreSQL 18.4 arm64 physical-streaming HA 已实跑通过。轮换后的新 key durable output 在 primary 通过原 execution request 精确解密,standby WAL replay 与 promoted runtime-role decrypt 结果一致,cross-target 保持 not_found,报告不含正文;pluginPackagePromptExecutionOutputRecoveryIsExactAndContentFreepluginPackagePromptExecutionOutputRecoveryReplicatesAndSurvivesPromotion 均为 true。timeline 1→2、旧主 fencing/rewind/read-only synchronous rejoin、两套 fresh control replica、gates.passed=true 与最终 ql3-ha-* container/network/volume 零残留全绿。

接受条件

  1. AI、Local Owner CLI、Cluster Control 定向与完整测试全绿;双方言 exact/cross-target/live-only/tombstone/replay/ malformed-result 测试覆盖。
  2. 完整 19-package clean build/test、backend、Edge/Cluster dependency、package boundary、deployment/local image 与十档 artifact/RSS 门无回归;默认 Edge/Standalone 非 AI 与 live-only 闭包不得新增 keyring/Artifact importer。
  3. PostgreSQL physical-streaming HA 必须证明 durable Artifact、request-keyed locator 和 decrypt read 在 primary、standby WAL replay、promotion 后 runtime role 上保持一致;cross-target/content-free audit、timeline、rewind、fresh replicas 和 零残留继续全绿。
  4. 刷新 GitNexus 后对所有已修改符号重新检查影响,并运行 detect_changes all/compare develop

后续边界

  • Prompt execution history、输出列表、全文搜索、流式增量输出与跨 Package 查询仍需独立索引、分页和可见性 RFC。
  • UI 可在 execute 超时后先读 content-free execution 状态;只有用户显式查看 durable output 时调用本内容接口,避免 状态轮询反复解密和传输正文。