Files
qinglong/docs/adr/ADR-0375-shared-current-task-point-read-api.md

65 lines
7.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-0375:共享的 current Task point-read API
- 状态:Accepted
- 日期:2026-08-11
- 关联:QL-RFC-0001 D-06、D-08、D-13、D-17、D-28、D-75、D-85、D-87、D-157、D-239、D-253、D-257、D-262、D-279、D-280、D-285、D-286、D-287ADR-0256、ADR-0272、ADR-0350、ADR-0373、ADR-0374
## 背景
D-286 已让 Local、Cluster 和 MCP 能以稳定 keyset 发现 Project 的 current Task,但客户端若持有一个 Task ID,仍必须扫描列表才能确认它当前是否存在、是否启用以及具体 revision。后续 Task start 又必须绑定明确的 current revision 与 immutable content digest,否则 discovery 与 mutation 之间的定义变化会被静默接受。
直接返回完整 TaskDefinition 不是可接受的捷径:command、public environment、SecretRef、working directory、placement、description 与 labels 都可能暴露执行细节或 secret-adjacent 内容,并会把内部 spec 格式冻结成公共 API。point read 应先提供精确 current-head identity/fence;完整 spec preview 与 Task start 继续分别评审。
## 决策
1. Runtime Core 在 `task-definition/projection` 拥有唯一 `executeBoundedTaskReadProjection`,输入为可信 Project ID 与一个 Task ID,只调用 `TaskDefinitionSource.findCurrentTaskDefinition(projectId, taskId)`
2. 找到时只返回 `found=true``taskId`、current `revision``name``kind``specSchema``enabled``contentDigest``createdAtMs``updatedAtMs``contentDigest` 是后续 mutation 的 optimistic fence,不是执行授权。
3. 不得返回 Project、description、spec config/command/environment/placement、labels、mutationId、SecretRef 或数据库 row。合法的不存在、Task identity 不匹配与跨 Project 记录必须统一为 `found=false`;畸形 record、digest/time 不一致和 repository failure 必须失败关闭为 unavailable。
4. Local 与 Cluster 增加同构 `GET /api/v3/projects/{projectId}/tasks/{taskId}`,固定 operation `task.get`、permission `task.read`。不允许 query 或 bodyLocal 继续在 authentication 前拒绝非规范 path/queryCluster 复用 route registry 的 exact path/query 编译。
5. HTTP 找不到统一返回 `404 task_not_found`;存储或投影不可用统一返回 `503 task_query_unavailable`。响应不把 Project ID 重复写入 bodyProject authority 来自经过 admission 的 path binding。
6. 本机 MCP 增加 `qinglong.task.get@1.0.0`,输入只有 `taskId`,输出直接复用共享 projection。Tool 固定 `effect=read``risk=low``task.read` 与 5 秒上限,复用 authentication→Tool Policy→durable audit→credential confirm→同一 SQLite authority。
7. Local Application product surface 和 Local MCP database 只把既有 source 的 `findCurrentTaskDefinition` 加入窄 read authorityCluster 复用 `ClusterControlAssemblyInput.taskDefinitions` 与现有 PostgreSQL Pool。
8. 不新增 workspace package、第三方依赖、migration、表、索引、数据库连接、listener、sidecar、timer、watcher、cache 或写 authority。历史 revision read、完整 spec preview、Task start、input payload 与 mutation 继续需要独立 ADR。
9. D-285/D-286 的 18-package、14 Profile artifact、真实 Local image、完整 backend/packages、dependency/package boundary 与 PostgreSQL HA 门不得放宽。
## 不采用方案
- **让客户端扫描 Task list**:深链接成本随 Task 数量增长,也不能获得明确的 current digest fence。
- **返回完整 TaskDefinition**:会泄露命令、环境、SecretRef 和部署细节,并提前冻结扩展 spec 协议。
- **只返回 revision、不返回 digest**:同一 revision 的损坏或错误 adapter 映射无法被客户端/后续 start 计划绑定。
- **把 `task.get` 合入 `task.list` query**:混合 collection 与 resource 语义,增加游标和 not-found 歧义。
- **只实现 HTTP 或只实现 MCP**:会让人类客户端与 AI 客户端拥有不同的 current-head/fence 语义。
- **新增 Task query package/service**:纯投影没有独立部署、authority 或重依赖隔离价值。
## 完成门
- Runtime Core 覆盖 found/absent、字段脱敏、disabled Task、跨 Project、畸形 record、digest/time drift 与 repository failureleaf import 不加载 Tool Registry/SemVer。
- Local route、transport、admission、product authority 与真实 SQLite HTTP 覆盖 `task.read`、pre-auth query rejection、credential confirm、durable `task.get` audit、404 masking 和同一 storage authority。
- Cluster route、registry 与 production composition 使用既有 `TaskDefinitionSource`/Pool,并覆盖 Policy、audit、404 masking、无 query/body 与响应上限。
- MCP 覆盖精确 Tool schema、`task.read` admission、durable audit、credential confirm、真实 stdio/SQLite current Task read,并证明只调用共享投影。
- Runtime Core、Local SQLite、Local API、Local Application、Local MCP、Cluster Control、双方言相关测试、完整 backend/18-package、14 Profile artifact、真实 Local image与 PostgreSQL HA 全绿。
## 验收证据
- Runtime Core 486/486、Local SQLite 213/213、Local API 39/39、Local MCP 45/45、Local Application
45 pass/4 条件 skip、Cluster Control 204 pass/2 条件 skip;完整 18-package clean build/test 退出 0,完整
backend 1,163 pass/2 条件 skip、0 fail。Local HTTP 使用真实 SQLite authority 持久化 `task.get` auditMCP
stdio 使用同一 SQLite current Task sourceCluster production composition 使用既有 PostgreSQL source/Pool。
- workspace 保持 18 package/1,035 source,其中 1,017 nested/18 个受审根入口,`singleSourcePackages=[]`
`shallowSourcePackages=[]`。package boundary 正反向门 62/62dependency audit `findings=[]`;没有新增 package、
第三方依赖、migration、表、索引、连接、listener、timer、watcher、cache 或写 authority。
- 14 个 Profile artifact 全部 `compatible=true`。默认 Edge/Standalone 仍为 2,385,220/2,385,298 bytes、288 files、
50 loaded modulesApplication、Adopted、AI 与 Application AI 档相对 D-286 精确不变。选择 Local API 的
Edge/Standalone 为 3,538,918/3,539,062 bytes、416 files、80 modules,相对 D-286 增加 5,412/5,412 bytes、
2 files、2 modules;选择 MCP 的 Edge/Standalone 为 7,161,579/7,161,687 bytes、776 files、213 modules
相对 D-286 增加 7,364/7,364 bytes、2 files、2 modules。未选择 API/MCP 的低配部署不承担该增量。
- 真实 arm64 Local Application image 为 10 package/380 files/3,284,889 bytes,默认不含 Local API、MCP、AI 或
Cluster packageEdge 128 MiB/64 PIDs 与 Standalone 256 MiB/256 PIDs 均以 UID/GID `65532:65532`、只读根、
`network=none` 完成 active→graceful stopSQLite integrity `ok`。临时 image 已删除。
- PostgreSQL 18.4 arm64 HA 通过 112 gatestimeline `1→2`,报告 SHA-256
`d2f02a7cd67a712e5fe3e2152c8c3afdefe9680d51c6c0ab108c6882ac7c841c`;旧主 fence、promotion、`pg_rewind`/
rejoin 与 fresh replica 收敛后 Docker 容器、网络、卷零残留。
- GitNexus 刷新为 47,031 nodes/106,513 edges/1,853 clusters/295 flows。四个新增生产符号均为 LOWLocal route
1 direct/1 processCluster route 1 direct/2 totalMCP Tool 1 direct,共享投影 0 indexed upstream;跨 package
export 未形成的调用边由三端定向测试、完整 package、真实 SQLite/MCP 与 artifact 门补强。无 HIGH/CRITICAL。