Commit Graph
289 Commits
Author SHA1 Message Date
digital-garbageandClaude Opus 5 7537ec0bef maint: remove the mid-scene guide
Not used on H3, not used on LTX any more. Two widgets, the append method, the
Editor's continuity controls for it, and the auto-enable that turned it on for
every multi-scene carry chain.

JoyAI memory and carried i2v guides keep the guide-attention machinery they
share with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:32:20 +03:00
digital-garbageandClaude Opus 5 aebc286042 maint: remove the H3 render gains
Six widgets (three write gains, prompt loudness, taste push, learned/manual
mode) and the whole rating loop behind them. Never proved out on the rental:
picture gain past +-0.1 adds distortion and latent noise, the rest changed
nothing legible, and the audio gain was never worth testing.

The final-layer picture detail SURVIVES and now reads its own widget — it was
the only one of the set that showed a real effect. Relabelled experimental.

Two things fall out with them. The refinement key no longer holds any sampler
value, so key scoping has nothing left to scope and goes too. And the card's
ownership table now reads dependsVals as well as dependsValue: the Studio rows
use the plural form, so absolute_strength was printing under steer_mode
"relative", where it does nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:30:19 +03:00
digital-garbageandClaude Opus 5 8374838e46 maint: remove the reference-weight dial (h3_prompt_time)
Seven rental runs across its whole range: below 0.5 the picture breaks up,
above 0.5 it reproduces the reference outright, and nothing in between is
worth having. It never did the job it was built for either.

Kept: the final-layer video scale it shipped alongside, which does work.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:23:57 +03:00
digital-garbageandClaude Opus 5 511713593c maint: remove the plateau step-cache
Measured on the rental and it never worked as intended. Two widgets, the
wrapper, the context-windows exclusion it needed, and its two tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:21:58 +03:00
digital-garbageandClaude Opus 5 cb5910568e feat(h3): reference weight applies only after the shot has been composed
Measured: 0.4 loose and inventive, 0.6-0.75 several versions of the shot
attempted at once with the strongest winning, 0.75 and up simply the
reference. No usable band anywhere in the range.

The timestep is how the model knows what stage everything is at, so a prompt
that disagrees with the picture about the stage costs it the ability to settle
on one reading — which is what "multiple variants in one video" is. Structure
is chosen early, so the edit now waits until it has been: ramped in through
_make_steer_ramp, the same late-step gate the rating-driven wrappers share,
interpolating from the prompt's own row so a closed gate is byte-identical to
not being installed.

Third hypothesis for this dial. If it still just reproduces the reference, the
feature does not earn its place and comes out.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 00:55:24 +03:00
digital-garbageandClaude Opus 5 217882e695 docs(h3): "Prompt is settled" is a reference-weight dial — relabel it as one
Measured, after the label fix: at 1.0 it still reproduces the reference
almost exactly, so the <Picture N> label was never the cause. In H3
"finished" is what marks a row as reference material — content that was given
and should be reproduced. Marking the prompt rows that way moves them into
that category, and the reference takes over the frame.

Measured range: 1.0 copies the reference; ~0.4 follows the prompt but invents
things in neither; below 0.3 the picture breaks up. It does not improve
prompt adherence, which is what it was built for.

The widget NAME stays h3_prompt_time — it is in saved projects and saved
workflows, and renaming it would drop the setting from both.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 00:49:15 +03:00
digital-garbageandClaude Opus 5 450be1c232 fix(h3): picture detail ran backwards — H3's final-layer scale is negative
Measured on a rental: 0.8 gave more contrast and 1.2 less, and 1.15 was
nearly inert.

The layer computes norm(x) * (1 + scale) + shift, and the first build
multiplied `scale` itself. H3's scale is negative, so raising the dial shrank
(1 + scale) and the control inverted. Scaling the whole (1 + scale) term
instead is monotone in magnitude whichever sign a checkpoint carries, so
"above 1.0 is more" holds by construction rather than by luck. shift is still
left alone — it is the bias.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 00:38:46 +03:00
digital-garbageandClaude Opus 5 1652b7197a fix(h3): "Prompt is settled" was settling the reference label, not the prompt
Measured on a rental at 0.9-1.0: it reproduced the reference image almost
untouched in the frame, overriding a prompt that said in words the reference
was not where the scene begins.

An r2v conditioning is laid out `<Picture n>: ` label / vision block / prompt,
and the LABEL is text — the vision block is not. The first version re-timed by
modality tag, so it hit the label too. That label already reads as "compose
like this"; made maximally authoritative, the model composed like it.

The prompt is the LAST text run, and nothing outside the text span carries the
text tag, so that identifies it with no help from the conditioning. Row ranges
live only in mod_segments, which AdalnProj never sees — so this moves onto
ComfyUI's own per-block replace hook, which is handed them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 00:36:50 +03:00
digital-garbageandClaude Opus 5 a5f7679321 fix(h3): the prompt dial no longer costs you the rating loop
h3_prompt_time is not one of the learned strengths, but it was gated behind
h3_gain_mode=manual like the ones that are — so using it meant switching
rating-learned gains off. It now reads its widget in both modes, and shows in
both.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 00:12:55 +03:00
digital-garbageandClaude Opus 5 edcedd9062 feat(h3): two more punctures — prompt timing, and picture detail that spares the audio
h3_prompt_time: the prompt is told how finished it is independently of the
picture, so the model leans on it from the first step instead of treating it
as unreliable while the picture is noise. One extra row through each block's
AdaLN projection, dropped before the result returns. Manual dial only — its
off value sits at the end of its range, not the middle, so the rating loop
cannot explore around it safely.

h3_video_detail: crisper or softer picture with the audio bit-for-bit
unchanged. The final layer is past the last attention pass, so unlike every
other picture control it has no path to the soundtrack.

apply_adaln_gains -> apply_adaln_edits; both block edits share one wrapper.
video_detail joins the rating-learned gains.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 00:05:42 +03:00
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 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 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 985cf8048d feat(h3): the anchor is its own cache chunk, so it can be released
Every chunk restarting from the input image on the rental. The prompt and the
anchor shared one cache chunk, so pinning the prompt pinned the anchor with it —
for the whole clip, in a context of three visible blocks. In a dense render the
anchor is one pin among hundreds of frames' worth of rows; there it was a third
of everything the model could see, and the model did what it was trained to do
with a conditioning row: compose from it.

They are now two chunks. The prompt is 0 and always pinned — it is every moment
of the clip. The conditioning is 1, so `sink` decides how long it stays: 1
releases the anchor after the opening, 2 keeps it (today's behaviour), 3 also
pins the opening shot. Media chunks moved to i + 2, and the conditioning slot is
reserved even on a t2v run so `sink` counts the same either way.

The prefill is two forwards, and the conditioning pass reads the text already in
the cache — so the anchor is still represented WITH the prompt rather than in
isolation.

Note the widget's meaning shifted by one: sink 2 was prompt+anchor+opening shot
and is now prompt+anchor.

Tests: 1806 python, 68 JS. The upstream check now prefills a real keyframe and
confirms sink 1 releases it while keeping the prompt.
2026-08-26 22:49:42 +03:00
digital-garbage 3bfe8b3254 fix(h3): the causal lane installs itself, and both ends now say what happened
The refusal asserted a cause it had never checked — "switch on chunk_causal" —
which was wrong, and sent you looking at a switch that was already on.

Three changes, none of them a guess:

  - build_session no longer refuses a stock H3. Re-classing adds no parameter,
    renames no key and costs nothing, and with no cache passed the model is
    bit-identical to stock — so a mode that is already switched ON has no
    reason to refuse itself over a switch on another node. It does the work.
  - when it does that, it says so, naming the loader as the end that did not
    take. That is the line that tells us whether `chunk_causal` is off or its
    value never reaches the node.
  - the loader PRINTS its chunk-causal outcome. It only ever went into the
    `status` string, which the Editor's fixed graph shows nowhere, so a
    "REQUESTED BUT NOT APPLIED" was invisible and the sampler downstream had
    nothing to go on but a guess.

If make_causal genuinely cannot run, the message now names the diffusion
model's actual class instead of asserting what the user did.

Tests: 1804 python (+3), 68 JS.
2026-08-26 19:42:31 +03:00
digital-garbage 7981adc20f fix(h3): stop pointing at the raven_lora widget that no longer exists
The chunk-causal switch replaced a `raven_lora` combo on the diffusion loader
with a boolean plus an ordinary LoRA, but the Chain Sampler tooltip and the
Engine Settings detail still told the user to go and set the old widget. Both
now name what is actually there. A test refuses the string anywhere a user can
read it.

Tests: 1801 python (+1), 68 JS.
2026-08-26 19:34:08 +03:00
digital-garbage 4661fe6ad5 feat(h3): the causal lane runs on our own model, with no third-party pack
The two entry points the rollout was waiting on — prefill_text and forward_chunk
— are written, and with them the whole lane is ours. raven_causal.py is gone:
its pure parts (step rules, the audio sigma remap, the rollout loop) moved into
h3_causal.py, and its bridge to ComfyUI-MiniMax-H3-RAVEN-Streaming is deleted
along with the probe that hunted for that package in custom_nodes. Nothing has
to be installed for the mode to exist.

How a chunk is cut: ONE full-clip PackedLayout is built by ComfyUI's own
extra_conds, and every chunk is a SELECTION of its rows. So a chunk's RoPE
angles, modality tags and timestep classes are the ones a dense forward would
have given those same rows, and the keyframe pins and reference blocks keep the
rows upstream packed for them — which is what makes i2v and r2v work here
rather than be refused. Those rows are the prefix: cached once as chunk 0, so
media chunk i is cache chunk i + 1 and a sink of 2 pins the prompt plus the
opening shot.

A chunk is committed CLEAN — one extra forward at sigma 0 after its last step.
Caching the last denoising step's K/V would hand every later chunk a context
that still carries that step's noise.

Two failures that used to be a crash fifty blocks deep are now refusals by
name: a clip whose soundtrack does not cover its picture, and a clip too short
to have anything for a cache to remember.

Tests: 1800 python (+1 net; the RAVEN bridge's tests are gone, the plan,
session and real-model checks are new), 68 JS. The new upstream check drives
the REAL DiT at toy width through both lanes and confirms the safety property
holds: with no cache passed, the causal model is bit-identical to stock H3.

Not yet run on the rental.
2026-08-26 19:26:36 +03:00
digital-garbage e0044425ca feat(loaders): raven_lora on our own diffusion loader
FunPack owns its loading pipeline, so the causal lane must not need a
third-party loader node in the graph. `raven_lora` on FunPack Diffusion Model
Loader turns an ordinary H3 checkpoint into the chunk-causal DiT with the
adapter attached. Same checkpoint either way — it is a LoRA, there is no
separate RAVEN model file, and every message now says so.

The weight load itself is DELEGATED to the RAVEN package rather than
reimplemented, and not for convenience: the adapter is an FP32 activation
residual registered on the base Linear leaves and must be attached before the
ModelPatcher is built. ModelPatcher.model_size() memoises, so an adapter
attached afterwards is invisible to Comfy's memory ledger and never moved by
partial CPU offload — the model would report itself smaller than it is and the
residual would end up on the wrong device.

Selecting a LoRA when the causal class is unavailable RAISES with the fix in
the message, rather than quietly loading a plain model: a model without the
adapter would leave the causal lane reading an attention pattern nothing was
trained for, which reads as a quality problem with no visible cause.

Strength is fixed at 1.0 — the adapter is what teaches the chunked attention
pattern, so "partly on" is not a useful state.

Tests: 1730 passed (+12).
2026-08-26 18:37:37 +03:00
digital-garbage 20bd542af2 feat(h3): the causal chunk lane is wired to the Chain Sampler
A mode on the existing sampler, not a new node. h3_causal_chunks generates the
clip in time chunks that each attend to a KV cache of the ones before them, so
a long clip stays one continuous shot with real memory instead of separate
scenes stitched together. Sink and window are exposed as what they actually
are: chunks pinned from the start, and recent chunks still remembered.

Two defects found while auditing the bridge I had sketched earlier (which a
blanket `git add -A` had swept into an unrelated commit — it was dead code, but
it should not have gone in under that message):

  - it read request.video_channels / audio_channels, which do not exist on
    RAVEN's LatentRequest. First real call would have been an AttributeError.
  - it handed BOTH streams the same sigma. H3 denoises audio on its own shifted
    grid (3 against video's 12), so that is exactly the error h3_audio_clock
    exists to correct, and it bites hardest on the few-step schedules this lane
    is built for. Audio now goes through the same remap, transcribed from
    comfy.ldm.minimax.model.time_shift_sigma and verified equal to the live
    function across the range.

The lane REPLACES the sampler rather than wrapping it, so every reason it
cannot run falls through loudly: not H3, pack not installed, stock
bidirectional model. A rollout that fails mid-way raises rather than quietly
falling back to ordinary sampling, which would return a clip under a mode the
user believes ran. The run states that the wired sampler and CFG are unused on
this path, and that there is no per-chunk redo.

Editor: Settings > Engine > Sampler > Experimental, hidden entirely off H3.

Tests: 1714 passed (+18). Never run on hardware.
2026-08-26 18:06:36 +03:00
digital-garbage 0fced8cb63 fix(h3): the render-gain tooltip still said four, there are five now 2026-08-25 22:03:41 +03:00
digital-garbage 30df1ebcfd fix(h3): JoyAI-Echo is a LoRA technique, not just a frame-index conflict
The prior wording made the frame-index/anchor-eviction issue read as the
reason JoyAI is blocked on H3. It isn't: no JoyAI-Echo LoRA exists for H3, so
it's inaccessible by design regardless of interior pins. The frame-index issue
is real but secondary — it's what would also go wrong if someone forced it on.
2026-08-25 22:00:52 +03:00
digital-garbage 54fa8e4b43 feat(h3): region-locked anchors, and the taste direction lands after the refiner
Region lock: a keyframe pin can cover part of a frame. Transparent areas of an
i2v anchor are dropped from the packed sequence entirely — not blanked, not
noised, absent — so the model invents them. Row deletion re-derives the layout
from upstream's own output; two patches share one keep-mask so they cannot
disagree. Surfaced through the anchor's alpha, which needs no new wire and works
in the Editor. Excluded pixels are filled with the kept area's mean before the
VAE so no hard edge bleeds in. EXPERIMENTAL: fl2va saw whole condition frames.

Taste bias: the liked direction Studio already learns is now also added AFTER
H3's token refiner, where it lands as sent instead of being mixed across tokens
and normalized away. Relative to the span's own row norm, so one strength means
the same thing on every prompt. How far to push is a fifth learned gain,
centred on 0 and signed; h3_taste_bias is the manual override. Needs 3 liked
runs.

Gain state generalized to per-key centres, bounds and exploration width.

Tests: 1608 passed (+46). Untested on a rental.
2026-08-25 21:48:28 +03:00
digital-garbage ffe2a49a9e feat(h3): render gains are learned from ratings, manual is the opt-in
The four H3 render strengths shipped as hand-set dials. They should not
have: four scalars is a SMALLER search than the sigma profile, which
already converges on ratings alone, so typing them is the user doing work
the loop can do.

Same ES update as the sigma profile, with one difference — that profile is
centred on 0, so its applied value IS its perturbation; these are centred
on 1.0, so the perturbation is (applied - value) and that is what the
reward is credited to. Exploration narrows on a like, widens otherwise,
and is seeded from the run seed so a repeat repeats.

Learned values reach the sampler through the conditioning meta, the bridge
h3 token weighting already uses: Studio owns the key, the sampler owns the
application. h3_gain_mode defaults to "learned" and ignores the widgets;
"manual" uses them as typed and still works with no Refiner in the graph.

Learning runs on every rating regardless of the toggle, the same rule
value_guidance follows.

Also fixes four note_on_change calls added earlier this session that were
missing the required tag argument — they would have raised on the non-H3
and unreadable-tags paths.
2026-08-25 18:48:50 +03:00
digital-garbage 0e50d708c4 feat(h3): edit the token refiner's output, and h3_prompt_scale
Qwen text reaches the DiT through condition_proj + a 2-block token
refiner ending in an RMSNorm. Everything steered today happens BEFORE
that, so the refiner mixes the edit across tokens and its final norm
renormalizes the magnitude away — what lands is not what was learned.

TokenRefinerEdit patches the refiner's output instead: a scale and/or a
bias over a row range, landing unchanged in the space the 50 blocks read.
project_into_refiner_space maps a conditioning-space direction across with
condition_proj's weight only (a direction is a difference of points, so
the bias would move the origin).

Ships h3_prompt_scale: how loudly the prompt is read through attention,
distinct from h3_gain_prompt (how much each block writes back into those
rows). Confined to the prompt rows via minimax_token_tags, so a wired
reference's vision block is left alone. Free, 1.0 = model not cloned.

The bias path is the mechanism for a learned direction and is not wired to
one yet: a single [hidden] vector added to every prompt row is
prompt-length-independent, which is the shape a learned direction needs
here since Qwen does not pad.
2026-08-25 18:39:18 +03:00
digital-garbage b696c92c4a feat(h3): per-modality AdaLN write gain on every DiT block
Each H3 block carries AdalnProj(t_dim, hidden, expand=6, modalities=3):
shift/scale/gate for attention and MLP, in three copies indexed
t_row*3 + tag (video 0, text 1, audio 2). The gate scales what a block
writes back into a row range, so scaling one modality's gate is per-block,
per-stream write strength — the only mechanism in this architecture that
separates prompt, picture and soundtrack at the point of writing.

Three sampler widgets, 1.0 = untouched and the model is not cloned. Free:
one vector multiply per block, no extra model calls.

Sampler-side and self-contained — reads no key, rating or learned
direction, so conditioning steering being off does not disable it and the
Refiner need not be wired at all.

Attached with add_object_patch, restored by ComfyUI on unpatch; nothing
survives the run. Pins and reference images carry the VIDEO tag, so the
video gain moves them too — stated on the console and in the tooltip.
2026-08-25 18:31:48 +03:00
digital-garbage e966b0ab19 fix(sampler): Distilled Flow's s_noise is rectified-flow ancestral now
It stepped the full distance to sigma_next and then added
sqrt(sigma^2 - sigma_next^2) of noise on top. That is the VP variance
formula, and adding noise without shortening the step leaves the latent
noisier at sigma_next than the schedule defines — so s_noise never behaved
like euler_ancestral on H3 or LTXAV at any value.

Lands short (sigma_down) and renoises with flow matching's alpha rescaling:
the arithmetic _sample_const_rf_full already carried, and comfy's
sample_euler_ancestral_RF. At s_noise=1.0 it IS euler_ancestral.

s_noise now means eta (fraction of the step taken stochastically); range
raised to 1.0 so euler_ancestral is expressible. A value carried over from
before does NOT mean what it did — the tooltip says so. Non-CONST models
keep the eps path unchanged. Audio still never gets ancestral noise.
2026-08-25 17:53:45 +03:00
digital-garbage 1bcdd1ce1c fix(sampler): final_correction_steps counts steps that can be corrected
The Heun corrector evaluates the model at sigma_next, and the terminal step
lands on sigma 0 — degenerate, and it returns early before the corrector is
reached. The window was measured back from the end of the schedule, so it
started on that step: final_correction_steps=1, the default, performed zero
corrections on any schedule ending at 0.

Counted over correctable steps instead, so N means N.

Default moves 1 -> 0: fixing the arithmetic alone would have added a model
call to every existing run (~14% on a 7-step schedule). 0 is what every run
has actually been doing. quality_sharpness shares the window by design.
2026-08-25 17:45:13 +03:00
digital-garbage d995132c92 feat(h3): a keyframe pin can sit at any frame, not just the first or last
Upstream PackedLayout computes a pin's time coordinate in two branches and
raises for anything between them. They are the two endpoints of one line:
the packed sequence advances FRAME_RESCALE per PIXEL frame, so
cond_t = text_len + FRAME_RESCALE * pixel_index reproduces both exactly at
every clip length, including the irregular (1,4,4,4,4) latent grouping.

Upstream still builds the layout; this rewrites the time column of the
condition rows it produced. Endpoint-only runs call straight through and are
bit-identical. The rule is re-derived from upstream's own constants before
patching, so a changed frame grid disables the feature instead of misplacing
pins.

Unlocks mid-clip guides on the Chain Sampler, which were refused outright.
EXPERIMENTAL: fl2va trained on first/last pins only, so the coordinate is
representable without being learned. Costs no extra model call.
2026-08-25 16:46:21 +03:00
digital-garbageandClaude Opus 5 8e3c707c81 fix(sampler): a wired reference conditioning is not a second scene
The Chain Sampler reads one conditioning entry per SCENE
(scene_conditionings = positive[:max_scenes]). When Studio stopped discarding
the entries past the first of a wired CONDITIONING — the fix for a reference
surviving while the prompt did not — those entries reached the sampler
untagged, and the r2v reference block was counted as a scene of its own. The
run sampled the shot twice, which from outside is "the model ran a second pass
for no reason".

Studio tags every pass-through entry as a companion; the sampler excludes
companions when counting scenes and hands them to every scene instead, so they
still reach the model. Both halves of the original bug stay fixed: nothing is
dropped, and nothing is mistaken for a scene.

Also fixes the liked-conditioning blend, which was the last payload path still
doing a raw lerp: _v2_shape_compatible ignores sequence length by design, so a
direction learned at 586 positions met a 494-position prompt, threw, and took
the whole pull toward what the user rated well with it. Routed through
_v2_payload_like like every other payload.

Adds stage timers for the nine learning steps the first pass did not cover —
55% of a 26.9s run was accounted for, and the rest was unnamed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 14:06:52 +03:00
digital-garbage 338c6aadc2 fix(h3): make the phrase emphasis mean something
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.
2026-08-23 08:44:48 +03:00
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-garbageandClaude Opus 5 ce9e679f0e 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>
2026-08-23 04:50:23 +03:00
digital-garbageandClaude Opus 5 1af51e034c feat(samplers): report the pinned-memory budget
Page-locked pages cannot be swapped or reclaimed, so a budget near
total RAM is what wedges a Linux host rather than killing the process.
Warn when ComfyUI's budget exceeds 80% of RAM.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 04:06:59 +03:00
digital-garbageandClaude Opus 5 69fd454a0b feat(samplers): report memory around the decode
RSS, host RAM, swap, VRAM and what ComfyUI is holding (with how much
sits on the CPU), before and after the decode — the call that evicts
model weights from VRAM into host RAM.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 03:58:18 +03:00
digital-garbageandClaude Opus 5 9b46288159 feat(samplers): show a decoding phase and its duration
A decode is one uninterruptible call with no progress of its own, so a
slow decode looked identical to a hung one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 03:55:58 +03:00
digital-garbageandClaude Opus 5 33cf628d4b fix(samplers): say what the decode needs before it needs it
Log latent shape, estimated CPU pixel size, free VRAM/RAM, and empty
torch's cache before decoding — a decode that kills the process leaves
no traceback. Sharpness proxy releases its retained prediction.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 03:48:54 +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 13bcdb24f3 fix(sampler): H3 audit — context windows and ALG guide blur off and hidden
Both are structurally inert on H3; context windowing also mis-reported the
cause as an old ComfyUI. alg_anchor deliberately kept: a continuation scene
carries real latent frames for it to act on.
2026-08-22 22:49:27 +03:00
digital-garbage dacfeeea0e fix(sampler): JoyAI-Echo overwrote the i2v anchor on H3
H3 keys keyframe pins by frame index and takes only first/last, so memory
frame 0 evicted the anchor and the rest were refused. Forced off with a
reason; hidden in Engine Settings. Tooltips now state the LoRA requirement.
2026-08-22 22:43:36 +03:00
digital-garbageandClaude Opus 5 d7267ba7a8 feat: finish the reporting sweep on the feature paths
14 more silent no-ops made audible: conditioning memory blend/repel/rollback,
Bounded Attention, ALG blur, guide image load, identity install, wired pins,
shortcut expansion. Both hook-removal leaks now name the restart.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-22 18:03:57 +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 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