Stamp Step (gte)
Write where the latent is onto the latent itself
- latent
- latent
A latent that's been sampled part-way is meaningless without the sigma it sits at. Everyone who writes staged diffusion believes this. The graph did not: the position travelled on a separate wire - the stage's checkpoint widget - while the latent itself said nothing. Two facts, two places, free to disagree.
They disagree the moment a stage is skipped. Bypass Step C and ComfyUI passes the latent through correctly (the bypass rule matches inputs to outputs by slot), so the FINAL stage receives Step B's latent - while its start_step is still wired to Checkpoint C. The sampler is told the latent holds 34% noise when it holds 69%. It under-denoises, hands back a soft, still-noisy image, and nothing errors. Nothing is broken enough to complain.
Stamp Step makes the latent self-describing instead.
How it works
A ComfyUI LATENT is just a dict: {"samples": tensor} plus whatever else rides along. Core already does this - batch_index from Latent From Batch, noise_mask from the inpaint nodes - and every node that passes a latent on rebuilds it with latent.copy(), so extra keys survive untouched. The pack verified that for the whole chain it uses, SamplerCustomAdvanced included.
So stamping is literally latent["gte_step"] = 11 (plus gte_sigma). The position travels with the tensor, the way EXIF travels with a photo, instead of alongside it on a wire that can be rerouted, bypassed, or left pointing at the wrong stage. One copy of the fact means it cannot get out of sync.
Why this beats the obvious fix - a switch that picks the right checkpoint depending on which stages are enabled - is that the switch makes the graph encode the enabled-stage set twice, once in the bypass state and once in the wiring. Those two drift. A stamp needs no such knowledge: bypass a stage and its Stamp Step goes with it, so the latent arrives carrying whichever stage last actually ran. Skipping the middle stage becomes a valid two-branch tree instead of a silent mis-render.
Inputs and outputs
- latent (required) - the latent this stage is handing on. Normally the sampler's
output. - step (required, INT, default 0) - the absolute step this stage ended on. Same number as its Sigma Segment
end_step. Wire the stage's checkpoint control to both and they can't drift apart. - sigma (optional, FLOAT, wire-only) - wire Sigma Segment's
end_sigma. This is the one that matters for branching: the latent then carries its own noise level onward, so the next stage's Noise Rotate knows how much noise it's looking at without anything else being wired. Leave it off and Noise Rotate will tell you it has a model but no sigma. - Output: latent - the same latent, now carrying its position. One output, chain it onward.
It returns a copy, never a mutation. The input latent may still be feeding other nodes, and a stage stamping its own number onto a tensor someone else is reading is exactly the kind of action-at-a-distance this pack avoids.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/mgkgng/ComfyUI-GTE
Restart ComfyUI; the console prints [gte] loaded 8 node(s). No Python dependencies - the pack's requirements.txt is empty on purpose, everything runs on the torch/numpy/Pillow ComfyUI ships. Manager search: ComfyUI-GTE / "Generative Trajectory Explorer". No model files, no downloads, works with any checkpoint family.
Common issues
"This latent is already at step 5, but the stage claims to end at 4." You've got checkpoint controls out of order along the chain. Sampling only ever moves forward through the schedule, so a stage finishing earlier than it began means the numbers on screen are wrong - catch it here, where they're still readable.
A soft, over-soft final image is the signature of a missing stamp, not a broken node. If you wire start_step by hand while bypassing stages, you're back to the two-copies problem this node exists to delete. Route it through Resume Step.
Latents that leave ComfyUI lose their stamps. Save a mid-trajectory latent, load it back next week, and gte_step is gone - it's not a core key, so it isn't serialised. Resume Step's fallback exists for exactly this case.
Re-use the same step number in two places if you can. The pack's own advice: wire the stage's checkpoint control into both Sigma Segment's end_step and Stamp Step's step. Then the stamp can't disagree with the slice, and the only remaining source of truth is the control you can see.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| latent | LATENT | The latent this stage is handing on — normally the sampler's `output`. | |
| step | INT | 00–10000 | The absolute step this stage ended on: the same number as its Sigma Segment `end_step`. Wire the stage's checkpoint control to both and they cannot drift apart. |
| sigmaopt | FLOAT | The noise level this stage ended at — wire Sigma Segment's `end_sigma`. The latent then carries it onward, so the next stage's Noise Rotate knows how much noise it is looking at without anything else being wired. A step number alone is not enough: the same step means different noise on different schedulers. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| latent | LATENT | The same latent, now carrying its position for the next stage to read. |