AgentEvalTool/.scratch/v111-architecture-scan.md
sinohqb a03067720b
All checks were successful
CI / test (push) Successful in 4m18s
test(intelligent-eval): add openclaw_client + webhook tests (#5)
T5 OpenClawClient subprocess args: docker exec cmd + token-last placement,
   cron add/rm/list params, JSON parse success + failure paths.
T6 webhook: marked sent on 2xx, failure does not raise; xfail guards expose
   missing retry and missing dedupe (.scratch/v111-architecture-scan.md §6.2).
2026-08-13 02:56:32 +08:00

11 KiB
Raw Blame History

v1.1.1 智能评估模块架构扫描

生成2026-08-13 用途v1.1.1(收尾 + 测试加固 + 架构深化)的输入文档,驱动 Gitea tickets 拆解 范围:backend/agenteval/intelligent_eval/ 为核心 + 外部边界web routers、openclaw_client、前端、Worker Skill 依据grilling 共识(测试先行为锁定 → 分阶段深化 → 统一发布 v1.1.1


1. 模块现状

intelligent_eval/ 共 13 文件 / 2883 行v1.1.0 新增功能模块,生产单进程 FastAPI + SQLite

文件 行数 职责
repository.py 459 3 个 Repository 类Eval/Session/Message+ CAS 条件写
lifecycle.py 354 智能评估生命周期create/plan/approve/reject/cancel/report + session 会话)
cron_pool.py 310 Cron 池管理initialize/scale/auto_scale/sync/stuck 检测)
decision.py 276 自主决策(时段/欠账/严重度 → execute/wait/analyze
task_queue.py 247 任务队列(扫描入队/优先级/next/assign/complete
alerts.py 216 告警规则与历史
fault_tolerance.py 204 故障恢复stuck 处理/对账/双端重启恢复)
read_model.py 196 读模型投影list/detail/report
openclaw_client.py 177 OpenClaw 容器 CLI 客户端docker exec
report.py 130 报告渲染
metrics.py 117 指标聚合
config_snapshot.py 109 配置快照
models.py 87 领域模型

依赖关系要点lifecycle→repositoryread_model→repositorycron_pool→openclaw_client + task_queue267 行运行时 import complete_taskfault_tolerance→cron_pool+task_queue+openclaw_clientdecision/task_queue 直接 session.exec 查库。

外部边界

  • Webweb/routers/intelligent_evals.py(前缀 /api/intelligent-evals+ web/routers/openclaw_cron_pool.py(前缀 /api/openclaw
  • OpenClaw 客户端docker exec openclaw CLI 管理容器内 cron硬编码 gateway_token="agenteval-openclaw-token-2026"
  • Worker SkillOpenClaw 容器内 cron worker 经 docker 网络直连后端 tasks/next|assign|complete + heartbeat不经前端
  • 前端IntelligentEvals.tsx(读模型 useIntelligentEvalRead,统一轮询 + stale 过滤);CronPoolMonitor.tsx自带 setInterval 5s,无统一 hook

2. Seam 泄漏清单(深化候选)

# 位置 泄漏 影响 深化方向
S1 task_queue.py_is_slot_due/_calculate_session_deficit/_calculate_priorityvs decision.py_parse_time_slot/_get_current_slot/_count_sessions_in_slot/_has_high_severity_issues 时段/欠账/严重度领域知识重复"8-10h" 解析两份、时段内 session 统计两份、优先级/欠账各自实现 改口径需改两处,易漂移 收敛为 shared 领域模块,两模块消费同一实现
S2 web/routers/intelligent_evals.py 后段tasks/next 内联拼装、assign/complete、decision-logs POST/GET 直接 ORM at L332/360+ openclaw_cron_pool.pyscale 决策混入、heartbeat ORM at L86/87 HTTP 层直接拼装 ORM/领域逻辑;前段干净 HTTP→lifecycle后段落差 decision-logsWorker 审计面)回归风险高 收进 service/repositoryrouter 只做参数校验+委托
S3 decision.pytask_queue.py 直接 session.execIntelligentEvalSessionDB 纯决策/队列逻辑与 SQLite 直接耦合,绕过 repository/read_model 可测试性受限(需真实 DB逻辑难单测 注入读模型/查询接口,逻辑层纯化
S4 cron_pool.py:267 handle_stuck_cronfrom ... import complete_task stuck→任务结算横跨两模块(运行时 import 卡死恢复的结算顺序分散 把 stuck→requeue/complete 结算收进 task_queue/统一作业模块
S5 openclaw_client.py 硬编码 gateway_token/container_name + subprocess 外部系统边界配置硬编码token 明文进进程列表;无独立测试(全 mock 换 token/环境需改代码;边界无守护 token/容器走 settings 注入subprocess 参数/解析加契约测试
S6 pages/CronPoolMonitor.tsx 自带 setInterval 前端轮询不一致Cron 池不走统一 usePolling无 stale 过滤;无测试 与智能评估读模型行为漂移;卸载/不可见不清理 抽统一轮询 hook + 页面测试
S7 Worker Skill 回路tasks/next/assign/complete + heartbeat 关键链路无端到端守护heartbeat→busy→kill→requeue 故障链路缺失) 深化动代码时最怕破坏的回环 补 e2e 测试 + router 下沉后契约守卫

非候选:repository.py 单文件多类——v2 方法论明确"不因文件长度拆分 Repository文件移动不算 deepening",不处理。


3. 测试覆盖矩阵

现有覆盖智能评估相关10 单元 + 9 集成 + 1 前端)

主题 单元 集成 前端 评价
生命周期状态机 model 测试 evals_api 完善
决策逻辑 decision 测试 分支覆盖好
任务队列 task_queue 测试 task_queue_api happy path 完整
Cron 池管理 cron_pool 测试 cron_pool_api 扩缩容路径完整
故障恢复 fault_tolerance fault_tolerance_e2e 双端恢复均有
告警 alerts 测试 metrics_alerts_api 规则覆盖好
快照 config_snapshot config_snapshot_api 完善
读模型 read_model 测试 intelligentEval.test 有 stale 过滤
Worker Skill worker_skill_api CRUD 有,回路无 e2e
Cron 池监控前端 0 测试 5s 轮询无守卫

6. 实施期间发现的新问题v1.1.1 P0 期间)

这里记录在按本扫描实施时新暴露的真实问题(不在原 seam/T 列表里),是测试防护网的首要价值。

6.1 assign_task 缺原子 CAS真 bugT1 暴露)

症状tests/integration/test_worker_task_resilience.py::test_concurrent_assign_via_two_sessions 失败。 两个独立 session两个 worker 进程)并发调用 assign_task 同一 pending task 时,两个都返回 True——任务被双认领。

根因backend/agenteval/intelligent_eval/task_queue.pyassign_task 是非原子的 读-检查-写

task = session.get(...); if task.status != "pending": return False
task.status = "assigned"; session.commit()

SQLitecheck_same_thread=False + StaticPool下两个 session 各自读到 pending、各自检查通过、各自 commit无行级锁/CAS。

影响Worker Skill 端点 POST /tasks/{id}/assign 可被双认领 → 两个 cron 同时执行同一任务 → 重复执行、可能双写 report/decision log。当前顺序 assign单 session通过只是因为 session 内 serializable。

修复方向(待开独立 issue不在 #3 范围):

  • assign_task 改为 UPDATE ... WHERE id=? AND status='pending',按 affected_rows 判定(真正的 CAS
  • 同样审计 complete_task 的并发(虽然 converge 测试通过,但非原子写)。
  • get_next_taskSELECT ... LIMIT 1 也非原子,应改 UPDATE ... WHERE status='pending' ... RETURNING 抢占式。

6.2 Webhook 缺重试 + 缺去重(两个真缺口T6 暴露)

症状test_webhook_retries_on_failuretest_webhook_dedupes_repeat_triggers xfail。 backend/agenteval/intelligent_eval/alerts.py::AlertManager._send_webhook

try:
    httpx.post(self.webhook_url, json=payload, timeout=5.0); ...
except Exception as e:
    _logger.error(f"Failed to send webhook: {e}")  # 吞掉,不重试
  • 无重试:首次失败仅 logwebhook_sent 保持 False,无后续尝试。
  • 无去重check_alerts 每次触发都会调 _send_webhook(alert);同一 alert 在恢复前可被重复发送。

影响:瞬时网络抖动丢告警;告警风暴期间 webhook 被反复打。

修复方向(待开独立 issue不在 #5 范围):

  • 重试:失败后排队 N 次重试(指数退避),或记入 outbox 表后台重发。
  • 去重:alert.webhook_sent=True 后跳过;或加 webhook_in_flight 锁。

当前状态:两个 xfail 守卫在 test_openclaw_client_and_webhook.pyCI 不阻塞;修复后移除 xfail 即转绿。

薄弱/缺失点(加固清单 T

薄弱/缺失点(加固清单 T

# 缺口 位置
T1 Worker Skill 三端点并发/竞争(双 worker 拉 next 不得同 taskcomplete 与 stuck 同时发生不丢任务) task_queue / worker 回路
T2 CronPoolMonitor 页面/hook 测试unmount 清理、不可见暂停轮询) 前端
T3 router 内嵌 ORM 契约测试decision-logs、heartbeat 一旦下沉的守卫) 集成
T4 auto-scale 振荡(连续调度不抖动翻转) cron_pool
T5 OpenClawClient 单元测试subprocess 参数、token 位置、JSON 解析失败路径) openclaw_client
T6 webhook 失败重试/去重(已发送但失败、重发不重复建 alert alerts
T7 告警→扩缩容端到端联动check_alerts → auto_scale 贯穿链路) 集成
T8 decision-logs 不可变性/去重(同 eval+type+context 不重复context 修改追加非覆盖) worker_skill
T9 stuck 检测临界值边界last_active_at 临界) cron_pool
T10 e2e 故障链路heartbeat→busy→kill→requeue 完整闭环) 集成 e2e

4. 深化 Phase 框架v2 风格,内容待 tickets 细化)

Phase 内容 对应 seam
P0 测试加固(防护网) 覆盖矩阵清零 + T1T10 补齐;不改生产代码
P1 收敛领域知识 时段/欠账/严重度 → shared 模块stuck 结算收敛 S1, S4
P2 解耦 DB decision/task_queue 走读模型/repository逻辑纯化 S3
P3 下沉 Router 逻辑 decision-logs/heartbeat/tasks 收进 service S2
P4 边界收尾 + ADR openclaw_client 配置化、前端轮询统一、删旧、记录 ADR S5, S6, S7

顺序依赖P0 先行(锁行为)→ P1收敛→ P2解耦为 P3 提供 repository 能力)→ P3router 下沉)→ P4边界+ADR。每阶段 CI 全绿、可独立合入。


5. 收尾发布v1.1.1

  • 测试/深化全部合入 main、CI 全绿后统一发布:bump 1.1.0 → 1.1.1 → 完整回归(后端全套 + 前端 + tsc + 生产构建 + ruff + 迁移往返)→ 生产部署演练(副本验证迁移/恢复/读取)→ CD 自动部署到生产1.0.0→1.1.1)→ 健康检查 + 关键路径 smoke
  • 附带收尾CI 镜像 push 到私有 registry持久化