Skip to content

fix(refine): keep refined SRT cues across a rate-limit pause - #313

Merged
hydropix merged 1 commit into
mainfrom
claude/fix-302-srt-refine-rate-limit-5821b1
Oct 23, 2026
Merged

hydropix merged 1 commit into
mainfrom
claude/fix-302-srt-refine-rate-limit-5821b1

Conversation

@hydropix

Copy link
Copy Markdown
Owner

Fixes #302

Problem

src/core/refine/srt_refiner.py had no RateLimitError handling. A 429 during an SRT refine pass propagated bare, every cue already refined was lost, and a resume restarted refinement from the first cue.

Fix

Follows the TXT refiner fix from #252 (#228), then goes one step further so the resume actually skips finished cues.

  • refine_subtitle_translations attaches RateLimitError.partial_result before re-raising: the complete position-to-text map (refined for finished blocks, the draft from the failing block onward) and next_index, the first position still to refine.
  • refine_srt_file catches the error, writes the partial file through _write_refined_srt (shared with the success path, so cue numbers and timings stay verbatim), records the last finished cue via checkpoint_manager.save_checkpoint, then re-raises so auto-pause / auto-resume still trigger.
  • refine_file now forwards checkpoint_manager, translation_id and resume_from_index to the SRT refiner. On resume, the finished cues are read back from the partial output, but only when it still lines up with the input cue for cue (same count and timings). Otherwise the pass logs a warning and restarts from the first cue. Only the remaining cues go to the LLM, and progress is reported against the whole file.

Because the checkpoint index now advances, the auto-resume "stuck" detector in handlers.py also sees real progress for SRT refine jobs.

Note: the TXT refiner still saves its partial output but re-refines from chunk 0 on resume. That is unchanged here.

Tests

New tests/unit/test_srt_refine_rate_limit.py (all 4 fail without the fix):

  • a 429 on the second block writes refined + untouched cues with gapped numbering and timings intact, saves the checkpoint, and re-raises
  • a 429 on the first block writes the drafts and saves no checkpoint
  • a resume sends only the leftover cues to the LLM and produces the fully refined file with whole-file progress
  • a resume against a mismatched output restarts from the first cue

Full suite: 2582 passed. Two known failures are unrelated. The tests/characterization/test_progress_baseline.py goldens are stale on main (deselected). test_litellm_provider.py::test_rate_limit_without_pool_keeps_plain_backoff fails only in a full-suite run, and it fails the same way on the unmodified base.

🤖 Generated with Claude Code

refine_srt_file had no RateLimitError handling: a 429 midway through an SRT
refine pass propagated bare, every cue already refined was discarded, and a
resume started the refinement over from the first cue.

refine_subtitle_translations now attaches a partial result before
re-raising: the complete position -> text map (refined for finished blocks,
the draft for the failing block onward) plus the first position still to
refine. refine_srt_file writes that map through the same helper as the
success path, so cue numbers and timings stay verbatim, and records the last
finished cue in the checkpoint before letting the error propagate to the
pause / auto-resume logic.

On resume, refine_file now forwards checkpoint_manager, translation_id and
resume_from_index to the SRT refiner. It reads the finished cues back from
the partial output (only when it still matches the input cue for cue, else
it restarts from the first cue), sends only the remaining cues to the LLM,
and reports progress against the whole file.

Fixes #302

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hydropix
hydropix merged commit e7f188f into main Oct 23, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refine/SRT: rate-limit pause discards all refined cues (no partial persistence)

1 participant