acdream/docs/research/2026-08-10-settings-track-handoff.md
Erik ed0dbff90a docs: handoff — Fable fixes directly after two review failures (user-directed)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 22:01:16 +02:00

12 KiB

Settings track handoff — retail Options panel campaign (fresh session)

Written 2026-08-10 at the close of Campaign CH (chat parity, CLOSED USER-ACCEPTED the same day). The user pivoted the alpha program's settings track: the target is retail's four-tab Options panel, not merely a status-bar button over the existing F11 panel. The user supplied four retail screenshots (transcribed below — the fresh session cannot see them). Deep research REQUIRED before implementation, campaign-style.

What the user showed (retail screenshots, transcribed)

The options button opens a tall panel with four tabs: Gameplay Options | Character | Chat | Config, with Apply / Reset / Defaults buttons at the bottom of (at least) the Character tab. Options render as LED-style dots (lit green = on) beside labels, grouped under gold section headers, with a scrollbar.

Tab 1 — "Gameplay Options" (button list, no LEDs)

  • Exit to Character Selection
  • Exit Game
  • Configure Keyboard
  • Use Mouse Turning Settings
  • In-Game Help Files
  • Urgent Assistance
  • Report Abuse

Tab 2 — "Character" (scrolling LED option list; three screenshots)

User Interface Behavior: Keep Combat Targets in View · Salvage Multiple Materials at Once · Use Main Pack as Default for Picking Up Items. User Interface Display: Vivid Targeting Indicator · Display 3D Tooltips · Show Coordinates By the Radar · Side By Side Vitals · Display Spell Durations · Disable Most Weather Effects · Disable Distance Fog · Always Daylight Outdoors · Disable House Restriction Effects · Use Crafting Chance of Success Dialog · Confirm Use of Rare Gems · Display Timestamps · Filter Language · Show Your Helm or Head Gear · Show Your Cloak. Grouping: Ignore Allegiance Requests · Ignore Fellowship Requests · Show Allegiance Logons · Share Fellowship Experience and Luminance · Share Fellowship Loot · Automatically Accept Fellowship Requests. Other Players: Accept Corpse Looting Permissions · Attempt to Deceive Other Players · Let Other Players Give You Items · Ignore All Trade Requests · Drag Item to Player Opens Trade · Allow Others to See Your Date of Birth · ...Your Age · ...Your Chess Rank · ...Your Fishing Skill · ...Your Number of Deaths · ...Your Number of Titles. Character Behavior: Run as Default Movement · Advanced Combat Interface · Auto Target · Automatically Repeat Attacks · Use Charge Attack · Lead Missile Targets · Use Fast Missiles. Chat: Stay in Chat Mode After Sending a Message · Listen to Allegiance Chat · Listen to General Chat · Listen to Trade Chat · Listen to LFG Chat · Listen to Roleplay Chat · Listen to Society Chat · Listen to PK death messages.

Tabs 3+4 — "Chat" and "Config"

Not screenshotted. Research must derive their contents (Chat tab is plausibly the per-window text-type filter blocks + opacity the CH research already located in gmChatOptionsUI; Config is unknown — plausibly video/audio/mouse).

What already exists (do NOT re-derive)

  • The chat digest (claude-memory/project_chat_digest.md) — START THERE. Campaign CH built most of the plumbing this campaign needs.
  • Wire, already working: SetSingleCharacterOption (0x0005) codec + the six Hear-chat toggles (CH3); RuntimeCharacterOptionsState (Options1/Options2 words, SetOptionBit, seeded from every PlayerDescription); the membership-gate consumption of those bits. ACE's CharacterOption.cs maps option id → bit; CharacterOptions1.Default = 0x50C4A54A (verified; the register once carried a phantom mismatch — see docs/research/2026-08-09-chat-side-channels-vs-ace.md corrections).
  • Wire, known-missing: the full-blob SetCharacterOptions (0x01A1) builder was DELETED at CH3 (the old one was malformed: CharacterOptionDataFlag.CharacterOptions2 = 0x40 collides with CharacterOptions1.AllowGive; ACE's real layout is in GameActionSetCharacterOptions.cs). Retail's Apply button presumably sends the blob — the REAL builder must be ported. The per-window GameplayOptions blob (0x1000008C, elements 0x1000008B) is stored by ACE as an opaque byte[] it never parses — acdream owns that format (research: 2026-08-09-chat-retail-window-shell.md §4).
  • Decomp beachheads: gmChatOptionsUI::InitOptions @0x0049FC60 (the five per-window filter blocks, SetUserData ids 8/2/3/4/5, defaults); opacity options 0x10000080/0x10000081 (ChatInterface::SetOpacity @0x004F3120 family — implemented in CH6c); PlayerModule option accessors (InqChatWindowOption 0x1000007F, SetHearGeneralChat @0x005D35C0 writes options2 locally THEN notifies — the local-write pattern CH3/CH4 ported). The options panel class family (gmOptionsUI? gmGameplayOptionsUI? the tab host) is UNEXPLORED.
  • UI machinery, fully proven by CH6: LayoutDesc import (incl. Resizebar grips, buttons, scrollbars, outline properties 0x21/0x22), RetailWindowManager/UiRoot, fixture generation (RetailLayoutFixtureGenerator — add layouts, commit fixtures, pin conformance), the retained-controller pattern (ChatWindowController/FloatingChatWindowController are the templates), the settings persistence seams (RuntimeSettingsController/RuntimeSettingsTargets, J4.4 generation-gated command path).
  • The F11 panel (SettingsPanel, UI.Abstractions) — the NON-retail developer/client surface: audio sliders, quality presets, keybind rebinding (modal capture), chat opacity sliders (CH6c), Hear-chat toggles (CH3). The user's original ask ("client settings, different from retail") coexists with the retail panel — how they split (retail panel = retail options; Config tab or F11 = acdream client settings?) is a DESIGN DECISION for the plan, made by Claude, reactable at the gate.
  • Keybinds: KeyBindings.RetailDefaults() (the ONLY production table — AcdreamCurrentDefaults() is dead; #358's lesson), InputDispatcher modal capture, the F11 rebind UX. Retail's "Configure Keyboard" screen is unexplored decomp territory.
  • Status bar: the retail toolbar exists (RetailUiRuntime mounts it); the options BUTTON on it (which authored element, what it opens) is unexplored.

Research questions for the campaign's Opus lanes

  1. Panel structure: which LayoutDesc(s) author the Options panel (tab host + four tab pages)? The class family in the decomp (grep gmOptionsUI / gmGameplayOptionsUI / gmCharacterOptionsUI / gmConfigOptionsUI / the tab control); how Apply/Reset/Defaults work (what each sends/restores, per tab or global); how the panel opens (the status-bar button element + any keybind).

  2. The Character tab's complete option map: every row transcribed above → its storage (CharacterOptions1 bit / CharacterOptions2 bit / PlayerModule property id) → its wire (0x0005 single vs 0x01A1 blob) → ACE's handling (which bits ACE honors server-side vs stores-only) → acdream's current state (exists/ignored/missing). acclient.h + PlayerModule/CharacterOptionsMapper decomp + ACE enums.

  3. The Chat tab and Config tab contents (no screenshots): derive from the decomp/LayoutDescs what retail shows there.

  4. The real 0x01A1 blob: exact layout from ACE's reader + retail's builder; when retail sends blob vs single-option.

  5. Configure Keyboard: retail's keymap UI + storage (the keymap file/wire?) — and the design call on reusing acdream's existing rebind UX vs porting retail's screen.

  6. Gameplay Options tab actions: Exit to Character Selection (ties into the FUTURE pre-world flow — probably lands as Exit Game initially with a register row), Urgent Assistance / Report Abuse (server messages?), In-Game Help Files, Use Mouse Turning Settings.

  7. Which options have live acdream consumers today (timestamps → chat; hear-chat → CH3 gate; run-as-default → movement; weather/fog/ daylight → sky pipeline; helm/cloak → appearance) vs options whose subsystems don't exist yet (chess rank...) — the implement-vs-store split per row.

  8. Headless bot settings (user-directed 2026-08-10): character options must be settable by bots too. DESIGN CONSTRAINT for the plan: the option map (option -> CharacterOptions1/2 bit or PlayerModule property -> wire) is RUNTIME-owned, exposed as a typed set-option command on the shared IGameRuntimeCommands surface; the graphical Options panel and the headless host are BOTH consumers of that one seam (CH3's hear-chat toggles are the proven precedent). The headless session config (K1 strict versioned JSON) gains an optional characterOptions block of declared desired values; at login, after the PlayerDescription seeds actual state, the host DIFFS declared vs actual and sends only changes through the shared command path (0x0005 per change or one 0x01A1 blob) — idempotent on reconnect. Presentation-only settings (opacity/audio/quality) stay graphical-only; the strict schema keeps them out of bot config by construction. Research: verify which options a bot can meaningfully hold and whether ACE rejects any option change from a logged-in session.

Process (binding, from Campaign CH's five gate rounds)

  • Model split: Opus research lanes → Fable (main loop) plans → Sonnet implements → dual-lens Opus review per slice, fixes applied; REJECT verdicts get focused re-reviews.
  • Max 3-4 agents in parallel INCLUDING children; every agent prompt carries an explicit no-subagent clause; ONE implementer at a time on shared files; agents never launch the graphical client; the user runs connected gates.
  • Ledger discipline: never blanket-replace "(this commit)" placeholders (anchor every replacement); post-amend SHAs recorded by the coordinator, not chased in the same commit.
  • User gates are AXIOMS; screenshots must be transcribed into docs immediately (they don't survive sessions); honesty markers NEVER appear in user-visible text; decomp claims byte-verified (BN pooled strings, sbb idioms, and ~33-char previews are known artifact classes — sweep push-imm32 literals from the PDB-paired binary at C:\Users\erikn\Downloads\acclient.exe, check_exe_pdb.py MATCH first).
  • SERIAL TREE OWNERSHIP: only ONE agent that builds/tests may run at a time (all agents share the one worktree; concurrent dotnet build/test collide on bin locks). Read-only research/review agents may overlap a builder EXCEPT at their end-of-run targeted test step — in practice, run reviews and implementers serially; overlap only pure-read research.
  • ESCALATION ON REPEATED REVIEW FAILURE (user-directed 2026-08-10): if a slice fails review TWICE (two REJECT rounds, or a rework that fails its re-review), the main loop (Fable) takes over and fixes it directly — no third Sonnet dispatch. Two failures mean the contract or the mechanism is being misunderstood at the implementer tier; the fix needs the coordinator'''s full context.
  • STALLED/YIELDED AGENTS: a watchdog-killed or early-yielding agent is resumed with SendMessage to its id — the transcript survives and it continues where it stopped (used twice in Campaign CH). Never redo its work from scratch before trying a resume.
  • PERSIST WHAT TWO CONSUMERS NEED: review findings that feed both a fixer AND a re-reviewer go into a docs/research findings doc (committed) before dispatching either — notification text does not survive session restarts or compaction. Same for any diagnosis a later agent works from.
  • VERIFY AGENT CLAIMS AT THE SEAMS: spot-check each agent'''s load-bearing claims against source before building on them (git log for SHAs, the cited file:line for mechanisms) — reported SHAs are stale-by-one after amends, and two review rounds this campaign found implementer summaries that overclaimed what shipped.
  • dotnet build + FULL Release suite green per commit (baseline at handoff: 12,610/4/0 at bcc34ee3; plus the in-flight polish commit below). Register rows same-commit. CLAUDE.md campaign paragraph updated at close (see feedback_claude_md_staleness).

In-flight at handoff

A post-gate polish agent (round-5 review S1-S3: per-block outline pass, non-UiText outline plumbing, citation fix) was running when this handoff was written — check git log for fix(ui): round-5 review polish and collect/verify its landing first if absent.

Carried tail (do not lose)

#360/#361 (command families), #366 (unseen-text indicator), #368 (headless thread affinity — separate session exists), #369 (floaty send channel), AP-177 (SpewBox line lifetime), AP-190 (opacity ease), AP-191 (transcript tag colors).