docs(perf): audit errata + plan governance/contract amendments (2026-07-24 review)

Adversarial review of the 2026-07-24 runtime audit + modern runtime plan
(43-agent verification at e627d9a4). Audit: append errata section 13 --
the capture ran with ACDREAM_UNCAPPED_RENDER=1 + ACDREAM_DUMP_MOVE_TRUTH=1
(not "normal capped presentation"; the 32 FPS ceiling was the RDP display
path); the 203.6 MiB single-frame figure is frame-thread-only and cannot
include worker-side MeshExtractor decode (it is main-thread publication/
retirement); GiB conversions, committed-peak, 65% LOH fragmentation,
exception-count provenance, GC-counter semantics, and cache-undersizing
corrections. Original sections left untouched per historical-record rules.

Plan: new section 0 governance interlocks (Slices F/G resume the deferred
2026-07-05 MP3/ECS decision -> explicit user gate; side-track session
discipline; freeze-exception scope for H-network/J; evidence-base
corrections; baseline prerequisite blocking Slice C). Slice amendments:
A (per-frame history, process-wide alloc, contention stacks, cache
counters, screenshot-diff pulled forward, reference config, exit criteria),
C (Portal-dat-wins precedence contract, dual-dat + ObjDesc fixtures, cache
identity rule, exception-semantics cleanup), D (unify/retune existing
eviction rather than rebuild; ResidencyManager concurrency contract),
E (gate rescoped to what E owns; release-later != run-later; audio in the
immediate detach set; reveal stall behavior with the AP-115 cue; retail
teardown anchors), F (referee-first digest, journal coalescing bound,
IRenderScene home project, identity enforcement), G (provisional 300 FPS
target; retail dynamics viewcone-cull contract), H (split H-a/H-b/H-c with
the AP-85 lights pin and receive-side allocation scope), I (verbatim-float
bake rule + differential BSP sweep; floats after B), J (teardown protocol,
multi-plan track), K (wire-timing parity per TS-33, hours-scale soak).
Section 11 gate corrections (percentile populations, anti-gaming
process-wide row, provisional budgets, scoped third-visit rule, soak +
jitter rows, scheduled harness); section 12 adjudication protocol;
section 14 order list now includes Slice I and the user decision gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-24 11:38:20 +02:00
parent e627d9a403
commit 38e14c6a71
2 changed files with 453 additions and 15 deletions

View file

@ -15,6 +15,11 @@ behavior were changed during the benchmark.
**Architecture response:**
[`../plans/2026-07-24-modern-runtime-architecture.md`](../plans/2026-07-24-modern-runtime-architecture.md)
**Errata:** section 13 records the corrections from the 2026-07-24
adversarial review (test-condition disclosure, single-frame allocation
attribution, unit conversions, LOH fragmentation, exception-count
provenance). Read it before citing this report's §1/§2/§4 numbers.
---
## 1. Executive result
@ -599,3 +604,93 @@ tools to inspect, and can expose local/session metadata.
This report plus the compact JSON and checkpoint CSV preserve the benchmark's
method, provenance, measurements, interpretation, and decision-driving evidence
in a form another engineer or model can review directly.
---
## 13. Errata — 2026-07-24 adversarial review
An independent adversarial review (43-agent verification against commit
`e627d9a4`, same date) confirmed every cited code mechanism in this report
(12/12 file:line citations accurate) but found the following statements wrong
or under-qualified. Per the project's historical-record rules the original
sections above are left untouched; this appendix is the correction record.
1. **Test conditions (§2) — "Normal capped presentation" is wrong.** The
reproduction script this report cites (`tools/run-connected-r6-soak.ps1`)
unconditionally set `ACDREAM_UNCAPPED_RENDER=1`, which disables BOTH VSync
and the software pacer (`FramePacingPolicy.Resolve`). The ~32 FPS ceiling
came solely from the RDP display path, not client pacing.
`ACDREAM_DUMP_MOVE_TRUTH=1` (per-movement console logging) was also active
for the whole capture and undisclosed. Unresolved provenance question: the
CPU trace shows `FramePacingController.CompleteFrame` at 6.44% inclusive,
which should be a near-zero no-op under those flags — either the capture
used a different launcher than documented or the trace row is
misattributed. Post-review the soak script defaults to capped and takes an
explicit `-Uncapped` switch, and emits an `env-disclosure.json` per run.
2. **Single-frame allocation attribution (§1, §9 P0).** The 203.6 MiB
"maximum single-frame allocation" is measured with
`GC.GetAllocatedBytesForCurrentThread()` — frame-thread only.
`MeshExtractor` decode runs exclusively on 4 background `Task.Run` workers
(`ObjectMeshManager.ProcessQueue`), so it structurally cannot appear in
that figure. The single-frame spike belongs to the main-thread
publication/retirement sources (`StreamingController.DrainAndApply` /
`ApplyResult`, retirement, static publication). `MeshExtractor` remains
the top source of the PROCESS-WIDE impacts (allocation rate, Gen-2, GC
pauses — §8's sampled stacks are process-wide). Consequence: Slice E owns
the frame-spike symptom; Slices B/C own the process-wide rate.
3. **Unit conversions (§1).** 1,661.9 MiB = 1.62 GiB (not 1.66) and
2,269.1 MiB = 2.22 GiB (not 2.27); the printed values divided MiB by 1000.
4. **Committed managed memory (§5).** 830.6 MiB is the FINAL checkpoint, not
the peak: the checkpoint peak was 1,242.1 MiB (caul-return) and the
continuous counter maximum 1,360,900,096 B ≈ 1,298 MiB.
5. **LOH fragmentation (§5).** The companion JSON records LOH size max
807.5 MB with 524.1 MB fragmentation (~65%) — the largest quantified
contributor to the committed-vs-live gap. It never appears in the prose
above and should anchor the Slice D accounting work.
6. **Exception counts (§8).** This report's own figures are the
focused-trace 1,587 (1,335 `ArgumentOutOfRangeException` + 252
`SocketException`). The "4,520 + 1,168" figures quoted by the companion
plan document have no derivation here or in the committed artifacts and
must not be cited until re-derived from a fresh capture.
7. **GC counts (§4).** 99/105/38 are per-generation EXCLUSIVE counts from
the .NET 10 `System.Runtime` meter (`dotnet.gc.collections`), under which
gen1 > gen0 is legal; cumulative `GC.CollectionCount` equivalents are
242/143/38. The "38 Gen-2" headline is correct under either reading.
8. **Cache context (§8, §9 P1).** Four bounded LRU caches already front the
mesh/texture path (GPU render-data 1 GiB / 50 objects; CPU prepared-mesh
128 MiB / 100 entries; decoded-texture 64 MiB / 128 entries; DAT typed
object 64 MiB / 256 entries ×4 databases). Revisits rebuild because these
are UNDERSIZED relative to the route's working set (~599 tracked
textures), not because no caching mechanism exists. Likewise, texture
atlas arrays have real fence-gated, budgeted eviction (empty-atlas pool
64 MiB; composite arrays 128/64 MiB) — the route simply never pushed the
ceilings, so "bounded" in §7 was bounded-by-route, not policy-exercised.
9. **Portal-burst list (§4).** The five max-frame values are not attributed
to specific transitions or route order, so warm-vs-cold portal behavior
is not derivable from the committed data. Cache hit/miss/evict counters
were added to the checkpoint JSON post-review to settle this.
10. **Dead-code caveat (§9 P2).** The "fixed 65,536-instance particle
CPU/GPU buffer" belonged to an unreachable code path (`ParticleBatcher`;
never fed by production — the live particle renderer is
`ParticleRenderer` with growable buffers). It was deleted post-review;
its ~7 MiB combined residency was dead weight, and its GPU buffer was
one concrete instance of the §7 tracked-vs-OS gap (never registered with
the GPU tracker).
11. **Soak-script dwell bug (§11).** The script's own comment requires
sampling after the 25-second liveness deadline
(`LiveEntityLivenessController`), but it slept 12 s — return-gate samples
could include un-pruned prior-destination records. Fixed post-review
(26 s).
12. **Reproducibility scope (§12).** The §4 headline table's continuous
CPU/GPU-engine/memory percentiles were produced by manual sampling not
committed to the repo; per-scene steady-allocation figures, four of five
portal-burst values, "~20,000 registry records", "599 tracked textures /
4348 atlas arrays", and the 2330 ms gpu_ms figure likewise have no
surviving committed evidence. They can be reviewed but not independently
regenerated; treat them as reproducible-not-reviewed until the Slice A
tooling recaptures them.
The full review (verdicts, refutations, and the new findings the audit
missed) and the resulting plan amendments are recorded in
[`../plans/2026-07-24-modern-runtime-architecture.md`](../plans/2026-07-24-modern-runtime-architecture.md)
section 0.