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>
81 lines
3.0 KiB
Python
81 lines
3.0 KiB
Python
"""Failing-first tests for the deterministic taste interview/profile."""
|
|
|
|
from __future__ import annotations
|
|
|
|
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 interview, schema # noqa: E402
|
|
|
|
|
|
class QuestionSetTests(unittest.TestCase):
|
|
def test_questions_cover_required_axes(self):
|
|
ids = {q.id for q in interview.QUESTIONS}
|
|
for required in (
|
|
"palette", "grain", "lighting", "focal_length", "camera_motion",
|
|
"subject_framing", "grade_description", "mood_adjectives", "avoid",
|
|
"brief",
|
|
):
|
|
self.assertIn(required, ids)
|
|
|
|
def test_every_question_has_prompt_and_id(self):
|
|
for q in interview.QUESTIONS:
|
|
self.assertTrue(q.id)
|
|
self.assertTrue(q.prompt)
|
|
|
|
|
|
class ConductTests(unittest.TestCase):
|
|
def _answers(self):
|
|
return {
|
|
"palette": "near-black void with bone-white highlights and one violet bloom",
|
|
"grain": "fine 35mm grain",
|
|
"lighting": "single hard key, backgrounds unlit",
|
|
"focal_length": "35mm, mild compression",
|
|
"camera_motion": "locked off with slow push-ins",
|
|
"subject_framing": "centered subjects, generous headroom",
|
|
"grade_description": "crushed blacks, blown highlights, cool mids",
|
|
"mood_adjectives": "holy, crystalline, distant",
|
|
"avoid": "over-saturated skin, plastic highlights, drifting camera",
|
|
"brief": "a courier weaves through night traffic",
|
|
}
|
|
|
|
def test_conduct_produces_valid_profile(self):
|
|
profile = interview.conduct(self._answers(), genre="flashethereal")
|
|
problems = schema.validate(profile, schema.TASTE_PROFILE_SCHEMA)
|
|
self.assertEqual(problems, [])
|
|
self.assertEqual(profile["genre"], "flashethereal")
|
|
|
|
def test_missing_answers_are_flagged_not_invented(self):
|
|
answers = self._answers()
|
|
del answers["lighting"]
|
|
profile = interview.conduct(answers, genre="flashethereal")
|
|
self.assertIn("lighting", profile["unanswered"])
|
|
self.assertNotIn("lighting", profile["constraints"]["look"])
|
|
# but the profile is still schema-valid
|
|
self.assertEqual(schema.validate(profile, schema.TASTE_PROFILE_SCHEMA), [])
|
|
|
|
def test_profile_deterministic(self):
|
|
a = interview.conduct(self._answers(), genre="g")
|
|
b = interview.conduct(self._answers(), genre="g")
|
|
a.pop("created"), b.pop("created")
|
|
self.assertEqual(a, b)
|
|
|
|
def test_constraints_split_look_and_content(self):
|
|
profile = interview.conduct(self._answers(), genre="flashethereal")
|
|
look = profile["constraints"]["look"]
|
|
self.assertIn("lighting", look)
|
|
self.assertIn("mood_adjectives", look)
|
|
self.assertIn("avoid", look)
|
|
self.assertEqual(
|
|
profile["constraints"]["content"]["brief"],
|
|
"a courier weaves through night traffic",
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|