Commit Graph

100 Commits

Author SHA1 Message Date
sinohqb
58c2ad0227 refactor(intelligent-eval): unify watchdog failures behind fail_eval seam
All checks were successful
CI / test (push) Successful in 3m10s
架构审查候选③(状态机归一):_TRANSITIONS 成为评估状态机的唯一真相。

三个 watchdog(planning 双闸 / executing 兜底 / 触发失败闸门)原先直接
row.status = FAILED 绕过转换表、手工重复写字段。收编到新的公开接缝
fail_eval(session, eval_id, reason, decision_type, context):表校验 →
repo CAS 条件写(status/plan_feedback/updated_at/completed_at 一条 SQL)
→ append_decision_log 留痕。

CAS 冲突(如用户在扫描间隙抢先取消)跳过并留日志,不当故障。API 路径
本已在表内,不动。新增 4 个契约测试,870 tests passed,零行为变化。
2026-08-21 03:35:05 +08:00
sinohqb
182b0e59cb refactor(intelligent-eval): extract scheduler runtime + internalize decision-log dedup
All checks were successful
CI / test (push) Successful in 3m9s
架构深化两则(架构审查候选①②):

① scheduler 抽取:web/app.py 约 400 行触发式执行编排(60s 扫描循环、
docker exec 触发、失败落账)沉入 intelligent_eval/scheduler.py,runtime
单例 start()/stop()/scan_once() 与 campaign_runtime 惯例一致;worker/planner
两处重复触发代码合并为一个触发原语;_supplement_decision_logs 归入
decision_logs.py。测试改为直接驱动 scan_once(interface 即测试面)。

② 决策日志去重内化:create_decision_log 的去重只服务 agent 上报路径;
新增 append_decision_log(平台落账纯追加)与 count_decisions(计数原语),
lifecycle/task_queue 全部平台落账切换,调用方不再需要塞 attempt 骗去重。

零行为变化:提示词、60s 节拍、编排顺序、闸门语义原样保留,866 tests passed。
2026-08-21 03:20:14 +08:00
sinohqb
d0487b54b4 fix(intelligent-eval): respect time-window slots before nudging analyst
冒烟发现 analyst_nudge 不考虑时间窗口:首会话完成后 10 分钟即催促,
但后续时段尚未到期,导致报告提前收敛、漏掉计划内会话。催促闸门新增
"窗口未结束且会话数未达计划则跳过";worker 触发指令同步明确仅当所有
时段会话都达终态才转 analyst。
2026-08-20 16:27:05 +08:00
sinohqb
eb4944a8bd feat(intelligent-eval): terminal-state discipline watchdogs (ADR-0011)
常见故障自愈有上限,超限收敛终态且可见:任务 attempts 上限、会话过期、
planning 双闸、executing 超窗兜底、触发失败计数判死、孤儿 agent 双管、
fire-and-forget 触发;open_session 预算硬闸门、settle 按终态区分、报告
scores 归一化;cron 池遗留面全删。
2026-08-20 14:34:17 +08:00
sinohqb
5de46d514a fix(intelligent-eval): trigger worker/planner with isolated session
All checks were successful
CI / test (push) Successful in 4m0s
t480 排查:评估 cd636d71 一直'等待 OpenClaw 创建会话',scan loop 每 60s 触发
worker,但 worker 被触发后 0 次工具调用、直接幻觉输出'评估 pending_approval'
(实际 executing),任务永不认领。

根因:openclaw agent --agent main 复用 main 持久 session,多次触发累积上下文
缓存(~12 万 token)后 LLM 不再执行 worker skill 的 API 步骤。
验证:独立 --session-id 触发 worker → 正常取任务、建会话、close。

修复:worker/planner 触发命令加 --session-id(每次唯一 agenteval-worker-*/planner-*),
避免 main session 污染;timeout 300→600(独立 session 首次加载 skill 更慢)。
测试:触发断言含 --session-id,901 passed
2026-08-18 17:22:30 +08:00
sinohqb
71d38ebef6 fix(intelligent-eval): settle stale tasks of finished evals
All checks were successful
CI / test (push) Successful in 3m57s
任务队列出现'评估已 completed 却有待认领/执行中任务'的残留:评估离开
executing 后,其 pending/assigned 任务无人清理(requeue_stale_assigned_tasks
只处理 executing 评估的 assigned,评估结束被跳过)。

- 新增 task_queue.settle_tasks_for_finished_evals:评估非 executing 时,
  其 pending/assigned 任务回收为 completed;executing 评估的任务保留
- scan loop 每 60s 在 requeue+scan 后调用清理
测试:+1(已结束评估的 pending/assigned 回收、executing 保留、幂等),901 passed
2026-08-18 16:04:46 +08:00
sinohqb
56d709c44f fix(intelligent-eval): reject report until all sessions closed
All checks were successful
CI / test (push) Successful in 3m59s
t480 实测:评估 completed 但 completed_sessions=0(进度 0%)。根因
(diagnosing-bugs):submit_report 无条件 CAS executing→completed,不看会话
状态——worker 建会话未 close 时,analyst 仍可提交报告把评估标完成。

- lifecycle.submit_report 加校验:存在会话时须全部 close(completed),
  否则抛 IntelligentEvalTransitionError(409)——杜绝'评估完成但进度 0%'
- 无会话的评估仍可直接提交(analyst 正常路径不变)
回归测试(诊断闭环 Phase 1 反馈环先红后绿):
- +test_submit_report_rejects_when_sessions_not_closed(running 会话→409)
- +test_submit_report_allows_when_sessions_closed(全 close→200)
900 passed
2026-08-18 15:30:51 +08:00
sinohqb
60c54a67e4 fix(intelligent-eval): parse minute-level time slots (1h windows)
All checks were successful
CI / test (push) Successful in 3m54s
planner 对短窗口(1h)产出分钟级时段(如 0-20min/20-40min/40-60min),
但 parse_time_slot 只支持小时级(8-10h),分钟格式解析失败返回 None →
is_slot_due=False → 审批后评估永不入队、不触发 worker。
- parse_time_slot 支持 h/min 后缀,统一换算成小时(float)返回
- is_slot_due/get_current_slot/count_sessions_in_slot 用 timedelta(hours=float)
  兼容两种格式;decision._parse_time_slot 类型标注同步 float
测试:+1(分钟格式时段解析与到期判断),898 passed
2026-08-18 13:15:46 +08:00
sinohqb
9d87ecf736 fix(intelligent-eval): trigger OpenClaw planner for planning evals
All checks were successful
CI / test (push) Successful in 3m59s
方案③只自动化了 executing(worker)→completed(analyst),缺少 planning 阶段的
planner 触发——新建/被打回的评估永远停在 planning(无任何机制唤醒
agenteval-intelligent-planner skill)。
- 新增 _has_planning_eval + _trigger_intelligent_planner:scan loop 每 60s
  对 planning 状态评估触发 planner skill(产出粗计划并 PUT /plan 提交),
  与 worker 触发同模式(docker exec openclaw agent -m 带'立即完成'语义)
- scan loop 在 worker 触发后追加 planner 触发
测试:+2(无 planning 不触发 / 有 planning 触发 planner skill),897 passed
2026-08-18 11:30:02 +08:00
sinohqb
cc2ac8da89 feat(intelligent-eval): paginate the eval list
All checks were successful
CI / test (push) Successful in 4m5s
GET /api/intelligent-evals 支持 page/page_size(默认不传仍返回全部,向后兼容):
repository 加 count/list_page,lifecycle 加 list_evals_page,router 返回 total。
前端服务端分页:useIntelligentEvalRead 接 page/pageSize,list 存 total,
IntelligentEvals 表格 showSizeChanger + 页码切换重新加载;5s 轮询保持当前页。
测试:+3 后端分页 + hook 页码透传/总数断言,895 passed,vitest 19 passed
2026-08-17 14:09:17 +08:00
sinohqb
b4f9c887f4 feat(intelligent-eval): task queue monitor (方案③可视化)
All checks were successful
CI / test (push) Successful in 4m1s
方案③的定时触发(scan loop 每 60s 入队 + 触发 worker)此前只有 Worker
消费端 API,无可查看的列表。新增:
- GET /api/intelligent-evals/tasks:任务明细(含评估名/状态)+ 状态分布统计
  (注册在 /{eval_id} 之前避免被捕获为 eval_id="tasks")
- 前端 TaskQueueMonitor 组件 + 智能评估页任务队列入口:5s 轮询
  (usePolling),状态卡 + 状态筛选 + 明细表
测试:+3(列表/筛选/不被 {eval_id} 遮蔽),892 passed,tsc 通过
2026-08-17 13:57:00 +08:00
sinohqb
b0969ae582 feat(intelligent-eval): backfill decision logs for completed evals
All checks were successful
CI / test (push) Successful in 4m2s
COMPLETED 状态的评估(历史/异常路径)可能完全没有决策日志,
导致旧报告决策过程为空。扩展 _supplement_decision_logs 支持
COMPLETED:按时段补 execute_session + 补 start_analysis(历史回填),
scan loop 每分钟自动回填,无需一次性脚本。幂等,只补缺失类型。
2026-08-17 13:06:27 +08:00
sinohqb
32f63e80ae style: ruff format (decision-log backfill)
Some checks failed
CI / test (push) Failing after 36s
2026-08-17 05:12:09 +08:00
sinohqb
25920280f6 feat(intelligent-eval): platform audit backfill for decision logs + disable legacy cron workers
Some checks failed
CI / test (push) Failing after 35s
- _supplement_decision_logs: executing evals missing a decision log get a
  platform-derived execute_session (deficit) or start_analysis (all sessions
  done) entry. Audit backfill only — records observable state, does not change
  agent execution. Called each scan tick after requeue+scan.
- t480 legacy cron workers (5) disabled: superseded by platform-triggered
  headless agent (plan C); they kept firing every minute and failing on
  Channel-required.
2026-08-17 05:11:18 +08:00
sinohqb
71c7cd3d39 fix(intelligent-eval): requeue stale assigned tasks (worker crash recovery)
All checks were successful
CI / test (push) Successful in 3m45s
方案③ worker 由平台触发 openclaw agent(cron=manual-run,非真实 cron),
fault_tolerance 的 stuck 检测不适用——agent 中断/失败时任务永久卡 assigned,
scan 只查 pending 不再入队(死锁)。

requeue_stale_assigned_tasks:assigned 超过 10 分钟且评估仍 executing 的
任务重置为 pending(清空认领),平台 scan 循环随后重新触发 worker 重试。
接入 scan loop,每轮先 requeue 再 scan。
2026-08-17 03:30:42 +08:00
sinohqb
8e65e2e7b0 fix(intelligent-eval): worker trigger message must demand immediate execution
All checks were successful
CI / test (push) Successful in 3m47s
openclaw agent has no cron state; a bare 'agenteval-intelligent-worker'
message made the worker skill decide then 'wait for the next tick',
deadlocking (task assigned, session never created). The trigger message now
demands '立即完成当前任务,不要等待下一节拍' and, when all sessions are
done, delegates to agenteval-intelligent-analyst. Verified end-to-end on
t480: 1h-window eval went executing -> session (2 real turns) -> close ->
report -> completed, fully agent-driven, no external IM channel.
2026-08-17 02:57:08 +08:00
sinohqb
775b070bab feat(intelligent-eval): platform triggers OpenClaw agent as worker (avoid external IM channel)
All checks were successful
CI / test (push) Successful in 3m48s
OpenClaw cron requires a channel (announce->last fail-closed); webchat is a
Control-UI feature, not an addressable channel, and platform-side static
execution would degrade the intelligent eval into a static evaluation.

Solution (plan C): the platform keeps the scan loop and, when the queue has
a pending task, invokes the headless agent:
  docker exec openclaw-eval openclaw agent --agent main \
    -m agenteval-intelligent-worker --json
--deliver defaults to false, so no cron delivery channel is involved. The
worker skill runs unchanged under the OpenClaw agent (LLM decisions +
evaluator/analyst skills). Verified headless invocation returns ok.
2026-08-17 02:37:37 +08:00
sinohqb
5836b84681 fix(intelligent-eval): add lifespan scan-loop for worker task enqueue
All checks were successful
CI / test (push) Successful in 3m53s
scan_and_enqueue_tasks had no scheduler: the OpenClaw Worker wakes every
minute but the platform never enqueued executing evals, so the queue was
always empty. lifespan now starts an asyncio background task that scans
executing intelligent evals every 60s (aligned with the Worker wake),
cancelled cleanly on shutdown. Verified by a new startup test (879 total).
2026-08-17 02:08:40 +08:00
sinohqb
4bcab065f1 fix(decision-logs): dedupe on (eval_id, decision_type, context) (resolves T8)
Some checks failed
CI / test (push) Failing after 37s
create_decision_log now checks for an existing log with the same
(eval_id, decision_type, context) tuple before inserting. If found, it
returns the existing row's dict instead of appending a duplicate. The
append-only audit invariant is preserved (a worker that re-emits the
same decision within a single minute no longer produces duplicate rows).

Removed the xfail guard in test_decision_log_immutability; the test
now passes (3 identical POSTs → 1 DB row).
2026-08-14 15:14:05 +08:00
sinohqb
6d32653675 fix(intelligent-eval): link check_alerts to auto-scale_up (resolves T7)
All checks were successful
CI / test (push) Successful in 3m56s
AlertManager gains an optional openclaw_client. check_alerts records
each newly created alert and AlertManager.maybe_autoscale (called
from the async router for each alert) invokes cron_pool.scale_up(1).
scale_up itself caps at MAX_POOL_SIZE so repeated invocations are safe.

Removed the xfail guard in test_alert_autoscale_link; rewrote the test
to use task_backlog (duration_minutes=0) so a single check_alerts call
fires an alert and triggers auto-scale.
2026-08-14 15:08:24 +08:00
sinohqb
f85eca11ca fix(alerts): webhook retry + dedupe (resolves §6.2)
All checks were successful
CI / test (push) Successful in 3m57s
_send_webhook:
- Dedupe: skip if alert.webhook_sent is already True (guards against
  repeated check_alerts ticks re-sending the same alert).
- Retry: up to 3 attempts with exponential backoff (1s, 2s) before
  giving up. webhook_sent=True is persisted only on success.

Two xfail guards in test_openclaw_client_and_webhook now pass (876/4 xfail).
2026-08-14 14:54:57 +08:00
sinohqb
38e3817433 fix(intelligent-eval): atomic CAS in assign_task and complete_task (resolves §6.1)
Some checks failed
CI / test (push) Has been cancelled
Replace read-check-write in task_queue.assign_task with UPDATE...WHERE
status='pending' and decide on rowcount so two concurrent workers
cannot both claim the same task. Also harden complete_task with the
same CAS pattern (status='assigned') so a worker + stuck-handler
double-complete leaves the DB in one state.

The xfail guard in test_worker_task_resilience now passes (4/4).
2026-08-14 14:52:34 +08:00
sinohqb
b5bcd13fa0 test(intelligent-eval): add #6 frontend + router contract + immutability + alert-autoscale link tests
Some checks failed
CI / test (push) Failing after 4m34s
T2 frontend CronPoolMonitor: polls every 5s, unmount clears interval,
   plus it.fails guard for missing visibilitychange listener (S6).
T3 router ORM contract: heartbeat updates fields + 404, decision-logs
   POST persists + 404, GET lists inserted (guards S2 — must continue to
   pass after router handlers move into a service in P3).
T8 decision-log immutability: append-only on context change passes;
   dedupe of identical (decision_type, context) is xfail (real gap).
T7 alert→auto-scale: task_backlog alert recorded on first call (passes);
   check_alerts never invokes auto_scale is xfail (real gap, §6.4).

All real gaps are logged in .scratch/v111-architecture-scan.md §6.
2026-08-13 04:03:17 +08:00
sinohqb
a03067720b test(intelligent-eval): add openclaw_client + webhook tests (#5)
All checks were successful
CI / test (push) Successful in 4m18s
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
sinohqb
4c45dba95d test(intelligent-eval): add cron_pool boundary tests (#4)
Some checks failed
CI / test (push) Has been cancelled
T4 auto-scale boundary: busy/total == 0.8 (exact threshold) must not fire
T4 auto-scale oscillation: repeated flips across 0.8 must respect MIN/MAX bounds
T9 stuck-detection critical edge: strict '<' semantics at 10min threshold
T9 detect_stuck_crons ignores non-busy: idle/stuck crons excluded even if stale
2026-08-13 02:54:21 +08:00
sinohqb
3025dcd255 test(intelligent-eval): add worker task resilience tests (#3)
All checks were successful
CI / test (push) Successful in 4m21s
T1 concurrent assign: only one worker wins (sequential + dual-session)
T1 complete×stuck convergence: task reaches terminal state, never lost
T10 fault loop: heartbeat busy → cron stuck → handler fails task + creates retry

发现真 bug(assign_task 缺原子 CAS,详见 .scratch/v111-architecture-scan.md §6.1):
两个独立 session 并发 assign 同一 task 双认领。
以 xfail(strict=False) 留守卫,CI 不阻塞;修复后移除 xfail 即转绿。
该 bug 修复不在本 #3 范围,待开独立 issue。
2026-08-13 02:45:56 +08:00
sinohqb
2e7d419f05 feat(intelligent-eval): implement monitoring and alerting (ticket 07)
- Add metrics.py with pool utilization, task backlog, stuck rate, avg processing time, eval completion rate
- Add alerts.py with alert rules (pool utilization > 90%, task backlog > 50, stuck rate > 10%)
- Implement alert history and webhook notifications
- Add metrics and alerts APIs
- Add database migration for alert history table
- Add 11 unit tests for metrics, 10 unit tests for alerts, 8 integration tests
- Update migration tests to include new alert history table

All 853 tests passing.
2026-08-12 10:41:15 +08:00
sinohqb
1d9228fd86 feat(intelligent-eval): implement fault tolerance and recovery (ticket 06)
- Add fault_tolerance.py with stuck cron detection and handling
- Implement state reconciliation (platform DB vs OpenClaw state)
- Implement platform restart recovery (requeue inactive tasks)
- Implement OpenClaw restart recovery (sync cron states)
- Add 6 unit tests and 5 integration tests

All 824 tests passing.
2026-08-12 10:30:05 +08:00
sinohqb
e6f98aaa6d feat(intelligent-eval): implement config snapshot management (ticket 05)
- Add config_snapshot.py with save/list/get/compare functions
- Auto-save snapshots on eval creation and plan submission
- Implement snapshot query APIs (list, get single)
- Implement snapshot comparison API (diff two snapshots)
- Add 8 unit tests and 7 integration tests

Snapshots track config changes over time (created/plan_submitted/config_updated).
All 813 tests passing.
2026-08-12 10:19:07 +08:00
sinohqb
fe3399297c feat(intelligent-eval): implement decision logic and e2e flow (ticket 04)
- Add decision.py with worker decision logic (execute_session/wait/start_analysis)
- Implement time slot parsing and current slot detection
- Implement session deficit calculation per time slot
- Implement high severity issue detection
- Implement eval completion detection
- Add 12 unit tests for decision logic
- Add 2 end-to-end tests for complete lifecycle

All 798 tests passing.
2026-08-12 10:10:42 +08:00
sinohqb
30b9cac224 feat(intelligent-eval): implement worker skill and APIs (ticket 03)
- Create agenteval-intelligent-worker SKILL.md with decision logic
- Implement heartbeat API (POST /api/openclaw/crons/{id}/heartbeat)
- Implement decision log API (POST /api/intelligent-evals/{id}/decision-logs)
- Skill includes idle/busy state management and cron state handling
- Deployment script already syncs skills automatically
- Add 6 integration tests

All 784 tests passing.
2026-08-12 10:01:56 +08:00
sinohqb
2ff023a65b feat(intelligent-eval): implement cron pool management (ticket 02)
- Add OpenClawClient wrapping CLI commands (create/delete/list crons)
- Implement pool initialization, scale up/down, auto-scaling logic
- Implement cron state sync and stuck cron detection
- Add pool status and manual scaling APIs
- Add 13 unit tests and 5 integration tests

Pool automatically scales between 5-20 crons based on load.
All 778 tests passing.
2026-08-12 09:47:04 +08:00
sinohqb
1aa453ef0a feat(intelligent-eval): add cron pool data model and task queue API
Implement Ticket 01 of intelligent eval cron pool architecture (ADR-0007):

- Add 4 new tables: task_queue, cron_pool, config_snapshots, decision_logs
- Implement task enqueueing logic with priority calculation
- Implement task assignment and completion APIs
- Add unit tests (9) and integration tests (7)
- Update CONTEXT.md with new vocabulary
- Add ADR-0007 documenting cron pool architecture decision

All 760 tests passing.
2026-08-12 02:13:21 +08:00
sinohqb
1782b245bf refactor(architecture): deepen campaign runtime modules 2026-08-11 13:18:48 +08:00
sinohqb
864ae2b7fe fix(review): address release correctness findings 2026-08-09 03:20:40 +08:00
sinohqb
62485684ca fix(architecture): enforce lifecycle consistency 2026-08-07 10:59:27 +08:00
sinohqb
c896ab3f71 refactor(architecture): deepen evaluation lifecycle and read model 2026-08-07 03:11:37 +08:00
sinohqb
9cdbc41808 docs(intelligent-eval): commit v1.0 spec, tickets, and post-v1.0 improvements
All 8 tickets' acceptance criteria checked off (incl. the real OpenClaw
E2E verified on t480). Trivial import-sort fix from ruff included.
2026-08-05 14:01:24 +08:00
sinohqb
1317552701 feat(intelligent-eval): add backend for OpenClaw-driven intelligent evaluation (tickets 01-04)
Introduce 智能评估 as an evaluation paradigm parallel to static evaluation,
driven by OpenClaw. The platform supplies storage, lifecycle, and reporting;
OpenClaw plans and executes.

- Data model: IntelligentEval + Session + Message tables (new, not reusing exploration)
- Lifecycle state machine: draft → planning → pending_approval → executing → completed/cancelled/failed
- Session API: create/message (channel-forwarded)/close with turn accounting
- Report API: pydantic-validated structured report, executing → completed, Markdown export (pure renderer)
- Alembic migration for the three tables; domain glossary added to CONTEXT.md
2026-08-05 03:18:52 +08:00
sinohqb
c24998c762 refactor(metrics): extract dashboard aggregation to compute_dashboard
仪表盘聚合逻辑从 stats.py router 下沉到 metrics.py 的 compute_dashboard
纯函数。_settled 重命名为 settled_runs 并公开,_ts 重命名为 _sortable_ts。
router 从 40 行聚合逻辑缩到 5 行,只负责数据获取和序列化。

- 新增 compute_dashboard(runs, scenario_names, target_names) -> dict
- 新增 settled_runs(runs) 公开接口(原 _settled)
- trend 端点同步迁移到 settled_runs
- 5 个新测试覆盖 dashboard 聚合逻辑
2026-08-04 11:36:55 +08:00
sinohqb
42be31dd1f feat(report): add load_campaign_view as unified campaign read model
活动级读模型单一出口:一次取齐报告 / 探索 / 分析 / 对比四大数据源。
markdown handler 从 30 行拼装逻辑缩到 3 行;分析执行器同步迁移。
comparison.py 内部的 8 次 load_campaign_report 调用暂不动(跨请求冗余,
缓存收益有限,改动风险高)。

- 新增 load_campaign_view(session, campaign) -> dict[str, Any]
- 返回 {report, exploration, analysis, comparison} 四键
- 迁移 markdown handler 和分析执行器两个调用点
- 4 个新测试覆盖 view 的组装逻辑
2026-08-04 11:33:45 +08:00
sinohqb
2fddce8c92 refactor(case-verdict): extract build_case_evidence as single evidence-construction seam
用例判定证据构建收敛到 case_verdict.py 的 build_case_evidence 纯函数,
report.py 和 runs.py 各删 ~15 行重复逻辑,换一行调用。locality 回归:
证据构建改一处,全局生效。

- 新增 build_case_evidence(turns, results) -> dict[str, CaseEvidence]
- report.py:76-83 证据构建替换为一行调用
- runs.py:175-201 证据构建替换为一行调用
- 5 个新测试覆盖 build_case_evidence(纯函数,无 DB 依赖)
2026-08-04 11:23:56 +08:00
sinohqb
2b6cab6cb2 feat(comparison): unify read model and validation for period comparison
周期对比读模型升位为单一出口(load_comparison_view),GET/POST/markdown
三处调用点统一走同一 view 投影,消除「取数三件套」重复。校验逻辑收敛到
validate_comparison_request,router 捕获映射 400,执行器捕获落 failed 行,
校验顺序权威不再漂移。

- 新增 load_comparison_view:无行返回 status=none + auto_baseline,有行
  返回完整 comparison dict(含 model_name 标签)+ metric_diff
- 新增 validate_comparison_request:活动终态 → 模型 → 基线 → 分析,违
  规抛 ComparisonError
- execute_campaign_comparison 内联校验替换为 validate_comparison_request
  调用,catch ComparisonError 落 failed 行
- router 三处迁移:GET /comparison、POST /comparison、markdown 导出
- 删除 build_comparison_payload(已吸收进 load_comparison_view)
- 8 个新测试覆盖读模型三态 + 校验五错
2026-08-04 10:49:14 +08:00
sinohqb
f3a528611e refactor(tasks): route LLM background tasks through TaskRegistry
架构保养第二轮候选 1:分析 / 周期对比 / judge 复核三条 LLM 任务链
收进各自的模块级 TaskRegistry(强引用防 GC、按 id 幂等、shutdown
统一收敛),删除 judge 的 _BACKGROUND_TASKS 私货,start_* 不再返回
无人消费的 Task。启动清理块补两笔 orphan 清扫:滞留的 generating
分析与对比行标记为 failed,与僵尸运行清扫同构。新增 7 个单测。
2026-08-04 09:58:20 +08:00
sinohqb
df76edcf55 refactor(exploration): move ledger and state machine into domain modules
Some checks failed
CI / test (push) Failing after 33s
架构保养候选 3:探索生命周期的账本规则与状态机从 HTTP 层落入
exploration/lifecycle.py(open/conduct/close)与 patrol.py(巡检读模型),
违规改用类型化领域异常(NotFound/Guardrail/Channel),router 瘦回纯
HTTP 翻译(404/409/502 映射),领域层不再依赖 fastapi,可脱离
TestClient 直测(新增 12 个单元测试)。
2026-08-04 03:46:51 +08:00
sinohqb
38849d46f1 refactor(repository): narrow atomic updates for patrol/cancel/scheduler writes
全行 update 逼着调用方承诺「持有最新完整快照」,巡检水位、活动取消、
调度循环三方并发写入会互相覆盖(后写者抹掉先写者的 summary/status)。
CampaignRepository 新增三个窄口径原子操作:touch_patrol_watermark、
mark_cancelled、save_scheduler_state,各自只写自己的列;三处调用点迁移。
2026-08-04 03:39:42 +08:00
sinohqb
f8d8450b1e refactor(report): unify campaign report loading behind one read model
「活动报告取数三件套」此前在报告/markdown/分析/对比等 7 处手写重复,
唯一深化产物 build_campaign_report_dict 被锁在周期对比私有角落。
升位为 report.py 的 load_campaign_report(session, campaign) 单一出口
(探索线 summarize_campaign_exploration 同口径),并把 8 处
scenario_names 推导式收敛为 ScenarioRepository.name_map() 窄方法。
纯结构重排、零行为变更,572 项测试全绿。
2026-08-04 03:30:29 +08:00
sinohqb
936640fb36 fix(exploration): include all judge findings instead of poor-only
Ticket 05 asks the judge review conclusions to flow into the report
verbatim; the aggregation silently dropped good/acceptable dimensions.
Collect every finding sorted poor-first and color drawer tags by rating.
2026-08-04 02:45:41 +08:00
sinohqb
9abf572949 fix(exploration): flatten dict reply payloads instead of storing str(dict)
E2E on t480 showed assistant bubbles rendering {'content': '...'} because
tutu replies carry msgBody as a parsed object and the router stored
str(reply.content). Coerce to the inner text before persisting.
2026-08-04 02:26:24 +08:00
sinohqb
62f7031b5b feat(exploration): expire dangling sessions on campaign finalize 2026-08-04 01:23:37 +08:00