Skip to content

Issue #116: SeedVR2 VAE tiled_args non-mutation regression test#22

Closed
pollockjj wants to merge 6 commits into
issue_101from
issue_116
Closed

Issue #116: SeedVR2 VAE tiled_args non-mutation regression test#22
pollockjj wants to merge 6 commits into
issue_101from
issue_116

Conversation

@pollockjj
Copy link
Copy Markdown
Owner

Tracking issue

pollockjj/mydevelopment#116 — Verify SeedVR2 tiled_args decode state is not mutated

Final QA PASS

Affected repository row

Repository Path Base Branch Issue Branch
pollockjj/ComfyUI $HOME/dev_cuda_0/ComfyUI issue_101 issue_116

Summary

Adds one new file: tests-unit/comfy_test/test_seedvr_vae_tiled_args_no_mutate.py. The test reads comfy/ldm/seedvr/vae.py as text via pathlib.Path(__file__).resolve().parents[2], asserts .tiled_args.pop( is absent and .tiled_args.get( is present, and locks in the upstream fix from Comfy-Org/ComfyUI#11294 commit 3b418da. No production source modified. No imports of comfy.ldm.seedvr.vae. No unittest.mock stubbing. No print().

Validation

  • Unmutated issue_116 HEAD 9a9efdbec: pytest tests-unit/comfy_test/test_seedvr_vae_tiled_args_no_mutate.py -v exits 0; evidence in pollockjj/mydevelopment github_issues/116/slice2/pytest_pass.log.
  • Mutation A/B (distinct SHAs): a temporary local-only branch swapping line 2256 .get.pop (SHA 219f6786f) FAILS pytest with exit 1 and assertion message containing tiled_args.pop; original issue_116 (SHA 9a9efdbec) PASSES with exit 0. Evidence in pollockjj/mydevelopment github_issues/116/slice2/mutation_proof.md.
  • Repo hygiene clean for both affected repos before QA submission. Evidence in github_issues/116/slice1/repo_hygiene.txt and github_issues/116/slice2/repo_hygiene.txt.

This PR does not

  • merge or auto-close the tracking issue
  • modify any production source under comfy/

It is opened as a draft for review per the PR-publication skill contract.

pollockjj and others added 6 commits April 23, 2026 09:23
Issue 130: Clean SeedVR2 native runtime fixes
Text-level pytest that reads comfy/ldm/seedvr/vae.py and asserts
.tiled_args.pop( is absent and .tiled_args.get( is present. Catches
drift back to dict-mutation semantics per upstream fix in
Comfy-Org#11294 commit 3b418da.

Refs: pollockjj/mydevelopment#116
@pollockjj pollockjj marked this pull request as ready for review April 28, 2026 00:20
Copilot AI review requested due to automatic review settings April 28, 2026 00:20
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 regression unit test to ensure SeedVR2 VAE decoding does not mutate tiled_args (i.e., guards against reintroducing tiled_args.pop(...) and expects tiled_args.get(...) per the referenced upstream fix).

Changes:

  • Add a new pytest test that reads comfy/ldm/seedvr/vae.py as text and asserts .tiled_args.pop( is absent.
  • Assert .tiled_args.get( is present to lock in the non-mutating access pattern.

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

Comment on lines +1 to +8
from pathlib import Path


def test_seedvr_vae_tiled_args_uses_get_not_pop():
path = Path(__file__).resolve().parents[2] / "comfy" / "ldm" / "seedvr" / "vae.py"
src = path.read_text(encoding="utf-8")
assert ".tiled_args.pop(" not in src, f"VideoAutoencoderKLWrapper.decode contains tiled_args.pop(...) which mutates self.tiled_args across calls; expected tiled_args.get(...) per the upstream fix in Comfy-Org/ComfyUI#11294 commit 3b418da. Source path: {path}"
assert ".tiled_args.get(" in src, f"VideoAutoencoderKLWrapper.decode does not read tiled_args via .get(); expected exactly one self.tiled_args.get(\"enable_tiling\", False) call per Slice 1 baseline. Source path: {path}"
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.

These substring checks scan the entire vae.py file, so the test could fail (or pass for the wrong reason) if .tiled_args.pop( / .tiled_args.get( appear in comments, strings, or other methods. To make the regression test more robust, consider extracting just VideoAutoencoderKLWrapper.decode (e.g., via ast parsing or a targeted regex slice) and assert on that method body only.

Suggested change
from pathlib import Path
def test_seedvr_vae_tiled_args_uses_get_not_pop():
path = Path(__file__).resolve().parents[2] / "comfy" / "ldm" / "seedvr" / "vae.py"
src = path.read_text(encoding="utf-8")
assert ".tiled_args.pop(" not in src, f"VideoAutoencoderKLWrapper.decode contains tiled_args.pop(...) which mutates self.tiled_args across calls; expected tiled_args.get(...) per the upstream fix in Comfy-Org/ComfyUI#11294 commit 3b418da. Source path: {path}"
assert ".tiled_args.get(" in src, f"VideoAutoencoderKLWrapper.decode does not read tiled_args via .get(); expected exactly one self.tiled_args.get(\"enable_tiling\", False) call per Slice 1 baseline. Source path: {path}"
import ast
from pathlib import Path
def _get_method_source(path: Path, class_name: str, method_name: str) -> str:
src = path.read_text(encoding="utf-8")
module = ast.parse(src)
lines = src.splitlines()
for node in module.body:
if isinstance(node, ast.ClassDef) and node.name == class_name:
for child in node.body:
if isinstance(child, ast.FunctionDef) and child.name == method_name:
return "\n".join(lines[child.lineno - 1:child.end_lineno])
raise AssertionError(f"Method {class_name}.{method_name} not found in source path: {path}")
raise AssertionError(f"Class {class_name} not found in source path: {path}")
def test_seedvr_vae_tiled_args_uses_get_not_pop():
path = Path(__file__).resolve().parents[2] / "comfy" / "ldm" / "seedvr" / "vae.py"
decode_src = _get_method_source(path, "VideoAutoencoderKLWrapper", "decode")
assert ".tiled_args.pop(" not in decode_src, f"VideoAutoencoderKLWrapper.decode contains tiled_args.pop(...) which mutates self.tiled_args across calls; expected tiled_args.get(...) per the upstream fix in Comfy-Org/ComfyUI#11294 commit 3b418da. Source path: {path}"
assert ".tiled_args.get(" in decode_src, f"VideoAutoencoderKLWrapper.decode does not read tiled_args via .get(); expected exactly one self.tiled_args.get(\"enable_tiling\", False) call per Slice 1 baseline. Source path: {path}"

Copilot uses AI. Check for mistakes.
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.

REJECT — the test design is fixed verbatim by the user's session-start directive: "The regression test is text-level: it locates vae.py via Path(file).resolve().parents[2] / comfy / ldm / seedvr / vae.py, reads it via path.read_text(encoding="utf-8"), and asserts ".tiled_args.pop(" is absent and ".tiled_args.get(" is present." The plan's Slice 2 AC-1 codifies the same form (text-level inspection of full source), and Slice 1 + Slice 2 QA gates posted by qa-agent-seveneves[bot] PASSed this exact assertion form (https://github.com/pollockjj/mydevelopment/issues/116#issuecomment-4330391259, https://github.com/pollockjj/mydevelopment/issues/116#issuecomment-4330429542). Switching to ast-method-extraction is a structural change away from the user's prescribed test design and the QA-PASSed artifact. The substring scope risk Copilot raises (and codex's matching [P3] advisory) is acknowledged but the user's directive explicitly chose full-source text-level over narrower scoping; per CLAUDE.md anti-pattern "Interpreting", cuda0 does not modify a verbatim user directive in PR review.

path = Path(__file__).resolve().parents[2] / "comfy" / "ldm" / "seedvr" / "vae.py"
src = path.read_text(encoding="utf-8")
assert ".tiled_args.pop(" not in src, f"VideoAutoencoderKLWrapper.decode contains tiled_args.pop(...) which mutates self.tiled_args across calls; expected tiled_args.get(...) per the upstream fix in Comfy-Org/ComfyUI#11294 commit 3b418da. Source path: {path}"
assert ".tiled_args.get(" in src, f"VideoAutoencoderKLWrapper.decode does not read tiled_args via .get(); expected exactly one self.tiled_args.get(\"enable_tiling\", False) call per Slice 1 baseline. Source path: {path}"
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 failure message says this should be "exactly one" self.tiled_args.get("enable_tiling", False) call, but the assertion only checks that the substring .tiled_args.get( appears at least once. If the intent is to lock in a single call (and/or the exact arguments), update the assertion to verify the exact call and its count (e.g., count occurrences or match the full string).

Suggested change
assert ".tiled_args.get(" in src, f"VideoAutoencoderKLWrapper.decode does not read tiled_args via .get(); expected exactly one self.tiled_args.get(\"enable_tiling\", False) call per Slice 1 baseline. Source path: {path}"
expected_call = 'self.tiled_args.get("enable_tiling", False)'
assert src.count(expected_call) == 1, f'VideoAutoencoderKLWrapper.decode must contain exactly one {expected_call} call per Slice 1 baseline. Source path: {path}'

Copilot uses AI. Check for mistakes.
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.

REJECT — the assertion logic matches the user's session-start directive verbatim: ".tiled_args.get( is present" → at-least-one presence check, NOT "exactly one". The failure-message text references the Slice 1 baseline observation ("exactly one ... per Slice 1 baseline") as descriptive context for what Slice 1 captured, not as an invariant the assertion enforces. The directive intentionally chose presence-check over count-check so the test guards against the specific drift class ".get → .pop" without coupling to call-count details that may legitimately change with future helper additions. Slice 2 QA gate (https://github.com/pollockjj/mydevelopment/issues/116#issuecomment-4330429542) PASSed this exact form. Per CLAUDE.md anti-pattern "Interpreting", cuda0 does not tighten the assertion past what the user's directive prescribed.

@qa-agent-seveneves
Copy link
Copy Markdown

Codex Review -- Round 1 -- KICKOFF

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

Prompt sent to codex review

Review the latest state of https://github.com/pollockjj/ComfyUI/pull/22. 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: #22
Reviewer model: codex review (configured codex CLI default)
Result timestamp (UTC): 2026-04-28T01:09:51Z
Codex exit code: 0
Duration (s): 61.5
Detected verdict: UNKNOWN

Prompt sent to codex review

Review the latest state of https://github.com/pollockjj/ComfyUI/pull/22. 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 added test does not introduce a merge-blocking functional failure; the only issue found is a non-blocking robustness problem in the test's scope.

Review comment:

  • [P3] Limit the substring check to the target decode method — /home/johnj/dev_cuda_0/ComfyUI/tests-unit/comfy_test/test_seedvr_vae_tiled_args_no_mutate.py:7-8
    Because this scans all of vae.py, an unrelated comment, string literal, or helper method containing .tiled_args.pop( would fail this regression test even when VideoAutoencoderKLWrapper.decode remains correct, and .tiled_args.get( elsewhere could satisfy the positive check for the wrong reason. Since the test is meant to guard decode, constrain the inspected source to that method body.

Codex runner stderr (non-evidence)

OpenAI Codex v0.125.0 (research preview)
--------
workdir: /home/johnj/dev_cuda_0/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: 019dd1a1-ba13-7923-8644-ac1fb585b66b
--------
user
Review the latest state of https://github.com/pollockjj/ComfyUI/pull/22. 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_0/mydevelopment
 succeeded in 0ms:
/home/johnj/dev_cuda_0/mydevelopment

exec
/bin/bash -lc 'git status --short --branch' in /home/johnj/dev_cuda_0/ComfyUI
 succeeded in 0ms:
## issue_116...origin/issue_116

exec
/bin/bash -lc 'git log --oneline --decorate -5' in /home/johnj/dev_cuda_0/ComfyUI
 succeeded in 0ms:
9a9efdbec (HEAD -> issue_116, origin/issue_116) tests-unit: regression for SeedVR2 VAE tiled_args non-mutation invariant
7936e591c (origin/issue_101, issue_101) Merge pull request #19 from pollockjj/issue_130_clean_seedvr2_native
8ab6eb074 Fix SeedVR2 Ruff unused import
1558a81e9 Remove SeedVR2 diagnostic tracing
26574f585 Fix SeedVR2 native VAE execution

exec
/bin/bash -lc 'git diff issue_101...issue_116 -- tests-unit/comfy_test/test_seedvr_vae_tiled_args_no_mutate.py' in /home/johnj/dev_cuda_0/ComfyUI
 succeeded in 0ms:
diff --git a/tests-unit/comfy_test/test_seedvr_vae_tiled_args_no_mutate.py b/tests-unit/comfy_test/test_seedvr_vae_tiled_args_no_mutate.py
new file mode 100644
index 000000000..77a902987
--- /dev/null
+++ b/tests-unit/comfy_test/test_seedvr_vae_tiled_args_no_mutate.py
@@ -0,0 +1,8 @@
+from pathlib import Path
+
+
+def test_seedvr_vae_tiled_args_uses_get_not_pop():
+    path = Path(__file__).resolve().parents[2] / "comfy" / "ldm" / "seedvr" / "vae.py"
+    src = path.read_text(encoding="utf-8")
+    assert ".tiled_args.pop(" not in src, f"VideoAutoencoderKLWrapper.decode contains tiled_args.pop(...) which mutates self.tiled_args across calls; expected tiled_args.get(...) per the upstream fix in Comfy-Org/ComfyUI#11294 commit 3b418da. Source path: {path}"
+    assert ".tiled_args.get(" in src, f"VideoAutoencoderKLWrapper.decode does not read tiled_args via .get(); expected exactly one self.tiled_args.get(\"enable_tiling\", False) call per Slice 1 baseline. Source path: {path}"

exec
/bin/bash -lc 'grep -n "tiled_args" comfy/ldm/seedvr/vae.py' in /home/johnj/dev_cuda_0/ComfyUI
 succeeded in 0ms:
2256:        self.enable_tiling = self.tiled_args.get("enable_tiling", False)
2259:            x = tiled_vae(latent, self, **self.tiled_args, encode=False).squeeze(2)

codex
The added test does not introduce a merge-blocking functional failure; the only issue found is a non-blocking robustness problem in the test's scope.

Review comment:

- [P3] Limit the substring check to the target decode method — /home/johnj/dev_cuda_0/ComfyUI/tests-unit/comfy_test/test_seedvr_vae_tiled_args_no_mutate.py:7-8
  Because this scans all of `vae.py`, an unrelated comment, string literal, or helper method containing `.tiled_args.pop(` would fail this regression test even when `VideoAutoencoderKLWrapper.decode` remains correct, and `.tiled_args.get(` elsewhere could satisfy the positive check for the wrong reason. Since the test is meant to guard `decode`, constrain the inspected source to that method body.
2026-04-28T01:09:50.787623Z ERROR codex_core::session: failed to record rollout items: thread 019dd1a1-ba33-7853-8793-2adbb8dd9460 not found
2026-04-28T01:09:50.809385Z ERROR codex_core::session: failed to record rollout items: thread 019dd1a1-ba13-7923-8644-ac1fb585b66b not found

@qa-agent-seveneves
Copy link
Copy Markdown

Codex Review -- Round 1 -- KICKOFF

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

Prompt sent to codex review

Review the latest state of https://github.com/pollockjj/ComfyUI/pull/22. 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 (issue_116) was forked from polluted ancestor of issue_101 and presented as a 5,800-line spurious diff against the reset base. The VAE tiled_args non-mutation test commit from this branch is 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 6 comments.


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

Comment thread comfy/ldm/seedvr/vae.py
Comment on lines 24 to 30
@torch.inference_mode()
def tiled_vae(x, vae_model, tile_size=(512, 512), tile_overlap=(64, 64), temporal_size=16, encode=True, **kwargs):

gc.collect()
torch.cuda.empty_cache()

x = x.to(next(vae_model.parameters()).dtype)
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

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

This function unconditionally calls gc.collect() and torch.cuda.empty_cache() at the start of every tiled encode/decode. For typical inference this can substantially hurt performance, and torch.cuda.empty_cache() can also raise on non-CUDA builds (or be incorrect on non-CUDA devices). Prefer using comfy.model_management.soft_empty_cache() (device-aware) and/or only clearing caches when handling an OOM / at well-defined boundaries rather than on every call.

Copilot uses AI. Check for mistakes.
Comment on lines 16 to 22
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()

Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

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

clear_vae_memory calls torch.cuda.empty_cache() unconditionally. That can raise on CPU-only / non-CUDA builds and is not correct for non-CUDA devices (MPS/XPU/etc). This codebase already has comfy.model_management.soft_empty_cache() for device-aware cache clearing—please use that (or at least guard with torch.cuda.is_available()).

Copilot uses AI. Check for mistakes.
images_bcthw = rearrange(images, "b t c h w -> b c t h w")
images_bthwc = rearrange(images, "b t c h w -> b t h w c")

# in case users a non-compatiable number for tiling
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

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

Typo in comment: "non-compatiable" → "non-compatible".

Copilot uses AI. Check for mistakes.
Comment thread nodes.py
"nodes_camera_trajectory.py",
"nodes_edit_model.py",
"nodes_tcfg.py",
"nodes_seedvr.py",
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

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

The PR description says no production source under comfy/ is modified and only a single unit test file is added, but this change adds nodes_seedvr.py to the builtin extra node load list (and the PR also includes multiple production code additions/edits elsewhere). Please update the PR description to reflect the actual scope, or split the SeedVR2 integration into a separate PR from the regression test so reviewers can evaluate risk appropriately.

Copilot uses AI. Check for mistakes.
Comment thread comfy/latent_formats.py
Comment on lines 758 to 760
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

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

latent_dimensions is used as a small enum-like value (e.g. 2 for BCHW images, 3 for BCTHW videos) and is checked explicitly in comfy/sample.py (only == 3 triggers an unsqueeze). Setting SeedVR2.latent_dimensions = 16 looks inconsistent with the rest of the latent formats and will likely break shape handling for empty latents / video latents. This should probably be 3 (video) or 2 (if SeedVR2 truly uses BCHW latents), but not 16.

Copilot uses AI. Check for mistakes.
Comment on lines 722 to 733
Copy link

Copilot AI May 1, 2026

Choose a reason for hiding this comment

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

var_attention_pytorch relies on torch.nested.nested_tensor_from_jagged, but this repo does not pin a minimum PyTorch version in requirements.txt and that API is not present in all supported Torch builds. As written, importing/using SeedVR2 can hard-crash at runtime with AttributeError on some environments. Consider guarding with hasattr(torch.nested, "nested_tensor_from_jagged") (or a version check) and falling back to a non-varlen attention path (or raising a clear error) when it’s unavailable.

Copilot uses AI. Check for mistakes.
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 issue_116 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