Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/actions/changed-paths/tests/test_package_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
import pathlib
import re
import subprocess
import sys
import unittest
from unittest.mock import patch


ROOT = pathlib.Path(__file__).resolve().parents[4]
sys.path.insert(0, str(ROOT / 'scripts'))
import test_oracle
SPEC = importlib.util.spec_from_file_location(
'changed_paths', ROOT / '.github/actions/changed-paths/changed_paths.py')
cp = importlib.util.module_from_spec(SPEC)
Expand Down Expand Up @@ -67,6 +70,24 @@ def test_wasm_triggers_cover_module_fixture_inputs(self):
patterns if key == 'paths-ignore' else [])
self.assertTrue(selected, f'add {path} to the WASM {event} trigger')

def test_release_and_avi_triggers_cover_qualification_and_fixture_inputs(self):
support = {'scripts/' + name for name in test_oracle.SUPPORT}
for workflow, inputs in (
('release', support | {'packages/cli/test/release-clips.sh'}),
('avi-output', support | {'scripts/gen-fixtures.sh', 'scripts/gen-fixtures-mkv.sh',
'scripts/gen-fixtures-ts.sh'})):
filters = workflow_check.trigger_filters(
(ROOT / '.github/workflows' / (workflow + '.yml')).read_text())
pull_filters = [(key, patterns) for event, key, patterns in filters
if event == 'pull_request']
self.assertTrue(pull_filters, workflow)
for key, patterns in pull_filters:
for path in sorted(inputs):
with self.subTest(workflow=workflow, path=path):
selected, _ = cp.decide([path], patterns if key == 'paths' else [],
patterns if key == 'paths-ignore' else [])
self.assertTrue(selected, f'add {path} to the {workflow} pull-request trigger')

def test_wasm_triggers_cover_notice_record_inputs(self):
script = ('import { requiredInputs } from "./scripts/notices/record.mjs"; '
'console.log(JSON.stringify(requiredInputs(process.argv[1], '
Expand Down
4 changes: 3 additions & 1 deletion .github/actions/ci-fixtures/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ runs:
run: |
set -euo pipefail
helpers=$(grep -o '\$SCRIPTS/[A-Za-z0-9_.-]*' scripts/gen-fixtures.sh | sed 's|^\$SCRIPTS/|scripts/|' | sort -u)
echo "key=linux-x64-fixtures-$(cat scripts/gen-fixtures.sh scripts/install-oracle-ffmpeg.sh scripts/oracle-ffmpeg.env $helpers | sha256sum | cut -c1-32)" >> "$GITHUB_OUTPUT"
support=$(python3 -I -B -c 'import sys; sys.path.insert(0, "scripts"); from test_oracle import SUPPORT; print(" ".join("scripts/" + name for name in SUPPORT))')
identity="$(cat scripts/gen-fixtures.sh scripts/install-oracle-ffmpeg.sh scripts/oracle-ffmpeg.env $helpers $support | sha256sum | cut -c1-32)"
echo "key=linux-x64-fixtures-$identity" >> "$GITHUB_OUTPUT"
- name: Restore the fixtures
id: fixtures
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/avi-output.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ on:
- tools/compat-corpus/v2-fixtures.json
- tools/compat-corpus/encode_breadth.py
- scripts/oracle-ffmpeg.env
- scripts/gen-fixtures*.sh
- scripts/test_oracle.py
- scripts/oracle_pin.py
- scripts/oracle_pin_macos.py
- scripts/oracle_audio.py
- scripts/oracle-ffmpeg-macos.env
- scripts/oracle-audio-args.txt
- scripts/install-oracle-ffmpeg.sh
- .github/workflows/avi-output.yml
workflow_dispatch:
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ on:
- packages/cli/test/release-smoke.py
- scripts/install-x264.sh
- scripts/oracle-ffmpeg.env
- scripts/test_oracle.py
- scripts/oracle_pin.py
- scripts/oracle_pin_macos.py
- scripts/oracle_audio.py
- scripts/oracle-ffmpeg-macos.env
- scripts/oracle-audio-args.txt
- scripts/install-oracle-ffmpeg.sh
- crates/**/Cargo.toml
- Cargo.toml
Expand Down
16 changes: 15 additions & 1 deletion .github/workflows/wasm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ on:
- docs/schema/policy-examples/**
- scripts/install-oracle-ffmpeg.sh
- scripts/oracle-ffmpeg.env
- scripts/test_oracle.py
- scripts/oracle_pin.py
- scripts/oracle_pin_macos.py
- scripts/oracle_audio.py
- scripts/oracle-ffmpeg-macos.env
- scripts/oracle-audio-args.txt
- scripts/binaryen.env
- scripts/install-binaryen.sh
- scripts/rust-dist.env
Expand Down Expand Up @@ -64,6 +70,12 @@ on:
- docs/schema/policy-examples/**
- scripts/install-oracle-ffmpeg.sh
- scripts/oracle-ffmpeg.env
- scripts/test_oracle.py
- scripts/oracle_pin.py
- scripts/oracle_pin_macos.py
- scripts/oracle_audio.py
- scripts/oracle-ffmpeg-macos.env
- scripts/oracle-audio-args.txt
- scripts/binaryen.env
- scripts/install-binaryen.sh
- scripts/rust-dist.env
Expand Down Expand Up @@ -148,7 +160,9 @@ jobs:
run: |
set -euo pipefail
helpers=$(grep -o '\$SCRIPTS/[A-Za-z0-9_.-]*' scripts/gen-fixtures.sh | sed 's|^\$SCRIPTS/|scripts/|' | sort -u)
echo "key=linux-x64-fixtures-$(cat scripts/gen-fixtures.sh scripts/install-oracle-ffmpeg.sh scripts/oracle-ffmpeg.env $helpers | sha256sum | cut -c1-32)" >> "$GITHUB_OUTPUT"
support=$(python3 -I -B -c 'import sys; sys.path.insert(0, "scripts"); from test_oracle import SUPPORT; print(" ".join("scripts/" + name for name in SUPPORT))')
Comment thread
capy-ai[bot] marked this conversation as resolved.
Resolved
identity="$(cat scripts/gen-fixtures.sh scripts/install-oracle-ffmpeg.sh scripts/oracle-ffmpeg.env $helpers $support | sha256sum | cut -c1-32)"
echo "key=linux-x64-fixtures-$identity" >> "$GITHUB_OUTPUT"
- uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684
id: fixtures
with:
Expand Down
63 changes: 24 additions & 39 deletions crates/coreav-cli/tests/ffmpeg_mkv_aac_copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use std::sync::atomic::{AtomicU64, Ordering};

#[path = "../../../test-support/oracle.rs"]
mod test_oracle;

static NEXT: AtomicU64 = AtomicU64::new(0);
struct FixtureDir(PathBuf);
impl Drop for FixtureDir {
Expand All @@ -24,20 +27,6 @@ fn fixtures() -> FixtureDir {
FixtureDir(path)
}

fn oracle() -> Option<PathBuf> {
let path = std::env::var_os("COREAV_FFMPEG")
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from("/opt/coreav-oracle-bin/ffmpeg"));
if path.is_file() && path.with_file_name("ffprobe").is_file() {
return Some(path);
}
assert!(
std::env::var_os("CI").is_none() && std::env::var_os("COREAV_REQUIRE_FFMPEG").is_none(),
"set COREAV_FFMPEG to the pinned oracle"
);
None
}

fn success(output: Output) -> Output {
assert!(
output.status.success(),
Expand Down Expand Up @@ -142,10 +131,9 @@ fn payloads(path: &Path) -> Vec<Vec<u8>> {

#[test]
fn aac_copy_is_exactly_clocked_or_preserved_fallback() {
let Some(ffmpeg) = oracle() else {
return;
};
let ffprobe = ffmpeg.with_file_name("ffprobe");
let oracle = test_oracle::require();
let ffmpeg = oracle.ffmpeg();
let ffprobe = oracle.ffprobe();
let owner = fixtures();
let dir = &owner.0;
let variants: &[&[&str]] = &[
Expand All @@ -165,7 +153,7 @@ fn aac_copy_is_exactly_clocked_or_preserved_fallback() {
for rate in [32_000, 44_100, 48_000] {
for channels in [1, 2] {
for samples in [1024, 4096, 4097] {
let source = generate(&ffmpeg, dir, rate, channels, samples);
let source = generate(ffmpeg, dir, rate, channels, samples);
for &options in variants {
let extension = if options.contains(&"-f") {
"m4a"
Expand All @@ -177,7 +165,7 @@ fn aac_copy_is_exactly_clocked_or_preserved_fallback() {
let mut args = vec!["-v", "error", "-y", "-i", source.to_str().unwrap()];
args.extend_from_slice(options);
let pin = success(
Command::new(&ffmpeg)
Command::new(ffmpeg)
.args(["-v", "error", "-y"])
.args(
include_str!("../../../scripts/oracle-audio-args.txt")
Expand All @@ -201,8 +189,8 @@ fn aac_copy_is_exactly_clocked_or_preserved_fallback() {
.unwrap(),
);
assert_eq!(
clocks(&ffprobe, &actual),
clocks(&ffprobe, &expected),
clocks(ffprobe, &actual),
clocks(ffprobe, &expected),
"{rate}/{channels}/{samples}/{options:?}"
);
assert_eq!(edits(&actual), edits(&expected));
Expand Down Expand Up @@ -239,7 +227,7 @@ fn aac_copy_is_exactly_clocked_or_preserved_fallback() {
.arg("ffmpeg")
.args(&args)
.arg(&actual)
.env("COREAV_FALLBACK", &ffmpeg)
.env("COREAV_FALLBACK", ffmpeg)
.env_remove("COREAV_STRICT_SAFE")
.env_remove("COREAV_FALLBACK_ACTIVE")
.output()
Expand All @@ -263,16 +251,15 @@ fn aac_copy_is_exactly_clocked_or_preserved_fallback() {

#[test]
fn unselected_aac_and_iso_copy_keep_their_native_paths() {
let Some(ffmpeg) = oracle() else {
return;
};
let ffprobe = ffmpeg.with_file_name("ffprobe");
let oracle = test_oracle::require();
let ffmpeg = oracle.ffmpeg();
let ffprobe = oracle.ffprobe();
let owner = fixtures();
let dir = &owner.0;
let source = generate(&ffmpeg, dir, 48_000, 1, 4096);
let source = generate(ffmpeg, dir, 48_000, 1, 4096);
let av = dir.join("av.mkv");
success(
Command::new(&ffmpeg)
Command::new(ffmpeg)
.args([
"-v",
"error",
Expand Down Expand Up @@ -341,10 +328,10 @@ fn unselected_aac_and_iso_copy_keep_their_native_paths() {
assert!(output.stdout.is_empty());
assert!(!refused.exists());

let aligned = generate(&ffmpeg, dir, 32_000, 2, 4096);
let aligned = generate(ffmpeg, dir, 32_000, 2, 4096);
let iso = dir.join("iso.mp4");
success(
Command::new(&ffmpeg)
Command::new(ffmpeg)
.args(["-v", "error"])
.args(include_str!("../../../scripts/oracle-audio-args.txt").split_whitespace())
.arg("-i")
Expand All @@ -356,7 +343,7 @@ fn unselected_aac_and_iso_copy_keep_their_native_paths() {
);
let expected = dir.join("iso-reference.mp4");
success(
Command::new(&ffmpeg)
Command::new(ffmpeg)
.args(["-v", "error"])
.args(include_str!("../../../scripts/oracle-audio-args.txt").split_whitespace())
.arg("-i")
Expand All @@ -376,7 +363,7 @@ fn unselected_aac_and_iso_copy_keep_their_native_paths() {
.output()
.unwrap(),
);
assert_eq!(clocks(&ffprobe, &actual), clocks(&ffprobe, &expected));
assert_eq!(clocks(ffprobe, &actual), clocks(ffprobe, &expected));
assert_eq!(payloads(&actual), payloads(&expected));
let a = edits(&actual);
let b = edits(&expected);
Expand Down Expand Up @@ -414,12 +401,10 @@ fn unselected_aac_and_iso_copy_keep_their_native_paths() {

#[test]
fn one_tick_source_changes_refuse_without_changing_fallback() {
let Some(ffmpeg) = oracle() else {
return;
};
let ffmpeg = test_oracle::require().ffmpeg();
let owner = fixtures();
let dir = &owner.0;
let source = generate(&ffmpeg, dir, 32_000, 1, 4096);
let source = generate(ffmpeg, dir, 32_000, 1, 4096);
let bytes = std::fs::read(source).unwrap();
let demux = coreav_mkv::Limits::default();
let segment = coreav_mkv::probe(
Expand Down Expand Up @@ -473,7 +458,7 @@ fn one_tick_source_changes_refuse_without_changing_fallback() {
let expected = dir.join("reference.mp4");
let actual = dir.join("actual.mp4");
let pin = success(
Command::new(&ffmpeg)
Command::new(ffmpeg)
.args(["-v", "error", "-y"])
.args(include_str!("../../../scripts/oracle-audio-args.txt").split_whitespace())
.arg("-i")
Expand Down Expand Up @@ -511,7 +496,7 @@ fn one_tick_source_changes_refuse_without_changing_fallback() {
.arg(&input)
.args(["-c", "copy"])
.arg(&actual)
.env("COREAV_FALLBACK", &ffmpeg)
.env("COREAV_FALLBACK", ffmpeg)
.env_remove("COREAV_STRICT_SAFE")
.env_remove("COREAV_FALLBACK_ACTIVE")
.output()
Expand Down
16 changes: 6 additions & 10 deletions crates/coreav-cli/tests/frame_handoff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,12 @@
use std::path::{Path, PathBuf};
use std::process::Command;

#[path = "../../../test-support/oracle.rs"]
mod test_oracle;

#[test]
fn shared_and_copied_handoffs_produce_identical_files() -> Result<(), Box<dyn std::error::Error>> {
let ffmpeg = std::env::var_os("COREAV_FFMPEG")
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from("/opt/coreav-oracle-bin/ffmpeg"));
if !ffmpeg.is_file() {
assert!(std::env::var_os("CI").is_none(), "missing pinned FFmpeg");
eprintln!("skipping frame handoff fixture without pinned FFmpeg");
return Ok(());
}
let ffmpeg = test_oracle::require().ffmpeg();
let dir = Path::new(env!("CARGO_TARGET_TMPDIR")).join("frame-handoff-identity");
std::fs::create_dir_all(&dir)?;
let x264 = std::env::var_os("COREAV_X264").map(PathBuf::from);
Expand All @@ -34,7 +30,7 @@ fn shared_and_copied_handoffs_produce_identical_files() -> Result<(), Box<dyn st
}
for (codec, format, size, grain) in cases {
let input = dir.join(format!("{codec}-{format}.mkv"));
let mut generate = Command::new(&ffmpeg);
let mut generate = Command::new(ffmpeg);
generate.args([
"-v",
"error",
Expand Down Expand Up @@ -80,7 +76,7 @@ fn shared_and_copied_handoffs_produce_identical_files() -> Result<(), Box<dyn st
.arg(&input)
.arg(&output)
.args(["--encoder", encoder, "--ffmpeg"])
.arg(&ffmpeg)
.arg(ffmpeg)
.args(["--preset", "medium", "--crf", "23", "--force"]);
if let Some(x264) = &x264 {
command.arg("--x264").arg(x264);
Expand Down
1 change: 1 addition & 0 deletions docs/agents/ci.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ Workflow required checks, path filters, DCO, pinned actions, merge-group reuse,
| The VideoToolbox smoke runs for every Rust path dependency it builds and the inherited workspace manifest | `test_videotoolbox_smoke_tracks_its_rust_build_closure` derives normal/build dependencies transitively and the standalone root's dev dependencies from TOML, then requires their directory globs and root manifest in both event filters (`deny.yml`). A Rust type cannot govern workflow triggers |
| Design notes change in the same pull request as the design | test_videotoolbox_owner_docs_do_not_describe_it_as_unimplemented rejects former preimplementation wording for the implemented VideoToolbox owner and requires the plan's explicit CoreAV-to-FFmpeg payload ratio and inclusive bounds (deny.yml). Other design consistency is not enforced: judgment. Rust types cannot establish the meaning of external prose |
| A change of an oracle platform's pin or installer starts every workflow that runs that installer | `scripts/workflow_check.py` (`deny.yml`) checks the platform-specific input lists, including the macOS verifier and its frozen Linux imports. `test_macos_installers_track_only_their_own_required_inputs` checks each macOS input and nested shell calls. A job-level filter (`changed-paths`) is review judgment |
| Fixture cache identities and fixture-consuming workflow triggers include every shared qualification support input, not only the directly called script | The existing `test_oracle.SUPPORT` owner supplies both cache keys; `test_both_fixture_cache_keys_bind_every_owner_support_file` executes both key blocks, changes every support file and rejects missing inputs. `test_all_fixture_support_changes_start_both_wasm_events` and `test_release_and_avi_triggers_cover_qualification_and_fixture_inputs` check the WASM, release and AVI filters against that owner and the generators they run. Workflow path filters cannot consume a Python owner at parse time, so checks prevent drift |
3 changes: 3 additions & 0 deletions docs/agents/ffmpeg-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ CLI and ffprobe behavior, the FFmpeg pin, and fallback names.

| Rule | Enforced by |
|---|---|
| Shell oracle consumers retain the complete pair and reject qualification or response failures before creating output, including under macOS's Bash 3.2 | The shared owner's two-line CLI and plain assignment own qualification; guarded array expansions and read loops avoid newer Bash builtins and nounset behavior. Shell regressions exercise malformed responses, retained paths, explicit overrides and audio arguments without `mapfile`; they default to `/bin/bash` and accept `COREAV_TEST_BASH` for legacy-interpreter checks. A path type cannot propagate shell exit status or establish an external interpreter's behavior |
| Invocation evidence is exact-site, source-bound and dependency-bound, including import-candidate absence and same-file fold severity | The classifier's single binding owner and schema validator reject stale files, import shadows, missing relay dependencies, duplicate or dead entries and weaker fold origins. The freshness, closure, source-span and proposal regressions exercise these external-file facts; a schema type alone cannot establish current checkout bytes |
| Invocation discovery normalizes its repository root and never opens missing index entries or nonregular gitlinks as source files | `inventory` owns root resolution and regular-file selection; the classifier retains missing and nonregular entries as unresolved closure rows. Symlink-root, deleted-file and gitlink regressions cover the public inventory boundary. A path type cannot establish the current filesystem kind |
| Generated concat presentation tests qualify the selected platform's oracle before fixtures and remain explicit on oracle-free platforms | `ffmpeg_concat_primed` delegates to the shared `test_oracle::require` owner instead of a Linux-only verifier. Its two real media tests are named in `test-support/oracle-dependent.json`, while mutation tests remain oracle-free; `test_oracle_free` rejects stale moved names. The owner rejects missing/unverified pairs rather than turning them into passing skips, and the registered macOS CI pair exercises the platform boundary |
| Primed AAC qualification requires stored media with a proven zero decode origin, including when audio is unselected | `primed_aac` receives the parsed `Movie` at both admission sites and rejects actual fragments before checking the skipped frame. The fragment-origin writer regression failed before this correction and covers four `tfdt` origins, both input positions, selected/unselected audio, unchanged native results and byte-identical admission for `mvex` without `moof`. A track description alone cannot establish its packet origin, so the single admission owner consumes the movie's parsed fragment state |
| HEVC summary slice prefixes use strict emulation-prevention validation without extending the qualification window | The shared `SUMMARY_PREFIX_BYTES` fixes the original twelve NAL bytes; `hevc_summary_authority` reads one extra byte only for a terminal escape, and `slice_selects` removes that lookahead before selector parsing. Failing-before malformed-escape, all-continuation, conditional-read and injected-I/O regressions enforce the boundary. A prefix byte slice alone cannot establish whether its final escape has a valid continuation |
Expand Down
Loading
Loading