4e0b1bbdbf
The first post-commit fix only handled merge-error-* strings and missed that build_train's single-PR failure reasons flow straight into terminal_state via _release. Four were unmapped (no-head-ref, rev-parse-fetched-head-failed, rebase-timeout, push-failed-force-lease-mismatch) — same stranding bug class. - _resolve_bridge_event no longer returns None. Any unrecognised terminal_state falls back to merge_retry_exhausted (-> STUCK): operator-visible and recoverable beats silently orphaned in MERGING. The three static build_train reasons are mapped explicitly; the catch-all logs loudly so an unanticipated state is still visible. - merge-error-* routing refined: 404 -> merge_external_action (reconcile via PR state), 422 -> merge_base_conflict (CONFLICT_- RESOLVING re-rebases) instead of blanket STUCK. - Hard-crash reaper: merge_drive is a singleton and run_one_cycle is serial, so any workflow in MERGING at cycle start is the residue of a crashed prior cycle. run_one_cycle now reclaims them via merge_interrupted (MERGING -> APPROVED) before picking candidates. Adds bridge.list_merging_workflows. - run_one_cycle warns if a claimed PR is absent from pr_terminal_states instead of silently using the aggregate. 3309 tests pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>