Skip to content

fix(cli): --timeout on check and snapshot takes units like 45s - #6521

Merged
miguel-heygen merged 3 commits into
mainfrom
fix/check-copy-cap-timeout-units
Oct 27, 2026
Merged

miguel-heygen merged 3 commits into
mainfrom
fix/check-copy-cap-timeout-units

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

This is a units fix only. It does not find the root of the silent 90 s to 4 minute hangs: the copy phase is already progress-bounded, so it does not explain them, and the hang root is still open.

What changes for the user

--timeout on check and snapshot is milliseconds, so --timeout 45 waited 45 ms. It now also takes 45s, 2m and 45000ms. A bare number under 1000 is still milliseconds but warns on stderr, naming the value actually used (check raises anything under 500 ms to 500 ms). Stdout is unchanged.

Copy phase: no new limit

An earlier version of this PR capped check's video copies at 10 minutes of wall time. That is dropped: it could kill a copy that was still progressing, and a re-run would start it over. The copy phase is already bounded on no progress: each ffmpeg copy ends when it reports no progress for 3 minutes (TRANSCODE_STALL_MS, adjustable with HYPERFRAMES_PROXY_STALL_MS), a long source is copied in 15 s pieces and finished pieces are kept for the next run, and the stderr heartbeat names each copy's progress. A copy that stalls shows up as the existing "Could not make a browser-playable copy of " finding.

Measured: a 676 MB 4K ProRes source spends 10.6 s in the copy phase, and stdout stays silent until the command exits. Minutes of silence therefore need bigger or longer media or a slow disk.

How it is checked

timeoutArg.test.ts covers bare, ms, s, m, fractional, zero and junk values, the warning for small bare values, and that the warning names the floored value; the floor test fails when the floor is not applied. 3 green runs.

Why under 100 lines

One small helper (timeoutArg.ts, 28 lines), its test, and a one-line call in each of check and snapshot. It is a single change (how --timeout is read), so splitting it would leave check and snapshot disagreeing on the unit.

…eout takes units

The copy phase of check had no overall limit: a source that kept moving was never
stopped, and stdout stays silent the whole time. It now ends after 10 minutes with
an error naming the files still unfinished and the elapsed seconds; finished copies
are reused on the next run. The stderr progress lines are unchanged.

--timeout on check and snapshot is milliseconds, so "--timeout 45" waited 45 ms.
It now accepts 45s, 2m and 45000ms, and a bare number under 1000 warns on stderr
that it is milliseconds. Output on stdout is unchanged.

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES · 1 blocker · 0 important · 1 nit · head f444828f

The 10-minute wall clock can fail a long copy that is still making progress, and running check again does not help. ↓ inline

Scope

Read the whole diff, plus resolveProxies/joinJob/leave in studio-server proxyTranscoder.ts, checkDeadline.ts, and how errors reach the user from runCheckPipeline and runPrepareMedia. Both changed test files pass locally (18/18). CI was still running when I reviewed. The --timeout parser looks right.

Nit: check --timeout 45 warns "45 is 45 ms", but parseCheckOptions then clamps it to 500 ms, so the warning names a value that is not used.

— Claude

Comment thread packages/cli/src/utils/checkBrowser.ts Outdated
`Making browser-playable copies took longer than ${elapsedText(COPY_PHASE_CAP_MS)} and was stopped after ${Math.round((Date.now() - startedAt) / 1000)}s. Still unfinished: ${unfinished.join(", ")}. Re-run check to keep going (finished copies are reused), or pass --no-proxy to skip them.`,
),
);
}, COPY_PHASE_CAP_MS);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocker: This adds a wall-clock limit to copies that are still making progress. The transcoder was designed to avoid that. resolveProxies says "A copy is ended only when it stops making progress (TRANSCODE_STALL_MS), so a long source that keeps moving is never cut by a clock", and CheckDeadline marks copies as before the deadline on purpose.

When the limit fires, stopped.abort() → joinJob → leave() → job.abandoned.abort() kills ffmpeg and throws away the partial copy. Each unfinished file then starts again from zero on the next run. So:

  • one source whose copy takes more than 10 minutes (a long 4K ProRes, a slow disk, a 2-vCPU runner) can never pass check. The message's "Re-run check to keep going" can't come true for that file.
  • the docstring above names a fresh CI checkout as the main cold-cache case. A CI checkout starts with an empty cache every time, so a project that took 12 minutes before now fails every run, where it used to pass slowly.
  • the limit also counts time spent waiting in the shared transcode queue, so a preview running at the same time eats into it.

A silent stdout is a better problem to have than a check that can never pass. Options: (a) keep the stall-only design and fix the silence; the stderr heartbeat already shows progress. (b) Fire only when nothing has made progress for N minutes (reset on heartbeat.progress), which is what TRANSCODE_STALL_MS already does per copy. (c) Make the limit opt-in or configurable, defaulting to off. If you keep a hard limit, the error should not tell the user that re-running will make progress.

A copy that keeps making progress must not be cut by a clock, and a re-run would
only start it over. The copy already ends when ffmpeg stops reporting progress
for 3 minutes (finished pieces are kept for the next run), so the phase is
bounded on no progress. The --timeout warning now names the value actually used
when check raises a small value to its 500 ms floor.
@miguel-heygen miguel-heygen changed the title fix(cli): check stops making video copies after 10 minutes, and --timeout takes units fix(cli): --timeout on check and snapshot takes units like 45s Oct 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 271 (base branch 271), smooth 135 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (0)

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE — 1 resolved, 0 open, 0 new · f444828f → c4c8e64d. The wall clock is gone, so this is a units fix only. The floor is now named in the warning. Changed suites pass locally (220/220). CI is green; I re-ran the failed Test (cli) job, an unrelated Chromium launch timeout in motion-signature.browser.

— Claude

@miguel-heygen
miguel-heygen added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit a669316 Oct 27, 2026
170 of 175 checks passed
@miguel-heygen
miguel-heygen deleted the fix/check-copy-cap-timeout-units branch October 27, 2026 07:11
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.

1 participant