docs(render): close Campaign V slice V4a and file #249

V4a landed on the second attempt at 096dd203, verified independently: offline pixel gate passing at 22 differing pixels against an 8-26 same-commit noise band, App suite at exactly the 3,843/3 baseline, 26 files touched, no encoding damage. Three audits of the reverted first attempt found defects that outlive it - resident bindless handles never released, no test coverage for the Multisample state dimension, and no encoding guard - now tracked as #249.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-27 19:41:08 +02:00
parent 096dd203fa
commit 79ee2361ad
2 changed files with 54 additions and 0 deletions

View file

@ -97,6 +97,45 @@ Copy this block when adding a new issue:
---
## #249 — Bindless handles stay resident after their table slot is released
**Status:** OPEN
**Severity:** MEDIUM
**Filed:** 2026-07-27
**Component:** rendering / GPU resource lifetime
**Description:** `GlGpuDevice.ReleaseTextureSlot` zeroes the table entry and
returns the index to the free list, but never calls
`BindlessSupport.MakeNonResident`. Two consequences:
1. Callers go on to `glDeleteTexture` a texture whose bindless handle is still
resident, which `GL_ARB_bindless_texture` leaves undefined. Six other caches in
the tree (`TextureCache`, `CompositeTextureArrayCache`,
`StandaloneBindlessTextureCache`, `TerrainAtlas`) do call `MakeNonResident`
first, so the omission is inconsistent as well as unsafe.
2. Every released slot leaks a resident handle for the process lifetime, even
though the index itself is recycled.
**Provenance:** found by the Campaign V slice V4a audits. Introduced in V1
(`4f94ad7d`), not in either V4a attempt; present on the current tree.
**Also in scope for this issue** (same audits, same class of "no gate would have
caught it"):
- No test covers the `Multisample` dimension of `GlRenderStateCache`. Mistyping
that comparison would leave the whole suite green — that is exactly the
regression that forced the V4a revert (`9aaf97e7`). Add a positive test plus
`Assert.False(changes.Multisample)` in the existing negative cases.
- Add an encoding guard: an `.editorconfig` with `charset = utf-8` and a
`.gitattributes` text rule, plus a check that rejects newly introduced BOMs or
mojibake. The first V4a attempt re-encoded 259 files and corrupted non-ASCII
characters in 116 of them, and no existing gate noticed.
**Acceptance:** released slots make their handle non-resident before the texture
is deleted; a test proves the `Multisample` dimension is diffed; an encoding
guard fails on a reintroduced BOM.
---
## #248 — FrustumCuller extracts the near plane with the GL-convention formula
**Status:** OPEN

View file

@ -616,6 +616,21 @@ forces revert of good work along with bad. Do not change type visibility, do not
delete or weaken tests, and do not refactor adjacent code. If the slice genuinely
cannot land without one of those, stop and report instead.
**Outstanding hardening from the V4a audits.** Three independent audits of the
reverted attempt found defects that outlive it and are tracked as `#249`:
1. `GlGpuDevice.ReleaseTextureSlot` frees the table index but never calls
`BindlessSupport.MakeNonResident`. Deleting a texture whose handle is still
resident is undefined under `GL_ARB_bindless_texture`, and every released slot
leaks a resident handle for the process lifetime. This is V1 code, present on
the current tree.
2. No test covers the `Multisample` render-state dimension. Mistyping the
comparison in `GlRenderStateCache` would leave the whole suite green — the
very regression that reverted V4a.
3. There is no `.editorconfig` `charset` rule and no `.gitattributes` text rule.
The first attempt silently re-encoded 259 files and corrupted non-ASCII text in
116 of them, and **no gate noticed**.
**Pre-approved transitional seam.** The retained UI draws the paperdoll and
appraisal viewport textures, which are produced by renderers that stay raw GL
until V4g. The GL backend may therefore expose a documented way to register an