* fix(pr-review): add three-tier recovery for structured output validation failure
When structured output validation fails after SDK max retries, the followup
reviewer crashed with RuntimeError instead of recovering. This wastes all
multi-agent analysis work (often 100+ messages across 3 specialist agents).
Changes:
- sdk_utils: add error_recoverable flag and last_assistant_text to stream result
- followup reviewer: attempt extraction call with minimal schema before text fallback
- pydantic_models: add FollowupExtractionResponse (~6 flat fields, near-100% success)
- orchestrator reviewer: add structured_output to FindingValidator retryable errors
Recovery cascade: structured output → extraction call → text parsing
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* fix(pr-review): address review findings from PR #1797
- Register pr_followup_extraction agent type in AGENT_CONFIGS (fixes Tier 2 dead code)
- Move RECOVERABLE_ERRORS to module-level constant in sdk_utils for importability
- Update docstring to document new return fields (last_assistant_text, error_recoverable)
- Use self.config.fast_mode instead of hardcoded True for consistency
- Rewrite tests to import actual production constants instead of reimplementing logic
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* fix(tests): fix import paths for CI environment
CI runs pytest from apps/backend/ so runners/github/ must be on sys.path
for services.sdk_utils and services.pydantic_models imports to resolve.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* fix(tests): use bare module imports to avoid services/ package collision
There are two services/ directories (apps/backend/services/ and
runners/github/services/). Adding github services dir to sys.path and
importing via `from services.sdk_utils` fails because Python finds the
wrong services/ package first. Fix: add the services dir directly and
use bare imports (from sdk_utils import ...).
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* fix(pr-review): fix extraction call type error and control flow issues
- Use self.project_dir instead of str(Path.cwd()) for create_client (fixes
AttributeError making Tier 2 always crash, and uses correct project path)
- Force structured_output = None on recoverable errors to skip redundant
parse-then-fail cycle and go directly to Tier 2 extraction
- Include dismissed_finding_count in extraction return dict for symmetry
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* fix(pr-review): address follow-up review findings
- Read dismissed_finding_count fallback in consumer (fixes silent data loss)
- Consolidate recoverable error handling into single control flow block
- Default text fallback verdict to NEEDS_REVISION (consistent with _create_empty_result)
- Add missing keys to _parse_text_output and _create_empty_result for consistent
return dict contracts across all three recovery tiers
Co-Authored-By: Claude Opus 4.6 <[email protected]>
* style: ruff format parallel_followup_reviewer.py
Co-Authored-By: Claude Opus 4.6 <[email protected]>
---------
Co-authored-by: Claude Opus 4.6 <[email protected]>