A slice block's lying base can no longer ship as a complete frame #398

Merged
enricobuehler merged 1 commits from worktree-slice-tiling-guard into main 2026-08-26 14:48:15 +00:00
1 Commits
Author SHA1 Message Date
enricobuehler e684b3e4bd fix(core): a slice block's lying base can no longer ship as a complete frame
ci / docs-drift (pull_request) Successful in 27s
ci / bun-nix (pull_request) Successful in 52s
ci / docs-site (pull_request) Successful in 1m10s
ci / web (pull_request) Successful in 1m39s
apple / swift (pull_request) Successful in 2m10s
apple / distribute (pull_request) Skipped
apple / screenshots (pull_request) Skipped
ci / rust-arm64 (pull_request) Successful in 2m50s
ci / rust (pull_request) Successful in 5m29s
android / android (pull_request) Successful in 6m27s
windows-client / client (arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (pull_request) Successful in 4m5s
windows-client / client (x64, , x86_64-pc-windows-msvc, C:\t) (pull_request) Successful in 7m21s
A slice-streamed sentinel's wire base was bounds-checked (in range, below
the final block) but never validated to TILE the AU: a base that lied
within bounds left a zero gap and an overlap, and the reassembler still
stamped the frame `complete`. The decoder then painted the wrong-offset
bytes as garbage rectangles while no loss counter moved — so the recovery
machinery never fired and the corruption marched on indefinitely (the
field report: black bars 'moving like an equalizer', identical across
Vulkan/DXVA/CPU decoders, Android immune because it never negotiates the
slice wire).

At completion, verify the blocks tile [0..total_data] contiguously; a
frame that doesn't is killed exactly like a lying final header — index
remembered against stragglers, counted into frames_dropped, which is the
signal that arms the freeze gate and requests recovery. The
slice-progressive prefix walk gets the same contiguity guard so a lying
base can't extend a 'contiguous' prefix either.
2026-08-26 16:28:11 +02:00