Repository navigation
v3.6.7
Automated release: version and notes generated from pull requests merged since 3.6.6.
Changed
- Tests no longer depend on the order they run in (#467: A227, A228, A229, and the
gappy.mp4
item).emoji_src.mp4was built by three classes with different content, soEmojiTests
usually ran without its sound;export_reels.mp4was a--fit cropfixture intest_analysis
and a--fit padoutput oftest_delivery;gappy.mp4had two layouts; and
test_sequence_no_match_refusedused a directory another test creates, so it tested the
missing-directory refusal instead. Each now has its own file, and the sequence test makes its
directory and asserts the "no files match" refusal. - Three test defects (#467: A230, A231, A232).
ContractTestsandSilentPathTestsremove
the temp folders they make;_ass_advanceescapes the path it puts intoass=(a colon in it
made the emoji-placeholder test skip);test_json_determinismcompared a document with itself
and now compares the emitted key order with the sorted one at every depth. The second A232
item, a "cached" test that passes without the cache, could not be identified in the tree and is
not changed. tests/sweep.pyruns every one-file tool (#467: A225; #466: A216). Seven were left out
(probe,check,cropdetect,scenes,sphere,verify,waveform): the table has 32 rows
for 31 tools, a tool that takes no-ois run without one, and a--baselinerun uses its own
folder.BY_HANDnames the eleven tools the table cannot run, and a test fails when a script is
in neither list. CONTRIBUTING's "25 single-input tools" (24,cutcounted twice) is corrected.- CI: a release no longer rebases its bump onto a merge it did not read (#467: A25). A PR
merged while the bump was being prepared was put under the release commit bygit pull --rebase: it shipped in the tag without its label or changelog line, and its own run found
nothing to release. The push is tried once; whenmainhas moved, that run drops the bump and
releases nothing, and the newer merge's queued run releases both. - CI: GitHub Pages is rebuilt after a release (#467: A28). The bump commit carries
[skip ci], so the site kept the previous version and showed the shipped notes under
"Unreleased".release.ymlnow dispatchespages.ymlonce the tag exists (the job gains
actions: write); a failed dispatch does not stop the npm publish and turns the job red at its
end. - Installer (#467: A29, A30, A31, A37).
npx ffmpeg-skillfrom a git checkout copies what
the npm package ships (2.6 MB) instead of all ofdocs/andreferences/(17 MB), and copies
LICENSE. An unknown argument, or--dirwith no value, is refused with exit 2 before anything
is installed or removed (--uninstall --cursrused to remove the Claude Code install). A failed
install removes itsffmpeg-skill.tmp-<pid>/scratch folder, and--uninstallremoves ones an
interrupted install left. - Docs corrected against the code (#466: A203, A204, A205, A206, A207, A208, A213, A214, A215;
#467: A35, A248, A249). README:contract_versionis 2.0, not 1.0; a PR does write
CHANGELOG.mdnotes; three demos use AI-generated footage; the Gemini CLI install is the whole
repository; the no-Node route copiesdocs/contract.md, notdocs/. CONTRIBUTING: the MCP
Registry entry is published byrelease.yml. Roadmap:look.py --best-framenever shipped, and
the document ends at 2.0.0. CHANGELOG: the two## 1.15.0headings are one section, so the
release-notes extraction reads all of it. The notes under.claude/skills/no longer say
there is no release workflow, that an existing output is replaced without a word, that CI has
noconcurrency, that there are 22 tools, or thatprobeis ananalysis_onlytool. - Evals, demos and examples (#467: A242, A245, A246, A250, A251, A252, A253, A272, A273).
Gallery commands are shell-quoted (an unquoted#colour made the rest of a pasted line a
comment).examples/make_demo.shpasses--overwrite, so a second run works, and says it runs
13 of the 42 scripts.evals/write_fixtures.pybuildssource.mp4, sokw1,ff1and--all
stage;evals/grade_runs.pyreadsagent_prompts.json;evals/grade_runs_25.pypairs each
command with its own output by tool-use id, and grades a run that never startedNOT_RUN;
evals/README.mdcounts 99 + 11 prompts and says which paths in them are the maintainer's.
Fixed
- In the paths below, a measurement that did not happen is reported as not measured instead of as a value or a pass
(A60, A67, A76, A97, A111, A113, A114, A117, A131, A172, A182, A193, A236, A237, A239, A240,
A241, A257).check.pyPASSed the duration of a file that states no length (read as 0.00 s) and
dropped its--contentblack/frozen/silence rows; those rows are now "could not measure"
(duration FAILs under a length limit), as are an unread frame rate and file size. Its aspect row
reads the displayed frame, so a 16:9 anamorphic file (1440x1080 at SAR 4:3) is 16:9, not 4:3,
and--platform custom --tp Nwithout--lufsnow measures the true peak instead of reporting
0 failed.multicam.py --fix-driftreportsdrift_ppm: nulland adrift_skipped_reason
(too_short/low_confidence, adrift_correction_skippedskip) for a camera whose drift it
did not measure, assync.pydoes, where it said 0.0. A clip shorter than one 400 ms loudness
block is not silent:loudness.py --measure-onlysaystoo_shortwith its true peak and a
normalisation is refused (error.reason: audio_too_short) without telling the caller to replace
the audio;export.pyrecordsloudness_not_measuredwith the measured peak instead of
output_audio_silent, andcheck.py's loudness row WARNs. A loudness step on an output with no
integrated loudness fails (not_measured) where a silent one passed.loudness.pyreports
loudnorm_modeand, when loudnorm fell back to dynamic mode, its shortfall note says so instead
of blaming the encoder.caption.pyreportssize_used: nullwhen no fit ran (a
--transcribe --dry-run),fit_scope: filewith a note when--fit-size-scope cuemet the
plain SRT burn (which draws one size), and a kept subtitle track's own default disposition in
--mode mux(probe.py'ssubtitle_stream_detailscarriesdefault), clearing it when
--default-trackmakes a new track the default.render.py --dry-runplans a clip's speed on
its in..out (a stand-in 10 s only when nothing can be read, recorded as
speed_length_placeholder), and a pack row whose check did not run saysnot checked, not
pass.overlay.pyandgraphics.pyrefuse a--startat or after the end of the video,
where they completedverified: truewith nothing drawn.pad.pyrecords the even scale it
adds (odd_dimensions_scaled_even). A stopped run says "nothing was written" only when no file
it wrote is on disk.verify.py --dry-run(accepted and ignored) saysdry_run: falseand a
note. The contract listsmetadata(--auto-chapters),cut(--snap beats),renderand
batchasanalysis_onlyunder--dry-run, which a test now derives from what each tool's dry
run decodes;report's note no longer claims contact sheets are measured, andcommandsno
longer claims every ffmpeg command line. - fix: a measurement that did not happen is reported as not measured (#490)
- chore: tests, CI, installer, evals and docs findings from the audit (#489)
What's Changed
- chore: tests, CI, installer, evals and docs findings from the audit (#467, #466) by @kajisho5 in #489
- fix: a measurement that did not happen is reported as not measured by @kajisho5 in #490
Full Changelog: v3.6.6...v3.6.7