Commit graph

7 commits

Author SHA1 Message Date
Erik
1d73ce524c test(app): measure the warmed path, not the path being warmed (#250)
The zero-allocation family failed about one full-suite run in three, on
unchanged trees, and had been dismissed as inherent noise in
`GC.GetAllocatedBytesForCurrentThread` three separate times. It is not noise.
Reading the four members side by side, they share one root: **the measured
window was never the warmed path.**

  UiDatFontTests            1 warm call, then a 10,000-iteration loop inline
  RenderFrameProductTests   8 warm calls, then a 1,000-iteration loop inline
  OracleTests               1 warm call, 1 measured call
  ArchRenderSceneTests      warms Apply(registrations), measures Apply(updates)

Two mechanisms come out of that table. A test method is JIT-compiled at tier 0
like anything else, and a long-running loop in tier-0 code gets 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
first two. 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 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. 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. Clean in isolation,
failing under load, on a tree that changed nothing.

`ZeroAllocationProbe` 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 is what
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, which is a real regression made
invisible. 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.
Without those, a later edit could quietly make the whole family unfailable.

Twelve further sites in this assembly still use the hand-rolled shape. None has
been observed failing, and each needs its own repeatability analysis — several
mutate state or consume monotonic sequences — so they are listed in the issue
for adoption when next touched rather than converted blind at scale.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 03:42:08 +02:00
Erik
20f9fadb12 Reapply "perf(rendering): draw retained frame product"
This reverts commit 2c848d4167.
2026-07-25 08:36:11 +02:00
Erik
2c848d4167 Revert "perf(rendering): draw retained frame product"
This reverts commit ef1d263337.
2026-07-25 06:28:31 +02:00
Erik
ef1d263337 perf(rendering): draw retained frame product
Make the incremental render scene the production entity source at the existing retail PView stages while retaining the accepted dispatcher upload and draw executor. Keep diagnostics consumer-gated, retain ordered indices across unchanged frames, refresh only dirty records, and preserve exact mesh-load, selection, alpha, lighting, and route lifecycle semantics.
2026-07-25 04:12:23 +02:00
Erik
91463db551 fix(rendering): reconcile shadow roots from live runtime
Recover ordinary live roots from LiveEntityRuntime's canonical active spatial workset instead of relying on already-retained derived records. Keep attached children callback-authoritative, cache immutable selection geometry fingerprints, and pin zero-allocation retained update paths with regression tests.

Release gate: 3,733 App tests / 3 skips; 8,217 complete-solution tests / 5 skips.

Co-Authored-By: OpenAI Codex <codex@openai.com>
2026-07-24 22:45:14 +02:00
Erik
ff5d86175f feat(rendering): index incremental scene queries
Maintain packed render worksets as lifecycle deltas arrive and synchronize active animated statics without scanning the resident world. This keeps Slice F non-drawing while preparing exact spatial and feature queries for shadow comparison.

Release: 8,206 passed, 5 skipped.
2026-07-24 22:12:26 +02:00
Erik
dbd8318417 feat(rendering): contain incremental render scene
Pin Arch behind acdream-owned identities, deltas, queries, generation gates, and memory diagnostics. The new five-archetype store is unbound and non-drawing so static publication can be shadowed without changing production behavior.

Co-authored-by: Erik Nilsson <erikn@users.noreply.github.com>
2026-07-24 21:42:42 +02:00