mirror of
https://github.com/affaan-m/ECC.git
synced 2026-09-18 15:50:25 +02:00
* 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>
90 lines
3.2 KiB
Python
90 lines
3.2 KiB
Python
"""Failing-first tests for offline distillation and the fail-closed live path."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1] / "scripts"
|
|
sys.path.insert(0, str(REPO_ROOT))
|
|
|
|
from tasteforge import distill, interview, schema # noqa: E402
|
|
|
|
FIXTURE = Path(__import__("tasteforge").__file__).resolve().parent / "fixtures" / "flashethereal"
|
|
|
|
|
|
def _profile():
|
|
return interview.conduct(
|
|
{
|
|
"palette": "near-black void, bone white, violet bloom",
|
|
"grain": "fine 35mm grain",
|
|
"lighting": "single hard key",
|
|
"focal_length": "35mm",
|
|
"camera_motion": "locked off",
|
|
"subject_framing": "centered, headroom",
|
|
"grade_description": "crushed blacks",
|
|
"mood_adjectives": "holy, crystalline",
|
|
"avoid": "plastic highlights",
|
|
"brief": "courier in night traffic",
|
|
},
|
|
genre="flashethereal",
|
|
)
|
|
|
|
|
|
class LocalDistillTests(unittest.TestCase):
|
|
def test_distill_local_produces_valid_spec(self):
|
|
spec = distill.distill_local(_profile())
|
|
problems = schema.validate(spec, schema.SPEC_SCHEMA)
|
|
self.assertEqual(problems, [])
|
|
|
|
def test_distill_local_is_deterministic(self):
|
|
a = distill.distill_local(_profile())
|
|
b = distill.distill_local(_profile())
|
|
a["source"].pop("generated"), b["source"].pop("generated")
|
|
self.assertEqual(a, b)
|
|
|
|
def test_distill_local_labels_dry_run_and_carries_answers(self):
|
|
spec = distill.distill_local(_profile())
|
|
self.assertTrue(spec["source"]["dry_run"])
|
|
self.assertEqual(spec["source"]["provider"], "none")
|
|
self.assertEqual(spec["lighting"], "single hard key")
|
|
self.assertEqual(spec["mood_adjectives"], ["holy", "crystalline"])
|
|
|
|
def test_grounding_from_grade_states_measurements(self):
|
|
grade = json.loads((FIXTURE / "grade.json").read_text())
|
|
cadence = json.loads((FIXTURE / "cadence.json").read_text())
|
|
text = distill.grounding_from_grade(grade, cadence)
|
|
self.assertIn("MEASURED GROUND TRUTH", text)
|
|
self.assertIn("black point", text)
|
|
self.assertIn("#131215", text) # dominant palette hex survives
|
|
self.assertIn("cuts/min", text)
|
|
# The banned-words contract from the recovered grounding prompt.
|
|
self.assertIn("Do not contradict", text)
|
|
|
|
def test_grounding_from_empty_inputs_is_empty(self):
|
|
self.assertEqual(distill.grounding_from_grade({}, {}), "")
|
|
|
|
|
|
class FailClosedLiveTests(unittest.TestCase):
|
|
def test_distill_live_raises_provider_disabled(self):
|
|
with self.assertRaises(distill.ProviderDisabledError) as ctx:
|
|
distill.distill_live(_profile())
|
|
self.assertIn("separately authorized", str(ctx.exception))
|
|
|
|
def test_no_network_module_imported(self):
|
|
import sys as _sys
|
|
|
|
_sys.modules.pop("fal_client", None)
|
|
try:
|
|
distill.distill_live(_profile())
|
|
except distill.ProviderDisabledError:
|
|
pass
|
|
self.assertNotIn("fal_client", _sys.modules)
|
|
self.assertNotIn("urllib.request", _sys.modules)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|