Stale-state cleanup + 7-day threshold + smoke tests (additive to #16) #19
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Mark/whisper-transcribe#19
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Origin
Decomposed from kanban t_e5ac8155 (auto-decomposer, 2026-09-05). Sibling of t_9b77a683 (the --resume / --fresh core implementation), both children of t_d5c5d159 (issue #16 root). Issue #16 + the spec at docs/state-file.md (branch docs/state-file-schema, commit
217cb08) cover the core resume + atomic-write + soft-staleness story, but this issue adds four concrete user-facing items that #16 does not capture.Scope (additions to #16)
These four items are additive to the #16 implementation and are intended to land in the SAME PR if possible -- they're not parallel work, they're part of the complete resumable-chunk story.
1. Change default
--stale-hoursfrom 24 to 168 (= 7 days)Spec §5.4 / §6 say
--stale-hoursdefaults to 24 hours. The user-facing product decision is 7 days -- long-running transcription jobs (overnight batch runs, multi-day podcasts) should not warn after 24h, and a state file that hasn't been touched in a week is genuinely stale.Update the default in:
--stale-hoursdefault in the CLI2. Source-audio mtime newer than state mtime -> WARN + REQUIRE
--fresh(not hard-reject)Spec §5.1/§5.2 currently treats source-audio mtime change as a hard reject (StaleStateError). This is too aggressive -- users who legitimately re-edited or upgraded the source want a confirmation step, not a crash. New behavior:
When
state['source_audio_mtime'] < source_audio.mtime_at_startup, emit a clear warning to stderr:warning: source audio is newer than transcribe.state.json
(state recorded mtime 2026-09-01 12:00; current mtime 2026-09-05 09:14)
Pass --fresh to re-transcribe, or --resume to ignore the mtime change.
With
--resume: continue anyway (with the warning).Without
--resume: refuse to start, error classStaleStateError, exit code 2.The
--freshflag still deletes and restarts.This requires a small refactor of
validate_state()to distinguish "hard reject" from "warning + gate" outcomes. Either return a result object instead of raising, or raise a distinctSourceMtimeChangedWarningexception that the CLI catches.3. New
--clean-staleflagA bulk-cleanup subcommand / flag: list (and, with
--yes, delete) alltranscribe.state.jsonfiles older than--stale-hours(default 7 days per #1) found in the search paths.CLI surface:
transcribe --clean-stale [--stale-hours N] [--workdir PATH ...] [--yes] [--dry-run]--workdirvalues passed. Recurses one level into subdirs.--yes): a table of(path, age_hours, chunks_done, chunks_total)for each stale state file, then exit 0 without deleting.--yes: deletestranscribe.state.jsonand the matchingtranscribe.chunk_*.jsonfiles in each stale workdir. Prompts via stdin if--yesis not passed and stdin is a TTY; in non-TTY contexts, refuses to delete.--dry-run: print the table, never delete, exit 0.Failure modes:
in_progresschunk -> emit an additional warning that the chunk was never completed; delete anyway (user explicitly asked for --clean-stale).skipped: 3 read-only).4. tests/test_resume.py -- four-scenario smoke test
New test file (no test file by this name exists today -- verified via tests/conftest.py import surface). Four scenarios, all unit-level (no GPU, no network, no real WhisperX -- use the
tmp_pathfixture and a faketranscribe.state.jsonwritten directly):(a) Interrupted run leaves state file. Simulate a chunk loop that writes
transcribe.state.jsonwithchunks[0..2].status == 'done'and crashes (raiseKeyboardInterrupt) beforechunks[3]. Assert the state file exists on disk, parses, and reflects the partial progress.(b) Resume picks up correctly. Spawn a fresh chunk-loop run with the state file from (a) as input and assert:
chunks[0..2]are NOT re-processed (mock the chunk processor and assert it was called only for chunks 3..N), the final state file has all chunksdone, and no duplicate segments appear in the merged output.(c) Modified source audio triggers stale warning. Write a state file with
source_audio_mtime = T-1h, then bump the source audio's mtime toT. Run the resume entry point and assert: a warning matchingsource audio .* newer than transcribe.state.jsonappears on stderr, and the function exits non-zero (or, depending on the chosen implementation shape, returns a distinct error code) without--resume.(d)
--freshclears state. Pre-populate a workdir withtranscribe.state.json+ threetranscribe.chunk_*.jsonfiles. Runtranscribe --freshagainst it. Assert: all four files are deleted; the chunk processor is called for chunks 0..N from scratch; the new state file is fresh.Acceptance: all four scenarios pass; warning messages are grep-friendly (exact regex in test) so future message rewording is intentional, not accidental.
Tied to
217cb08) -- items #1 and #2 require spec updates before the implementation lands.Acceptance (this issue)
--stale-hoursdefault is 168 (= 7 days).--clean-staleflag implemented per #3, with--dry-rundefault behavior and--yesopt-in for delete.tests/test_resume.pyexists and covers all four scenarios;pytest tests/test_resume.py -vis green.pytest tests/ --ignore=tests/test_benchmark_gpu_sizing.pybaseline still passes.ruff check src testsis clean.Routing
feature-request+triage-approved(per kanban-worker discipline -- daemon webhook will pick uptriage-approvedand dispatchgsd-issue-fixer.py).feat/stale-cleanup-and-tests(or whatever the in-flight #16 branch is named, with these additions appended).kilo-gsd-whisper-transcribe-16, Phase 2/9 at filing time) can absorb the additions. If the Plan phase has already progressed past the spec-update step, file as a follow-up PR.Kanban tracking
t_e5ac8155(this work)t_9b77a683(--resume/--fresh core; delegated to kilo-gsd.py)t_d5c5d159(issue #16 root)Cross-linked from #16. Sibling issue (and the kanban subtask t_e5ac8155) intends for these additions to land in the same PR as #16 if the Plan phase of tmux kilo-gsd-whisper-transcribe-16 has not yet finalized (Phase 2/9 at filing time, 2026-09-06 06:22 PDT). Watcher profile on t_d5c5d159 will own the terminal transition.
Cross-link note (kanban t_583cec8a, 2026-09-06 06:24 PDT): kilo-gsd-runner attempted to spawn kilo-gsd.py against this issue at 23:24 PDT, but the per-repo concurrency gate rejected the spawn because Mark/whisper-transcribe#16 still holds the lock (Phase 4/9 Implement, tmux kilo-gsd-whisper-transcribe-16, pid 134253).
Resolution path: file as a follow-up PR after #16 lands. The card body already names this as the expected outcome when the Plan phase has progressed past the spec-update step. Once the #16 PR merges (or its branch is pushed), a re-dispatch of t_583cec8a will spawn a fresh kilo-gsd.py against this issue and the four items (stale-hours default 168, source-mtime soft warn, --clean-stale, tests/test_resume.py) will land on a new branch atop the #16 commit.
No code work attempted from this run. kanban t_583cec8a blocked transient.
Re-dispatched: kilo-gsd.py Mark/whisper-transcribe#19 launched from kanban t_583cec8a (re-run after #16 cleared the concurrency cap on origin/main,
b95dfe3). Monitor session:kilo-monitor-whisper-transcribe-19; log at~/.hermes/logs/kilo-monitor/whisper-transcribe-19.log. Follow-up PR track per card body: items #1 (stale-hours=168), #2 (source-mtime soft-warn), #3 (--clean-stale flag), #4 (tests/test_resume.py four-scenario smoke test). Watcher card: t_edbd396b.