Commit graph

2 commits

Author SHA1 Message Date
Erik
f7a6f46ba0 fix(chat): consolidated-review fixes — retail /help Detail extraction, seam wiring test
SHOULD-FIX 1: RetailClientCommandCatalog's ~45 catalog leaf verbs were
showing acdream-authored Summary text for /help <verb> instead of
retail's own Detail_HelpType(2) text. Byte-swept every Help* handler
against the PDB-paired acclient.exe (verified MATCH), confirmed each
Detail/Summary branch by reading the actual decompiled if/else shape
(address order and string length both proved unreliable alone), and
fixed a sweep_weenie_strings.py 800-char truncation bug that silently
dropped several longer Detail branches. Resolved every ambiguous
CmdHashData-registered verb (hor/hr/hom/hoa/alh/ah/friends_add/
friends_remove/squelch/unsquelch) by reading for Binary Ninja's
nullptr-4th-arg decompiler artifact instead of trusting it. Coverage:
42 of 47 distinct catalog Definitions verbatim-extracted, 4
confirmed-null (index/clist/on/off register with a genuinely null help
pointer — DoHelp falls to UnknownCommand for these, now reproduced),
1 honest UNVERIFIED (messagetypes builds its text from a runtime enum
table, not a static string). ChatCommandRouter now prefers retail
Detail text over the catalog summary; RetailCommandHelpTable's class
doc no longer overclaims its own scope.

SHOULD-FIX 2: extracted the a5a7eb4f-class OnInterfaceText wiring into
a testable CreateChatViewModel method and added
ComposedChatViewModelWiresOnInterfaceTextToSpewBox, which the prior
FakeFactory-based test suite could never exercise.

SHOULD-FIX 3: retires register row AP-113. DoLifestone/DoMarketplace
print their own 0x1A refusal text (byte-recovered, UTF-16LE) instead
of falling through to the generic 0x26 fallback; ChatCommandRouter's
comment corrected to state the fallback's real scope.

SHOULD-FIX 4: corrected the divergence register's stale AP section
header sentence about AP-190's opacity default (refuted by cc582899).

NITs: (a) HeadlessStaticStateAudit routes through the injected
HeadlessDiagnosticWriter instead of Console.WriteLine; (b) a bounded
300-pump liveness diagnostic on the IsQuiescent conductor gate (no
retry, no behavior change); (c) fixed the #365 hydration test's doc
comment contradiction against diagnosis §8; (d) the 0x26 fallback
dispatches on WeenieErrorMessages' own Type instead of hardcoding
ClientLocal.

Full Release suite: 12,553 passed / 4 skipped / 0 failed (baseline
03404b71: 12,542/4/0; net +11 tests, zero regressions).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 16:22:36 +02:00
Erik
41b408f3e6 fix(headless): #365 — collision-admission-open window drove the first-entry conductor into a permanent seal refusal
Root cause (measured live via ACDREAM_PROBE_PARK=1): HeadlessSessionWorldProjection
drove the first-entry conductor unconditionally, including while
HeadlessCollisionNeighborhood's own 3x3 publication plan held a genuinely open
RuntimeCollisionAdmission for the local player's landblock. Every
TrySealCollisionEvaluationAuthority attempt during that window failed
(IsCollisionEvaluationPrefixAdmissible false) and retried forever without
recovering — measured verdict: "seal-refused" repeating with no preceding
[rearm] verdict= line (the operation never even reached the AwaitingCell park).
This is the diagnosis doc's "structural half" mechanism; no evidence of the
"circular HasOldPrefixPlacementDebt" hypothesis was observed, so that shape
was not needed.

Step 1 (enabler): HeadlessStaticStateAudit.ValidateProcessIsolation now takes
sessionCount and only refuses process-global physics probes for
sessionCount > 1 — its own multi-root-attribution rationale never applied to
a single session, and it was blocking the exact probe built to diagnose this
class of stall.

Step 3a (root cause): new IHeadlessCollisionNeighborhood.IsQuiescent gates
ProjectSpawn/ProjectPosition/PumpFirstEntry's conductor-drive calls — the
conductor is never driven while the neighborhood's own publication owns
collision authority for that tick.

Step 4 (defense-in-depth): HeadlessLocalPlayerFrameHost.CanAdvancePlayer now
requires Controller.CanExecuteLiveMovement instead of just a non-null
controller — the headless-only gap that turned the (now-fixed) hydration
stall into a hard crash reaching SuspendObjectUpdate on a dormant controller.
RuntimeLocalPlayerFrameController's three shared entry points gained the same
guard, contract-preserving for the graphical host.

Verified end-to-end against live ACE (jump-probe policy, three runs):
hydration succeeds cleanly (136 entities load vs. 0 before), no seal-refused
spam, no crash from the original bug, graceful logout every time. Full
airborne-transition confirmation is blocked by a separate, newly-discovered,
pre-existing defect filed as #368 (the headless scheduler's
Task.Delay(...).ConfigureAwait(false) tick loop can resume on a different
ThreadPool thread mid collision-generation, tripping
EnsureCollisionMutationThread) — explicitly out of scope here, not mentioned
anywhere in the #365 diagnosis, and unsafe to fix without graphical-host
verification this session was constrained not to perform.

New tests: the real-admission hydration test (fails on the pre-Step-3a tree,
verified by temporarily reverting the three gates and confirming failure,
then restoring), the PumpFirstEntry quiescence-gate test, the
CanAdvancePlayer publication-lifecycle test, the dormant-controller
sabotage tests for RuntimeLocalPlayerFrameController, and the audit
single/multi-session tests. RuntimeLocalPlayerPhysicsPublicationStateTests
is untouched.

Full Release suite: 12,343 passed / 4 skipped / 0 failed (baseline ~12,330/4
plus 11 new tests).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 11:34:36 +02:00