A wired positive CONDITIONING means Studio does not encode the prompt.
That is not a preference to configure; it is what wiring the input says,
and it is what a wired negative CONDITIONING has always done. Wanting
CLIP to own the prompt means not wiring one.
Removes clip_owns_prompt from the node, both settings panels and the
settings JSON.
A new scale was invented where two calibrated ones existed.
The ceiling is now 1.25 — the exact boost _v2_build_attn2_patch has
applied to an emphasised phrase's K/V on LTX since long before this, on
a path that works. A different mechanism for the same intent should not
push harder.
The ramp toward it is _v2_auto_strength, which already answers "how much
evidence is there": base 0.030, scaled by bad_streak and reward EMA,
clamped to [0.008, 0.085]. So one Awful reaches about x1.13 and a
sustained bad streak x1.19, instead of the top phrase jumping straight to
the maximum off a single rating.
Two defects behind a reported x1.9.
Spans overlap — a phrase and one of its own words match the same tokens
and their biases ADD. Intended, so the word reinforces the phrase, but
unbounded three overlapping x1.5 spans reach an effective x3.4 on one
token. Bounded against the strongest SINGLE span, so an explicit
(word:2.0) still means exactly 2.0.
And it shipped on by default. It changes what the model sees on every
rated run, and it is gated on is_h3_clip — which is why disconnecting
CLIP made generations normal again. Now a toggle, off.
Also replaces prefer_wired_conditioning with clip_owns_prompt: a wired
conditioning owns the prompt by default, and the old order is the opt-in.
It claimed the toggle skips shortcuts, $variables and the scene split.
Only the scene split is true. _expanded_link_texts pre-expands shortcuts
and resolves $variables for every LINKED input, so a node outside Studio
receives the finished text — which is why a prompted soundtrack still
plays with the toggle on.
Also: prompt_base now refuses to place the bias when the text run in the
conditioning does not match the text measured here. A reference node
encodes the whole combined prompt while Studio may be measuring one
scene's, and taking the tail of a longer run would bias the wrong words.
CLIP won whenever both were connected, so Studio replaced an R2V/I2V
node's conditioning with its own text-only encode. On H3 that discards
the reference outright: Qwen3-VL is causal and the vision block precedes
the prompt, so every prompt row is a hidden state that already read the
image. Studio cannot reproduce that — nothing wires h3_references or
source_image in the editor pipeline, so its encode never sees a picture.
Detected from minimax_token_tags (0 marks a vision block) rather than
guessed, so a text-only or non-H3 graph keeps the old precedence.
Three problems, all visible in the first live run.
x1.03 on every phrase: category scores are 0..1 confidences and a phrase
rarely carries much of one axis, so `1 + strength * score` was applied
and inert. Weights are now relative to the strongest candidate, making
strength mean "how much the best phrase gets".
94 candidates capped to 8 by LENGTH kept an arbitrary eight. Ranking is
by weight; longest-first is now only the application order, so a phrase
still lands before one of its own words adds to it.
The prompt was assumed to be the tail of the conditioning. The same run
reported 367 conditioning rows against 368 modality tags, which is
exactly how that assumption breaks. minimax_token_tags marks text as 1
and vision blocks as 0, and references precede the prompt, so the prompt
is the trailing run of 1s — read it instead of inferring it. The status
line says which of the two placed it.
Studio has known which words to weight since 2.0 —
_v2_concept_units_for_run splits every run into phrases, single words and
n-grams; _v2_update_phrase_memory trains each against the rating's
missing/wrong axes. The only consumer was _v2_build_attn2_patch, and H3
skips it: one packed self-attention stream, no cross-attention. So the
learning ran on every generation and reached nothing.
It now becomes an attention-logit bias on the prompt's token positions in
the packed stream, which is the same statement the K/V x1.25 emphasis was
making, at a place H3 has. Boost only by default.
Located with the tokenizer's offset mapping (verified against ComfyUI's
H3 vocabulary), not by re-encoding each phrase through Qwen3-VL-32B the
way _v2_find_phrase_token_ranges does.
The bias is a mask and SLA routes masked calls to dense, so a weighted
run is a dense run. Said once, at install.
Qwen never applies (word:1.2): ComfyUI's H3 tokenizer hardcodes every
weight to 1.0 and runs the raw tokenizer over the literal string, so the
syntax reaches the encoder as punctuation inside the sentence and
sd1_clip's weighting arm never runs.
Scaling embeddings would not have worked either — Qwen's rows are
contextual hidden states, not per-word vectors. But H3 is one packed
self-attention stream with the prompt's tokens in it, so log(w) added to
the logits at that phrase's key positions multiplies its share of the
attention mass by w, which is what a weight means.
Module and tests only; nothing is wired to a node yet.
The check was stricter than the merge it was protecting. comfy merges with
mm(mat1.flatten(1), mat2.flatten(1)).reshape(weight.shape), so the element
count is the constraint, not the two dimensions — and a locon `mid` or a
`reshape` entry changes what the delta has to fit at all. Those two now
abstain instead of dropping, and the count is what is compared.
The message carries both shapes. "Trained against a different variant" says
nothing you can act on; "LoRA 5376x5376 into weight 16128x5376" says whether
every layer is off by one factor (a different width, nothing to do) or only
some are (a fusion or naming difference, fixable).
Reverts 6bf533e, 78c9625, 4bacc9c, 993e5e4, ae337b5 and c4d8018 —
gguf_support.py, loaders.py and their tests are byte-identical to
6f04642. Nothing else is touched.
The quantized path loaded fast and gave the sampler a model it could not
run: shape [21504, 5376] against an input of 22848x5376, one 1344-token
unit apart. Expanding at load is slow and works.
ComfyUI-GGUF hands back either the state dict or a (state_dict, arch)
pair depending on version. Passed on whole, ComfyUI iterates the tuple,
gets the dict as its first element and raises "'dict' object has no
attribute 'startswith'" — an error naming nothing that led back here.
Unwrapped, and the shape check now runs on every load rather than only
when FunPack had overridden the architecture list, which is why a pack
that already knew the architecture went through unvalidated.
The expansion cache is gone. It wrote the model's full dequantized size
beside it, and rented disk is billed. A leftover from it is named with
its size on the next load; deleting it is left to the user.
Dequantizing produces float32 — four times the width the weight ends up
at. Every tensor was collected before any was cast, so the peak was the
whole checkpoint in float32 plus a copy of each: tens of GB of transient
host allocation on a video model, enough to take the machine down rather
than just the load. ThreadPoolExecutor.map made it worse by submitting
everything at once and buffering results in order.
Now cast-and-release per tensor, with a fixed in-flight window. Peak is
the finished model plus a handful of tensors. Pool capped at 4.
Also prints the path and tensor count before the wait, so a load killed
part way leaves evidence of which backend it chose.
No env var. Stepping around the pack's guard means doing its job here:
the returned state dict is validated, and anything unexpected raises
into the existing fallback rather than reaching ComfyUI.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A bare "'dict' object has no attribute 'startswith'" names neither the
step nor the file. Each stage now labels itself in the re-raise. The
ComfyUI-GGUF architecture override is opt-in, not default.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add an unlisted architecture to ComfyUI-GGUF's image list so the
quantized path works, and cache the dequantized weights beside the
file when it does not, so the expansion is paid once.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Attention and SLA are applied to a clone of a one-entry weight cache
keyed on file identity + dtypes, so a sparsity change skips the disk.
GGUF dequantization now runs across threads instead of serially.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Native crashes print a Python traceback instead of nothing, and
kill -USR1 dumps every thread's stack from a hung process without
attaching anything or restarting it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
MiniMax H3 encodes with Qwen3-VL; the stand-in path fetched a 12B Gemma
tokenizer regardless. Local HF cache is now tried before any download,
and a download announces itself — it blocks the run with no timeout.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comfy materialises the full delta before discovering it will not
reshape: 51 blocks x 96768x2688 on a curve-form H3 checkpoint, ~25 GB
churned in bf16, for adapters that could never have applied.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
FUNPACK_PINNED_MEMORY=off|<GB>|<pct>%, applied at import — after the
budget is computed, before any model is staged. Only ever lowers it.
Unevictable pinned pages wedge a host rather than killing the process.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A token pointing along the negative is left with rounding error after
projection; restoring its norm amplified that noise ~1000x into the
conditioning. Cap the gain and refuse a non-finite result.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Erase the negative's pooled direction from the positive conditioning
(projection by default, never the vision span). Plus an option to let a
wired positive CONDITIONING own the prompt while CLIP keeps its jobs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Pass 2 can run a different algorithm. Unwired it reuses pass 1; in the
Editor it is behind Second pass > Own sampler, and Studio mirrors the
high pass into that output when off, so existing projects are unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Lift the unsharp out of the sampler loop through a denoiser proxy, the
same way ALG does. Window is a fraction of the schedule; audio excluded.
Off by default; an unwrappable sampler keeps sampling and says so.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The panel is the Editor's Properties column: collapsed there it stayed
display:none, and its folds are hidden in Simple mode, so the button opened
nothing. ComfyUI-GGUF refusing an arch now falls back to dequantizing.
A .gguf renamed .safetensors reached the safetensors parser (UTF-8 decode
error); content now decides. ComfyUI-GGUF's loader uses relative imports, so
its directory is mounted as a package instead of loaded file-by-file.
Curve-form H3 checkpoints read adaLN from a compact basis, so a full-width
turbo LoRA matches all 51 adaLN keys and merges into none. Named explicitly
instead of 51 generic warnings under a clean-looking status line.
Core lists no .gguf, so the files were invisible. Backend is whichever is
installed: ComfyUI-GGUF keeps weights quantized, the gguf package
dequantizes at load. Family detection reads GGUF containers too.
One mechanism for both: failed() names the attempt, the error and the effect on
the output, once per run; note_on_change states a standing condition once and
again only when it changes. 13 silent no-ops made audible, 4 repeats silenced.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CLIP wins whenever it is connected and the wired CONDITIONING is never read;
the ownership label that knew this was computed and thrown away.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
H3's shifted schedules keep sigma high to the end, so max(0, 1-2*sigma) gave
the rating wrappers 0 of 4 steps on turbo and 4 of 20 at shift 3 while they
reported active. Read the base grid off the schedule; report the window.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Only the fixed-direction fallback announced its lift, so a working value
function was indistinguishable from nothing happening.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Fitted on raw conditioning, it was handed H3's refined tensor and threw every
step; the run fell back to the fixed direction while reporting VF steering.
Take the gradient at the raw cond, lift it, cache it per scene.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
H3 refines conditioning in extra_conds, so c_crossattn is 5376-dim hidden
state while the taste store holds 5120-dim raw text: embed_guidance raised,
score_slider swallowed it and steered nothing. Lift via the model's own
preprocessor; same bridge fixes DynaShift's prompt weighting.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A pin is packed as condition rows, so its token count belongs to the grid it was
encoded on and upscale_2x crashed the model placing it. LTX guides are dropped
here; on H3 the pin is the anchor, so it is brought along instead.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
H3's resizer interpolates to a requested size and takes 1.0-4.0; Lightricks' is a
fixed 2x network and now says it ignored the value instead of rounding quietly.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both did LTX latent surgery unguarded: prepending frames off H3's 5k+2 grid and
attaching conditioning it never reads. Carry now pins the original reference at
frame 0; a mid-clip guide declines by the same rule as every other H3 pin.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ComfyUI has no branch for this architecture, so the only published 24-channel
upsampler needed its own node pack — and second_pass_op on H3 needs a 24-channel
one to run. Shape and statistics come off the checkpoint; it owns its normalisation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
H3 has no latent conditioning, so a carried tail was noise it could overwrite:
the seam matched and the rest of the shot knew nothing about the scene before it.
The previous scene's last latent frame becomes this scene's frame-0 pin.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Core's latent-upscale loader is an if/elif with no else, so an unrecognised file
falls off the end as "cannot access local variable 'model'". The architectures it
knows are probed here first, and an unknown one is reported by name and key shape.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
It is a toggle now, not a value in the list: SLA takes H3's packed self-attention
and the chosen backend takes the text refiner, masked calls and dense-last steps.
When SLA does not take, the chosen backend is still installed on its own.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Picked in the diffusion model loader's attention list, not wired as a node.
Six settings folded under Advanced; offered only where CUDA and Triton run it
and ignored on any model that is not H3. Kernel vendored from LightX2V.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Rows are picked from a searchable list of installed files instead of typed into a
table of dropdowns, and an input the node calls advanced (the trained stack) is
folded away unless something feeds it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
v2a scale and bounded attention install on attn2 / video_to_audio_attn, which the
block-only sweep never reached and never tagged. The census prints what is still
installed before sampling, so a count that grows is proof rather than a hunch.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Empty is a working state now, logged as "No active LoRAs", so the hop every
LoRA needs is already wired into a fresh pipeline.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both were switched off on H3 because Lightricks' upsampler is 128-channel — a fact about
the file, not the family. They now load any upsampler ComfyUI can (core's loader handles
the rest), refuse a mismatched one by name, and never download the LTX file for H3.
Quantization + a per-model attention backend read from ComfyUI's own registry, so only
installed ones are offered. The LoRA loader now takes its own list and scores wrapper
prefixes against the model's key map, instead of applying a diffusers LoRA as a silent no-op.
Old frontends build their API base from location.pathname, so a page left open on the old
URL polled /funpack/<old>/api/health, got 404, and sat on "Reloading ComfyUI" forever —
never reaching the reload that would have hit the page redirect.
Three unrelated reports.
Wires lost or "(not allowed)" after loading a project. /api/pipeline-ports read the
family from the GLOBAL models.json, so it described whichever project was saved last.
Open one on the other family and its saved wires point at ports that family has no rule
for. It takes ?pid= now, and the panel asks for the config before the rules that depend
on it. Reconcile also dropped a port wire when core_overrides named a deleted slot — it
cleared every other slot's wire to that port, then failed to add the replacement.
Guided mode also filtered harder than the builder validates. A node added through
"Any node…" has role `custom`, which no rule table mentions, so a custom VAE loader
could not reach the pipeline at all. A role with no rule for an output type now reaches
any port of that type; a role that HAS one keeps it, and internal links stay closed.
Both sides read the same list, since the panel hiding what the builder accepts is what
produced "(not allowed)".
Frames / scene silently missed shots. Any timeline resize, trim or split moves a scene
off project length for good, and nothing said so — typing 305 and rendering 450 read as
the edit being ignored. The Project panel now says how many shots it doesn't reach and
offers to put them back. The panel's fingerprint had to learn about scene state, or the
warning outlived the fix.
second_pass_op=upscale_2x no longer drops the i2v pin. The pinned frames in the upscaled
latent ARE the anchor — carried through the same upsampler as the rest of the clip — so
only the mask needed scaling to the new grid. Pass 2 at 4x the pixels was the run most
likely to drift off the reference, and it was the one running unpinned. The pin now
holds the upscaled anchor rather than the encoded source image, and the report says so.
Guide keyframes are still dropped: those are token indices, not pixels.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>