* Keep per-item LATENT session refs when joining mapped outputs
Ordered phases bridge values between phases as remote session refs.
Joining mapped LATENT outputs ran _join_latent_batches on those refs,
which copied the first ref's fields and collapsed every item to item 0.
The next phase then broadcast item 0's latent to all items, so a second
KSampler fed by a mapped first KSampler always refined the first image.
Only merge LATENT values that are real latent mappings; otherwise keep
the ordered list. Log boundary inputs that are broadcast because they
cannot be split instead of dropping the error silently.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Cap Modal containers at instance_count across parameter-set pools
Modal enforces max_containers per RemoteEngine parameter set. Remote
components without loaders (e.g. SaveImageAdvanced) had an empty
snapshot profile, so they opened a second pool of GPU containers beside
the samplers and doubled the container count past instance_count.
- Stamp the environment's most common loader snapshot profile onto
profile-less Comfy-pool components so they share one container pool.
- Hold one host-side slot per in-flight Modal call per deployment app,
capped at max_containers, so concurrent mapped components share the
configured budget.
- Lower the per-item unsplittable boundary input log to debug.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The Modal Configuration node gains three advanced widgets:
- global_cooldown (default 60s): idle scaledown for every Modal worker.
- reserve_cooldown_count (default 0): how many worker slots use the reserve
cooldown; must not exceed instance_count.
- reserve_cooldown (default 300s): idle scaledown for the reserved slots.
The policy travels on remote payloads and is applied per call with
Cls.with_options(scaledown_window=...), keyed by the worker-pool slot parsed
from the affinity key. Slots below reserve_cooldown_count stay warm longer;
other slots and unslotted keys use the global cooldown. Local-gap pools still
keep at least the local keepalive window. The fields do not shape the runtime
fingerprint, but derived payloads (warmups, prewarm targets, mapped phases)
inherit them so they land in the same container pool.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hybrid mapped execution rebuilt its static, mapped, and cleanup phase payloads
from a fixed field list that dropped modal_gpu and modal_max_containers. Those
payloads resolved default settings and expected a different runtime fingerprint
for the same Modal app, so the sibling-validation guard refused them with
ModalRemoteAppOutOfDateError.
Define the fingerprint-shaping payload fields once in settings and copy them at
every derived-payload site (mapped phases, warmup requests, speculative
prewarm targets).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>