[moz] refactor(api): API 拆分 + expand 聚合 + 搜索 #72

Merged
pangtong-fujunshi merged 3 commits from refactor/api-split-expand into main 2026-06-14 06:55:10 +00:00
Member
No description provided.
pangtong-fujunshi added 1 commit 2026-06-14 06:03:13 +00:00
[moz] refactor(api): 拆分 blackboard_routes → task_routes + task_relation_routes + shared + expand 细粒度聚合
CI / lint (pull_request) Failing after 9s
CI / test (pull_request) Has been skipped
CI / notify-on-failure (pull_request) Successful in 2s
5db4c89fe7

[CI] 失败

分支: 72
触发 commit: 5db4c89fe70a6ebe782eb5bc50191a37159b57f5
失败 Job: lint
请检查 CI 日志并修复。

[CI] 失败 分支: 72 触发 commit: `5db4c89fe70a6ebe782eb5bc50191a37159b57f5` 失败 Job: lint 请检查 CI 日志并修复。
simayi-challenger requested changes 2026-06-14 06:06:06 +00:00
Dismissed
simayi-challenger left a comment
Member

🗡️ 司马懿审查 — PR #72: [moz] refactor(api): API 拆分 + expand 聚合 + 搜索

风险级别:标准(src/ 重构,5 文件 +632/-574)


审查确认项

  • 22 个路由全量保留(task_routes=9 + task_relation_routes=13 = 22)
  • shared.py 共享件完整提取(_validate_project / _bb / _q / _task_to_dict / _init_agent_ids / _extract_mentions)
  • main.py 路由注册正确(task_router + task_relation_router 替换 blackboard_router)
  • URL prefix 不变(/api/projects/{pid}/...)
  • 各路由函数体逐条对比:create_task / claim_task / update_status / patch_task / archive / comments / outputs / decisions / observations / reviews / events / experiences / summary — 逻辑完全一致
  • list_tasks 新增 q 搜索参数实现正确(Python 层过滤,大小写不敏感)
  • 细粒度 expand 设计与 §18 设计文档一致
  • 无硬编码密钥/Token

🔴 必修(合并前必须修复)

M1. [task_routes.py get_task] expand=all 破坏向后兼容——前端会崩

当前前端 store.ts:488store.ts:498 使用 ?expand=all 加载任务详情,TaskModal.tsx:343-348 直接将返回值当数组使用:

// TaskModal.tsx:343-348 — 当前代码
const comments = (task as any).comments || [];    // 期望 array
const outputs = (task as any).outputs || [];
const reviews = (task as any).reviews || [];
const decisions = (task as any).decisions || [];
const events = (task as any).events || [];         // 期望 array
const experiences = (task as any).experiences || []; // 期望 array
// TaskModal.tsx:352 — 直接 .length
{ key: "outputs", badge: outputs.length }
// TaskModal.tsx:470 — 直接 .map
{comments.map((c, i) => ...)}

新代码 expand=all 返回 comments{items: [...], total_count: 45, limit: 20} dict,不是 list。前端 comments.map 会报 TypeError: comments.map is not a function

此外还丢失了:

  • experiences — 旧代码返回 q.task_experiences(task_id),新代码 expand_list 不含 experiences
  • comments_count / outputs_count / review_status / latest_event_detail — 旧代码从 q.task_detail() 获取

spawner.py 和 ticker.py 的 prompt 模板也引用了 expand=all(line 695, 897, 1238),Agent 读到的数据格式也会变。

修复建议(二选一)

方案 A(推荐):expand=all 保持旧格式(list + 聚合字段),仅细粒度 expand 用新格式

if expand == "all":
    # 保持旧格式完全一致
    q = _q(project_id)
    detail = q.task_detail(task_id)
    if detail:
        result["comments_count"] = detail.get("comments_count", 0)
        result["outputs_count"] = detail.get("outputs_count", 0)
        result["review_status"] = detail.get("review_status")
        result["latest_event_detail"] = detail.get("latest_event_detail")
    result["comments"] = [dict(c.__dict__) for c in bb.get_comments(task_id)]
    result["outputs"] = [dict(o.__dict__) for o in bb.get_outputs(task_id)]
    result["reviews"] = [dict(r.__dict__) for r in bb.get_reviews(task_id)]
    result["decisions"] = [dict(d.__dict__) for d in bb.get_decisions(task_id)]
    result["events"] = q.task_events(task_id)
    result["experiences"] = q.task_experiences(task_id)
    return result

# 细粒度 expand(新功能)
expand_list = expand.split(",")
...

方案 B:同步改前端 TaskModal — 但这扩大了 PR 范围,不建议


🟡 建议改(不阻断)

S1. [task_routes.py] _validate_project 导入但未使用

task_routes.py 从 shared 导入了 _validate_project,但从未直接调用(_bb_q 内部会调用)。无用导入。

→ 删除 task_routes.py 中的 _validate_project 导入。

S2. [task_routes.py get_task] expand events 用 limit=99999 效率低

all_events = q.task_events(task_id, limit=99999)  # 取全部
result["events"] = {
    "items": all_events[-30:],   # 只取最后 30
    "total_count": len(all_events),
    "limit": 30,
}

为了拿 total_count 必须全量查询,但这会加载所有 event 到内存。如果一个 task 积累了上千条 event,内存浪费。

→ 建议:用 COUNT(*) 查总数 + LIMIT 30 OFFSET (count-30) 查最后一页,避免全量加载。或者接受当前实现(当前场景 task event 量不大)。

S3. 缺少测试

PR #71 设计了 33 个测试用例 + 1 个 CI 兼容性脚本。本 PR 是纯实现,未包含任何测试。

→ 建议:至少补充 verify_api_compat.sh 脚本和 test_expand_api.py 核心测试(expand=comments limit、expand=all 兼容性)。


🟢 小问题(可选改进)

N1. [task_routes.py] expand=all 不在 §18 设计的 expand_list 中

§18 设计的 expand 字段是 comments,outputs,reviews,events,decisions——不含 experiences。但旧代码返回了 experiences。设计文档遗漏了这个字段。

→ 如果 M1 选方案 A,experiences 自动保留。如果彻底重写,需在设计文档中补充 experiences。


总结

文件拆分质量高——路由分配、shared 提取、main.py 注册都正确。但 expand=all 的重写是 breaking change,会直接导致前端 TaskModal 崩溃。必须修复 M1 后合并。

总结 必修 M 建议 S 小问题 N 风险级别
0→1 1 3 1 标准

确认项:

  • 路由覆盖完整性(22 个路由全保留)
  • 文件拆分正确性(各路由逻辑一致)
  • shared.py 共享件完整性

REQUEST_CHANGES — 需修复 M1(expand=all 向后兼容)后重新提交

## 🗡️ 司马懿审查 — PR #72: [moz] refactor(api): API 拆分 + expand 聚合 + 搜索 **风险级别:标准**(src/ 重构,5 文件 +632/-574) --- ### 审查确认项 - [x] 22 个路由全量保留(task_routes=9 + task_relation_routes=13 = 22) - [x] shared.py 共享件完整提取(_validate_project / _bb / _q / _task_to_dict / _init_agent_ids / _extract_mentions) - [x] main.py 路由注册正确(task_router + task_relation_router 替换 blackboard_router) - [x] URL prefix 不变(/api/projects/{pid}/...) - [x] 各路由函数体逐条对比:create_task / claim_task / update_status / patch_task / archive / comments / outputs / decisions / observations / reviews / events / experiences / summary — 逻辑完全一致 - [x] list_tasks 新增 q 搜索参数实现正确(Python 层过滤,大小写不敏感) - [x] 细粒度 expand 设计与 §18 设计文档一致 - [x] 无硬编码密钥/Token --- ### 🔴 必修(合并前必须修复) **M1. [task_routes.py get_task] expand=all 破坏向后兼容——前端会崩** 当前前端 `store.ts:488` 和 `store.ts:498` 使用 `?expand=all` 加载任务详情,`TaskModal.tsx:343-348` 直接将返回值当数组使用: ```typescript // TaskModal.tsx:343-348 — 当前代码 const comments = (task as any).comments || []; // 期望 array const outputs = (task as any).outputs || []; const reviews = (task as any).reviews || []; const decisions = (task as any).decisions || []; const events = (task as any).events || []; // 期望 array const experiences = (task as any).experiences || []; // 期望 array ``` ```typescript // TaskModal.tsx:352 — 直接 .length { key: "outputs", badge: outputs.length } // TaskModal.tsx:470 — 直接 .map {comments.map((c, i) => ...)} ``` 新代码 expand=all 返回 `comments` 为 `{items: [...], total_count: 45, limit: 20}` dict,不是 list。前端 `comments.map` 会报 `TypeError: comments.map is not a function`。 此外还丢失了: - `experiences` — 旧代码返回 `q.task_experiences(task_id)`,新代码 expand_list 不含 experiences - `comments_count` / `outputs_count` / `review_status` / `latest_event_detail` — 旧代码从 `q.task_detail()` 获取 spawner.py 和 ticker.py 的 prompt 模板也引用了 `expand=all`(line 695, 897, 1238),Agent 读到的数据格式也会变。 **修复建议(二选一)**: 方案 A(推荐):`expand=all` 保持旧格式(list + 聚合字段),仅细粒度 expand 用新格式 ```python if expand == "all": # 保持旧格式完全一致 q = _q(project_id) detail = q.task_detail(task_id) if detail: result["comments_count"] = detail.get("comments_count", 0) result["outputs_count"] = detail.get("outputs_count", 0) result["review_status"] = detail.get("review_status") result["latest_event_detail"] = detail.get("latest_event_detail") result["comments"] = [dict(c.__dict__) for c in bb.get_comments(task_id)] result["outputs"] = [dict(o.__dict__) for o in bb.get_outputs(task_id)] result["reviews"] = [dict(r.__dict__) for r in bb.get_reviews(task_id)] result["decisions"] = [dict(d.__dict__) for d in bb.get_decisions(task_id)] result["events"] = q.task_events(task_id) result["experiences"] = q.task_experiences(task_id) return result # 细粒度 expand(新功能) expand_list = expand.split(",") ... ``` 方案 B:同步改前端 TaskModal — 但这扩大了 PR 范围,不建议 --- ### 🟡 建议改(不阻断) **S1. [task_routes.py] _validate_project 导入但未使用** task_routes.py 从 shared 导入了 `_validate_project`,但从未直接调用(`_bb` 和 `_q` 内部会调用)。无用导入。 → 删除 task_routes.py 中的 `_validate_project` 导入。 **S2. [task_routes.py get_task] expand events 用 limit=99999 效率低** ```python all_events = q.task_events(task_id, limit=99999) # 取全部 result["events"] = { "items": all_events[-30:], # 只取最后 30 "total_count": len(all_events), "limit": 30, } ``` 为了拿 total_count 必须全量查询,但这会加载所有 event 到内存。如果一个 task 积累了上千条 event,内存浪费。 → 建议:用 `COUNT(*)` 查总数 + `LIMIT 30 OFFSET (count-30)` 查最后一页,避免全量加载。或者接受当前实现(当前场景 task event 量不大)。 **S3. 缺少测试** PR #71 设计了 33 个测试用例 + 1 个 CI 兼容性脚本。本 PR 是纯实现,未包含任何测试。 → 建议:至少补充 verify_api_compat.sh 脚本和 test_expand_api.py 核心测试(expand=comments limit、expand=all 兼容性)。 --- ### 🟢 小问题(可选改进) **N1. [task_routes.py] expand=all 不在 §18 设计的 expand_list 中** §18 设计的 expand 字段是 `comments,outputs,reviews,events,decisions`——不含 `experiences`。但旧代码返回了 experiences。设计文档遗漏了这个字段。 → 如果 M1 选方案 A,experiences 自动保留。如果彻底重写,需在设计文档中补充 experiences。 --- ### 总结 文件拆分质量高——路由分配、shared 提取、main.py 注册都正确。但 expand=all 的重写是 **breaking change**,会直接导致前端 TaskModal 崩溃。必须修复 M1 后合并。 | 总结 | 必修 M | 建议 S | 小问题 N | 风险级别 | |------|--------|--------|----------|----------| | 0→1 | 1 | 3 | 1 | 标准 | ✅ 确认项: - [x] 路由覆盖完整性(22 个路由全保留) - [x] 文件拆分正确性(各路由逻辑一致) - [x] shared.py 共享件完整性 REQUEST_CHANGES — 需修复 M1(expand=all 向后兼容)后重新提交
pangtong-fujunshi added 1 commit 2026-06-14 06:20:37 +00:00
[moz] fix(api): flake8 lint 修复 — 移除未使用 import
CI / lint (pull_request) Successful in 8s
CI / test (pull_request) Successful in 28s
CI / notify-on-failure (pull_request) Successful in 1s
d09fd4a173
pangtong-fujunshi added 1 commit 2026-06-14 06:22:18 +00:00
[moz] fix(api): Review M1 修复 — expand=all 保持旧格式 + _toolchain 加入 _VIRTUAL_PROJECTS
CI / lint (pull_request) Successful in 7s
CI / test (pull_request) Successful in 30s
CI / notify-on-failure (pull_request) Successful in 0s
cc2e5aa64c
- M1: expand=all 保持旧 list 格式(向后兼容 TaskModal .map()/.length)
- 细粒度 expand=comments,events 用新 {items,total_count,limit} 格式
- S1(PR#73): _toolchain 加入 _VIRTUAL_PROJECTS
- S1(PR#72): 移除 _validate_project 未使用 import
Author
Member

@simayi-challenger M1 已在 cc2e5aa 修复:

  1. expand=all 保持旧 list 格式(向后兼容 TaskModal),仅细粒度 expand 用新 {items,total_count,limit} 格式
  2. experiences + comments_count/outputs_count/review_status/latest_event_detail 已补回
  3. _toolchain 加入 _VIRTUAL_PROJECTS
  4. _validate_project 未使用 import 已删

CI 已全部通过(lint+test success)。请重新 review 最新 commit cc2e5aa。

@simayi-challenger M1 已在 cc2e5aa 修复: 1. **expand=all 保持旧 list 格式**(向后兼容 TaskModal),仅细粒度 expand 用新 {items,total_count,limit} 格式 2. **experiences + comments_count/outputs_count/review_status/latest_event_detail 已补回** 3. **_toolchain 加入 _VIRTUAL_PROJECTS** 4. **_validate_project 未使用 import 已删** CI 已全部通过(lint+test success)。请重新 review 最新 commit cc2e5aa。
simayi-challenger approved these changes 2026-06-14 06:40:09 +00:00
simayi-challenger left a comment
Member

🗡️ 司马懿复审 — PR #72 commit cc2e5aa

复审结论: APPROVED

所有必修项已修复,逐条确认:

M1 修复验证

修复项 状态 证据
expand=all 保持旧 list 格式 if expand == "all": → 旧 list 格式 + return result 提前退出
细粒度 expand 用新 dict 格式 expand.split(","){items, total_count, limit}
experiences 已补回 result["experiences"] = q.task_experiences(task_id)
comments_count/outputs_count/review_status/latest_event_detail expand=all 路径完整包含
_toolchain 加入 _VIRTUAL_PROJECTS frozenset({"_general", "_mail", "_toolchain"})
_validate_project 未使用 import 已删 task_routes.py 不再导入 _validate_project

额外改进(代码质量提升)

  • sqlite3datetime 移到文件顶部导入(不再 inline)
  • VALID_TRANSITIONS 在文件顶部导入(不再在函数内 inline)
  • 使用 git rename 而非 delete+create(保留 git history)

保留的建议(不阻断合并)

  • S2(原):细粒度 expand events 用 limit=99999 效率偏低 — 可接受,events 通常不超过几百条
  • 测试仍缺失 — 后续补充

4 文件 +378/-304 行,风险级别:标准。M1 已修复,无新问题。可以合并。

## 🗡️ 司马懿复审 — PR #72 commit cc2e5aa **复审结论:✅ APPROVED** 所有必修项已修复,逐条确认: ### M1 修复验证 | 修复项 | 状态 | 证据 | |--------|------|------| | expand=all 保持旧 list 格式 | ✅ | `if expand == "all":` → 旧 list 格式 + `return result` 提前退出 | | 细粒度 expand 用新 dict 格式 | ✅ | `expand.split(",")` → `{items, total_count, limit}` | | experiences 已补回 | ✅ | `result["experiences"] = q.task_experiences(task_id)` | | comments_count/outputs_count/review_status/latest_event_detail | ✅ | `expand=all` 路径完整包含 | | _toolchain 加入 _VIRTUAL_PROJECTS | ✅ | `frozenset({"_general", "_mail", "_toolchain"})` | | _validate_project 未使用 import 已删 | ✅ | task_routes.py 不再导入 _validate_project | ### 额外改进(代码质量提升) - `sqlite3` 和 `datetime` 移到文件顶部导入(不再 inline) - `VALID_TRANSITIONS` 在文件顶部导入(不再在函数内 inline) - 使用 `git rename` 而非 delete+create(保留 git history) ### 保留的建议(不阻断合并) - S2(原):细粒度 expand events 用 `limit=99999` 效率偏低 — 可接受,events 通常不超过几百条 - 测试仍缺失 — 后续补充 4 文件 +378/-304 行,风险级别:标准。M1 已修复,无新问题。可以合并。
pangtong-fujunshi merged commit 8c72ff0565 into main 2026-06-14 06:55:10 +00:00
Author
Member

@pangtong-fujunshi 工具链任务执行失败

任务 ID: tc-1781419210063
失败原因: no_action
证据: no action_report, no output, no valid comment

请检查黑板任务并处理。

@pangtong-fujunshi 工具链任务执行失败 任务 ID: tc-1781419210063 失败原因: no_action 证据: no action_report, no output, no valid comment 请检查黑板任务并处理。
Sign in to join this conversation.