Badge Local Selection Guard V1 (DAELab)
The bouncer that stops a stale mask from reaching a paid edit
- pre_edit_master
- selection_reference
- candidate_mask
- edit_support_mask
- validated_mask
- selection_overlay
- effective_apply
- snapshot_token
- status
What this is for
Masked editing has one failure that costs real money and looks like a model problem: you preview a selection, then change the image or nudge the mask, then hit apply - and the edit lands against the selection you previewed, not the one you have. The output is a badge with a material patch in almost the right place, which is worse than an outright failure because it's plausible.
Badge Local Selection Guard V1 is the node that makes that impossible. It takes the candidate mask plus everything the selection depends on - the pre-edit master, the reference image, the edit support mask, the routing strings, the prompt digest, the picker configuration - validates them, and emits a mask plus a snapshot_token that encodes exactly what was approved. If any of it changed, the token doesn't match and the apply doesn't happen.
It's the least glamorous node in the pack and arguably the most important one. Fourteen required inputs, most of them strings you never type. Yes, that's a lot of wiring. Every one of them is there because something needed to be in the fingerprint.
How it works
Two layers.
The first is masking: it clips the candidate mask against edit_support_mask so a selection can never reach outside the region edits are allowed to touch, rejects selections below minimum_region_pixels, and returns the clipped mask as validated_mask plus a red-tinted selection_overlay you can preview. effective_apply is the boolean that actually says "go", and it only comes true when you asked to apply and the selection survived validation.
The second layer is the fingerprint. IS_CHANGED builds a digest over the two images, the candidate mask, the support mask, the apply flag, confirmation_revision, route_id, map_mode, map_cache_key, edit_mode, action_digest, selection_mode, minimum_region_pixels, the node's own id, and the resolved picker configuration. That last one is subtle: if picker_config is empty it looks up the node by picker_node_id inside the workflow (extra_pnginfo) and reads the picker's settings from there. So a color picker's tolerance changing - a widget with no wire at all - still invalidates the approval.
The digest is the cache key. Same inputs, cached, nothing runs. One pixel different anywhere, the node re-runs and produces a new snapshot_token, and the apply that carried the old one is stale.
map_mode and map_cache_key are there because selections can be sampled from a generated Color ID Map instead of the image itself; both the ID map and the live-picker path have to be in the fingerprint, or swapping the map would silently reuse an approval.
The inputs and outputs
The ones you actually set: requested_apply (default false), minimum_region_pixels (default 16, min 1, max 65536), and confirmation_revision - an integer you bump to force a fresh approval without changing anything else. picker_node_id and picker_config are for the workflow-introspection path; leave picker_config empty and the node reads the picker from the workflow.
The rest come from upstream: pre_edit_master, selection_reference, candidate_mask, edit_support_mask, plus route_id, edit_mode, action_digest, selection_mode - the strings from Badge Entry Route V1, Badge Edit Prompt Route V1 and Badge Local Mask Route V1. map_cache_key is optional.
Outputs: validated_mask, selection_overlay, effective_apply, snapshot_token, status (JSON with selected pixel counts, minimum, token, revision, a digest of the picker config and the selection mode).
Install
cd ComfyUI/custom_nodes
git clone https://github.com/TeutonicMepheles/ComfyUI-DAELab-Custom-Nodes-Library.git
# restart ComfyUI
No models; standard core dependencies. Note that extra_pnginfo is a hidden input, which means the picker-introspection path only works when the job is queued as a normal workflow - a raw API submit with a stripped-down prompt won't be able to resolve the picker at all.
Where people get burned
Bypassing the guard. The obvious shortcut when you're debugging: delete the guard, wire the mask straight into the edit. Now nothing checks the selection size or clips it to the support mask, and the composite downstream has to fix a mask that's five pixels from wrong. If a paid call is behind it, you've also removed the only thing preventing a stale apply.
Empty picker_config + no workflow context. In API-driven runs the fallback lookup finds nothing, the config digests as empty, and anything that changed in the picker stops mattering to the fingerprint. Pass the config explicitly if you're not going through the normal front end.
Assuming effective_apply means "the edit ran". It means the selection was legal. Whether the model behaved is a different question entirely.
14 inputs, hand-wired. This is a node the pack's front end wires for you, and it's built that way on purpose. If you're assembling it manually you're re-implementing the workflow - expect to spend an hour matching digests before you get a ready.
Inputs (15)
| Name | Type | Default | Description |
|---|---|---|---|
| pre_edit_master | IMAGE | — | |
| selection_reference | IMAGE | — | |
| candidate_mask | MASK | — | |
| edit_support_mask | MASK | — | |
| requested_apply | BOOLEAN | false | — |
| confirmation_revision | INT | 00–2147483647 | — |
| route_id | STRING | — | |
| map_mode | BOOLEAN | false | — |
| picker_node_id | STRING | — | |
| picker_config | STRING | — | |
| edit_mode | STRING | — | |
| action_digest | STRING | — | |
| selection_mode | STRING | — | |
| minimum_region_pixels | INT | 161–65536 | — |
| map_cache_keyopt | STRING | — |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| validated_mask | MASK | — |
| selection_overlay | IMAGE | — |
| effective_apply | BOOLEAN | — |
| snapshot_token | STRING | — |
| status | STRING | — |