dzmdd's picture
Upload folder using huggingface_hub
e488ce7 verified
Raw History Blame Contribute Delete
29.3 kB
#!/usr/bin/env python3
"""Unit test for the timeline surface: plan schema, backend seam, compiler.
python tests/test_timeline_compile.py
Synthetic, no GPU, no models, no renders. torch is needed only
because timeline/h3/gridlaw.py reaches into motion.py for the grid
law (deliberately: reuse it, never fork it).
What it checks:
1. THE ROUND TRIP the packet asks for: a plan describing the v3.1
fight-scene window compiles to the same execution the hand-built
t2c_w45e_v001.api.json encodes — window 68..123, hold map
[1]*5+[2]*51, 107 dilated frames, 17 -> 32 tokens, tail guide at
dilated 105 — and the emitted graph's links all resolve.
2. DITHERING: a drawn 2.5x is met in aggregate by mixed integer holds,
and the achieved average tracks the drawn one across ratios.
3. CEILINGS: an envelope above the lane ceiling is refused by the
schema and clamped by the compiler (with a warning), never silently
obeyed.
4. LEGALITY SWEEP: over many envelopes/windows, every compile lands on
the 17k+5 grid, adds a multiple of 17, starts on the 17-phase, keeps
the window inside the clip, and places the guide at the prefix sum.
5. PRICE: monotone in work, layer (b) abstains without calibration and
answers with it, the VRAM fit line says STUB.
6. THE EPISTEMIC BOUNDARY (amendment 2): the semantic schema imports and
validates a plan in a subprocess with NO h3 module and NO torch
loaded; recipe values carry evidence; a deprecated value refuses to
be read and keeps its reason; structural spec facts agree with the
grid law they describe.
7. IDENTITY: compiled sections record backend/spec/recipe/compiler
versions and derive from (plan id, revision); a semantic edit bumps
the revision and makes the compiled cache stale.
Exit code 0 = pass.
"""
import json
import os
import subprocess
import sys
# The pack's own __init__ imports comfy, so the suites load the pack's
# modules directly rather than through it (same trick as
# tests/test_expand_to_end.py). timeline/ is a plain package on disk, so
# adding the pack dir to sys.path is enough.
HERE = os.path.dirname(os.path.abspath(__file__))
PACK = os.path.dirname(HERE)
sys.path.insert(0, PACK)
from timeline import price, schema # noqa: E402
from timeline.h3 import compile as h3compile # noqa: E402
from timeline.h3 import gridlaw as G # noqa: E402
from timeline.h3 import propose as h3propose # noqa: E402
from timeline.h3 import recipe as h3recipe # noqa: E402
from timeline.h3 import spec as h3spec # noqa: E402
W45E = ("/mnt/work/ai/apps/ComfyUI-ModelCatalog/workflows/"
"t2c_w45e_v001.api.json")
FAILS = []
def check(name, ok, detail=""):
print((" PASS " if ok else " FAIL ") + name + (" " + detail if detail else ""))
if not ok:
FAILS.append(name)
def fight_scene_plan():
"""The v3.1 fight-scene window, said semantically: real time through
frame 72, then 2x to the end of the 124-frame clip."""
plan = schema.new_plan("/tmp/seedhunt_20260963_00001_.mp4", frames=124,
fps=24, width=1152, height=640,
proposed_by="test",
settings={"regen_strength": 0.45, "steps": 25,
"seed": 20260817,
"output_prefix": "video/t2c_timeline"})
plan["lanes"].append(schema.generation_density_lane(
[[0, 1.0], [72, 1.0], [73, 2.0], [123, 2.0]], ceiling=4.0))
return plan
def main():
B = h3compile.H3Backend()
# ---- 1. the round trip against the hand-built graph
print("1. ROUND TRIP vs t2c_w45e_v001.api.json")
hand = json.load(open(W45E))
hand_holds = json.loads(hand["404"]["inputs"]["hold_map"])["holds"]
hand_guide = hand["406"]["inputs"]["frame_idx"]
hand_len = hand["524"]["inputs"]["length"]
hand_w0 = hand["410"]["inputs"]["batch_index"]
hand_wlen = hand["410"]["inputs"]["length"]
plan = fight_scene_plan()
check("the plan validates as pure semantics", schema.validate(plan) == [],
str(schema.validate(plan)))
res = B.compile(plan)
c = res.compiled
art = c["artifact"]
check("window matches the hand-built crop",
(art["window"]["start"], art["window"]["len"]) == (hand_w0, hand_wlen),
f"compiled {art['window']} vs hand {hand_w0}+{hand_wlen}")
check("dilated length matches", art["dilated_frames"] == hand_len == 107,
f"{art['dilated_frames']} vs {hand_len}")
check("token count matches: 17 -> 32",
(art["tokens"]["world"], art["tokens"]["dilated"]) == (17, 32),
str(art["tokens"]))
check("tail guide lands on the hand-placed dilated frame",
art["guide_dilated_idx"] == hand_guide == 105,
f"{art['guide_dilated_idx']} vs {hand_guide}")
check("the compiled hold map IS the hand-built one",
art["hold_map"]["holds"] == hand_holds,
G.hold_runs_str(art["hold_map"]["holds"]))
check("added frames are a multiple of 17",
art["added_frames"] % 17 == 0 and art["added_frames"] == 51,
str(art["added_frames"]))
check("dilated length is on the 17k+5 grid", G.is_legal(art["dilated_frames"]))
g = res.graph
ids = set(g)
missing = [k for k, v in g.items() for a in v["inputs"].values()
if isinstance(a, list) and a[0] not in ids]
check("every link in the minted graph resolves", not missing, str(missing[:4]))
check("the graph carries the compiled map verbatim",
json.loads(g["404"]["inputs"]["hold_map"])["holds"] == hand_holds)
check("the node is told NOT to rewrite the map again",
g["404"]["inputs"]["expand_to_end"] is False)
check("class types match the hand-built recipe node for node",
all(g[k]["class_type"] == hand[k]["class_type"]
for k in ("403", "404", "406", "410", "522", "526", "530",
"531", "541")))
# ...with ONE deliberate difference from the hand-built graph (compiler
# 0.3): the hand recipe passed the recovered window through an
# H3TimeSmear at dilation 1 for CPU images, which H3ExactRecover already
# returns. That pass is a no-op only above the legal floor; below it, it
# snapped the window up and lengthened the whole render.
check("no identity H3TimeSmear pass is emitted",
not any(n["class_type"] == "H3TimeSmear" for n in g.values())
and hand["413"]["class_type"] == "H3TimeSmear")
check("the recovered window feeds the splice directly",
g["412"]["inputs"]["image2"] == ["531", 0],
str(g["412"]["inputs"]))
check("inject came from the plan, not from a constant",
g["522"]["inputs"]["inject"] == 0.45
and g["522"]["inputs"]["inject"]
== schema.setting(plan, "regen_strength"))
# ---- 2. dithering
print("\n2. DITHERING (fractional ratios met in aggregate)")
holds = h3compile.dither_holds([2.5] * 56, 141)
check("a flat 2.5x over 56 frames spends exactly 141 dilated frames",
sum(holds) == 141 and min(holds) >= 1, G.hold_runs_str(holds))
check("...as MIXED integer rates, not one rate plus a lump",
set(holds) == {2, 3} and abs(sum(holds) / 56 - 2.5) < 0.02,
f"rates {sorted(set(holds))}, mean {sum(holds) / 56:.3f}")
check("...alternating, so the retime is even across the span",
max(abs(holds[i] - holds[i + 1]) for i in range(len(holds) - 1)) == 1)
for r in (1.5, 2.0, 2.25, 3.0, 3.75):
p = schema.new_plan("/tmp/c.mp4", frames=124, width=1152, height=640)
p["lanes"].append(schema.generation_density_lane([[0, r], [123, r]],
ceiling=4.0))
cc = B.compile(p).compiled["artifact"]
got = cc["achieved_average_density"]
check(f"drawn {r}x over the whole clip -> achieved {got:.3f}x "
f"(grid-rounded)", abs(got - r) <= 0.15,
f"{cc['dilated_frames']}f from {cc['window']['len']}f")
# ---- 3. ceilings
print("\n3. CEILINGS (per-lane, user-settable)")
over = schema.new_plan("/tmp/c.mp4", frames=124, width=1152, height=640)
over["lanes"].append(schema.generation_density_lane(
[[0, 1.0], [60, 6.0], [123, 1.0]], ceiling=4.0))
probs = schema.validate(over)
check("the schema refuses a point above its lane ceiling",
any("above the lane ceiling" in p for p in probs), str(probs[:1]))
over["lanes"][0]["ceiling"] = 8.0
check("raising the ceiling makes the same envelope legal",
schema.validate(over) == [], str(schema.validate(over)))
cc = B.compile(over).compiled["artifact"]
check("an 8x ceiling really is spent (no hidden 4x wall)",
max(cc["hold_map"]["holds"]) >= 5,
f"peak hold x{max(cc['hold_map']['holds'])}, "
f"{cc['dilated_frames']}f")
# ---- 4. legality sweep
print("\n4. LEGALITY SWEEP")
bad = []
n_sweep = 0
for frames in (39, 56, 90, 124, 209):
for lo in (0, 7, 20, 40):
for span in (5, 17, 40):
for r in (1.5, 2.0, 4.0):
hi = min(frames - 1, lo + span)
if lo >= frames - 1:
continue
n_sweep += 1
p = schema.new_plan("/tmp/c.mp4", frames=frames,
width=1152, height=640)
p["lanes"].append(schema.generation_density_lane(
[[0, 1.0], [lo, 1.0], [min(lo + 1, hi), r], [hi, r],
[min(hi + 1, frames - 1), 1.0],
[frames - 1, 1.0]], ceiling=4.0))
if schema.validate(p):
continue
try:
cc = B.compile(p).compiled["artifact"]
except Exception as e:
bad.append((frames, lo, span, r, f"{type(e).__name__}: {e}"))
continue
w0, wl = cc["window"]["start"], cc["window"]["len"]
holds = cc["hold_map"]["holds"]
why = []
if not G.is_legal(cc["dilated_frames"]):
why.append("dilated off grid")
if not G.is_legal(wl):
why.append("window length off grid")
if w0 % 17:
why.append("window start off the 17-phase")
if w0 + wl > frames:
why.append("window runs past the clip")
if len(holds) != wl:
why.append("hold map is not window-local")
if cc["added_frames"] % 17:
why.append("added frames not a multiple of 17")
if cc["guide_dilated_idx"] != sum(holds[:wl - 1]):
why.append("guide is not the prefix sum")
if cc["dilated_frames"] < 39:
why.append("under the 39-frame floor")
if why:
bad.append((frames, lo, span, r, ";".join(why)))
check(f"all {n_sweep} swept plans compile legally", not bad, str(bad[:3]))
# ---- 5. price
print("\n5. PRICE METER (geometry x complexity x calibration)")
model = price.ComplexityModel(
h3recipe.PROFILE.get("cost_exponent"),
h3recipe.PROFILE.get("speed_anchors"))
geoms = [price.Geometry(u, 32, steps=11, frames_plan=107, frames_plain=124,
pixels=1152 * 640)
for u in (32, 47, 62, 92)]
check("cost is monotone in work units",
price.monotonic_check(model, geoms))
check("the exponent is the recipe's, not a literal in price.py",
abs(model.exponent - 1.55) < 1e-9, str(model.exponent))
e0 = price.estimate(geoms[2], model, price.Calibration([]))
check("layer (a) always answers", e0.multiplier > 1.0,
f"{e0.multiplier:.2f}x")
check("layer (b) abstains without calibration and says why",
e0.seconds is None and "not calibrated" in e0.lines[2],
e0.lines[2][:90])
calib = price.Calibration([
{"work_units": 32, "s_per_step": 4.97, "streamed": False},
{"work_units": 47, "s_per_step": 9.1, "streamed": False}])
e1 = price.estimate(geoms[2], model, calib)
check("layer (b) answers once the recorder has runs",
e1.seconds and e1.seconds > 0, f"{e1.seconds / 60:.1f} min")
check("layer (c) declares itself a stub",
"STUB" in e1.lines[-1], e1.lines[-1][:80])
e2 = price.estimate(geoms[3], model, price.Calibration([
{"work_units": 32, "s_per_step": 4.97, "streamed": False},
{"work_units": 80, "s_per_step": 90.0, "streamed": True}]))
check("a streamed run brackets the cliff: bigger plans go red",
e2.fit == "red", f"{e2.fit}: {e2.fit_why[:60]}")
check("the receipt carries the estimate, the artifact carries the number",
c["receipt"]["estimate"]["equivalent_clip_time_x"] > 0
and abs(art["equivalent_clip_time_x"]
- c["receipt"]["estimate"]["equivalent_clip_time_x"]) < 1e-6,
f"{art['equivalent_clip_time_x']:.2f}x a plain 124f render")
# ---- 6. the epistemic boundary
print("\n6. EPISTEMIC BOUNDARY (semantics vs model vs experiment)")
code = (
"import sys, json;"
f"sys.path.insert(0, {PACK!r});"
"from timeline import schema as s;"
"p = s.new_plan('/tmp/c.mp4', frames=124, fps=24);"
"p['lanes'].append(s.generation_density_lane([[0,1.0],[60,2.5],[123,1.0]]));"
"assert s.validate(p) == [], s.validate(p);"
"assert abs(s.sample_envelope(p['lanes'][0]['envelope'], 30) - 1.75) < 1e-9;"
"bad = [m for m in sys.modules if 'torch' in m or 'numpy' in m "
"or '.h3' in m or m.endswith('h3')];"
"print(json.dumps(bad))")
out = subprocess.run([sys.executable, "-c", code], capture_output=True,
text=True)
leaked = json.loads(out.stdout or "null") if out.returncode == 0 else None
check("the semantic schema validates a plan with NO h3 and NO torch "
"loaded", out.returncode == 0 and leaked == [],
(out.stderr or str(leaked))[-200:])
stray = schema.validate(dict(plan, lanes=[dict(plan["lanes"][0],
compiled_hold_map=[1, 2])]))
check("a backend artifact in a semantic lane is a validation error",
any("backend artifact" in p for p in stray), str(stray[:1]))
prof = h3recipe.PROFILE
noev = [k for k, v in prof.values.items() if not v.evidence]
check("every recipe value cites evidence", not noev, str(noev))
check("confidence is one of the declared levels",
all(v.confidence in h3recipe.CONFIDENCE for v in prof.values.values()))
check("deprecation is first class: the value is kept with its reason",
"cost_exponent_legacy" in prof.deprecated_keys()
and prof.record("cost_exponent_legacy").superseded_by == "cost_exponent"
and "motion.py" in prof.record("cost_exponent_legacy").deprecation_reason)
try:
prof.get("cost_exponent_legacy")
ok = False
except KeyError as e:
ok = "deprecated" in str(e)
check("...and reading a deprecated value refuses, naming the successor", ok)
ch = prof.challenges("d_max_sweet_spot", 8, "test", "because")
check("a challenge FLAGS and does not override",
ch["profile_value"] == 4 and "flagged" in ch["resolution"])
check("a proposal above the sweet spot raises that flag",
h3propose.challenge_ceiling(6.0) is not None
and h3propose.challenge_ceiling(3.0) is None)
S = h3spec.SPEC
check("structural spec agrees with the grid law it describes",
all(S.is_legal_length(n) == G.is_legal(n)
for n in range(0, 400))
and all(S.token_count(n) == G.token_count_exact(n)
for n in (5, 22, 39, 56, 90, 107, 124, 209)))
check("the recipe's tail guard is the one the shipped code enforces",
prof.get("max_end_tail") == G.MAX_END_TAIL == 17)
check("audio-exact lengths are DERIVED from the two clocks, not stored",
S.audio_exact_lengths(200) == (39, 90, 141, 192)
and "segment_lengths_audio_exact" not in prof.values,
str(S.audio_exact_lengths(200)))
check("...and an inexact length reports its error instead of refusing",
not S.audio_is_exact(107) and 0 < S.audio_error_ms(107) <= 12.5,
f"107f is {S.audio_error_ms(107):.1f} ms off")
# ---- 7. identity and derivation
print("\n7. IDENTITY / DERIVATION LINKS")
v = c["versions"]
check("the compiled section records what produced it",
v["model_spec"] == S.version and v["recipe_profile"] == prof.version
and v["compiler"] == h3compile.COMPILER_VERSION
and c["backend"] == "h3", json.dumps(v))
check("...and which plan revision AND semantic hash it came from",
c["derived_from"] == {"plan_id": plan["id"],
"revision": plan["revision"],
"semantic_hash": schema.semantic_hash(plan)},
json.dumps(c["derived_from"])[:120])
check("the section is keyed by a fingerprint over intent + versions",
c["fingerprint"] == schema.fingerprint(
schema.semantic_hash(plan), "h3", c["versions"]),
c["fingerprint"][:16])
check("a fresh compile of the same revision is not stale",
not schema.compiled_is_stale(plan, "h3"))
schema.note_edit(plan, "test", "artist raised the envelope")
check("a semantic edit bumps the revision and staleness fires",
plan["revision"] == 1 and schema.compiled_is_stale(plan, "h3"),
f"rev {plan['revision']}, compiled from rev "
f"{c['derived_from']['revision']}")
p2 = fight_scene_plan()
r2 = B.compile(p2)
check("compilation is deterministic for the same plan content",
json.dumps(r2.graph, sort_keys=True)
== json.dumps(res.graph, sort_keys=True))
check("the ARTIFACT is byte-stable across compiles (no timestamps in it)",
json.dumps(r2.compiled["artifact"], sort_keys=True)
== json.dumps(art, sort_keys=True),
"artifact keys: " + ",".join(sorted(art)))
check("...while the RECEIPT is where the timestamp lives",
"compiled_at" in r2.compiled["receipt"]
and "compiled_at" not in json.dumps(art),
r2.compiled["receipt"]["compiled_at"])
# semantic_hash: a hand edit with no revision bump must still invalidate
hand_edited = json.loads(json.dumps(p2)) # as if reloaded from disk
hand_edited["lanes"][0]["envelope"][-1][1] = 2.5
check("a hand-edited JSON invalidates the cache with NO revision bump",
hand_edited["revision"] == p2["revision"]
and schema.compiled_is_stale(hand_edited, "h3"),
f"rev {hand_edited['revision']} both sides, hash "
f"{schema.semantic_hash(hand_edited)[:8]} vs "
f"{schema.semantic_hash(p2)[:8]}")
moved = json.loads(json.dumps(p2))
moved["clip"]["path"] = "/somewhere/else/same_clip.mp4"
moved["provenance"]["created"] = "1999-01-01T00:00:00"
check("...but moving the file or re-stamping provenance does NOT",
schema.semantic_hash(moved) == schema.semantic_hash(p2)
and not schema.compiled_is_stale(moved, "h3"))
check("the fingerprint moves when the compiler version would",
schema.fingerprint(schema.semantic_hash(p2), "h3",
{"compiler": "other"})
!= r2.compiled["fingerprint"])
# ---- 7b. settings groups and ids
print("\n7b. SETTING GROUPS / OBJECT IDS")
st = plan["settings"]
check("settings are grouped, and seed/steps are EXECUTION not intent",
set(st) == set(schema.SETTING_GROUPS)
and "seed" in st["execution_preferences"]
and "steps" in st["execution_preferences"]
and "seed" not in st["intent"]
and "prompt" in st["intent"]
and "max_regen_seconds" in st["constraints"]
and "output_prefix" in st["delivery"], ",".join(sorted(st)))
check("reading a setting does not care which group it is in",
schema.setting(plan, "seed") == 20260817
and schema.setting(plan, "regen_strength") == 0.45
and schema.setting(plan, "sync_policy") == "exact_trim")
legacy = {"plan_version": 0, "id": "x", "revision": 0,
"clip": {"path": "/a.mp4", "frames": 124, "fps": 24,
"width": 1152, "height": 640},
"lanes": [], "settings": {"seed": 7, "steps": 9},
"provenance": {}, "compiled": {}}
check("a pre-grouping flat settings block still reads",
schema.setting(legacy, "seed") == 7
and schema.setting(legacy, "steps") == 9
and schema.setting(legacy, "sync_policy") == "exact_trim")
check("every semantic object carries an id",
all(l.get("id") for l in plan["lanes"])
and schema.pin_lane(10)["id"]
and schema.tracked_region({"kind": "box"})["id"])
noid = fight_scene_plan()
noid["lanes"][0].pop("id")
check("...and a lane without one is a validation error",
any("no id" in x for x in schema.validate(noid)),
str(schema.validate(noid)[:1]))
check("the old lane type name still loads as generation_density",
schema.lane_type({"type": "temporal"}) == "generation_density"
and schema.lane_type({"type": "generation_density"})
== "generation_density")
reserved = fight_scene_plan()
reserved["lanes"].append({"id": "r1", "type": "presentation_map",
"enabled": True})
check("presentation_map / action_rate are RESERVED, refused by name",
any("RESERVED" in x for x in schema.validate(reserved)),
str(schema.validate(reserved)[:1]))
# ---- 8. the backend seam
print("\n8. BACKEND SEAM")
caps = B.capabilities()
check("capabilities name the compiled lanes and the versions",
caps["lanes_compiled"] == ("generation_density",)
and caps["compiler"] == h3compile.COMPILER_VERSION)
unsup = fight_scene_plan()
unsup["lanes"].append(schema.pin_lane(104, authority=1.0))
check("an uncompilable lane is refused BY NAME, not ignored",
any("pin" in p and "not compiled" in p for p in B.validate(unsup)),
str(B.validate(unsup)[:1]))
# ---- 8b. the minimum generation length (minted from a render 2026-08-15)
print("\n8b. TOO-SHORT WINDOWS: widen the region, never the timeline")
min_len = h3spec.SPEC.min_generation_length
def spliced_frames(graph):
"""What the emitted graph actually hands to CreateVideo: the source
pieces plus the recovered window, counted the way ComfyUI will."""
total = 0
for nid, n in graph.items():
if n["class_type"] == "ImageFromBatch" and nid != "405":
total += int(n["inputs"]["length"])
return total # window crop + head + tail, window recovered 1:1
tiny = schema.new_plan("/tmp/clip.mp4", frames=124, fps=24, width=1152,
height=640, proposed_by="test")
tiny["lanes"].append(schema.generation_density_lane(
[[0, 1.0], [20, 1.0], [21, 2.0], [30, 2.0], [31, 1.0], [123, 1.0]]))
res_t = B.compile(tiny)
at = res_t.compiled["artifact"]
wd = at["widened"]
check("a burst too short to generate widens instead of padding",
wd is not None and at["window"]["len"] >= min_len,
f"{wd['from_len'] if wd else '?'}f -> {at['window']['len']}f "
f"(min {min_len})")
# Symmetry is an aim the 17-phase quantizes: the burst must end up as
# centred as a legal start allows, i.e. the source margins either side of
# it cannot differ by more than one group.
lead = 21 - at["window"]["start"]
trail = at["window"]["start"] + at["window"]["len"] - 1 - 30
check("...centred on the burst, within one 17-frame group",
abs(lead - trail) <= G.LEGAL_STEP and lead >= 0 and trail >= 0,
f"{lead} source frames before the burst, {trail} after; absorbed "
f"{wd['before']}/{wd['after']}")
check("...and says so in the warnings and the report",
any("widened" in w for w in res_t.warnings)
and "region widened" in res_t.report,
"; ".join(res_t.warnings)[:90])
check("the widened window still starts on the 17-phase and fits the clip",
at["window"]["start"] % G.LEGAL_STEP == 0
and at["window"]["start"] + at["window"]["len"] <= 124
and G.is_legal(at["window"]["len"]),
str(at["window"]))
check("the drawn burst is still inside the region",
at["window"]["start"] <= 21
and at["window"]["start"] + at["window"]["len"] - 1 >= 30,
str(at["window"]))
check("OUTPUT LENGTH EQUALS THE PLAN's (the 141-frame failure, fixed)",
spliced_frames(res_t.graph) == 124,
f"{spliced_frames(res_t.graph)} vs 124")
check("the spec's generation floor IS the grid law's snap floor",
min_len == G.legal_ceil(1) == G.legal_ceil(min_len) == 39,
f"spec {min_len}, grid law {G.legal_ceil(1)}")
for name, env in (("a mid-clip burst", [[0, 1.0], [50, 1.0], [51, 2.0],
[60, 2.0], [61, 1.0], [123, 1.0]]),
("a burst at the head", [[0, 3.0], [8, 3.0], [9, 1.0],
[123, 1.0]]),
("a burst at the tail", [[0, 1.0], [114, 1.0],
[115, 2.0], [123, 2.0]])):
p2 = schema.new_plan("/tmp/clip.mp4", frames=124, fps=24, width=1152,
height=640, proposed_by="test")
p2["lanes"].append(schema.generation_density_lane(env, ceiling=4.0))
r2 = B.compile(p2)
a2 = r2.compiled["artifact"]
check(f" {name}: region >= {min_len}f, output still 124f, no smear",
a2["window"]["len"] >= min_len
and spliced_frames(r2.graph) == 124
and not any(n["class_type"] == "H3TimeSmear"
for n in r2.graph.values()),
f"window {a2['window']}, spliced {spliced_frames(r2.graph)}")
# ---- 9. migration fixtures
print("\n9. MIGRATION FIXTURES (plan_version 0 is EXPERIMENTAL)")
fx = os.path.join(HERE, "fixtures")
names = sorted(n[:-len(".plan.json")] for n in os.listdir(fx)
if n.endswith(".plan.json"))
check("fixtures exist for the shapes a v1 migration must carry",
len(names) >= 3, ", ".join(names))
for n in names:
fp = schema.load(os.path.join(fx, f"{n}.plan.json"))
want = json.load(open(os.path.join(fx, f"{n}.artifact.json")))
probs = schema.validate(fp)
got = B.compile(fp).compiled["artifact"]
check(f" {n}: still validates and recompiles to its stored artifact",
probs == [] and json.dumps(got, sort_keys=True)
== json.dumps(want, sort_keys=True),
str(probs[:1]) if probs else
f"{got['dilated_frames']}f, "
f"{G.hold_runs_str(got['hold_map']['holds'])[:40]}")
old_shape = {"plan_version": 0, "clip": {"path": "/a.mp4", "frames": 124,
"fps": 24, "width": 1152, "height": 640},
"lanes": [{"type": "temporal", "enabled": True,
"ceiling": 4.0, "proposer": "old",
"envelope": [[0, 1.0], [72, 1.0], [73, 2.0],
[123, 2.0]]}],
"settings": {"seed": 20260817, "steps": 25,
"regen_strength": 0.45},
"provenance": {}, "compiled": {}}
m = schema.migrate(json.loads(json.dumps(old_shape)))
check("a plan from this morning's shape migrates: alias, groups, ids",
schema.validate(m) == []
and schema.lane_type(m["lanes"][0]) == "generation_density"
and set(m["settings"]) == set(schema.SETTING_GROUPS)
and schema.setting(m, "seed") == 20260817
and m["revision"] == 0,
str(schema.validate(m)[:1]))
check("...and compiles to the same execution it always did",
B.compile(m).compiled["artifact"]["hold_map"]["holds"] == hand_holds,
f"{B.compile(m).compiled['artifact']['dilated_frames']}f")
check("the schema says out loud that v0 is experimental",
schema.PLAN_VERSION_STATUS == "EXPERIMENTAL"
and "EXPERIMENTAL" in (schema.__doc__ or ""))
print()
if FAILS:
print(f"FAILED: {len(FAILS)} check(s): " + ", ".join(FAILS))
return 1
print("all checks passed")
return 0
if __name__ == "__main__":
sys.exit(main())