Skip to content

fix: add _handle_qa error handling, workflow_dispatch simulate mode, cache env improvements#101

Merged
nevstop merged 3 commits into
mainfrom
fix/router-qa-error-handling-and-simulate
Jun 22, 2026
Merged

fix: add _handle_qa error handling, workflow_dispatch simulate mode, cache env improvements#101
nevstop merged 3 commits into
mainfrom
fix/router-qa-error-handling-and-simulate

Conversation

@nevstop

@nevstop nevstop commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

修复内容

1. _handle_qa 错误处理(根因修复)

  • CSM_QA.from_env()qa_engine.ask() 现在被 try/except 包裹
  • 失败时向 Discussion 发布用户可见的错误提示,而非让 workflow 崩溃
  • _handle_join_handle_other 同样加强了异常保护
  • 对齐 discussion_bot.py 的防御模式

2. workflow_dispatch 手动模拟模式

  • discussion_number 改为可选(默认 0 = 模拟模式)
  • 模拟模式下跳过所有 Discussion API 调用:
    • QA:使用 comment_body 作为问题,调用 CSM_QA 生成回答并打印到日志
    • JOIN:打印模拟条件检测报告
    • OTHER:打印引导消息
  • QA/JOIN/OTHER 步骤新增 ROUTER_COMMENT_BODYROUTER_EVENT_TYPE 环境变量
  • QA 步骤新增 GH_TOKEN 确保 wiki 克隆有认证

3. 缓存修复(已在基线 commit 2161106 中)

  • vector store cache key 包含 hashFiles('requirements-bot.txt')
  • check-vs-populated 步骤用 jq 校验 commit_id 防止过期缓存

手动测试

  1. Actions → Org Discussion Router → Run workflow
  2. discussion_number 留空(默认 0)
  3. comment_body 输入技术问题
  4. category_nameQ&A
  5. dry_runtrue
  6. 查看日志中的 SIMULATE 输出

Closes #99

… mode, improve cache env vars

Three fixes in one PR:

1. Error handling: _handle_qa now wraps CSM_QA.from_env() and qa_engine.ask()
   in try/except, posting user-facing error replies on failure instead of
   crashing the workflow. Also added error handling to _handle_join and
   _handle_other. This aligns with discussion_bot.py's defensive pattern
   (lines 932-936).

2. Simulate mode: workflow_dispatch now supports discussion_number=0 (made
   optional with default '0') to simulate a complete classify+intent flow
   without a real Discussion. In simulate mode:
   - QA: uses ROUTER_COMMENT_BODY as question, calls CSM_QA.ask(), prints result
   - JOIN: prints simulated condition report
   - OTHER: prints guide message
   All handlers skip Discussion API calls when discussion_number==0.

3. Workflow env: added GH_TOKEN to QA step (for wiki clone auth),
   ROUTER_COMMENT_BODY+ROUTER_EVENT_TYPE to QA/JOIN/OTHER steps
   (required for simulate mode and consistent logging).

@nevstop nevstop left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: fix/router-qa-error-handling-and-simulate

Verdict: minor issues, OK to ship after fixing the blocking item

Blocking

  • scripts/router.py L676 (new): _handle_qa 现在使用 router 自己的 fetch_discussion 获取 discussion,但该函数的 GraphQL 查询缺少 author { login } 字段(对比 discussion_bot.py L252 中的 fetch_discussion 包含此字段)。导致 L732 discussion.get(author) 始终返回 NoneSKIP_AUTHORS 检查永久失效 — nevstop 的 discussions 将不再被跳过。
    修复: 在 router 的 fetch_discussion GraphQL 查询中添加 author { login }(与 discussion_bot 版本对齐)。

Should-fix

  • scripts/router.py L655–690 (simulate 分支): 模拟模式从 os.environ.get(ROUTER_COMMENT_BODY) 读取问题,但 main() 已经将 --comment-body 参数解析到 args.comment_body。更一致的做法是将 comment_body 作为参数传入 _handle_qa(与 _handle_join 接收 comment_author 的模式对齐),避免同一个值从两种途径获取。
  • scripts/router.py L935–936: _handle_joinGitHubGraphQL(token) 新增了 try/except ValueError,但只捕获了 ValueError。如果 GitHubGraphQL.__init__ 抛出其他异常(如 RuntimeError),仍会崩溃。建议放宽为 except Exception,与其他 handler 保持一致。
  • 测试覆盖: 新增的 simulate 分支和 error-handling 分支没有单元测试。建议至少添加 test_simulate_qa_no_comment_bodytest_handle_qa_init_failure 两个 case。

Nits

  • scripts/router.py L664: 模拟分支的 from csm_llm_qa import CSM_QA # noqa: F811 与非模拟分支的导入重复。两个分支互斥所以无害,但 # noqa: F811 提示这不够优雅。可考虑将 CSM_QA 导入提升到函数顶部通用位置。
  • .github/workflows/org-router.yml L22: discussion_number 默认值 '0' 作为 string 类型,但 router.py 中 --discussion-numbertype=int。GitHub Actions 传 0 给 shell 后 python --discussion-number 0 能正确解析为 int 0,所以实际没问题,但类型不一致值得注意。
    验证: argparsetype=int 会调用 int(0)0,无问题。

正向确认

  • _handle_qa 的三级 try/except(导入 / from_env / ask)正确对齐 discussion_bot.py 的防御模式
  • ✅ 模拟模式下 main() 跳过 _build_classify_history(无真实 Discussion 可拉取)逻辑正确
  • is_simulate 标志传递给 handler 作为 dry_run or is_simulate,确保模拟模式始终不发布回复
  • GH_TOKEN 添加到 QA step env 解决 wiki clone 认证问题
  • _handle_other_handle_join 的异常保护合理,不会掩盖根因(均记录 logger.exception

…ent_body as param, widen exception catch

- fetch_discussion: add author { login } at discussion level (was missing,
  causing SKIP_AUTHORS check to always fail)
- _handle_qa: accept comment_body as explicit parameter instead of reading
  from os.environ (consistent with _handle_join pattern)
- _handle_join: widen GitHubGraphQL init catch from ValueError to Exception
@nevstop

nevstop commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

Review 修复 — commit 6189f61

🔴 Blocking → 已修复

fetch_discussion 添加 author { login } 字段scripts/router.py L903)

  • GraphQL 查询在 discussion 级别补全了 author { login }
  • discussion_bot.py L252 对齐
  • SKIP_AUTHORS 检查恢复正常,nevstop 的 discussions 会被正确跳过

🟡 Should-fix → 已修复

_handle_qa 模拟分支改为参数传递scripts/router.py L643, L657, L1298)

  • 新增 comment_body: str = "" 参数
  • 模拟分支直接使用参数而非 os.environ.get("ROUTER_COMMENT_BODY")
  • _handle_join 接收 comment_author 的模式一致

_handle_join 放宽异常捕获scripts/router.py L1013)

  • GitHubGraphQL(token)except ValueErrorexcept Exception
  • 与其他 handler 保持一致,避免 RuntimeError 等非预期异常导致崩溃

📝 Nits — 未修改

  • # noqa: F811 重复导入:两个分支互斥,不影响运行时,保持现状
  • discussion_number string → int 类型转换:argparse type=int 自动处理,无问题
  • 测试覆盖:本地无 Python 环境,CI 通过后可作为后续 PR 补充

@nevstop

nevstop commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

Re-review — commit 6189f61

Verdict: ship as-is ✅

已修复确认

  • 🔴 fetch_discussion 缺少 author { login } → 已修复。GraphQL 查询在 L903 新增 author { login },与 discussion_bot.py L252 对齐。discussion.get("author") 现在能正确返回 author 对象,SKIP_AUTHORS 检查恢复正常。

  • 🟡 _handle_qa 环境变量 vs 参数不一致 → 已修复。新增 comment_body: str = "" 参数,模拟分支直接使用参数。main() L1298 传入 args.comment_body

  • 🟡 _handle_join except ValueError → 已修复。L1013 改为 except Exception,与其他 handler 一致。

无新问题

  • 工作流 YAML 变更仅限于 env vars 和 discussion_number 默认值,无语法错误
  • _handle_qa 非模拟路径的 discussion 只取一次(L715),复用于 author_login 检查和 compute_reply_plan,逻辑正确
  • is_simulate 标志正确传递:main() 中传给 handler 作为 dry_run or is_simulate,确保模拟模式始终不发布回复
  • GH_TOKEN 仅在 QA 步骤添加,JOIN/OTHER 不受影响

小注(不影响合入)

  • --classify-only + --discussion-number 0 + 空 body 会被 L1208 拦截(合理,空 body 无需分类)
  • # noqa: F811 在 L664:两个互斥分支各有 CSM_QA 导入,无害

…boundLocalError

The  inside _handle_qa
shadowed the module-level import, causing Python to treat GitHubGraphQL as
a local variable throughout the entire function. This caused UnboundLocalError
in the non-Q&A guidance path (L649/L654) which runs before the import.

Fix: remove GitHubGraphQL from the local import — the module-level
 (L35) is sufficient since
discussion_bot re-exports the same class.
@nevstop

nevstop commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

测试结果 — commit 09a3790

workflow_dispatch 测试(discussion #100,General 分类,dry_run=true):✅ 全部通过

https://github.com/NEVSTOP-LAB/.github/actions/runs/27927696285

发现的额外 bug 及修复

测试 main 分支时发现 中存在 UnboundLocalError

  • 根因:from scripts.discussion_bot import GitHubGraphQL 在函数内部创建了局部变量,遮蔽了模块级导入
  • 影响:非 Q&A 引导路径在导入之前使用 GitHubGraphQL(token) 时抛出 UnboundLocalError
  • 修复(09a3790):从局部导入中移除 GitHubGraphQL,直接使用模块级 from scripts._github import GitHubGraphQL(两者是同一个类)

测试通过步骤

  1. ✅ Run tests(13 passed)
  2. ✅ Classify → QA(如题 → General 分类下短正文被识别为 QA)
  3. ✅ QA handler → 非 Q&A 引导路径(dry_run 仅打印)
  4. ✅ 无 UnboundLocalError,无崩溃

@nevstop nevstop merged commit 013c472 into main Jun 22, 2026
1 check passed
@nevstop nevstop deleted the fix/router-qa-error-handling-and-simulate branch June 22, 2026 03:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant