fix(review): salvage findings from nested-object fences + bare arrays + unfenced tail JSON

The canalhandia PR review lost all findings because the agent ran out of
context before emitting the closing json fence. Three failure modes hit
the old regex \{.*?\}:
  * nested objects inside the fence truncated at the first }
  * bare arrays (no {summary, findings} wrapper) returned []
  * unfenced JSON in the prose tail was never reached (first not last)

Replace the regex with a balanced-brace scanner:
  * _last_json_block walks the fence contents with a depth counter so
    nested objects survive
  * _last_balanced_json + _balanced_json_substring handle bare arrays and
    prose-tail JSON when no fence is present
  * _parse_json_tolerant returns list as well as dict; parse_findings and
    parse_review_output accept a bare array as the outer value

Agent prompt tightened: reserve the final step for emitting the JSON
block so the analysis isn't lost when context runs out.

10 new tests in tests/pilot/test_ai_review.py cover the new shapes.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Marcos
2026-08-20 16:29:44 +00:00
parent ec26ec000a
commit 5302e8dcd7
4 changed files with 280 additions and 27 deletions
+4 -1
View File
@@ -164,4 +164,7 @@ Rules:
- If the diff is clean, output `{"summary":"...","findings":[]}`.
- Do NOT repeat anything in `prior_reviews`.
- The JSON block must be the LAST thing in your message — the Python shell parses
the last ```json fenced block from your output.
the last ```json fenced block from your output. If you run out of context/steps
before emitting it, your analysis is wasted: ALWAYS reserve the final step for
writing the JSON. Stop exploring and write findings at the first sign you've
covered the diff (no new findings in the last 2 file reads = stop).