feat(card): print what produced the video, not every widget that exists

Two rules: skip a value equal to the widget's own default, and skip a value
whose feature is switched off. A region-sharpening prompt printed under a
disabled sharpener read as if it had run, and enough of that buries the few
values that did decide the render. On a realistic project this cuts the Chain
Sampler section from 8 rows to 4.

Defaults are read off the node's own INPUT_TYPES rather than copied here.
Ownership mirrors the Editor's dependsOn wiring, and a test regenerates the
table from engine_settings.js so the two cannot drift. Owner chains are walked
to the end — v2a_grad_scale belongs to joyai_audio_memory, which belongs to
joyai_memory. A section left with nothing to say is dropped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
digital-garbage
2026-08-27 04:34:22 +03:00
co-authored by Claude Opus 5
parent cb5910568e
commit 138e13d901
2 changed files with 258 additions and 6 deletions
+127 -6
View File
@@ -148,6 +148,127 @@ def _pass_rows(cfg: dict) -> list:
return rows
# ── what is worth printing ───────────────────────────────────────────────────
#
# The card answers "what produced this video". A setting left at its default produced
# nothing, and a setting belonging to a switched-off feature produced nothing either — a
# region-sharpening prompt printed under a disabled sharpener reads as if it ran. Both are
# noise, and enough of it buries the handful of values that DID decide the render.
#
# Two rules, both the user's: skip a value that equals the widget's own default, and skip a
# value whose feature is off.
#: knob -> (the toggle that owns it, the value of that toggle which switches it on).
#: None means "any truthy value". Mirrored from the Editor's own dependsOn wiring, and a
#: test regenerates this from engine_settings.js so the two cannot drift apart.
_OWNED_BY = {
"absolute_strength": ("steer_mode", None),
"alg_anchor_sigma_threshold": ("alg_anchor", None),
"alg_anchor_strength": ("alg_anchor", None),
"alg_guide_blur_sigma_threshold": ("alg_blur_guides", None),
"alg_guide_blur_strength": ("alg_blur_guides", None),
"arcface_mode": ("identity_transfer_enabled", None),
"context_window_freenoise": ("context_windows", None),
"context_window_fuse": ("context_windows", None),
"context_window_length": ("context_windows", None),
"context_window_overlap": ("context_windows", None),
"context_window_retain_first": ("context_windows", None),
"context_window_schedule": ("context_windows", None),
"debug_log": ("identity_transfer_enabled", None),
"detail_max_area": ("segmented_detailing", None),
"detail_mode": ("segmented_detailing", None),
"detail_strength": ("segmented_detailing", None),
"detail_targets": ("segmented_detailing", None),
"detail_threshold": ("segmented_detailing", None),
"dynashift_strength": ("dynashift", None),
"dynashift_threshold": ("dynashift", None),
"embed_guidance_source": ("embed_guidance", None),
"embed_guidance_strength": ("embed_guidance", None),
"h3_gain_audio": ("h3_gain_mode", "manual"),
"h3_gain_prompt": ("h3_gain_mode", "manual"),
"h3_gain_video": ("h3_gain_mode", "manual"),
"h3_prompt_scale": ("h3_gain_mode", "manual"),
"h3_taste_bias": ("h3_gain_mode", "manual"),
"h3_video_detail": ("h3_gain_mode", "manual"),
"id_strength": ("identity_transfer_enabled", None),
"joyai_audio_memory": ("joyai_memory", None),
"joyai_fix_frames": ("joyai_memory", None),
"joyai_frame_select": ("joyai_memory", None),
"joyai_memory_size": ("joyai_memory", None),
"joyai_memory_strength": ("joyai_memory", None),
"mid_scene_guide_strength": ("mid_scene_guide", None),
"negative_erase_mode": ("negative_erase", None),
"negative_erase_renorm": ("negative_erase", None),
"negative_erase_strength": ("negative_erase", None),
"output_guidance_strength": ("output_guidance", None),
"phase_scale": ("identity_transfer_enabled", None),
"plateau_cache_threshold": ("plateau_cache", None),
"prompt_enhance_max_length": ("prompt_enhance", None),
"prompt_enhance_system": ("prompt_enhance", None),
"prompt_enhance_temperature": ("prompt_enhance", None),
"prompt_enhance_thinking": ("prompt_enhance", None),
"prompt_enhance_top_p": ("prompt_enhance", None),
"score_slider_strength": ("score_slider", None),
"source_id": ("identity_transfer_enabled", None),
"v2a_grad_scale": ("joyai_audio_memory", None),
}
def _node_defaults(node_class: str) -> dict:
"""Declared defaults for one node's widgets, read off the node itself.
Off the NODE rather than a table here: the node is the thing whose value is being
printed, so a default copied to this file would be one more thing to keep in step.
"""
try:
from . import bridge
spec = bridge._funpack_attr("samplers" if "Sampler" in node_class else "conditioning",
node_class).INPUT_TYPES()
except Exception:
return {}
out = {}
for group in ("required", "optional"):
for name, decl in (spec.get(group) or {}).items():
if not isinstance(decl, (list, tuple)) or not decl:
continue
if len(decl) >= 2 and isinstance(decl[1], dict) and "default" in decl[1]:
out[name] = decl[1]["default"]
elif isinstance(decl[0], (list, tuple)) and decl[0]:
out[name] = decl[0][0] # a combo's first entry is its default
return out
def _switched_on(name: str, values: dict, defaults: dict, _seen=None) -> bool:
"""Is the feature this knob belongs to actually running?
Walks the chain: v2a_grad_scale belongs to joyai_audio_memory, which belongs to
joyai_memory. An owner that is itself off takes everything under it with it.
"""
owner, wanted = _OWNED_BY.get(name, (None, None))
if owner is None:
return True
seen = _seen or set()
if owner in seen: # a cycle in the table is a bug, not a hang
return True
seen.add(owner)
current = values.get(owner, defaults.get(owner))
live = bool(current) if wanted is None else str(current) == str(wanted)
return live and _switched_on(owner, values, defaults, seen)
def _live_rows(values: dict, node_class: str) -> list:
"""`values` filtered down to what actually decided this render."""
defaults = _node_defaults(node_class)
rows = []
for name, value in (values or {}).items():
if name in defaults and value == defaults[name]:
continue
if not _switched_on(name, values, defaults):
continue
rows.append((name, _short(value)))
return rows
def _sampling_sections(studio_inputs: dict, sampler_inputs: dict) -> list:
"""Everything that decided HOW it was sampled, as card sections.
@@ -184,13 +305,13 @@ def _sampling_sections(studio_inputs: dict, sampler_inputs: dict) -> list:
out.append({"title": "Studio", "node_class": "",
"rows": [(k, _short(v)) for k, v in refiner.items()]})
extras = {k: v for k, v in studio_inputs.items() if k not in _SKIP_STUDIO_KEYS}
extras = _live_rows({k: v for k, v in studio_inputs.items()
if k not in _SKIP_STUDIO_KEYS}, "FunPackStudio")
if extras:
out.append({"title": "Studio inputs", "node_class": "",
"rows": [(k, _short(v)) for k, v in extras.items()]})
if sampler_inputs:
out.append({"title": "Chain Sampler", "node_class": "",
"rows": [(k, _short(v)) for k, v in sampler_inputs.items()]})
out.append({"title": "Studio inputs", "node_class": "", "rows": extras})
chain = _live_rows(sampler_inputs, "FunPackLTXAVSceneChainSampler")
if chain:
out.append({"title": "Chain Sampler", "node_class": "", "rows": chain})
return out
+131
View File
@@ -0,0 +1,131 @@
"""The settings card prints what produced the video, not every widget that exists.
Reported from a rental: too much on the card to read, including a region-sharpening prompt
printed under a sharpener that was switched off. A value left at its default produced
nothing, and a value belonging to a disabled feature produced nothing either — but printed
side by side with the handful that DID decide the render, they read as if they had.
Two rules: skip a value equal to the widget's own default, and skip a value whose feature
is off.
"""
import re
import sys
from pathlib import Path
import pytest
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from movie_editor.backend import settings_card as sc
FRONTEND = Path(__file__).resolve().parents[1] / "movie_editor" / "frontend"
@pytest.fixture
def defaults(monkeypatch):
"""Stand in for the node's declared defaults, so these tests describe the RULE."""
table = {
"segmented_detailing": False, "detail_targets": "hands, face",
"context_windows": False, "context_window_overlap": 40,
"joyai_memory": False, "joyai_audio_memory": False, "v2a_grad_scale": 1.0,
"h3_gain_mode": "learned", "h3_video_detail": 1.0,
"cfg": 1.0, "frame_overlap": 8,
}
monkeypatch.setattr(sc, "_node_defaults", lambda _cls: table)
return table
def rows(values, defaults_unused=None):
return dict(sc._live_rows(values, "FunPackLTXAVSceneChainSampler"))
# ── rule 1: a default decided nothing ───────────────────────────────────────
def test_a_value_left_at_its_default_is_not_printed(defaults):
assert rows({"cfg": 1.0}) == {}
def test_a_changed_value_is_printed(defaults):
assert "cfg" in rows({"cfg": 3.5})
def test_a_value_the_node_does_not_declare_is_kept(defaults):
"""Not every key on the card comes from a widget. Unknown means unjudgeable, and
dropping it would hide something the card was asked to show."""
assert "mystery" in rows({"mystery": 7})
# ── rule 2: an off feature decided nothing ──────────────────────────────────
def test_a_setting_under_a_disabled_toggle_is_not_printed(defaults):
"""The one that was reported: a region-sharpening prompt under a disabled sharpener."""
assert rows({"detail_targets": "the hands, the face"}) == {}
def test_the_same_setting_is_printed_once_its_feature_is_on(defaults):
got = rows({"segmented_detailing": True, "detail_targets": "the hands, the face"})
assert got["detail_targets"] == "the hands, the face"
assert "segmented_detailing" in got
def test_a_default_value_under_an_enabled_toggle_is_still_dropped(defaults):
"""The two rules are independent: on does not make a default worth printing."""
got = rows({"context_windows": True, "context_window_overlap": 40})
assert "context_window_overlap" not in got
def test_a_chain_of_owners_is_walked_to_the_end(defaults):
"""v2a_grad_scale belongs to joyai_audio_memory, which belongs to joyai_memory. An
owner that is itself off takes everything under it with it."""
assert rows({"joyai_audio_memory": True, "v2a_grad_scale": 0.5}) == {}
got = rows({"joyai_memory": True, "joyai_audio_memory": True, "v2a_grad_scale": 0.5})
assert "v2a_grad_scale" in got
def test_an_owner_matched_by_value_not_by_truthiness(defaults):
"""h3_gain_mode is a combo: 'manual' switches its dials on, 'learned' does not — and
'learned' is a perfectly truthy string."""
assert rows({"h3_video_detail": 1.4}) == {}
assert "h3_video_detail" in rows({"h3_gain_mode": "manual", "h3_video_detail": 1.4})
def test_a_cycle_in_the_table_does_not_hang(monkeypatch, defaults):
monkeypatch.setitem(sc._OWNED_BY, "a", ("b", None))
monkeypatch.setitem(sc._OWNED_BY, "b", ("a", None))
assert sc._live_rows({"a": 1, "b": 1}, "X") is not None
# ── the table matches the Editor it was copied from ─────────────────────────
def test_the_ownership_table_is_the_editors_own():
"""The Editor hides a knob whose feature is off; the card must hide the same ones. Two
copies of one rule in two languages, so the test regenerates this one from that one."""
src = (FRONTEND / "engine_settings.js").read_text(encoding="utf-8")
found = {}
for name, body in re.findall(r'\{\s*name:\s*"([a-z0-9_]+)"(.*?)\n\s*(?=\{ name:|\];)',
src, re.S):
m = re.search(r'dependsOn:\s*"([a-z0-9_]+)"(?:,\s*dependsValue:\s*"([^"]*)")?', body)
if m:
found[name] = (m.group(1), m.group(2))
assert found, "no dependsOn rows parsed — the parser, not the table, is what broke"
assert found == sc._OWNED_BY
# ── the sections it feeds ───────────────────────────────────────────────────
def test_an_empty_section_is_dropped_rather_than_printed_bare(defaults):
out = sc._sampling_sections({}, {"cfg": 1.0})
assert not [s for s in out if s["title"] == "Chain Sampler"]
def test_a_section_with_something_to_say_survives(defaults):
out = sc._sampling_sections({}, {"cfg": 3.5})
chain = next(s for s in out if s["title"] == "Chain Sampler")
assert chain["rows"] == [("cfg", "3.5")]
def test_defaults_are_read_off_the_node_not_copied_here():
"""A default copied into this file is one more thing to keep in step with the node."""
import inspect
src = inspect.getsource(sc._node_defaults)
assert "INPUT_TYPES()" in src