#125 filed + WB-DIAG median crash fixed - the #119 stairs mechanism is a sticky GL upload failure

The in-tower ACDREAM_WB_DIAG launch (the saved character spawns inside
the #119 tower - a free deterministic repro lever) produced the
mechanism evidence in one run (tower-wbdiag3.log):

1. [wb-error] upload of 0x0100321D died on a GL InvalidOperation in
   ManagedGLTextureArray..ctor (new TextureAtlasManager) - caught,
   returns null, and the drop is STICKY: _preparationTasks.TryRemove
   runs BEFORE the upload, so a failed upload is never re-prepared.
   Permanently invisible mesh, one log line. This failure class is the
   likely #119 missing-stairs mechanism (dat + extraction +
   registration + dispatcher all exonerated by read/test this session).
2. The SAME GL error then fired UNCAUGHT in Tick -> GenerateMipmaps ->
   ProcessDirtyUpdatesInternal and killed the process. Both render-
   thread - not thread affinity. Filed as #125 (HIGH) with the open
   question of GL error attribution (a stale error queued by an earlier
   unchecked call lands on WB's diligent glGetError checks).

Also fixed here: WbDrawDispatcher.MedianMicros crashed with
IndexOutOfRange on the first diag flush when exactly 1 sample was
recorded (copy[copy.Length - nz/2] with nz==1) - the same off-by-one
GameWindow's TerrainDiagMedianMicros twin fixed; same fix applied.
ACDREAM_WB_DIAG=1 is usable again.

Suites: App 236, Core 1419+2skip, UI 420, Net 294.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-11 18:08:46 +02:00
parent 1b8c9f1f50
commit 63d14c3d6b
2 changed files with 50 additions and 1 deletions

View file

@ -1583,7 +1583,12 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
int nz = 0;
foreach (var v in copy) if (v > 0) nz++;
if (nz == 0) return 0;
return copy[copy.Length - nz / 2];
// Sorted ascending: zero-padding front, samples at the back. (nz - 1) / 2
// from the end keeps the offset >= 0 for all nz >= 1 — the original
// nz / 2 form indexed copy[copy.Length] (crash) on the first diag flush
// when exactly 1 sample was recorded. Same fix as GameWindow's
// TerrainDiagMedianMicros twin.
return copy[copy.Length - 1 - (nz - 1) / 2];
}
private static long Percentile95Micros(long[] samples)