docs(render): V11 closeout — register, architecture, code structure, issues

Retires the GL framing from the documents that described a two-backend,
two-UI-stack client, and files what the deletion left behind.

Divergence register:
  * AD-46 (anisotropic tap pattern in dense alpha scenery) is REFRAMED rather
    than retired. Its substance survives -- distant foliage may read denser
    than retail's -- but it was measured GL-vs-Vulkan, and with GL gone it is
    a Vulkan-vs-retail question against the D3D oracle it already cited. The
    measurement is kept as the evidence that the residual is a driver tap
    pattern; the row now records that it is no longer falsifiable by
    self-differential, which is a real loss the deletion causes.
  * AD-47 and AD-48 are NEW, and the campaign's own risk register scheduled
    them here: MSAA sample positions (measured at 8.83% of the frame at 4x,
    which is why every strict gate runs MSAA off -- and therefore why a
    regression confined to the multisample path would not be caught) and
    present pacing (#235 is the live instance).
  * AD-17's justification moves from a GL clip-plane citation to Vulkan's
    maxClipDistances floor, which is the same 8, so the divergence is
    unchanged and only its authority moves.
  * AP-92 keeps IUiViewportRenderer.TextureIsBottomUp rather than folding it
    flat, because it is what let the origin question be answered by data.

Architecture and code structure: the layer diagram, the frame order, the
residency vocabulary and the reference table all said OpenGL. The UI section
said two stacks. Rule 3's rationale is rewritten around what actually
happened -- ImGui was deleted and not one panel, ViewModel or command had to
change, because none of them had ever imported ImGuiNET. That is the rule
paying for itself, so it is recorded as evidence rather than removed as
obsolete.

Issues: #258 files the dev-panel host as a decision rather than an accident,
and #255 is REOPENED. Its TaskCreationOptions.LongRunning fix asks the
scheduler for a thread but does not promise two callbacks overlap; under nine
concurrent test assemblies it still failed 2 of 5 whole-suite runs. The
earlier evidence tested a narrower pool, not a contended one. The fix it
needs is a rendezvous inside the read stub -- not a weakened assertion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-29 03:20:04 +02:00
parent 5852bdb877
commit c265b52d4b
5 changed files with 143 additions and 62 deletions

View file

@ -97,9 +97,49 @@ Copy this block when adding a new issue:
---
## #258 — Developer panels have no host after V11 deleted ImGui
**Status:** OPEN
**Severity:** MEDIUM (developer capability regression; no player-facing effect)
**Filed:** 2026-07-29
**Component:** developer tooling / retained UI
**Description:** Campaign V slice V11 deleted `src/AcDream.UI.ImGui/` and the
UI Studio tree, because ImGui was a GL-only frontend and porting it to Vulkan
was never in the campaign's scope. The consequence, recorded here so it is a
decision rather than an accident: **`ACDREAM_DEVTOOLS=1` no longer produces any
developer UI.** The variable survives — it still selects Vulkan's debug-utils
instance extensions, and the client logs one line saying so — but the panel
overlay, the menu bar, the debug panel and the UI Studio previewer are gone.
What was lost: the `IPanel`/`IPanelRenderer` overlay and every panel written
against it, the `ui-studio` CLI verb (layout preview, `--layout`, `--dump`,
`--mockup`, `--screenshot`), and the ImGui-hosted Settings/Diagnostics
surfaces. `AcDream.UI.Abstractions` itself **survives intact** — the panel
contract, ViewModels and commands were always backend-agnostic, which is the
whole reason Code Structure Rule 3 exists. Only the ImGui *backend* went.
**What this issue is for:** deciding what replaces it. The retained
`UiHost`/`UiRoot` tree is already a working, Vulkan-capable retained-UI engine
with its own layout, input routing and rendering — so the cheapest credible
answer is to host the developer panels as retained-UI windows rather than
reintroduce an immediate-mode dependency. That keeps one UI stack instead of
two, which is a simplification the campaign paid for.
**Not urgent, and deliberately unscheduled.** Nothing in M4's remaining work
needs a dev overlay, and the diagnostic env-var family
(`ACDREAM_PROBE_*`, `ACDREAM_DUMP_*`) still works without one. Sequence this
when a debugging task actually wants a panel, not before.
**Files:** `src/AcDream.UI.Abstractions/**` (the surviving contract),
`src/AcDream.App/UI/**` (the retained engine that would host it). The deleted
tree is recoverable from git history at `844cf092^`.
---
## #255 — Two RetailDatLoader concurrency tests measured the thread pool, not the loader
**Status:** DONE — 2026-07-28; the pair now runs on dedicated threads
**Status:** REOPENED 2026-07-29 — the `LongRunning` fix is a hint, not a guarantee
**Severity:** LOW (test infrastructure only; no production defect)
**Filed:** 2026-07-28
**Component:** tests / xUnit parallelism, content loaders
@ -134,6 +174,32 @@ afterwards.
**Files:** `tests/AcDream.Content.Tests/Vfx/RetailDatLoaderTests.cs`.
### Reopened 2026-07-29 by the V11 gate
`AnimationCache_CoalescesSameDidAndAllowsUnrelatedReadsInParallel` failed again
on Windows, at `RetailDatLoaderTests.cs:311` (`Assert.True(portal.MaxConcurrentReads >= 2)`),
in **2 of 5 complete-solution Release runs** on an otherwise green V11 tree —
and passed 124/124 in isolation and in the other 3 whole-suite runs. V11 does
not touch the subject: its only change under `src/AcDream.Content/` is
`UploadFormats.cs`, which is pixel-format enum documentation.
**Why the fix did not hold.** `TaskCreationOptions.LongRunning` *asks* the
scheduler for a dedicated thread; it does not promise the two callbacks overlap
in time. With nine test assemblies running concurrently, the first 40 ms
`Thread.Sleep` read can finish before the second callback is scheduled at all,
so `MaxConcurrentReads` never reaches 2 — the same failure mode #255 originally
described, merely made rarer. The evidence in the section above (10/10 under a
two-CPU pin) tested a *narrower* pool, not a *contended* one, which is why it
looked closed.
**What a real fix needs:** the two callbacks must be synchronised against each
other rather than against the scheduler — e.g. a `Barrier` or two-party
`SemaphoreSlim` rendezvous *inside* the read stub, so each read cannot complete
until both have entered. That makes the assertion measure the loader's
coalescing, which is what it is for, and makes it independent of how many
threads the host happens to offer. **Do not weaken the assertion or add a
retry** — the assertion is correct; the harness around it is what is wrong.
---
## #254 — Logout confirmation wait overran its timeout on a starved thread pool