Its step wrapper held its own ModelPatcher, a cycle only a full gc frees;
that gc clears ComfyUI's weak link to the parent copy first, leaving it
tracking a dead model ("memory leak with model MiniMaxH3").
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_get_latent_shapes only looked under a CFGGuider's conds; wrappers hold a
ModelPatcher, so on packed AV latents every video-only wrapper passed through
unchanged. Also: late-branch and STAS say when they applied nothing, and a
learned value is only rated when the feature actually applied.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
STAS (arXiv 2603.17825) sets massive-activation channels on frame 0 and
frame edges to alpha x peak at one block over the first 40% of steps.
Rating-learned dials now share rated_dial.py.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Skip guidance at CFG 1: the weak copy reuses blocks before the branch and
skips the branch block, so only the tail runs twice. Picture only; capture
hooks ignore the weak pass; compiler off while installed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shot memory reuses a liked gen's coarse starting noise (layout) with fresh
fine noise; reuse-vs-fresh, which shot and how strongly are learned.
Decisiveness is Temporal Score Rescaling (arXiv 2510.01184) on the picture
rows, k learned per key or set by hand.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It replaces every block's forward, so the model compiler must be off for that
call, as it already is for block repeat and REINS injection. Never seen before
because until d4d4e29 shadow negative never ran.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
H3 blocks add their residual into the input in place, so the kept single-pass
tensor was overwritten by the next pass and audio was restored from the
repeated stream. Keep a copy instead (block repeat and span loop).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It read the prompt length from transformer_options['c_crossattn'], which
ComfyUI never sets, so every block ran the stock forward. A model wrapper now
records it per call. Per-token mod rows (any pinned frame) no longer disable
it, and the step window reads the real schedule.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Studio gains an enhanced_prompt output; the link wires to it. Enhancer off or failed sends prompt + postfix unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ComfyUI tokenizers drop an unknown system_prompt kwarg, and Gemma skips its chat template by default. Instructions now go in the user turn of the model's own template, which also places the image.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- region lock: layout patch matched the old PackedLayout signature and crashed every H3 run; interior pins now use upstream's native any-frame placement
- REINS/Q-steer/AV decouple/probes: masks cover the target video/audio rows only, not pins, refs or vision pads
- video detail: works with the PDD FinalLayer signature; now in Engine Settings
- Q-steer: steers queries before RoPE, not after (old banks are not reused)
- ALG anchor: blurs the frame-0 pin on H3
- temporal style: hidden on H3
- shadow negative: main-window chip names what it switches off without compose
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Own tab with its full sampling settings (temperature, top-p, top-k, min-p,
repetition/presence penalty, seed, greedy) and a last-run before/after view.
Studio's source_image now reaches the enhancer on the per-scene path too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sel.onchange only passed the filename, missing the "detail_upsampler" key
setSamplerInputNow(name, value) expects -- so it wrote sampler_inputs["<the
filename>"] = undefined instead of sampler_inputs.detail_upsampler, and the
next render recomputed the visible value from the untouched (still unset)
field and fell back to "auto". Matches the working sibling call one line
below (identity_projector).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
These were force-disabled for a gate bug, not a measured failure: they
all rode _make_steer_ramp's last-half window, which measured 0-of-4 and
0-of-12 real step coverage on H3's shift-based schedules because it read
sigma as schedule position, which is false there. That gate was already
rewritten to recover the true position from the schedule's own base grid
and is wired into all three call sites -- their correction steps are
also self-normalizing (a fraction of the live tensor/embedding's own
norm, not an LTXAV-tuned constant), and trajectory_guidance's buckets
were built for H3's schedules from the start. Re-enabled to actually
test them now that the thing that broke them is fixed.
embed_guidance/taste_nearest_prompt stay off: different value function,
and phrase emphasis's own manipulation check directly measured
near-invisible pushes from it at H3's calibration -- an actual negative
result, not a stale gate.
Unvalidated on real hardware -- this removes a stale reason for
disabling them, not a claim that any of the three help.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The previous fix (67b1324) put mediaUpload straight into the mediabrowser
zone's fingerprint, so every XHR progress tick did a full rebuild of the
media grid, thumbnails, and project list -- and closed any open <select>
in there (e.g. "Sort by"), the same class of bug just fixed in Engine
settings. Only the file boundary (which file, 1-of-how-many) is in the
fingerprint now; byte-level progress goes through a quiet
updateMediaUploadProgress + a funpack-media-upload-progress event that
mediabrowser.js uses to patch the bar/percent in place, mirroring the
existing updateGenProgress/funpack-gen-progress pattern for the player.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A <select> was excluded from the field-editing protection that shields
text inputs from autosave/notify-driven rebuilds. Any unrelated store
notify while the dropdown was open (autosave tick, a generation poll,
another zone's change) tore down and rebuilt the pane underneath it,
which closes a native dropdown immediately. Selects are now protected
the same way while focused; their own change event still applies right
away so dependent controls don't wait for blur.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
mediaUpload changes on every XHR tick but wasn't part of the mediabrowser
zone's ViewBus fingerprint, so real ticks hashed identically to the last
paint and were skipped -- the bar only ever appeared to update via some
unrelated repaint (e.g. clicking a thumbnail changes mediaPreviewId, which
IS tracked).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Uploads now go through XHR instead of fetch so byte-level progress is
visible; the drop zone shows a bar, percent, and filename instead of
looking stale while the backend receives the file.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The media bin's grid always requested the FULL original file for a
thumbnail (an <img>/video-frame decode of the whole thing, only
cropped down visually via CSS/canvas afterward). A 4K photo or a
multi-MB clip got fully downloaded and decoded just to show a 96px
square, every render.
Added GET /api/media/{mid}/thumb: generates a small JPEG on first
request (Pillow resize for images, one ffmpeg frame-grab for video),
caches it under media/thumbnails/, and serves that instead. Deleting
a media item removes its cached thumbnail too. mediabrowser.js now
loads from this endpoint for both image and video kinds -- the same
canvas-drawing path as before, just fed a file that's already small
instead of the original. Measured live: a 1.57MB test clip's cached
thumbnail is 1.6KB.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
generate()/generateMontage()/generateSelected() awaited a full project
save (and a separate models save) before doing anything visible --
both are plain network round-trips that can retry for tens of seconds
on a flaky connection (_retryOnTunnel), and nothing set a gen state
until they finished. Clicking Generate on bad internet looked exactly
like the app had frozen: no disabled button, no message, no feedback,
for however long those saves took.
The wait existed because /api/projects/{pid}/generate read the
project BY ID from disk (_project_or_404) -- if the disk copy was
stale, Generate would silently build a graph from old data. Fixed at
the actual source instead of papering over the wait: the endpoint now
also accepts the current project inline in the request body (the same
shape /api/projects/{pid}'s own PUT already takes) and persists
exactly that payload before generating from it, atomically, in one
step. The client sends its live in-memory snapshot instead of relying
on whatever the last autosave wrote. body["project"] stays optional
so any other caller keeps the old disk-read behavior.
Adversarial review (two rounds) found this reopened a narrower race:
the generate handler's own existing tail already saved the project a
SECOND time afterward (to record the queued prompt's hash), so an
ambient autosave landing between this request's two internal writes
would get silently clobbered by the second one. Closed by suspending
the client's ambient autosave (suspendSave/resumeSave, an existing
primitive) for the exact span of the generate request, and by waiting
out any autosave that was already in flight before generate started.
Also moved _markGenInFlight to fire right before the actual request
instead of before that wait, so a scene deleted during a brief
already-in-flight wait isn't ghosted for a request that hadn't
actually been sent yet.
Verified live end-to-end: an edit made only in memory (never
autosaved) reached disk through the generate request itself and
survived a concurrent pending edit through the suspend/resume window,
confirmed via direct reads against the running dev server.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Image thumbnails appended the raw <img> (full-resolution decoded
bitmap held in memory for the card's lifetime, just to be shown at
56-96px via CSS crop). Video thumbnails already snapshotted to a
canvas but sized it at the source's native resolution. Neither ever
downscaled anything -- a bin of real photos/4K clips kept every one
of them fully decoded in memory at once.
Both paths now draw down to a capped 320px long edge before caching
(_thumbScale), same visual result, far smaller resident bitmaps. Also
drops the img.draggable=false workaround the old <img>-based image
thumb needed to stop the browser's native image drag from hijacking
card drag-and-drop -- a <canvas> was never draggable to begin with.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
_select_best_seed called value_fn.forward()/compress() directly on a
candidate's captured prediction with no device handling -- the value
function loads CPU-only (map_location='cpu'), but the candidate tensor
lives on whatever device the model ran on (cuda in production). Every
candidate failed to score on every real GPU generation since this
feature shipped; _select_best_seed always fell back to the unchanged
seed, silently a no-op the entire time despite passing all tests
(the suite is CPU-only, so a mismatch never had two devices to hit).
Every other value_function.py call site (gradient/ascend/search) moves
its input onto next(self.parameters()).device first -- this was the
one path that skipped that. Mirrored it: compress on the candidate's
own device (cheap reduction), then move the small compressed vector
onto the value function's device before scoring.
Added a regression test using a real second torch device (mps on this
box, cuda in CI/production) to reproduce the exact cross-device
failure, and fixed three pre-existing value_fn test doubles that were
missing parameters() and had silently started hitting this same
crash branch once the fix started calling it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Clear references only ever sat above the grid, so clearing refs on a
large bin meant scrolling all the way back to the top first. Made
.media-bin-actions sticky within the bin's scroll container, same
pattern already used for the (currently unused) bin-tabs-sticky class.
z-index bumped to 4 to clear each card's kind badge (z-index 2), which
otherwise ties and wins on DOM order, painting over the sticky bar.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>