agent-Specialization/cache_research/gateway/gateway_implementation_review_2026-09-07.md
JOJO f77f1d67a8 refactor(runtime): 审核 F1-F4 收口——发现入口、范围校验、入口统一转调、验收加固
- F1: RuntimeService.list_runs 公共 Run 发现(工作区/会话/状态筛选);
  task_public_payload 序列化收敛至 models.py 核心层单一实现(Web/公共入口同构,
  helpers.py 旧实现删除,无新旧双轨)
- F2: tasks/api.py 7 处、api_v1.py 3 处、chat/approval.py 6 处全部转调
  runtime_service;HTTP 轮询透传 window_start 缺口水位;死导入清零
- F3: _resources_for_query 补 principal workspace_id 一致性校验
  (跨工作区查询必须重新认证)
- F4: config 新增 ASTRION_IGNORE_DOTENV 逃生门(.env 对 ASTRION_DATA_ROOT 的
  优先覆盖是刻意设计,保留);验收测试自包含(假模型 127.0.0.1:9 快失败)+
  隔离生效断言;lifecycle 改 api_request_start 装配证据断言;
  新增审批等待链验收(approval 档真实工具循环:等待→公共入口批准→继续);
  chain 首段改双客户端场景(B 经 list_runs 发现 A 的 Run 并观察/取消)
- execution_plane/base.py 注释修正:命令校验/路径授权仍在旧链路(审核 §4)
- 全量 75 测试:失败恰为 4 项存量,与改造无关
2026-09-08 01:29:43 +08:00

116 lines
11 KiB
Markdown
Raw 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.

# Gateway 改造实现审核记录
> 审核日期2026-09-07
> 审核方式主智能体综合审阅3 个 Luna 子智能体分别核查服务初始化、协议与多端交互、执行环境边界。
> 审核基线:`b4deee0f`;目标提交:`d7cb854f`。结论只描述该提交快照,后续修复须重新验证。
> 本轮只审核并记录,未修改业务代码。本文不替换既有规划或子报告。
## 1. 范围与结论
本次审核以下 4 个提交:
| 提交 | 内容 |
|---|---|
| `d9bd599c` | Gateway 独立启动与公共协议落地 |
| `27aeed70` | Execution Contract 与替身执行器 |
| `4378eb6a` | 会话查询公共入口与代码就绪度收口 |
| `d7cb854f` | 审批/提问公共入口与①②③链路收口声明 |
对照依据:[当前状态规划](gateway_current_state.md) §7、[公共协议](../../docs/runtime_protocol.md)、[执行契约](../../docs/execution_contract.md),以及前序关于四层职责、公共入口、状态归属和行为验收的约定。
**结论改造已有实质进展但现有证据尚不能支持“①客户端—②Gateway—③Runtime 已完整贯通”的完成声明。** 当前完成的是主要进程内服务能力、独立初始化相关拆分和 E1E4 替身接入;公共任务发现、既有适配入口收敛、资源范围校验及验收可靠性仍需收口。
按规划中记录的本轮收口范围,生产 Host/Docker 迁入 ExecutionBackend、E5E10 全量接入、正式 CLI/GUI/IDE 客户端开发均已后置。本文不把这些已明确后置的工作算作本轮违约,也不要求事件全量持久化、重启续跑或 Remote Worker。
## 2. 完成度核查
| 能力 | 审核结论 | 证据与限制 |
|---|---|---|
| 任务核心与 Web 路由加载拆分 | 已实现 | `server/tasks/__init__.py` 不再顶层装配 Blueprint 与路由;`server/tasks/web.py` 承担 Web 装配 |
| 非 Web 环境的消息输出与后台任务启动 | 已提供适配 | `server/extensions.py` 增加 `emit_event` / `run_background`;独立生命周期仍需加强验收 |
| Run、审批、会话查询公共方法 | 主要方法已实现 | `server/runtime/service.py`;存在 F1、F3且 Web 调用尚未全部迁移F2 |
| 事件 offset 与窗口水位 | 进程内接口已实现 | `get_task_events` 返回 `meta.window_start`;现有 HTTP 轮询未透传该信息 |
| 多客户端发现、操作与恢复闭环 | 部分完成,未充分验收 | 新客户端缺活动 Run 发现入口;测试没有覆盖真实 A 发起/B 操作和断连重连 |
| CLI/GUI/IDE 独立接入 | 部分服务基础已具备 | 进程内直调成功不等于已有独立传输适配器;正式客户端后置可以接受,但应准确限定“代码就绪度” |
| ExecutionBackend | E1E4 替身接入已实现 | 默认 `execution_backend=None`;生产 Host/Docker 与 E5E10 后置,符合当前范围记录 |
## 3. 本轮需要收口的发现
以下均列为 **P2本轮完成验收前应修正或明确处理的事项**。其中 F1/F2 是能力与迁移缺口F3 是新增公共接口的资源校验缺口F4 是验证缺陷;不应全部表述为线上行为回归。
### F1新客户端无法通过公共入口发现已有任务
- **位置**`server/runtime/service.py:277`、`docs/runtime_protocol.md:4956`。
- **现状**RuntimeService 只有按已知 task_id 查询的 `get_task` / `get_task_events`,没有 `list_runs` / `list_tasks`。底层 `TaskManager.list_tasks` 已存在,旧 Web `/api/tasks` 也提供列表,但没有提升到公共服务。
- **触发场景**:客户端 A 发起任务后,客户端 B 新连接,尚不知道该 task_id。B 无法仅通过当前公共协议发现 A 的活动 Run仍需旧 Web 列表接口或其他协议外信息。
- **影响**:仅验证 `get_task(task_id)`不足以证明“B 经公共入口查询并操作”已经成立。
- **建议**:增加受授权的 Run 发现查询,可按工作区、会话和活动状态筛选;复用底层能力,返回适合公共协议的结果。
- **验收**A 创建 RunB 只持已授权身份及工作区/会话范围,通过公共查询取得该 Run再观察、回答审批或取消不从 A 的测试变量直接获取 task_id。
### F2既有适配入口未统一新恢复信息未到达实际客户端
- **位置**`server/tasks/api.py:236/281/304/332/355/377`、`server/api_v1.py:424/432/453`、`server/chat/approval.py:56/71/100/115/143/159`。
- **现状**Web/API 的事件轮询、取消、引导、队列操作仍有直接调用 task_manager 的路径;三类审批查询/回答仍直接调用对应 manager。
- **具体差异**RuntimeService 的事件查询新增 `meta.window_start`,旧 HTTP 轮询仍用 `get_events_since` 构造响应,不包含该水位。新增协议的缺口检测信息尚未到达这些客户端。
- **影响**:“公共方法已提供”不能等同于“既有入口均已转调”。多条路径仍可独立演进,新增语义也不会自动共享。直接调用同一 manager 不等于出现多份状态,但不满足本轮入口收敛约定。
- **建议**:相关 Web/API 路由转调公共服务,保留现有认证及兼容响应;将事件窗口信息适配到响应,并验证消费者的缺口处理。更新完成速览,区分接口存在、适配完成和行为验收。
- **验收**:同一组受理、取消、队列和审批行为,经 Web 适配与直接服务调用得到等价结果;裁剪事件窗口后,调用方能检测缺口并按已定义规则重新同步,不仅验证未裁剪时 window_start=0。
### F3会话查询未检查 principal 绑定的工作区
- **位置**`server/runtime/service.py:250270`,重点为 `:254269`
- **现状**`_resources_for_query` 只检查 `principal.username == username`,没有检查 principal 的 workspace_id 与查询目标一致,随后直接按调用参数的 workspace_id 装配资源。
- **已复现**:主侧用资源解析替身调用 `_resources_for_query('alice', 'B', TrustedPrincipal(username='alice', workspace_id='A'))`,得到 `resource_workspace='B'`,没有被拒绝。
- **影响**:服务接口未守住 TrustedPrincipal 所声明的资源范围。当前是进程内可信调用接口,不能据此断言已有外部可利用漏洞;但新适配器将外部查询参数传入时,这个不一致必须被阻止或经明确重新授权处理。
- **建议**:查询目标与已授权 principal 范围保持一致;若允许切换工作区,应显式完成目标授权,而不是直接信任第二份 workspace_id 参数。
- **验收**:覆盖同名用户不同工作区、用户名不一致、正确范围查询,以及 host/API/web 身份。当前测试只检查用户名不一致。
### F4独立验收测试存在假通过、隔离及配置依赖
- **位置**`test/runtime_standalone_checks.py:2527/83144/147258`、`config/__init__.py:5152`。
- **假通过**:生命周期测试接受任意 failed 终态terminal 不存在时跳过门闸检查。主侧在缺少模型配置、资源装配失败的环境中,观察到该生命周期测试仍通过。
- **交互覆盖不足**chain 测试在 Run 结束后手工向 manager 创建审批,再验证公共入口路由。这能验证查询、裁决和重复回答的服务行为,但不能证明“执行中的任务进入等待→另一客户端回答→原任务继续”。提问与计划确认的完整等待链同样缺少对应证据。
- **隔离缺口**:测试设置临时 ASTRION_DATA_ROOT 后config 仍会用源码目录 `.env` 的同名值覆盖。子审核在当前工作区执行时,观察到尝试访问真实运行态目录并被写权限拒绝;因此原隔离设置不能作为可靠保证。
- **配置依赖**:主侧在无 `.env`、无真实凭证的隔离源码副本中执行fake_exec 因“未配置可用模型”失败chain 因没有建立会话 ID 失败。测试未提供自包含的模型配置与受控响应。
- **建议**:提供确定的测试资源根、模型配置和模型响应替身,保留真实任务线程与资源装配。分别断言成功、取消、审批等待/继续、预期异常及清理结果,不用任意 failed 替代成功验收;强制确认 terminal、会话历史和门闸状态。
- **验收**:全新隔离目录、无真实凭证、禁用网络时可稳定复现;改变开发者 `.env` 不改变测试数据路径;人为使装配失败时,成功生命周期用例必须失败。
## 4. 已后置执行层工作的契约提醒
`modules/execution_plane/base.py:29` 声称路径授权与 `_validate_command` 已在 Runtime 编排层完成,但当前真实命令校验仍位于旧 `terminal_ops` 链路,文件路径检查也不能只依赖“先读后写”前置检查。注入 backend 的新分支未完整复用这些旧后端校验。
**当前默认生产路径未因此改变,不将其报告为现有 Host/Docker 权限绕过。** 但未来接入真实 ExecutionBackend 前,必须准确分配并保留命令校验、路径授权和实际执行限制;不能按照当前注释误认为上层已完成全部检查。
此项跟随已后置的③↔④工作处理,不作为本轮①②③收口的额外扩张。
## 5. 验证记录与限制
主侧测试方法:从目标 HEAD 导出临时源码副本(不带未跟踪 `.env`),指定临时数据/部署配置目录,移除继承的模型凭证,并通过测试进程的网络连接拦截禁止外部调用。未修改被审核源码。运行器使用仓库 `.venv/bin/python` 的 unittest discovery未依赖 pytest。
运行以下 5 组测试,共 **28 项26 通过、2 失败**
- `test_server_refactor_smoke.py`
- `test_runtime_service.py`
- `test_runtime_identity_resources.py`
- `test_conversation_model_persistence.py`
- `test_runtime_standalone_lifecycle.py`
| 失败用例 | 观察结果 | 解释 |
|---|---|---|
| `ExecutionPlaneFakeBackendTest.test_runtime_with_fake_execution_backend` | get_default_model_key 抛“未配置可用模型” | 未进入替身工具断言,不能认定工具实现回归;证明测试配置不自包含 |
| `ProtocolSmokeChainTest.test_full_chain_run_history_offset_approval` | “Run 应建立会话 id”断言失败 | 本次隔离环境下会话装配未成功,不能作为全链路完成证据 |
对照观察:同一环境下 `StandaloneRuntimeLifecycleTest` 通过,结合其接受 failed 及可跳过 terminal 检查的逻辑,确认 F4 的验收假通过问题。
另外完成了 F3 的最小替身复现、适配入口静态对照及最近提交范围核验。未执行真实模型调用、真实多客户端联调或 UI 人工验收;不据上述测试结果声称这些场景已通过,也不将这两项失败直接归为生产业务回归。
## 6. 建议收口顺序
1. 补公共 Run 发现查询,修复会话查询的工作区范围校验。
2. 将本轮承诺的 Web/API 控制、审批与事件观察入口转调公共服务,落实事件缺口响应与处理。
3. 修复测试隔离和自包含配置,用受控模型响应验证真实装配、执行中审批/提问、取消及清理。
4. 用两个相互独立的客户端调用方完成 A 发起、B 发现并操作、断连及重连验收;传输适配尚未实现时,明确记录进程内调用的实际覆盖范围。
5. 根据证据更新 `gateway_current_state.md` 完成速览;其余生产执行后端与正式客户端工作继续按已后置范围推进。
完成上述收口后,再将“主要服务方法已具备”升级为“本轮①②③边界已按约定验收”。