Skip to content

Add SeedVR2 schema/signature regression test#24

Closed
pollockjj wants to merge 12 commits into
issue_101from
seedvr-signature-regression-review
Closed

Add SeedVR2 schema/signature regression test#24
pollockjj wants to merge 12 commits into
issue_101from
seedvr-signature-regression-review

Conversation

@pollockjj
Copy link
Copy Markdown
Owner

Summary

Adds a unit regression test for SeedVR2InputProcessing that compares the schema input id order with the execute() positional parameter order.

Validation

  • .venv/bin/pytest tests-unit/comfy_extras_test/test_seedvr_node_signature.py -v

pollockjj and others added 9 commits April 23, 2026 09:23
Issue 130: Clean SeedVR2 native runtime fixes
…p print noise

Follow-up to PR #20 review feedback and the new mydevelopment#114 plan
(Production-Code Shape Independence rule):

- stub comfy.model_management via unittest.mock.patch.dict instead of
  importing the real module, so test collection no longer triggers
  torch.cuda.is_available() or any GPU/server-side initialization.
  Live introspection confirmed comfy.model_management is the only
  heavy module transitively imported by comfy_extras.nodes_seedvr;
  nodes and server are not, so they are not stubbed.
- pop and re-import comfy_extras.nodes_seedvr inside the patch context
  via importlib.import_module so the stubbed sys.modules entry is the
  one observed during attribute resolution.
- replace the bare assert + print() pair with a single assert carrying
  a descriptive f-string failure message that includes both lists, so
  pytest's standard error report is the only failure surface and the
  passing-run stdout is quiet.
Adopt PR #20 Copilot review on e042ff2 verbatim: wrap the stubbed import
in try/finally so the mocked comfy.model_management cannot leak into
later tests via the cached comfy_extras.nodes_seedvr module.

- Bind the MagicMock to a local mock_model_management so the finally
  block can identity-check before deleting.
- Pop comfy_extras.nodes_seedvr from sys.modules in finally so the
  next test that imports it gets a fresh load with the real
  comfy.model_management.
- If the comfy package object itself acquired model_management as an
  attribute pointing at the test mock, delete that attribute so the
  package state matches the unstubbed condition.

The assertion logic is unchanged; the test still passes on issue_114
HEAD and still fails on the spatial_overlap/temporal_tile_size swap.
Two stylistic suggestions from Copilot's review of 5eb9257:

1. Reword the module docstring so it no longer claims the stub prevents
   GPU init at *test collection*; the stub/import happens inside the
   test body, so the wording now scopes the guarantee to the import
   performed inside the test. Adopted verbatim from the review.

2. Iterate inspect.signature(...).parameters.keys() instead of
   .parameters so it reads as 'list of names' rather than 'list of
   Parameter objects'. The runtime semantics are identical because
   .parameters yields keys when iterated, but .keys() makes the
   reader's job easier.

Behaviour, assertion text, and stubbing strategy are unchanged. The
test still passes on issue_114 HEAD and still fails on the
spatial_overlap/temporal_tile_size swap.
Copilot AI review requested due to automatic review settings April 27, 2026 21:36
f"parameter order: schema_ids={schema_ids}, exec_params={exec_params}"
)
finally:
sys.modules.pop("comfy_extras.nodes_seedvr", None)
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Clear the parent package submodule cache

When this test imports comfy_extras.nodes_seedvr under the mocked comfy.model_management, Python also leaves that module on the comfy_extras.nodes_seedvr parent package attribute. The finally block only removes sys.modules, so any later test in the same process that does from comfy_extras import nodes_seedvr can receive the stale module loaded with the mock instead of re-importing the real dependency.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a unit-level regression test to prevent silent argument reordering bugs in the SeedVR2 node by asserting the declared schema input order matches the execute() positional parameter order.

Changes:

  • Introduces a new pytest that compares SeedVR2InputProcessing.define_schema().inputs[*].id ordering to the SeedVR2InputProcessing.execute() signature order.
  • Stubs comfy.model_management during import to avoid CUDA/GPU probing side effects and cleans up relevant sys.modules entries afterward.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@qa-agent-seveneves
Copy link
Copy Markdown

Codex Review -- Round 1 -- KICKOFF

Runner: scripts/run_codex_review.py
PR: #24
Reviewer model: codex review (configured codex CLI default)
Kickoff timestamp (UTC): 2026-04-28T00:22:01Z

Prompt sent to codex review

Review the latest state of https://github.com/pollockjj/ComfyUI/pull/24. Output findings using strict P0-P3 priority tags ([P0], [P1], [P2], [P3]) at the start of each finding title. Surface P0/P1/P2 -- these block merge in this repo. Surface P3 with that tag explicitly. Do not surface style nits, formatting, typos, or pre-existing bugs. End your output with a single line either 'APPROVE' (no P0/P1/P2 found) or 'REQUEST_CHANGES' (one or more P0/P1/P2 found). Output nothing else after that line.

Awaiting codex output. The result will be posted as a separate comment on this PR when codex exits.

@qa-agent-seveneves
Copy link
Copy Markdown

Codex Review -- Round 1 -- RESULT

PR: #24
Reviewer model: codex review (configured codex CLI default)
Result timestamp (UTC): 2026-04-28T00:23:37Z
Codex exit code: 0
Duration (s): 93.8
Detected verdict: UNKNOWN

Prompt sent to codex review

Review the latest state of https://github.com/pollockjj/ComfyUI/pull/24. Output findings using strict P0-P3 priority tags ([P0], [P1], [P2], [P3]) at the start of each finding title. Surface P0/P1/P2 -- these block merge in this repo. Surface P3 with that tag explicitly. Do not surface style nits, formatting, typos, or pre-existing bugs. End your output with a single line either 'APPROVE' (no P0/P1/P2 found) or 'REQUEST_CHANGES' (one or more P0/P1/P2 found). Output nothing else after that line.

Verbatim codex review output

This PR was reviewed using codex review with the prompt above and produced the following output:


The regression test leaves a parent-package submodule reference behind after importing under a mocked dependency, which can contaminate later tests in the same process. This P2 issue should block merge until cleanup is complete.

Review comment:

  • [P2] Clear the parent package submodule cache — /home/johnj/dev_cuda_1/ComfyUI/tests-unit/comfy_extras_test/test_seedvr_node_signature.py:45-45
    When this test runs in a shared pytest process, importing comfy_extras.nodes_seedvr under the mocked comfy.model_management also caches the module as comfy_extras.nodes_seedvr on the parent package. The cleanup only removes sys.modules, so a later from comfy_extras import nodes_seedvr can receive the module created with this test's mock instead of forcing a clean import, leaking the stubbed import state into unrelated tests.

Codex runner stderr (non-evidence)

OpenAI Codex v0.125.0 (research preview)
--------
workdir: /home/johnj/dev_cuda_1/mydevelopment
model: gpt-5.5
provider: openai
approval: never
sandbox: workspace-write [workdir, /tmp, $TMPDIR, /home/johnj/.codex/memories]
reasoning effort: high
reasoning summaries: none
session id: 019dd176-e550-7c80-be03-8607c8b45d5c
--------
user
Review the latest state of https://github.com/pollockjj/ComfyUI/pull/24. Output findings using strict P0-P3 priority tags ([P0], [P1], [P2], [P3]) at the start of each finding title. Surface P0/P1/P2 -- these block merge in this repo. Surface P3 with that tag explicitly. Do not surface style nits, formatting, typos, or pre-existing bugs. End your output with a single line either 'APPROVE' (no P0/P1/P2 found) or 'REQUEST_CHANGES' (one or more P0/P1/P2 found). Output nothing else after that line.
mcp: codex_apps/github_fetch_pr started
mcp: codex_apps/github_fetch_pr (completed)
exec
/bin/bash -lc pwd in /home/johnj/dev_cuda_1/mydevelopment
 succeeded in 0ms:
/home/johnj/dev_cuda_1/mydevelopment

exec
/bin/bash -lc 'ls ../ComfyUI' in /home/johnj/dev_cuda_1/mydevelopment
 succeeded in 0ms:
CODEOWNERS
CONTRIBUTING.md
LICENSE
QUANTIZATION.md
README.md
__pycache__
alembic.ini
alembic_db
api_server
app
blueprints
comfy
comfy_api
comfy_api_nodes
comfy_config
comfy_execution
comfy_extras
comfyui_version.py
cuda_malloc.py
custom_nodes
execution.py
extra_model_paths.yaml.example
folder_paths.py
hook_breaker_ac10a0.py
input
latent_preview.py
main.py
manager_requirements.txt
middleware
models
new_updater.py
node_helpers.py
nodes.py
output
protocol.py
pyproject.toml
pytest.ini
requirements.txt
script_examples
server.py
tests
tests-unit
user
utils

exec
/bin/bash -lc 'git status --short' in /home/johnj/dev_cuda_1/ComfyUI
 succeeded in 0ms:
exec
/bin/bash -lc 'git branch --show-current' in /home/johnj/dev_cuda_1/ComfyUI
 succeeded in 0ms:
seedvr-signature-regression-review

exec
/bin/bash -lc 'nl -ba tests-unit/comfy_extras_test/test_seedvr_node_signature.py' in /home/johnj/dev_cuda_1/ComfyUI
 succeeded in 0ms:
     1	"""Regression test: SeedVR2InputProcessing schema input ids must match
     2	execute() positional parameter order. Drift between the two would silently
     3	swap arguments at runtime; this test fails loudly on any future drift.
     4	
     5	The schema input attribute is `.id` (verified live via Python introspection
     6	on the upstream class -- there is no `.name`).
     7	
     8	`comfy.model_management` is stubbed via `patch.dict(sys.modules, ...)` for
     9	the import performed inside this test, so importing
    10	`comfy_extras.nodes_seedvr` here does not call
    11	`torch.cuda.is_available()` or trigger other GPU/server-side
    12	initialization through that dependency. Live introspection indicated that
    13	`comfy_extras.nodes_seedvr` pulls in `comfy.model_management`
    14	transitively here (not `nodes`, not `server`).
    15	
    16	`comfy_extras.nodes_seedvr` is unconditionally evicted from `sys.modules`
    17	in a `finally` block, and the mocked `model_management` attribute is
    18	removed from the `comfy` package object if it points at the test's mock,
    19	so the stub does not leak into later tests that may import the real
    20	`comfy_extras.nodes_seedvr`."""
    21	
    22	import importlib
    23	import inspect
    24	import sys
    25	from unittest.mock import MagicMock, patch
    26	
    27	
    28	def test_seedvr_node_signature_matches_schema():
    29	    mock_model_management = MagicMock()
    30	    with patch.dict(sys.modules, {"comfy.model_management": mock_model_management}):
    31	        sys.modules.pop("comfy_extras.nodes_seedvr", None)
    32	        try:
    33	            nodes_seedvr = importlib.import_module("comfy_extras.nodes_seedvr")
    34	            schema_ids = [i.id for i in nodes_seedvr.SeedVR2InputProcessing.define_schema().inputs]
    35	            exec_params = [
    36	                p
    37	                for p in inspect.signature(nodes_seedvr.SeedVR2InputProcessing.execute).parameters.keys()
    38	                if p != "cls"
    39	            ]
    40	            assert schema_ids == exec_params, (
    41	                f"SeedVR2InputProcessing schema input ids do not match execute() "
    42	                f"parameter order: schema_ids={schema_ids}, exec_params={exec_params}"
    43	            )
    44	        finally:
    45	            sys.modules.pop("comfy_extras.nodes_seedvr", None)
    46	            comfy_module = sys.modules.get("comfy")
    47	            if comfy_module is not None and getattr(comfy_module, "model_management", None) is mock_model_management:
    48	                delattr(comfy_module, "model_management")

exec
/bin/bash -lc 'grep -n "class SeedVR2InputProcessing" -A120 comfy_extras/nodes_seedvr.py' in /home/johnj/dev_cuda_1/ComfyUI
 succeeded in 0ms:
123:class SeedVR2InputProcessing(io.ComfyNode):
124-    @classmethod
125-    def define_schema(cls):
126-        return io.Schema(
127-            node_id = "SeedVR2InputProcessing",
128-            category="image/video",
129-            inputs = [
130-                io.Image.Input("images"),
131-                io.Vae.Input("vae"),
132-                io.Int.Input("resolution", default = 1280, min = 120), # just non-zero value
133-                io.Int.Input("spatial_tile_size", default = 512, min = 1),
134-                io.Int.Input("spatial_overlap", default = 64, min = 1),
135-                io.Int.Input("temporal_tile_size", default=5, min=1, max=16384, step=4),
136-                io.Boolean.Input("enable_tiling", default=False),
137-            ],
138-            outputs = [
139-                io.Latent.Output("vae_conditioning")
140-            ]
141-        )
142-
143-    @classmethod
144-    def execute(cls, images, vae, resolution, spatial_tile_size, spatial_overlap, temporal_tile_size, enable_tiling):
145-
146-        comfy.model_management.load_models_gpu([vae.patcher])
147-        vae_model = vae.first_stage_model
148-        scale = 0.9152
149-        shift = 0
150-        if images.dim() != 5: # add the t dim
151-            images = images.unsqueeze(0)
152-        images = images.permute(0, 1, 4, 2, 3)
153-
154-        b, t, c, h, w = images.shape
155-        images = images.reshape(b * t, c, h, w)
156-
157-        clip = Lambda(lambda x: torch.clamp(x, 0.0, 1.0))
158-        normalize = Normalize(0.5, 0.5)
159-        images = side_resize(images, resolution)
160-
161-        images = clip(images)
162-        o_h, o_w = images.shape[-2:]
163-        images = div_pad(images, (16, 16))
164-        images = normalize(images)
165-        _, _, new_h, new_w = images.shape
166-
167-        images = images.reshape(b, t, c, new_h, new_w)
168-        images = cut_videos(images)
169-        images_bcthw = rearrange(images, "b t c h w -> b c t h w")
170-        images_bthwc = rearrange(images, "b t c h w -> b t h w c")
171-
172-        # in case users a non-compatiable number for tiling
173-        def make_divisible(val, divisor):
174-            return max(divisor, round(val / divisor) * divisor)
175-
176-        spatial_tile_size = make_divisible(spatial_tile_size, 32)
177-        spatial_overlap = make_divisible(spatial_overlap, 32)
178-
179-        if spatial_overlap >= spatial_tile_size:
180-            spatial_overlap = max(0, spatial_tile_size - 8)
181-
182-        args = {"tile_size": (spatial_tile_size, spatial_tile_size), "tile_overlap": (spatial_overlap, spatial_overlap),
183-                "temporal_size":temporal_tile_size}
184-        if enable_tiling:
185-            vae_model.img_dims = [o_h, o_w]
186-            vae_model.original_image_video = images_bcthw
187-            latent = vae.encode_tiled(
188-                images_bthwc,
189-                tile_x=spatial_tile_size,
190-                tile_y=spatial_tile_size,
191-                overlap=spatial_overlap,
192-                tile_t=temporal_tile_size,
193-            )
194-        else:
195-            vae_model.img_dims = [o_h, o_w]
196-            vae_model.original_image_video = images_bcthw
197-            latent = vae.encode(images_bthwc)
198-
199-        clear_vae_memory(vae_model)
200-        #images = images.to(offload_device)
201-        #vae_model = vae_model.to(offload_device)
202-
203-        vae_model.img_dims = [o_h, o_w]
204-        args["enable_tiling"] = enable_tiling
205-        vae_model.tiled_args = args
206-        vae_model.original_image_video = images_bcthw
207-
208-        latent = latent.unsqueeze(2) if latent.ndim == 4 else latent
209-        latent = rearrange(latent, "b c ... -> b ... c")
210-
211-        latent = (latent - shift) * scale
212-
213-        return io.NodeOutput({"samples": latent})
214-
215-class SeedVR2Conditioning(io.ComfyNode):
216-    @classmethod
217-    def define_schema(cls):
218-        return io.Schema(
219-            node_id="SeedVR2Conditioning",
220-            category="image/video",
221-            inputs=[
222-                io.Latent.Input("vae_conditioning"),
223-                io.Model.Input("model"),
224-                io.Float.Input("latent_noise_scale", default=0.0, step=0.001)
225-            ],
226-            outputs=[io.Conditioning.Output(display_name = "positive"),
227-                     io.Conditioning.Output(display_name = "negative"),
228-                     io.Latent.Output(display_name = "latent")],
229-        )
230-
231-    @classmethod
232-    def execute(cls, vae_conditioning, model, latent_noise_scale) -> io.NodeOutput:
233-
234-        vae_conditioning = vae_conditioning["samples"]
235-        device = vae_conditioning.device
236-        model = model.model.diffusion_model
237-        pos_cond = model.positive_conditioning
238-        neg_cond = model.negative_conditioning
239-
240-        for module in model.modules():
241-            if hasattr(module, 'rope') and hasattr(module.rope, 'freqs'):
242-                module.rope.freqs.data = module.rope.freqs.data.to(torch.float32)
243-

exec
/bin/bash -lc 'head -80 comfy_extras/nodes_seedvr.py' in /home/johnj/dev_cuda_1/ComfyUI
 succeeded in 0ms:
from typing_extensions import override
from comfy_api.latest import ComfyExtension, io
import torch
import math
from einops import rearrange

import gc
import comfy.model_management

import torch.nn.functional as F
from torchvision.transforms import functional as TVF
from torchvision.transforms import Lambda, Normalize
from torchvision.transforms.functional import InterpolationMode


def clear_vae_memory(vae_model):
    for module in vae_model.modules():
        if hasattr(module, "memory"):
            module.memory = None
    gc.collect()
    torch.cuda.empty_cache()

def expand_dims(tensor, ndim):
    shape = tensor.shape + (1,) * (ndim - tensor.ndim)
    return tensor.reshape(shape)

def get_conditions(latent, latent_blur):
    t, h, w, c = latent.shape
    cond = torch.ones([t, h, w, c + 1], device=latent.device, dtype=latent.dtype)
    cond[:, ..., :-1] = latent_blur[:]
    cond[:, ..., -1:] = 1.0
    return cond

def timestep_transform(timesteps, latents_shapes):
    vt = 4
    vs = 8
    frames = (latents_shapes[:, 0] - 1) * vt + 1
    heights = latents_shapes[:, 1] * vs
    widths = latents_shapes[:, 2] * vs

    # Compute shift factor.
    def get_lin_function(x1, y1, x2, y2):
        m = (y2 - y1) / (x2 - x1)
        b = y1 - m * x1
        return lambda x: m * x + b

    img_shift_fn = get_lin_function(x1=256 * 256, y1=1.0, x2=1024 * 1024, y2=3.2)
    vid_shift_fn = get_lin_function(x1=256 * 256 * 37, y1=1.0, x2=1280 * 720 * 145, y2=5.0)
    shift = torch.where(
        frames > 1,
        vid_shift_fn(heights * widths * frames),
        img_shift_fn(heights * widths),
    ).to(timesteps.device)

    # Shift timesteps.
    T = 1000.0
    timesteps = timesteps / T
    timesteps = shift * timesteps / (1 + (shift - 1) * timesteps)
    timesteps = timesteps * T
    return timesteps

def inter(x_0, x_T, t):
    t = expand_dims(t, x_0.ndim)
    T = 1000.0
    B = lambda t: t / T
    A = lambda t: 1 - (t / T)
    return A(t) * x_0 + B(t) * x_T
def area_resize(image, max_area):

    height, width = image.shape[-2:]
    scale = math.sqrt(max_area / (height * width))

    resized_height, resized_width = round(height * scale), round(width * scale)

    return TVF.resize(
        image,
        size=(resized_height, resized_width),
        interpolation=InterpolationMode.BICUBIC,
    )


exec
/bin/bash -lc '.venv/bin/python -c "import inspect; from comfy_extras.nodes_seedvr import SeedVR2InputProcessing; print(inspect.signature(SeedVR2InputProcessing.execute)); print(list(inspect.signature(SeedVR2InputProcessing.execute).parameters.keys()))"' in /home/johnj/dev_cuda_1/ComfyUI
 exited 1 in 2012ms:
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/johnj/dev_cuda_1/ComfyUI/comfy_extras/nodes_seedvr.py", line 8, in <module>
    import comfy.model_management
  File "/home/johnj/dev_cuda_1/ComfyUI/comfy/model_management.py", line 257, in <module>
    total_vram = get_total_memory(get_torch_device()) / (1024 * 1024)
                                  ^^^^^^^^^^^^^^^^^^
  File "/home/johnj/dev_cuda_1/ComfyUI/comfy/model_management.py", line 207, in get_torch_device
    return torch.device(torch.cuda.current_device())
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/johnj/dev_cuda_1/ComfyUI/.venv/lib/python3.12/site-packages/torch/cuda/__init__.py", line 1148, in current_device
    _lazy_init()
  File "/home/johnj/dev_cuda_1/ComfyUI/.venv/lib/python3.12/site-packages/torch/cuda/__init__.py", line 478, in _lazy_init
    torch._C._cuda_init()
RuntimeError: No CUDA GPUs are available

exec
/bin/bash -lc ".venv/bin/python -c \"import sys, importlib, inspect; from unittest.mock import MagicMock, patch; m=MagicMock();\\nwith patch.dict(sys.modules, {'comfy.model_management': m}):\\n sys.modules.pop('comfy_extras.nodes_seedvr', None); ns=importlib.import_module('comfy_extras.nodes_seedvr'); print(inspect.signature(ns.SeedVR2InputProcessing.execute)); print(list(inspect.signature(ns.SeedVR2InputProcessing.execute).parameters.keys())); print([i.id for i in ns.SeedVR2InputProcessing.define_schema().inputs])\"" in /home/johnj/dev_cuda_1/ComfyUI
 exited 1 in 0ms:
  File "<string>", line 1
    import sys, importlib, inspect; from unittest.mock import MagicMock, patch; m=MagicMock();\nwith patch.dict(sys.modules, {'comfy.model_management': m}):\n sys.modules.pop('comfy_extras.nodes_seedvr', None); ns=importlib.import_module('comfy_extras.nodes_seedvr'); print(inspect.signature(ns.SeedVR2InputProcessing.execute)); print(list(inspect.signature(ns.SeedVR2InputProcessing.execute).parameters.keys())); print([i.id for i in ns.SeedVR2InputProcessing.define_schema().inputs])
                                                                                               ^
SyntaxError: unexpected character after line continuation character

exec
/bin/bash -lc "python - <<'PY'
import sys, types, importlib
pkg = types.ModuleType('pkg')
pkg.__path__ = []
old = types.ModuleType('pkg.sub')
new = types.ModuleType('pkg.sub')
sys.modules['pkg'] = pkg
sys.modules['pkg.sub'] = new
pkg.sub = old
import pkg.sub
print(pkg.sub is old, pkg.sub is new)
print(sys.modules['pkg.sub'] is new)
PY" in /home/johnj/dev_cuda_1/ComfyUI
 succeeded in 0ms:
True False
True

exec
/bin/bash -lc "python - <<'PY'
import sys, types, importlib
pkg = types.ModuleType('pkg')
pkg.__path__ = []
old = types.ModuleType('pkg.sub')
sys.modules['pkg'] = pkg
pkg.sub = old
try:
    m = importlib.import_module('pkg.sub')
except Exception as e:
    print(type(e).__name__, e)
else:
    print(m is old, m)
PY" in /home/johnj/dev_cuda_1/ComfyUI
 succeeded in 0ms:
ModuleNotFoundError No module named 'pkg.sub'

exec
/bin/bash -lc "python - <<'PY'
import sys, types
pkg = types.ModuleType('pkg')
pkg.__path__ = []
old = types.ModuleType('pkg.sub')
sys.modules['pkg'] = pkg
pkg.sub = old
try:
    from pkg import sub
except Exception as e:
    print(type(e).__name__, e)
else:
    print(sub is old)
PY" in /home/johnj/dev_cuda_1/ComfyUI
 succeeded in 0ms:
True

exec
/bin/bash -lc '.venv/bin/pytest tests-unit/comfy_extras_test/test_seedvr_node_signature.py -q' in /home/johnj/dev_cuda_1/ComfyUI
 succeeded in 2913ms:
.
=============================== warnings summary ===============================
.venv/lib/python3.12/site-packages/_pytest/cacheprovider.py:475
  /home/johnj/dev_cuda_1/ComfyUI/.venv/lib/python3.12/site-packages/_pytest/cacheprovider.py:475: PytestCacheWarning: cache could not write path /home/johnj/dev_cuda_1/ComfyUI/.pytest_cache/v/cache/nodeids: [Errno 30] Read-only file system: '/home/johnj/dev_cuda_1/ComfyUI/.pytest_cache/v/cache/nodeids'
    config.cache.set("cache/nodeids", sorted(self.cached_nodeids))

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
1 passed, 1 warning in 1.74s

exec
/bin/bash -lc 'grep -R "from comfy_extras import nodes_seedvr" -n tests tests-unit comfy_extras comfy_api_nodes' in /home/johnj/dev_cuda_1/ComfyUI
 succeeded in 0ms:
grep: tests-unit/comfy_extras_test/__pycache__/test_seedvr_node_signature.cpython-312-pytest-9.0.3.pyc: binary file matches

mcp: github/run_secret_scanning started
mcp: github/run_secret_scanning (failed)
exec
/bin/bash -lc 'git diff --stat issue_101...HEAD' in /home/johnj/dev_cuda_1/ComfyUI
 succeeded in 0ms:
 .../test_seedvr_node_signature.py                  | 48 ++++++++++++++++++++++
 1 file changed, 48 insertions(+)

2026-04-28T00:23:36.757954Z ERROR codex_core::session: failed to record rollout items: thread 019dd176-e575-7f51-88b0-d32ae0d5526e not found
codex
The regression test leaves a parent-package submodule reference behind after importing under a mocked dependency, which can contaminate later tests in the same process. This P2 issue should block merge until cleanup is complete.

Review comment:

- [P2] Clear the parent package submodule cache — /home/johnj/dev_cuda_1/ComfyUI/tests-unit/comfy_extras_test/test_seedvr_node_signature.py:45-45
  When this test runs in a shared pytest process, importing `comfy_extras.nodes_seedvr` under the mocked `comfy.model_management` also caches the module as `comfy_extras.nodes_seedvr` on the parent package. The cleanup only removes `sys.modules`, so a later `from comfy_extras import nodes_seedvr` can receive the module created with this test's mock instead of forcing a clean import, leaking the stubbed import state into unrelated tests.
2026-04-28T00:23:36.780846Z ERROR codex_core::session: failed to record rollout items: thread 019dd176-e550-7c80-be03-8607c8b45d5c not found

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +45 to +48
sys.modules.pop("comfy_extras.nodes_seedvr", None)
comfy_module = sys.modules.get("comfy")
if comfy_module is not None and getattr(comfy_module, "model_management", None) is mock_model_management:
delattr(comfy_module, "model_management")
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup removes comfy.model_management from the comfy package via delattr when it points at the mock. If comfy.model_management was already imported earlier in the test session, this test overwrites that attribute with the mock and then deletes it, rather than restoring the original module reference. That can leak state and create order-dependent failures for code that expects comfy.model_management to remain attached to the comfy package.

Consider capturing the pre-test value of getattr(comfy_module, "model_management", sentinel) before importing comfy_extras.nodes_seedvr, then restore it in finally (set back to the original if it existed, otherwise delete).

Copilot uses AI. Check for mistakes.
When this test imports comfy_extras.nodes_seedvr under a stubbed
comfy.model_management, Python caches the imported module on the
comfy_extras package object as a 'nodes_seedvr' attribute as well as in
sys.modules. The existing finally block only popped sys.modules, so a
later 'from comfy_extras import nodes_seedvr' in the same process could
resolve through the stale parent-package attribute and receive the
mock-loaded module instead of forcing a fresh import.

Add a parallel cleanup step in the finally block: when comfy_extras is
in sys.modules and carries a nodes_seedvr attribute, delete it. This
mirrors the existing comfy.model_management attribute cleanup so both
halves of the cached-import path are cleared.

References: #24 (comment)
            codex review round 1 (issue 114) [P2] finding
…management and comfy_extras.nodes_seedvr package attrs

Capture the pre-test value of comfy.model_management on the comfy
package and nodes_seedvr on the comfy_extras package before importing
comfy_extras.nodes_seedvr under the mock, then in finally restore the
attribute to its pre-test value if it had one, or delete it if it did
not. This addresses the case where another test in the same pytest
process had already legitimately imported comfy.model_management (or
comfy_extras.nodes_seedvr) prior to this test running: the previous
delete-on-mock cleanup left those package attributes unset even though
the real modules were still in sys.modules, which would AttributeError
on a subsequent comfy.model_management or comfy_extras.nodes_seedvr
attribute access without re-import.

The pattern is applied symmetrically to both attributes since the
correctness concern Copilot flagged on comfy.model_management is the
same correctness concern that motivated the codex P2 cleanup of
comfy_extras.nodes_seedvr — both are package attributes set as a
side-effect of import that we must restore rather than blindly delete.

References:
  #24 (comment)
  Copilot review id 4184963495 (round 1, head e96447f, ComfyUI#24)
@qa-agent-seveneves
Copy link
Copy Markdown

Codex Review -- Round 2 -- KICKOFF

Runner: scripts/run_codex_review.py
PR: #24
Reviewer model: codex review (configured codex CLI default)
Kickoff timestamp (UTC): 2026-04-28T00:31:43Z

Prompt sent to codex review

Review the latest state of https://github.com/pollockjj/ComfyUI/pull/24. Output findings using strict P0-P3 priority tags ([P0], [P1], [P2], [P3]) at the start of each finding title. Surface P0/P1/P2 -- these block merge in this repo. Surface P3 with that tag explicitly. Do not surface style nits, formatting, typos, or pre-existing bugs. End your output with a single line either 'APPROVE' (no P0/P1/P2 found) or 'REQUEST_CHANGES' (one or more P0/P1/P2 found). Output nothing else after that line.

Awaiting codex output. The result will be posted as a separate comment on this PR when codex exits.

@qa-agent-seveneves
Copy link
Copy Markdown

Codex Review -- Round 2 -- RESULT

PR: #24
Reviewer model: codex review (configured codex CLI default)
Result timestamp (UTC): 2026-04-28T00:33:10Z
Codex exit code: 0
Duration (s): 84.7
Detected verdict: UNKNOWN

Prompt sent to codex review

Review the latest state of https://github.com/pollockjj/ComfyUI/pull/24. Output findings using strict P0-P3 priority tags ([P0], [P1], [P2], [P3]) at the start of each finding title. Surface P0/P1/P2 -- these block merge in this repo. Surface P3 with that tag explicitly. Do not surface style nits, formatting, typos, or pre-existing bugs. End your output with a single line either 'APPROVE' (no P0/P1/P2 found) or 'REQUEST_CHANGES' (one or more P0/P1/P2 found). Output nothing else after that line.

Verbatim codex review output

This PR was reviewed using codex review with the prompt above and produced the following output:


The test still mutates global import state when the target module was already imported earlier in the same pytest process. This can cause order-dependent failures or unexpected GPU-dependent re-imports, so the patch should not be considered correct yet.

Review comment:

  • [P2] Restore preexisting nodes_seedvr module cache — /home/johnj/dev_cuda_1/ComfyUI/tests-unit/comfy_extras_test/test_seedvr_node_signature.py:53-53
    When another test has already imported comfy_extras.nodes_seedvr, this pop discards the real sys.modules entry and the cleanup only restores the parent package attribute. After this test runs, from comfy_extras import nodes_seedvr can still see the old attribute while import comfy_extras.nodes_seedvr re-imports the module under the real GPU dependency, creating order-dependent global import state. Capture and restore the prior sys.modules["comfy_extras.nodes_seedvr"] entry when it existed, mirroring the attribute restoration.

Codex runner stderr (non-evidence)

OpenAI Codex v0.125.0 (research preview)
--------
workdir: /home/johnj/dev_cuda_1/mydevelopment
model: gpt-5.5
provider: openai
approval: never
sandbox: workspace-write [workdir, /tmp, $TMPDIR, /home/johnj/.codex/memories]
reasoning effort: high
reasoning summaries: none
session id: 019dd17f-c9e8-72a3-aab7-47deea018d97
--------
user
Review the latest state of https://github.com/pollockjj/ComfyUI/pull/24. Output findings using strict P0-P3 priority tags ([P0], [P1], [P2], [P3]) at the start of each finding title. Surface P0/P1/P2 -- these block merge in this repo. Surface P3 with that tag explicitly. Do not surface style nits, formatting, typos, or pre-existing bugs. End your output with a single line either 'APPROVE' (no P0/P1/P2 found) or 'REQUEST_CHANGES' (one or more P0/P1/P2 found). Output nothing else after that line.
mcp: codex_apps/github_fetch_pr started
mcp: codex_apps/github_fetch_pr (completed)
mcp: github/run_secret_scanning started
mcp: github/run_secret_scanning (failed)
2026-04-28T00:33:09.974227Z ERROR codex_core::session: failed to record rollout items: thread 019dd17f-ca17-70c1-b4cf-c79d7ded7204 not found
codex
The test still mutates global import state when the target module was already imported earlier in the same pytest process. This can cause order-dependent failures or unexpected GPU-dependent re-imports, so the patch should not be considered correct yet.

Review comment:

- [P2] Restore preexisting nodes_seedvr module cache — /home/johnj/dev_cuda_1/ComfyUI/tests-unit/comfy_extras_test/test_seedvr_node_signature.py:53-53
  When another test has already imported `comfy_extras.nodes_seedvr`, this pop discards the real `sys.modules` entry and the cleanup only restores the parent package attribute. After this test runs, `from comfy_extras import nodes_seedvr` can still see the old attribute while `import comfy_extras.nodes_seedvr` re-imports the module under the real GPU dependency, creating order-dependent global import state. Capture and restore the prior `sys.modules["comfy_extras.nodes_seedvr"]` entry when it existed, mirroring the attribute restoration.
2026-04-28T00:33:09.997791Z ERROR codex_core::session: failed to record rollout items: thread 019dd17f-c9e8-72a3-aab7-47deea018d97 not found

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +39 to +75
comfy_module_pre = sys.modules.get("comfy")
comfy_extras_module_pre = sys.modules.get("comfy_extras")
prior_comfy_mm_attr = (
getattr(comfy_module_pre, "model_management", sentinel)
if comfy_module_pre is not None
else sentinel
)
prior_comfy_extras_seedvr_attr = (
getattr(comfy_extras_module_pre, "nodes_seedvr", sentinel)
if comfy_extras_module_pre is not None
else sentinel
)

with patch.dict(sys.modules, {"comfy.model_management": mock_model_management}):
sys.modules.pop("comfy_extras.nodes_seedvr", None)
try:
nodes_seedvr = importlib.import_module("comfy_extras.nodes_seedvr")
schema_ids = [i.id for i in nodes_seedvr.SeedVR2InputProcessing.define_schema().inputs]
exec_params = [
p
for p in inspect.signature(nodes_seedvr.SeedVR2InputProcessing.execute).parameters.keys()
if p != "cls"
]
assert schema_ids == exec_params, (
f"SeedVR2InputProcessing schema input ids do not match execute() "
f"parameter order: schema_ids={schema_ids}, exec_params={exec_params}"
)
finally:
sys.modules.pop("comfy_extras.nodes_seedvr", None)
comfy_extras_module = sys.modules.get("comfy_extras")
if comfy_extras_module is not None:
if prior_comfy_extras_seedvr_attr is sentinel:
if hasattr(comfy_extras_module, "nodes_seedvr"):
delattr(comfy_extras_module, "nodes_seedvr")
else:
setattr(comfy_extras_module, "nodes_seedvr", prior_comfy_extras_seedvr_attr)
comfy_module = sys.modules.get("comfy")
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup restores comfy_extras.nodes_seedvr / comfy.model_management attributes on the parent packages, but it doesn’t restore the original sys.modules["comfy_extras.nodes_seedvr"] entry if it existed before the test. If another test imported comfy_extras.nodes_seedvr earlier, this leaves the parent package attribute potentially pointing at a module that is no longer in sys.modules, and later imports will create a second module instance. Capture the pre-test sys.modules.get("comfy_extras.nodes_seedvr") value and restore/remove that entry in finally (similar to the attribute restoration), or wrap the whole import+pop logic in a patch.dict("sys.modules", ...) that restores prior state automatically.

Copilot uses AI. Check for mistakes.
…odules['comfy_extras.nodes_seedvr']

Both reviewers on round 2 of the autonomous review loop independently
flagged the same concern: the previous cleanup restored the
comfy_extras.nodes_seedvr package attribute but did not explicitly
restore the sys.modules['comfy_extras.nodes_seedvr'] entry. While
patch.dict's clear-and-restore semantics would actually undo the
finally-block pop on with-exit, that behavior is not obvious to a
reader and the intent is better expressed as an explicit
capture-before-patch / restore-in-finally pair, exactly mirroring the
existing handling of the comfy.model_management and
comfy_extras.nodes_seedvr package attributes.

Capture prior_comfy_extras_seedvr_module = sys.modules.get(...) before
the patch.dict block. In finally, if the prior value was the sentinel
(absent before the test) pop the entry; otherwise restore the prior
module object directly into sys.modules. The sys.modules pop inside
finally is replaced by this explicit conditional restore; the
sys.modules.pop before the try stays — that pop is functionally
required so importlib.import_module re-imports under the mock instead
of returning a cached real module.

References:
  #24 (comment) (codex round 2 [P2])
  #24 (comment) (Copilot id 3150906079)
@qa-agent-seveneves
Copy link
Copy Markdown

Codex Review -- Round 3 -- KICKOFF

Runner: scripts/run_codex_review.py
PR: #24
Reviewer model: codex review (configured codex CLI default)
Kickoff timestamp (UTC): 2026-04-28T00:39:30Z

Prompt sent to codex review

Review the latest state of https://github.com/pollockjj/ComfyUI/pull/24. Output findings using strict P0-P3 priority tags ([P0], [P1], [P2], [P3]) at the start of each finding title. Surface P0/P1/P2 -- these block merge in this repo. Surface P3 with that tag explicitly. Do not surface style nits, formatting, typos, or pre-existing bugs. End your output with a single line either 'APPROVE' (no P0/P1/P2 found) or 'REQUEST_CHANGES' (one or more P0/P1/P2 found). Output nothing else after that line.

Awaiting codex output. The result will be posted as a separate comment on this PR when codex exits.

@qa-agent-seveneves
Copy link
Copy Markdown

Codex Review -- Round 3 -- RESULT

PR: #24
Reviewer model: codex review (configured codex CLI default)
Result timestamp (UTC): 2026-04-28T00:41:30Z
Codex exit code: 0
Duration (s): 118.2
Detected verdict: UNKNOWN

Prompt sent to codex review

Review the latest state of https://github.com/pollockjj/ComfyUI/pull/24. Output findings using strict P0-P3 priority tags ([P0], [P1], [P2], [P3]) at the start of each finding title. Surface P0/P1/P2 -- these block merge in this repo. Surface P3 with that tag explicitly. Do not surface style nits, formatting, typos, or pre-existing bugs. End your output with a single line either 'APPROVE' (no P0/P1/P2 found) or 'REQUEST_CHANGES' (one or more P0/P1/P2 found). Output nothing else after that line.

Verbatim codex review output

This PR was reviewed using codex review with the prompt above and produced the following output:


No P0/P1/P2/P3 issues were found in the latest PR state.


Codex runner stderr (non-evidence)

OpenAI Codex v0.125.0 (research preview)
--------
workdir: /home/johnj/dev_cuda_1/mydevelopment
model: gpt-5.5
provider: openai
approval: never
sandbox: workspace-write [workdir, /tmp, $TMPDIR, /home/johnj/.codex/memories]
reasoning effort: high
reasoning summaries: none
session id: 019dd186-e7fa-7993-b545-96109321d497
--------
user
Review the latest state of https://github.com/pollockjj/ComfyUI/pull/24. Output findings using strict P0-P3 priority tags ([P0], [P1], [P2], [P3]) at the start of each finding title. Surface P0/P1/P2 -- these block merge in this repo. Surface P3 with that tag explicitly. Do not surface style nits, formatting, typos, or pre-existing bugs. End your output with a single line either 'APPROVE' (no P0/P1/P2 found) or 'REQUEST_CHANGES' (one or more P0/P1/P2 found). Output nothing else after that line.
mcp: codex_apps/github_fetch_pr started
mcp: codex_apps/github_fetch_pr (completed)
exec
/bin/bash -lc 'git -C /home/johnj/dev_cuda_1/ComfyUI status --short' in /home/johnj/dev_cuda_1/mydevelopment
 succeeded in 0ms:
exec
/bin/bash -lc 'git -C /home/johnj/dev_cuda_1/ComfyUI branch --show-current' in /home/johnj/dev_cuda_1/mydevelopment
 succeeded in 0ms:
seedvr-signature-regression-review

exec
/bin/bash -lc 'git -C /home/johnj/dev_cuda_1/ComfyUI rev-parse HEAD' in /home/johnj/dev_cuda_1/mydevelopment
 succeeded in 0ms:
f9938b9566400d37e824f1bc72e36fdad5ad59f9

exec
/bin/bash -lc 'nl -ba tests-unit/comfy_extras_test/test_seedvr_node_signature.py' in /home/johnj/dev_cuda_1/ComfyUI
 succeeded in 0ms:
     1	"""Regression test: SeedVR2InputProcessing schema input ids must match
     2	execute() positional parameter order. Drift between the two would silently
     3	swap arguments at runtime; this test fails loudly on any future drift.
     4	
     5	The schema input attribute is `.id` (verified live via Python introspection
     6	on the upstream class -- there is no `.name`).
     7	
     8	`comfy.model_management` is stubbed via `patch.dict(sys.modules, ...)` for
     9	the import performed inside this test, so importing
    10	`comfy_extras.nodes_seedvr` here does not call
    11	`torch.cuda.is_available()` or trigger other GPU/server-side
    12	initialization through that dependency. Live introspection indicated that
    13	`comfy_extras.nodes_seedvr` pulls in `comfy.model_management`
    14	transitively here (not `nodes`, not `server`).
    15	
    16	The test snapshots three pieces of import state before patching and
    17	restores all three in `finally` via a sentinel:
    18	
    19	1. `sys.modules["comfy_extras.nodes_seedvr"]`
    20	2. `comfy.model_management` package attribute on the `comfy` package
    21	3. `comfy_extras.nodes_seedvr` attribute on the `comfy_extras` package
    22	
    23	If any of the three was set before the test, it is restored verbatim;
    24	if it was unset, it is deleted on exit. This prevents the test from
    25	clobbering a real `comfy.model_management` (or
    26	`comfy_extras.nodes_seedvr`) module that another test may have
    27	legitimately imported earlier in the same pytest process, while still
    28	preventing the test's mock from leaking into later tests that import
    29	the real `comfy_extras.nodes_seedvr`."""
    30	
    31	import importlib
    32	import inspect
    33	import sys
    34	from unittest.mock import MagicMock, patch
    35	
    36	
    37	def test_seedvr_node_signature_matches_schema():
    38	    mock_model_management = MagicMock()
    39	    sentinel = object()
    40	
    41	    comfy_module_pre = sys.modules.get("comfy")
    42	    comfy_extras_module_pre = sys.modules.get("comfy_extras")
    43	    prior_comfy_mm_attr = (
    44	        getattr(comfy_module_pre, "model_management", sentinel)
    45	        if comfy_module_pre is not None
    46	        else sentinel
    47	    )
    48	    prior_comfy_extras_seedvr_attr = (
    49	        getattr(comfy_extras_module_pre, "nodes_seedvr", sentinel)
    50	        if comfy_extras_module_pre is not None
    51	        else sentinel
    52	    )
    53	    prior_comfy_extras_seedvr_module = sys.modules.get("comfy_extras.nodes_seedvr", sentinel)
    54	
    55	    with patch.dict(sys.modules, {"comfy.model_management": mock_model_management}):
    56	        sys.modules.pop("comfy_extras.nodes_seedvr", None)
    57	        try:
    58	            nodes_seedvr = importlib.import_module("comfy_extras.nodes_seedvr")
    59	            schema_ids = [i.id for i in nodes_seedvr.SeedVR2InputProcessing.define_schema().inputs]
    60	            exec_params = [
    61	                p
    62	                for p in inspect.signature(nodes_seedvr.SeedVR2InputProcessing.execute).parameters.keys()
    63	                if p != "cls"
    64	            ]
    65	            assert schema_ids == exec_params, (
    66	                f"SeedVR2InputProcessing schema input ids do not match execute() "
    67	                f"parameter order: schema_ids={schema_ids}, exec_params={exec_params}"
    68	            )
    69	        finally:
    70	            if prior_comfy_extras_seedvr_module is sentinel:
    71	                sys.modules.pop("comfy_extras.nodes_seedvr", None)
    72	            else:
    73	                sys.modules["comfy_extras.nodes_seedvr"] = prior_comfy_extras_seedvr_module
    74	            comfy_extras_module = sys.modules.get("comfy_extras")
    75	            if comfy_extras_module is not None:
    76	                if prior_comfy_extras_seedvr_attr is sentinel:
    77	                    if hasattr(comfy_extras_module, "nodes_seedvr"):
    78	                        delattr(comfy_extras_module, "nodes_seedvr")
    79	                else:
    80	                    setattr(comfy_extras_module, "nodes_seedvr", prior_comfy_extras_seedvr_attr)
    81	            comfy_module = sys.modules.get("comfy")
    82	            if comfy_module is not None:
    83	                if prior_comfy_mm_attr is sentinel:
    84	                    if hasattr(comfy_module, "model_management"):
    85	                        delattr(comfy_module, "model_management")
    86	                else:
    87	                    setattr(comfy_module, "model_management", prior_comfy_mm_attr)

exec
/bin/bash -lc "sed -n '1,140p' comfy_extras/nodes_seedvr.py" in /home/johnj/dev_cuda_1/ComfyUI
 succeeded in 0ms:
from typing_extensions import override
from comfy_api.latest import ComfyExtension, io
import torch
import math
from einops import rearrange

import gc
import comfy.model_management

import torch.nn.functional as F
from torchvision.transforms import functional as TVF
from torchvision.transforms import Lambda, Normalize
from torchvision.transforms.functional import InterpolationMode


def clear_vae_memory(vae_model):
    for module in vae_model.modules():
        if hasattr(module, "memory"):
            module.memory = None
    gc.collect()
    torch.cuda.empty_cache()

def expand_dims(tensor, ndim):
    shape = tensor.shape + (1,) * (ndim - tensor.ndim)
    return tensor.reshape(shape)

def get_conditions(latent, latent_blur):
    t, h, w, c = latent.shape
    cond = torch.ones([t, h, w, c + 1], device=latent.device, dtype=latent.dtype)
    cond[:, ..., :-1] = latent_blur[:]
    cond[:, ..., -1:] = 1.0
    return cond

def timestep_transform(timesteps, latents_shapes):
    vt = 4
    vs = 8
    frames = (latents_shapes[:, 0] - 1) * vt + 1
    heights = latents_shapes[:, 1] * vs
    widths = latents_shapes[:, 2] * vs

    # Compute shift factor.
    def get_lin_function(x1, y1, x2, y2):
        m = (y2 - y1) / (x2 - x1)
        b = y1 - m * x1
        return lambda x: m * x + b

    img_shift_fn = get_lin_function(x1=256 * 256, y1=1.0, x2=1024 * 1024, y2=3.2)
    vid_shift_fn = get_lin_function(x1=256 * 256 * 37, y1=1.0, x2=1280 * 720 * 145, y2=5.0)
    shift = torch.where(
        frames > 1,
        vid_shift_fn(heights * widths * frames),
        img_shift_fn(heights * widths),
    ).to(timesteps.device)

    # Shift timesteps.
    T = 1000.0
    timesteps = timesteps / T
    timesteps = shift * timesteps / (1 + (shift - 1) * timesteps)
    timesteps = timesteps * T
    return timesteps

def inter(x_0, x_T, t):
    t = expand_dims(t, x_0.ndim)
    T = 1000.0
    B = lambda t: t / T
    A = lambda t: 1 - (t / T)
    return A(t) * x_0 + B(t) * x_T
def area_resize(image, max_area):

    height, width = image.shape[-2:]
    scale = math.sqrt(max_area / (height * width))

    resized_height, resized_width = round(height * scale), round(width * scale)

    return TVF.resize(
        image,
        size=(resized_height, resized_width),
        interpolation=InterpolationMode.BICUBIC,
    )

def div_pad(image, factor):

    height_factor, width_factor = factor
    height, width = image.shape[-2:]

    pad_height = (height_factor - (height % height_factor)) % height_factor
    pad_width = (width_factor - (width % width_factor)) % width_factor

    if pad_height == 0 and pad_width == 0:
        return image

    if isinstance(image, torch.Tensor):
        padding = (0, pad_width, 0, pad_height)
        image = torch.nn.functional.pad(image, padding, mode='constant', value=0.0)

    return image

def cut_videos(videos):
    t = videos.size(1)
    if t == 1:
        return videos
    if t <= 4 :
        padding = [videos[:, -1].unsqueeze(1)] * (4 - t + 1)
        padding = torch.cat(padding, dim=1)
        videos = torch.cat([videos, padding], dim=1)
        return videos
    if (t - 1) % (4) == 0:
        return videos
    else:
        padding = [videos[:, -1].unsqueeze(1)] * (
            4 - ((t - 1) % (4))
        )
        padding = torch.cat(padding, dim=1)
        videos = torch.cat([videos, padding], dim=1)
        assert (videos.size(1) - 1) % (4) == 0
        return videos

def side_resize(image, size):
    antialias = not (isinstance(image, torch.Tensor) and image.device.type == 'mps')
    resized = TVF.resize(image, size, InterpolationMode.BICUBIC, antialias=antialias)
    return resized

class SeedVR2InputProcessing(io.ComfyNode):
    @classmethod
    def define_schema(cls):
        return io.Schema(
            node_id = "SeedVR2InputProcessing",
            category="image/video",
            inputs = [
                io.Image.Input("images"),
                io.Vae.Input("vae"),
                io.Int.Input("resolution", default = 1280, min = 120), # just non-zero value
                io.Int.Input("spatial_tile_size", default = 512, min = 1),
                io.Int.Input("spatial_overlap", default = 64, min = 1),
                io.Int.Input("temporal_tile_size", default=5, min=1, max=16384, step=4),
                io.Boolean.Input("enable_tiling", default=False),
            ],
            outputs = [
                io.Latent.Output("vae_conditioning")
            ]

exec
/bin/bash -lc '.venv/bin/pytest tests-unit/comfy_extras_test/test_seedvr_node_signature.py -v' in /home/johnj/dev_cuda_1/ComfyUI
 succeeded in 2749ms:
============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-9.0.3, pluggy-1.6.0 -- /home/johnj/dev_cuda_1/ComfyUI/.venv/bin/python3.12
cachedir: .pytest_cache
rootdir: /home/johnj/dev_cuda_1/ComfyUI
configfile: pytest.ini
plugins: asyncio-1.3.0, aiohttp-1.1.0, anyio-4.13.0
asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collecting ... collected 1 item

tests-unit/comfy_extras_test/test_seedvr_node_signature.py::test_seedvr_node_signature_matches_schema PASSED

=============================== warnings summary ===============================
.venv/lib/python3.12/site-packages/_pytest/cacheprovider.py:475
  /home/johnj/dev_cuda_1/ComfyUI/.venv/lib/python3.12/site-packages/_pytest/cacheprovider.py:475: PytestCacheWarning: cache could not write path /home/johnj/dev_cuda_1/ComfyUI/.pytest_cache/v/cache/nodeids: [Errno 30] Read-only file system: '/home/johnj/dev_cuda_1/ComfyUI/.pytest_cache/v/cache/nodeids'
    config.cache.set("cache/nodeids", sorted(self.cached_nodeids))

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
========================= 1 passed, 1 warning in 1.65s =========================

exec
/bin/bash -lc 'git -C /home/johnj/dev_cuda_1/ComfyUI diff --stat issue_101...HEAD' in /home/johnj/dev_cuda_1/mydevelopment
 succeeded in 0ms:
 .../test_seedvr_node_signature.py                  | 87 ++++++++++++++++++++++
 1 file changed, 87 insertions(+)

exec
/bin/bash -lc '.venv/bin/python -m pytest tests-unit/comfy_extras_test/test_seedvr_node_signature.py tests-unit/model_management_test/dummy.py' in /home/johnj/dev_cuda_1/ComfyUI
 exited 4 in 318ms:
============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-9.0.3, pluggy-1.6.0
rootdir: /home/johnj/dev_cuda_1/ComfyUI
configfile: pytest.ini
plugins: asyncio-1.3.0, aiohttp-1.1.0, anyio-4.13.0
asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collected 0 items

=============================== warnings summary ===============================
.venv/lib/python3.12/site-packages/_pytest/cacheprovider.py:475
  /home/johnj/dev_cuda_1/ComfyUI/.venv/lib/python3.12/site-packages/_pytest/cacheprovider.py:475: PytestCacheWarning: cache could not write path /home/johnj/dev_cuda_1/ComfyUI/.pytest_cache/v/cache/nodeids: [Errno 30] Read-only file system: '/home/johnj/dev_cuda_1/ComfyUI/.pytest_cache/v/cache/nodeids'
    config.cache.set("cache/nodeids", sorted(self.cached_nodeids))

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
============================== 1 warning in 0.00s ==============================
ERROR: file or directory not found: tests-unit/model_management_test/dummy.py


mcp: github/run_secret_scanning started
mcp: github/run_secret_scanning (failed)
mcp: codex_apps/github_fetch_pr started
mcp: codex_apps/github_fetch_pr (completed)
codex
No P0/P1/P2/P3 issues were found in the latest PR state.
2026-04-28T00:41:30.050459Z ERROR codex_core::session: failed to record rollout items: thread 019dd186-e81e-7d42-9221-a2ad2f6fe358 not found
2026-04-28T00:41:30.076665Z ERROR codex_core::session: failed to record rollout items: thread 019dd186-e7fa-7993-b545-96109321d497 not found

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@qa-agent-seveneves
Copy link
Copy Markdown

Codex Review -- Round 1 -- KICKOFF

Runner: scripts/run_codex_review.py
PR: #24
Reviewer model: codex review (configured codex CLI default)
Kickoff timestamp (UTC): 2026-05-01T16:05:31Z

Prompt sent to codex review

Review the latest state of https://github.com/pollockjj/ComfyUI/pull/24. Output findings using strict P0-P3 priority tags ([P0], [P1], [P2], [P3]) at the start of each finding title. Surface P0/P1/P2 -- these block merge in this repo. Surface P3 with that tag explicitly. Do not surface style nits, formatting, typos, or pre-existing bugs. End your output with a single line either 'APPROVE' (no P0/P1/P2 found) or 'REQUEST_CHANGES' (one or more P0/P1/P2 found). Output nothing else after that line.

Awaiting codex output. The result will be posted as a separate comment on this PR when codex exits.

@pollockjj
Copy link
Copy Markdown
Owner Author

Superseded by #30 — consolidated into a single test PR against the clean issue_101_pi base. Old head branch (seedvr-signature-regression-review) was forked from polluted ancestor of issue_101 and presented as a 5,800-line spurious diff against the reset base. The 7 SeedVR2InputProcessing schema-regression test commits from this branch are preserved in #30.

@pollockjj pollockjj closed this May 1, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 41 out of 44 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +3
"""Regression test: SeedVR2InputProcessing schema input ids must match
execute() positional parameter order. Drift between the two would silently
swap arguments at runtime; this test fails loudly on any future drift.
Comment thread comfy/latent_formats.py
Comment on lines 758 to 761
Comment on lines 722 to 746
Comment thread comfy/ldm/seedvr/model.py
Comment on lines 1387 to 1393
pollockjj added a commit that referenced this pull request May 1, 2026
SeedVR2 native PR regression tests (consolidates #21, #22, #24 onto issue_101_pi)
@pollockjj pollockjj deleted the seedvr-signature-regression-review branch May 1, 2026 16:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants