Nodes/DOGMA Nodes/DOGMA v56.5 Novel Structure Guard
ComfyUI Node

DOGMA v56.5 Novel Structure Guard

Catching the building your upscaler invented

By axior·Created 4 months ago·Updated 3 days ago· 1
DOGMA v56.5 Novel Structure Guard
  • generated
  • source
  • image
  • novelty_mask
  • info
strength1.00
threshold0.055
analysis_long_side512

Generative upscaling doesn't just sharpen. Give it a soft patch of cityscape and it will confidently resolve it into a facade with windows that were never in your source. Most workflows have no answer for that; this node does, and it's a surprisingly cheap one.

The failure mode

The KB's upscaling doc draws the line this belongs on: adding pixels is one job, adding detail is another, and the second one "will rewrite faces". Tiled diffusion upscaling is the classic version - split into overlapping tiles, re-diffuse each one, blend. Each tile is being asked to hallucinate plausible content, and occasionally a tile invents a coherent medium-scale structure: a tower, a wall, a doorway, a parked car. It doesn't look like an artefact. It looks like detail, which is why it survives review and why it ruins an otherwise faithful plate.

The v56.5 pass attacked it with a simple, defensible premise: fine detail is fine; coherent structure that exists only in the generated image is not.

How it works

Both images get downscaled to analysis_long_side (area sampling), then box-blurred with a 7-pixel kernel. That blur is doing real work - it suppresses micro-detail differences on purpose, so legitimate sharpening and recovered texture don't count as novelty. What's left to compare is medium-scale content.

Two signals are computed on the blurred pair:

  • Colour difference - absolute mean per-channel distance, which catches big flat changes like a new sky or a new wall.
  • New edge energy - gradient magnitude of the generated luma minus 1.2× the source's, rectified at zero. The 1.2 factor is a small tolerance so a modest edge gain passes; only edges that clearly aren't in the source contribute.

They're summed (edge energy weighted 0.3), smoothed with a 9-pixel box, then pushed through a smoothstep between threshold and roughly 2.2× threshold. After that comes a coherence filter - a 7-pixel averaging pass, a remap that zeroes anything below 0.12, a second smoothstep, a 5-pixel max-pool that grows the surviving blobs, and a final 7-pixel average. That chain is what turns scattered micro-changes into a mask that means "there is a coherent thing here" instead of static.

The mask is bilinearly upscaled to full size, multiplied by strength, and used to blend the generated image back toward the source. Mask weight 1 means source pixels; weight 0 means generated pixels.

Inputs and outputs

  • generated - the tile after the model had its way with it. Accepts a batch; the source is aligned to it (resized if needed, first frame expanded if the count doesn't match).
  • source - the reference. This is authority.
  • strength - 0 to 1, default 1.0, step 0.05. How hard to revert the flagged regions. 1.0 restores source pixels fully inside the mask; 0.5 is a half-way compromise.
  • threshold - 0.01 to 0.20, default 0.055. Lower catches subtler inventions and risks reverting legitimate change; raise it to 0.08–0.10 if the guard is eating detail you wanted.
  • analysis_long_side - 256 to 1024, default 512. The comparison resolution. The whole guard is scale-relative, so this is effectively "how big does an invention need to be before I care" - a bigger analysis side means smaller structures pass.

Outputs: image (the guarded result), novelty_mask (the guard's own view of where it intervened - invaluable to look at), and info (strength, threshold, analysis size, guarded coverage %, and peak mask value).

Install

comfy node install comfyui-dogma-nodes
# or
cd ComfyUI/custom_nodes
git clone https://github.com/axior/ComfyUI-DOGMA-Nodes
pip install -r ComfyUI-DOGMA-Nodes/requirements.txt

Restart afterwards. No models: this is pure tensor work and runs alongside your pipeline. The pack claims no extra dependencies, but requirements.txt ships scipy>=1.10 for the v56.6/v56.7 modules - install the pack properly and it doesn't matter.

Gotchas

Coverage in the info string is your tuning loop. If it reads 2%, the guard barely did anything and your invented tower is still there - lower the threshold or raise the analysis resolution. If it's pushing 30%, you're reverting legitimate detail and should raise the threshold.

It rewrites the whole tile toward the source where it fires. That's a local composite, so the transition is smooth, but a heavily-guarded tile drifts back toward looking like the pre-upscale input. For genuinely damaged tiles that's the wrong trade - this guard assumes your source is trustworthy and your generator is the suspect.

Batch behaviour is "first frame wins". If source has one frame and generated has eight, the single source is expanded across the batch. Which is fine if the eight frames are tiles of the same image and wrong if they're a video, so don't point this at a sequence unless you actually meant to compare every frame against frame one.

CategoryDOGMA/v56.5

Inputs (5)

NameTypeDefaultDescription
generatedIMAGE
sourceIMAGE
strengthFLOAT1.000–1
thresholdFLOAT0.0550.01–0.2
analysis_long_sideINT512256–1024

Outputs (3)

NameTypeDescription
imageIMAGE
novelty_maskMASK
infoSTRING