Two of the four Opus research lanes for the retail Options panel campaign
(docs/research/2026-08-10-settings-track-handoff.md):
- Lane B: the complete Character-tab option map. 50 rows / 6 groups
decomp-authored from gmCharacterSettingsUI::InitOptions @0x004a02f0
(the screenshots' PK-death row is 2015-client-only; the 2013 enum caps
at 0x33). Wire routing is retail's byte-verified lookup table
CPlayerModule::IsAutoSaveOption @0x0059a600 — ~21 ids send 0x0005
immediately, the rest dirty the module for the batched 0x01A1. Retail's
Defaults-button table reconstructs Options1 = 0x50C4A54A exactly
(independent confirmation of ACE's constant) and Options2 = 0x00008700
vs ACE creation's 0x00948700 (a real client-vs-server distinction, not
a bug). Per-option ACE handling + acdream consumer inventory included.
- Lane C: the real 0x01A1 body is PlayerModule::Pack @0x005D45C0
(builder CM_Character::Event_CharacterOptionsEvent @0x006A10C0), flag
enum PlayerModulePackHeader verbatim at acclient.h:7835;
SetPackHeader @0x005D44A0 always sets 0x460 and never 0x02/0x04/0x10/
0x80, so ACE's extra reader branches are dead legacy. Flush triggers:
Apply, logout, 480 s autosave. ACE stores options words raw, discards
the rest, refuses only pre-LoginComplete; unknown option ids THROW.
CH3 post-mortem: the deleted 16-byte builder put a CharacterOptions1
word in the section-flag slot.
Both lanes independently converged on the same latent defect: the
headless DirectGameRuntimeCommandAdapter.SetSingleOption sends the wire
but skips the local Options.SetOptionBit write the graphical path does
(LiveSessionRuntimeFactory.cs:348) — the CH4 stale-membership-gate bug
class reproduced on the bot side. Flagged for the campaign plan, not
fixed here (research-only lanes).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>