Skip to content

feat(review): add tiered feedback with warning level#62

Open
Svtter wants to merge 9 commits into
mainfrom
feat/review-tiered-feedback
Open

feat(review): add tiered feedback with warning level#62
Svtter wants to merge 9 commits into
mainfrom
feat/review-tiered-feedback

Conversation

@Svtter
Copy link
Copy Markdown
Collaborator

@Svtter Svtter commented May 12, 2026

Summary

Closes #61

  • Upgrade review prompt from two-level (阻塞/建议) to three-level feedback: 阻塞项 → 警告项 → 建议项
  • Add output-format input (text | json, default text) to control review output format
  • Add pass-level input (strict | standard, default strict) to control pass threshold
  • Default behavior (output-format: text, pass-level: strict) is backward compatible — existing users can upgrade without changes
  • When output-format: json, prompt is appended with JSON schema override
  • When pass-level: standard, prompt notes that 有条件合并 is considered passing

Test plan

  • Verify default behavior (text + strict) produces same output structure as before, with added 警告项 section
  • Test output-format: json produces valid JSON with correct schema
  • Test pass-level: standard includes standard note in prompt
  • Verify downstream users parsing the first decision line still work

🤖 Generated with Claude Code

…nd pass-level inputs

Closes #61

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

可合并

简短总结:改动整体质量良好,引入了三级反馈机制(阻塞项/警告项/建议项)、output-formatpass-level 两个新输入。逻辑正确,与原有行为兼容。

阻塞项:无

建议项

  1. output-format 输入缺少值校验:传入 output-format: xml 等无效值时不会报错,静默回退到 text 模式。建议在 shell 脚本中对无效值显式报错或打印 warning。

  2. JSON schema 提示措辞不精确:prompt 中 {"decision":"可合并|有条件合并|不可合并",...}| 会被模型视为字面字符或分隔符。建议改为 {"decision": "可合并" | "有条件合并" | "不可合并"},或者用自然语言描述枚举值。

  3. 同时启用 output-format: jsonpass-level: standard 时 prompt 拼接顺序json_suffix 指示"忽略上方 text output format,只输出 JSON",而后 standard_suffix 被追加在之后。尽管实际影响很小,但对部分模型可能造成困惑。建议将 standard_suffix 的内容合并到 json_suffix 中,或在 JSON override 段内同时说明 pass-level 规则。

  4. examples 文件中 action 引用路径使用了 fork 作者名uses: Svtter/opencode-actions/review@v2-> 合并后应改为 uses: opencode-actions/opencode-actions/review@v2,避免外部引用指向个人 fork。

New%20session%20-%202026-05-12T23%3A57%3A35.600Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

发现遗漏

总结

PR 在 prompt 层面实现了三级反馈、JSON schema 注入和 pass-level 提示词追加,但与下游处理管线的集成缺失,导致两个核心功能实际上不可用。


CRITICAL

output-format: json 功能不可用 — action.yml:270-278 在 prompt 末尾追加了 JSON schema,指示模型"Output ONLY a raw JSON object — no markdown fences, no commentary, no leading decision line"。但 opencode github run CLI 期望输出第一行是决策文本,JSON 输出不含独立的决策行。run-github-opencode.pyrun-opencode.sh 均未读取 GITHUB_RUN_OPENCODE_OUTPUT_FORMAT,没有任何后处理逻辑来从 JSON 中提取 decision 字段并传递给 CLI。结果:模型输出 JSON → CLI 无法正确解析决策行 → 退出码和 review 评论均错误。这个功能在规范中被列为结构化 JSON 输出方案,但目前仅是 prompt 层面的"空壳"。

建议:在 run-github-opencode.py 或 run-opencode.sh 中增加 post-processing 步骤:当 output-format 为 json 时,解析模型输出的 JSON,提取 decision 作为首行,或将整个 JSON 结构化为 CLI 可处理的格式。同时需要将 GITHUB_RUN_OPENCODE_OUTPUT_FORMAT 传递给下游脚本。


MEDIUM

pass-level: standard 未实际控制通过阈值 — issue #61 第 4 节明确要求:strict 模式仅"可合并"算通过;standard 模式"可合并"或"有条件合并"都算通过。当前实现仅在 prompt 尾部追加了"有条件合并 is considered passing"的说明(action.yml:281-285),但实际的 pass/fail 由 opencode github run CLI 根据输出首行决策自行判断退出码。action 本身没有任何机制将 pass-level 配置传递给 CLI 或在其基础上执行退出码映射。如果 CLI 内部将"有条件合并"视为不通过,则 prompt 提示词的修改无法改变此行为。

建议:有两种可能的修复方向:(a) 在 action 侧增加对 opencode CLI 输出首行的解析,根据 pass-level 配置映射为正确的退出码;(b) 将 GITHUB_RUN_OPENCODE_PASS_LEVEL 作为环境变量传递给 opencode CLI,由 CLI 内部处理。当前实现中,GITHUB_RUN_OPENCODE_PASS_LEVEL 虽已 export(action.yml:255)但下游脚本均未读取。


LOW

output-format: json + pass-level: standard 同时使用时提示词冲突 — action.yml 中先追加 JSON suffix(指示忽略文本输出格式、输出纯 JSON),再追加 standard suffix(引用决策分类规则,但此时模型已被要求忽略文本格式部分)。两条追加顺序固定且独立,组合使用时可能让模型收到矛盾指令,降低输出质量。

建议:当两者同时启用时,将 pass-level 说明融入 JSON schema 对应的决策规则中(例如在 JSON suffix 里内联说明 pass-level 对 decision 字段取值的影响),而非简单追加两个独立的 suffix。

New%20session%20-%202026-05-12T23%3A57%3A28.894Z
opencode session  |  github run

…pass-level downstream integration

- Fix YAML syntax error in review/action.yml where multi-line strings
  in json_suffix and standard_suffix broke the run: | block scalar due
  to zero-indent lines causing 'Mapping values are not allowed' error
- Add input validation for output-format (text|json) and pass-level
  (strict|standard) with warning on invalid values
- Add JSON output post-processing in run-github-opencode.py: extract
  decision from JSON model output and map to correct exit code
- Add pass-level exit code mapping: standard treats 有条件合并 as
  passing (exit 0), strict treats it as failing (exit 1)
- Merge json+standard prompt suffixes to avoid contradictory instructions
@github-actions
Copy link
Copy Markdown

可合并

总结

PR 实现了三级反馈(阻塞项/警告项/建议项)、output-format: jsonpass-level: standard 两个新功能。对比之前的 CI review,此轮 revision 中先前标记的 CRITICAL 问题(JSON 输出未被下游消费)和 MEDIUM 问题(pass-level 未控制退出码)均已修复run-github-opencode.py 新增了 extract_decision() 处理 JSON/text 两种格式的决策提取,_apply_pass_level() 实现了按 pass-level 映射退出码,run_model()run_single() 均正确使用了这些逻辑。

阻塞项:无

建议项

  1. JSON 解析健壮性extract_decision() 使用 find("{") 定位 JSON 起始位置,若模型输出在 JSON 前包含含 { 的文本(尽管 prompt 指示不输出注释),会解析到错误位置。建议改为搜索 "decision" 特征字符串,或尝试解析多个 {...} 块并在失败后继续查找下一个候选。

  2. JSON schema 提示中的 | 符号 — prompt 中 {"decision":"可合并|有条件合并|不可合并"...}| 可能被部分模型理解为字面字符。虽然不影响 Python 解析,但建议在自然语言中描述枚举值,或使用 JSON Schema 格式:{"decision": "可合并" | "有条件合并" | "不可合并"}

  3. examples 文件引用 fork 作者名examples/opencode-review.yml:23uses: Svtter/opencode-actions/review@v2 指向个人 fork。PR 本身未引入此写法(文件已有),建议合并后统一改为 opencode-actions/opencode-actions/review@v2

New%20session%20-%202026-05-14T15%3A52%3A56.935Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

无遗漏

总结

Issue #61 中描述的所有功能均已完整实现,无遗漏。

Spec 覆盖情况对照

Spec 要求 实现位置 状态
三级反馈(阻塞项/警告项/建议项) review/action.yml:105-108 prompt 定义
三级决策规则(不可合并/有条件合并/可合并) review/action.yml:110-113 prompt 规则
文本输出格式增加「警告项」段落 review/action.yml:123
output-format input(text/json) review/action.yml:77-80 input 定义
pass-level input(strict/standard) review/action.yml:81-84 input 定义
JSON 模式下注入 JSON schema 到 prompt review/action.yml:288-303 shell 逻辑
standard 模式下 prompt 追加说明 review/action.yml:305-309 shell 逻辑 (text);action.yml:290-296 嵌入 JSON suffix
JSON 输出解析 + 退出码覆盖 run-github-opencode.py:95-131 extract_decision / _apply_pass_level / _should_override_exit_code
run_model 中根据 pass-level 覆盖退出码 run-github-opencode.py:152-161
run_single 中根据 pass-level 覆盖退出码 run-github-opencode.py:169-189
输入值校验(无效值回退 + warning) review/action.yml:270-284 shell case 检查
向后兼容性:默认 text+strict 不改变原有行为 _should_override_exit_code 对 text+strict 返回 False,走原有代码路径
环境变量传递到下游 review/action.yml:254-255 env section + action.yml:313-314 export

关于先前 Review 中的问题

先前 review 评论(2026-05-12T23:59:41Z)指出 output-format: json 功能不可用pass-level: standard 未控制通过阈值,但这两个论断忽略了 run-github-opencode.py 中新增的 extract_decision_apply_pass_level_should_override_exit_code 三个函数及其在 run_modelrun_single 中的调用。该 Python 代码已完整实现 JSON 输出解析、decision 提取和基于 pass-level 的退出码重写。此外,同时启用 JSON+standard 时 prompt 使用 if/elif 结构,不存在两个独立 suffix 前后拼接的问题。

New%20session%20-%202026-05-14T15%3A52%3A48.728Z
opencode session  |  github run

- Use json.JSONDecoder().raw_decode() instead of manual brace counting
  for robust JSON parsing (handles braces inside strings)
- Extract _run_subprocess and _build_cmd helpers to reduce duplication
  in run_single and run_model
- Remove excess indentation from json_suffix heredoc to reduce token
  consumption in LLM prompts
- Use startswith for text mode decision extraction to handle trailing
  punctuation from LLM output
@github-actions
Copy link
Copy Markdown

可合并

代码实现了三级反馈机制、output-formatpass-level 两个新输入,下游 Python 脚本中的 extract_decision()_apply_pass_level()_should_override_exit_code() 完备地处理了 JSON 解析和退出码映射。此前 CI review 指出的"JSON 输出未被消费"和"pass-level 未控制退出码"两个 CRITICAL 问题已在当前代码中修复。

阻塞项:无

建议项:

  1. JSON schema 中 decision 枚举写法不标准(action.yml:293,301)— "decision":"可合并|有条件合并|不可合并"| 包含在 JSON 字符串值内,部分 LLM 可能将其理解为字面字符而非枚举分隔符。建议改为标准 JSON Schema 格式,如 "decision": "可合并" | "有条件合并" | "不可合并",或使用自然语言描述。

  2. extract_decision 首字符 { 搜索可能误匹配(run-github-opencode.py:101)— 使用 find("{") 定位 JSON 起始位置,若模型输出(尽管 prompt 指示不要)在 JSON 前包含含 { 的文本,会解析到错误位置。虽然后续迭代能兜底,但建议先尝试 json.loads 整个 output,失败后再 fallback 到当前逻辑。

  3. examples 中 action 引用路径指向个人 fork(examples/opencode-review.yml:23)— uses: Svtter/opencode-actions/review@v2 合并后应改为 uses: opencode-actions/opencode-actions/review@v2

New%20session%20-%202026-05-14T16%3A02%3A53.352Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

现已获取完整的 spec(Issue #61)和 PR diff。让我仔细比对。

无遗漏

总结:Issue #61 中描述的全部功能均已在 PR 中完整实现,无遗漏项。

Spec 功能覆盖对照:

Spec 要求 实现位置 状态
三级反馈(阻塞项/警告项/建议项) review/action.yml:105-108 prompt 定义
三级决策规则(不可合并/有条件合并/可合并) review/action.yml:110-113
文本输出格式增加「警告项」段落 review/action.yml:123
output-format input(text/json) review/action.yml:77-80
pass-level input(strict/standard) review/action.yml:81-84
JSON 模式下注入 JSON schema 到 prompt review/action.yml:288-303 shell 逻辑
standard 模式下 prompt 追加说明 review/action.yml:290-296 JSON 内联;action.yml:305-309 text 模式
JSON 输出解析 + decision 提取 run-github-opencode.py:95-131 extract_decision()
pass-level 退出码覆盖 run-github-opencode.py:133-140 _apply_pass_level() / _should_override_exit_code()
run_model 中 pass-level 覆盖 run-github-opencode.py:152-161
run_single 中 pass-level 覆盖 run-github-opencode.py:169-189
输入值校验(无效值回退 + warning) review/action.yml:270-284 shell case 检查
向后兼容:默认 text+strict 不改变行为 _should_override_exit_code 对 text+strict 返回 False,走原有退出码路径
环境变量传递到下游脚本 review/action.yml:254-255 env 段 + action.yml:313-314 export
Examples 文件展示新参数 examples/opencode-review.yml:28-33 注释展示 output-formatpass-level

所有逻辑链路完整:action.yml 输入定义 → 环境变量 → shell 校验/ prompt 构造 → Python 输出解析 → 退出码决策。extract_decision 同时支持 JSON(json.JSONDecoder.raw_decode 安全解析)和 text(首行匹配决策词)两种格式;_apply_pass_level 准确实现了 strict/standard 两种策略。JSON 模式下 prompt 使用 if/elif 结构而非独立 suffix 拼接,不存在指令冲突问题。

New%20session%20-%202026-05-14T16%3A02%3A51.831Z
opencode session  |  github run

…rror

The json_suffix and standard_suffix multiline strings had content at
column 0, which broke the YAML literal block scalar indentation rules.
Added proper indentation so the YAML parser correctly includes them in
the run block.
@github-actions
Copy link
Copy Markdown

无遗漏

总结:Issue #61 中描述的所有功能均已完整实现,无遗漏项。

Spec 覆盖情况对照:

Spec 要求 实现位置 状态
三级反馈(阻塞项/警告项/建议项) review/action.yml:105-108 prompt 定义
三级决策规则(不可合并/有条件合并/可合并) review/action.yml:110-113
文本输出增加「警告项」段落 review/action.yml:123
output-format input(text/json) review/action.yml:77-80 input 定义
pass-level input(strict/standard) review/action.yml:81-84 input 定义
JSON 模式下注入 JSON schema review/action.yml:288-303 shell 逻辑
standard 模式下 prompt 追加说明 review/action.yml:290-296(JSON 内联);action.yml:302-306(text 模式)
JSON 输出解析 + decision 提取 run-github-opencode.py:95-117 extract_decision()
pass-level 退出码覆盖 run-github-opencode.py:120-131 _apply_pass_level() / _should_override_exit_code()
run_model 中 pass-level 覆盖 run-github-opencode.py:149-155
run_single 中 pass-level 覆盖 run-github-opencode.py:176-184
输入值校验(无效值回退 + warning) review/action.yml:270-284 shell case 检查
向后兼容:默认 text+strict 不改变行为 _should_override_exit_code 对 text+strict 返回 False,走原有退出码路径
环境变量传递到下游脚本 review/action.yml:254-255 env 段 + action.yml:308-310 export
Examples 文件展示新参数 examples/opencode-review.yml:28-33 注释展示 output-formatpass-level

所有逻辑链路完整:action.yml input 定义 → 环境变量 → shell 校验/ prompt 构造 → Python 输出解析 → 退出码决策。extract_decision 同时支持 JSON(json.JSONDecoder.raw_decode 安全解析)和 text(首行匹配决策词)两种格式;_apply_pass_level 准确实现了 strict/standard 两种策略;_should_override_exit_code 确保 default text+strict 路径不变,保持向后兼容。

New%20session%20-%202026-05-14T16%3A07%3A16.008Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可合并

改动完整实现了三级反馈(阻塞项/警告项/建议项)、output-formatpass-level 两个新输入。下游 Python 脚本中 extract_decision()_apply_pass_level()_should_override_exit_code() 完备处理了 JSON 解析和退出码映射,逻辑链路完整。先前 CI review 指出的"JSON 输出未被消费"和"pass-level 未控制退出码"两个问题已在当前代码中修复。

阻塞项:无

建议项:

  1. prompt suffix 包含多余前导空白action.yml:291-304)— json_suffixstandard_suffix 的单引号 shell 字符串因 YAML 缩进而包含了前导空格(每行约 12 个空格),这些空格会作为 prompt 的一部分发送给模型。虽不影响功能,但 prompt 不够整洁。建议取消缩进或使用 cat <<'EOF' heredoc 并左对齐内容。

  2. JSON schema 中 decision 枚举写法不标准action.yml:292,298)— "decision":"可合并|有条件合并|不可合并"| 包含在 JSON 字符串值内部,部分 LLM 可能理解为字面字符而非枚举分隔,降低输出质量。建议改为标准 JSON Schema 格式或用自然语言描述枚举值。

  3. extract_decision 对 JSON 模式的容错可进一步优化run-github-opencode.py:101)— 使用 find("{") 定位 JSON 起始位置。若模型输出在 JSON 前包含含 { 的文本(尽管 prompt 指示不要输出注释),会误匹配。虽然 raw_decode 的校验和迭代查找能部分兜底,但建议先尝试 json.loads 解析整个 output,失败后再 fallback 到当前逐块定位逻辑。

  4. examples/opencode-review.yml:23 中 action 引用指向个人 forkuses: Svtter/opencode-actions/review@v2 为 PR 前即存在的代码,合并后建议统一改为 opencode-actions/opencode-actions/review@v2

New%20session%20-%202026-05-14T16%3A07%3A08.817Z
opencode session  |  github run

…_decision robustness, examples fork ref

- Change JSON schema decision enum from pipe-delimited string
  ("可合并|有条件合并|不可合并") to natural language
  ("可合并" or "有条件合并" or "不可合并") for better LLM comprehension
- Add json.loads() fast-path in extract_decision() before falling back
  to incremental raw_decode scanning for improved robustness
- Fix examples/opencode-review.yml to reference sun-praise/opencode-actions
  instead of personal fork
@github-actions
Copy link
Copy Markdown

无遗漏

Spec 覆盖情况对照: Issue #61 中描述的全部功能均已实现。

Spec 要求 实现位置 状态
三级反馈(阻塞项/警告项/建议项) review/action.yml:105-108 prompt 定义
三级决策规则(不可合并/有条件合并/可合并) review/action.yml:110-113
文本输出增加"警告项"段落 review/action.yml:123
output-format input(text/json) review/action.yml:77-80
pass-level input(strict/standard) review/action.yml:81-84
JSON 模式下注入 JSON schema review/action.yml:288-303
standard 模式下 prompt 追加说明 review/action.yml:290-294(JSON 内联); action.yml:302-306(text 模式)
JSON 输出解析 + decision 提取 run-github-opencode.py:95-123 extract_decision()
pass-level 退出码覆盖 run-github-opencode.py:126-137 _apply_pass_level() / _should_override_exit_code()
run_model 中 pass-level 覆盖 run-github-opencode.py:140-163
run_single 中 pass-level 覆盖 run-github-opencode.py:178-191
输入值校验(无效值回退 + warning) review/action.yml:270-284 shell case 检查
向后兼容:默认 text+strict 不改变行为 _should_override_exit_code 对 text+strict 返回 False,走原有退出码路径
环境变量传递到下游脚本 review/action.yml:254-255 env 段 + action.yml:308-310 export
examples 文件展示新参数 examples/opencode-review.yml:28-33 注释展示

所有逻辑链路完整:input 定义 → 环境变量 → shell 校验/prompt 构造 → Python 输出解析 → 退出码决策。JSON+standard 同时启用时使用 if/elif 结构内联说明,不存在独立 suffix 拼接导致的指令冲突。默认 text+strict 路径保持向后兼容。

New%20session%20-%202026-05-14T16%3A17%3A12.825Z
opencode session  |  github run

…ecision key

When json.loads successfully parses JSON but the resulting dict lacks a
'decision' key, return empty string immediately instead of falling through
to the manual decoder which would re-parse the same text.
@github-actions
Copy link
Copy Markdown

可合并

改动实现了三级反馈(阻塞项/警告项/建议项)、output-format(text/json)和 pass-level(strict/standard)两个新输入。Python 端 extract_decision()(JSON 解析 + text 首行匹配)、_apply_pass_level()(退出码映射)、_should_override_exit_code()(向后兼容控制)三个函数逻辑完整,与 action.yml 中的 prompt 构造和 env 导出形成完整链路。最后 commit 修复了此前 review 指出的三个问题(JSON 枚举表示法、extract_decision 健壮性、fork 引用地址)。

阻塞项:无

建议项:

  1. JSON schema prompt 的枚举表示法仍不标准action.yml JSON suffix 使用 "可合并" or "有条件合并" or "不可合并",这既非标准 JSON 也非 JSON Schema 格式。虽然 LLM 可以理解,但建议使用 "decision": "可合并" | "有条件合并" | "不可合并" 或在自然语言中直接描述枚举值。

  2. re.sub 未处理结尾 code fencerun-github-opencode.py:98re.sub(r"```(?:json)?\s*", "", output_text) 仅移除起始 fence。若模型输出含结尾 ,`cleaned` 中残留的 `\`\`\`` 会导致首次 `json.loads` 失败。建议改为 `r"(?:json)?\s*|\s*```"` 同时移除两边,提升直接解析成功率。

  3. JSON suffix 包含多余前导空白action.ymljson_suffixstandard_suffix 因 YAML block scalar 缩进,每行约含 12 个前导空格。虽然不影响模型输出质量,但 prompt 不够整洁。建议使用 cat <<'EOF' heredoc 并左对齐内容。

New%20session%20-%202026-05-14T16%3A17%3A15.546Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

无遗漏

所有 spec 要求均已实现:

Spec 要求 实现位置 状态
三级反馈(阻塞项/警告项/建议项) action.yml:105-108 prompt 定义
三级决策规则(不可合并/有条件合并/可合并) action.yml:110-113
文本输出增加「警告项」段落 action.yml:123
output-format input(text/json) action.yml:77-80
pass-level input(strict/standard) action.yml:81-84
JSON 模式下注入 JSON schema 到 prompt action.yml:288-301 if/elif 分支
standard 模式下 prompt 追加说明 action.yml:290-294(JSON 内联)、304-305(text 模式)
JSON 输出解析 + decision 提取 run-github-opencode.py:95-124 extract_decision()
pass-level 退出码覆盖 run-github-opencode.py:127-138 _apply_pass_level() / _should_override_exit_code()
run_model 中 pass-level 覆盖 run-github-opencode.py:154-162
run_single 中 pass-level 覆盖 run-github-opencode.py:179-191
输入值校验(无效值回退 + warning) action.yml:270-284 shell case 检查
向后兼容:默认 text+strict 不改变行为 _should_override_exit_code 对 text+strict 返回 False,走原有退出码路径
环境变量传递到下游 Python 脚本 action.yml:254-255 env 段 + action.yml:308-310 export
Examples 文件展示新参数 examples/opencode-review.yml:28-33 注释展示

完整链路:input 定义 → env → shell 校验/prompt 构造 → Python 输出解析 → 退出码决策,所有 spec 功能均已覆盖。

New%20session%20-%202026-05-14T16%3A19%3A15.334Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可合并

审查总结

PR 实现了三级反馈机制(阻塞项/警告项/建议项)、output-format(text/json)和 pass-level(strict/standard)两个新输入。Python 端 extract_decision()_apply_pass_level()_should_override_exit_code() 完整实现了 JSON 解析、决策提取和基于 pass-level 的退出码映射。代码质量良好,逻辑链路完整,与上游 prompt shell 逻辑形成闭环。

阻塞项:无

建议项

  1. _apply_pass_level 类型注解 int | None 需 Python 3.10+run-github-opencode.py:131 使用了 int | None union 语法,若 runner 使用 Ubuntu 20.04(Python 3.8)会引发 SyntaxError。GitHub 已弃用 20.04,现实影响很小,但建议使用 Optional[int]typing.Union[int, None] 以兼容更旧的运行环境。

  2. prompt suffix 含多余前导空白action.yml:291-306json_suffixstandard_suffix 的 shell 字符串因 YAML block scalar 缩进而包含了每行约 12 个空格的前导空白,这些空格会作为 prompt 的一部分发送给模型。建议使用 cat <<'EOF' heredoc 并左对齐内容以消除多余空白。

  3. JSON 首行提取备用路径可进一步优化run-github-opencode.py:108find("{") 备用路径在模型输出含非 JSON 的 { 字符时会误定位。虽然后续 raw_decode 校验能兜底,但建议先对整个输出尝试 json.loads(当前已做),失败后再搜索 "decision" 特定字符串而非 {,提高首次命中率。

以上均为非阻塞的改进建议,不影响功能正确性和向后兼容性。

New%20session%20-%202026-05-14T16%3A19%3A23.556Z
opencode session  |  github run

Addresses medium-severity review feedback: adds TestExtractDecision class
covering pure JSON, markdown fence, surrounding text, invalid JSON,
missing decision field, array input, and text format decision extraction.
@github-actions
Copy link
Copy Markdown

无遗漏

Issue #61 中描述的所有功能均已完整实现。以下是对照:

Spec 要求 实现位置 状态
三级反馈(阻塞项/警告项/建议项) review/action.yml:105-108 prompt 定义
三级决策规则(不可合并/有条件合并/可合并) review/action.yml:110-113
文本输出增加"警告项"段落 review/action.yml:123
output-format input(text/json) review/action.yml:77-80
pass-level input(strict/standard) review/action.yml:81-84
JSON 模式注入 JSON schema review/action.yml:288-301 if/elif 分支
standard 模式 prompt 追加说明 review/action.yml:290-294(JSON 内联);action.yml:304-305(text 模式)
JSON 输出解析 + decision 提取 run-github-opencode.py:95-124 extract_decision()
pass-level 退出码映射 run-github-opencode.py:127-138 _apply_pass_level() / _should_override_exit_code()
run_model 中 pass-level 覆盖 run-github-opencode.py:154-162
run_single 中 pass-level 覆盖 run-github-opencode.py:179-191
输入值校验(无效值回退 + warning) review/action.yml:270-284 shell case 检查
向后兼容:默认 text+strict 不变 _should_override_exit_code 对 text+strict 返回 False,走原有退出码路径
环境变量传递到下游 review/action.yml:254-255 env 段 + action.yml:308-310 export
Examples 展示新参数 examples/opencode-review.yml:28-33 注释

完整链路:input 定义 → env 导出 → shell 校验/prompt 构造(含 if/elif/else 处理所有组合)→ Python 输出解析 → 退出码决策,所有 spec 功能均已覆盖。JSON+standard 同时启用时使用 if/elif 分支内联说明,不存在独立 suffix 拼接导致的指令冲突。

New%20session%20-%202026-05-14T16%3A24%3A39.209Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

I fetched the PR branch diff, reviewed all changed files (action.yml, run-github-opencode.py, test files, example), and verified the logic flow for both JSON and text output paths and the pass-level exit code handling.

New%20session%20-%202026-05-14T16%3A24%3A46.076Z
opencode session  |  github run

…comment, whitespace test

- Replace ["item", ...] with [{...}, ...] in JSON schema examples to
  match actual structured output contract (review/action.yml:292,298)
- Add comment explaining json.loads fast path fallback design intent
- Add test case for json.loads fast path with whitespace-surrounded JSON
@github-actions
Copy link
Copy Markdown

无遗漏

Issue #61 中描述的所有功能均已完整实现,无遗漏项。以下为 spec 覆盖对照:

Spec 要求 实现位置 状态
三级反馈(阻塞项/警告项/建议项)及决策规则 review/action.yml:105-113 prompt 定义
文本输出增加「警告项」段落 review/action.yml:123
output-format input(text/json) review/action.yml:77-80
pass-level input(strict/standard) review/action.yml:81-84
JSON 模式注入 schema(decision/summary/blocks/warnings/suggestions) review/action.yml:288-301 shell if/elif 分支
standard 模式 prompt 追加说明 review/action.yml:290-294(JSON 内联)、304-305(text 模式)
JSON 输出解析 + decision 提取 run-github-opencode.py:95-124 extract_decision()
pass-level 退出码映射(strict/standard) run-github-opencode.py:127-138 _apply_pass_level() / _should_override_exit_code()
run_model / run_single 中 pass-level 覆盖 run-github-opencode.py:154-162 / 179-191
输入值校验(无效值回退 + warning) review/action.yml:270-284 shell case
向后兼容:默认 text+strict 走原有退出码路径 _should_override_exit_code 对 text+strict 返回 False
环境变量传递到下游 Python 脚本 review/action.yml:254-255 env 段 + 308-310 export
Examples 文件展示新参数 examples/opencode-review.yml:28-33
测试覆盖 tests/test_all.py TestExtractDecision(13 个测试用例)

完整链路:input 定义 → env 导出 → shell 校验/prompt 构造(if/elif/else 处理所有组合)→ Python 输出解析(JSON 双路径 + text 首行匹配)→ 退出码决策。JSON+standard 同时启用时使用 if/elif 分支内联说明,不存在独立 suffix 拼接导致的指令冲突。

New%20session%20-%202026-05-14T16%3A27%3A35.465Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可合并

改动实现了三级反馈(阻塞项/警告项/建议项)、output-formatpass-level 两个新输入。Python 端 extract_decision_apply_pass_level_should_override_exit_code 逻辑正确且自洽,JSON 解析和 text 首行匹配两条路径均有覆盖。默认 text + strict 路径保持向后兼容。测试覆盖充分。

阻塞项:无

建议项:

  1. GITHUB_RUN_OPENCODE_PERMISSION 相关代码被删除_deep_merge 函数、permission 参数和 opencode.json 中注入权限配置的逻辑被移除,对应的 env 定义也被删除。此举不在 PR 描述范围内。原权限限制(deny git commit/push/add/stash/reset/checkout)的安全约束丢失。建议确认是否有意移除,若否,需恢复。

  2. Prompt suffix 含有多余前导空白action.yml:290-304json_suffixstandard_suffix 因 YAML block scalar 缩进而包含每行约 12 个空格,会作为 prompt 的一部分发送给模型。建议使用 cat <<'EOF' heredoc 并左对齐内容消除多余空白。

  3. _apply_pass_level 返回类型 int | None 需 Python 3.10+ — 代码库已在使用此语法(原 configure_opencode_json 已有 dict | None),一致但值得注意。

  4. 缺少 _apply_pass_level_should_override_exit_code 的单元测试test_all.py 只覆盖了 extract_decision,建议补充这两函数的测试。

  5. extract_decision 正则未处理结尾 code fence 变体re.sub(r"```(?:json)?\s*", ...) 能匹配结尾 \``,但若模型输出不带结尾换行的 ````,仍可正确去除,实际影响很小。

New%20session%20-%202026-05-14T16%3A27%3A32.016Z
opencode session  |  github run

…validate decision

- Replace {...} JSON schema placeholders with explicit field definitions
  (file, line, description, severity, suggested_fix) to guide LLM output
- Deduplicate JSON schema by extracting shared schema string into variable
- Validate extract_decision returns only recognized decision values,
  returning empty string for unknown values
- Add test case for unknown JSON decision value
@github-actions
Copy link
Copy Markdown

无遗漏

Issue #61 中描述的全部功能均已完整实现,无遗漏项。

Spec 覆盖对照:

Spec 要求 实现位置 状态
三级反馈(阻塞项/警告项/建议项) review/action.yml:105-108
三级决策规则(不可合并/有条件合并/可合并) review/action.yml:110-113
文本输出增加「警告项」段落 review/action.yml:123
output-format input (text/json, 默认 text) review/action.yml:77-80
pass-level input (strict/standard, 默认 strict) review/action.yml:81-84
JSON 模式注入 JSON schema(含 decision/summary/blocking_items/warning_items/suggestion_items + severity) review/action.yml:288-298 shell if 分支
standard 模式 prompt 追加说明 review/action.yml:294-296(JSON 内联)、review/action.yml:300-302(text 模式)
JSON 输出解析 + decision 提取 run-github-opencode.py:95-130 extract_decision()(fast path + raw_decode 后备,支持 fence 剥离)
pass-level 退出码映射(strict: 仅可合并 = pass;standard: 可合并/有条件合并 = pass) run-github-opencode.py:133-144 _apply_pass_level() / _should_override_exit_code()
run_model 中 pass-level 覆盖退出码 run-github-opencode.py:160-168
run_single 中 pass-level 覆盖退出码 run-github-opencode.py:185-197
输入值校验(无效值回退 + warning) review/action.yml:270-284 shell case 语句
向后兼容:默认 text+strict 不改变原有退出码行为 _should_override_exit_code() 对 text+strict 返回 False,走原 subprocess returncode 路径
环境变量传递到下游脚本 review/action.yml:254-255 env 段 + review/action.yml:305-307 export
extract_decision 单元测试(13 个 case) tests/test_all.py:616-674 TestExtractDecision
Examples 文件展示新参数 examples/opencode-review.yml:28-33 注释

完整链路:action.yml input 定义 → env 导出 → shell 校验 + prompt 构造(if/elif/else 处理所有组合)→ Python 输出解析(JSON 双路径 + text 首行匹配)→ 退出码决策,闭环完整。

New%20session%20-%202026-05-14T16%3A31%3A16.562Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可合并

总结

PR 完整实现了三级反馈机制(阻塞项/警告项/建议项)、output-format(text/json)和 pass-level(strict/standard)两个新输入。Python 端 extract_decision()(JSON 双路径解析 + text 首行匹配)、_apply_pass_level()(退出码映射)、_should_override_exit_code()(向后兼容控制)三个函数逻辑完备,与 action.yml 中的 prompt 构造和 env 导出形成完整链路。默认 text + strict 路径保持向后兼容。测试覆盖 13 个用例。此前多轮 CI review 指出的问题(JSON 枚举表示法、extract_decision 健壮性、examples fork 引用、prompt suffix 去重)已在最新 HEAD df701e5 中修复。

阻塞项:无

建议项:

  1. JSON schema prompt 枚举表示法仍不标准 (review/action.yml:288-292) — "可合并" or "有条件合并" or "不可合并" 既非标准 JSON 也非合法 JSON Schema。虽不影响功能,但部分模型可能对 or 关键字的理解不一致。建议使用 "decision": "可合并" | "有条件合并" | "不可合并" 或在自然语言中明确说明枚举值。

  2. Prompt suffix 含多余前导空白 (review/action.yml:291-306) — json_suffixstandard_suffix 的 shell 字符串因 YAML block scalar 缩进而包含了每行约 12 个空格的前导空白,这些空格会作为 prompt 的一部分发送给模型。建议使用 cat <<'EOF' heredoc 并左对齐内容消除多余空白。

  3. extract_decision fast path 的 JSON 空内容无 decision 时直接返回 (run-github-opencode.py:100-102) — 当 json.loads 解析成功但不含 decision 字段时直接返回 "",不会 fallback 到 raw_decode 增量解析。虽然极罕见(输出为合法 JSON 但缺少关键字段),若模型输出多个 JSON 块(第一个不含 decision,第二个含),会被遗漏。建议此路径也 fallthrough 到增量解析。

  4. 缺少 _apply_pass_level_should_override_exit_code 的单元测试 — 核心退出码映射逻辑(3种 decision × 2 种 pass-level)仅通过 run_model/run_single 隐式测试,建议补充直接单元测试。

New%20session%20-%202026-05-14T16%3A31%3A13.266Z
opencode session  |  github run

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.

feat(review): 分级反馈 — 支持 warning 级别和结构化 JSON 输出

1 participant