CMKFamilyBranchGateSDXLSampled
Gating the Latent Handoff So Module 10 Doesn't Run Twice
- MODEL
- PROCESS
- SAMPLED
- LOG
- VISUAL
- diagnostic
- MODEL
- SAMPLED
- LOG
- PROCESS
- IMAGE
- VISUAL
- diagnostic
CMK doesn't pass IMAGE between its SDXL sampler, InstantID and refiner. It passes a proprietary SAMPLED type - still-latent data, because decoding and re-encoding between those stages would throw away quality for nothing. That's a better design and a worse caching problem, and this node is the fix.
What it does that its siblings don't
The plain SDXL gate passes MODEL, IMAGE and LOG. This one adds SAMPLED to the gated set, and adds two outputs the others don't have: PROCESS and IMAGE. Five outputs total - MODEL, SAMPLED, LOG, PROCESS, IMAGE.
Why it needs its own cache logic: it holds a small boundary cache keyed on a fingerprint of the sampler node in the prompt graph, so a boundary that already resolved doesn't get asked for again in the same session. And it resolves in a deliberate order - MODEL first, then SAMPLED - because requesting both together lets ComfyUI open the shared sampler preparation through two lazy paths after a process restart, which executes the sampler module twice. On a 30-step SDXL pass with InstantID attached, that's not a rounding error. The comment in the source is explicit that SAMPLED is the expensive authoritative stage while MODEL is cheap.
Same family validation as the rest of the set: it reads model_family off the process pipe and raises if it isn't sdxl. Same family_active short-circuit: if the process says this family is inactive, all five outputs come back blocked and nothing upstream runs.
The decoded-image trick worth knowing about
There's a genuinely interesting detail in here. During a split InstantID run, latent_1st_pass is deliberately still noisy - module 15 is going to keep sampling it, so the handoff is unfinished on purpose. But you still want a clean preview at the sampler boundary.
So when an image is needed and none exists, this node decodes the sampler's own clean x0 estimate for the visual artifact, without touching the functional latent handoff. It prefers instantid_keypoints_latent where present, falls back to latent_1st_pass or latent_image, and VAE-decodes that. The functional path keeps the noisy latent; the preview gets a finished-looking picture. It stores the result on the payload as image_1st_pass, which is also what the HYBRID bridge later reads.
If you've ever wondered why the comparison preview after a CMK SDXL sampler looks finished while the refiner is clearly still working, that's why. It's not a rendering trick in the frontend; it's a decode on a different tensor.
Inputs and outputs
Inputs: MODEL (CMK_MODEL_PIPE), PROCESS (CMK_PROCESS_SDXL), SAMPLED (CMK_SAMPLED_PIPE), LOG - all optional and lazy.
Outputs: MODEL, SAMPLED, LOG, PROCESS, IMAGE. The PROCESS pass-through exists so the boundary can hand the process pipe onward without a second wire through half the graph, and IMAGE is the decoded first-pass artifact.
When you'd reach for it
You're building or repairing a flow with a sampler → InstantID → refiner chain, and you're seeing the sampler execute twice. That's the signature symptom this node exists to prevent, and the fix is making sure the boundary is actually in the path rather than wired directly from sampler to refiner.
Or you want the first-pass image available downstream without breaking the latent handoff. IMAGE is right there.
Install
Manager: search CMK Flow, install the CMKFlow entry, restart. Manual:
git clone https://github.com/CMKFlow/cmk_nodes.git custom_nodes/cmk_nodes
python3 custom_nodes/cmk_nodes/scripts/install_cmk_requirements.py
No models needed for the gate. The pipeline it gates does need weights - InstantID adapter and ControlNet files are among the things the pack's resource check fetches per item:
python3 custom_nodes/cmk_nodes/scripts/check_cmk_resources.py --models-root "/path/to/ComfyUI-Shared"
Gotchas
Boundary caches here are session-scoped, and they're cleared on restart. That's why the double-execution guard has to be careful about resolution order rather than simply trusting a hit.
And if you rewire the sampler, the fingerprint changes and every downstream boundary re-materialises. Expected, but it means "I moved one node and the whole chain re-ran" is a designed response, not a caching failure.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| MODELopt | CMK_MODEL_PIPE | — | |
| PROCESSopt | CMK_PROCESS_SDXL | — | |
| SAMPLEDopt | CMK_SAMPLED_PIPE | — | |
| LOGopt | CMK_LOG_PIPE | — | |
| VISUALopt | CMK_VISUAL_PIPE | — | |
| diagnosticopt | CMK_DIAGNOSTIC | — |
Outputs (7)
| Name | Type | Description |
|---|---|---|
| MODEL | CMK_MODEL_PIPE | — |
| SAMPLED | CMK_SAMPLED_PIPE | — |
| LOG | CMK_LOG_PIPE | — |
| PROCESS | CMK_PROCESS_SDXL | — |
| IMAGE | IMAGE | — |
| VISUAL | CMK_VISUAL_PIPE | — |
| diagnostic | CMK_DIAGNOSTIC | — |