Skip to content

Commit b269284

Browse files
Pigbibicodex
andcommitted
fix: preserve contract behavior ordering
Co-Authored-By: Codex <noreply@openai.com>
1 parent 865e212 commit b269284

2 files changed

Lines changed: 30 additions & 5 deletions

File tree

scripts/run_codex_pr_review.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ def _normalize_contract_text(value: Any) -> str:
811811
"must", "should", "will", "return",
812812
}
813813
return " ".join(
814-
sorted(token for token in re.findall(r"[a-z0-9]+", text) if token not in stop_words)
814+
token for token in re.findall(r"[a-z0-9]+", text) if token not in stop_words
815815
)
816816

817817

@@ -842,9 +842,8 @@ def _behavior_digest(finding: dict[str, Any]) -> str:
842842
payload = json.dumps(
843843
{
844844
"contract_key": _contract_key(finding),
845-
"behavior": _normalize_contract_text(
846-
finding.get("suggestion") or finding.get("description")
847-
),
845+
"description": _normalize_contract_text(finding.get("description")),
846+
"suggestion": _normalize_contract_text(finding.get("suggestion")),
848847
},
849848
sort_keys=True,
850849
separators=(",", ":"),

tests/test_run_codex_pr_review.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,9 @@ def test_replay_fixtures_cover_pure_contract_identity(self) -> None:
121121
crypto = fixtures["crypto_pr_125"]["findings"]
122122
dispatch_identity = run_codex_pr_review._contract_finding(dispatch["finding"])
123123
reworded_identity = run_codex_pr_review._contract_finding(dispatch["reworded"])
124-
self.assertEqual(dispatch_identity["fingerprint_v2"], reworded_identity["fingerprint_v2"])
124+
self.assertEqual(dispatch_identity["contract_key"], reworded_identity["contract_key"])
125+
self.assertNotEqual(dispatch_identity["behavior_digest"], reworded_identity["behavior_digest"])
126+
self.assertNotEqual(dispatch_identity["fingerprint_v2"], reworded_identity["fingerprint_v2"])
125127
self.assertNotEqual(
126128
run_codex_pr_review._contract_key(crypto[0]),
127129
run_codex_pr_review._contract_key(crypto[1]),
@@ -148,6 +150,30 @@ def test_no_anchor_subject_combines_description_and_suggestion(self) -> None:
148150
run_codex_pr_review._contract_key(first),
149151
run_codex_pr_review._contract_key(second),
150152
)
153+
self.assertNotEqual(
154+
run_codex_pr_review._behavior_digest(first),
155+
run_codex_pr_review._behavior_digest(second),
156+
)
157+
self.assertNotEqual(
158+
run_codex_pr_review._fingerprint_v2(first),
159+
run_codex_pr_review._fingerprint_v2(second),
160+
)
161+
162+
def test_ordered_contract_text_distinguishes_reversed_behavior(self) -> None:
163+
before = {
164+
"category": "logic", "file": "service/review.py",
165+
"description": "Validate A before B.",
166+
"suggestion": "Use the required order.",
167+
}
168+
after = dict(before, description="Validate B before A.")
169+
self.assertEqual(
170+
run_codex_pr_review._normalize_contract_text(before["description"]),
171+
"validate a before b",
172+
)
173+
self.assertNotEqual(
174+
run_codex_pr_review._behavior_digest(before),
175+
run_codex_pr_review._behavior_digest(after),
176+
)
151177

152178
def test_parse_arbitration_output_requires_supported_verdict(self) -> None:
153179
self.assertEqual(

0 commit comments

Comments
 (0)