docs: the overnight consolidation report, open questions first

Adds `docs/reports/2026-07-29-overnight-report.md` and brings the Campaign V
report page's status section in line with what is actually true.

The report leads with what needs the user, because most of it is genuinely
blocked rather than merely unfinished: the #259 reboot and the five V11 runtime
gates behind it, the enum campaign's three decisions (adopt `WeenieError`
wholesale? adopt retail's `SoundId` table or record our subset as a divergence?
re-clone the reference repos), the wire audit's one instrumented session, and
the walked-portal follow-up for #256/#257. Then what landed, with numbers, then
Campaign V's final state.

Two notes worth surfacing rather than burying. `references/` is empty **in the
main checkout**, not just in a worktree — which is why 456 of the enum
campaign's 864 property members are single-sourced, and why CLAUDE.md's
"cross-reference at least two of them" is currently unexecutable as written.
And two `MEMORY.md` entries index research documents that exist nowhere: not in
the tree, not under any ref, and the memory directory has no `research/` folder
at all. Two separate sessions hit that wall tonight and both regenerated from
scratch. User-level memory is out of my reach, so it is recorded as a
needs-user item with the two documents that supersede them.

The Campaign V page said V8 was running, V9 pending and V10/V11 ahead. All four
have landed. Its status section now records the deletion (204 files, +1,870 /
-27,607), the three findings worth keeping — Chorizite survives on the pak
format rather than on `IUniformBuffer`, `Studio/SampleData.cs` was production
code, and `WbMeshAdapter.Dispose()`'s GPU-work wait had been silently dead since
V6a — and, plainly, that the runtime gates did not run because this machine
cannot create a Win32 Vulkan surface for any process. A gate that could not run
is not a gate that passed. The #248 and #250 entries are updated to DONE with
their outstanding halves named.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-29 03:54:43 +02:00
parent 200f19ce47
commit b023ac95f0
2 changed files with 477 additions and 27 deletions

View file

@ -238,31 +238,57 @@ that mattered. That's the campaign's per-slice discipline working as intended:
## Current status ## Current status
- **V8 (performance gate)** is **running**. Its first commit landed the > **Updated 2026-07-29.** The campaign is **complete**. V8 through V11 have all
missing instrument: the Vulkan arm had been silently wired to > landed; the tree is statically green and OpenGL is gone. What remains is
`NullRenderFrameGpuMeasurement` and emitted no `[frame-prof]` line at all, so > runtime evidence for V11, which is blocked by a **machine fault rather than a
the campaign's own performance tooling had nothing to point at it. GPU > campaign result** — see below and
timestamp measurement now brackets identically on both arms. The acceptance > [`2026-07-29-overnight-report.md`](2026-07-29-overnight-report.md) §1.1.
table (CPU frame p50 ≤ 1.60 ms, GPU p50 ≤ 1.00 ms, working set ≤ 600 MiB,
private set ≤ 860 MiB, 0 B/frame managed allocation, CPU/GPU p99 ≤ GL) is the - **V8 (performance gate)**, **V9 (Linux CI)** and **V10 (cutover)** are
next thing this slice measures against the RX 9070 XT. **complete**. V8's first commit landed the missing instrument: the Vulkan arm
- **V9 (Linux CI)** is **implemented, first CI run pending**. A `linux-vulkan` had been silently wired to `NullRenderFrameGpuMeasurement` and emitted no
job now runs the probe on lavapipe under Xvfb, asserts a clean accepting `[frame-prof]` line at all, so the campaign's own performance tooling had
verdict, checks the forced-unsupported exit-4 path, and verifies committed nothing to point at it. V9's `linux-vulkan` job runs the probe on lavapipe
`.spv` binaries are byte-identical to a fresh compile. lavapipe satisfies under Xvfb, asserts a clean accepting verdict, checks the forced-unsupported
every one of the seventeen gated features, including `samplerAnisotropy`, exit-4 path, and verifies committed `.spv` binaries are byte-identical to a
which V7 made load-bearing. The physical Linux GPU row and Wayland stay fresh compile. V10 made Vulkan the default backend behind the user's visual
deferred on the same precedent as Slice L. sign-off; the one open finding from that session is #253 below. The physical
- **V10 (cutover)** is **ahead**: Vulkan becomes the default backend, GL stays Linux GPU row and Wayland stay deferred on the same precedent as Slice L.
reachable by environment variable for one further slice, and **user visual - **V11 (closeout)** is **deleted and statically green; runtime gates
sign-off** is the gate — the same kind of connected session the user already outstanding.** Five commits (`844cf092``c265b52d`) removed **27,607 lines
ran once mid-campaign (six targeted checks, all passed with merits: the AD-46 against 1,870 added** across 204 files. `Gpu/Gl`, `OpenGLGraphicsDevice`, the
treeline judged invisible in practice, dyed-gear composites, doorway `ManagedGL*` stack, `GLHelpers`, `GLStateScope`, both render-state caches,
look-out/threshold crossing, stacked translucency, icon/text crispness, and `BindlessSupport`, `GraphicalGlFunctionProbe`, the ImGui project, the Studio
motion feel — the one open finding from that session is #253 below). tree, the `ui-studio` verb, `RenderBackendKind` and the
- **V11 (closeout)** deletes `Gpu/Gl`, `OpenGLGraphicsDevice`, the `ACDREAM_RENDER_BACKEND` escape hatch are all gone. `Silk.NET.OpenGL` and
`ManagedGL*` stack, the ImGui developer stack, and UI Studio, and re-measures `.Extensions.ARB` are dropped — **final reference count zero**. 9/9 shader
working set one final time. pairs recompile.
**Three findings from the deletion.** *Chorizite could not be dropped*, and not
for the reason the risk register predicted: `TextureFormat` sits in the
`IWorldTextureArray.CreateClampedArray` signature the **Vulkan** path
implements, and `BoundingBox` is a **serialized type in the pak format**, so
removing it touches the on-disk format and is its own slice.
*`Studio/SampleData.cs` was production code*, not devtools —
`InteractionRetainedUiComposition` uses it as the character sheet's fallback —
so it was moved, not deleted. And *one real bug fell out*:
`WbMeshAdapter.Dispose()` was still pattern-matching the deleted
`GpuFrameFlightController` to decide whether to wait for submitted GPU work.
`VulkanFrameFlightController` replaced that type at V6a and the site was never
updated, so **the wait had been silently dead on every Vulkan run since V6a**.
Deleting the GL type is what turned a no-op into a compile error.
**Why the runtime gates did not run.** The offline pixel gate died at startup in
`vkGetPhysicalDeviceSurfaceCapabilitiesKHR`. Bisecting put the fault outside the
tree — the client fails identically at a pre-V11 commit whose offline capture had
succeeded three hours earlier — and `vulkaninfo --summary`, a Khronos tool
containing no acdream code, fails at the same call. Win32 surface creation is
broken process-wide on this machine ([#259](../ISSUES.md)); Vulkan itself is
healthy and both adapters report 1.4. Nothing was relaxed to manufacture a pass
and nothing was declared green on a prediction — a gate that could not run is not
a gate that passed. The outstanding commands are listed in the overnight report;
the pre-deletion baseline for the self-differential is already on disk at
`artifacts/v11-pre`.
--- ---
@ -271,7 +297,10 @@ that mattered. That's the campaign's per-slice discipline working as intended:
- **[#248](../ISSUES.md)** — `FrustumCuller` extracts its near plane with the - **[#248](../ISSUES.md)** — `FrustumCuller` extracts its near plane with the
GL `[-1,1]`-NDC formula against a `[0,1]`-NDC projection; harmless today GL `[-1,1]`-NDC formula against a `[0,1]`-NDC projection; harmless today
(makes culling strictly more permissive near the eye) but wrong hygiene. (makes culling strictly more permissive near the eye) but wrong hygiene.
OPEN. **DONE 2026-07-29**`near = Normalize(col3)`, pinned by a theory asserting
the extracted near distance equals the camera's near value across four
near/far pairs; the old formula fails all four. The gate half of its
acceptance (offline pixel gate + connected route) is outstanding under #259.
- **#249** — Released bindless texture slots never call `MakeNonResident` - **#249** — Released bindless texture slots never call `MakeNonResident`
before the texture is deleted, which `GL_ARB_bindless_texture` leaves before the texture is deleted, which `GL_ARB_bindless_texture` leaves
undefined, and leaks a resident handle for the process lifetime per release. undefined, and leaks a resident handle for the process lifetime per release.
@ -279,7 +308,14 @@ that mattered. That's the campaign's per-slice discipline working as intended:
- **#250** — Four "zero managed allocation" tests fail intermittently, roughly - **#250** — Four "zero managed allocation" tests fail intermittently, roughly
one run in three, from tiered-JIT/GC measurement noise rather than a real one run in three, from tiered-JIT/GC measurement noise rather than a real
regression — but an acceptance-gating test that flakes trains everyone to regression — but an acceptance-gating test that flakes trains everyone to
re-run until green. OPEN. re-run until green. **DONE 2026-07-29**, and it was not noise: in all four the
measured window was never the warmed path — two measured a thousand-iteration
loop written inline (which on-stack replacement rewrites mid-flight, on the
measuring thread), and two measured a code path the warmup had never taken.
Fixed with a shared `ZeroAllocationProbe` that measures already-warmed batches
and reports their minimum; **the zero bound is unchanged and the apparatus has
its own tests proving it can still fail.** The family turned out to be ten
tests, not four. 20/20 clean App-suite runs.
- **#251** — `glClientWaitSync` returned a fence status of `0` (not a value - **#251** — `glClientWaitSync` returned a fence status of `0` (not a value
the API is specified to return) and crashed the render loop once in nine the API is specified to return) and crashed the render loop once in nine
connected runs; possibly the same below-the-API driver family the connected runs; possibly the same below-the-API driver family the

View file

@ -0,0 +1,414 @@
# Overnight consolidation — 2026-07-29
**Branch:** `claude/git-sync-status-5fb1d2`
**Started at:** `d312bd2f` (Campaign V slice V11 landed; OpenGL deleted)
**Sessions merged:** the enum verification campaign and the wire-stack audit
**Machine constraint:** [#259](../ISSUES.md) — Win32 Vulkan surface creation is
broken process-wide, so **no client was launched**. Everything below is build,
test and documentation.
---
## 1. What needs you
Open questions first, because several of them gate work that is otherwise ready
to start. Nothing here is blocked on more analysis — each one needs a decision or
a machine that can make a window.
### 1.1 Reboot the machine, then run five gates
`vulkaninfo --summary` — a Khronos tool containing no acdream code — fails at
`vkGetPhysicalDeviceSurfaceCapabilitiesKHR` with `ERROR_UNKNOWN`. Vulkan itself
is healthy (both adapters enumerate and report 1.4); Win32 *surface* creation is
what is broken, and it is broken for every process on the box. It was bisected
to a pre-V11 commit whose offline capture had succeeded three hours earlier, so
it is transient driver/compositor state of the class a reboot clears.
V11 is committed and statically green. Its runtime evidence is outstanding, and
this is the exact outstanding list from campaign §5.5.24:
| Gate | Command |
|---|---|
| Offline pixel gate (VK self-differential) | `tools/run-offline-pixel-gate.ps1 -Out artifacts/v11-post -Baseline artifacts/v11-pre -SkipBuild` |
| Repeat connected gate | `tools/run-repeat-connected-gate.ps1 -Runs 3` |
| Connected world-lifecycle route | `tools/run-connected-world-lifecycle-gate.ps1` |
| Validation proven-loaded, zero errors | any connected launch with `ACDREAM_DEVTOOLS=1` |
| Working-set re-measure | the offline scene, once it renders |
The pre-deletion baseline for the self-differential is **already on disk** at
`artifacts/v11-pre`, captured before the deletion. The left-hand side of the
comparison survived the fault; only the right-hand side is missing.
**Also now runtime-outstanding:** [#248](../ISSUES.md)'s near-plane fix landed
tonight with a unit test, but its other acceptance criterion — unchanged culling
in the offline pixel gate and the connected route — needs the same window. The
change can only tighten culling toward the true frustum, which the issue had
already established is the safe direction, but it has not been seen running.
### 1.2 Three decisions the enum campaign could not make
The campaign explicitly refused to guess on these and recorded them rather than
inventing an answer. All three are yours.
1. **`WeenieError` — adopt 362 server-side status codes wholesale?** acdream has
16 members; the catalog's `StatusMessage` has 372, with 10 shared and **zero
conflicts**. Retail's `charError` (26 members) is a *different* enum —
character-creation errors only — so retail cannot arbitrate this one. Register
row AP-15 already tracks that our translation table covers only ~30 common
codes. Ideally paired with retail's `string_table.bin` for the real sentences.
2. **`SoundId` — adopt retail's table, or record the subset as a divergence?**
Ours is a curated 23-member local subset of retail's `SoundType` (206), with
acdream-local names (`FootstepGrass`, `BuffApplied`) that do not correspond
1:1 to retail members. Either adopt wholesale, or give it a register row.
Neither was done.
3. **Re-clone the reference repos.** Five of six are empty — **and this is true
of the main checkout, not just a worktree.** It has two concrete costs. The
enum campaign left **456 of 864 property members single-sourced** (transcribed
from the catalog, no independent attestation) that ACE and Chorizite would
promote to two-oracle confirmed. And CLAUDE.md's "cross-reference at least two
of them" is currently unexecutable as written, so every session re-solves it
privately — four duplicate ACE copies under `%TEMP%` are the evidence. Working
copies exist at `C:\Users\erikn\source\repos\client\ACE` and
`C:\Users\erikn\source\repos\holtburger`; **Chorizite.ACProtocol was not found
anywhere on disk** and needs a genuine re-clone.
A fourth, cheaper lead the campaign flagged but could not pursue: the client
DAT's own `EnumMapper` file type is a genuinely *retail* oracle for property
names, and `acclientlib` already has a reader for it. That is the most promising
unexplored route to attesting the single-sourced members without any re-clone.
### 1.3 One instrumented connected session
The wire audit's highest-leverage next action, and it needs a connected client:
```
ACDREAM_DUMP_OPCODES=1
```
on an otherwise normal Coldeve session. The audit catalogued all 349 opcodes but
could not *rank* the 128 MISSING rows, because nothing tells it which of them the
server actually sends during play. One environment variable converts "128 missing
parsers, unknown priority" into a real work order. This is the cheapest
high-value item on the board.
### 1.4 Walked-portal follow-up for #256 and #257
Both were observed in the same long live Coldeve session with repeated
town-portal-network transits, and both are HIGH:
- **#256** — server-spawned signs and portals go *visually* missing after
repeated transits while remaining interactive, so the entity is alive in the
object table and only its render projection is gone.
- **#257** — working set balloons to ~1.5 GB against the ~930 MiB neighborhood
the campaign baselines measured, suggesting per-transit accumulation.
Neither has been reproduced since, and neither can be worked without a client.
Both are marked "backend attribution pending" — whether they are Vulkan-era or
pre-existing is unknown, and a walked portal-network session is the only thing
that settles it. Worth doing in the same sitting as §1.1, since the machine will
already be up.
### 1.5 Two `MEMORY.md` entries point at documents that do not exist
Out of my reach to fix — user-level memory lives outside this repo — so flagging
it here instead.
`claude-memory/MEMORY.md` indexes `research/2026-06-04-property-enum-divergence.md`
(the "929 values across 7 enums" ledger) and
`research/2026-06-04-magic-number-audit.md`. **Neither exists** — not in the
working tree, not under any ref (`git log --all --diff-filter=A` finds no add),
and the memory directory has no `research/` subfolder at all. The same pattern
holds for the 2026-06-04 combat-math and wire-catalog drops.
This has a real cost, already paid twice tonight. The enum campaign could not
reproduce or audit the 929 figure and regenerated from scratch, arriving at 864
property members; the wire audit hit the identical wall. A link that silently
resolves to nothing is worse than no link, because a future session plans around
a document that does not exist. Suggest either restoring them or repointing those
index entries at the two documents that landed tonight, which supersede them:
- `docs/research/2026-07-29-enum-verification-campaign.md`
- `docs/research/2026-07-29-wire-stack-audit.md`
---
## 2. What landed overnight
Six commits on `claude/git-sync-status-5fb1d2`, `d312bd2f``HEAD`.
### 2.1 The enum verification campaign (merged)
`github/overnight/enums` (`c19680fd`, 5 commits) merged **with no conflicts**.
It was cut at `b70b9832`, before the deletion, and its subject turned out to be
disjoint from V11's: the campaign lives entirely in `AcDream.Core` and its tests,
while V11 emptied `AcDream.App`. Not one file was touched by both.
- 17 files, **+3,767 / 27** lines
- **+597 tests**, verified exactly — the `Properties` namespace alone runs 597
- Names for AC's seven property tables, verified against two oracles
- Corrections to `DamageType`'s rotated bits and `ItemType`'s shifted craft ladder
- The retail members the equipment and physics enums were missing
- Names for `AmmoType`, `CombatUse` and `ItemUseable`
### 2.2 The wire-stack audit (merged)
`github/overnight/wire-audit` (`41f74fcd`, 6 commits), same base, **one conflict**
— see §2.3.
- 14 files, **+2,068 / 38** lines
- **+59 tests**; `AcDream.Core.Net.Tests` went 600 → 659
- **Three real parser fixes:** ranged speech carries a range float the parser was
eating; a chat type that is never sent was silently dropping every transient
string on it; `xpSpent` is a dword on the wire where we were writing eight bytes
- The transport flag word pinned against ACE across all 23 bits
- Golden fixtures generated from ACE's own writer rather than hand-typed hex
- The audit document, covering all 349 opcodes
### 2.3 The one merge conflict: #255, reconciled
Both branches reopened **#255** — the `RetailDatLoader` concurrency tests that
measure the thread pool rather than the loader — on the same day, from different
trees, without knowing about each other.
Neither is a duplicate. The V11 closeout saw **2 failures in 5** complete-solution
Release runs on the post-deletion tree; the wire-audit session saw **2 in 4** on
the pre-deletion tree; both saw **124/124 in isolation every time**. They
independently reached the same conclusion — `TaskCreationOptions.LongRunning` is
a hint, not a guarantee — and independently proposed the same fix, a rendezvous
inside the read stub.
Resolved by merging the two notes into one issue with **both evidence sets kept**
as labelled subsections, rather than one overwriting the other. Four failures
across nine runs on two trees is a materially stronger case than either half, and
the agreement between two blind observations is the part worth preserving. No
assertion was weakened; the fix itself remains open.
My own 20-run baseline tonight independently reproduced it a third time —
**4 failures in 20** complete-solution runs — which is consistent with both.
### 2.4 #248 — the near plane is `col3`, not `col4 + col3`
`FrustumPlanes.FromViewProjection` extracted the near plane with the
Gribb-Hartmann form written for OpenGL's `[-1,1]` clip-space z range, against
projections from `Matrix4x4.CreatePerspectiveFieldOfView`, whose range is `[0,1]`.
Under `[-1,1]` the near plane is `clip.z = -clip.w`, which is `col4 + col3`;
under `[0,1]` it is `clip.z = 0`, which is `col3` alone.
The error put the effective near threshold at `-n·f/(2f-n)` — about 0.5 m where
the retail chase camera asks for 1.0 m — which only ever *kept* geometry the true
frustum would have dropped. Harmless, and still wrong; it is the same mistake
that *was* visible in `PortalProjection`, where it culled the cell behind a
doorway the camera stood close to.
Pinned by a theory over four near/far pairs asserting the extracted plane is unit
length, faces down -Z, and stands off the eye by exactly the camera's near value.
**The test was run against the old formula before commit and fails all four
cases**, so it measures the fix rather than merely accompanying it. The far plane
is unchanged under both conventions and is pinned alongside so a later edit
cannot drift it.
Status: DONE for the unit-test half of its acceptance criterion; the gate half is
in §1.1.
### 2.5 #250 — fixed at the measurement, and the family was larger than four
**The four named members shared one root: the measured window was never the
warmed path.** This had been dismissed as inherent noise in
`GC.GetAllocatedBytesForCurrentThread` three separate times. It is not noise.
| Test | Warmup | Measured window |
|---|---|---|
| `UiDatFontTests` | 1 call | a **10,000-iteration loop** written inline |
| `RenderFrameProductTests` | **8** calls | a **1,000-iteration loop** written inline |
| `CurrentRenderSceneOracleTests` | 1 call | a 10,000-iteration loop written inline |
| `ArchRenderSceneTests` | `Apply(registrations)` | `Apply(**updates**)` — a different switch arm |
Two mechanisms follow. A test method is JIT-compiled at tier 0 like anything
else, and a long-running loop in tier-0 code is replaced mid-flight by **on-stack
replacement**, which compiles on the thread running the loop — so its bookkeeping
is charged to the window being measured. That is the loop-shaped ones. And
`ArchRenderSceneTests` warmed one arm of a switch and measured the other, so the
measured call was the first ever into `ApplyUpdate` and paid that arm's tier-0
JIT, type loads and static initialisation inside the window;
`RenderFrameProductTests` warmed 8 times, below the tier-0 call-counting
threshold of **30**, so promotion was still pending when measurement began.
That also explains the signature nobody could account for — clean in isolation,
failing about one run in three. Alone, the process is quiet and the runtime has
finished before the assertion arrives. Alongside eight other test assemblies,
tier-0 compilation never stops, the call-counting delay is re-armed continually,
and the work slides into the window.
**The fix** is `tests/AcDream.App.Tests/ZeroAllocationProbe.cs`. It invokes the
step many times before measuring anything, then measures windows that run the
same already-warmed loop over the same already-taken path. Each window is a
**batch** of 32 invocations and it reports the **minimum** across 4 of them. Both
halves are load-bearing: the minimum excludes a one-time cost, and the batch is
what keeps the assertion as strong as the loops it replaces — minimising over
*single* invocations would report zero for a path that allocates every tenth
call. I had written it that way first and the apparatus test caught it.
**The bound is untouched: exactly zero, no tolerance, no retry, no assertion
relaxed.** `ZeroAllocationProbeTests` proves the apparatus can still fail — a
step allocating every call reads above zero and does throw, a first-invocation
cost reads as zero, a cost every tenth call is caught, and the one stated limit
(the batch must cover the period) is pinned as a test rather than left as prose.
**The family was larger than four.** The first pass converted only the named four.
A 20-run baseline disproved "none of the others has been observed failing" within
minutes — `LiveEntityRuntimeTests` failed in run 2, `StaticRenderProjection`
`JournalTests` in runs 14 and 18, both the same shape, neither previously
recorded. Run 19 was sharper still: the issue named
`SurfaceOverrideFingerprint_DictionaryHotPathAllocatesNothing`, and the first
pass had converted a *different* test in that same file. Matching by file was not
matching by test.
All ten strict-zero sites are now on the probe. **Two came out stricter rather
than merely steadier:**
- `StaticRenderProjectionJournalTests` was measuring a synchronise whose journal
**does not coalesce**. Repeating it grew the journal by 1,000 entries per call
— 192,000 by the end of a probe run — so the steady state it claimed to test
did not exist, and the single-call window had been hiding that. Its step is now
the whole frame cycle, synchronise *and* drain, putting `DrainTo` inside the
measured window for the first time.
- `RetailInboundEventDispatcherTests` asserted a hard-coded 1,001 callbacks; it
now counts its own dispatches and pins the callback count against them.
Four sites asserting a *tolerance* rather than zero were deliberately left alone
(`CellViewDedupTests` ×2, `PortalProjectionTests` ×2) — their ceilings already
absorb this noise and none has flaked. `PortalProjectionTests` is worth
revisiting: its ceiling exists explicitly to tolerate "a tiered-JIT/ArrayPool
bookkeeping transition ... to the first measured batch", which is exactly what
the probe removes, so it could probably be tightened to zero now.
**Acceptance:** the issue asks for 20 consecutive clean Release runs of the App
suite. See §4 for the count actually achieved and how to read it.
### 2.6 Worktree sweep
Removed **9** finished worktrees — the two temp ones
(`%TEMP%\claude\prerevert`, `%TEMP%\claude\v4a-verify-base`) and seven
`agent-a*` paths including the two whose branches were merged tonight. Pruned
afterward. `codex/*`, `.worktrees/*` and the named `claude/*` worktrees were not
touched.
**Two were deliberately left in place**, because "finished" is load-bearing and
neither is:
- `agent-a1589ee2f5360c7a2` — has an **unresolved merge conflict** (`UU
src/AcDream.Core/Physics/TransitionTypes.cs`), three other modified physics
files, and an untracked new `EdgeSlideTests.cs`. This is in-progress L.2.3
step-up/step-down work belonging to some other session, not tonight's.
- `agent-af83539515c87d43e` — has an uncommitted **1,073-line** edit to
`WbDrawDispatcher.cs` (961/+112), an in-progress GL-removal pass. V11 has
since landed the equivalent, so this is probably superseded scratch — but it is
a thousand lines of uncommitted work and deleting it is not reversible.
Both are yours to keep or discard.
---
## 3. Campaign V — final state
**The campaign is complete and the tree is statically green. Its runtime
evidence is outstanding, and that is a machine fault rather than a campaign
result.**
V11 removed the GL backend across 5 commits (`844cf092``c265b52d`): 204 files,
**+1,870 / 27,607** lines. Gone are `Gpu/Gl`, `ManagedGL*`, `GLHelpers`,
`GLStateScope`, both render-state caches, `BindlessSupport`,
`GraphicalGlFunctionProbe`, the ImGui project, the Studio tree, the `ui-studio`
verb, `RenderBackendKind` and the `ACDREAM_RENDER_BACKEND` escape hatch.
`Silk.NET.OpenGL` and `.Extensions.ARB` are dropped — **final reference count
zero**. 9/9 shader pairs recompile.
Three findings from the deletion are worth keeping:
- **Chorizite could not be dropped, and not for the reason the risk register
predicted.** It was assumed to survive only via `IUniformBuffer`. In fact
`TextureFormat` sits in the `IWorldTextureArray.CreateClampedArray` signature
that the **Vulkan** path implements, and `BoundingBox` is a **serialized type
in the pak format**. Dropping it touches the on-disk format and is its own
slice.
- **`Studio/SampleData.cs` was production code**, not devtools —
`InteractionRetainedUiComposition` uses it as the character sheet's fallback.
Moved, not deleted.
- **One real bug fell out.** `WbMeshAdapter.Dispose()` was still pattern-matching
the deleted `GpuFrameFlightController` to decide whether to wait for submitted
GPU work. `VulkanFrameFlightController` replaced that type at V6a and the site
was never updated, so **the wait had been silently dead on every Vulkan run
since V6a**. Deleting the GL type is what turned a no-op into a compile error.
Nothing was relaxed to manufacture a pass and nothing was declared green on a
prediction. A gate that could not run is not a gate that passed — the outstanding
list is §1.1.
---
## 4. Numbers
### Complete solution suite
| | Passed | Skipped | Total |
|---|---|---|---|
| V11 baseline (`d312bd2f`) | 8,999 | 5 | 9,004 |
| **Tonight (`HEAD`)** | **9,666** | **5** | **9,671** |
The **+667** decomposes exactly, with nothing unaccounted for:
| Source | Tests |
|---|---|
| Enum verification campaign | +597 |
| Wire-stack audit | +59 |
| #248 near-plane theory (4 near/far pairs) + far-plane pin | +5 |
| #250 `ZeroAllocationProbe` apparatus guards | +6 |
| **Total** | **+667** |
Per project at `HEAD`: App 3,941/3 · Core 3,898/2 · Core.Net 659 · UI.Abstractions
543 · Runtime 415 · Content 124 · Headless 67 · Bake 15 · Cli 4. **Zero failures.**
Release build: **0 errors.** 21 warnings, all pre-existing — one `xUnit1025`
(duplicate `InlineData` in `MotionInterpreterTests`) and a family of `CS8767`
nullability mismatches in the App test composition fakes. None cites a file
touched tonight; the count is unchanged from the V11 baseline.
### The #250 acceptance gate
The issue asks for 20 consecutive clean Release runs of the **App suite**, and
that is the right scope: it isolates #250 from #255, which lives in
`AcDream.Content.Tests` and is still open.
**Result: 20 / 20 clean, 3,941 passed / 3 skipped every run.**
For contrast, the pre-fix 20-run **complete-solution** baseline taken earlier the
same night, on the same machine:
| Failure | Runs |
|---|---|
| #250 family (3 distinct tests) | 2, 14, 18, 19 |
| #255 `RetailDatLoaderTests` | 7, 14, 17, 18 |
So the #250 family went from 4 failing runs in 20 to 0 in 20, and the three tests
involved were each converted. **#255 is untouched and still flakes** — it is a
different issue with an open fix, and it will keep appearing in
complete-solution runs until the rendezvous lands.
One caveat, stated plainly: 20 consecutive App-suite runs is what the acceptance
criterion asks for and what was delivered, but the App suite alone applies less
parallel pressure than a complete-solution run. The strongest evidence would be
20 clean complete-solution runs, and that is not currently obtainable while #255
flakes independently. Re-running this gate after #255 is fixed would close that
gap.
---
## 5. Where to pick up
1. Reboot, then §1.1's five gates and §1.4's walked portal session — one sitting.
2. Answer §1.2's three enum decisions; they unblock adoption commits that are
otherwise ready.
3. One `ACDREAM_DUMP_OPCODES=1` session (§1.3) turns the wire audit's 128 MISSING
rows into a ranked work order.
4. #255's rendezvous fix — the diagnosis is settled from three independent
observations and the fix direction is agreed; it is only unwritten.