Skip to content

Commit 5af76f1

Browse files
igerberclaude
andcommitted
Address CI review: incomplete status handling, pricing, help text
P1: Treat status='incomplete' as a hard error even when content exists, since truncated reviews may silently suppress findings. Print incomplete_details and suggest remediation (reduce diff, lower context). P2: Fix gpt-5.4-pro pricing from (15,60) to (30,180) per official rates. P3: Fix argparse description to say "Responses API" not "Chat Completions". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent a832404 commit 5af76f1

2 files changed

Lines changed: 43 additions & 7 deletions

File tree

.claude/scripts/openai_review.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ def apply_token_budget(
854854
# MAINTENANCE: Update when OpenAI changes pricing.
855855
PRICING = {
856856
"gpt-5.4": (2.50, 15.00),
857-
"gpt-5.4-pro": (15.00, 60.00),
857+
"gpt-5.4-pro": (30.00, 180.00),
858858
"gpt-4.1": (2.00, 8.00),
859859
"gpt-4.1-mini": (0.40, 1.60),
860860
"o3": (2.00, 8.00),
@@ -1209,6 +1209,24 @@ def call_openai(
12091209

12101210
content = _extract_response_text(result)
12111211

1212+
# Treat truncated responses as errors — partial reviews may suppress findings.
1213+
status = result.get("status")
1214+
if content.strip() and status == "incomplete":
1215+
detail = result.get("incomplete_details") or ""
1216+
print(
1217+
"Error: Review was truncated (status='incomplete'). "
1218+
"Output may be missing findings.",
1219+
file=sys.stderr,
1220+
)
1221+
if detail:
1222+
print(f"Detail: {detail}", file=sys.stderr)
1223+
print(
1224+
"Try reducing diff size, disabling --full-registry, or "
1225+
"lowering --context to 'minimal'.",
1226+
file=sys.stderr,
1227+
)
1228+
sys.exit(1)
1229+
12121230
if not content.strip():
12131231
# No usable content — report the best diagnostic we have.
12141232
status = result.get("status", "<missing>")
@@ -1244,7 +1262,7 @@ def _read_file(path: str, label: str) -> str:
12441262

12451263
def main() -> None:
12461264
parser = argparse.ArgumentParser(
1247-
description="Run local AI code review via OpenAI Chat Completions API."
1265+
description="Run local AI code review via OpenAI Responses API."
12481266
)
12491267
parser.add_argument(
12501268
"--review-criteria",

tests/test_openai_review.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,19 +1710,37 @@ def test_status_none_with_valid_output_succeeds(self, review_mod, mock_urlopen):
17101710
content, _ = review_mod.call_openai("test", "gpt-5.4", "fake-key")
17111711
assert content == "Good review."
17121712

1713-
def test_incomplete_status_with_valid_content_succeeds(self, review_mod, mock_urlopen):
1714-
"""Non-completed status should still return content when output is usable."""
1713+
def test_incomplete_status_with_content_exits(self, review_mod, mock_urlopen):
1714+
"""Truncated response (status=incomplete) should exit even if content exists."""
17151715
mock_urlopen["response_data"] = {
17161716
"status": "incomplete",
17171717
"output_text": None,
17181718
"output": [{
17191719
"type": "message",
1720-
"content": [{"type": "output_text", "text": "Partial but usable."}],
1720+
"content": [{"type": "output_text", "text": "Partial review."}],
17211721
}],
17221722
"usage": {"input_tokens": 10, "output_tokens": 5},
17231723
}
1724-
content, _ = review_mod.call_openai("test", "gpt-5.4", "fake-key")
1725-
assert content == "Partial but usable."
1724+
with pytest.raises(SystemExit):
1725+
review_mod.call_openai("test", "gpt-5.4", "fake-key")
1726+
1727+
def test_incomplete_status_surfaces_details(self, review_mod, mock_urlopen, capsys):
1728+
"""Incomplete response should print incomplete_details to stderr."""
1729+
mock_urlopen["response_data"] = {
1730+
"status": "incomplete",
1731+
"incomplete_details": {"reason": "max_output_tokens"},
1732+
"output_text": None,
1733+
"output": [{
1734+
"type": "message",
1735+
"content": [{"type": "output_text", "text": "Partial."}],
1736+
}],
1737+
"usage": {"input_tokens": 10, "output_tokens": 5},
1738+
}
1739+
with pytest.raises(SystemExit):
1740+
review_mod.call_openai("test", "gpt-5.4", "fake-key")
1741+
captured = capsys.readouterr()
1742+
assert "truncated" in captured.err.lower()
1743+
assert "max_output_tokens" in captured.err
17261744

17271745
def test_output_text_convenience_field_used(self, review_mod, mock_urlopen):
17281746
"""When output_text is populated (SDK-style), use it directly."""

0 commit comments

Comments
 (0)