fix(studio): the scene split no longer discards a wired reference

The split re-encodes each scene from text and its entries replace
output_conditioning WHOLESALE. It re-establishes H3's visual conditioning
from source_image / h3_references — and nothing in the editor pipeline
sets either, because the reference lives on the R2V node, not on Studio.
So a wired reference conditioning was replaced by text-only encodes: not
appearance drift, a different person.

_v2_transition_scene_conditionings returns None when clip is None, so the
wired conditioning survived with CLIP disconnected. That is why
disconnecting CLIP "fixed" it, and why every fix upstream of the split
changed nothing.

Studio cannot split a conditioning it did not build. When one is wired it
keeps it, for every scene, and says so.
This commit is contained in:
digital-garbage
2026-08-23 09:24:51 +03:00
parent 154926523b
commit ef5e46303b
3 changed files with 57 additions and 1 deletions
+8
View File
@@ -38,6 +38,14 @@
`$style` while the encoded prompt had it resolved.
### Fixed
- **A wired reference conditioning is no longer thrown away by the scene split.** The split
re-encodes every scene from text and its entries replace the output wholesale. It
re-establishes H3's visual conditioning from `source_image` / `h3_references` — neither of
which anything in the editor pipeline sets — so on a reference run the identity was
replaced by text-only encodes and the character came out as a different person entirely.
With CLIP disconnected the split returned None and the wired conditioning survived, which
is why disconnecting CLIP appeared to fix it. Studio cannot split a conditioning it did not
build, so it now keeps the one it was given and says so.
- **A reference image's encoded rows are no longer steered.** H3 tokenizes a reference INTO
the conditioning — comfy marks the whole vision block as 0 in `minimax_token_tags` and text
as 1 — and those rows are Qwen's encoding of the picture. Every steering path (learned
+17 -1
View File
@@ -13094,7 +13094,23 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
)
if _conditioning_plan_reason:
print(f"[FunPackVideoRefinerV2] {_conditioning_plan_reason}")
if split_by_transitions:
# The split RE-ENCODES every scene from text and its entries replace
# `output_conditioning` wholesale. It re-establishes H3's visual conditioning from
# `source_image` / `h3_references` — but a wired CONDITIONING carries a reference this
# node never received: nothing in the editor pipeline sets either of those, so the
# re-encode is textually blind to the picture and the identity is simply gone. Not
# drift — a different person. Studio cannot split a conditioning it did not build, so
# it keeps the one it was given.
if split_by_transitions and conditioning_owner == "CONDITIONING-owned":
_log.note_on_change(
"studio:split_vs_wired", "FunPackStudio",
"the positive CONDITIONING is wired, so the scene split is SKIPPED — "
"splitting means re-encoding each scene from text, and this node cannot "
"reproduce a reference it never received. Every scene uses the wired "
"conditioning. Disconnect it to let Studio split and encode per scene.")
status = status + ("\nTransition split: skipped — the wired positive "
"CONDITIONING owns the prompt") + enhancement_status
elif split_by_transitions:
try:
scene_texts = split_scene_texts
if scene_texts:
@@ -7,6 +7,7 @@ so the vision block precedes the prompt and every prompt row is a hidden state t
already read the picture. Studio cannot reproduce that: nothing in the editor pipeline wires
`h3_references` or `source_image`, so its encode never sees an image at all.
"""
import inspect
import sys
import types
@@ -83,3 +84,34 @@ def test_an_invalid_wired_conditioning_falls_back_to_clip(studio, monkeypatch, c
assert owner == "CLIP-owned"
assert torch.equal(cond, torch.ones(1, 4, 8))
assert "invalid" in capsys.readouterr().out
# --- the scene split cannot rebuild what it did not encode -----------------
def test_the_split_is_skipped_when_the_conditioning_is_wired(monkeypatch, capsys):
"""The split re-encodes every scene from text and its entries replace the output
WHOLESALE. It re-establishes H3's visual conditioning from source_image /
h3_references — neither of which the editor pipeline ever sets — so a wired reference
conditioning was replaced by text-only encodes and the character became someone else.
With CLIP disconnected the split returns None and the wired conditioning survived, which
is exactly why disconnecting CLIP 'fixed' it.
"""
import conditioning
node = conditioning.FunPackVideoRefinerV2()
called = []
monkeypatch.setattr(node, "_v2_transition_scene_conditionings",
lambda *a, **k: called.append(a) or None, raising=False)
src = inspect.getsource(conditioning.FunPackVideoRefinerV2.refine_v2)
# The guard is on ownership, not on CLIP being absent.
assert 'split_by_transitions and conditioning_owner == "CONDITIONING-owned"' in src
assert "elif split_by_transitions:" in src
def test_the_skip_is_reported_not_silent():
"""A silently unsplit multi-scene run looks like the scene texts were ignored."""
import conditioning
src = inspect.getsource(conditioning.FunPackVideoRefinerV2.refine_v2)
assert "the scene split is SKIPPED" in src
assert "Disconnect it to let Studio split and encode per scene." in src