Skip to content

Commit 91a69fe

Browse files
Pigbibicodex
andcommitted
fix: harden dual review alert delivery
Co-Authored-By: Codex <noreply@openai.com>
1 parent 448ab61 commit 91a69fe

4 files changed

Lines changed: 53 additions & 4 deletions

File tree

service/briefing_dispatch.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def create_github_issue(*, title: str, body: str, labels: tuple[str, ...] = ())
117117
return None
118118
if not shutil_which("gh"):
119119
return None
120-
cmd = [
120+
base_cmd = [
121121
"gh",
122122
"issue",
123123
"create",
@@ -128,12 +128,33 @@ def create_github_issue(*, title: str, body: str, labels: tuple[str, ...] = ())
128128
"--body",
129129
body,
130130
]
131+
cmd = list(base_cmd)
131132
for label in labels:
132133
cmd.extend(["--label", label])
133134
try:
134135
output = subprocess.check_output(cmd, text=True, stderr=subprocess.STDOUT).strip()
135136
return output
136-
except Exception:
137+
except subprocess.CalledProcessError as exc:
138+
if labels:
139+
print(
140+
"::warning title=GitHub issue labels unavailable::"
141+
"retrying durable issue creation without labels"
142+
)
143+
try:
144+
return subprocess.check_output(
145+
base_cmd,
146+
text=True,
147+
stderr=subprocess.STDOUT,
148+
).strip()
149+
except (OSError, subprocess.CalledProcessError) as retry_exc:
150+
detail = str(getattr(retry_exc, "output", "") or retry_exc).strip()
151+
print(f"::warning title=GitHub issue creation failed::{detail}")
152+
return None
153+
detail = str(exc.output or exc).strip()
154+
print(f"::warning title=GitHub issue creation failed::{detail}")
155+
return None
156+
except OSError as exc:
157+
print(f"::warning title=GitHub issue creation failed::{exc}")
137158
return None
138159

139160

service/dual_review_primary.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@ def run_codex_primary_review(
8787
raise RuntimeError("CODEX_AUDIT_SERVICE_URL is not configured")
8888

8989
timeout = int(timeout_minutes or os.environ.get("DUAL_REVIEW_PRIMARY_TIMEOUT_MINUTES", "15"))
90+
review_prompt = f"{_PRIMARY_SYSTEM}\n\n{prompt}"
9091
result = AiGatewayClient(GatewayConfig.from_env()).execute(
91-
prompt,
92+
review_prompt,
9293
task="dual_review",
9394
mode="review_only",
9495
complexity="high",

tests/test_briefing_dispatch.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import os
4+
import subprocess
45
import unittest
56
from unittest.mock import patch
67

@@ -134,6 +135,26 @@ def test_create_github_issue_uses_actions_repository(self, _which, check_output)
134135
self.assertEqual(issue, "https://example.test/issues/1")
135136
self.assertIn("QuantStrategyLab/CryptoStrategies", check_output.call_args.args[0])
136137

138+
@patch(
139+
"service.briefing_dispatch.subprocess.check_output",
140+
side_effect=[
141+
subprocess.CalledProcessError(1, ["gh"], output="label not found"),
142+
"https://example.test/issues/2\n",
143+
],
144+
)
145+
@patch("service.briefing_dispatch.shutil_which", return_value="/usr/bin/gh")
146+
def test_create_github_issue_retries_without_missing_labels(self, _which, check_output) -> None:
147+
with patch.dict(os.environ, {"GITHUB_REPOSITORY": "QuantStrategyLab/CryptoStrategies"}, clear=True):
148+
issue = create_github_issue(
149+
title="review disagreement",
150+
body="details",
151+
labels=("dual-review", "needs-human"),
152+
)
153+
154+
self.assertEqual(issue, "https://example.test/issues/2")
155+
self.assertIn("--label", check_output.call_args_list[0].args[0])
156+
self.assertNotIn("--label", check_output.call_args_list[1].args[0])
157+
137158
@patch("service.briefing_dispatch.subprocess.check_output")
138159
@patch("service.briefing_dispatch.shutil_which", return_value="/usr/bin/gh")
139160
def test_create_github_issue_rejects_invalid_repository(self, _which, check_output) -> None:

tests/test_dual_review_primary.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,14 @@ def test_budget_error_is_unavailable(self, review) -> None:
124124
review.return_value = AiResult.unavailable("codex", "Daily budget exceeded")
125125
result = run_codex_primary_review(prompt="review")
126126
self.assertEqual(result["verdict"], VERDICT_UNAVAILABLE)
127+
expected_prompt = (
128+
"You are the primary Codex reviewer for quantitative strategy promotion and risk decisions. "
129+
"Respond with JSON only: "
130+
'{"verdict":"approve"|"reject","confidence":0.0-1.0,"summary":"..."}'
131+
"\n\nreview"
132+
)
127133
review.assert_called_once_with(
128-
"review",
134+
expected_prompt,
129135
task="dual_review",
130136
mode="review_only",
131137
complexity="high",

0 commit comments

Comments
 (0)