diff --git a/CHANGELOG.md b/CHANGELOG.md index 9aea86a7..1301c75c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -99,6 +99,12 @@ looked exactly like one where the feature was switched off. ### Fixed +- **Context windowing and ALG's guide blur are switched off and hidden on MiniMax H3.** + Core's windowing unpacks the LTXAV stream specifically and measures its window on LTX's 8x + latent ratio; ALG's guide blur acts on guide frames appended to the latent, and an H3 guide + is a condition row, so that tail is always empty. Context windowing also reported the wrong + reason on H3 — it blamed the ComfyUI version for what is a model difference. + - **JoyAI-Echo is switched off and hidden on MiniMax H3, where it was doing damage.** The memory bank places frame *i* at sequence position *i*, but H3's packed layout pins only the first or last frame — so every frame past the first was refused, and the one that landed diff --git a/movie_editor/frontend/pipeline_caps.js b/movie_editor/frontend/pipeline_caps.js index 606bd192..f6ff5a69 100644 --- a/movie_editor/frontend/pipeline_caps.js +++ b/movie_editor/frontend/pipeline_caps.js @@ -128,6 +128,14 @@ bounded_attention_enabled: "Bounded Attention masks text cross-attention; H3 puts text in the same self-attention " + "stream as the video, where the mask would be far too large to hold.", + context_windows: + "Core's context windowing unpacks the LTXAV stream specifically — mapping each video " + + "window onto its audio window and re-slicing the guide entries. H3 packs its sequence " + + "by a different layout, and the window length is measured on LTX's 8x latent ratio.", + alg_blur_guides: + "This blurs the trailing GUIDE frames appended to the latent. On H3 a guide is a " + + "condition row rather than an appended frame, so that tail is always empty. " + + "(alg_anchor is NOT hidden — a continuation scene does carry real latent frames.)", joyai_memory: "JoyAI-Echo places memory frame i at sequence position i. H3's packed layout pins only " + "the FIRST or LAST frame, so every frame past the first is refused — and the one that " @@ -135,6 +143,13 @@ + "one is not merely inert on H3, it is harmful, so the sampler forces it off.", }; + // Sub-settings of the two groups above: they configure machinery that cannot run here. + const CONTEXT_SUB_INPUTS = [ + "context_window_length", "context_window_overlap", "context_window_schedule", + "context_window_fuse", "context_window_freenoise", "context_window_retain_first", + ]; + const ALG_GUIDE_SUB_INPUTS = ["alg_guide_blur_strength", "alg_guide_blur_sigma_threshold"]; + // JoyAI's own sub-settings: they configure a bank that cannot be built here. const JOYAI_SUB_INPUTS = [ "joyai_memory_size", "joyai_fix_frames", "joyai_frame_select", "joyai_memory_strength", @@ -182,7 +197,8 @@ if (!usesChainSampler(st)) return new Set(); if (!isH3(st)) return new Set(Object.keys(H3_ONLY_SAMPLER_INPUTS)); return new Set([...Object.keys(H3_DEAD_SAMPLER_INPUTS), ...IDENTITY_SUB_INPUTS, - ...JOYAI_SUB_INPUTS, ...H3_DEAD_VALUE_INPUTS]); + ...JOYAI_SUB_INPUTS, ...CONTEXT_SUB_INPUTS, ...ALG_GUIDE_SUB_INPUTS, + ...H3_DEAD_VALUE_INPUTS]); } // Returns [{short, detail}] for settings that are ON but cannot do anything on H3. diff --git a/movie_editor/frontend/pipeline_caps.test.js b/movie_editor/frontend/pipeline_caps.test.js index 7b175cad..5679ca50 100644 --- a/movie_editor/frontend/pipeline_caps.test.js +++ b/movie_editor/frontend/pipeline_caps.test.js @@ -93,3 +93,44 @@ test("JoyAI stays available on LTX", () => { assert.ok(!inert.has(k), `${k} must remain reachable on LTX`); } }); + +// ── the rest of the H3 audit ────────────────────────────────────────────────── + +test("context windowing and its settings disappear on H3", () => { + const inert = PC.familyInertInputs(h3); + for (const k of ["context_windows", "context_window_length", "context_window_overlap", + "context_window_schedule", "context_window_fuse", + "context_window_freenoise", "context_window_retain_first"]) { + assert.ok(inert.has(k), `${k} should be hidden on H3`); + } +}); + +test("ALG's GUIDE blur goes on H3 but its ANCHOR blur stays", () => { + // The guide blur acts on frames appended to the latent, and H3 guides are condition rows + // (tail always 0). The anchor blur acts on latent frame 0, which a continuation scene + // really does carry — hiding that one would neuter a knob that works. + const inert = PC.familyInertInputs(h3); + assert.ok(inert.has("alg_blur_guides")); + assert.ok(inert.has("alg_guide_blur_strength")); + assert.ok(inert.has("alg_guide_blur_sigma_threshold")); + assert.ok(!inert.has("alg_anchor")); + assert.ok(!inert.has("alg_anchor_strength")); +}); + +test("knobs that depend on the INSTALL, not the family, stay visible", () => { + // decode noise (which VAE), second pass / detailing (which upsampler) are reported at run + // time against the actual object. A family rule here would be a guess about a models folder. + const inert = PC.familyInertInputs(h3); + for (const k of ["decode_noise_scale", "decode_timestep", "second_pass_op", + "segmented_detailing", "plateau_cache"]) { + assert.ok(!inert.has(k), `${k} is install-dependent and must not be hidden by family`); + } +}); + +test("LTX keeps everything H3 cannot run", () => { + const inert = PC.familyInertInputs(ltx); + for (const k of ["context_windows", "alg_blur_guides", "joyai_memory", + "bounded_attention_enabled", "identity_transfer_enabled"]) { + assert.ok(!inert.has(k), `${k} must remain reachable on LTX`); + } +}); diff --git a/samplers.py b/samplers.py index 73a1dd0c..f35306d2 100644 --- a/samplers.py +++ b/samplers.py @@ -6062,6 +6062,16 @@ class FunPackLTXAVSceneChainSampler: window the packed tensor blindly and quietly wreck audio and guides — the same class of packed-vs-unpacked mistake that killed DynamicConditioning. Refuse instead. """ + if self._is_h3: + # Checked BEFORE the capability gate below, which would otherwise report a + # missing LTXAV core feature and blame the ComfyUI version for what is really a + # model difference. Core's windowing unpacks LTXAV's packed AV stream and + # re-slices its guide entries; H3's sequence is packed by a different layout + # entirely, and the latent window length here is computed on LTX's 8x temporal + # ratio besides. + return None, None, ("MiniMax H3 has no context-window support — core's windowing " + "unpacks the LTXAV stream specifically, and the window length " + "is measured on LTX's 8x latent ratio") try: import comfy.context_windows as _cw import comfy.patcher_extension as _pe @@ -6680,6 +6690,15 @@ class FunPackLTXAVSceneChainSampler: "against LTX's 4096-wide cross-attention context, and the overlap " "tokens need LTX's patchifier; H3's native ref2va reference blocks " "are the equivalent and are not wired yet)") + if context_windows: + _dead.append("context_windows (core's windowing unpacks the LTXAV stream and " + "re-slices its guide entries; H3 packs its sequence differently, " + "and the window length is measured on LTX's 8x latent ratio)") + if alg_blur_guides: + _dead.append("alg_blur_guides (it blurs the trailing GUIDE frames appended to " + "the latent; on H3 a guide is a condition row, so the appended " + "tail is always 0 and there is nothing to blur. alg_anchor still " + "works — a continuation scene does carry real latent frames)") if joyai_memory: _dead.append("joyai_memory / JoyAI-Echo (the memory bank places frame i at " "sequence position i, and H3's packed layout pins only the FIRST " @@ -6709,6 +6728,10 @@ class FunPackLTXAVSceneChainSampler: # an LTX project must not keep doing that here. joyai_memory = False joyai_audio_memory = False + # These two only ever no-op on H3 — off here so the run report does not list a + # mechanism that did nothing. + context_windows = False + alg_blur_guides = False v2a_grad_scale = 1.0 # second_pass_op is NOT switched off here. It only needs a latent upsampler that # matches this model's latent width; which file that is depends on what is