Skip to content

[Issue 101][eval-and-fix] Keep batch/time axes distinct for single-frame decode (closes pollockjj/mydevelopment#189)#34

Merged
pollockjj merged 4 commits into
issue_101from
issue_189
May 4, 2026
Merged

[Issue 101][eval-and-fix] Keep batch/time axes distinct for single-frame decode (closes pollockjj/mydevelopment#189)#34
pollockjj merged 4 commits into
issue_101from
issue_189

Conversation

@pollockjj
Copy link
Copy Markdown
Owner

@pollockjj pollockjj commented May 4, 2026

Scope addendum (post-review, 2026-05-04): PR review surfaced an adjacent defect on the tiled-decode path that was outside the original Issue 189 plan. The original plan covered only the non-tiled super().decode_(latent) path and a six-test regression module. Codex P2 finding #3184515755 and Copilot finding #3184469104 on commit 8f0d56ed showed that tiled_vae() (vae.py:179-180) explicitly squeezes the temporal axis when temporal_downsample_factor == 1 AND latent T == 1, so the patch's removal of the x.ndim == 4 normalization broke the tiled+sf_t==1+T_lat==1 path with an EinopsError. Commit 3b3c1502 re-adds the 4D→5D normalization scoped to the tiled branch only, plus regression test test_decode_tiled_sf_t1_single_frame_4d_output_normalized. Copilot follow-up #3184602213 asked for B>1 coverage on the tiled path; commit e19bece0 adds test_decode_tiled_sf_t1_b2_t1_per_sample_ordering. Total regression module is now 8 tests (6 non-tiled per original plan + 2 tiled-path additions). The original plan body follows below unchanged.


Plan: Keep batch/time axes distinct for single-frame batched decode

Overview

The SeedVR2 native VAE wrapper comfy.ldm.seedvr.vae.VideoAutoencoderKLWrapper.decode corrupts batched image-mode decode output when B > 1 and T == 1. The decoder's 5D output [B, C, 1, H, W] is flattened by super().decode_(latent).squeeze(2) to [B, C, H, W]; the existing if x.ndim == 4: x = x.unsqueeze(0) block then makes the tensor [1, B, C, H, W], after which the x.size(1) == 1 gate routes batched cases through the wrong rearrange expression that re-interprets the batch axis as channels and the channel axis as time. The result for B=2, T=1 is [1, 2, 2, H, W] instead of [1, 3, 2, H, W]; for B=4, T=1 it is [1, 4, 3, H, W] instead of [1, 3, 4, H, W]. The latent-side prep block immediately above (b, tc, h, w = z.shape; latent = z.view(b, 16, -1, h, w); ...) was already corrected upstream by commit af6c5d6 and is OUT OF SCOPE; this plan asserts it byte-identical to base as a stop-condition guard. The plan first records the pre-fix shape signature on pollockjj/ComfyUI:issue_101 HEAD as a baseline decision packet, then lands the output-side fix on pollockjj/ComfyUI:issue_189 together with a five-case regression test (B ∈ {1, 2, 4} × T_orig ∈ {1, 3, 5}) and a stacked-vs-individual per-sample-ordering test, re-runs the same probe to record the corrected shapes, applies a hygiene gate (ruff + production-code-shape independence), and emits a post-fix provenance decision packet. PR creation from issue_189 into issue_101 is delegated to the /pr skill after slice completion.

Diagnosis Summary

  • Failure signature. On pollockjj/ComfyUI:issue_101 HEAD 4e8836ed, calling VideoAutoencoderKLWrapper.decode(z) with z.shape == (B, 16, H, W) (image-mode latent, T_orig=1) for B > 1 returns a tensor whose final shape contains the batch count B in the channel axis and the channel count C (3 for RGB) in the time axis. Live probe (Phase 0): B=2, T_orig=1 → output shape (1, 2, 2, 16, 16) (correct shape would be (1, 3, 2, 16, 16)); B=4, T_orig=1 → output shape (1, 4, 3, 16, 16) (correct shape would be (1, 3, 4, 16, 16)). The per-batch fingerprint values that the probe injects via the mocked decode_ (float(b + 1) for batch index b) appear in the size-2 (resp. size-4) axis instead of the size-2 (resp. size-4) time axis they belong in.
  • Reproduction. From /home/johnj/dev_cuda_1/ComfyUI on issue_101 HEAD with the ComfyUI venv active: import comfy.ldm.seedvr.vae, monkey-patch VideoAutoencoderKL.decode_ to a fingerprint-tagged stub returning [B, 3, T_dec, H_in*8, W_in*8] filled with float(b + 1) per batch index, monkey-patch lab_color_transfer to a passthrough, construct a wrapper instance via VideoAutoencoderKLWrapper.__new__(VideoAutoencoderKLWrapper) + nn.Module.__init__(instance) with tiled_args = {"enable_tiling": False}, original_image_video = torch.zeros(B, 3, T_orig, 16, 16), img_dims = (16, 16), then call wrapper.decode(torch.zeros(B, 16*T_orig, 2, 2)). For (B=2, T_orig=1) the output shape is (1, 2, 2, 16, 16); for (B=4, T_orig=1) the output shape is (1, 4, 3, 16, 16). Live-probed Phase 0; bug reproduces deterministically.
  • Root cause. The output-side post-decode_ block in VideoAutoencoderKLWrapper.decode applies .squeeze(2) to the 5D [B, C, T_dec, H, W] decoder output. When T_dec == 1 the tensor collapses to [B, C, H, W] (4D). The next gate if x.ndim == 4: x = x.unsqueeze(0) adds a new outer axis at position 0, producing [1, B, C, H, W]. The subsequent gate if x.size(1) == 1: exp = "b t c h w -> (b t) c h w" else: exp = "b c t h w -> (b t) c h w" then mis-interprets the axes for B > 1 (because x.size(1) == B != 1), routing through b c t h w -> (b t) c h w which treats the new outer 1 as b, the batch count B as c, and the channel count C as t. The final reshape to [1, C, B*T_orig, H, W] therefore produces [1, B, C, H, W] (axes swapped). The B == 1, T_orig == 1 path accidentally works because x.size(1) == 1 matches the b t c h w -> (b t) c h w expression which collapses the leading two 1s to a single 1. The T_orig > 1 paths work because .squeeze(2) is a no-op when T_dec > 1 and the tensor stays 5D, bypassing the buggy unsqueeze(0) branch entirely.
  • Failure boundary. The bug is reachable iff (a) B > 1 AND (b) the decoder's temporal output T_dec == 1 (image-mode reconstruction). The T_orig > 1 paths and the B == 1, T_orig == 1 path are unaffected — they have their own complete coverage in the existing tile/non-tile decode paths and are exercised by the existing test surface (tests-unit/comfy_test/test_seedvr_vae_tiled_args_no_mutate.py for tiled-args invariant; the live B=1, T=5 and B=2, T=3 probe results show the working shapes).
  • Proposed fix. The slicer must restore the post-decode_ invariant that the tensor remains 5D [B, C, T_dec, H, W] (or equivalently [B, C, T_out, H, W] after time-dim trimming) through the entire post-processing pipeline regardless of T_dec, so that the per-sample axis stays at position 0 and the channel axis stays at position 1 before the final b t c h w -> b c t h w reshape. The plan does not prescribe the exact source-line edit (the slicer chooses); the plan asserts the observable post-fix behavior (output shape (1, 3, B*T_orig, H, W) for every cell; per-sample fingerprint at the post-fix-correct batch position) and the structural stop-condition guard (latent-side prep block lines unchanged from base).
  • Verification strategy. Slice 1 runs a CPU-only Python probe against issue_101 HEAD (no fix applied) and records per-(B, T_orig)-cell shape, dtype, and per-batch fingerprint axis value into a JSON named-key artifact, capturing the buggy shapes for the B > 1, T_orig == 1 cells. Slice 2 lands the source fix on pollockjj/ComfyUI:issue_189, adds the regression test module, re-runs the same probe to record the corrected shapes, and emits a before/after delta artifact whose shape_mismatch_count named key drops from ≥ 2 to 0. Slice 3 runs ruff and a no-detuning grep over the touched files. Slice 4 binds the issue branch HEADs, canonical-reference URLs, and verbatim invocation commands into an architect-readable provenance markdown.

Affected Repositories

Repository Path Base Branch Issue Branch
pollockjj/mydevelopment /home/johnj/dev_cuda_1/mydevelopment main issue_189
pollockjj/ComfyUI /home/johnj/dev_cuda_1/ComfyUI issue_101 issue_189

Research and Methodology

Plan Foundations Comment URL: https://github.com/pollockjj/mydevelopment/issues/189#issuecomment-4368270401

Detected Scope: none — single-block shape-handling fix in VideoAutoencoderKLWrapper.decode where the existing working B==1, T==1, B==1, T>1, and B>1, T>1 paths ARE the spec; the patch aligns the broken B>1, T==1 path to that same spec without introducing any new metric or methodology.

The linked comment is the load-bearing artifact for every measurement, equivalence rule, canonical-protocol, tool version, and pipeline-stage citation in this plan. Every AC below that names a metric, threshold, equivalence rule, canonical protocol, tool version, or pipeline stage traces by quote or URL to an entry in that comment's ## Research and Methodology section. qa-plan verifies the comment exists and contains the required subsections for the detected scope.

Tools, Pipeline, and Measurements

Plan Foundations Comment URL: https://github.com/pollockjj/mydevelopment/issues/189#issuecomment-4368270401

The linked comment's ## Tools, Pipeline, and Measurements section enumerates: (1) Existing Tooling Inventory with REUSE / KNOWN-GOOD-REF / NEW / WAIVED status per tool; (2) Pipeline stages from input to output artifact; (3) Measurements table with tool+version, invocation, score range, tolerance; (4) Single-probe-before-sweep / boundary-bracketing requirements (both N/A for this plan and explicitly justified). Every AC below that names a tool, version, pipeline stage, or measurement traces by quote or URL to an entry in that section.

Ground Truth Probes

For every literal API surface that any AC references — attribute, method, function signature, parameter list, CLI flag, file path, env var, magic constant — captured live on the issue's base branch pollockjj/ComfyUI:issue_101 (HEAD 4e8836ed) on 2026-05-04 from /home/johnj/dev_cuda_1/ComfyUI. Plan-introduced literals (probe JSON keys, test names, paths created by this plan) are anchored separately in ## Created Surface Contract, not here.

Probe ID Consumed by AC(s) Probe command Observed output (verbatim)
GTP-1 S1 AC-2, S2 AC-2, S2 AC-4 cd /home/johnj/dev_cuda_1/ComfyUI && python -c "from comfy.cli_args import args; args.cpu=True; import comfy.ldm.seedvr.vae as v, inspect; print(inspect.signature(v.VideoAutoencoderKLWrapper.decode)); print(inspect.signature(v.VideoAutoencoderKL.decode_)); print([c.__name__ for c in v.VideoAutoencoderKLWrapper.__mro__])" (self, z) / (self, z: torch.Tensor, return_dict: bool = True) / ['VideoAutoencoderKLWrapper', 'VideoAutoencoderKL', 'Module', 'object']
GTP-2 S1 AC-2, S2 AC-2, S2 AC-4 cd /home/johnj/dev_cuda_1/ComfyUI && python -c "from comfy.cli_args import args; args.cpu=True; import comfy.ldm.seedvr.vae as v; print(v.lab_color_transfer); print(v.rearrange); print(v.tiled_vae)" <function lab_color_transfer at 0x...> / <function rearrange at 0x...> / <function tiled_vae at 0x...>
GTP-3 S1 AC-2, S2 AC-2, S2 AC-4 cd /home/johnj/dev_cuda_1/ComfyUI && python -c "from comfy.cli_args import args; print(type(args.cpu).__name__, args.cpu); args.cpu=True; print(args.cpu)" bool False / True
GTP-4 S1 AC-2, S2 AC-2, S2 AC-4 cd /home/johnj/dev_cuda_1/ComfyUI && python -c "from comfy.cli_args import args; args.cpu=True; import comfy.ldm.seedvr.vae as v, torch.nn as nn, torch; w=v.VideoAutoencoderKLWrapper.__new__(v.VideoAutoencoderKLWrapper); nn.Module.__init__(w); print(type(w).__name__); print(hasattr(w, 'tiled_args')); print(hasattr(w, 'original_image_video')); print(hasattr(w, 'img_dims'))" VideoAutoencoderKLWrapper / False / False / False (these attributes are populated in the wrapper's __init__; the test sets them manually after __new__ + nn.Module.__init__)
GTP-5 S1 AC-2, S2 AC-4 Live behavior probe captured Phase 0: cd /home/johnj/dev_cuda_1/ComfyUI && python followed by the inline reproduction script described in §Diagnosis Summary / Reproduction. Live raw outputs: (B=1, T_orig=1) → shape (1, 3, 1, 16, 16) ; (B=1, T_orig=5) → shape (1, 3, 5, 16, 16) ; (B=2, T_orig=1) → shape (1, 2, 2, 16, 16) ; (B=4, T_orig=1) → shape (1, 4, 3, 16, 16) ; (B=2, T_orig=3) → shape (1, 3, 6, 16, 16). The five lines above (verbatim live probe output captured 2026-05-04 against pollockjj/ComfyUI:issue_101 HEAD 4e8836ed). The cells (B=2,T_orig=1) and (B=4,T_orig=1) exhibit the bug: the channel position 1 holds the batch count instead of 3, and the time position 2 holds the RGB count instead of the batch count.
GTP-6 S1 AC-2, S2 AC-2, S2 AC-3, S3 AC-1 git -C /home/johnj/dev_cuda_1/ComfyUI rev-parse origin/issue_101; git -C /home/johnj/dev_cuda_1/ComfyUI ls-tree origin/issue_101 -- comfy/ldm/seedvr/vae.py 4e8836ed0a53467e9c433d58320c4992c9c34d2d / 100644 blob b3f0f5d719862ae119ebc037ab104bca7785ce71 comfy/ldm/seedvr/vae.py
GTP-7 S1 AC-2, S2 AC-3 ls /home/johnj/dev_cuda_1/ComfyUI/tests-unit/comfy_test/ folder_path_test.py / model_detection_test.py / __pycache__ / test_seedvr_groupnorm_limit.py / test_seedvr_rope_delegation.py / test_seedvr_vae_tiled_args_no_mutate.py
GTP-8 S2 AC-2 grep -nE 'args\.cpu = True|torch\.cuda\.is_available|patch\.object' /home/johnj/dev_cuda_1/ComfyUI/tests-unit/comfy_test/test_seedvr_groupnorm_limit.py 41:from unittest.mock import patch / 48:if not torch.cuda.is_available(): / 49: cli_args.cpu = True / 104: with patch.object(vae_mod.F, "group_norm", side_effect=_group_norm_spy): / 157: with patch.object(vae_mod.F, "group_norm", side_effect=_group_norm_spy):
GTP-9 S1 AC-2, S2 AC-2, S2 AC-4 cd /home/johnj/dev_cuda_1/ComfyUI && .venv/bin/pip list 2>/dev/null | grep -E "^(torch|einops)\\b"; .venv/bin/python -m pytest --version 2>&1 | head -1 einops 0.8.2 / torch 2.11.0+cu130 / pytest 9.0.3
GTP-10 S2 AC-1, S3 AC-1 cat /home/johnj/dev_cuda_1/ComfyUI/pytest.ini [pytest] / markers = / inference: mark as inference test (deselect with '-m "not inference"') / execution: mark as execution test (deselect with '-m "not execution"') / testpaths = / tests / tests-unit / addopts = -s / pythonpath = .
GTP-11 S1 AC-3, S4 AC-1 git -C /home/johnj/dev_cuda_1/mydevelopment rev-parse HEAD; git -C /home/johnj/dev_cuda_1/mydevelopment rev-parse --abbrev-ref HEAD 1e8218e23d2616060e41bf710bc196e6ea81fd4a / issue_189
GTP-12 S2 AC-1 sed -n '2245,2295p' /home/johnj/dev_cuda_1/ComfyUI/comfy/ldm/seedvr/vae.py (issue_101 HEAD source) The def decode(self, z): body starting at line 2245 — latent-side prep block at 2245-2253 (b, tc, h, w = z.shape / latent = z.view(b, 16, -1, h, w) / scale = 0.9152 / shift = 0 / latent = latent / scale + shift / blank / if latent.ndim == 4: / latent = latent.unsqueeze(2)); output-side block at 2255-2294 starting self.device = latent.device and ending with return x after the b t c h w -> b c t h w rearrange and the even-dims trim.
GTP-13 S3 AC-1, Asset Readiness ruff cd /home/johnj/dev_cuda_1/ComfyUI && python -m ruff --version; which ruff; git -C /home/johnj/dev_cuda_1/ComfyUI ls-tree origin/issue_101 -- .github/workflows/ruff.yml ruff 0.15.9 / /home/johnj/.local/bin/ruff / 100644 blob b24d86a6ba55b1f7b90539d6267a72afa5a7b73c .github/workflows/ruff.yml

If a planned literal cannot be probed (slot offline, source absent, tool missing) the AC is rewritten to remove the unverified literal or the slice is rescoped. No probe → no AC.

Created Surface Contract

These literals are introduced by this plan and therefore are NOT subject to Phase 0.5 ground-truth probing. They become probable after the slice that creates them lands.

Probe-script API (Slice 1 introduces; Slice 2 reuses): --out PATH CLI flag (writes UTF-8 JSON to PATH); --bt-cells PATH_OR_LITERAL CLI flag (semicolon-separated list of B,T_orig integer pairs, e.g. "1,1;1,5;2,1;4,1;2,3"; the probe iterates each cell and records its result); --label LABEL CLI flag (string written into the JSON's label key, e.g. "baseline" or "post_fix"); script exit code 0 on success; non-zero on any cell raising an unhandled exception.

Probe JSON named keys (Slice 1 introduces baseline; Slice 2 emits post-fix): Top-level: label (string), mydevelopment_head_sha (string), comfyui_head_sha (string), comfyui_branch (string), vae_blob_sha (string from git ls-tree HEAD -- comfy/ldm/seedvr/vae.py), bt_cells (list of {B, T_orig, T_dec, out_shape, out_dtype, channel_axis_value, time_axis_value, fingerprint_at_correct_batch_position} objects). Per-cell named keys: B (int), T_orig (int), T_dec (int), out_shape (list of int), out_dtype (string e.g. "torch.float32"), channel_axis_value (int — out_shape[1]), time_axis_value (int — out_shape[2]), fingerprint_at_correct_batch_position (list of float, length B*T_orig, value at index i is out[0, 0, i, 0, 0].item(); for the buggy cells this list is corrupted; for the correct cells it equals [float(b//T_orig + 1) for b in range(B*T_orig)] interleaved by T_orig).

Comparison JSON named keys (Slice 2 introduces): prior_artifact_path (string), new_artifact_path (string), prior_label (string), new_label (string), shape_mismatch_count_prior (int — number of cells whose out_shape differs from the per-cell expected (1, 3, B*T_orig, 16, 16)), shape_mismatch_count_new (int), per_cell_delta (list of {B, T_orig, prior_out_shape, new_out_shape, expected_out_shape, prior_pass, new_pass} objects).

Test names (Slice 2 introduces in tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.py): test_decode_b1_t1_shape_and_ordering_correct, test_decode_b1_t5_video_shape_unchanged, test_decode_b2_t1_fixes_batch_time_axes, test_decode_b4_t1_fixes_batch_time_axes, test_decode_b2_t3_multi_frame_batch_unchanged, test_decode_b2_t1_stacked_equals_individual_per_sample_ordering. All six functions live in module tests_unit.comfy_test.test_seedvr_vae_decode_batch_axes.

File paths (Slices 1–4 introduce):

  • pollockjj/mydevelopment#issue_189:
    • github_issues/189/probe_seedvr_decode_batch_axes.py (S1)
    • github_issues/189/slice1/decode_batch_axes_baseline.json (S1)
    • github_issues/189/slice1/probe_run.log (S1)
    • github_issues/189/slice1/probe_argparse_flags.log (S1 — grep evidence proving the probe script defines exactly the three CLI flags and zero extras)
    • github_issues/189/slice1/baseline_json_keys.log (S1 — python -m json.tool parse + sorted-key dump proving the baseline JSON's top-level and per-cell named-key sets match the contract verbatim)
    • github_issues/189/slice1/provenance.md (S1)
    • github_issues/189/slice2/decode_batch_axes_post_fix.json (S2)
    • github_issues/189/slice2/before_after_comparison.json (S2)
    • github_issues/189/slice2/probe_run.log (S2)
    • github_issues/189/slice2/pytest_decode_batch_axes.log (S2)
    • github_issues/189/slice2/pytest_seedvr_regression_guard.log (S2)
    • github_issues/189/slice2/test_module_internals.log (S2 — grep evidence proving the regression test module's six function definitions and the per-test assertion shape constants match the AC contract verbatim)
    • github_issues/189/slice2/vae_diff.patch (S2)
    • github_issues/189/slice2/latent_side_unchanged.log (S2)
    • github_issues/189/slice3/ruff.log (S3)
    • github_issues/189/slice3/no_detuning.log (S3)
    • github_issues/189/slice4/provenance.md (S4)
  • pollockjj/ComfyUI#issue_189:
    • comfy/ldm/seedvr/vae.py (modified — output-side block of VideoAutoencoderKLWrapper.decode only; latent-side prep block lines 2245-2253 byte-identical to base) (S2)
    • tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.py (S2 introduces)

Latent-side guard token set (Slice 2 AC-1 protects these tokens; the diff MUST NOT add or remove lines containing these tokens): b, tc, h, w = z.shape ; latent = z.view(b, 16, -1, h, w) ; scale = 0.9152 ; shift = 0 ; latent = latent / scale + shift ; if latent.ndim == 4: ; latent = latent.unsqueeze(2). These seven tokens appear consecutively as the body of the latent-side prep block on pollockjj/ComfyUI:issue_101 HEAD per GTP-12.

Asset Readiness

Asset Location Provenance Status
pollockjj/ComfyUI:issue_101 HEAD 4e8836ed /home/johnj/dev_cuda_1/ComfyUI latest deliverable trunk per #101 fleet status; git rev-parse origin/issue_101 returns 4e8836ed0a53467e9c433d58320c4992c9c34d2d VERIFIED (GTP-6)
Source surface comfy/ldm/seedvr/vae.py (VideoAutoencoderKLWrapper.decode body at lines 2245-2295; latent-side prep at 2245-2253; output-side block at 2255-2294) /home/johnj/dev_cuda_1/ComfyUI/comfy/ldm/seedvr/vae.py (blob b3f0f5d7) base branch issue_101 HEAD VERIFIED (GTP-6, GTP-12)
comfy.ldm.seedvr.vae.VideoAutoencoderKL.decode_ parent-class method base branch HEAD base branch issue_101 HEAD VERIFIED (GTP-1)
comfy.ldm.seedvr.vae.lab_color_transfer module-level function base branch HEAD base branch issue_101 HEAD VERIFIED (GTP-2)
comfy.ldm.seedvr.vae.rearrange (re-export of einops.rearrange) base branch HEAD base branch issue_101 HEAD VERIFIED (GTP-2)
Test directory tests-unit/comfy_test/ and existing seedvr tests /home/johnj/dev_cuda_1/ComfyUI/tests-unit/comfy_test/ base branch issue_101 HEAD VERIFIED (GTP-7)
Established test pattern in tests-unit/comfy_test/test_seedvr_groupnorm_limit.py (args.cpu = True block before comfy.ldm.* import; unittest.mock.patch.object usage) /home/johnj/dev_cuda_1/ComfyUI/tests-unit/comfy_test/test_seedvr_groupnorm_limit.py base branch issue_101 HEAD VERIFIED (GTP-8)
Deliverable venv (torch==2.11.0+cu130, einops==0.8.2, pytest==9.0.3) /home/johnj/dev_cuda_1/ComfyUI/.venv host slot VERIFIED (GTP-9)
ruff 0.15.9 binary /home/johnj/.local/bin/ruff (also resolvable via python -m ruff against the deliverable venv) live python -m ruff --version from /home/johnj/dev_cuda_1/ComfyUI; ComfyUI CI invokes the same binary at pollockjj/ComfyUI:issue_101 HEAD .github/workflows/ruff.yml (blob b24d86a6ba55b1f7b90539d6267a72afa5a7b73c, line 24 run: ruff check .) VERIFIED (GTP-13)
comfy.cli_args.args.cpu flag /home/johnj/dev_cuda_1/ComfyUI/comfy/cli_args.py base branch issue_101 HEAD VERIFIED (GTP-3)
pytest.ini discovery config (pythonpath = ., testpaths = tests tests-unit, addopts = -s) /home/johnj/dev_cuda_1/ComfyUI/pytest.ini base branch issue_101 HEAD VERIFIED (GTP-10)
pollockjj/mydevelopment:main parent context HEAD 1e8218e2 /home/johnj/dev_cuda_1/mydevelopment local checkout VERIFIED (GTP-11)
Plan Foundations comment ID IC_kwDOR2e1q88AAAABBF6EQQ issue Comfy-Org#189 comment 4368270401 tdd-agent[bot] post 2026-05-04T04:37:08Z, edited 2026-05-04T05:28:59Z VERIFIED

No external assets (model weights, video/image datasets, OS packages) are required. The plan is CPU-only by construction.

Slices


Slice 1: Pre-fix Baseline Reproduction Probe

Kind: decision-packet

Objective: Produce the baseline reproduction decision packet recording the buggy output shape and per-batch fingerprint position for every (B, T_orig) cell in the bug taxonomy on pollockjj/ComfyUI:issue_101 HEAD 4e8836ed before any production fix is applied.

Acceptance Criteria

  • AC-1: File github_issues/189/probe_seedvr_decode_batch_axes.py is committed on pollockjj/mydevelopment:issue_189 and is a Python module that exposes a --out PATH CLI flag, a --bt-cells STR CLI flag (semicolon-separated B,T_orig integer pairs), a --label STR CLI flag, exits 0 on success, and writes a UTF-8 JSON file to PATH containing exactly the named-key set {label, mydevelopment_head_sha, comfyui_head_sha, comfyui_branch, vae_blob_sha, bt_cells} with each bt_cells entry containing exactly the per-cell named-key set {B, T_orig, T_dec, out_shape, out_dtype, channel_axis_value, time_axis_value, fingerprint_at_correct_batch_position} — verified by (a) committed artifact github_issues/189/slice1/probe_argparse_flags.log capturing the stdout of grep -nE "add_argument\(['\"](--out\|--bt-cells\|--label)['\"]" /home/johnj/dev_cuda_1/mydevelopment/github_issues/189/probe_seedvr_decode_batch_axes.py returning exactly three matching lines (one per flag) and zero extra add_argument( lines outside that set, with the log's final line recording ARGPARSE_FLAGS_EXIT: 0; (b) committed artifact github_issues/189/slice1/baseline_json_keys.log capturing the stdout of python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); print("TOP_KEYS:", sorted(d.keys())); print("CELL_KEYS:", sorted(d["bt_cells"][0].keys())); print("CELL_COUNT:", len(d["bt_cells"]))' /home/johnj/dev_cuda_1/mydevelopment/github_issues/189/slice1/decode_batch_axes_baseline.json whose three printed lines are verbatim TOP_KEYS: ['bt_cells', 'comfyui_branch', 'comfyui_head_sha', 'label', 'mydevelopment_head_sha', 'vae_blob_sha'], CELL_KEYS: ['B', 'T_dec', 'T_orig', 'channel_axis_value', 'fingerprint_at_correct_batch_position', 'out_dtype', 'out_shape', 'time_axis_value'], and CELL_COUNT: 5, with the log's final line recording JSON_KEYS_EXIT: 0; (c) committed artifact github_issues/189/slice1/probe_run.log capturing the stdout+stderr of the AC-2 probe invocation including the verbatim exit-status line PROBE_EXIT: 0; AND (d) the JSON artifact existing at the path declared in AC-2.

    • Assumes-passed: none
    • In-scope-of: Slice 1 Objective "Produce the baseline reproduction decision packet recording the buggy output shape and per-batch fingerprint position for every (B, T_orig) cell in the bug taxonomy on pollockjj/ComfyUI:issue_101 HEAD 4e8836ed before any production fix is applied."
    • Foundations-pin: comment-id=IC_kwDOR2e1q88AAAABBF6EQQ edited-at=2026-05-04T05:28:59Z
  • AC-2: Probe is invoked as cd /home/johnj/dev_cuda_1/ComfyUI && python3 /home/johnj/dev_cuda_1/mydevelopment/github_issues/189/probe_seedvr_decode_batch_axes.py --out /home/johnj/dev_cuda_1/mydevelopment/github_issues/189/slice1/decode_batch_axes_baseline.json --bt-cells "1,1;1,5;2,1;4,1;2,3" --label baseline against the issue branch's working tree at HEAD (which is byte-identical to origin/issue_101 HEAD 4e8836ed because no source fix has been applied in Slice 1) and the resulting github_issues/189/slice1/decode_batch_axes_baseline.json is committed on pollockjj/mydevelopment:issue_189 with the per-cell out_shape named-key values: cell B=1, T_orig=1[1, 3, 1, 16, 16]; cell B=1, T_orig=5[1, 3, 5, 16, 16]; cell B=2, T_orig=1[1, 2, 2, 16, 16]; cell B=4, T_orig=1[1, 4, 3, 16, 16]; cell B=2, T_orig=3[1, 3, 6, 16, 16]. The label value is "baseline". The comfyui_head_sha value is "4e8836ed0a53467e9c433d58320c4992c9c34d2d". The vae_blob_sha value is "b3f0f5d719862ae119ebc037ab104bca7785ce71". Verified by committed artifact github_issues/189/slice1/decode_batch_axes_baseline.json parsed and key-checked, plus committed artifact github_issues/189/slice1/probe_run.log capturing the probe's stdout/stderr.

    • Assumes-passed: none
    • In-scope-of: Slice 1 Objective "Produce the baseline reproduction decision packet recording the buggy output shape and per-batch fingerprint position for every (B, T_orig) cell in the bug taxonomy on pollockjj/ComfyUI:issue_101 HEAD 4e8836ed before any production fix is applied."
    • Probe: GTP-1, GTP-2, GTP-3, GTP-4, GTP-5, GTP-6, GTP-9, GTP-12
    • Foundations-pin: comment-id=IC_kwDOR2e1q88AAAABBF6EQQ edited-at=2026-05-04T05:28:59Z
  • AC-3: File github_issues/189/slice1/provenance.md is committed on pollockjj/mydevelopment:issue_189 containing exactly the named-line keys decision_summary:, recommended_action:, mydevelopment_head_sha:, comfyui_head_sha:, comfyui_branch:, vae_blob_sha:, coderabbit_url:, upstream_pr_url:, parent_findings_comment_url:, probe_command:, probe_output_path:, bug_cells_observed:, with decision_summary value baseline_b_gt_1_t_eq_1_decode_shape_corrupted, recommended_action value apply_output_side_fix_on_pollockjj/ComfyUI_issue_189, comfyui_head_sha value 4e8836ed0a53467e9c433d58320c4992c9c34d2d, comfyui_branch value issue_101, vae_blob_sha value b3f0f5d719862ae119ebc037ab104bca7785ce71, coderabbit_url value https://github.com/Comfy-Org/ComfyUI/pull/11294#discussion_r2959796352, upstream_pr_url value https://github.com/Comfy-Org/ComfyUI/pull/11294, parent_findings_comment_url value https://github.com/pollockjj/mydevelopment/issues/101#issuecomment-4305426643, probe_command value matching the AC-2 command verbatim, probe_output_path value github_issues/189/slice1/decode_batch_axes_baseline.json, bug_cells_observed value B=2,T_orig=1 -> shape (1,2,2,16,16); B=4,T_orig=1 -> shape (1,4,3,16,16) — verified by committed artifact github_issues/189/slice1/provenance.md and grep '^<key>: ' parseability against the listed key set.

    • Assumes-passed: none
    • In-scope-of: Slice 1 Objective "Produce the baseline reproduction decision packet recording the buggy output shape and per-batch fingerprint position for every (B, T_orig) cell in the bug taxonomy on pollockjj/ComfyUI:issue_101 HEAD 4e8836ed before any production fix is applied."
    • Probe: GTP-6, GTP-11
    • Foundations-pin: comment-id=IC_kwDOR2e1q88AAAABBF6EQQ edited-at=2026-05-04T05:28:59Z

Slice 2: Output-side Shape Fix, Regression Test Module, Post-Fix Probe and Comparison

Kind: implementation

Objective: Prove that modifying the output-side block of VideoAutoencoderKLWrapper.decode in comfy/ldm/seedvr/vae.py makes batch and time axes distinct for every (B, T_orig) cell including B>1, T_orig==1 while leaving the latent-side prep block byte-identical to base, by landing the source change on pollockjj/ComfyUI:issue_189, adding a six-test regression module that fails pre-fix on the B>1, T_orig==1 cells, re-running the same probe to record corrected shapes, and emitting a before/after delta artifact whose shape_mismatch_count_new named-key is 0 while shape_mismatch_count_prior is 2.

Acceptance Criteria

  • AC-1: File comfy/ldm/seedvr/vae.py on pollockjj/ComfyUI:issue_189 HEAD has a non-empty diff against origin/issue_101 restricted to the output-side block of VideoAutoencoderKLWrapper.decode (the lines starting at self.device = latent.device through the final return x after the even-dims trim, per GTP-12); the latent-side prep block tokens enumerated in ## Created Surface Contract (the seven-token set b, tc, h, w = z.shape ; latent = z.view(b, 16, -1, h, w) ; scale = 0.9152 ; shift = 0 ; latent = latent / scale + shift ; if latent.ndim == 4: ; latent = latent.unsqueeze(2)) appear in zero + lines and zero - lines of the diff — verified by committed artifact github_issues/189/slice2/vae_diff.patch containing the output of git -C /home/johnj/dev_cuda_1/ComfyUI diff origin/issue_101...HEAD -- comfy/ldm/seedvr/vae.py (non-zero size) AND committed artifact github_issues/189/slice2/latent_side_unchanged.log containing the output of grep -nE '^[+-][[:space:]]+(b, tc, h, w = z\.shape\|latent = z\.view\(b, 16, -1, h, w\)\|scale = 0\.9152\|shift = 0\|latent = latent / scale \+ shift\|if latent\.ndim == 4:\|latent = latent\.unsqueeze\(2\))$' /home/johnj/dev_cuda_1/mydevelopment/github_issues/189/slice2/vae_diff.patch returning zero matching lines, with the log's final line recording LATENT_SIDE_GUARD_EXIT: 0.
    • Pre-fix-fingerprint: §Diagnosis Summary / Failure signature — output-side block of VideoAutoencoderKLWrapper.decode on issue_101 HEAD applies super().decode_(latent).squeeze(2) followed by if x.ndim == 4: x = x.unsqueeze(0), producing [1, B, C, H, W] for B>1, T_dec==1 per GTP-5; pre-fix git diff origin/issue_101...HEAD -- comfy/ldm/seedvr/vae.py is empty (no fix applied yet)
    • Post-fix-expectation: vae_diff.patch is non-empty AND contains zero +/- lines matching the seven-token latent-side guard set; the modification is restricted to lines within the output-side block (per the GTP-12 line-range observation 2255-2294)
    • Assumes-passed: 1
    • In-scope-of: Slice 2 Objective "Prove that modifying the output-side block of VideoAutoencoderKLWrapper.decode in comfy/ldm/seedvr/vae.py makes batch and time axes distinct for every (B, T_orig) cell including B>1, T_orig==1 while leaving the latent-side prep block byte-identical to base, by landing the source change on pollockjj/ComfyUI:issue_189, adding a six-test regression module that fails pre-fix on the B>1, T_orig==1 cells, re-running the same probe to record corrected shapes, and emitting a before/after delta artifact whose shape_mismatch_count_new named-key is 0 while shape_mismatch_count_prior is 2."
    • Probe: GTP-6, GTP-12
    • Foundations-pin: comment-id=IC_kwDOR2e1q88AAAABBF6EQQ edited-at=2026-05-04T05:28:59Z
  • AC-2: File tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.py on pollockjj/ComfyUI:issue_189 HEAD defines exactly the six functions test_decode_b1_t1_shape_and_ordering_correct, test_decode_b1_t5_video_shape_unchanged, test_decode_b2_t1_fixes_batch_time_axes, test_decode_b4_t1_fixes_batch_time_axes, test_decode_b2_t3_multi_frame_batch_unchanged, and test_decode_b2_t1_stacked_equals_individual_per_sample_ordering. Each per-cell test (a) sets comfy.cli_args.args.cpu = True before importing any comfy.ldm.* symbol when torch.cuda.is_available() is False (matching the pattern at tests-unit/comfy_test/test_seedvr_groupnorm_limit.py:48-49 per GTP-8), (b) constructs a wrapper instance via VideoAutoencoderKLWrapper.__new__(VideoAutoencoderKLWrapper) + nn.Module.__init__(instance) with tiled_args = {"enable_tiling": False}, original_image_video = torch.zeros(B, 3, T_orig, 16, 16), img_dims = (16, 16) per the __init__-bypass pattern in §Diagnosis Summary / Reproduction (per GTP-4), (c) patches VideoAutoencoderKL.decode_ with a fingerprint-tagged stub returning [B, 3, T_dec, 16, 16] filled with float(b + 1) per batch index, (d) patches comfy.ldm.seedvr.vae.lab_color_transfer with a passthrough that returns its first argument, (e) calls wrapper.decode(torch.zeros(B, 16*T_orig, 2, 2)), and (f) asserts tuple(out.shape) == (1, 3, B*T_orig, 16, 16) for the per-cell B and T_orig. The test_decode_b2_t1_fixes_batch_time_axes test additionally asserts out[0, 0, 0, 0, 0].item() == 1.0 AND out[0, 0, 1, 0, 0].item() == 2.0 (per-sample fingerprint at the correct batch position). The test_decode_b4_t1_fixes_batch_time_axes test additionally asserts [out[0, 0, b, 0, 0].item() for b in range(4)] == [1.0, 2.0, 3.0, 4.0]. The test_decode_b2_t1_stacked_equals_individual_per_sample_ordering test invokes wrapper.decode(torch.zeros(2, 16, 2, 2)) (stacked, with original_image_video set to torch.zeros(2, 3, 1, 16, 16)) producing out_stacked, then resets the wrapper's original_image_video to torch.zeros(1, 3, 1, 16, 16) and invokes wrapper.decode(torch.zeros(1, 16, 2, 2)) twice with the per-call fingerprint stub returning float(b + 1) for the stacked indices b ∈ {0, 1} (the second call's stub pinned to 2.0), then asserts torch.equal(out_stacked[0, :, 0, :, :], out_individual_0[0, :, 0, :, :]) AND torch.equal(out_stacked[0, :, 1, :, :], out_individual_1[0, :, 0, :, :]). All six tests pass under cd /home/johnj/dev_cuda_1/ComfyUI && python -m pytest -q tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.py with overall exit 0 and the summary line containing 6 passed — verified by (a) committed artifact github_issues/189/slice2/test_module_internals.log capturing seven greps over /home/johnj/dev_cuda_1/ComfyUI/tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.py against the issue_189 HEAD source: (i) grep -cE '^def (test_decode_b1_t1_shape_and_ordering_correct\|test_decode_b1_t5_video_shape_unchanged\|test_decode_b2_t1_fixes_batch_time_axes\|test_decode_b4_t1_fixes_batch_time_axes\|test_decode_b2_t3_multi_frame_batch_unchanged\|test_decode_b2_t1_stacked_equals_individual_per_sample_ordering)\(' returning the literal 6; (ii) grep -cE '^def test_' returning the literal6(proves no extra test functions); (iii)grep -nE 'tuple(out.shape) == (1, 3, 1, 16, 16)|tuple(out.shape) == (1, 3, 5, 16, 16)|tuple(out.shape) == (1, 3, 2, 16, 16)|tuple(out.shape) == (1, 3, 4, 16, 16)|tuple(out.shape) == (1, 3, 6, 16, 16)' returning at least five lines (one per per-cell shape assertion); (iv)grep -nE 'out[0, 0, 0, 0, 0].item() == 1.0|out[0, 0, 1, 0, 0].item() == 2.0' returning at least two matching lines (the b2_t1 fingerprint asserts); (v)grep -nE '[out[0, 0, b, 0, 0].item() for b in range(4)] == [1.0, 2.0, 3.0, 4.0]' returning at least one matching line (the b4_t1 fingerprint assert); (vi)grep -nE 'torch.equal(out_stacked[0, :, 0, :, :], out_individual_0[0, :, 0, :, :])|torch.equal(out_stacked[0, :, 1, :, :], out_individual_1[0, :, 0, :, :])' returning at least two matching lines (the stacked-vs-individual asserts); (vii)grep -nE 'args.cpu = True|VideoAutoencoderKLWrapper.new|nn.Module.init|patch.object(.*decode_|patch.object(.*lab_color_transfer' returning at least one match per fixture-pattern line (cpu flag,newbypass,nn.Module.initbypass,decode_patch,lab_color_transferpatch), with the log's final line recordingTEST_INTERNALS_EXIT: 0; **(b)** committed artifact github_issues/189/slice2/pytest_decode_batch_axes.logcapturing stdout+stderr ofcd /home/johnj/dev_cuda_1/ComfyUI && python -m pytest -q tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.pyincluding the6 passedsummary line and the verbatim final-linePYTEST_DECODE_BATCH_AXES_EXIT: 0`.

    • Pre-fix-fingerprint: §Diagnosis Summary / Reproduction — running the test_decode_b2_t1_fixes_batch_time_axes and test_decode_b4_t1_fixes_batch_time_axes tests against issue_101 HEAD (no fix) causes both to FAIL with AssertionError: tuple(out.shape) == (1, 3, 2, 16, 16) (got (1, 2, 2, 16, 16)) and tuple(out.shape) == (1, 3, 4, 16, 16) (got (1, 4, 3, 16, 16)) respectively, per the live shapes observed in GTP-5; the test_decode_b2_t1_stacked_equals_individual_per_sample_ordering test fails on the torch.equal assertion because the stacked tensor's batch axis has been swapped with channels; pytest summary contains at minimum 3 failed
    • Post-fix-expectation: pytest summary contains 6 passed; per-cell tuple(out.shape) equals (1, 3, B*T_orig, 16, 16) for every cell; per-sample fingerprint at out[0, 0, b, 0, 0] equals float(b + 1) for the B>1, T_orig=1 cells; torch.equal(out_stacked[0, :, b, :, :], out_individual_b[0, :, 0, :, :]) holds for b ∈ {0, 1}
    • Assumes-passed: 1
    • In-scope-of: Slice 2 Objective "Prove that modifying the output-side block of VideoAutoencoderKLWrapper.decode in comfy/ldm/seedvr/vae.py makes batch and time axes distinct for every (B, T_orig) cell including B>1, T_orig==1 while leaving the latent-side prep block byte-identical to base, by landing the source change on pollockjj/ComfyUI:issue_189, adding a six-test regression module that fails pre-fix on the B>1, T_orig==1 cells, re-running the same probe to record corrected shapes, and emitting a before/after delta artifact whose shape_mismatch_count_new named-key is 0 while shape_mismatch_count_prior is 2."
    • Probe: GTP-1, GTP-2, GTP-3, GTP-4, GTP-5, GTP-7, GTP-8, GTP-9
    • Foundations-pin: comment-id=IC_kwDOR2e1q88AAAABBF6EQQ edited-at=2026-05-04T05:28:59Z
  • AC-3: Existing SeedVR2 unit-test modules tests-unit/comfy_test/test_seedvr_groupnorm_limit.py, tests-unit/comfy_test/test_seedvr_vae_tiled_args_no_mutate.py, and tests-unit/comfy_test/test_seedvr_rope_delegation.py (per GTP-7) all pass under cd /home/johnj/dev_cuda_1/ComfyUI && python -m pytest -q tests-unit/comfy_test/test_seedvr_groupnorm_limit.py tests-unit/comfy_test/test_seedvr_vae_tiled_args_no_mutate.py tests-unit/comfy_test/test_seedvr_rope_delegation.py on pollockjj/ComfyUI:issue_189 HEAD with overall exit 0 and the summary line containing passed (no failed, no errors) — verified by committed artifact github_issues/189/slice2/pytest_seedvr_regression_guard.log capturing stdout+stderr of that pytest invocation, with the log's penultimate or final line matching the regex ^[0-9]+ passed( in [0-9.]+s)?$ and zero occurrences of the substring failed or errors outside the verbatim summary line context.

    • Pre-fix-fingerprint: §Diagnosis Summary / Failure boundary — the existing seedvr tests cover GroupNorm chunking, tiled-args non-mutation, and RoPE delegation; none exercises the B>1, T_orig==1 decode path, so they all pass on issue_101 HEAD; this AC asserts they continue to pass post-fix (regression guard against the output-side block edit unintentionally breaking another path)
    • Post-fix-expectation: pytest summary contains a non-zero passed count and zero failed/errors; the existing tests are unaffected by the output-side block change; code-behavior-equivalence (per equivalence_methods.md) holds for the existing-test surface
    • Assumes-passed: 1
    • In-scope-of: Slice 2 Objective "Prove that modifying the output-side block of VideoAutoencoderKLWrapper.decode in comfy/ldm/seedvr/vae.py makes batch and time axes distinct for every (B, T_orig) cell including B>1, T_orig==1 while leaving the latent-side prep block byte-identical to base, by landing the source change on pollockjj/ComfyUI:issue_189, adding a six-test regression module that fails pre-fix on the B>1, T_orig==1 cells, re-running the same probe to record corrected shapes, and emitting a before/after delta artifact whose shape_mismatch_count_new named-key is 0 while shape_mismatch_count_prior is 2."
    • Probe: GTP-7, GTP-9
    • Foundations-pin: comment-id=IC_kwDOR2e1q88AAAABBF6EQQ edited-at=2026-05-04T05:28:59Z
  • AC-4: Probe is invoked as cd /home/johnj/dev_cuda_1/ComfyUI && python3 /home/johnj/dev_cuda_1/mydevelopment/github_issues/189/probe_seedvr_decode_batch_axes.py --out /home/johnj/dev_cuda_1/mydevelopment/github_issues/189/slice2/decode_batch_axes_post_fix.json --bt-cells "1,1;1,5;2,1;4,1;2,3" --label post_fix against pollockjj/ComfyUI:issue_189 HEAD (post-fix from AC-1) and the resulting github_issues/189/slice2/decode_batch_axes_post_fix.json is committed on pollockjj/mydevelopment:issue_189 with the per-cell out_shape named-key values: cell B=1, T_orig=1[1, 3, 1, 16, 16]; cell B=1, T_orig=5[1, 3, 5, 16, 16]; cell B=2, T_orig=1[1, 3, 2, 16, 16]; cell B=4, T_orig=1[1, 3, 4, 16, 16]; cell B=2, T_orig=3[1, 3, 6, 16, 16]. Every cell's channel_axis_value equals 3 and time_axis_value equals B*T_orig. The label value is "post_fix". The comfyui_branch value is "issue_189". The vae_blob_sha value differs from the Slice 1 baseline vae_blob_sha of b3f0f5d719862ae119ebc037ab104bca7785ce71. Verified by committed artifact github_issues/189/slice2/decode_batch_axes_post_fix.json parsed and key-checked, plus committed artifact github_issues/189/slice2/probe_run.log.

    • Pre-fix-fingerprint: §Diagnosis Summary / Reproduction — same probe run on issue_101 HEAD (Slice 1 AC-2 outcome) records cell B=2, T_orig=1 out_shape=[1, 2, 2, 16, 16] and cell B=4, T_orig=1 out_shape=[1, 4, 3, 16, 16] — both differ from the (1, 3, B*T_orig, 16, 16) post-fix expectation per the live observations in GTP-5
    • Post-fix-expectation: every cell's out_shape equals (1, 3, B*T_orig, 16, 16); every cell's channel_axis_value == 3; every cell's time_axis_value == B*T_orig; the working B=1 and B>1, T_orig>1 cells remain bit-identical to baseline (out_shape unchanged for cells B=1, T_orig=1, B=1, T_orig=5, B=2, T_orig=3)
    • Assumes-passed: 1
    • In-scope-of: Slice 2 Objective "Prove that modifying the output-side block of VideoAutoencoderKLWrapper.decode in comfy/ldm/seedvr/vae.py makes batch and time axes distinct for every (B, T_orig) cell including B>1, T_orig==1 while leaving the latent-side prep block byte-identical to base, by landing the source change on pollockjj/ComfyUI:issue_189, adding a six-test regression module that fails pre-fix on the B>1, T_orig==1 cells, re-running the same probe to record corrected shapes, and emitting a before/after delta artifact whose shape_mismatch_count_new named-key is 0 while shape_mismatch_count_prior is 2."
    • Probe: GTP-1, GTP-2, GTP-3, GTP-4, GTP-5, GTP-9
    • Foundations-pin: comment-id=IC_kwDOR2e1q88AAAABBF6EQQ edited-at=2026-05-04T05:28:59Z
  • AC-5: File github_issues/189/slice2/before_after_comparison.json is committed on pollockjj/mydevelopment:issue_189 containing exactly the named-key set {prior_artifact_path, new_artifact_path, prior_label, new_label, shape_mismatch_count_prior, shape_mismatch_count_new, per_cell_delta} with values prior_artifact_path="github_issues/189/slice1/decode_batch_axes_baseline.json", new_artifact_path="github_issues/189/slice2/decode_batch_axes_post_fix.json", prior_label="baseline", new_label="post_fix", shape_mismatch_count_prior=2 (cells B=2, T_orig=1 and B=4, T_orig=1), shape_mismatch_count_new=0, and per_cell_delta containing exactly five entries (one per cell) with each entry containing the named-key set {B, T_orig, prior_out_shape, new_out_shape, expected_out_shape, prior_pass, new_pass} and the per-cell values listed in AC-2 / AC-4 — verified by committed artifact at the named path parsed and key-checked.

    • Pre-fix-fingerprint: §Diagnosis Summary / Verification strategy — pre-Slice-2 only the Slice 1 baseline JSON exists; the comparison artifact does not exist and shape_mismatch_count_new cannot be 0 because no post-fix run has been performed
    • Post-fix-expectation: shape_mismatch_count_prior == 2 AND shape_mismatch_count_new == 0 AND every per_cell_delta entry has new_pass=true; the comparison JSON exists at the named path on the issue branch
    • Assumes-passed: 1
    • In-scope-of: Slice 2 Objective "Prove that modifying the output-side block of VideoAutoencoderKLWrapper.decode in comfy/ldm/seedvr/vae.py makes batch and time axes distinct for every (B, T_orig) cell including B>1, T_orig==1 while leaving the latent-side prep block byte-identical to base, by landing the source change on pollockjj/ComfyUI:issue_189, adding a six-test regression module that fails pre-fix on the B>1, T_orig==1 cells, re-running the same probe to record corrected shapes, and emitting a before/after delta artifact whose shape_mismatch_count_new named-key is 0 while shape_mismatch_count_prior is 2."
    • Foundations-pin: comment-id=IC_kwDOR2e1q88AAAABBF6EQQ edited-at=2026-05-04T05:28:59Z

Slice 3: Hygiene Validator Gate (Ruff Lint + Production-Code Shape Independence)

Kind: hygiene

Objective: Prove the Slice 2 commits leave comfy/ldm/seedvr/vae.py and tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.py ruff-clean and free of any observability detuning (no added print / logging.debug / sentinel comments) that could land as production-code noise alongside the output-side fix.

Acceptance Criteria

  • AC-1: cd /home/johnj/dev_cuda_1/ComfyUI && python -m ruff check comfy/ldm/seedvr/vae.py tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.py exits 0 against pollockjj/ComfyUI:issue_189 HEAD — verified by committed validator-output artifact github_issues/189/slice3/ruff.log capturing stdout+stderr of that invocation and ending with the All checks passed! line, with shell exit code recorded as 0 in the log's final line RUFF_EXIT: 0.

    • Assumes-passed: 1, 2
    • In-scope-of: Slice 3 Objective "Prove the Slice 2 commits leave comfy/ldm/seedvr/vae.py and tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.py ruff-clean and free of any observability detuning (no added print / logging.debug / sentinel comments) that could land as production-code noise alongside the output-side fix."
    • Probe: GTP-7
    • Foundations-pin: comment-id=IC_kwDOR2e1q88AAAABBF6EQQ edited-at=2026-05-04T05:28:59Z
  • AC-2: Slice 2 introduced zero observability detuning (print, logging.debug, logging.info, sentinel comments, debug markers) in comfy/ldm/seedvr/vae.py and in tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.py — verified by committed validator-output artifact github_issues/189/slice3/no_detuning.log containing the combined output of two greps: (a) grep -nE '^[+][[:space:]]*(print\(\|logging\.debug\|logging\.info\|# TODO\s*(?:DEBUG\|MARKER\|SENTINEL))' /home/johnj/dev_cuda_1/mydevelopment/github_issues/189/slice2/vae_diff.patch returning no matches, AND (b) grep -nE '\bprint\(\|logging\.debug\|logging\.info\|# TODO\s*(?:DEBUG\|MARKER\|SENTINEL)' /home/johnj/dev_cuda_1/ComfyUI/tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.py returning no matches, with the log's final line recording NO_DETUNING_EXIT: 0.

    • Assumes-passed: 1, 2
    • In-scope-of: Slice 3 Objective "Prove the Slice 2 commits leave comfy/ldm/seedvr/vae.py and tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.py ruff-clean and free of any observability detuning (no added print / logging.debug / sentinel comments) that could land as production-code noise alongside the output-side fix."
    • Foundations-pin: comment-id=IC_kwDOR2e1q88AAAABBF6EQQ edited-at=2026-05-04T05:28:59Z

Slice 4: Post-Fix Provenance Decision Packet

Kind: decision-packet

Objective: Produce the post-fix provenance decision packet binding the issue branch HEADs, the canonical-reference URLs, and the verbatim invocation commands used by Slices 2 and 3 into a single architect-readable record.

Acceptance Criteria

  • AC-1: File github_issues/189/slice4/provenance.md is committed on pollockjj/mydevelopment:issue_189 containing exactly the named-line keys decision_summary:, recommended_action:, mydevelopment_head_sha:, comfyui_head_sha:, comfyui_branch:, comfyui_base_sha:, comfyui_base_branch:, coderabbit_url:, upstream_pr_url:, parent_findings_comment_url:, probe_command:, probe_baseline_path:, probe_post_fix_path:, comparison_path:, regression_test_command:, seedvr_regression_guard_command:, ruff_command:, with decision_summary value post_fix_b_gt_1_t_eq_1_decode_axes_distinct_restored, recommended_action value invoke_/pr_from_issue_189_to_issue_101, comfyui_base_sha value 4e8836ed0a53467e9c433d58320c4992c9c34d2d, comfyui_base_branch value issue_101, comfyui_branch value issue_189, coderabbit_url value https://github.com/Comfy-Org/ComfyUI/pull/11294#discussion_r2959796352, upstream_pr_url value https://github.com/Comfy-Org/ComfyUI/pull/11294, parent_findings_comment_url value https://github.com/pollockjj/mydevelopment/issues/101#issuecomment-4305426643, probe_command value matching the Slice 2 AC-4 command verbatim, probe_baseline_path value github_issues/189/slice1/decode_batch_axes_baseline.json, probe_post_fix_path value github_issues/189/slice2/decode_batch_axes_post_fix.json, comparison_path value github_issues/189/slice2/before_after_comparison.json, regression_test_command value matching the Slice 2 AC-2 pytest invocation verbatim, seedvr_regression_guard_command value matching the Slice 2 AC-3 pytest invocation verbatim, ruff_command value matching the Slice 3 AC-1 ruff invocation verbatim — verified by committed artifact at the named path and grep '^<key>: ' parseability against the listed key set.
    • Assumes-passed: 1, 2, 3
    • In-scope-of: Slice 4 Objective "Produce the post-fix provenance decision packet binding the issue branch HEADs, the canonical-reference URLs, and the verbatim invocation commands used by Slices 2 and 3 into a single architect-readable record."
    • Probe: GTP-6, GTP-11
    • Foundations-pin: comment-id=IC_kwDOR2e1q88AAAABBF6EQQ edited-at=2026-05-04T05:28:59Z

Constraints

  • Python: python3 (resolved by the slicer's environment to the deliverable venv at /home/johnj/dev_cuda_1/ComfyUI/.venv/bin/python for ComfyUI-touching commands; no AC hardcodes an absolute interpreter path).
  • Runner: debug/run_debug.py (not exercised — this plan is CPU-only static-source plus pytest; no ComfyUI launch).
  • Isolation flags: --use-process-isolation --disable-cuda-malloc (not exercised — see above).
  • No packages installed into host venv.
  • No pkill, no rm -rf, no python main.py.
  • All commits on issue branch issue_189 in both pollockjj/mydevelopment and pollockjj/ComfyUI, not on base branches main / issue_101.
  • Relevant Existing Tooling:
    • pytest 9.0.3 in deliverable venv — REUSE; cited from tools_register.md#pytest and start flag to not open webui at launch Comfy-Org/ComfyUI#187 plan TPM Inventory.
    • ruff 0.15.9 system binary — REUSE; ComfyUI CI invocation pattern is python -m ruff check . per .github/workflows/ruff.yml.
    • torch 2.11.0+cu130, einops 0.8.2 in deliverable venv — REUSE.
    • comfy.ldm.seedvr.vae.VideoAutoencoderKLWrapper and VideoAutoencoderKL in deliverable source — REUSE; constructable on CPU via __new__ + nn.Module.__init__ per GTP-4.
    • comfy.ldm.seedvr.vae.VideoAutoencoderKL.decode_ — REUSE (mocked in tests via unittest.mock.patch.object).
    • comfy.ldm.seedvr.vae.lab_color_transfer — REUSE (mocked in tests via unittest.mock.patch.object).
    • comfy.ldm.seedvr.vae.rearrange — REUSE (called inside decode(); not patched).
    • unittest.mock.patch.object (stdlib) — REUSE for measurement instrumentation.
    • nn.Module.__init__ (torch) — REUSE for the __init__-bypass test fixture pattern.
    • gh CLI — REUSE for issue body update via scripts/run_tdd_post.py update-issue (PR creation is the /pr skill's responsibility, not this plan).
  • Evidence Primitive Requirements:
    • Output-shape correctness claim → fingerprint-tagged decoder mock + per-cell shape assertion + per-batch fingerprint position check (deterministic; zero rtol/atol per equivalence_methods.md#tensor-numerical-equivalence).
    • Per-sample-ordering preservation claim → stacked-vs-individual decode comparison via torch.equal (binary; per the issue body's Acceptance Intent verbatim quote in the Plan Foundations comment R&M section).
    • Behavioral-change claim (output-side block edit) → committed git diff artifact + regression test that fails pre-fix and passes post-fix (per equivalence_methods.md#code-behavior-equivalence) + Slice 1 baseline probe + Slice 2 post-fix probe + comparison delta JSON.
    • Stop-condition guard (latent-side prep block byte-identical) → grep over the committed vae_diff.patch against the seven-token guard set (zero matching +/- lines required).
    • Existing-test regression guard → pytest log over the three existing seedvr unit-test modules (test_seedvr_groupnorm_limit.py, test_seedvr_vae_tiled_args_no_mutate.py, test_seedvr_rope_delegation.py) with code-behavior-equivalence zero-new-failures tolerance.
    • Decision-packet artifacts → JSON or markdown files with the named-key set declared in ## Created Surface Contract; grep '^<key>:' parseable for key existence; python -m json.tool parseable for structural validity.
    • Hygiene validator output → ruff log + grep log; both exit 0 / no matches respectively.
  • Repository Hygiene (local pre-submit gate, NOT a QA artifact):
    • Every dirty repo state is resolved by the agent without git stash and without external decision deferral.
    • Dirty paths are classified as committed work, precise committed .gitignore rules for safe generated bulk, or discarded generated debris.
    • Clean committed work already present on the active branch is repo provenance and is integrated, not removed as dirty-state cleanup.
    • Slicers and Melian must run live git status --short gates locally and must refuse to submit while any touched repo is dirty.
    • Plans MUST NOT require repo_hygiene.md, repo_hygiene.txt, raw git status --short transcripts, or CLEAN markers as QA evidence; this plan deliberately omits any hygiene-evidence AC. QA verifies submitted commits, branch refs, and artifact presence through GitHub rather than trusting slicer-authored cleanliness transcripts.

Out of Scope

  • The latent-side prep block at comfy/ldm/seedvr/vae.py lines 2245-2253 (b, tc, h, w = z.shape; latent = z.view(b, 16, -1, h, w); ...). Per the issue body's Risks / Stop Conditions block, "Any code change to the latent-side prep block (lines 2245-2253) indicates plan drift — stop and surface." This block was already corrected upstream by commit af6c5d6 and is asserted byte-identical to base by Slice 2 AC-1.
  • Upstream propagation to Comfy-Org/ComfyUI#11294. Per the issue body's Non-Goals block and Risks block ("Upstream PR feat: Add support For SeedVR2 (CORE-6) Comfy-Org/ComfyUI#11294 is mergeable=DIRTY and silent for two weeks; do not attempt to push fixes back to yousef-rafat:seedvr2 from this issue."), upstream propagation is a separate later decision.
  • Other #101 Leg-1 sibling defects: #187 GroupNorm memory limit (closed), #188 frame count, #190/#192 forward return contracts, #191 latent metadata, #193 cache clearing, #194 decode state guards. Each owns its own scope and its own issue branch.
  • Any benchmark, video-quality, or end-to-end runtime measurement (no PSNR / SSIM / LPIPS / DOVER; no real GPU encode/decode; no debug/run_debug.py launches). The plan is CPU-only and CPU-deterministic by construction.
  • Custom-node changes (numz/ComfyUI-SeedVR2_VideoUpscaler, ComfyUI-SeedVR2-Canonical, etc.). Only the in-tree comfy/ldm/seedvr/vae.py carries this output-side defect.
  • Edits to debug harness files (debug/run_debug.py, debug/reset_gpu.py, debug/harness_runtime.py, etc.). The plan exercises no harness path.
  • PR creation, codex review, and Copilot review on the resulting PR. These are the /pr and /pr-review skills' responsibilities; this plan only lands committed work on issue branches and exits.
  • Tiled-decode path (if self.enable_tiling: branch in decode()). The bug only manifests in the non-tiled path (super().decode_(latent).squeeze(2)). Tiled-decode is covered by the existing test_seedvr_vae_tiled_args_no_mutate.py regression guard cited in Slice 2 AC-3.
  • Modifications to the encode path (VideoAutoencoderKLWrapper.encode). The bug is in the decode output-side block only.

Tracked in pollockjj/mydevelopment Comfy-Org#189 (bookkeeping PR pollockjj/mydevelopment#197).

pollockjj added 2 commits May 4, 2026 01:25
…hed image-mode decode

VideoAutoencoderKLWrapper.decode applied .squeeze(2) followed by an
ndim==4 unsqueeze(0) and a size(1)==1 heuristic that mis-routed the
batch axis into channels and the channel axis into time when B>1 and
T_dec==1. For B=2,T_orig=1 the output became (1,2,2,H,W) instead of
(1,3,2,H,W); for B=4,T_orig=1 it became (1,4,3,H,W) instead of
(1,3,4,H,W).

Drop the squeeze/unsqueeze dance and keep the post-decoder tensor 5D
[B,C,T_dec,H,W] through the post-processing pipeline so the
"b c t h w -> (b t) c h w" rearrange resolves axes consistently for
all (B, T_orig) cells, including B>1, T_orig==1.

Latent-side prep block (b, tc, h, w = z.shape ; latent.view(b, 16, ...)
;  scale=0.9152 ; shift=0 ; latent / scale + shift ; ndim==4 unsqueeze(2))
is byte-identical to base.

CodeRabbit finding:
Comfy-Org#11294 (comment)

Adds tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.py with
six cases pinning shape and per-sample ordering across
B in {1,2,4} x T_orig in {1,3,5}, including a stacked-vs-individual
ordering check for the previously-broken B=2, T_orig=1 path.
…ssion

Replace tuple(out.shape) == (1, 3, B * T_orig, 16, 16) with the
per-cell literal numeric form so the AC-2 grep contract for
test_module_internals.log matches verbatim. Also flatten the two
patch.object(...) context managers onto single source lines so the
fixture-pattern grep matches each patch.object(...decode_) and
patch.object(...lab_color_transfer) call without crossing newlines.
Behavior unchanged: 6 passed in 1.81s.
Copilot AI review requested due to automatic review settings May 4, 2026 20:54
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

Fixes the SeedVR2 VAE decode shape bug where single-frame batched decodes were swapping batch/time semantics, and adds regression tests around the non-tiled decode path.

Changes:

  • Removes the single-frame squeeze/unsqueeze heuristic from VideoAutoencoderKLWrapper.decode so decoder outputs stay 5D through reshape logic.
  • Simplifies the post-decode flattening path to always treat decoder output as b c t h w.
  • Adds regression tests covering several (B, T_orig) shape cases plus stacked-vs-individual ordering for non-tiled decode.

Reviewed changes

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

File Description
comfy/ldm/seedvr/vae.py Adjusts SeedVR decode output handling to preserve batch/time axes.
tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.py Adds CPU-only regression tests for single-frame and multi-frame non-tiled decode cases.

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

Comment thread comfy/ldm/seedvr/vae.py
else:
x = super().decode_(latent).squeeze(2)
x = super().decode_(latent)

Comment thread comfy/ldm/seedvr/vae.py

if self.enable_tiling:
x = tiled_vae(latent, self, **self.tiled_args, encode=False).squeeze(2)
x = tiled_vae(latent, self, **self.tiled_args, encode=False)
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] Preserve 4D tiled outputs for single-frame sf_t=1 decodes

When tiling is enabled on a wrapper configured with temporal_downsample_factor == 1 and a single latent frame, tiled_vae() still returns a 4D tensor because it squeezes the temporal axis before returning. This patch removes the only x.ndim == 4 normalization, so the next rearrange(x, "b c t h w -> (b t) c h w") raises instead of decoding that tiled image case; keep or replace the 4D-to-5D normalization for the tiled path.

…rmalization on tiled-decode branch for sf_t==1 + T_lat==1

tiled_vae() at comfy/ldm/seedvr/vae.py:179-180 explicitly squeezes the
temporal axis when temporal_downsample_factor == 1 AND the latent has a
single temporal frame:

    if x.shape[2] == 1 and sf_t == 1:
        result = result.squeeze(2)

The Issue 189 patch removed the prior `if x.ndim == 4: x = x.unsqueeze(0)`
heuristic (which had its own batch/time confusion bug). On the tiled
branch with that wrapper configuration, the unconditional rearrange
"b c t h w -> (b t) c h w" then receives a 4D tensor and raises
EinopsError instead of decoding the tiled image case.

Re-add the 4D->5D normalization scoped to the tiled branch only.
The non-tiled path stays unchanged because super().decode_(latent)
returns 5D unconditionally.

Adds test_decode_tiled_sf_t1_single_frame_4d_output_normalized() to
tests-unit/comfy_test/test_seedvr_vae_decode_batch_axes.py: patches
vae_mod.tiled_vae with a 4D-returning stub mimicking the squeeze
branch and asserts the decode returns the expected 5D shape with the
per-sample fingerprint preserved.
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 2 out of 2 changed files in this pull request and generated 2 comments.


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

Comment on lines +131 to +137
def test_decode_tiled_sf_t1_single_frame_4d_output_normalized():
"""Codex P2 / Copilot finding on PR #34: ``tiled_vae`` returns 4D
when ``temporal_downsample_factor == 1`` AND latent T == 1, so the
wrapper must re-add the temporal axis on the tiled branch before
the rearrange ``b c t h w -> (b t) c h w``. Pre-fix this case raised
an einops ``EinopsError`` because the patch removed the only
``x.ndim == 4`` normalization.
Comment thread comfy/ldm/seedvr/vae.py
Comment on lines +2259 to +2265
x = tiled_vae(latent, self, **self.tiled_args, encode=False)
if x.ndim == 4:
# tiled_vae squeezes the temporal axis when
# temporal_downsample_factor == 1 AND latent T == 1
# (see tiled_vae line 179-180); re-add it so the post-decode
# pipeline can keep batch and time distinct on the tiled path.
x = x.unsqueeze(2)
…n coverage

Copilot follow-up on PR #34: the tiled-path 4D->5D normalization
(commit 3b3c150) was only covered for B=1, leaving the entire reason
the issue exists — the batched single-frame batch/time axis swap —
unprotected on the tiled path. A future change could reintroduce the
batched single-frame bug on tiled decode without failing this suite.

Adds test_decode_tiled_sf_t1_b2_t1_per_sample_ordering: mirrors
test_decode_b2_t1_fixes_batch_time_axes for the enable_tiling=True
path with sf_t==1 + T_lat==1, asserting tuple(out.shape) ==
(1, 3, 2, 16, 16) and per-sample fingerprint preservation
(out[0,0,0,0,0]=1.0, out[0,0,1,0,0]=2.0).
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 2 out of 2 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.

@pollockjj pollockjj merged commit 861c824 into issue_101 May 4, 2026
10 checks passed
@pollockjj pollockjj deleted the issue_189 branch May 4, 2026 22:00
pollockjj added a commit that referenced this pull request May 5, 2026
…n contract (closes pollockjj/mydevelopment#192) (#46)

* [Issue 101][eval-and-fix] Fix VideoAutoencoderKLWrapper.forward return contract (closes pollockjj/mydevelopment#192)

VideoAutoencoderKLWrapper.forward() called self.decode(z).sample, but
VideoAutoencoderKLWrapper.decode() returns a plain torch.Tensor (post-Comfy-Org#189
/ PR #34 normalization). Direct wrapper invocation therefore raised
AttributeError on the tensor return.

Drop the .sample dereference; use the tensor return directly. forward()
now returns the (x_out, z, p) triple as documented in the wrapper's
encode/decode contract.

Sister to mydevelopment#190 (PR #44) which fixed the parent class
VideoAutoencoderKL.forward for the same bug class flagged on
Comfy-Org#11294 by CodeRabbit (thread r2959796348, "Also applies
to: 2083-2087" trailer).

Adds tests-unit/comfy_test/seedvr_vae_wrapper_forward_test.py — four
CPU-only regression tests that build a wrapper standin via __new__ +
nn.Module.__init__, register a single dummy parameter so the wrapper's
encode dtype lookup resolves, set original_image_video / img_dims /
tiled_args so the wrapper.decode guards pass, patch the parent
VideoAutoencoderKL.encode / decode_ plus the module-level
lab_color_transfer with fingerprint-tagged stubs, then call
wrapper.forward(x) end-to-end and assert (1) the return is a 3-tuple
of tensors with no AttributeError raised, (2) x_out has exact
expected shape, dtype, and value-fingerprint under torch.equal, (3) z
matches the encode-side posterior squeezed on dim 2 under torch.equal,
and (4) inspect.getsource(wrapper.forward) contains no ".sample" string.

* [Issue 101][eval-and-fix] Tighten VideoAutoencoderKLWrapper.forward regression test to two-test contract (pollockjj/mydevelopment#192)

The regression suite for VideoAutoencoderKLWrapper.forward now defines
exactly the two contract-named tests:

  - test_wrapper_forward_returns_tensor_triple monkeypatches
    VideoAutoencoderKLWrapper.encode and VideoAutoencoderKLWrapper.decode
    directly on the class, builds the wrapper standin via __new__ +
    nn.Module.__init__, sets original_image_video to a 5-D tensor and
    img_dims to a 2-tuple, invokes wrapper.forward(x), and asserts the
    full return-contract: 3-tuple, three torch.Tensor types, binary
    shape equality (x_out.shape == decode_out.shape, z.shape ==
    posterior.squeeze(2).shape), tensor equality
    (torch.equal(x_out, decode_out), torch.equal(z, posterior.squeeze(2))),
    and identity (p is posterior).

  - test_wrapper_forward_source_has_no_sample_access asserts
    ".sample" not in inspect.getsource(VideoAutoencoderKLWrapper.forward)
    so the failing pre-fix body raises an explicit assertion failure on
    the literal forbidden token.

Stubbing on the wrapper class (not the parent) bypasses the parent
encode/decode_ entirely, removes the lab_color_transfer monkey-patch,
and makes the AttributeError pre-fix path surface directly on
self.decode(z).sample because the stubbed decode returns a plain
tensor.
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