fix(acestep): C512 VAE windows on 1 GiB-capped adapters (iPhone memory) - #58
Merged
Conversation
…memory PR #55's capped C2176 window contract fixed the LIMIT_UNAVAILABLE device rejection on iPhone (2^30 maxBufferSize adapters), but generation now dies mid-song: the C2176 VAE phase holds three whole-window FP16 workspaces of 1,069,547,520 bytes each, a 3,448,065,296-byte accounted GPU phase on a 30 s song (the tracked peak of the capped e2e baseline), and iOS jetsam kills the Safari tab under that residency. Bindability was the wrong criterion on iPhone-class adapters; total resident workspace bytes are the binding constraint. selectAceVaeWindowRuntimeProfileForLimits now resolves a configured C2378 contract by what the adapter limits betray about the device, still purely limits-derived and never UA-sniffed: - At or below the one-GiB cap (every iOS WebGPU adapter reports exactly 2^30 for both buffer limits) the upstream C512 baseline geometry is selected: 3 x 251,658,240-byte workspaces, ~944 MB accounted VAE phase, a ~2.5 GB reduction. OPT-0035's correctness authority proved the overlap-64 discard decode byte-identical across window geometries, so the smaller authenticated window is exact by construction; the 30 s seed-12345 capped e2e WAV stays byte-identical (sha256 095267d7...). - Above one GiB but below the C2378 workspace the capped C2176 contract remains selected (desktop-class memory, only bindability short). - Below the C512 workspace the configured contract is returned unchanged so the device request fails closed with its true deficits; configured C512 contracts never change geometry. The derived device limit request consequently shrinks to the C512 workspace, merging to the base Stage-1 256 MiB contract that the whole pipeline (DiT included) ran under before OPT-0070 raised it for the C2378 workspace; a new plan test pins that every production DiT arena slot at the 240 s maximum still fits (largest: 73,728,000 bytes). The 240 s C512 decode is 16 bounded windows. The DiT phase itself is untouched and remains the capped-adapter peak (3.31 GB accounted at 30 s, 3.64 GB at 120 s, dominated by 3,150,917,888 bytes of resident fp16 weights). If the iPhone crash occurs during denoising rather than decode, only weight compression can fix it, which is out of scope here. Tests: selection matrix (one-GiB to C512, 1.1 GB to C2176, at/above C2378 unchanged, fail-closed below C512), 240 s C512 plan and workspace accounting, DiT arena slot fit, pipeline downshift and sub-C2378 intermediate tests. The OPT-0023 registered source hash for webgpu-pipeline.ts is refreshed for the comment change.
…window plan The capped C512 e2e failed at the last step with INVALID_GENERATION_RESULT: isVaeSchedulingReceipt reconstructed the expected chunk plan from the configured diagnostics identity (vaeMaxWindowFrames 512 or 2378), but the runtime plans windows from the adapter-derived effective geometry. PR #55's 30 s capped e2e passed this check only by coincidence: 750 latent frames are a single window under both C2176 and C2378, so the receipt matched the configured plan. Under the C512 downshift the same song decodes as two windows and the receipt was rejected after a fully successful generation. The validator now reconstructs the same authenticated selection the pipeline used: requireAceVaeWindowRuntimeProfile on the reported window identity, then selectAceVaeWindowRuntimeProfileForLimits over the reported adapter limits from the diagnostics capability report. Nothing is accepted by size alone, and an incoherent identity still fails closed inside the existing try/catch. The opt0080ProductionDiagnostics protocol fixture now advertises adapter limits that can actually bind the C2378 workspace (the base one-GiB fixture limits would downshift, making a C2314 depth-two receipt an impossible tuple on the reported adapter). The pipeline downshift tests now run a 30 s request (two C512 windows, mirroring the e2e regression) and assert isAceGenerationResultValue on the result for both the C512 and intermediate C2176 selections.
A blanket coherence error cost a debugging cycle; the reject message now lists which identity clause diverged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Real iPhone 17 Safari, after #55 (1 GiB buffer-limit cap) and #57 (portable subgroups): generation now starts and crashes midway through a 2-minute song — the iOS jetsam tab kill under memory pressure, not a WebGPU validation error.
#55 fixed bindability (no single buffer above 2^30) by downshifting the configured C2378 VAE windows to the capped C2176 contract. But bindability was the wrong criterion for what an iPhone-class adapter can hold: the FP16 VAE backend allocates three whole-window workspaces, so C2176 still resides 3 × 1,069,547,520 ≈ 3.21 GB of workspace during the decode phase. #55's own "Remaining iPhone risks" section called this out as untested.
Change
selectAceVaeWindowRuntimeProfileForLimitsnow resolves a configured C2378 contract by what the adapter's limits betray about the device — still purely limits-derived, never UA-sniffed:maxBufferSizeandmaxStorageBufferBindingSize): the upstream C512 baseline geometry is selected — 3 × 251,658,240 = 755 MB total workspaces, ~943 MB accounted VAE phase. C512 is upstream-authenticated: OPT-0035's correctness authority proved the overlap-64 discard decode byte-identical across window geometries, so the smaller authenticated window is exact by construction (re-verified below — same WAV sha256).The derived device limit request consequently shrinks on capped adapters from 1,069,547,520 to the C512 workspace, which merges under the base Stage-1 contract (268,435,456) — exactly the limits the whole pipeline (DiT included) ran under before OPT-0070 raised them for the C2378 workspace. A new plan-level test pins that every production DiT arena slot at the 240 s maximum still fits (largest slot: 73,728,000 bytes). The OPT-0080 depth-two VAE policy stays disabled off-C2378 (audited depth-one baseline), diagnostics keep reporting the configured window identity, and the 240 s maximum decodes as 16 bounded windows.
Second fix the e2e itself surfaced: receipt validation against the effective plan
The first capped e2e run of this branch completed generation and then failed with
INVALID_GENERATION_RESULT:isVaeSchedulingReceiptreconstructed the expected chunk plan from the configured diagnostics identity (512 or 2378 only). #55's 30 s e2e passed that check by coincidence — 750 latent frames are a single window under both C2176 and C2378 — but under C512 the same song decodes as two windows. The validator now reconstructs the same authenticated selection the pipeline used (requireAceVaeWindowRuntimeProfile→selectAceVaeWindowRuntimeProfileForLimitsover the adapter limits already present in the diagnostics capability report); nothing is accepted by size alone, and incoherent identities still fail closed. The OPT-0080 protocol fixture now advertises adapter limits that can actually bind C2378 (its previous one-GiB fixture limits made a C2314 depth-two receipt an impossible tuple on the reported adapter).Per-phase accounted GPU bytes on a capped (2^30) adapter
From the runtime's own memory planners (DiT: resident weights + arena + readback; VAE: weights + 3 workspaces + staging/output/readback/control):
The DiT→VAE release ordering is real, not aspirational: the pipeline drains and destroys the DiT owner (
dit-drain-and-destroy,hardBoundaryBeforeVae: true) before the VAE package is even acquired, and the suite assertsvae-acquireorders afterdit-destroy. Phases do not stack; the per-generation peak is the max of the rows above.Plain statement of what this does and does not fix
Selection matrix (vendored vitest, extended per the #55 pattern)
Verification
npm run acestep:test: 216 files, 2025 passed, including newvae-capped-c512-downshift.test.ts(selection resolution, 240 s C512 plan + workspace accounting + per-buffer fit, DiT arena slot fit under the C512-derived device limits) and updated pipeline tests (2^30 → C512 end to end with a 30 s two-window request validated throughisAceGenerationResultValue; 1.1 GB → C2176 intermediate; fail-closed threshold below C512).npx tsc --noEmit,npm run build,npm run format:checkall clean (prettier does not touch the vendored package).src/runtime/webgpu-pipeline.tsre-pinned in the OPT-0023 browser contract (comment-only change at thederiveRequiredLimitsseam); nooptimization/records touched.E2E on real Chrome + WebGPU, adapter capped to 1,073,741,824 via
?aceTestMaxGpuBufferBytes(#55 seam)adapterLimits.maxBufferSize=1073741824,requestedLimits.maxBufferSize=268435456(was 1069547520),deviceLimits.maxBufferSize=268435456; the VAE ran as two C512 windows and the scheduling receipt validated.095267d7be0317ed9af10c64b8495d573b43207cd86615b6bbe66f27dc17895d— same as the fix(acestep): support 1 GiB-capped WebGPU adapters (iPhone) #55 capped baseline and the uncapped desktop baseline.LIMIT_UNAVAILABLE: maxBufferSize must be at-least 1168834560; adapter reports 200000000) — no downshift below the authenticated geometry.