Commit Graph
218 Commits
Author SHA1 Message Date
digital-garbage b3c2dd3315 feat(h3): give the rating's phrase emphasis somewhere to land
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.
2026-08-23 08:36:17 +03:00
digital-garbage 6ae95b6fbd feat(h3): token weighting as an attention-logit bias
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.
2026-08-23 08:25:05 +03:00
digital-garbage 6308578bd7 fix(lora): stop dropping adapters comfy would have merged, and say which shapes
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).
2026-08-23 08:22:22 +03:00
digital-garbage a490b8a6ed revert(gguf): back to the load path from 6f04642
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.
2026-08-23 08:12:43 +03:00
digital-garbage c4d8018c09 fix(gguf): unwrap a (state dict, architecture) return; drop the disk cache
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.
2026-08-23 05:53:26 +03:00
digital-garbage ae337b5196 fix(gguf): expand one tensor at a time instead of all of them
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.
2026-08-23 05:34:28 +03:00
digital-garbageandClaude Opus 5 993e5e4d04 feat(gguf): read an unlisted architecture by default
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>
2026-08-23 05:26:32 +03:00
digital-garbageandClaude Opus 5 4bacc9c7d3 fix(loaders): name the stage a load failed at; gate the arch override
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>
2026-08-23 05:24:50 +03:00
digital-garbageandClaude Opus 5 78c9625a1a perf(gguf): load quantized where possible, expand only once
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>
2026-08-23 05:04:07 +03:00
digital-garbageandClaude Opus 5 6bf533e808 perf(loaders): stop re-reading the checkpoint for inference settings
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>
2026-08-23 05:00:29 +03:00
digital-garbageandClaude Opus 5 729027d7e1 feat: FUNPACK_FAULTHANDLER for crashes and hangs
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>
2026-08-23 04:35:41 +03:00
digital-garbageandClaude Opus 5 52724066a6 fix(studio): right tokenizer family, and never the network first
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>
2026-08-23 04:32:44 +03:00
digital-garbageandClaude Opus 5 9542b49d35 fix(lora): drop weights that cannot fit instead of attempting them
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>
2026-08-23 04:22:12 +03:00
digital-garbageandClaude Opus 5 1e98ad56bb feat: cap ComfyUI's pinned memory without a launch flag
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>
2026-08-23 04:17:41 +03:00
digital-garbageandClaude Opus 5 2b3a97ec8d fix(studio): cap the negative_erase renorm gain
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>
2026-08-23 03:52:45 +03:00
digital-garbageandClaude Opus 5 7a2526a8b7 feat(studio): use the negative prompt at CFG 1
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>
2026-08-23 03:33:17 +03:00
digital-garbageandClaude Opus 5 2a259a24a7 feat(samplers): optional second_pass_sampler
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>
2026-08-23 03:25:10 +03:00
digital-garbageandClaude Opus 5 a0fdc24142 feat(samplers): quality sharpness on any KSampler
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>
2026-08-23 00:08:57 +03:00
digital-garbage c55d22752a feat(loaders): make gguf a FunPack requirement
A fresh install now reads .gguf with nothing extra. The no-backend message
points at re-running requirements rather than naming a lone package.
2026-08-22 23:27:48 +03:00
digital-garbage 9af45cf695 fix: Simple mode Advanced settings, and GGUF arch fallback
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.
2026-08-22 23:26:31 +03:00
digital-garbage ba9388f216 fix(loaders): GGUF by container magic, and mount the pack as a package
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.
2026-08-22 23:22:01 +03:00
digital-garbage a812c52189 feat(lora): report weights that match by name but not by shape
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.
2026-08-22 23:18:36 +03:00
digital-garbage b57db12eaf feat(loaders): load .gguf diffusion models and text encoders
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.
2026-08-22 23:13:46 +03:00
digital-garbageandClaude Opus 5 49ad84db45 feat: report failures, stop repeating standing conditions
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>
2026-08-22 17:59:01 +03:00
digital-garbageandClaude Opus 5 a571e0ec7c fix(studio): say when a wired conditioning is being ignored
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>
2026-08-21 01:58:11 +03:00
digital-garbageandClaude Opus 5 733266388b fix(sampler): gate steering on schedule position, not absolute sigma
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>
2026-08-21 01:55:27 +03:00
digital-garbageandClaude Opus 5 e409ac8f82 fix(sampler): the value function path steered without saying so
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>
2026-08-21 01:50:25 +03:00
digital-garbageandClaude Opus 5 3e6cb7fbb3 fix(sampler): ask the value function for a gradient in its own space
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>
2026-08-21 01:40:32 +03:00
digital-garbageandClaude Opus 5 68515b3825 fix(sampler): carry taste directions into the space the model consumes
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>
2026-08-21 01:35:40 +03:00
digital-garbageandClaude Opus 5 1c4d449a83 fix(sampler): resample H3 keyframe pins when a second pass resizes the latent
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>
2026-08-21 00:26:07 +03:00
digital-garbageandClaude Opus 5 fce300cf48 feat(second pass): a resample factor, honoured only where it is real
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>
2026-08-21 00:16:07 +03:00
digital-garbageandClaude Opus 5 6bcd869d4e fix(sampler): carry_i2v_guides and mid_scene_guide had no H3 path
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>
2026-08-21 00:09:36 +03:00
digital-garbageandClaude Opus 5 a9d2c0d9f0 feat(detailing): load MiniMax H3's latent upscaler natively
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>
2026-08-21 00:03:43 +03:00
digital-garbageandClaude Opus 5 d4a69eb873 fix(sampler): H3 scenes continue from the previous one, not just next to it
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>
2026-08-20 23:59:27 +03:00
digital-garbageandClaude Opus 5 71777a9f29 fix(second pass): name the upsampler ComfyUI cannot load, instead of its traceback
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>
2026-08-20 23:56:10 +03:00
digital-garbageandClaude Opus 5 a4839c36f2 refactor(loaders): SLA composes with the attention backend instead of replacing it
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>
2026-08-20 23:36:01 +03:00
digital-garbageandClaude Opus 5 caf13f4ed9 feat(loaders): SLA block-sparse attention for MiniMax H3
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>
2026-08-20 23:06:15 +03:00
digital-garbageandClaude Opus 5 614ce0a196 feat(models): the LoRA loader gets a real picker; advanced inputs fold away
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>
2026-08-20 19:29:35 +03:00
digital-garbageandClaude Opus 5 eb78f35a1e fix(sampler): sweep leaked hooks below the blocks; log a hook census per run
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>
2026-08-20 19:14:24 +03:00
digital-garbageandClaude Opus 5 aa08b909f3 feat(models): seed the LoRA loader; empty list passes the model through
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>
2026-08-20 19:09:33 +03:00
digital-garbage 8d4a199e1f feat(sampler): second pass and segmented detailing on any model family
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.
2026-08-20 18:38:36 +03:00
digital-garbage 3837f8fc95 feat(loaders): FunPack diffusion/CLIP/VAE loaders; LoRA loader works alone
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.
2026-08-20 18:20:16 +03:00
digital-garbage e1a907a93b fix: redirect the legacy /movie and /easy API prefix, not just the page
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.
2026-08-14 23:01:40 +03:00
digital-garbageandClaude Opus 5 bf73835e3b fix: wiring survives a project load; Frames says when it reaches nothing; anchor survives upscale_2x
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>
2026-08-14 02:24:53 +03:00
digital-garbageandClaude Opus 5 b56900b499 fix(refiner): follow the encoder instead of assuming Gemma3
LTX-2.5 encodes with Gemma4 where 2.3 used Gemma3. Concept steering finds a phrase
by matching its token ids inside the prompt's, so a tokenizer from the wrong family
still returns spans — pointing at the wrong tokens. Nothing raises; steering just
stops working.

The tokenizer now comes from the connected CLIP, which is by construction the one
that produced the conditioning. The download stays as the fallback for runs with no
CLIP, and says so rather than claiming to be Gemma3.

Learned state is stamped with its encoder and cleared when that changes, on both the
V1 and V2 paths. Clearing reuses Session Reset so the value function, x0 snapshots
and the keyless Absolute store go with it instead of being orphaned. An unstamped
key is adopted, never wiped: every key predating this has no stamp.

The vision probe no longer depends on the submodule being called gemma3_12b — it
still is on 2.5, where it holds Gemma4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 20:03:37 +03:00
digital-garbageandClaude Opus 5 7329cd9680 fix: multi-scene chains work with a resolution-changing second pass
second_pass_op="upscale_2x" hands a scene back at twice the latent size while
every LATER scene is still built from latent_template at the original size.
Everything that crosses a scene boundary — carried overlap frames, the anchor's
continuation, the soft join, the JoyAI memory frame, per-scene guide sources —
is spliced into a chunk on the template's grid, so the second scene died on the
shape mismatch and the combination was simply unavailable.

One choke point, _match_template_resolution, brings the carried material back
before it is used, applied at the three places a finished scene crosses into the
next one. Each scene still samples and OUTPUTS at 2x: only what is carried gets
resampled, and only downwards, which is the direction that survives it — those
frames exist to say "continue from here", which a resample preserves far better
than invented detail would.

Identity no-op when the grids already agree, so any run without a resizing op is
bit-identical. Audio has no spatial axes and is never touched. A stale
noise_mask is dropped rather than reapplied at the wrong scale, and a resample
that throws costs continuity with a console line, not the run.

No grid guard on the chain blend: second_pass and second_pass_op are run-level
settings applied to every scene, so a chain cannot hold two resolutions — every
scene is upscaled or none is. Both tooltips said this combination dropped
multi-scene; they now say how it works.

Also: About reads "FunPack 3" with the codename on its own line, rather than
attaching the major to the codename.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 00:05:52 +03:00
digital-garbageandClaude Opus 5 98d48e78e3 fix: cut_opening_frames cuts decoded pixels, not latents (noisy first frame)
The opening frame came out noisy because the cut was made in latent space. The
LTX video VAE is causal: latent frame 0 is the temporal origin and decodes to a
single pixel frame, while every later latent frame was generated as a
CONTINUATION of the frames before it. Slicing the front off the latent promoted
a continuation frame to position 0, and the decoder then applied the
temporal-origin handling that frame was never generated for. H3 already cut
decoded images for unrelated reasons and so never had the bug; LTX now does the
same thing.

The count was wrong too, quietly. A latent cut could only remove whole latent
frames, and the promoted frame changed from covering 1 pixel to covering
`scale`, so dropping k latent frames shortened the clip by k*scale rather than
the (k-1)*scale+1 it actually spanned. The value was also rounded up to a whole
latent frame on the way in. It is now exact: N means N, matching H3.

Each eligible scene records a (start, count) pixel span instead of cutting; the
spans are removed after decode, later ones first so earlier removals cannot
shift their indices. Mid-chain hard-cut scenes keep working — the span is
computed from the scene's position in the chain, which is exact because anchor
scenes append with zero blend overlap. The latent's audio stream loses the same
stretches of TIME, mapped by proportion on its own axis, or sound would run
ahead of picture with no error. The latent's VIDEO stream is deliberately left
whole (cutting it is the bug), so video comes from the IMAGES output — which the
Editor already wires. A run with IMAGES unconnected now skips with a reason
instead of silently doing nothing.

_cut_opening_latent is removed rather than left dead, since its docstring
documented the broken approach as correct.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 23:47:51 +03:00
digital-garbageandClaude Opus 5 e7b624d684 fix: drop guide keyframes on a resized second pass; unify the two ALG switches
Two unrelated fixes.

**Guide keyframes vs a resolution-changing second_pass_op.** Guide keyframes are
recorded as TOKEN indices into pass 1's latent grid, so upscale_2x — which
doubles each spatial dim and thus quadruples the tokens per latent frame —
leaves them addressing the wrong tokens. Since the LTX-2.5 commit core rejects
that outright ("keyframe_idxs holds N tokens, which is not a whole number of
M-token latent frames"), which is how this surfaced; older cores silently
mis-placed the guides instead, which is worse. Pass 2 now drops them and says
so in the scene report, exactly as segmented detailing already does for its
crop — so detailing's stripper becomes public rather than being duplicated. Only
pass 2 is affected; pass 1 ran at the grid the guides were recorded against and
keeps every one. The pin loss and the guide loss now share one predicate
(_latent_spatial_changed) so they cannot drift apart, and an unreadable shape
answers "no change" so a probe failure never costs a guide.

**One ALG control instead of two.** The Distilled Flow panel had its own
alg_enabled while the chain sampler's alg_anchor did the same guidance on any
sampler and already drove the Distilled Flow one when set — two switches for one
behaviour, with precedence depending on which you had touched. The Editor now
shows only alg_anchor. The node input stays for hand-built graphs; what moved is
the Editor's control. A project still carrying the old switch is migrated once,
strength and threshold included, and told so, rather than left running ALG with
nothing on screen to turn it off.

The migration is deferred out of the render pass and guarded by a module-level
set of project ids: every store write re-renders the pane synchronously, so
migrating inline recursed until the stack blew (caught in the browser, not by
the suite).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 23:39:47 +03:00
digital-garbageandClaude Opus 5 03158b4edf fix: two LTX-2.5 assumptions that would have failed silently
LTX 2.5 reuses LTXAVModel/LTXBaseModel behind config flags, so the samplers,
the identity-transfer wrappers and the guide path all bind to it unchanged.
Two places assumed 2.3 specifics, and both would have gone wrong quietly.

The AV channel split was a hardcoded width table. From 2.5 on comfy reads the
video/audio projection widths off the checkpoint rather than assuming them, so
a checkpoint can ship a pair the table has never seen — and an unrecognised
width made ltxav_video_channels return the FULL width, which silently steers
the audio text context along with the video one. The only symptom would have
been degraded audio. The split is now measured off the live model when one is
on hand; the table stays as the fallback.

Decode-time noise only ever reached VideoVAE.decode. 2.5's diffusion decoder
takes no timestep and seeds itself, but it is an nn.Module, so stamping the
attributes onto it succeeded and was then ignored — a knob that reads as live
and does nothing. It is now capability-tested against the real contract
(hasattr decode_timestep, not a class name) and says so when it cannot apply.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 22:36:38 +03:00
digital-garbageandClaude Opus 5 48ff7f0f48 feat: schedules for every sampler, a usable frames field, ALG on any sampler
Three things that were each locked to one implementation detail:

- steps + schedule were a KSampler-branch feature, though every sampler here
  walks a sigma list handed in from outside. They are now pass-level, so
  Distilled Flow and Hybrid Euler 2S can run a named schedule (and the second
  pass can be computed rather than typed) in both frontends and on the node.
- the project's Frames field snapped to the model's grid on every family. On
  H3 that is required, but its arrows moved by 1 and the snap put the value
  straight back; on LTX the builder rounds up by itself, so the snap only
  fought the user. H3 now steps a whole 17 frames per arrow, LTX keeps what
  you type and walks 8k+1 with its arrows.
- ALG lived inside the Distilled Flow step loop, so it was unreachable with a
  stock KSampler. Its blurred/sharp swap is decided by the step's sigma, and
  sigma is an argument of every model call, so a denoiser proxy drives it from
  outside any sampler. New alg_anchor toggle on the Chain Sampler drives the
  in-loop version too, so there is one control wherever you are.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 03:53:11 +03:00