fix(runtime/core): Slice 5.3 review corrections — retirement/transit close, per-unit pricing, guarded auto-close dispatch
Some checks are pending
Headless portability / portable-headless (ubuntu-latest) (push) Waiting to run
Headless portability / portable-headless (windows-latest) (push) Waiting to run
Headless portability / linux-graphical (push) Waiting to run
Headless portability / linux-vulkan (push) Waiting to run

The adversarial review's three blocking findings, each fixed at root:

1. A vendor session now CLOSES when its entity retires (despawn,
   death, ObjectDelete) and at teleport BEGIN
   (HasPendingTeleportStart || IsTeleportActive at the existing
   per-frame seam — both hosts funnel through
   RuntimeWorldTransitState.TryQueueTeleportStart, which flips the
   pending flag strictly before activation). The previous permissive
   early-return stranded the session forever: panel pinned to a stale
   guid, ActiveVendorId swallowing Use for the rest of the session.
2. VendorShopItem carries the desc's stack size, and
   VendorPricing.PerUnitValue ports retail's stack-total division
   (VendorProfile::VendorSellPrice 0x005D1B00: <= 0 guard, integer
   division) — a stack of 50 arrows now prices per arrow, not at 50x.
3. VendorState.Close() guards its observer fanout with the
   dispatcher's catch-and-log semantics — a throwing panel listener
   can no longer propagate into the unprotected per-frame path.

Register honesty rides along: the 0.6 m UseRadius fallback was
acdream's invention (ACE's CheckClose has no fallback; retail passes
the raw authored radius) — removed, the watcher now uses the raw
radius and AP-160's citations are corrected and extended with the
accepted-position-snapshot cadence; AD-72 files VendorPricing's
double-vs-x87-extended narrowing (AD-33's class, bounded by the
±0.1 margin).

Nine tests added. Clean-room complete solution: 11,311 passed /
4 skipped / 0 failed.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-07 16:15:57 +02:00
parent 9796d71522
commit 609a2dfda0
9 changed files with 369 additions and 23 deletions

View file

@ -157,8 +157,13 @@ public sealed class VendorApproachTests
public void TryParse_TruncatedMidItemPrefix_ReturnsNull()
{
// The item's packed stack-size dword is present but its guid is
// cut off entirely — truncation inside the per-item PREFIX (before
// PublicWeenieDescParser is even reached) must fail the whole parse.
// cut off entirely. This does NOT reach a guid read that fails --
// TryParse's own minimum-size guard (`(long)itemCount * 12 >
// payload.Length - pos`, the smallest possible per-item size:
// packed(4) + guid(4) + weenieFlags(4)) rejects the whole parse
// right after itemCount is read (remaining=4 bytes here, the packed
// dword only; 1 * 12 = 12 > 4), before the per-item loop that would
// read the packed dword/guid ever runs.
var w = new AceWireWriter();
WriteMinimalProfilePrefix(w, vendorGuid: 0x40000500u);
w.Write(1u); // item count = 1