fix(runtime): same-value LocalEntityId re-assertion is a no-op; file #365 headless hydration regression

The Campaign CH jump-probe headless reproduction quarantined on its first
advance tick: AdvanceBeforeNetwork re-asserts the resolved local entity id
every tick, which the C3c configuration seal treats as a mutation on a
dormant controller. A same-value write is now a no-op; a DIFFERENT id
while sealed still throws. One layer deeper the probe exposed #365: the
headless world never hydrates (entities stay 0, the movement controller
never publishes), so headless bots cannot move at head — filed with the
full evidence chain. HeadlessDiagnosticWriter.Failure now emits the full
exception detail (type-only cost a whole diagnosis round-trip).

Runtime tests 1,322/0, Headless tests 89/0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-10 08:48:37 +02:00
parent c1f1582576
commit ab82347d42
3 changed files with 56 additions and 0 deletions

View file

@ -121,6 +121,51 @@ than a REJECT-review fix batch; CH5-or-later.
**Campaign:** `docs/plans/2026-08-09-chat-parity-campaign.md` (Campaign CH,
CH4 REJECT-review).
## #365 — Headless host cannot move at head: session quarantines on the first advance tick; world never hydrates
**Status:** OPEN — filed 2026-08-10 during the Campaign CH jump-probe
reproduction. Distinct from #330 (no collision) and #332 (no remote DR):
this is the LOCAL player.
**Symptom:** a headless session (`jump-probe` policy, real ACE connect,
`testaccount`/`+Acdream`) reaches `InWorld`, `live: in world — CreateObject
stream active` prints, but `entityCount` stays **0** for the whole run and
the local movement controller is never published. The first
`SetIntent(Jump: true)` → next `AdvanceBeforeNetwork` tick quarantined the
session.
**Evidence chain (2026-08-10):**
1. First quarantine: `RuntimeLocalPlayerFrameController.AdvanceBeforeNetwork:93`
unconditionally re-assigned `controller.LocalEntityId` — a sealed
configuration property — on a still-dormant controller. FIXED in the
probing session: a same-value re-assertion is now a no-op (a different
id while sealed still throws).
2. Second quarantine (one layer deeper): the frame controller takes the
`ObjectClockDisposition == Suspend` branch and calls
`SuspendObjectUpdate``EnsurePublishedForRuntimeOperation` throws —
`_host.CanAdvancePlayer` is true while the controller is unpublished.
3. Root condition: the session's world never hydrates (`entities: 0`
despite the active CreateObject stream), so dormant local activation
never completes and the controller never publishes. K3/K4 ran full
connected multi-session gates with movement — this regressed somewhere
in the many Runtime/placement/CH landings since 2026-07-27.
**Also observed in the same run:** `[weenie-error] unmapped code=0x051D`
an ACE-only id outside retail's 344-case `HandleFailureEvent` switch;
CH2's silent-toward-player + diagnostics-line fallback handled it as
designed (no action needed, noted for completeness).
**Repro:** `dotnet run --project src/AcDream.Headless -c Release -- run
--config <cfg>` with a `jump-probe` policy session against local ACE
(config shape: version 1, endpoint 127.0.0.1:9000, credential provider
Environment). `HeadlessDiagnosticWriter.Failure` now emits `errorDetail`
(full exception) — added during this diagnosis.
**Next step:** bisect the headless hydration path (why zero entities admit
headless when the graphical host hydrates fine) BEFORE touching
`CanAdvancePlayer` — the #357 closeout warns that dormant-activation
classification changes have a strict test matrix.
## #364 — Three `/help` group topics still partial: HelpStupidChannelHack unresolved
**Status:** OPEN — filed 2026-08-09, Campaign CH user-gate round 2, item 3.