From 536b8284a053b247938d5573b5864225d01e8c3b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 30 Jul 2026 13:47:37 +0900 Subject: [PATCH 1/5] fix(review): hand OpenCode approval to Noema --- .../workflows/opencode-review-dispatch.yml | 35 +++ scripts/ci/noema_review_handoff.py | 227 ++++++++++++++++++ tests/test_noema_review_handoff.py | 193 +++++++++++++++ tests/test_opencode_agent_contract.py | 4 +- .../test_required_workflow_queue_contract.py | 49 ++++ 5 files changed, 507 insertions(+), 1 deletion(-) create mode 100644 scripts/ci/noema_review_handoff.py create mode 100644 tests/test_noema_review_handoff.py diff --git a/.github/workflows/opencode-review-dispatch.yml b/.github/workflows/opencode-review-dispatch.yml index 94f5cbb7c..0e1891f1b 100644 --- a/.github/workflows/opencode-review-dispatch.yml +++ b/.github/workflows/opencode-review-dispatch.yml @@ -7233,6 +7233,37 @@ jobs: -f target_url="$RUN_URL" \ -f description="$description" >/dev/null + - name: Dispatch Noema after current-head OpenCode approval + if: >- + always() + && github.event_name == 'repository_dispatch' + && needs.validate-pr-metadata.outputs.target_repository != '' + && needs.validate-pr-metadata.outputs.pr_number != '' + && needs.validate-pr-metadata.outputs.head_sha != '' + continue-on-error: true + timeout-minutes: 18 + env: + GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || steps.opencode_app_token.outputs.token || github.token }} + GH_REPOSITORY: ${{ needs.validate-pr-metadata.outputs.target_repository }} + PR_NUMBER: ${{ needs.validate-pr-metadata.outputs.pr_number }} + PR_HEAD_SHA: ${{ needs.validate-pr-metadata.outputs.head_sha }} + OPENCODE_CHANGED_FILES_FILE: ${{ runner.temp }}/opencode-changed-files.txt + OPENCODE_ARTIFACT_MANIFEST_SHA256: ${{ steps.seal_artifacts.outputs.manifest_sha256 }} + OPENCODE_SOURCE_WORKDIR: ${{ runner.temp }}/opencode-pr-head + OPENCODE_REQUIRE_ADVERSARIAL_VALIDATION: "true" + run: | + set -euo pipefail + if [ -z "${GH_TOKEN:-}" ]; then + echo "::warning::Noema handoff skipped because no target-repository dispatch credential was available." + exit 1 + fi + python3 scripts/ci/noema_review_handoff.py \ + --repo "$GH_REPOSITORY" \ + --pr-number "$PR_NUMBER" \ + --head-sha "$PR_HEAD_SHA" \ + --attempts 90 \ + --interval-seconds 10 + - name: Run merge scheduler after approval continue-on-error: true env: @@ -7244,6 +7275,10 @@ jobs: PR_BASE_REF: ${{ needs.validate-pr-metadata.outputs.base_ref }} PR_NUMBER: ${{ needs.validate-pr-metadata.outputs.pr_number }} PR_HEAD_SHA: ${{ needs.validate-pr-metadata.outputs.head_sha }} + OPENCODE_CHANGED_FILES_FILE: ${{ runner.temp }}/opencode-changed-files.txt + OPENCODE_ARTIFACT_MANIFEST_SHA256: ${{ steps.seal_artifacts.outputs.manifest_sha256 }} + OPENCODE_SOURCE_WORKDIR: ${{ runner.temp }}/opencode-pr-head + OPENCODE_REQUIRE_ADVERSARIAL_VALIDATION: "true" run: | set -euo pipefail if [ -z "${GH_TOKEN:-}" ]; then diff --git a/scripts/ci/noema_review_handoff.py b/scripts/ci/noema_review_handoff.py new file mode 100644 index 000000000..5b74127b5 --- /dev/null +++ b/scripts/ci/noema_review_handoff.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python3 +"""Dispatch Noema after a current-head OpenCode approval and await its verdict.""" + +from __future__ import annotations + +import argparse +import json +import re +import subprocess +import sys +import time +from collections.abc import Callable, Sequence +from typing import Any, TextIO + +from scripts.ci.opencode_existing_approval_gate import ( + flatten_reviews, + has_reusable_real_model_approval, +) +from scripts.ci.redact_sensitive_log import redact_text + + +REPOSITORY_RE = re.compile(r"^ContextualWisdomLab/[A-Za-z0-9_.-]+$") +SHA_RE = re.compile(r"^[0-9a-fA-F]{40}$") +NOEMA_REVIEW_MARKER = "" + ), + } + + +class FakeGitHub: + def __init__( + self, + review_pages: list[list[dict]], + *, + heads: list[str] | None = None, + ) -> None: + self.review_pages = list(review_pages) + self.heads = list(heads or [HEAD]) + self.dispatch_payloads: list[dict] = [] + + def __call__(self, args, stdin=None): + path = next((value for value in args if value.startswith("repos/")), "") + if path.endswith("/dispatches"): + self.dispatch_payloads.append(json.loads(stdin or "{}")) + return "" + if path.endswith("/reviews"): + pages = self.review_pages + if len(self.review_pages) > 1: + pages = [self.review_pages.pop(0)] + return json.dumps(pages) + if "/pulls/" in path: + head = self.heads[0] + if len(self.heads) > 1: + head = self.heads.pop(0) + return head + raise AssertionError(f"unexpected gh args: {args!r}") + + +def test_existing_noema_approval_avoids_duplicate_dispatch(capsys): + fake = FakeGitHub([[opencode_review(), noema_review()]]) + + result = handoff.run_handoff( + "ContextualWisdomLab/example", + 7, + HEAD, + attempts=2, + interval_seconds=0, + runner=fake, + approval_checker=lambda *_args, **_kwargs: True, + ) + + assert result == 0 + assert fake.dispatch_payloads == [] + assert "already published APPROVED" in capsys.readouterr().err + + +def test_missing_primary_approval_never_dispatches(capsys): + fake = FakeGitHub([[]]) + + result = handoff.run_handoff( + "ContextualWisdomLab/example", + 7, + HEAD, + attempts=2, + interval_seconds=0, + runner=fake, + approval_checker=lambda *_args, **_kwargs: False, + ) + + assert result == 1 + assert fake.dispatch_payloads == [] + assert "no reusable OpenCode App" in capsys.readouterr().err + + +def test_dispatches_exact_head_and_waits_for_noema_approval(capsys): + fake = FakeGitHub( + [ + [opencode_review()], + [opencode_review()], + [opencode_review(), noema_review()], + ] + ) + + result = handoff.run_handoff( + "ContextualWisdomLab/example", + 7, + HEAD, + attempts=3, + interval_seconds=0, + runner=fake, + sleeper=lambda _: None, + approval_checker=lambda *_args, **_kwargs: True, + ) + + assert result == 0 + assert fake.dispatch_payloads == [ + { + "event_type": "noema-review", + "client_payload": { + "target_repository": "ContextualWisdomLab/example", + "pr_number": 7, + "pr_head_sha": HEAD, + }, + } + ] + assert "after poll 2/3" in capsys.readouterr().err + + +def test_noema_changes_requested_is_terminal(capsys): + fake = FakeGitHub( + [ + [opencode_review()], + [opencode_review(), noema_review("CHANGES_REQUESTED")], + ] + ) + + result = handoff.run_handoff( + "ContextualWisdomLab/example", + 7, + HEAD, + attempts=2, + interval_seconds=0, + runner=fake, + approval_checker=lambda *_args, **_kwargs: True, + ) + + assert result == 1 + assert "CHANGES_REQUESTED" in capsys.readouterr().err + + +def test_head_change_stops_polling(capsys): + fake = FakeGitHub( + [[opencode_review()], [opencode_review()]], + heads=[HEAD, OTHER_HEAD], + ) + + result = handoff.run_handoff( + "ContextualWisdomLab/example", + 7, + HEAD, + attempts=2, + interval_seconds=0, + runner=fake, + approval_checker=lambda *_args, **_kwargs: True, + ) + + assert result == 2 + assert "head changed" in capsys.readouterr().err + + +def test_run_gh_redacts_credentials_from_failures(monkeypatch): + def fake_run(*_args, **_kwargs): + return CompletedProcess( + args=["gh", "api"], + returncode=1, + stdout="", + stderr="authorization: Bearer ghp_abcdefghijklmnopqrstuvwxyz123456", + ) + + monkeypatch.setattr(handoff.subprocess, "run", fake_run) + + with pytest.raises(RuntimeError) as error: + handoff.run_gh(["api", "repos/ContextualWisdomLab/example"]) + + assert "ghp_" not in str(error.value) + assert "[REDACTED]" in str(error.value) diff --git a/tests/test_opencode_agent_contract.py b/tests/test_opencode_agent_contract.py index 0e791907f..a51dcfb16 100644 --- a/tests/test_opencode_agent_contract.py +++ b/tests/test_opencode_agent_contract.py @@ -1665,7 +1665,9 @@ def test_opencode_runs_merge_scheduler_after_review_without_repo_local_dispatch( assert "github.event_name == 'pull_request_target'" in workflow status_step = workflow.split( " - name: Publish repository_dispatch OpenCode status", 1 - )[1].split(" - name: Run merge scheduler after approval", 1)[0] + )[1].split( + " - name: Dispatch Noema after current-head OpenCode approval", 1 + )[0] assert ( "GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || " "secrets.OPENCODE_APPROVE_TOKEN || github.token }}" diff --git a/tests/test_required_workflow_queue_contract.py b/tests/test_required_workflow_queue_contract.py index 50601fbff..1ea6376fe 100644 --- a/tests/test_required_workflow_queue_contract.py +++ b/tests/test_required_workflow_queue_contract.py @@ -443,6 +443,55 @@ def test_noema_review_mints_a_least_privilege_github_app_token() -> None: assert permission in workflow +def test_opencode_dispatch_hands_approved_head_to_noema_before_merge() -> None: + """The two-reviewer chain must run Noema before the direct merge follow-up.""" + workflow = workflow_text("opencode-review-dispatch.yml") + handoff = workflow_step( + workflow, "Dispatch Noema after current-head OpenCode approval" + ) + + assert workflow.index( + " - name: Dispatch Noema after current-head OpenCode approval" + ) < workflow.index(" - name: Run merge scheduler after approval") + assert "always()" in handoff + assert "github.event_name == 'repository_dispatch'" in handoff + assert ( + "needs.validate-pr-metadata.outputs.target_repository != github.repository" + not in handoff + ) + assert "continue-on-error: true" in handoff + assert "timeout-minutes: 18" in handoff + assert ( + "GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || " + "secrets.OPENCODE_APPROVE_TOKEN || " + "steps.opencode_app_token.outputs.token || github.token }}" + ) in handoff + assert "python3 scripts/ci/noema_review_handoff.py" in handoff + assert '--repo "$GH_REPOSITORY"' in handoff + assert '--pr-number "$PR_NUMBER"' in handoff + assert '--head-sha "$PR_HEAD_SHA"' in handoff + assert "--attempts 90" in handoff + assert "--interval-seconds 10" in handoff + for sealed_env in ( + "OPENCODE_CHANGED_FILES_FILE: ${{ runner.temp }}/opencode-changed-files.txt", + "OPENCODE_ARTIFACT_MANIFEST_SHA256: ${{ " + "steps.seal_artifacts.outputs.manifest_sha256 }}", + "OPENCODE_SOURCE_WORKDIR: ${{ runner.temp }}/opencode-pr-head", + 'OPENCODE_REQUIRE_ADVERSARIAL_VALIDATION: "true"', + ): + assert sealed_env in handoff + + merge_follow_up = workflow_step(workflow, "Run merge scheduler after approval") + for sealed_env in ( + "OPENCODE_CHANGED_FILES_FILE: ${{ runner.temp }}/opencode-changed-files.txt", + "OPENCODE_ARTIFACT_MANIFEST_SHA256: ${{ " + "steps.seal_artifacts.outputs.manifest_sha256 }}", + "OPENCODE_SOURCE_WORKDIR: ${{ runner.temp }}/opencode-pr-head", + 'OPENCODE_REQUIRE_ADVERSARIAL_VALIDATION: "true"', + ): + assert sealed_env in merge_follow_up + + def test_noema_and_scheduler_trusted_checkouts_use_static_main() -> None: noema = workflow_text("noema-review.yml") scheduler = workflow_text("pr-review-merge-scheduler.yml") From 7e4e0feb559cba8490a618ee92c3c161d5d22097 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 30 Jul 2026 14:26:04 +0900 Subject: [PATCH 2/5] test(review): cover Noema handoff gates --- tests/test_noema_review_handoff.py | 165 +++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/tests/test_noema_review_handoff.py b/tests/test_noema_review_handoff.py index 2b376336b..637feee65 100644 --- a/tests/test_noema_review_handoff.py +++ b/tests/test_noema_review_handoff.py @@ -81,6 +81,35 @@ def test_existing_noema_approval_avoids_duplicate_dispatch(capsys): assert "already published APPROVED" in capsys.readouterr().err +def test_noema_state_ignores_reviews_for_other_heads(): + reviews = [ + noema_review("APPROVED", OTHER_HEAD), + noema_review("COMMENTED", HEAD), + ] + + assert handoff.noema_review_state(reviews, HEAD) == "COMMENTED" + assert handoff.noema_review_state([reviews[0]], HEAD) is None + + +def test_stale_initial_head_never_reads_reviews_or_dispatches(capsys): + fake = FakeGitHub([[opencode_review()]], heads=[OTHER_HEAD]) + + result = handoff.run_handoff( + "ContextualWisdomLab/example", + 7, + HEAD, + attempts=2, + interval_seconds=0, + runner=fake, + approval_checker=lambda *_args, **_kwargs: True, + ) + + assert result == 2 + assert fake.review_pages == [[opencode_review()]] + assert fake.dispatch_payloads == [] + assert "refused stale input" in capsys.readouterr().err + + def test_missing_primary_approval_never_dispatches(capsys): fake = FakeGitHub([[]]) @@ -175,6 +204,38 @@ def test_head_change_stops_polling(capsys): assert "head changed" in capsys.readouterr().err +def test_missing_noema_verdict_times_out_closed(capsys): + fake = FakeGitHub([[opencode_review()]]) + + result = handoff.run_handoff( + "ContextualWisdomLab/example", + 7, + HEAD, + attempts=1, + interval_seconds=0, + runner=fake, + approval_checker=lambda *_args, **_kwargs: True, + ) + + assert result == 1 + assert len(fake.dispatch_payloads) == 1 + assert "did not publish an exact-head verdict after 1 polls" in capsys.readouterr().err + + +def test_run_gh_returns_stdout_on_success(monkeypatch): + def fake_run(*_args, **_kwargs): + return CompletedProcess( + args=["gh", "api"], + returncode=0, + stdout="current-head\n", + stderr="", + ) + + monkeypatch.setattr(handoff.subprocess, "run", fake_run) + + assert handoff.run_gh(["api", "repos/ContextualWisdomLab/example"]) == "current-head\n" + + def test_run_gh_redacts_credentials_from_failures(monkeypatch): def fake_run(*_args, **_kwargs): return CompletedProcess( @@ -191,3 +252,107 @@ def fake_run(*_args, **_kwargs): assert "ghp_" not in str(error.value) assert "[REDACTED]" in str(error.value) + + +def test_run_gh_reports_exit_code_when_cli_has_no_output(monkeypatch): + def fake_run(*_args, **_kwargs): + return CompletedProcess(args=["gh", "api"], returncode=9, stdout="", stderr="") + + monkeypatch.setattr(handoff.subprocess, "run", fake_run) + + with pytest.raises(RuntimeError, match="exit code 9"): + handoff.run_gh(["api", "repos/ContextualWisdomLab/example"]) + + +def test_parse_args_accepts_valid_handoff(): + args = handoff.parse_args( + [ + "--repo", + "ContextualWisdomLab/example", + "--pr-number", + "7", + "--head-sha", + HEAD, + "--attempts", + "3", + "--interval-seconds", + "0.5", + ] + ) + + assert args.repo == "ContextualWisdomLab/example" + assert args.pr_number == 7 + assert args.head_sha == HEAD + assert args.attempts == 3 + assert args.interval_seconds == 0.5 + + +@pytest.mark.parametrize( + ("argument", "value", "message"), + [ + ("--repo", "external/example", "ContextualWisdomLab repository"), + ("--pr-number", "0", "pr-number must be positive"), + ("--head-sha", "short", "40-character Git SHA"), + ("--attempts", "0", "attempts must be positive"), + ("--interval-seconds", "-1", "interval-seconds must be non-negative"), + ], +) +def test_parse_args_rejects_unsafe_inputs(argument, value, message, capsys): + argv = [ + "--repo", + "ContextualWisdomLab/example", + "--pr-number", + "7", + "--head-sha", + HEAD, + "--attempts", + "3", + "--interval-seconds", + "0", + ] + argv[argv.index(argument) + 1] = value + + with pytest.raises(SystemExit, match="2"): + handoff.parse_args(argv) + + assert message in capsys.readouterr().err + + +def test_main_passes_validated_arguments_to_handoff(monkeypatch): + observed = {} + + def fake_handoff(repo, number, head_sha, *, attempts, interval_seconds): + observed.update( + repo=repo, + number=number, + head_sha=head_sha, + attempts=attempts, + interval_seconds=interval_seconds, + ) + return 17 + + monkeypatch.setattr(handoff, "run_handoff", fake_handoff) + + result = handoff.main( + [ + "--repo", + "ContextualWisdomLab/example", + "--pr-number", + "7", + "--head-sha", + HEAD, + "--attempts", + "4", + "--interval-seconds", + "1.25", + ] + ) + + assert result == 17 + assert observed == { + "repo": "ContextualWisdomLab/example", + "number": 7, + "head_sha": HEAD, + "attempts": 4, + "interval_seconds": 1.25, + } From 201cca8db52b3a760627670d262957879bb16cc4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 30 Jul 2026 15:24:55 +0900 Subject: [PATCH 3/5] fix(review): harden Noema handoff --- .../workflows/opencode-review-dispatch.yml | 7 +- scripts/ci/noema_review_gate.py | 6 +- scripts/ci/noema_review_handoff.py | 164 ++++++++++++------ scripts/ci/test_strix_quick_gate.sh | 2 +- tests/test_noema_review_gate.py | 15 +- tests/test_noema_review_handoff.py | 88 +++++++++- tests/test_opencode_agent_contract.py | 7 +- 7 files changed, 232 insertions(+), 57 deletions(-) diff --git a/.github/workflows/opencode-review-dispatch.yml b/.github/workflows/opencode-review-dispatch.yml index ec78ee18d..91f54b789 100644 --- a/.github/workflows/opencode-review-dispatch.yml +++ b/.github/workflows/opencode-review-dispatch.yml @@ -1828,9 +1828,10 @@ jobs: # Coverage and current-head evidence are prepared before the model pool. # A single legitimate review may need a full hour. The enclosing job must # contain the 12-minute evidence step, 205-minute provider-pool step, the - # 36-minute publication gate, and setup/cleanup overhead without truncating - # a late current-head verdict or its bounded failure reason. - timeout-minutes: 300 + # 36-minute publication gate, the 18-minute Noema handoff, and setup/cleanup + # overhead without truncating a late current-head verdict, handoff, merge + # scheduler follow-up, or bounded failure reason. + timeout-minutes: 325 permissions: actions: read checks: read diff --git a/scripts/ci/noema_review_gate.py b/scripts/ci/noema_review_gate.py index 5b024c849..9317860e4 100644 --- a/scripts/ci/noema_review_gate.py +++ b/scripts/ci/noema_review_gate.py @@ -266,7 +266,11 @@ def existing_noema_review(pr: dict[str, Any], actor: str) -> bool: continue if str(review.get("state") or "").upper() not in {"APPROVED", "CHANGES_REQUESTED", "COMMENTED"}: continue - if review_author(review) == actor or marker in str(review.get("body") or ""): + if ( + actor + and review_author(review) == actor + and marker in str(review.get("body") or "") + ): return True return False diff --git a/scripts/ci/noema_review_handoff.py b/scripts/ci/noema_review_handoff.py index 5b74127b5..aff595b42 100644 --- a/scripts/ci/noema_review_handoff.py +++ b/scripts/ci/noema_review_handoff.py @@ -21,6 +21,9 @@ REPOSITORY_RE = re.compile(r"^ContextualWisdomLab/[A-Za-z0-9_.-]+$") SHA_RE = re.compile(r"^[0-9a-fA-F]{40}$") +GH_COMMAND_TIMEOUT_SECONDS = 60.0 +MAX_TRANSIENT_BACKOFF_MULTIPLIER = 4 +NOEMA_REVIEW_AUTHOR = "cwl-noema-review[bot]" NOEMA_REVIEW_MARKER = "" assert noema.existing_noema_review( - make_pr(reviews={"nodes": [review(login="noema", body="")]}), + make_pr(reviews={"nodes": [review(login="noema", body=noema_marker)]}), "noema", ) + assert not noema.existing_noema_review( + make_pr(reviews={"nodes": [review(login="human", body=noema_marker)]}), + "noema", + ) + assert not noema.existing_noema_review( + make_pr(reviews={"nodes": [review(login="noema", body="review without gate marker")]}), + "noema", + ) + assert not noema.existing_noema_review( + make_pr(reviews={"nodes": [review(login="", body=noema_marker)]}), + "", + ) assert not noema.existing_noema_review(make_pr(reviews={"nodes": [review("DISMISSED", login="noema")]}), "noema") assert not noema.existing_noema_review(make_pr(reviews={"nodes": [review(commit="old", login="noema")]}), "noema") diff --git a/tests/test_noema_review_handoff.py b/tests/test_noema_review_handoff.py index 637feee65..8d8d01a36 100644 --- a/tests/test_noema_review_handoff.py +++ b/tests/test_noema_review_handoff.py @@ -91,6 +91,13 @@ def test_noema_state_ignores_reviews_for_other_heads(): assert handoff.noema_review_state([reviews[0]], HEAD) is None +def test_noema_state_ignores_forged_marker_from_other_actor(): + forged = noema_review() + forged["user"] = {"login": "untrusted-reviewer"} + + assert handoff.noema_review_state([forged], HEAD) is None + + def test_stale_initial_head_never_reads_reviews_or_dispatches(capsys): fake = FakeGitHub([[opencode_review()]], heads=[OTHER_HEAD]) @@ -159,7 +166,7 @@ def test_dispatches_exact_head_and_waits_for_noema_approval(capsys): }, } ] - assert "after poll 2/3" in capsys.readouterr().err + assert "after poll 3/3" in capsys.readouterr().err def test_noema_changes_requested_is_terminal(capsys): @@ -222,8 +229,76 @@ def test_missing_noema_verdict_times_out_closed(capsys): assert "did not publish an exact-head verdict after 1 polls" in capsys.readouterr().err +def test_transient_poll_failure_retries_and_reaches_noema_verdict(capsys): + fake = FakeGitHub( + [ + [opencode_review()], + [opencode_review(), noema_review()], + ] + ) + review_calls = 0 + observed_sleeps = [] + + def transient_runner(args, stdin=None): + nonlocal review_calls + path = next((value for value in args if value.startswith("repos/")), "") + if path.endswith("/reviews"): + review_calls += 1 + if review_calls == 2: + raise RuntimeError("temporary GitHub API outage") + return fake(args, stdin) + + result = handoff.run_handoff( + "ContextualWisdomLab/example", + 7, + HEAD, + attempts=3, + interval_seconds=2, + runner=transient_runner, + sleeper=observed_sleeps.append, + approval_checker=lambda *_args, **_kwargs: True, + ) + + assert result == 0 + assert observed_sleeps == [2, 2] + assert "Transient GitHub API failure" in capsys.readouterr().err + + +def test_consecutive_initial_failures_use_bounded_exponential_backoff(capsys): + fake = FakeGitHub([[opencode_review(), noema_review()]]) + head_calls = 0 + observed_sleeps = [] + + def transient_runner(args, stdin=None): + nonlocal head_calls + path = next((value for value in args if value.startswith("repos/")), "") + if "/pulls/" in path and not path.endswith("/reviews"): + head_calls += 1 + if head_calls < 3: + raise RuntimeError("rate limited") + return fake(args, stdin) + + result = handoff.run_handoff( + "ContextualWisdomLab/example", + 7, + HEAD, + attempts=3, + interval_seconds=2, + runner=transient_runner, + sleeper=observed_sleeps.append, + approval_checker=lambda *_args, **_kwargs: True, + ) + + assert result == 0 + assert observed_sleeps == [2, 4] + assert "already published APPROVED" in capsys.readouterr().err + + def test_run_gh_returns_stdout_on_success(monkeypatch): + observed = {} + def fake_run(*_args, **_kwargs): + observed.update(_kwargs) return CompletedProcess( args=["gh", "api"], returncode=0, @@ -234,6 +309,17 @@ def fake_run(*_args, **_kwargs): monkeypatch.setattr(handoff.subprocess, "run", fake_run) assert handoff.run_gh(["api", "repos/ContextualWisdomLab/example"]) == "current-head\n" + assert observed["timeout"] == handoff.GH_COMMAND_TIMEOUT_SECONDS + + +def test_run_gh_turns_process_timeout_into_bounded_failure(monkeypatch): + def fake_run(*_args, **_kwargs): + raise handoff.subprocess.TimeoutExpired(["gh", "api"], 60) + + monkeypatch.setattr(handoff.subprocess, "run", fake_run) + + with pytest.raises(RuntimeError, match="timed out after 60 seconds"): + handoff.run_gh(["api", "repos/ContextualWisdomLab/example"]) def test_run_gh_redacts_credentials_from_failures(monkeypatch): diff --git a/tests/test_opencode_agent_contract.py b/tests/test_opencode_agent_contract.py index bd41cd03b..ab09330dd 100644 --- a/tests/test_opencode_agent_contract.py +++ b/tests/test_opencode_agent_contract.py @@ -1248,7 +1248,7 @@ def test_workflow_provisions_sandbox_tool_and_reviewer_agent(): r"Prepare bounded OpenCode review evidence[\s\S]{0,120}timeout-minutes: 12", workflow, ) - assert re.search(r"opencode-review-target:[\s\S]*?timeout-minutes: 300", workflow) + assert re.search(r"opencode-review-target:[\s\S]*?timeout-minutes: 325", workflow) assert "timeout-minutes: 12" in workflow assert re.search( r"Run OpenCode PR Review model pool[\s\S]{0,240}timeout-minutes: 205", workflow @@ -1566,11 +1566,16 @@ def timeout_minutes(pattern: str) -> int: r"^ - name: Publish OpenCode review outcome\n" r"[\s\S]{0,1200}?^ timeout-minutes: (\d+)$" ) + noema_handoff_timeout = timeout_minutes( + r"^ - name: Dispatch Noema after current-head OpenCode approval\n" + r"[\s\S]{0,500}?^ timeout-minutes: (\d+)$" + ) setup_and_cleanup_margin = 30 required_timeout = ( evidence_timeout + model_pool_timeout + max(fast_publish_timeout, normal_publish_timeout) + + noema_handoff_timeout + setup_and_cleanup_margin ) From 32ace05b946794d86e2a0bc4072247bae31da1f3 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 30 Jul 2026 15:41:39 +0900 Subject: [PATCH 4/5] test(review): cover Noema handoff failure paths --- tests/test_noema_review_handoff.py | 100 +++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/tests/test_noema_review_handoff.py b/tests/test_noema_review_handoff.py index 8d8d01a36..433ef23d3 100644 --- a/tests/test_noema_review_handoff.py +++ b/tests/test_noema_review_handoff.py @@ -94,8 +94,11 @@ def test_noema_state_ignores_reviews_for_other_heads(): def test_noema_state_ignores_forged_marker_from_other_actor(): forged = noema_review() forged["user"] = {"login": "untrusted-reviewer"} + unmarked = noema_review() + unmarked["body"] = "review without the authenticated Noema marker" assert handoff.noema_review_state([forged], HEAD) is None + assert handoff.noema_review_state([unmarked], HEAD) is None def test_stale_initial_head_never_reads_reviews_or_dispatches(capsys): @@ -294,6 +297,103 @@ def transient_runner(args, stdin=None): assert "already published APPROVED" in capsys.readouterr().err +def test_final_transient_poll_failure_exhausts_without_dispatch(capsys): + observed_sleeps = [] + + def failing_runner(_args, _stdin=None): + raise RuntimeError( + "authorization: Bearer ghp_abcdefghijklmnopqrstuvwxyz123456" + ) + + result = handoff.run_handoff( + "ContextualWisdomLab/example", + 7, + HEAD, + attempts=2, + interval_seconds=2, + runner=failing_runner, + sleeper=observed_sleeps.append, + approval_checker=lambda *_args, **_kwargs: True, + ) + + log = capsys.readouterr().err + assert result == 1 + assert observed_sleeps == [2] + assert "exhausted its bounded polls" in log + assert "was not dispatched after 2 bounded polls" in log + assert "ghp_" not in log + assert "[REDACTED]" in log + + +def test_transient_dispatch_failure_retries_then_reaches_verdict(capsys): + fake = FakeGitHub( + [ + [opencode_review()], + [opencode_review()], + [opencode_review(), noema_review()], + ] + ) + dispatch_calls = 0 + observed_sleeps = [] + + def transient_runner(args, stdin=None): + nonlocal dispatch_calls + path = next((value for value in args if value.startswith("repos/")), "") + if path.endswith("/dispatches"): + dispatch_calls += 1 + if dispatch_calls == 1: + raise RuntimeError( + "authorization: Bearer ghp_abcdefghijklmnopqrstuvwxyz123456" + ) + return fake(args, stdin) + + result = handoff.run_handoff( + "ContextualWisdomLab/example", + 7, + HEAD, + attempts=3, + interval_seconds=2, + runner=transient_runner, + sleeper=observed_sleeps.append, + approval_checker=lambda *_args, **_kwargs: True, + ) + + log = capsys.readouterr().err + assert result == 0 + assert observed_sleeps == [2, 2] + assert dispatch_calls == 2 + assert len(fake.dispatch_payloads) == 1 + assert "Transient GitHub API failure while dispatching Noema" in log + assert "ghp_" not in log + assert "[REDACTED]" in log + + +def test_final_dispatch_failure_exhausts_without_dispatch(capsys): + fake = FakeGitHub([[opencode_review()]]) + + def failing_dispatch_runner(args, stdin=None): + path = next((value for value in args if value.startswith("repos/")), "") + if path.endswith("/dispatches"): + raise RuntimeError("temporary dispatch outage") + return fake(args, stdin) + + result = handoff.run_handoff( + "ContextualWisdomLab/example", + 7, + HEAD, + attempts=1, + interval_seconds=0, + runner=failing_dispatch_runner, + approval_checker=lambda *_args, **_kwargs: True, + ) + + log = capsys.readouterr().err + assert result == 1 + assert fake.dispatch_payloads == [] + assert "dispatch exhausted its bounded polls" in log + assert "was not dispatched after 1 bounded polls" in log + + def test_run_gh_returns_stdout_on_success(monkeypatch): observed = {} From b515fdc52529da5004edba35dfae7cd62dede4f8 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 30 Jul 2026 16:05:32 +0900 Subject: [PATCH 5/5] fix(review): configure Zen reasoning effort --- .../workflows/opencode-review-dispatch.yml | 32 +++++++++++++++++++ tests/test_opencode_agent_contract.py | 6 ++++ 2 files changed, 38 insertions(+) diff --git a/.github/workflows/opencode-review-dispatch.yml b/.github/workflows/opencode-review-dispatch.yml index 91f54b789..1966a7562 100644 --- a/.github/workflows/opencode-review-dispatch.yml +++ b/.github/workflows/opencode-review-dispatch.yml @@ -3462,6 +3462,14 @@ jobs: "name": "Big Pickle", "tool_call": true, "reasoning": true, + "options": { + "reasoningEffort": "high" + }, + "variants": { + "high": { + "reasoningEffort": "high" + } + }, "limit": { "context": 200000, "output": 32000 @@ -3471,6 +3479,14 @@ jobs: "name": "Laguna S 2.1 Free", "tool_call": true, "reasoning": true, + "options": { + "reasoningEffort": "high" + }, + "variants": { + "high": { + "reasoningEffort": "high" + } + }, "limit": { "context": 256000, "output": 32000 @@ -3480,6 +3496,14 @@ jobs: "name": "Ling-3.0-flash Free", "tool_call": true, "reasoning": true, + "options": { + "reasoningEffort": "high" + }, + "variants": { + "high": { + "reasoningEffort": "high" + } + }, "limit": { "context": 262144, "output": 32768 @@ -3489,6 +3513,14 @@ jobs: "name": "MiMo V2.5 Free", "tool_call": true, "reasoning": true, + "options": { + "reasoningEffort": "high" + }, + "variants": { + "high": { + "reasoningEffort": "high" + } + }, "limit": { "context": 200000, "output": 32000 diff --git a/tests/test_opencode_agent_contract.py b/tests/test_opencode_agent_contract.py index ab09330dd..bd300a839 100644 --- a/tests/test_opencode_agent_contract.py +++ b/tests/test_opencode_agent_contract.py @@ -197,6 +197,12 @@ def test_opencode_model_pool_sets_high_effort_for_capable_candidates(): "context": 200000, "output": 32000, } + for model_name, model_config in free_models.items(): + if model_config.get("reasoning") is True: + assert model_config["options"]["reasoningEffort"] == "high", model_name + assert model_config["variants"]["high"]["reasoningEffort"] == "high", ( + model_name + ) assert github_candidate_models == [ "deepseek/deepseek-v3-0324", "openai/gpt-4.1",