Commit Graph
39 Commits
Author SHA1 Message Date
digital-garbage d80c17bfaa maint: remove the chunk-causal lane
Validated on the rental and it does not earn its place: 3.5 minutes against 1
for the same clip, worse picture, garbage audio. Some of that was mine — no
weight prefetch across the 50 blocks, a host-offloaded K/V cache, and an extra
commit forward per chunk — but fixing those only buys parity on speed, and the
technique's real win is unbounded length, which H3 already covers natively at
the lengths in use here.

Gone: h3_causal.py, the four h3_causal_* sampler widgets and their Engine
Settings rows, `chunk_causal` on the diffusion loader, and five test files.

KEPT, because it is not about this at all: the LoRA key RENAME table. Stripping
a wrapper head leaves `blocks.0...`, comfy's key map has no bare form, and the
file silently applies nothing — 532 keys, zero applied, no error. That was
breaking any PEFT-style adapter named this way, not just the one that found it.
Its tests moved to test_lora_shape_mismatch.py alongside the MATCHED NOTHING
diagnostics.

Two INPUT_TYPES widgets go with this (h3_causal_* on the sampler, chunk_causal
on the loader). A saved workflow carrying them loads fine — both were optional
and are matched by name — but the values are ignored from here.

Tests: 1700 python, 68 JS.
2026-08-26 23:39:32 +03:00
digital-garbage cf6d153f12 fix(lora): the curve-form note leads with its verdict, and prints whole
It was trimmed at "adaLN reads a compact…", which cut every actionable word:
how many dropped, that the rest of the LoRA still applies, and what to do. The
verdict is now the first sentence, and the line asks for its full text — this
only prints when a LoRA is half-landing, which is the one moment the whole
explanation earns its line.

Tests: 1830 python (+1), 68 JS.
2026-08-26 23:29:51 +03:00
digital-garbage 88cc86aef0 fix(h3): the RAVEN LoRA needs its head RENAMED, not stripped — and the lane shows progress
Two things, both from the rental.

THE LORA. Its keys are ComfyUI's module paths exactly, under a different head:

    base_model.model.dit.audio_patch_proj.lora_A.weight
    diffusion_model.audio_patch_proj                      <- what comfy's map holds

Every candidate the loader tried was a STRIP, which left `audio_patch_proj...`
— and comfy's key map has no bare form to land on, so 532 keys matched nothing
and the file did nothing at all. LORA_KEY_RENAMES adds (prefix, replacement)
candidates, scored against the real key map like the strips, so a rename that
lands beats a strip that does not without either being ordered first.

THE PROGRESS. The causal lane replaces comfy's sampler rather than wrapping it,
so nothing ticked the progress bar and nothing answered an interrupt: a long
generation looked exactly like a hung one, and Cancel did nothing until the
whole clip finished. The rollout now reports every model call, and the sampler
maps that onto the budget this scene was allotted — the bar was sized in
scenes x steps and a chunked scene runs that many steps PER CHUNK, so ticking
raw would have overrun it. The phase readout says "scene 1/3 · chunk 7/22", and
the interrupt is checked before every step, not just every chunk.

Tests: 1829 python (+5), 68 JS.
2026-08-26 23:25:09 +03:00
digital-garbage 5f1a40a73d fix(lora): a file that matched nothing says what it looked like, and is not "Active"
The rental found it: the RAVEN LoRA reports MATCHED NOTHING. Every chunk-causal
result so far was base H3 driving a cache it has never been trained for, which
is exactly the failure mode the loader warns about — and the warning was
invisible, in a status string the Editor shows nowhere.

Two fixes so the next one is diagnosable:

  - MATCHED NOTHING now prints BOTH namings, three keys each: what the file has
    and what the model wants. "Matched no weights" is not actionable; the names
    are, because they say whether the file is for another architecture (nothing
    alike) or the same one under different module names (a rename rule away).
    Every entry in LORA_KEY_PREFIXES was found by hand for want of this line.
  - a LoRA that matched nothing no longer logs as Active. Loaded is not applied,
    and that was the same lie the status string used to tell in private.

funpack_log gains `full=True` for the rare message whose PAYLOAD is the detail,
where the first-clause trim removes the only reason to print it. Not for
emphasis — a feature's state and its reason stay one clause.

Also: the H3 checkpoint-mode note no longer asserts a mismatch it never checked.
Nothing in the state dict identifies fl2va from ref2va, so it cannot know which
file is loaded, yet it said "fl2va weights will read it, but were not trained on
it" on EVERY run with references — including on the ref2va and hybrid
checkpoints where nothing is wrong. It now names the conditioning and stops.
Pins-and-references together stays a warning; that one is a real finding.

Tests: 1824 python (+4), 68 JS.
2026-08-26 23:20:31 +03:00
digital-garbage b30ec8edba fix(lora): say on the console what the LoRA actually matched
`keys=384 fmt=stripped base_model.model.dit.` only ever went into the node's
`status` output, and the Editor's fixed graph shows that nowhere. So a LoRA that
matched nothing looked exactly like one that applied — and on the chunk-causal
lane, where the adapter is what the whole mode depends on, there was no way to
tell which had happened.

    [FunPack] LoRA raven_streaming_4nfe.safetensors: Active | keys=384 … at +1.000
    [FunPack] LoRA stack: Inactive | No LoRA is selected

Tests: 1818 python (+1), 68 JS.
2026-08-26 23:15:04 +03:00
digital-garbage 0597603980 feat(log): one line per feature, state then reason
[FunPack] K/V conditioning patch: Inactive | Non-LTX model loaded
    [FunPack] Chunk cache: Active | 22 chunks, 4 steps each, consistency

`feature(tag, name, active, reason)` is the shape, and `skipped` renders
identically — a deliberate skip and an inactive feature are the same fact and
should not have two spellings. `failed` becomes `Name: Failed | <effect>`,
keeping the effect rather than the exception text: "that explains what I am
looking at" is the half worth the line, and an exception message rarely says it.

Everything funpack_log prints is now cut at the first sentence end, so the call
sites keep their reasoning without spending it on every run. SENTENCE ENDS ONLY
— an em-dash introduces the reason as often as the essay, and a renderer that
guesses wrong eats the one part of the line worth reading. A single long
sentence is hard-trimmed instead of left to run.

FUNPACK_LOG=verbose (or set_verbose) prints the full text, exception included.

Converted to the new shape: the chunk cache, region locks, interior pins, the
taste push, the token-refiner edit, AdaLN gains, rating-learned gains, phrase
emphasis, the K/V conditioning patch, the scene split, Bounded Attention,
per-block LoRA weights, LTX enhancements. The rest of the log gets the trim for
free and keeps its own phrasing until converted.

Tests: 1815 python (+9), 68 JS.
2026-08-26 23:10:27 +03:00
digital-garbage 2790a6263d fix(loaders): point at FunPack LoRA Loader, which applies on its own
Every message about loading the chunk-causal adapter named FunPack Apply LoRA
Weights. That is the wrong node: it is the optional stack producer for
prompt-specific trained strengths. FunPack LoRA Loader loads AND applies from
its own file list, and always has — so the instruction sent the user to add a
node they do not need.

Its own description read the same way ("Loads LoRAs from a FunPack LoRA
stack"), which is where the confusion came from. Both it and the docstring now
say the stack is the narrow case, not the way in.

Tests: 1767 passed (+5).
2026-08-26 19:00:58 +03:00
digital-garbage b5594b00a7 feat(loaders): chunk-causal is a switch on our loader, the adapter is just a LoRA
Both halves now go through nodes we already own, so nothing third-party has to
be installed for the feature to exist.

The diffusion loader gains `chunk_causal`, which RE-CLASSES an already-loaded
H3 in place. That is what removes the need for a separate loader entirely: the
alternative is reimplementing ComfyUI's whole diffusion-model load path so the
adapter can be attached before the ModelPatcher exists and its memory ledger
counts it. Re-classing adds no parameter, renames no key and copies nothing —
only which forward runs changes — so the ledger and offload accounting are
untouched and the switch is idempotent.

The adapter is then an ORDINARY LoRA through FunPack Apply LoRA Weights. Our
loader already scores prefix variants against the model's real key map; it just
did not know this one. RAVEN's keys are `base_model.model.dit.<path>`, so
stripping only `base_model.model.` left `dit.` in front of every key and the
whole file matched nothing, silently. One entry in LORA_KEY_PREFIXES fixes it.

A ComfyUI too old for H3, or a non-H3 model, declines with a reason rather than
raising — one optional switch must not turn the loader into a dead node.

Tests: 1751 passed.
2026-08-26 18:55:58 +03:00
digital-garbageandClaude Opus 5 71f41259b3 feat(lora): per-block application works on any model, not just LTX
Per-block scaling is derived from the LoRA's own deltas — which blocks it put
energy into — so it is a property of the adapter, not of the architecture. Two
things made it LTX-only anyway:

The gate required image_model in {ltxv, ltxav} and mode ltx2, so a model
FunPack had not heard of got the global fallback without anything ever reading
its weights. Whether per-block can run is now discovered from the patches:
fewer than two numbered blocks and the existing fallback takes over, as before.

The key pattern only matched transformer_blocks.N. — MiniMax H3 names its
stack blocks.N., so even with the gate open every H3 patch counted as global
and per-block would have been a silent no-op. The pattern now covers blocks,
transformer_blocks, double_blocks, single_blocks, joint_blocks and layers.

The semantic anchors (PAG 14, STG 14/19) were absolute indices measured on
LTX's 28-block DiT and meant nothing on a stack of another depth. They are
positions now; a 28-block model still resolves to exactly 14 and 19, so LTX
behaviour is unchanged, and a deeper stack gets the equivalent blocks.

Declines, loudly, when a model numbers blocks in two separate stacks
(Flux-style double/single): both start at 0, so one scale would land on two
unrelated blocks.

Untested on a real model — local runs cannot load one. 13 new tests, 11 of
which fail against the previous code.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 13:10:49 +03:00
digital-garbageandClaude Opus 5 c22207c1f9 diag(lora): say which file dropped weights, and how much of it
The drop message named three keys and a count with no file attached, and
note_on_change keyed it globally, so in a stack only the first LoRA's shapes
were ever printed. Each file now carries its name into its own log key, and
the count is reported as dropped-of-matched: 51 of 400 is a variant mismatch,
51 of 51 is a file that contributes nothing.

Adds one stack-level line. Every LoRA dropping every weight is not a property
of the LoRAs but of the model they were all measured against, and that is the
reading worth making explicit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 11:42:22 +03:00
digital-garbageandClaude Opus 5 494894ef3b fix(lora): a delta that fits by count but not by shape is not a fitting delta
comfy merges with mm(...).reshape(weight.shape) and adds the result. The
reshape succeeds on any pair with the right element count, so loosening the
drop test to a count comparison let transposed and differently fused deltas
merge in silence. A correct adapter always produces exactly
(weight.shape[0], weight.shape[1:].numel()); anything else fitting by count
corrupts the weight at load and surfaces mid-render as an all-NaN latent.

The two abstentions kept: a locon mid and a padded reshape target are still
left to comfy rather than dropped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 11:35:21 +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-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-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-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 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 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-garbageandClaude Sonnet 4.6 8a0db7f92f Remove FunPackGemmaVision node — DualCLIPLoader already loads vision weights
LTXAVTEModel.load_sd passes the full checkpoint sd to Gemma3_12B.load_state_dict,
which has vision_model and multi_modal_projector as real attributes with matching
key names. Vision weights are already present after DualCLIPLoader runs.

Drop _vision_loaded flag check; detect vision capability by attribute existence.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 19:59:11 +03:00
digital-garbageandClaude Sonnet 4.6 1038c20155 Fix vision weight key detection: handle already-remapped ComfyUI format
Checkpoints converted for ComfyUI use vision_model.* and
multi_modal_projector.* as top-level keys directly, not the HuggingFace
model.vision_tower.* nesting. Accept both formats.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 19:47:07 +03:00
digital-garbageandClaude Sonnet 4.6 242ef82342 Improve vision weight load diagnostics; fix stale log prefix
When no vision keys are found, log the top-level key prefixes actually
present in the checkpoint so the user can see whether the vision tower
was stripped. Also rename all [FunPackGemmaLoader] log prefixes to
[FunPackGemmaVision].

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 19:20:46 +03:00
digital-garbageandClaude Sonnet 4.6 081d322423 Remove redundant FunPackGemmaLoader
FunPackGemmaVision covers the use case without requiring a separate loader.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 19:19:34 +03:00
digital-garbageandClaude Sonnet 4.6 863539d1a9 Add FunPackGemmaVision: inject vision weights into existing CLIP
Companion to DualCLIPLoader: takes the already-built CLIP object (which has
the correct LTXAVTEModel structure) and loads the SigLIP vision tower +
multi-modal projector from the Gemma3-12B-IT checkpoint, setting
_vision_loaded=True. Workflow: DualCLIPLoader → FunPackGemmaVision → Studio.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 19:17:50 +03:00
digital-garbageandClaude Sonnet 4.6 3318a2df76 Add FunPackGemmaLoader, Gemma3 vision prompting, and i2v in-context conditioning
FunPackGemmaLoader: drop-in replacement for Load CLIP Model that additionally
loads the SigLIP vision tower and multi-modal projector from Google's
Gemma3-12B-IT checkpoint into the already-initialized Gemma3_12B module,
enabling reference-image vision prompting without a separate CLIP Vision model.

Vision prompting: _v2_encode_prompt accepts reference_image; when the clip
has _vision_loaded=True, tokenizes with image=reference_image and
skip_template=False so Gemma3 sees the reference frame before generating
conditioning. Cache key includes image fingerprint to avoid stale hits.
source_image from Studio/refine_v2 flows through to _v2_conditioning_source.

K/V injection revamp (Technique 5): identity blocks in i2v mode now use
in-context conditioning instead of lerp injection. Pre-hook prepends reference
hidden-state tokens to vx and extends v_pe with neutral-rotation entries
(cos=1, sin=0) so video tokens self-attend to reference tokens in attn1.
Post-hook crops the reference prefix from the block output. Strength raised
from 0.02 → 1.0 (sigma-gated: active at 0.35–0.80). _extend_v_pe helper
handles 2-D/3-D/4-D PE tensors. Anchor blocks keep the existing lerp path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 18:53:59 +03:00
digital-garbageandClaude Sonnet 4.6 e24459b501 Remove 'concept' LoRA type - it was an undifferentiated alias for action
Removed from LORA_BLOCK_TYPE_PROFILES, LORA_TYPE_BLOCK_ZONES,
LORA_REFINER_TYPE_PROFILES, ACTION_LORA_TYPES, the validation
special-case, and the Studio JS LORA_TYPES dropdown.

normalize_lora_type() keeps the concept->action mapping for silent
backwards compatibility with any existing saved stacks.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 20:01:53 +03:00
digital-garbageandClaude Sonnet 4.6 51a9478dd7 Per-block LoRA: type-zone suppression, semantic anchor handling, quality signal
- Add LORA_TYPE_BLOCK_ZONES: type-aware block zones that suppress bad-fit
  blocks to 0.0 and mildly boost good-zone blocks per LoRA type
- Add SEMANTIC_ANCHOR_BLOCKS {14, 19}: confirmed semantic focal points
  (PAG default=14, STG defaults=14,19) protected from all suppression
- Add _semantic_anchor_quality: uses LoRA energy share in blocks 14+19
  as a quality signal, scaling all block weights 0.92-1.08x accordingly
- Stack priority: weaker LoRA keeps base scale on anchor blocks instead
  of being damped, letting the dominant signal carry semantic content
- Fix range display: status line now shows effective weights (model_weight
  * scale) instead of raw multipliers; adds zeroed= and anchor_q= fields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 19:14:13 +03:00
digital-garbage 78dc9252f6 Release Refiner V2 appearance safety 2026-05-08 19:28:00 +03:00
digital-garbage cf9afb2539 Prepare 2.2.0 refiner release 2026-05-07 20:28:30 +03:00
digital-garbage f722a06526 Add video refiner v2 2026-05-07 20:04:44 +03:00
digital-garbage 8d1bc3cc24 Cache LoRA block analysis 2026-04-30 23:23:02 +03:00
digital-garbage fd9eb835d7 Add smart LoRA block balancing 2026-04-30 23:06:03 +03:00
digital-garbage 0eaeabbbc4 Serialize compact LoRA rows as a list 2026-04-24 15:28:28 +03:00
digital-garbage 556c8799e7 Refresh LoRA dropdowns on UI refresh 2026-04-24 14:21:41 +03:00
digital-garbage eaa69611e8 Fix LoRA weight row restore order 2026-04-24 03:00:58 +03:00
digital-garbage bee4145832 Add hidden per-block LoRA support for LTX 2026-04-23 22:50:32 +03:00
digital-garbage c1d02a2b1f Respect updated LoRA base weights 2026-04-23 17:05:05 +03:00
digital-garbage 63c7fd70b7 Refresh FunPack LoRA options dynamically 2026-04-23 16:57:32 +03:00
aimfordeb 19ffe6612f Expose flexible LoRA inputs to Comfy 2026-04-23 14:56:42 +03:00
aimfordeb 7315fab459 Simplify FunPack LoRA weight workflow 2026-04-23 14:52:03 +03:00
aimfordeb 0f0d726b1f Release FunPack 2.0.0 2026-04-23 13:57:23 +03:00