"""Regression for task 182: a malformed/truncated/thought-wrapped model reply is a technical failure that must trigger a repair retry and, if still unparseable, RAISE (so the orchestrator retries the panel) — never a silent skip. Run: ./.venv/bin/python test_vision_parse.py""" import worker_vision as wv def test_extract_handles_thought_wrapped(): raw = "<|channel>thought I should answer{\"skip\": false, \"characters\": []}" assert wv._extract_json(raw) == {"skip": False, "characters": []} def test_extract_rejects_malformed_and_truncated(): for bad in ("sorry, no json here", '{"skip": false, "characters": [', "", "```json\n{oops"): try: wv._extract_json(bad) assert False, f"should have raised on: {bad!r}" except ValueError: pass def test_repair_retry_recovers(): calls = [] good = '{"skip": false, "characters": [{"local_id": "person_1"}]}' def fake(content, temperature=0.2, max_tokens=768): calls.append(content) return "garbled not-json" if len(calls) == 1 else good wv.call_gemma4 = fake result = wv.call_gemma4_json([{"type": "text", "text": "p"}]) assert result["characters"][0]["local_id"] == "person_1" assert len(calls) == 2, "must make exactly one repair retry" def test_raises_when_repair_also_fails(): wv.call_gemma4 = lambda content, temperature=0.2, max_tokens=768: "still broken {" try: wv.call_gemma4_json([{"type": "text", "text": "p"}]) assert False, "must raise so the orchestrator records a stage error and retries" except ValueError: pass if __name__ == "__main__": test_extract_handles_thought_wrapped() test_extract_rejects_malformed_and_truncated() test_repair_retry_recovers() test_raises_when_repair_also_fails() print("ok")