Skip to content

feat(multi-review): add multi-agent parallel code review action#81

Merged
Svtter merged 6 commits into
mainfrom
worktree-multi-review
May 19, 2026
Merged

feat(multi-review): add multi-agent parallel code review action#81
Svtter merged 6 commits into
mainfrom
worktree-multi-review

Conversation

@Svtter

@Svtter Svtter commented May 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add new multi-review action that runs multiple reviewer personas in parallel (quality, security, performance, architecture) on a single GitHub Actions runner
  • Coordinator agent synthesizes all reviewer outputs with dedup, cross-validation, and conflict resolution
  • Supports custom personas via YAML config, reviewer redundancy, and model fallback per reviewer

Key Files

  • multi-review/action.yml — GitHub Action composite definition
  • multi-review/run-multi-review.py — Python orchestrator (parallel subprocess, coordinator synthesis)
  • multi-review/reviewers/*.yaml — Built-in reviewer persona prompts
  • multi-review/README.md — Usage documentation
  • tests/test_multi_review.py — 21 unit tests

Design Decisions

  • Single job, Python subprocess parallelism (vs multi-job matrix) for simplicity and lower cost
  • YAML persona config with built-in defaults (quality + security)
  • Coordinator acts as a debate/synthesis agent, not just concatenation
  • All agents run in read-only mode

Test plan

  • Unit tests pass (21/21)
  • E2E: Create a test PR and trigger multi-review action
  • Verify: Reviewer timeout degradation behavior
  • Verify: Custom persona config file loading

🤖 Generated with Claude Code

Introduces a new `multi-review` action that runs multiple reviewer personas
(quality, security, performance, architecture) in parallel via Python
subprocess, then synthesizes a unified report through a coordinator agent
with dedup, cross-validation, and conflict resolution.

Key features:
- 4 built-in reviewer personas with domain-specific prompts
- Parallel execution on a single GitHub Actions runner
- Coordinator synthesis with multi-reviewer confirmation markers
- Custom personas via YAML config file
- Reviewer redundancy (multiple instances of same persona)
- Model fallback per reviewer
- Read-only enforcement for all agents

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

有条件合并

总结

该 PR 新增了一个功能丰富的 multi-review 并行代码审查 action,整体设计合理,代码结构清晰,测试覆盖较好(21/21)。但存在若干需要修复和可改进的问题。

阻塞项

  1. model-timeout-seconds 输入未连接到 Python 代码action.yml:73-76):该输入在 action.yml 中定义(默认 300),但 action 步骤中没有设置对应的环境变量(如 MULTI_REVIEW_MODEL_TIMEOUT_SECONDS),Python 代码中也未读取任何来源的 model_timeout 配置。设置了此参数的用户的意图会被静默忽略,per-model timeout 实际由 reviewer-timeout-seconds 代替。应当为该输入添加 env var 映射,或将其删除。

建议项

  1. _parse_simple_yaml 对嵌套 YAML 静默失败run-multi-review.py:56-92):当 PyYAML 未安装时,自定义配置文件(含 personas/reviewers 列表的嵌套结构)被扁平解析器处理,custom_data.get("personas", []) 返回的是字符串而非列表,后续迭代逐字符进行,导致自定义配置被完全静默忽略。建议在 _parse_simple_yaml 检测到嵌套结构时打印警告,或在 import yaml 失败时直接报错而非降级。

  2. gh api --paginate 多页评论时 JSON 解析风险run-multi-review.py:406):当 PR 评论数超过一页时,旧版本 gh CLI 的 --paginate 会拼接各页的 JSON 数组(如 [{...}][{...}]),导致 json.loads 抛出异常,cleanup_error_comments 静默失效。建议取消 --paginate 或改用 jq/--jq 处理后拼接。

  3. README 中 GitHub org 名称不一致multi-review/README.md:8,54,86):三处示例均使用 sun-praise/opencode-actions,而主 README.md:13 及其他现有 action 文档使用 Svtter/opencode-actions。用户照抄示例将无法使用。

  4. model-timeout-seconds 未在 README 参数表中列出multi-review/README.md:93-110):该参数有定义、有默认值,但 README 表格缺失。

  5. needs_config 写入可能破坏 JSONC 格式的 opencode.jsonrun-multi-review.py:484-508):使用 json.load 读取 + json.dump 重写,若原文件含有注释(JSONC 格式,如 ///* */)则 json.load 会失败,导致配置丢失。建议先尝试 json.load,失败时保留原文件不变。

  6. 测试 test_generic_model_always_supported 未隔离环境变量tests/test_multi_review.py:158-159):该方法未使用 @patch.dict(os.environ, {}, clear=True),若运行环境中存在 ZHIPU_API_KEY 等变量且模型名以对应前缀开头,可能产生假阴性。建议增加 clear=True 保护。

  7. finally 块无条件执行 cleanup_error_commentsrun-multi-review.py:427-434):即使全部 reviewer 和 coordinator 成功返回,也会执行一次无必要的评论清理(读取所有评论、正则匹配、逐条尝试 DELETE)。建议仅在非零返回时执行。

New%20session%20-%202026-05-19T07%3A57%3A13.969Z
opencode session  |  github run

@github-actions

Copy link
Copy Markdown

发现遗漏

摘要

PR 实现了核心并行审查与协调框架,但在关键集成点、输入接线和错误处理上存在遗漏。


CRITICAL

1. 最终合成评论(含可折叠详情)未发布到 PR

  • 问题: README(第 35 行)明确说明"最终输出以单个 PR 评论形式发布,包含协调器合成结果及每个审查者的可折叠原始输出"。format_pr_comment()run-multi-review.py:341)确实生成了这种格式的内容,但仅 print() 到 stdout(第 590 行),流向 Action 日志而非 PR。与此同时,每个审查者子进程和协调器子进程各自通过 run-opencode.shopencode github run 独立发布原始评论(run-multi-review.py:229, 296)。
  • 结果: PR 上出现 N+1 条独立原始评论(各审查者 + 协调器),而非 README 描述的"一条合成评论"。
  • 建议修复: 不应让子进程各自调用 opencode github run,而是将 Python 脚本的输出通过管道传递给外层的 opencode github run,或使用 gh pr comment API 直接发布 format_pr_comment() 的结果。

MEDIUM

2. model-timeout-seconds 输入已定义但从未使用

  • 问题: action.yml:73-76 定义了 model-timeout-seconds,描述为"每个模型超时后切换到 fallback 模型",默认值 300。但在 action.yml:210-235 的 env 传递中没有为它设置 MULTI_REVIEW_MODEL_TIMEOUT_SECONDS 环境变量。Python _main() 中仅读取 MULTI_REVIEW_REVIEWER_TIMEOUT_SECONDS(第 442 行)并传给 run_reviewer()model_timeout 参数(第 543 行)。因此用户无法独立配置 per-model 超时——model-timeout-seconds 完全被忽略,实际使用的是 reviewer-timeout-seconds 的值。
  • 建议修复: 在 action.yml 中添加 MULTI_REVIEW_MODEL_TIMEOUT_SECONDS: ${{ inputs.model-timeout-seconds }},并在 _main() 中读取该变量。

3. 自定义 YAML 配置文件在 PyYAML 不可用时静默解析失败

  • 问题: README(第 63-81 行)定义的自定义配置 YAML 格式包含嵌套结构(personas: [...]reviewers: [...])。_parse_simple_yaml()run-multi-review.py:56-92)仅处理扁平 key: value 结构,无法解析列表和嵌套字典。当 yaml 模块(PyYAML)不可用时,resolve_reviewers()(第 115-128 行)调用该函数得到一个不含 personasreviewers 键的扁平 dict,导致自定义审查者配置被静默忽略,无任何错误或警告。
  • 建议修复: 在 _parse_simple_yaml() 返回后检查是否需要 personas/reviewers 键但未找到时,打印警告并退出;或者在 PyYAML 不可用时直接报错并建议安装。

LOW

4. model-timeout-secondsfallback-on-regex 未出现在 README 输入表中

  • 问题: action.yml 定义了 model-timeout-seconds(第 73 行)和 fallback-on-regex(第 78 行),但 README 输入表(第 95-110 行)未列出它们。其中 fallback-on-regex 是实现模型 fallback 机制的关键配置(PR body 明确提到该机制)。
  • 建议修复: 在 README 输入表中补充这两个输入。

New%20session%20-%202026-05-19T07%3A57%3A14.019Z
opencode session  |  github run

- Extract _run_opencode() to deduplicate subprocess run pattern between
  run_reviewer and run_coordinator
- Extract _truncate() to deduplicate output truncation logic
- Extract _flush() helper in _parse_simple_yaml for cleaner key flushing
- Replace 9-line set_env forwarding with data-driven mapping loop
- Simplify extra-env parsing to remove intermediate variables
- Remove unused imports (glob, Future, json, tempfile, textwrap, MagicMock)

All 21 tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

架构有疑虑

该 PR 新增的 multi-review 动作在目录结构、action.yml 规范(composite 类型、Linux-only 检查、version 解析、cache 缓存、install 步骤复用)上严格遵循了项目既有约定,模块放置合理。但存在以下架构层面的疑虑:

阻塞项:无

建议项:

  1. 绕过 github-run-opencode 层,导致关键逻辑重复 — 其他 opinionated 动作(reviewarchitect-reviewfeature-missing, spec-coverage)均通过 github-run-opencode/run-github-opencode.py 执行;而 run-multi-review.py 直接调用 run-opencode/run-opencode.sh,自行实现了 model fallback 循环、timeout 处理、error comment cleanup、permission JSON 构建、API key 过滤等逻辑。这部分逻辑与 run-github-opencode.py 高度重叠(约 40%),后续若在单审模式中修复 bug 或增强功能(如改进 fallback 策略、优化错误清理匹配),multi-review 需要手动同步,存在维护分歧风险。建议将公共逻辑(fallback 编排、错误清理、权限注入、额外环境变量解析)抽取为共享 Python 模块,供两个脚本引用,而非在 run-multi-review.py:193-265run-multi-review.py:370-424 中独立实现。

  2. 四个 reviewers/*.yaml 提示词模板高度同构quality.yamlsecurity.yamlperformance.yamlarchitecture.yaml 的结构、输出格式段落 95% 相同,仅有审查维度和分类标识不同。这种 "一个 yaml 对应一个 prompt" 的模式是合理的,但建议通过统一的 prompt 模板 + 参数化替换来消除段落层面的重复,而非四个独立的 YAML 文件各自维护一套完整模板。

New%20session%20-%202026-05-19T07%3A58%3A57.989Z
opencode session  |  github run

@github-actions

Copy link
Copy Markdown

No linked issues. Extracting requirements from PR body and README. Comparing implementation to spec.

发现遗漏

摘要

PR 实现了核心并行审查框架,但存在 1 处关键集成缺口、1 处中等遗漏和 1 处轻微遗漏。


CRITICAL

1. 最终格式化合结果(含可折叠详情)未发布到 PR

  • 描述: README(第 34 行)明确说明 "The final output is posted as a single PR comment with the coordinator's synthesis plus collapsible sections for each reviewer's raw output"。format_pr_comment()run-multi-review.py:341)确实生成了含 <details> 标签的格式化内容,但该函数仅在 _main() 末尾被 print() 到 stdout(第 582 行),流向 Action 日志而非 PR。与此同时,每个 reviewer 子进程(通过 run_reviewer_run_opencode 第 240 行)和 coordinator 子进程(第 295 行)各自独立调用 opencode github run,向 PR 发布原始输出。结果是:PR 上散落 N+1 条独立原始评论(各 reviewer + coordinator),而 README 承诺的 "single PR comment with collapsible sections" 从未实际发布到 PR。
  • 建议修复: 将 format_pr_comment() 的输出通过 gh pr comment API 发布到 PR,或者在 action.yml 中额外增加一个 step 将 Python 脚本的输出通过 pipe 传递给 opencode github run。同时应避免子进程独立发布原始评论,或清理多余的独立评论。

MEDIUM

2. model-timeout-seconds 输入已定义但完全未使用

  • 描述: action.yml:73-76 定义了 model-timedown-seconds(默认 300),描述为 "Per-model timeout before rotating to fallback",是 PR body 声称的 "model fallback per reviewer" 功能的核心配置项。然而在 action.yml:210-235 的 env 传递段中,没有为它设置 MULTI_REVIEW_MODEL_TIMEOUT_SECONDS 环境变量。Python _main() 只读取 MULTI_REVIEW_REVIEWER_TIMEOUT_SECONDS(第 434 行)并传递给 run_reviewer()model_timeout 参数(第 535 行)。用户配置的 model-timeout-seconds 被静默忽略,实际 per-model 超时完全由 reviewer-timeout-seconds 的值决定。
  • 建议修复: 在 action.yml 的 env 块中添加 MULTI_REVIEW_MODEL_TIMEOUT_SECONDS: ${{ inputs.model-timeout-seconds }},并在 _main() 中读取该环境变量后传给 run_reviewer()

LOW

3. model-timeout-secondsfallback-on-regex 未出现在 README 输入表中

  • 描述: action.yml 定义了 model-timeout-seconds(第 73 行)和 fallback-on-regex(第 77 行)两个输入,且 fallback-on-regex 已通过 MULTI_REVIEW_FALLBACK_ON_REGEX 环境变量传递并实际用于 fallback 判定逻辑。但 README 输入表(第 95-110 行)未列出它们,用户无从知晓这些配置项的存在。其中 fallback-on-regex 是实现 "model fallback per reviewer" 的关键配置,缺失文档会影响用户对 fallback 行为的控制。
  • 建议修复: 在 README 输入表中补充这两行。

New%20session%20-%202026-05-19T08%3A02%3A22.563Z
opencode session  |  github run

@github-actions

Copy link
Copy Markdown

架构有疑虑

该 PR 新增的 multi-review action 在目录结构、composite action 规范、Linux-only 检查、version 解析、cache 配置、install 步骤复用上严格遵循了项目既有约定。但存在以下架构层面的疑虑:

阻塞项:无

建议项:

  1. 绕过 github-run-opencode 共享编排层,导致关键逻辑重复 — 所有现有 opinionated action(reviewarchitect-reviewfeature-missingspec-coverage)均通过 github-run-opencode/run-github-opencode.py 执行。而 run-multi-review.py 直接调用 run-opencode/run-opencode.sh,自行实现了以下与 run-github-opencode.py 高度重叠的逻辑:model fallback 循环(run_reviewer L209-264 ↔ run-github-opencode.py L377-426)、API key 过滤(_supports_model L267-274 ↔ L33-40)、error comment 清理(cleanup_error_comments L362-416 ↔ L168-243)、opencode.json 配置(L482-504 ↔ L71-112)。后续若在单审模式中修复 bug 或增强功能(如改进 fallback 策略、优化清理匹配 URL),multi-review 需要手动同步,存在维护分歧风险。建议将公共逻辑(model fallback 编排、API key 过滤、error comment 清理、opencode.json 注入)抽取为 github-run-opencode/shared.py 供两个脚本引用。

  2. 输出策略与 README 描述不一致 — README(第 30-34 行)明确描述 "The final output is posted as a single PR comment with the coordinator's synthesis plus collapsible sections",但实现中:每个 reviewer 子进程和 coordinator 子进程各自独立通过 run-opencode.shopencode github run 向 PR 发布原始评论(L240, L295),而 format_pr_comment()(L341)生成的含 <details> 标签的最终合成结果仅 print() 到 stdout(L582),导致 PR 上散落 N+1 条独立原始评论,而非 README 承诺的单条合成评论。这是架构层面的设计-实现不匹配,建议统一由 orchestrator 收集原始输出并仅发布一次最终合成评论。

  3. model-timeout-seconds 输入未连接到环境变量action.yml:73-76 定义了 model-timeout-seconds(默认 300),但 env 映射段(L210-235)未为其设置 MULTI_REVIEW_MODEL_TIMEOUT_SECONDS。Python _main() 中实际使用的 per-model 超时是 reviewer-timeout-seconds 的值(L434 读取 MULTI_REVIEW_REVIEWER_TIMEOUT_SECONDS,L535 作为 model_timeout 传入)。这与 github-run-opencodemodel-timeout-seconds → GITHUB_RUN_OPENCODE_MODEL_TIMEOUT_SECONDS 的完整接线模式不一致,用户配置的 per-model 超时被静默忽略。

New%20session%20-%202026-05-19T08%3A06%3A27.534Z
opencode session  |  github run

Svtter and others added 2 commits May 19, 2026 18:04
- Post synthesized comment via `gh pr comment` instead of stdout only;
  suppress per-agent PR comments by setting USE_GITHUB_TOKEN=false in
  subprocess env
- Wire `model-timeout-seconds` input to MULTI_REVIEW_MODEL_TIMEOUT_SECONDS
  env var and read it in Python as separate per-model timeout
- Add missing `model-timeout-seconds` and `fallback-on-regex` to README
  inputs table
- Fix org name: update all `Svtter/` references to `sun-praise/` in both
  multi-review README and root README
- Isolate env vars in `test_generic_model_always_supported` with clear=True

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ection

- Extract shared PR context detection (ref parsing + repo lookup) into
  _get_pr_context() used by both post_pr_comment and cleanup_error_comments
- Remove --paginate from cleanup_error_comments gh api call (avoids
  multi-page JSON concatenation issue flagged in review)
- Rename shadowed `body` variable to `comment_body` in cleanup loop

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

架构有疑虑

架构分析

该 PR 新增的 multi-review action 在目录结构、composite action 规范、boilerplate 步骤(Linux 检查、version 解析、paths 计算、cache 配置、install 步骤)上严格遵循了项目既有约定,模块放置合理。但存在以下架构层面的疑虑:

1. 绕过 github-run-opencode 共享编排层,导致关键逻辑重复

项目有一个清晰的 3 层架构:

  • Layer 1: run-opencode/run-opencode.sh(原始 CLI 调用)
  • Layer 2: github-run-opencode/run-github-opencode.py(共享编排:model fallback、API key 过滤、error comment 清理、opencode.json 配置)
  • Layer 3: 各 opinionated action(review/architect-review/feature-missing/spec-coverage/

run-multi-review.py 绕过 Layer 2 直接调用 Layer 1,并在自身中**重新实现**了以下与 run-github-opencode.py 高度重叠的逻辑:

功能 run-github-opencode.py run-multi-review.py
API key 过滤 supports_model_with_available_key (L33-40) _supports_model (L267-274)
Error comment 清理 cleanup_error_comments (L168-243) cleanup_error_comments (L395-449)
opencode.json 配置 configure_opencode_json (L71-112) 内联逻辑 (L514-538)
Model fallback 循环 _main 中的循环 (L377-426) run_reviewer 中的循环 (L228-264)

后续若在单审模式中修复 bug(如改进 fallback 正则匹配、优化 error comment URL 检测、调整 thinking 配置字段),multi-review 必须手动同步,存在维护分歧风险。建议将公共逻辑抽取到 github-run-opencode/shared.py 供两个脚本引用。

2. 输出策略对 USE_GITHUB_TOKEN=false 的行为有脆弱依赖

README 承诺 "The final output is posted as a single PR comment with collapsible sections"。实现中通过在 _run_opencode 设置 env["USE_GITHUB_TOKEN"] = "false"(L197)来抑制各 reviewer 子进程独立发评论,再由 post_pr_comment 统一发布。但若 opencode CLI 在 USE_GITHUB_TOKEN=false 时仍通过自有 GitHub App token 发表评论,PR 上将出现 N+1 条独立原始评论 + 1 条合成评论。这一设计决策将输出完整性建立在底层 CLI 的特定环境变量行为上,缺乏防御性措施。

3. 接口内聚性:run_reviewer 承载过多职责

run_reviewer 函数(L210-265)同时负责:

  • 候选模型列表构建与 API key 过滤
  • 全局 deadline 与 model timeout 的混合计算
  • Fallback 循环与退出条件判断
  • 异常处理和结果封装

建议将模型选取策略(candidate composition + timeout computation)与 reviewer 执行逻辑分离,使职责更清晰。


阻塞项:无

建议项:

  1. _supports_modelcleanup_error_comments、opencode.json 配置、fallback timeout 计算等公共逻辑抽取到 github-run-opencode/shared.py,消除 Layer 2 与 multi-review 之间的维护分歧。
  2. _run_opencode 中增加 USE_GITHUB_TOKEN=false 失效时的降级策略(如事后清理多余评论,或改用 gh api 而非 opencode github run 来避免自动发评论)。
  3. run_reviewer 中的模型选取/超时计算逻辑(L222-238)抽取为独立函数,与 reviewer 执行逻辑解耦。

New%20session%20-%202026-05-19T10%3A07%3A49.416Z
opencode session  |  github run

@github-actions

Copy link
Copy Markdown

发现遗漏

摘要

PR 实现了核心并行审查框架,所有声明的功能均有对应代码。但存在若干中低严重度的缺口。


MEDIUM

1. global_timeout 耗尽后 coordinator 未运行时的 fallback 结果未发布到 PR

  • 描述: 当 global_timeout 耗尽导致 coordinator 无时间运行时(run-multi-review.py:597-599),post_fallback_comment() 的结果仅通过 print(comment) 输出到 stdout(Action 日志),没有调用 post_pr_comment()。用户只能在 GitHub Actions 日志中看到原始审查结果,PR 上不会出现任何来自 multi-review 的评论。
  • 相关 spec: README 第 30-34 行——"The final output is posted as a single PR comment"
  • 建议修复: 在 _main() 的 "no time for coordinator" 分支中调用 post_pr_comment(comment),与正常流程第 616 行一致。

2. 自定义 YAML 审查者配置在 PyYAML 不可用时静默忽略

  • 描述: _parse_simple_yaml()run-multi-review.py:56-92)仅能处理扁平的 key: value 结构,无法解析 README 第 63-81 行示例中使用的嵌套结构(personas: [...]reviewers: [...])。当 runner 上未安装 yaml 模块时,resolve_reviewers() 第 113-117 行走 else 分支,调用 _parse_simple_yaml() 得到一个不含 personas/reviewers 键的扁平 dict,导致自定义审查者配置被静默忽略,无任何错误或警告输出,用户得到默认的 quality:1,security:1 团队。
  • 相关 spec: PR body "Supports custom personas via YAML config" + README "Custom Reviewer Config File" 章节
  • 建议修复: 在 _parse_simple_yaml() 返回后检查自定义配置中是否期望嵌套结构但未找到,输出警告;或在 PyYAML 不可用时直接报错退出。

LOW

3. cleanup_error_comments 在成功退出时也无条件执行

  • 描述: main()finally 块(run-multi-review.py:455-459)在每次退出时都调用 cleanup_error_comments(),包括所有 reviewer 和 coordinator 均成功返回时。这发起不必要的 API 调用(列出所有 PR 评论、正则匹配、逐条尝试 DELETE)。
  • 相关 spec: PR body 提到 "cleanup-error-comments" 功能,但未指定触发条件
  • 建议修复: 仅在 _main() 返回非零值时执行清理,或在 coordinator 成功时跳过。

4. gh api --paginate 多页评论时 JSON 解析失败

  • 描述: cleanup_error_comments() 第 425 行使用 gh api --paginate 获取 PR 评论。当评论数超过一页(通常 100 条)时,旧版本 gh CLI 拼接各页 JSON 数组产生无效的 JSON([{...}][{...}]),第 431 行 json.loads(result.stdout) 抛出异常,被 try-except 静默吞没,清理功能完全失效。
  • 相关 spec: PR body "Supports...cleanup-error-comments" 功能
  • 建议修复: 取消 --paginate 改用 --jq 拼接,或逐页请求后手动合并。

5. opencode.jsonjson.load 读取导致 JSONC 格式数据丢失

  • 描述: _main() 第 519-521 行使用 json.load() 读取 opencode.json。如果文件包含 JSONC 格式的注释(///* */),json.load() 抛出异常,退化为空 dict {}。随后第 537 行 json.dump() 覆写文件,使用户原有的 opencode.json 配置丢失。
  • 相关 spec: 未明确说明 JSONC 兼容性,但 opencodeopencode.json 支持 JSONC
  • 建议修复: 先尝试 json.load,失败时保留原文件不变,仅追加而非覆写。

6. fallback-on-regex 默认值在 README 中不完整

  • 描述: README 输入表第 104 行 fallback-on-regex 的 Default 列仅写 "timeout regex",未显示 action.yml:80 中定义的实际默认值 timed out|timeout|deadline exceeded|context deadline exceeded|operation timed out|connection timed out。用户无法知晓默认的 fallback 触发条件。
  • 相关 spec: README input table 应完整反映 action.yml 的输入默认值
  • 建议修复: 在 README 表格中列出完整的默认正则表达式。

New%20session%20-%202026-05-19T10%3A06%3A11.578Z
opencode session  |  github run

@github-actions

Copy link
Copy Markdown

发现遗漏

摘要

PR 实现了核心并行审查与协调框架,但在自定义 YAML 配置的降级路径中存在关键功能丢失。


MEDIUM

1. _parse_simple_yaml 无法解析嵌套结构的自定义配置文件,当 PyYAML 不可用时静默忽略用户配置

  • 描述: README(第 63-81 行)文档化了自定义 reviewer 配置文件格式,包含嵌套结构(personas: [...]reviewers: [...])。当 PyYAML 未安装时(代码第 19-22 行已处理此场景),_parse_simple_yaml()run-multi-review.py:55-91)仅能解析扁平的 name: / prompt: 键值对,无法处理列表和嵌套字典。resolve_reviewers()(第 113-126 行)调用该函数后,custom_data.get("personas", [])custom_data.get("reviewers", []) 均返回空列表,用户的自定义审查者配置被完全静默忽略,无任何错误或警告。
  • 建议修复: 在 _parse_simple_yaml() 返回后检测是否需要 personas/reviewers 键但未找到时打印警告并退出;或在 PyYAML 不可用时直接报错并建议安装 pyyaml

LOW

2. use-github-tokenextra-envcleanup-error-commentsattemptsretry-profileretry-delay-seconds 共 6 个输入在 README 输入表中缺失

  • 描述: 这些输入在 action.yml 中有定义且有非空默认值,但 multi-review/README.md:93-112 的输入表未列出它们。用户无法从文档中获知这些配置项的存在。其中 attemptsretry-profileretry-delay-seconds 影响 reviewer 的失败重试行为,cleanup-error-comments 控制是否自动清理错误评论。
  • 建议修复: 在 README 输入表中补充这 6 行的文档。

New%20session%20-%202026-05-19T10%3A07%3A42.171Z
opencode session  |  github run

@github-actions

Copy link
Copy Markdown

不可合并

总结

PR 实现了 multi-agent 并行代码审查的核心框架,整体设计合理,代码结构清晰。但存在一处运行时崩溃的阻塞 bug:Future 未导入却被用于 type annotation。

阻塞项

  1. Future 未导入导致 NameErrorrun-multi-review.py:561):第 15 行 from concurrent.futures import ThreadPoolExecutor, as_completed 未导入 Future,但第 561 行 futures: dict[Future, str] = {} 使用了 Future 作为类型注解。Python 在函数运行时求值该注解,抛出 NameError: name 'Future' is not defined,导致整个 action 崩溃。需要添加 from concurrent.futures import Future

建议项

  1. _parse_simple_yaml 对嵌套 YAML 静默丢弃run-multi-review.py:56-92):当 PyYAML 不可用时,自定义配置文件(含 personas/reviewers 列表)被扁平解析器处理,custom_data.get("personas", []) 返回字符串而非列表,导致自定义配置被完全静默忽略且无任何警告。建议在 _parse_simple_yaml 返回后发现未期望的嵌套结构时打印 stderr 警告,或引入对标准 YAML 语法的基本支持。

  2. 缺少 fallback_on_regex 合法性校验run-multi-review.py:251):run-github-opencode.py:327 通过 validate_regex 校验 fallback regex 合法性,而 run-multi-review.py 没有做该项检查。用户输入非法正则时会在 re.search 处抛出 re.error(虽被通用 except Exception 捕获静默降级,但难以调试)。

  3. needs_config 写入可能破坏 JSONC 格式文件run-multi-review.py:516-538):使用 json.load 读取 + json.dump 重写 opencode.json,若原文件含注释则为 JSONC 格式,json.load 失败后 config = {},重写导致已有配置丢失。建议先尝试 json.load,失败时保留原文件不覆盖。

  4. README 输入表格缺少三个参数multi-review/README.md:93-112):use-github-tokenextra-envcleanup-error-comments 已在 action.yml 定义,但未在 README 表格中列出。

  5. cleanup_error_comments 在成功时也运行run-multi-review.py:455-459):即使所有 reviewer 和 coordinator 成功返回,finally 块也执行一次无必要的 GitHub API 评论清理操作。建议仅在非零返回时执行。

  6. reviewer 端到端逻辑与 run-github-opencode.py 重复(约 40% 重叠):fallback 循环(第 209-265 行 ↔ run-github-opencode.py:377-426)、error comment 清理(第 395-449 行 ↔ run-github-opencode.py:168-243)、API key 过滤(第 268-275 行 ↔ run-github-opencode.py:33-40)、opencode.json 注入(第 514-538 行 ↔ run-github-opencode.py:71-112)存在大量重复实现。后续单审模式修复 bug 时需手动同步,存在维护分歧风险。

  7. 四个 reviewer YAML 提示词高度同构reviewers/quality.yamlsecurity.yamlperformance.yamlarchitecture.yaml):结构、输出格式段落 95% 相同,仅有审查维度和决策标签不同。建议通过统一模板 + 参数化替换削减重复。

New%20session%20-%202026-05-19T10%3A06%3A14.865Z
opencode session  |  github run

@github-actions

Copy link
Copy Markdown

基于对当前代码(HEAD 版本)的全面审查,以下是审核意见。

可合并

总结

PR 实现了功能完整的 multi-review 并行审查 action,代码结构清晰,测试覆盖良好(21/21),符合项目既有约定(composite action、Linux-only 检查、version 解析、cache 配置等)。核心逻辑正确:各 reviewer 通过 ThreadPoolExecutor 并行运行,设置 USE_GITHUB_TOKEN=false 阻止子进程独立发评论,最终由 orchestrator 通过 gh pr comment 发布单条合成评论。

阻塞项:无

建议项:

  1. _parse_simple_yaml 对自定义嵌套 YAML 配置静默降级run-multi-review.py:56-92):当 PyYAML 未安装时,自定义配置文件的 personas/reviewers 列表被扁平解析器处理,custom_data.get("personas", []) 返回的是字符串而非列表,后续逐字符迭代后不产生任何匹配,自定义配置被完全静默忽略且无任何警告或报错。建议在检测到嵌套结构时打印 stderr 告警,或在 import yaml 失败时直接提示安装。

  2. needs_config 写入时可能破坏 JSONC 格式的 opencode.jsonrun-multi-review.py:517-538):使用 json.load 读取 + json.dump 重写,若原文件含注释(JSONC 格式),json.load 抛出异常后 config = {},原文件内容被完全丢弃。建议先尝试 json.load,失败时保留原文件不做写入。

  3. env_forward 未转发 OPENCODE_REASONING_EFFORTOPENCODE_ENABLE_THINKINGrun-multi-review.py:479-491):这两个变量在 action.yml 中已映射为 MULTI_REVIEW_* 前缀,但 Python 的 env_forward 中缺少对应的目标映射。虽然 _main() 已提前写入了 opencode.json 配置,使得子进程中 run-opencode.shconfigure_opencode_json 不会重复执行(因缺少标准环境变量名),但这一缺口使得 subprocess 若独立运行则无法获取到这些配置,建议补充完整。

  4. fallback-on-regex 默认值在 action.yml 与 Python 中不一致:action.yml:80 的默认值多出 operation timed out|connection timed out 两个模式,而 Python _main() 第 472-475 行的默认值较短。由于 action.yml 的 env 映射会覆盖,实际运行时影响不大,但建议同步两处默认值以避免本地调试时行为不一致。

  5. timeout 命令依赖 GNU coreutils 特定版本run-multi-review.py:200):timeout --foreground 需要 coreutils ≥ 8.24,标准 GitHub Actions 的 Ubuntu runner 满足条件。若 runner 使用极简容器镜像可能缺失 timeout 命令,此时 subprocess 会报错并由泛化的 except Exception 捕获。非重要项,可补充注释说明。

  6. _parse_simple_yaml 不支持 inline 格式的 prompt::若 YAML 中写为 prompt: short text 而非多行缩进格式,| 指示符后的值被忽略,仅收集后续缩进行。内建模板均为多行格式不受影响。

New%20session%20-%202026-05-19T10%3A07%3A41.674Z
opencode session  |  github run

@github-actions

Copy link
Copy Markdown

架构有疑虑

该 PR 新增的 multi-review action 在目录结构、composite action 规范(Linux-only 检查、version 解析、paths/cache/install 步骤)上严格遵循了项目既有约定,模块放置合理。但存在以下架构层面的疑虑:

阻塞项:无

建议项:

  1. 绕过 github-run-opencode 共享编排层,导致关键逻辑重复 — 项目架构存在清晰的 3 层结构:setup-opencodegithub-run-opencode/run-github-opencode.py(共享编排层)→ 各 opinionated action(review/architect-review/feature-missing/spec-coverage/)。run-multi-review.py 跳过共享编排层,直接调用 run-opencode/run-opencode.sh,并在自身中独立实现了以下与 run-github-opencode.py 高度重叠的逻辑:

    功能 run-github-opencode.py run-multi-review.py
    API key 过滤 supports_model_with_available_key (L33-40) _supports_model (L267-274)
    Error comment 清理 --paginatecleanup_error_comments (L168-243) --paginatecleanup_error_comments (L399-450)
    opencode.json 配置 configure_opencode_json (L71-112) 内联逻辑 (L517-538)
    Fallback timeout 计算 compute_effective_timeout (L146-165) 内联计算 (L230-238)

    后续若在单审模式中修复 bug(如改进 fallback regex、优化 error comment 删除逻辑),multi-review 需要手动同步,存在维护分歧风险。建议将公共逻辑(API key 过滤、error cleanup、opencode.json 配置、fallback timeout 计算)抽取为共享模块供两者引用。

  2. reviewer-timeout-seconds 输入定义了但未被消费action.yml:57-60 定义了 reviewer-timeout-seconds,通过 MULTI_REVIEW_REVIEWER_TIMEOUT_SECONDS 环境变量传入 Python,run-multi-review.py:468 读取为 reviewer_timeout 变量,但该变量从未被传递给任何函数。用户设置的 per-reviewer timeout 被静默忽略。实际控制 per-reviewer 执行时长的只有 model-timeout-seconds(通过 global_deadline + model_timeout 共同决定)。这与 model-timeout-seconds 输入的概念几乎重复,造成混淆。

  3. USE_GITHUB_TOKEN=false 依赖脆弱_run_opencode (L197) 设置 USE_GITHUB_TOKEN=false 来抑制各 reviewer 子进程独立发评论,再由 post_pr_comment 统一发布。但 opencode CLI 在 USE_GITHUB_TOKEN=false 时可能仍通过自有 GitHub App token 发评论,导致 PR 上出现 N+1 条独立原始评论 + 1 条合成评论的行为不受控制。建议增加事后清理机制或改用不自动发评论的调用方式。

New%20session%20-%202026-05-19T10%3A09%3A37.056Z
opencode session  |  github run

- Remove unused `reviewer_timeout` variable (replaced by `model_timeout`
  in previous fix but assignment was left behind)
- Remove `dict[Future, str]` type hint that referenced unimported Future

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

不可合并

总结

PR 实现了功能完整的 multi-review 并行审查框架,架构清晰,测试覆盖良好(21/21),符合项目既有规范。但存在一处运行时崩溃的阻塞 bug。

阻塞项

1. Future 未导入导致 NameErrorrun-multi-review.py:15,562):第 15 行 from concurrent.futures import ThreadPoolExecutor, as_completed 未导入 Future,但第 562 行 futures: dict[Future, str] = {} 直接在函数体中使用 Future 作为类型注解。Python 在函数执行时求值该注解(未使用 from __future__ import annotations),抛出 NameError: name 'Future' is not defined,导致整个 action 崩溃,无法运行。需要在第 15 行增加 from concurrent.futures import Future,或将注解改为字符串形式 "futures: dict[Future, str] = {}"

建议项

  1. reviewer-timeout-seconds 输入定义了但从未被 Python 消费action.yml:57-60 vs run-multi-review.py:467-468):该输入在 action.yml 中定义(默认 300),通过 MULTI_REVIEW_REVIEWER_TIMEOUT_SECONDS 传入环境,但 Python _main() 中未读取该变量。per-reviewer 的实际超时由 model-timeout-seconds(通过 model_timeout 参数)和 timeout-seconds(通过 global_deadline)共同决定。

  2. _parse_simple_yaml 对嵌套 YAML 静默丢弃run-multi-review.py:56-92):当 PyYAML 不可用时,自定义配置文件(含 personas/reviewers 列表的嵌套结构)被扁平解析器处理,custom_data.get("personas", []) 返回空列表,自定义配置被完全静默忽略且无任何警告。建议在检测到嵌套结构时打印 stderr 警告,或 PyYAML 不可用时直接报错安装。

  3. global_timeout 耗尽时 fallback 结果未发布到 PRrun-multi-review.py:595-599):当 global_deadline 耗尽致 coordinator 无法运行时,post_fallback_comment() 的结果仅 print() 到 stdout(Action 日志),未调用 post_pr_comment()。正常流程(第 616 行)会调用 post_pr_comment,此处行为不一致。

  4. opencode.json 写入可能破坏 JSONC 格式文件run-multi-review.py:517-538):使用 json.load 读取 + json.dump 重写。若原文件含注释(JSONC 格式,///* */),json.load 抛出异常后 config = {},重写后原文件内容丢失。由于 enable-thinking 默认 true 导致 needs_config 恒为 True,此路径始终执行。建议先尝试 json.load,失败时不覆写文件。

  5. README 输入表缺少三个输入multi-review/README.md:93-112):use-github-tokencleanup-error-commentsextra-envaction.yml 中有定义且有非空默认值,但 README 表格未列出。

  6. cleanup_error_comments 在成功路径也无条件执行run-multi-review.py:455-459):即使所有 reviewer 和 coordinator 成功返回,main()finally 块也会调用该函数,进行一次无必要的 GitHub API 评论遍历检查。建议仅在非零返回时执行。

  7. env_forward 缺少 OPENCODE_REASONING_EFFORTOPENCODE_ENABLE_THINKINGrun-multi-review.py:478-491):这两个变量已通过 MULTI_REVIEW_* 前缀从 action.yml 接收,但未在 env_forward 中映射到标准环境变量名。subprocess 若直接读取这些 env var 会获取不到配置值(当前通过写入 opencode.json 间接传递)。

  8. fallback-on-regex 默认值在 action.yml 与 Python 中不一致action.yml:80 vs run-multi-review.py:473):action.yml 默认多出 operation timed out|connection timed out 两个模式。生产环境下 action.yml 的 env 映射会覆盖,但不一致导致本地调试时行为差异。

  9. reviewer 编排逻辑与 run-github-opencode.py 重复(约 40% 重叠):API key 过滤(_supports_model L268 ↔ run-github-opencode.py:33-40)、error comment 清理(L399 ↔ L168-243)、opencode.json 注入(L514 ↔ L71-112)、fallback timeout 计算(L230 ↔ L146-165)存在多段重复实现。后续单审模式修复 bug 时需手动同步。

New%20session%20-%202026-05-19T10%3A16%3A44.075Z
opencode session  |  github run

@github-actions

Copy link
Copy Markdown

发现遗漏

摘要

PR 实现了核心并行审查框架,所有四个内置审查角色、协调器合成、模型 fallback、审查员冗余等核心特性均已编码实现。存在 2 处中等和 4 处低严重度遗漏。


MEDIUM

1. 协调器超时后的降级评论未发布到 PR

  • 描述: 当全局超时(global_timeout)耗尽、协调器无剩余时间运行时(run-multi-review.py:595-599),post_fallback_comment() 的返回结果仅通过 print(comment) 输出到 stdout(Action 日志),未调用 post_pr_comment(comment)。README 第 30-34 行明确说明 "The final output is posted as a single PR comment",但此降级路径下 PR 上不会出现任何来自 multi-review 的评论。
  • 建议修复: 在 _main()remaining_time <= 0 分支中,print(comment) 之后增加 post_pr_comment(comment),与第 616 行的正常流程保持一致。

2. 自定义 YAML 配置在 PyYAML 不可用时被静默丢弃

  • 描述: PR body 声明 "Supports custom personas via YAML config",README 第 63-81 行展示的配置格式包含嵌套结构(personas: [...]reviewers: [...])。_parse_simple_yaml()run-multi-review.py:56-92)仅能解析扁平 key: value,无法解析列表和嵌套字典。当 runner 缺少 PyYAML(import yaml 失败走 else 分支,第 113-117 行)时,resolve_reviewers() 拿到空 dict,custom_data.get("personas", [])custom_data.get("reviewers", []) 均返回空列表,用户的自定义审查者配置被完全静默忽略,无任何错误或警告。
  • 建议修复: 在 _parse_simple_yaml() 返回后检测是否期望 personas/reviewers 键但未找到,输出 stderr 警告;或当 PyYAML 不可用时直接报错退出并提示安装 pyyaml

LOW

3. reviewer-timeout-seconds 输入定义了但 env var 从未被 Python 消费

  • 描述: action.yml:57-60 定义了 reviewer-timeout-seconds(默认 300),并映射为 MULTI_REVIEW_REVIEWER_TIMEOUT_SECONDS(第 215 行),但 Python 代码中没有任何地方读取该 env var。实际控制 per-reviewer 超时的是 model-timeout-secondsMULTI_REVIEW_MODEL_TIMEOUT_SECONDS(第 223 行)→ model_timeout(第 468 行)。reviewer-timeout-seconds 这个输入完全死亡,用户设置后会被静默忽略。
  • 建议修复: 在 README 中明确标注该参数已弃用,或将其从 action.yml 中移除。

4. fallback-on-regex 默认值在 action.yml 与 Python 中不一致

  • 描述: action.yml:80 的默认值为 timed out|timeout|deadline exceeded|context deadline exceeded|operation timed out|connection timed out(6 个模式),而 Python _main() 第 472-473 行的默认值为 "timed out|timeout|deadline exceeded|context deadline exceeded"(4 个模式,缺少 operation timed outconnection timed out)。生产环境中 action.yml 的 env 映射会覆盖 Python 默认值,故不影响运行时行为,但本地调试时行为可能不一致。
  • 建议修复: 同步两处默认值。

5. README 输入表缺少多个 action 特有输入

  • 描述: multi-review/README.md:93-112 的输入表格未列出以下在 action.yml 中有定义的输入:use-github-tokenextra-envcleanup-error-commentsattemptsretry-profileretry-delay-seconds。其中 cleanup-error-comments(控制是否自动清理错误评论)和 use-github-token(控制子进程是否使用 GitHub Token)对用户行为有直接影响。
  • 建议修复: 在 README 输入表中补充这些缺失项。

6. env_forward 未转发 reasoning-effortenable-thinking 的标准 env 变量

  • 描述: env_forward dict(run-multi-review.py:478-488)将 MULTI_REVIEW_REASONING_EFFORTMULTI_REVIEW_ENABLE_THINKING 写入 opencode.json(第 525-528 行),但未将其转发为子进程可识别的标准 env 变量(如 OPENCODE_REASONING_EFFORTOPENCODE_ENABLE_THINKING)。虽通过 JSON 配置已能满足当前需求,但与其他 action 的 env 转发模式不一致,若 run-opencode.sh 后续版本优先读取 env 变量而非 JSON 配置,则这两个设置可能失效。
  • 建议修复: 在 env_forward 中添加 "OPENCODE_REASONING_EFFORT": ("MULTI_REVIEW_REASONING_EFFORT", "")"OPENCODE_ENABLE_THINKING": ("MULTI_REVIEW_ENABLE_THINKING", "true")

New%20session%20-%202026-05-19T10%3A16%3A42.943Z
opencode session  |  github run

@github-actions

Copy link
Copy Markdown

架构有疑虑

该 PR 的 multi-review action 在目录结构、composite action 规范(Linux 检查、version 解析、paths 计算、cache 配置、install 步骤)上严格遵循了项目既有约定,模块放置合理。但存在以下架构层面的疑虑:

阻塞项:无

建议项:

  1. 绕过 github-run-opencode 共享编排层,导致关键逻辑重复与维护分歧 — 项目存在清晰的 3 层架构:run-opencode/run-opencode.shgithub-run-opencode/run-github-opencode.py(共享编排层)→ 各 opinionated action(review/architect-review/ 等)。所有现有 opinionated action 均委托至 Layer 2 的 run-github-opencode.py。但 run-multi-review.py 跳过该层直接调用 run-opencode.sh,在自身中重新实现了以下与 run-github-opencode.py高度重叠的逻辑:

    功能 run-github-opencode.py run-multi-review.py
    API key 过滤 supports_model_with_available_key (L33-40) _supports_model (L268-275)
    Error comment 清理 cleanup_error_comments (L168-243) cleanup_error_comments (L399-450)
    opencode.json 配置 configure_opencode_json (L71-112) 内联逻辑 (L516-538)
    Fallback timeout 计算 compute_effective_timeout (L146-165) 内联计算 (L230-238)

    后续若在单审模式中修复 bug(如新增 API key 模型提供商、改进 fallback 正则、优化 error comment 检测逻辑),multi-review 需要手动同步,存在维护分歧风险。建议将上述公共逻辑抽取为 github-run-opencode/shared.py 模块供两个脚本引用。由于 multi-review 需要多 reviewer 并行执行(ThreadPoolExecutor),确实无法直接复用 run-github-opencode.py 的顺序 fallback 流程,但辅助函数级别的抽取完全可行。

  2. reviewer-timeout-seconds 输入已定义但从未被 Python 消费action.yml:57-60 定义 reviewer-timeout-seconds(默认 300),action.yml:215 映射为 MULTI_REVIEW_REVIEWER_TIMEOUT_SECONDS 环境变量,但 run-multi-review.py _main() 中未读取该值。实际 per-reviewer 超时由 model-timeout-seconds → MULTI_REVIEW_MODEL_TIMEOUT_SECONDSmodel_timeout 参数控制。reviewer-timeout-seconds成为幽灵输入,用户配置被静默忽略,且与model-timeout-seconds` 语义几乎重叠造成混淆。建议删除该输入或将其用于独立于 model fallback 超时的 reviewer 级别超时控制。

  3. _parse_simple_yaml 对嵌套 YAML 静默降级 — 当 PyYAML 未安装时,自定义配置文件的 personas/reviewers 列表被扁平解析器处理,嵌套结构完全丢失,自定义配置被静默忽略且无任何警告。这是架构层面的可靠性缺口——功能声明("Supports custom personas via YAML config")与降级路径的实际表现不匹配。建议在检测到自定义配置期望嵌套结构但无法解析时,输出 stderr 警告并继续使用内置默认值,而非静默降级。

  4. 缺少 fallback_on_regex 合法性校验run-github-opencode.py:327 通过 validate_regex 校验正则合法性,run-multi-review.py 缺失该项检查。虽然 re.search 异常被 except Exception 捕获,但非法正则静默降级不利于调试。建议补充 validate_regex 调用保持一致。

New%20session%20-%202026-05-19T10%3A18%3A12.443Z
opencode session  |  github run

- Call post_pr_comment() in the global-timeout-exceeded fallback path
  (was only printing to stdout)
- Remove dead `reviewer-timeout-seconds` input (was mapped to env var
  but never read by Python; replaced by `model-timeout-seconds`)
- Fix duplicate MULTI_REVIEW_MODEL_TIMEOUT_SECONDS env mapping
- Sync fallback-on-regex default in Python with action.yml value
- Expand README inputs table: add attempts, retry-profile,
  retry-delay-seconds, use-github-token, extra-env,
  cleanup-error-comments; remove removed reviewer-timeout-seconds

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Confirmed: Future 引用已被清除(6 个 commits 中的 a8da235 已修复),reviewer-timeout-seconds 输入不存在于当前代码中。当前 HEAD(0600de4)已无这些遗留问题。

可合并

总结

PR 实现了功能完整的 multi-agent 并行代码审查 action,架构清晰,测试覆盖良好(21/21)。对比此前多轮 review 意见,当前 HEAD 已修正了 Future 类型注解缺失、model-timeout-seconds 接线断裂、format_pr_comment 未发布到 PR、fallback-on-regex 默认值不匹配、fallback 降级路径未调用 post_pr_comment 等问题。当前代码无运行时崩溃风险,核心功能完整可用。

阻塞项:无

建议项:

  1. _parse_simple_yaml 对嵌套 YAML 结构静默降级run-multi-review.py:56-91):当 PyYAML 未安装时,自定义配置文件中 personas/reviewers 列表等嵌套结构被扁平解析器完全丢弃,custom_data.get("personas", []) 返回 [],无任何告警,用户自定义审查者配置静默失效。标准 GitHub Actions runner 预装了 python3-yaml,此路径鲜少触发,但一旦触发排查困难。建议在 _parse_simple_yaml 返回后检测预期键缺失时输出 stderr 警告,或 import yaml 失败时直接报错。

  2. opencode.json 写入可能破坏 JSONC 格式文件run-multi-review.py:517-538):enable-thinking 默认 "true" 导致 needs_config 恒为 True。使用 json.load 读取 + json.dump 覆写,若原文件含 JSONC 注释(///* */),json.load 抛出 json.JSONDecodeErrorconfig = {},原文件数据丢失。建议 json.load 失败时跳过覆写。

  3. gh api 未使用分页run-multi-review.py:425-429):cleanup_error_comments 获取 PR 评论时未加 --paginate,仅获取第一页(默认 30 条)。若 PR 评论较多,超出一页的评论不会被扫描清理。

  4. finally 块无条件执行 cleanup_error_commentsrun-multi-review.py:455-459):即使所有 reviewer 和 coordinator 均成功,仍发起一次无必要的 GitHub API 评论遍历。建议仅在 _main() 非零返回时执行。

  5. Reviewer 编排逻辑与 run-github-opencode.py 存在约 40% 重叠:API key 过滤(_supports_model)、error comment 清理(cleanup_error_comments)、fallback timeout 计算、opencode.json 配置注入等多段逻辑有独立实现。后续单审模式修复 bug 时需手动同步。建议抽取共享模块。

  6. 四个 reviewer 提示词模板高度同构reviewers/*.yaml 的结构和输出格式段落 95% 相同,仅审查维度和决策标签不同。建议通过统一模板 + 参数化替换削减重复。

New%20session%20-%202026-05-19T10%3A23%3A29.346Z
opencode session  |  github run

@github-actions

Copy link
Copy Markdown

发现遗漏

摘要

PR 实现了核心并行审查框架,所有主要特性(四个内置审查角色、协调器合成、模型 fallback、审查员冗余、单评论输出)均已编码。存在 1 处中等和 2 处低严重度实现缺口。


MEDIUM

1. 自定义 YAML 配置文件在 PyYAML 不可用时被静默忽略

  • 描述: PR body 声明 "Supports custom personas via YAML config",README §"Custom Reviewer Config File"(第 63-81 行)展示的格式包含嵌套结构(personas: [...]reviewers: [...])。代码第 19-22 行处理了 yaml 模块不可用的情况,降级使用 _parse_simple_yaml()(第 55-91 行)。但该函数仅能解析扁平的 name: / prompt: 键值对,无法解析列表和嵌套字典。resolve_reviewers() 第 117 行调用该函数后,custom_data.get("personas", []) 返回空列表,用户的自定义审查者配置被完全静默忽略,无任何错误或警告。
  • 相关 spec: PR body "Supports custom personas via YAML config" + README "Custom Reviewer Config File" 章节
  • 建议修复: 在 _parse_simple_yaml() 返回后检测自定义配置中是否期望 personas/reviewers 键但未找到,输出 stderr 警告;或当 PyYAML 不可用时直接报错退出并提示安装 pyyaml

LOW

2. OPENCODE_REASONING_EFFORT / OPENCODE_ENABLE_THINKING 未通过 env_forward 转发为子进程标准环境变量

  • 描述: 这两个值通过 MULTI_REVIEW_REASONING_EFFORTMULTI_REVIEW_ENABLE_THINKING 从 action.yml 接收,并写入 opencode.json(第 525-528 行)。但 env_forward 字典(第 478-488 行)缺少对应的 OPENCODE_REASONING_EFFORTOPENCODE_ENABLE_THINKING 映射。与其他环境变量(如 OPENCODE_ATTEMPTSOPENCODE_RETRY_PROFILE 等)的转发模式不一致。虽通过 JSON 配置已能满足当前需求,但子进程若独立读取标准环境变量则会获取不到配置值。
  • 相关 spec: README 输入表第 109-110 行列出了 reasoning-effortenable-thinking
  • 建议修复: 在 env_forward 中添加 "OPENCODE_REASONING_EFFORT": ("MULTI_REVIEW_REASONING_EFFORT", "")"OPENCODE_ENABLE_THINKING": ("MULTI_REVIEW_ENABLE_THINKING", "true"),与第 480-482 行的模式保持一致。

3. README 输入表未列出多个共享基础设施输入

  • 描述: README 输入表(第 95-117 行)未列出 install-urlinstall-dirxdg-cache-homecachecache-keyinstall-attemptsallow-preinstalledversionworking-directory 共 9 个 action 输入。这些输入在 action.yml 中有定义且有默认值,会影响 action 的安装和运行行为。
  • 相关 spec: README 声明的 "## Inputs" 表格应完整反映用户可用的配置项
  • 建议修复: 在 README 输入表中补充缺失的共享输入,或增加说明引导用户参考 setup-opencode 文档。

New%20session%20-%202026-05-19T10%3A23%3A31.453Z
opencode session  |  github run

@github-actions

Copy link
Copy Markdown

架构有疑虑

架构分析

该 PR 新增的 multi-review action 在目录结构(顶层与 review/ 等平级)、composite action 规范(Linux-only 检查、version 解析、paths 计算、cache 配置、install 步骤)和测试文件放置(tests/test_multi_review.py)上严格遵循了项目既有约定,模块放置合理。

但存在以下架构层面的疑虑:

1. 绕过 github-run-opencode 共享编排层,导致关键逻辑重复

项目存在清晰的 3 层架构:run-opencode/run-opencode.sh(原始 CLI 调用)→ github-run-opencode/run-github-opencode.py(共享编排层:model fallback、API key 过滤、timeout 计算、error comment 清理、opencode.json 配置)→ 各 opinionated action(review/architect-review/feature-missing/spec-coverage/)。

所有现有 opinionated action 均通过 python3 ${{ github.action_path }}/../github-run-opencode/run-github-opencode.py 委托至 Layer 1。而 multi-review/action.yml:237 直接调用自身的 run-multi-review.py,后者绕过 Layer 1 直接调用 run-opencode/run-opencode.sh,并在自身中重新实现了以下与 run-github-opencode.py 高度重叠的逻辑:

功能 run-github-opencode.py run-multi-review.py
API key 过滤 supports_model_with_available_key (L33-40) _supports_model (L268-275)
Error comment 清理 cleanup_error_comments (L168-243) cleanup_error_comments (L399-450)
opencode.json 配置 configure_opencode_json (L71-112) 内联逻辑 (L516-538)
Fallback timeout 计算 compute_effective_timeout (L146-165) 内联计算 (L230-238)
Fallback 循环 _main 中的循环 (L377-426) run_reviewer 中的循环 (L228-264)

后续若在单审模式中修复 bug(如新增 model API key 提供商、改进 fallback 正则检测、优化 error comment 识别逻辑),multi-review 需要手动同步,存在维护分歧风险。虽然并行执行模式(ThreadPoolExecutor)决定了无法直接复用 run-github-opencode.py 的顺序编排流程,但上述辅助函数级别的复用完全可行——应抽取为 github-run-opencode/shared.py

2. _parse_simple_yaml 对嵌套 YAML 结构静默降级

_parse_simple_yaml(L55-92)只能解析 name: / prompt: 扁平的 key-value 对。当 PyYAML 未安装时,自定义配置文件(README 文档中使用了 personas: [...]reviewers: [...] 嵌套列表格式)会被扁平解析处理,custom_data.get("personas", []) 返回空列表。自定义 reviewer persona 定义和 reviewer team 配置被完全静默忽略,无任何错误或警告,用户得到的仍是默认 quality:1,security:1 团队。这是接口声明能力与降级路径实际表现的不匹配。

3. opencode.json 读写模式对 JSONC 格式不兼容

L516-538 使用 json.load 读取 + json.dump 覆写 opencode.json。若原文件含 ///* */ 注释(JSONC 格式,opencode 自身支持),json.load 抛出异常后 config = {},覆写导致原文件内容丢失。此问题与 run-github-opencode.pyconfigure_opencode_json 的行为一致,说明这是项目层面的共性问题,但在 multi-review 中提示了需要更安全的写入策略。

4. env_forward 未映射 OPENCODE_REASONING_EFFORTOPENCODE_ENABLE_THINKING 标准环境变量

L477-490 的 env_forward 字典将 MULTI_REVIEW_REASONING_EFFORTMULTI_REVIEW_ENABLE_THINKING 写入 opencode.json(L525-528),但未映射为标准环境变量名传递给子进程。虽然通过 JSON 配置当前能满足需求,但与 run-github-opencode.py 既有的 OPENCODE_REASONING_EFFORT / OPENCODE_ENABLE_THINKING 转发模式不一致。若 run-opencode.sh 后续版本优先读取环境变量而非 JSON 配置,这两个设置将失效。

阻塞项:无

建议项:

  1. _supports_modelcleanup_error_commentsconfigure_opencode_jsoncompute_effective_timeout 等公共辅助函数抽取到 github-run-opencode/shared.py,消除 multi-review 与单审编排层之间的维护分歧。
  2. _parse_simple_yaml 检测到无法解析 personas/reviewers 等嵌套 key 时,输出 stderr 警告说明自定义配置将无法生效,并建议安装 PyYAML
  3. 修改 opencode.json 写入策略:json.load 失败时不覆写原文件,或先尝试 json5 / jsonc 解析。
  4. env_forward 中补充 OPENCODE_REASONING_EFFORT: ("MULTI_REVIEW_REASONING_EFFORT", "")OPENCODE_ENABLE_THINKING: ("MULTI_REVIEW_ENABLE_THINKING", "true") 的映射。

New%20session%20-%202026-05-19T10%3A25%3A03.577Z
opencode session  |  github run

@Svtter Svtter merged commit f0f2142 into main May 19, 2026
4 checks passed
@Svtter Svtter mentioned this pull request May 27, 2026
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