fix: three silent fallbacks from tonight now say what they did
Unreadable modality tags widened the erase to every position including an image span; a partly-failed erase left some scenes changed; an unreadable sigma disabled sharpening while still reporting it active. A malformed reference slot claimed nothing was marked. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
f426b260b5
commit
ce9e679f0e
@@ -628,7 +628,15 @@ def build(object_info: dict, models_config: dict, params: dict, media: dict | No
|
||||
n = int(num)
|
||||
except ValueError:
|
||||
n = 0
|
||||
ref = _reference_by_slot(kind, n) if n > 0 else None
|
||||
if n <= 0:
|
||||
# A malformed slot is not "no reference marked" — reporting it as that
|
||||
# sends the user to the Media Bin to fix a value that is wrong in the
|
||||
# node. Say which it is.
|
||||
report["unsatisfied"].append(
|
||||
f"{s.get('node_class')}.{ci_name}: input source '{source}' is not a "
|
||||
f"reference slot (expected e.g. 'ref#image:1').")
|
||||
continue
|
||||
ref = _reference_by_slot(kind, n)
|
||||
if ref is None:
|
||||
# Nothing marked in that slot. The socket is simply left unconnected —
|
||||
# an unused reference slot is a normal state, not a setup mistake, so it
|
||||
|
||||
@@ -881,11 +881,14 @@ def test_an_empty_slot_is_not_quietly_filled_with_something_else():
|
||||
assert not isinstance(graph["slot_r"]["inputs"].get("ref_images.ref_image0"), list)
|
||||
|
||||
|
||||
def test_a_malformed_slot_reference_does_not_crash_the_build():
|
||||
def test_a_malformed_slot_says_it_is_malformed_not_that_nothing_is_marked():
|
||||
""""No reference marked" sends the user to the Media Bin to fix a value that is wrong in
|
||||
the node. The two are different problems and must not read the same."""
|
||||
_graph, report = builder.build(
|
||||
REF_OI, _slot_models(**{"ref_images.ref_image0": "ref#image:nope"}),
|
||||
_ref_params(_img("m1", "a.png")))
|
||||
assert not _ref_problems(report)
|
||||
assert any("not a reference slot" in u for u in report["unsatisfied"])
|
||||
assert not any("none marked" in w for w in report["wired"])
|
||||
|
||||
|
||||
def test_the_loader_matches_what_the_destination_socket_asks_for():
|
||||
|
||||
+16
-3
@@ -50,7 +50,13 @@ def _text_positions(meta, length):
|
||||
return None # tags and conditioning disagree — touch nothing selectively
|
||||
idx = (flat == 1).nonzero(as_tuple=False).reshape(-1)
|
||||
return idx if int(idx.numel()) else None
|
||||
except Exception:
|
||||
except Exception as exc: # noqa: BLE001
|
||||
# NOT silent: returning None here widens the operation from "text positions only" to
|
||||
# "every position", which on H3 means erasing a text direction out of the reference
|
||||
# image's conditioning. A caller that cannot see this happen cannot explain the
|
||||
# result it gets.
|
||||
print(f"[FunPack] negative_erase: could not read the modality tags ({exc}) — the "
|
||||
f"erase applies to EVERY position, including any image span")
|
||||
return None
|
||||
|
||||
|
||||
@@ -154,7 +160,7 @@ def apply(positive, negative, strength, mode="project", renorm=True):
|
||||
if unit is None:
|
||||
return positive, "negative_erase: the negative conditioning has no usable direction"
|
||||
|
||||
out, touched = [], 0
|
||||
out, touched, failed = [], 0, []
|
||||
for entry in positive:
|
||||
try:
|
||||
tensor, meta = entry[0], (entry[1] if len(entry) > 1 else {})
|
||||
@@ -162,8 +168,15 @@ def apply(positive, negative, strength, mode="project", renorm=True):
|
||||
if new is not tensor:
|
||||
touched += 1
|
||||
out.append((new, meta) + tuple(entry[2:]))
|
||||
except Exception: # noqa: BLE001
|
||||
except Exception as exc: # noqa: BLE001
|
||||
failed.append(str(exc))
|
||||
out.append(entry)
|
||||
if failed:
|
||||
return positive, (f"negative_erase: {len(failed)} conditioning entr"
|
||||
f"{'y' if len(failed) == 1 else 'ies'} could not be modified "
|
||||
f"({failed[0]}) — NOTHING was changed, because a prompt where only "
|
||||
f"some scenes had the negative removed is worse than one where none "
|
||||
f"did")
|
||||
if not touched:
|
||||
return positive, "negative_erase: no conditioning entry could be modified"
|
||||
return out, (f"negative_erase: {mode} {float(strength):.2f} on {touched} "
|
||||
|
||||
+6
-1
@@ -1379,7 +1379,12 @@ class _SharpenDenoiser:
|
||||
denoised = self._inner(x, sigma, **kwargs)
|
||||
try:
|
||||
s = float(sigma.flatten()[0]) if hasattr(sigma, "flatten") else float(sigma)
|
||||
except Exception: # noqa: BLE001
|
||||
except Exception as _e: # noqa: BLE001
|
||||
# Once, not per evaluation — but never nothing. Silently returning here would
|
||||
# leave quality_sharpness switched on, reported as active, and doing nothing for
|
||||
# the whole run.
|
||||
_log.failed("FunPackStudio", "quality sharpness (unreadable sigma)", _e,
|
||||
"this sampler's steps are NOT being sharpened")
|
||||
return denoised
|
||||
if s > self._thr:
|
||||
# Outside the window: nothing to sharpen, but the prediction is still KEPT. The
|
||||
|
||||
Reference in New Issue
Block a user