Files
ECC/skills/taste-application/tests/test_integration.py
T
928c1dea72 feat(tasteforge): package reusable workflows and preserve native edits (#3033)
* feat: bundle standalone taste distillation and application workflows

* docs: fix imported taste skill markdown lint

* docs: align Turkish agent catalog with taste skills

* refactor: make ECC the canonical reusable video engine

* fix: preserve video duration when applying image overlays

* fix: preserve background colors in image compositing

* fix: report best-effort duration targets and shortfalls

* feat: ship verified Fusion presets with compatibility provenance

* feat(tasteforge): preserve native edits in application bundles

* feat(tasteforge): compile local preservation without hosted input

* fix: update js-yaml to patched 4.3.2

* test: report bounded Stop wrapper failure diagnostics

* fix(tasteforge): fail closed on unsafe output names, missing overlays and cadence

- cli: default report and spec paths are derived from pack name and profile
  genre; require the manifest's name pattern before using either as a
  filename part so a traversal string cannot write outside cwd/out.
- apply_local: a pack without cadence.json, or with no measured shots and
  no explicit mean_shot, raises instead of silently planning 1.0s shots and
  reporting a measured cadence.
- legacy apply: a missing overlay aborts before any paid upload; forge()
  would have rejected it after every take was generated.
- requirements-live: pin fal-client>=0.13.0, the first release whose
  subscribe() accepts client_timeout.

Addresses the five P1 findings from the independent review of #3033.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015fxHRsydPqEcYngGbqkgt1

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 15:31:36 +01:00

543 lines
30 KiB
Python

"""Synthetic, local-only acceptance tests for preserving an existing edit."""
import copy
import hashlib
import json
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
from unittest import mock
from tasteforge.integration import build_application_bundle, validate_application_bundle
SCRIPT = Path(__file__).resolve().parents[1] / "scripts" / "workflow_graphs.py"
PAYLOAD = {"source_video": "https://media.example/source.mov", "compiled_prompt": "Test motion"}
class ApplicationBundleTests(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.addCleanup(self.temp.cleanup)
self.root = Path(self.temp.name).resolve()
self.rate = {"numerator": 30, "denominator": 1}
self.source = self.artifact("source.mov", b"synthetic original video")
self.audio = self.artifact("music.wav", b"synthetic music")
self.snapshot = {
"project": "Synthetic project", "timeline": "Original timeline",
"settings": {"timelineFrameRate": 30.0},
"timeline_readback": {
"video1": [self.clip(self.source["path"], 0, 120, 3, 2)],
"video2": [self.clip("/synthetic/contour.mov", 25, 38, 0, 0)],
"video3": [self.clip("/synthetic/disabled-bloom.mov", 20, 45, 0, 0, False)],
"audio1": [self.clip(self.audio["path"], 0, 117, 0, 1)],
},
}
self.config = {
"baseline": {
"project_file": self.artifact("project.drp", b"synthetic native project"),
"snapshot_file": self.artifact("snapshot.json", self.snapshot),
"project_name": "Synthetic project", "timeline_name": "Original timeline",
"fps": self.rate, "timeline_range": [0, 120],
},
"source": self.binding(self.source, "video1", 125, [3, 123], [0, 120]),
"audio": [self.binding(self.audio, "audio1", 118, [0, 117], [0, 117])],
"protected_intervals": [{"range": [24, 40], "reason": "Original hand treatment"}],
}
def artifact(self, name, content):
data = json.dumps(content).encode() if isinstance(content, dict) else content
path = self.root / name
path.write_bytes(data)
return {"path": str(path), "bytes": len(data), "sha256": hashlib.sha256(data).hexdigest()}
@staticmethod
def clip(path, start, end, left, right, enabled=True):
return {"path": path, "name": Path(path).name, "start": start, "end": end,
"left_offset": left, "right_offset": right, "enabled": enabled,
"properties": {"Opacity": 88.0, "CompositeMode": 0}}
def binding(self, media, track, frames, source_range, timeline_range):
return {"media": media, "track": track, "clip_index": 0, "media_frames": frames,
"fps": self.rate, "source_range": source_range, "timeline_range": timeline_range}
def approved_insert(self):
media = self.artifact("candidate.mov", b"synthetic generated variation")
candidate = {
"id": "take-1", "media": media, "media_frames": 30, "fps": self.rate,
"origin": "provider_generated", "relationship": "generated_variation",
"source_sha256": self.source["sha256"], "review_status": "approved",
"compiled_input_sha256": hashlib.sha256(
json.dumps(PAYLOAD, sort_keys=True, separators=(",", ":"), allow_nan=False).encode()
).hexdigest(),
}
candidate["generation_receipt"] = self.artifact("generation.json", {
"request_id": "synthetic-request", "source_url": PAYLOAD["source_video"],
"source_sha256": self.source["sha256"], "candidate_sha256": media["sha256"],
"compiled_input_sha256": candidate["compiled_input_sha256"],
})
insert = {"candidate_id": "take-1", "candidate_range": [2, 14],
"timeline_range": [60, 72], "retime": "none"}
approval = {"status": "approved", "candidate_sha256": media["sha256"],
"source_sha256": self.source["sha256"],
"compiled_input_sha256": candidate["compiled_input_sha256"],
"candidate_range": [2, 14], "timeline_range": [60, 72]}
approval["edit_context_sha256"] = hashlib.sha256(json.dumps(
{key: self.config[key] for key in ("baseline", "source", "audio", "protected_intervals")},
sort_keys=True, separators=(",", ":"), allow_nan=False).encode()).hexdigest()
insert["approval_file"] = self.artifact("approval.json", approval)
self.config["candidates"] = [candidate]
self.config["inserts"] = [insert]
return candidate, insert, approval
def test_default_bundle_preserves_baseline_audio_and_entire_protected_stack(self):
before = copy.deepcopy(self.config)
bundle = build_application_bundle(self.config, PAYLOAD)
self.assertEqual(self.config, before)
self.assertEqual(bundle["mode"], "preserve_native_timeline")
self.assertEqual(bundle["baseline"], before["baseline"])
self.assertEqual(bundle["audio"], before["audio"])
self.assertEqual(bundle["inserts"], [])
self.assertEqual(bundle["provider_calls"], 0)
self.assertIs(type(bundle["provider_calls"]), int)
self.assertIs(bundle["provider_execution"], False)
self.assertIs(bundle["submit"], False)
self.assertEqual(bundle["provider_input"], PAYLOAD)
self.assertEqual({c["track"] for c in bundle["protected_stack"]},
{"video1", "video2", "video3", "audio1"})
disabled = next(c for c in bundle["protected_stack"] if c["track"] == "video3")
self.assertEqual(disabled["clip"], self.snapshot["timeline_readback"]["video3"][0])
self.assertEqual(validate_application_bundle(bundle), None)
bundle["audio"][0]["timeline_range"][1] = 116
self.assertEqual(self.config, before)
def test_deterministic_bundle_and_no_provider_calls(self):
with mock.patch("socket.socket", side_effect=AssertionError("network forbidden")), \
mock.patch("subprocess.run", side_effect=AssertionError("process forbidden")):
self.assertEqual(build_application_bundle(self.config, PAYLOAD),
build_application_bundle(self.config, PAYLOAD))
def test_approved_insert_is_an_additive_video_only_proposal(self):
self.approved_insert()
bundle = build_application_bundle(self.config, PAYLOAD)
self.assertEqual(len(bundle["inserts"]), 1)
self.assertEqual(bundle["insert_policy"], "new_video_track_preserve_baseline_audio")
self.assertEqual(bundle["audio"], self.config["audio"])
validate_application_bundle(bundle)
def test_pending_rejected_and_historical_urls_never_become_inserts(self):
candidate, _, _ = self.approved_insert()
for state in ["pending", "rejected", "unknown"]:
candidate["review_status"] = state
with self.subTest(state=state), self.assertRaises(ValueError):
build_application_bundle(self.config, PAYLOAD)
candidate["review_status"] = "pending"
self.config["inserts"] = []
self.assertEqual(build_application_bundle(self.config, PAYLOAD)["inserts"], [])
candidate["media"] = {"url": "https://media.example/historical.mov"}
with self.assertRaises(ValueError):
build_application_bundle(self.config, PAYLOAD)
def test_protected_overlap_rejected_including_one_frame(self):
_, insert, approval = self.approved_insert()
for span in [[12, 25], [39, 51], [24, 40]]:
insert["timeline_range"] = span
insert["candidate_range"] = [0, span[1] - span[0]]
insert["approval_file"] = self.artifact("approval.json", {
**approval, "timeline_range": span, "candidate_range": insert["candidate_range"]})
with self.subTest(span=span), self.assertRaisesRegex(ValueError, "protected"):
build_application_bundle(self.config, PAYLOAD)
def test_approval_binds_both_source_and_exact_placement(self):
_, insert, approval = self.approved_insert()
for field, value in [("status", "pending"), ("source_sha256", "0" * 64),
("candidate_sha256", "1" * 64),
("compiled_input_sha256", "2" * 64),
("timeline_range", [72, 84]), ("candidate_range", [3, 15])]:
altered = {**approval, field: value}
insert["approval_file"] = self.artifact("approval.json", altered)
with self.subTest(field=field), self.assertRaises(ValueError):
build_application_bundle(self.config, PAYLOAD)
def test_approval_cannot_transfer_to_another_edit_or_timebase(self):
self.approved_insert()
for field in ["baseline", "fps", "protected"]:
cfg = copy.deepcopy(self.config)
if field == "baseline":
cfg["baseline"]["project_file"] = self.artifact("other.drp", b"another edit")
elif field == "fps":
cfg["baseline"]["fps"]["numerator"] = 60
changed_snapshot = {**self.snapshot, "settings": {"timelineFrameRate": 60.0}}
cfg["baseline"]["snapshot_file"] = self.artifact("other-snapshot.json", changed_snapshot)
else:
cfg["protected_intervals"][0]["range"] = [24, 41]
with self.subTest(field=field), self.assertRaisesRegex(ValueError, "approval"):
build_application_bundle(cfg, PAYLOAD)
def test_original_claim_wrong_source_or_wrong_input_is_rejected(self):
candidate, _, _ = self.approved_insert()
for field, value in [("origin", "original"), ("relationship", "original_hgx"),
("source_sha256", "0" * 64), ("compiled_input_sha256", "1" * 64)]:
prior = candidate[field]
candidate[field] = value
with self.subTest(field=field), self.assertRaises(ValueError):
build_application_bundle(self.config, PAYLOAD)
candidate[field] = prior
def test_exact_integer_frames_and_rational_fps(self):
for bad in [True, False, 1.0, float("nan"), float("inf"), -1, "30"]:
for key in ["numerator", "denominator"]:
cfg = copy.deepcopy(self.config)
cfg["baseline"]["fps"][key] = bad
with self.subTest(key=key, bad=bad), self.assertRaises(ValueError):
build_application_bundle(cfg, PAYLOAD)
cfg = copy.deepcopy(self.config)
cfg["protected_intervals"][0]["range"][0] = bad
with self.subTest(frame=bad), self.assertRaises(ValueError):
build_application_bundle(cfg, PAYLOAD)
def test_source_binding_must_match_native_clip_and_capacity(self):
for field, value in [("source_range", [0, 120]), ("timeline_range", [1, 121]),
("media_frames", 124), ("clip_index", True),
("track", "video2"), ("fps", {"numerator": 24, "denominator": 1})]:
cfg = copy.deepcopy(self.config)
cfg["source"][field] = value
with self.subTest(field=field), self.assertRaises(ValueError):
build_application_bundle(cfg, PAYLOAD)
def test_audio_cannot_be_dropped_retimed_or_extended(self):
for audio in [[], self.config["audio"] * 2,
[{**self.config["audio"][0], "timeline_range": [0, 120]}]]:
with self.subTest(audio=audio), self.assertRaises(ValueError):
build_application_bundle({**self.config, "audio": audio}, PAYLOAD)
def test_mismatched_fps_duration_retime_and_overlapping_inserts(self):
candidate, insert, approval = self.approved_insert()
candidate["fps"] = {"numerator": 30000, "denominator": 1001}
with self.assertRaisesRegex(ValueError, "retime ambiguity"):
build_application_bundle(self.config, PAYLOAD)
candidate["fps"] = self.rate
for field, value in [("retime", "fit"), ("candidate_range", [2, 15]),
("candidate_range", [20, 32]), ("timeline_range", [115, 127])]:
original = insert[field]
insert[field] = value
insert["approval_file"] = self.artifact("approval.json", {
**approval, "timeline_range": insert["timeline_range"],
"candidate_range": insert["candidate_range"]})
reason = "retime ambiguity" if field == "retime" or value == [2, 15] else "bounds"
with self.subTest(field=field), self.assertRaisesRegex(ValueError, reason):
build_application_bundle(self.config, PAYLOAD)
insert[field] = original
insert["approval_file"] = self.artifact("approval.json", approval)
self.config["inserts"].append(copy.deepcopy(insert))
with self.assertRaisesRegex(ValueError, "proposals overlap"):
build_application_bundle(self.config, PAYLOAD)
def test_missing_mutated_or_symlink_artifacts_are_rejected(self):
path = Path(self.source["path"])
original = path.read_bytes()
path.write_bytes(b"changed original")
with self.assertRaises(ValueError):
build_application_bundle(self.config, PAYLOAD)
path.unlink()
with self.assertRaises(ValueError):
build_application_bundle(self.config, PAYLOAD)
target = self.root / "target.mov"
target.write_bytes(original)
path.symlink_to(target)
with self.assertRaises(ValueError):
build_application_bundle(self.config, PAYLOAD)
def test_bundle_tampering_flags_omissions_and_extra_fields_fail(self):
bundle = build_application_bundle(self.config, PAYLOAD)
for field, value in [("provider_calls", False), ("provider_execution", True),
("submit", True), ("dry_run", False), ("protected_stack", []),
("mode", "replace_timeline"), ("extra", "unbound")]:
with self.subTest(field=field), self.assertRaises(ValueError):
validate_application_bundle({**bundle, field: value})
del bundle["audio"]
with self.assertRaises(ValueError):
validate_application_bundle(bundle)
def test_unresolved_hash_numeric_size_and_duplicate_json_fields_are_rejected(self):
for field, value in [("sha256", None), ("sha256", "https://media.example/a.mov"),
("bytes", True), ("bytes", 1.5)]:
cfg = copy.deepcopy(self.config)
cfg["source"]["media"][field] = value
with self.subTest(field=field), self.assertRaises(ValueError):
build_application_bundle(cfg, PAYLOAD)
self.config["baseline"]["snapshot_file"] = self.artifact(
"snapshot.json", b'{"project":"first","project":"second"}')
with self.assertRaisesRegex(ValueError, "duplicate"):
build_application_bundle(self.config, PAYLOAD)
def test_parent_symlink_special_file_and_cloud_placeholder_are_not_read(self):
path = Path(self.source["path"])
alias = self.root / "alias"
alias.symlink_to(self.root, target_is_directory=True)
cfg = copy.deepcopy(self.config)
cfg["source"]["media"]["path"] = str(alias / path.name)
with self.assertRaises(ValueError):
build_application_bundle(cfg, PAYLOAD)
import os
path.unlink()
os.mkfifo(path)
with self.assertRaises(ValueError):
build_application_bundle(self.config, PAYLOAD)
path.unlink()
path.write_bytes(b"synthetic original video")
actual_stat = os.stat
def cloud_stat(target, *args, **kwargs):
info = actual_stat(target, *args, **kwargs)
if target == path.name:
return mock.Mock(st_mode=info.st_mode, st_flags=0x40000000)
return info
with mock.patch("tasteforge.integration.os.stat", side_effect=cloud_stat), \
mock.patch("tasteforge.integration.os.read", wraps=os.read) as read:
with self.assertRaisesRegex(ValueError, "resident"):
build_application_bundle(self.config, PAYLOAD)
# Only baseline project/snapshot were read; the placeholder never opened.
self.assertTrue(read.called)
def test_generation_receipt_drift_and_unselected_history_are_distinct(self):
candidate, _, _ = self.approved_insert()
evidence = json.loads(Path(candidate["generation_receipt"]["path"]).read_text())
for field in ["request_id", "source_url", "source_sha256", "candidate_sha256",
"compiled_input_sha256"]:
bad = {**evidence, field: ""}
candidate["generation_receipt"] = self.artifact("generation.json", bad)
with self.subTest(field=field), self.assertRaises(ValueError):
build_application_bundle(self.config, PAYLOAD)
self.config["candidates"] = []
self.config["inserts"] = []
self.config["historical_receipts"] = [self.artifact("history.json", {
"request_id": "old", "output_url": "https://media.example/unknown.mov"})]
bundle = build_application_bundle(self.config, PAYLOAD)
self.assertEqual(bundle["inserts"], [])
self.assertEqual(bundle["candidates"], [])
def test_source_subset_and_ntsc_rate_preserve_exact_frame_mapping(self):
self.config["source"]["source_range"] = [13, 33]
self.config["source"]["timeline_range"] = [10, 30]
self.rate.update(numerator=30000, denominator=1001)
self.snapshot["settings"]["timelineFrameRate"] = "29.97"
self.config["baseline"]["snapshot_file"] = self.artifact("snapshot.json", self.snapshot)
bundle = build_application_bundle(self.config, PAYLOAD)
self.assertEqual(bundle["source"]["timeline_range"], [10, 30])
self.assertEqual(bundle["baseline"]["fps"], self.rate)
def test_missing_or_conflicting_native_fps_is_rejected(self):
for settings in [{}, {"timelineFrameRate": "24"}, {"timelineFrameRate": True}]:
self.snapshot["settings"] = settings
self.config["baseline"]["snapshot_file"] = self.artifact("snapshot.json", self.snapshot)
with self.subTest(settings=settings), self.assertRaisesRegex(ValueError, "fps"):
build_application_bundle(self.config, PAYLOAD)
def test_exponent_fps_is_rejected_before_fraction_allocation(self):
self.snapshot["settings"]["timelineFrameRate"] = "1e1000000000"
self.config["baseline"]["snapshot_file"] = self.artifact("snapshot.json", self.snapshot)
with mock.patch("tasteforge.integration.Fraction", side_effect=AssertionError("unsafe allocation")):
with self.assertRaisesRegex(ValueError, "fps"):
build_application_bundle(self.config, PAYLOAD)
def test_fileless_native_generator_is_preserved_without_becoming_a_source(self):
self.snapshot["timeline_readback"]["video4"] = [{
**self.clip("unused", 24, 40, 0, 0), "path": None, "name": "Native title"}]
self.config["baseline"]["snapshot_file"] = self.artifact("snapshot.json", self.snapshot)
bundle = build_application_bundle(self.config, PAYLOAD)
generator = next(row for row in bundle["protected_stack"] if row["track"] == "video4")
self.assertIsNone(generator["clip"]["path"])
self.config["source"]["track"] = "video4"
with self.assertRaises(ValueError):
build_application_bundle(self.config, PAYLOAD)
def test_parent_directory_substitution_during_read_is_rejected(self):
from tasteforge import integration
import os
parent = self.root / "reference"
parent.mkdir()
record = self.artifact("reference/source.mov", b"original bytes")
actual_read = os.read
replaced = False
def replace_parent(descriptor, length):
nonlocal replaced
data = actual_read(descriptor, length)
if not replaced:
replaced = True
parent.rename(self.root / "moved-reference")
parent.mkdir()
(parent / "source.mov").write_bytes(b"different bytes")
return data
with mock.patch("tasteforge.integration.os.read", side_effect=replace_parent):
with self.assertRaisesRegex(ValueError, "changed"):
integration._artifact(record)
def test_invalid_cli_bundle_creates_no_output_and_does_not_overwrite(self):
config = {"source_video": PAYLOAD["source_video"], "brief": "Synthetic test",
"style_steer": "Original motion", "integration": self.config}
cfg_file = self.root / "request.json"
cfg_file.write_text(json.dumps(config))
output = self.root / "bundle.json"
output.write_text("original file")
command = [sys.executable, str(SCRIPT), "--kind", "apply-bundle", "--config",
str(cfg_file), "--out", str(output)]
proc = subprocess.run(command, capture_output=True, text=True)
self.assertEqual(proc.returncode, 2)
self.assertEqual(output.read_text(), "original file")
output.unlink()
config["integration"]["source"]["media"]["sha256"] = "0" * 64
cfg_file.write_text(json.dumps(config))
proc = subprocess.run(command, capture_output=True, text=True)
self.assertEqual(proc.returncode, 2)
self.assertFalse(output.exists())
self.assertNotIn("Traceback", proc.stderr)
def test_bundle_cli_refuses_symlink_request_without_output(self):
cfg = {"source_video": PAYLOAD["source_video"], "brief": "Synthetic",
"style_steer": "Synthetic", "integration": self.config}
real = self.root / "request.json"
real.write_text(json.dumps(cfg))
alias = self.root / "alias.json"
alias.symlink_to(real)
out = self.root / "bundle.json"
proc = subprocess.run([sys.executable, str(SCRIPT), "--kind", "apply-bundle",
"--config", str(alias), "--out", str(out)],
capture_output=True, text=True)
self.assertEqual(proc.returncode, 2)
self.assertFalse(out.exists())
def test_growing_artifact_is_rejected_before_accumulating_unbounded_data(self):
from tasteforge import integration
record = self.config["baseline"]["project_file"]
with mock.patch("tasteforge.integration.os.read", side_effect=[b"x" * (record["bytes"] + 1), b""]):
with self.assertRaisesRegex(ValueError, "byte count exceeded"):
integration._artifact(record)
def test_cli_bundle_compilation_and_legacy_payload_are_separate(self):
config = {"source_video": PAYLOAD["source_video"], "brief": "Synthetic test",
"style_steer": "Original motion", "integration": self.config}
config_file = self.root / "request.json"
config_file.write_text(json.dumps(config))
for kind in ["apply", "apply-bundle"]:
proc = subprocess.run([sys.executable, str(SCRIPT), "--kind", kind,
"--config", str(config_file), "--out", str(self.root / kind)],
capture_output=True, text=True)
self.assertEqual(proc.returncode, 0, proc.stderr)
plain = json.loads((self.root / "apply").read_text())
bundle = json.loads((self.root / "apply-bundle").read_text())
self.assertEqual(set(plain), {"source_video", "compiled_prompt"})
self.assertEqual(bundle["provider_input"], plain)
validate_application_bundle(bundle)
def run_local_cli(self, request, *, suffix="local"):
config = self.root / (suffix + "-request.json")
output = self.root / (suffix + "-bundle.json")
config.write_text(json.dumps(request))
proc = subprocess.run([sys.executable, str(SCRIPT), "--kind", "apply-bundle",
"--config", str(config), "--out", str(output)],
capture_output=True, text=True)
return proc, output
def test_local_only_cli_compiles_preservation_without_hosted_source(self):
proc, output = self.run_local_cli({"local_only": True, "integration": self.config})
self.assertEqual(proc.returncode, 0, proc.stderr)
bundle = json.loads(output.read_text())
self.assertIs(bundle["local_only"], True)
self.assertIsNone(bundle["provider_input"])
self.assertIsNone(bundle["compiled_input_sha256"])
self.assertEqual(bundle["provider_input_status"], "not_prepared_local_only")
self.assertEqual(bundle["insert_policy"], "none_preserve_baseline")
self.assertEqual(bundle["inserts"], [])
self.assertEqual(bundle["candidates"], [])
self.assertEqual(bundle["baseline"], self.config["baseline"])
self.assertEqual(bundle["source"], self.config["source"])
self.assertEqual(bundle["audio"], self.config["audio"])
self.assertEqual(len(bundle["protected_stack"]), 4)
self.assertIs(bundle["submit"], False)
self.assertIs(bundle["provider_execution"], False)
validate_application_bundle(bundle)
def test_local_only_flag_is_exact_boolean_in_cli_and_api(self):
for i, bad in enumerate([None, 0, 1, "true", "false", [], {}]):
with self.subTest(flag=bad), self.assertRaisesRegex(ValueError, "local_only"):
build_application_bundle(self.config, None, local_only=bad)
request = {"local_only": bad, "integration": self.config,
"source_video": PAYLOAD["source_video"], "brief": "Synthetic",
"style_steer": "Synthetic"}
proc, output = self.run_local_cli(request, suffix=f"flag-{i}")
self.assertEqual(proc.returncode, 2, proc.stderr)
self.assertIn("local_only", proc.stderr)
self.assertFalse(output.exists())
def test_local_only_rejects_mixed_provider_request_fields(self):
for i, extra in enumerate([
{"source_video": PAYLOAD["source_video"], "brief": "Synthetic", "style_steer": "Synthetic"},
{"source_video": None}, {"provider_input": PAYLOAD}, {"provider_input": None},
{"compiled_prompt": "Synthetic"}, {"brief": "Uncompiled provider brief"},
]):
proc, output = self.run_local_cli(
{"local_only": True, "integration": self.config, **extra}, suffix=f"mixed-{i}")
self.assertEqual(proc.returncode, 2, proc.stderr)
self.assertIn("local-only request", proc.stderr)
self.assertFalse(output.exists())
for supplied in [PAYLOAD, {}, "https://media.example/source.mov"]:
with self.subTest(supplied=supplied), self.assertRaisesRegex(ValueError, "provider input"):
build_application_bundle(self.config, supplied, local_only=True)
def test_local_only_rejects_candidates_and_inserts_before_reading_them(self):
for field in ["candidates", "inserts"]:
cfg = {**self.config, field: [{"unresolved": "https://media.example/old.mov"}]}
with self.subTest(field=field), self.assertRaisesRegex(ValueError, "local-only.*candidates|local-only.*inserts"):
build_application_bundle(cfg, None, local_only=True)
def test_local_only_bundle_cannot_switch_modes_or_gain_provider_fields(self):
bundle = build_application_bundle(self.config, None, local_only=True)
for field, value in [("local_only", False), ("local_only", 1),
("provider_input", PAYLOAD), ("provider_input", {}),
("compiled_input_sha256", "0" * 64),
("provider_input_status", "prepared"),
("insert_policy", "new_video_track_preserve_baseline_audio")]:
with self.subTest(field=field), self.assertRaises(ValueError):
validate_application_bundle({**bundle, field: value})
without_flag = {k: v for k, v in bundle.items() if k != "local_only"}
with self.assertRaises(ValueError):
validate_application_bundle(without_flag)
normal = build_application_bundle(self.config, PAYLOAD)
with self.assertRaises(ValueError):
validate_application_bundle({**normal, "local_only": True})
def test_local_only_still_revalidates_native_evidence(self):
bundle = build_application_bundle(self.config, None, local_only=True)
before = copy.deepcopy(self.config)
self.assertEqual(build_application_bundle(self.config, None, local_only=True), bundle)
self.assertEqual(self.config, before)
Path(self.source["path"]).write_bytes(b"changed media")
with self.assertRaises(ValueError):
validate_application_bundle(bundle)
def test_normal_bundle_default_false_retains_legacy_behavior(self):
normal = build_application_bundle(self.config, PAYLOAD)
explicit = build_application_bundle(self.config, PAYLOAD, local_only=False)
self.assertEqual(normal, explicit)
self.assertNotIn("local_only", normal)
self.assertNotIn("provider_input_status", normal)
with self.assertRaises(ValueError):
build_application_bundle(self.config, None, local_only=False)
for local_only in [False, "omitted"]:
request = {"integration": self.config, "brief": "Synthetic", "style_steer": "Synthetic"}
if local_only is False:
request["local_only"] = False
proc, output = self.run_local_cli(request, suffix=f"normal-{local_only}")
self.assertEqual(proc.returncode, 2)
self.assertFalse(output.exists())
if __name__ == "__main__":
unittest.main()