# CH6a+CH6b review findings — `1fd51543` + `22020ef2` (REJECT; rework list) Dual-lens Opus review, 2026-08-10. The retail research held up under independent re-derivation (Type-2/Type-9 correction, filter masks, Alt+1..4, pure-mirror indicators all CONFIRMED); the rework list below is what did not. ## BLOCKER 1 — CH6a: chat window loses 7 of its 8 authored border pieces `UiResizeGrip : UiElement` (`UiResizeGrip.cs:33`) inherits the no-op `UiElement.OnDraw` and is constructed WITHOUT the `ElementInfo`/`resolve` pair (`DatWidgetFactory.cs:270-278`) — the seven Type-9 grips render NOTHING. Pre-CH6a, Type 9 fell through to `UiDatElement` (whose class doc names resize grips explicitly). Same commit also hides the eight `_Locked` media twins (`ChatWindowController.cs:239-245`) and switches to `Chrome = RetailWindowChrome.Imported` (`RetailWindowFrame.Mount:133-142` makes outerFrame = content, no wrapper chrome). Fixture proof: all 8 border elements carry real art (0x06006129/2A/2B/2C/2D family); the window root has NO background image. Net: only the 400×5 top strip (Type 2 → UiDatElement) draws — no left/right/bottom edges, no corners. **Fix:** `UiResizeGrip` derives from `UiDatElement` (or carries info+resolve and draws its active state's media), keeping `ClickThrough = false`; `BuildResizeGrip(info)` → `BuildResizeGrip(info, resolve)`. Conformance assertion: each of the seven grips resolves a non-zero sprite. ## SHOULD-FIX 2 — CH6b: wrong window-id model asserted as decomp fact `ChatWindowState.cs:31-42` claims `UpdateFromPlayerModule @0x004F3920` early-returns for the MAIN window and overloads id 0 as both "main" and "broadcast". Decomp refutes both: `PostInit @0x004F3DD0` switches on `m_eWindowID - 1` (case 0→0xFBFFFFFF, 1→0x101C, 2→0x40C00, 3→0x80000, 4→0x78000000, 7→0xFBFFFFFF); `gmChatOptionsUI::InitOptions @0x0049FC60` builds five per-window filter blocks with SetUserData window ids **8** (main, default 0xFBFFFFFF @0x0049FDC9), then **2/3/4/5** (@0x0049FF4E, :FF71, :FF93, @0x004A0000 default 0x78000000). Retail: main window is `m_eWindowID == 8`; floaties are 2–5; `m_eWindowID == 0` means UNAUTHORED (ctor default — what the UpdateFromPlayerModule guard is for); wire `arg5 == 0` is a pure broadcast sentinel, never a window id. Consequences: the MASKS are correct once re-indexed (confirmed); the main window's filter IS user-settable in retail (first block on the options page, with a dedicated high-dword Society child @0x0049FEFB — so `0x20` Society is opt-in on main; acdream's `accept: null` main view over-displays it today); `SetFilter(0,…)` hard no-op (`:119`) blocks the future options UI; the 0-overloading makes AP-180's `m_idCurrentCommandSource` routing inexpressible. `ShouldDisplay_MainWindow_ShowsEveryBroadcastRegardlessOfSeededFilter` (`:137-146`) pins the wrong behavior including 0x1A displaying in main. **Fix:** separate the broadcast sentinel from the main-window id — either carry retail's real ids (main 8, floaties 2–5) in `ChatWindowState`, or keep 0–4 internally plus an explicit `BroadcastTargetWindow` constant distinct from every id; drop the SetFilter main no-op; give the main window a real accept predicate (default 0xFBFFFFFF, i.e. everything except 0x1A and with the high dword zeroed so Society is opt-in) in `ChatWindowController.GetTranscriptLines`; correct the class doc; re-point the test. ## SHOULD-FIX 3 — CH6b: indicator buttons self-toggle on click `UiButton.cs:438-439`: `_pressed && _pointerOver && Enabled && ToggleBehavior → _selected = !_selected`; the fixture shows 0x10000522/0x10000523 carry DAT property `0x0B = true`, so a click flips Highlight↔Normal art with no visibility change — the mirror lies until the next real toggle. Retail: clicking does nothing (0x10000522–0x10000525 appear ONLY in `RecvNotice_SetPanelVisibility @0x004CCD80`). The existing test asserts `OnClick == null` (wrong level) on a synthetic fixture without 0x0B. **Fix:** a `SuppressSelfToggle` opt-out checked at `UiButton.cs:438`, set in `ChatWindowController.Bind` with the @0x004CDA80 citation; test presses/releases an indicator built WITH 0x0B=true, state unchanged. ## SHOULD-FIX 4 — CH6b: 0x2100005B never dumped (research doc's explicit instruction) No `chat_floaty_2100005b.json` fixture; `FloatingChatWindowControllerTests` is fully synthetic with Type-3 stand-ins. Three untested production assumptions: `FloatingChatWindowController.cs:122` (`FindElement(InputId) as UiField` — if 0x10000016 isn't Type-12 with Editable 0x16, all four windows mount non-interactive), `:199` (`TitleBarId is UiText` — if it imports as UiDatElement the "Chat N" title never renders), `:211` (`CloseButtonId is UiButton` — no test at all). The dump's `widget_kind` is media-presence-driven and cannot settle element types. **Fix:** add `0x2100005B` to `RetailLayoutFixtureGenerator.Layouts`, commit the fixture, conformance tests pinning the resolved widget types of 0x10000016, 0x10000019, 0x100004D9, 0x1000052A, and the border/corner element types (also determines whether floaties resize from real grips). ## SHOULD-FIX 5 — CH6b: missing register row for the shared-transcript model Retail: per-ChatInterface `m_chatLog`, truncated at 10,000 (`RecvNotice_DisplayFinalStringInfo @0x004F4711` → TruncateChatLog); a closed window keeps accumulating (`gmFloatyMainChatUI::SetVisible @0x004CE9B0` never unregisters the handler). acdream: one 500-entry ChatLog with a 200-line display tail each window filters — accumulate- while-closed and per-window scroll fall out correctly, but the EFFECTIVE per-window scrollback depth differs (a fellowship-only window retains up to 10,000 fellowship lines in retail; here only those inside the last 200 shared lines). **Fix:** file the register row (AP series) describing the depth divergence. ## NITs N1 — filter persistence saves only from `/saveautoui` (`SaveLayout()`), while geometry/visibility auto-save; harmless today, note for CH6e. N2 — `ChatWindows.ResetToDefaults()` called only in Dispose; not resetting across reconnect is likely correct but undocumented — add the one-line comment (deliberate, user preference survives reconnect). N3 — research doc §1.3 still says UNVERIFIED for the modifier decode (CH6b resolved it: MetaKeys 1=Shift, 2=Ctrl, 3=Alt→mask 0x4, 4=Win — also fix the §1.3 "0x00000002 = shift" mislabel). N4 — §1.4's "the ONLY function that branches on idMessage == 1" superlative is false (`gmFloatyChatUI::ListenToElementMessage @0x004CE330` does too); the substantive claim stands; fix the wording. N5 — `ChatTranscriptRenderer.BuildLines` calls back into `ChatWindowController.WrapText`; move WrapText into the renderer to close the circular dependency. ## CONFIRMED-OK (do not churn) CH6a layout geometry vs the independent 2026-06-25 dump; the Type-2/Type-9 correction; `DecodeBorderLocation` vs `StartMouseResizing @0x0046B7E0`; deleted compensations have no survivors and each removal is DAT-justified; cursor ids byte-exact; AP-185 accurate; the UiRoot grip/dragbar priority change is retail-correct. CH6b masks (via the options page, independent of PostInit); Alt+1..4 proven; pure-mirror indicators (the finding, not the implementation); closed-window accumulation reproduced; SpewBox 0x1A exclusion survives everywhere; ChatTranscriptRenderer behavior-identical for main; layering clean (Core presentation-free, single canonical instance, zero env reads, zero GameWindow changes); input pipeline conventions followed; visibility chokepoint genuine; AP-187/AP-188/#369 accurate.