docs: UI architecture review report + follow-up issues #159-#165
Full 6-dimension review (34 confirmed findings, 0 refuted) in docs/research/2026-07-02-ui-architecture-review.md. Verdict: widget toolkit / importer / controller-binding / cursor seams are sound; rot concentrates in GameWindow composition growth, state-write ownership, input-stack arbitration, and design-doc drift. New issues: #159 retail-chat ChatVM providers, #160 window-close notification + NoLongerViewingContents, #161 target-mode click chokepoint, #162 world-hover cursor, #163 raise ledger, #164 RetailWindowFrame migration, #165 UI doc reconciliation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
b7dc91a053
commit
59ea3252cd
2 changed files with 345 additions and 0 deletions
133
docs/ISSUES.md
133
docs/ISSUES.md
|
|
@ -46,6 +46,139 @@ Copy this block when adding a new issue:
|
|||
|
||||
---
|
||||
|
||||
## #159 — Retail chat ChatVM lacks Fps/Position providers — /framerate and /loc degrade
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** MEDIUM
|
||||
**Filed:** 2026-07-02
|
||||
**Component:** ui
|
||||
|
||||
**Description:** Two live `ChatVM` instances exist over the same `ChatLog`: the ImGui panel's (gets `FpsProvider` + `PositionProvider`) and the retail chat window's (`new ChatVM(Chat, displayLimit: 200)` — gets neither, and the providers are init-only). Typing `/framerate` or `/loc` in the retail chat window returns "(provider unavailable)".
|
||||
|
||||
**Root cause / status:** Found by the 2026-07-02 UI architecture review (theme T8). Fix direction: construct ONE `ChatVM` (with providers) before either UI block and share the instance.
|
||||
|
||||
**Files:** `src/AcDream.App/Rendering/GameWindow.cs:1438` (ImGui VM), `:1937` (retail VM), `src/AcDream.UI.Abstractions/Panels/Chat/ChatVM.cs:63/70`.
|
||||
|
||||
**Research:** `docs/research/2026-07-02-ui-architecture-review.md`.
|
||||
|
||||
**Acceptance:** `/framerate` and `/loc` produce real values in the retail chat window; one ChatVM instance per ChatLog.
|
||||
|
||||
---
|
||||
|
||||
## #160 — Inventory window close never notifies the controller (NoLongerViewingContents skipped)
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** MEDIUM
|
||||
**Filed:** 2026-07-02
|
||||
**Component:** ui / net
|
||||
|
||||
**Description:** `UiRoot`'s window registry flips `Visible` with no event, and the inventory close button routes to `GameWindow.CloseRetailWindow` (HideWindow + toolbar sync only). `InventoryController` never learns the window closed: `NoLongerViewingContents (0x0195)` is not sent for the viewed side pack, `_openContainer` stays stale, and reopening shows the old bag grid without re-sending Use.
|
||||
|
||||
**Root cause / status:** Review finding (theme T2). Fix direction: add `WindowShown`/`WindowHidden` events to the UiRoot window registry; InventoryController closes out the viewed container on hide; toolbar-button sync subscribes instead of the manual `SyncToolbarWindowButtons()` push at every mutation site.
|
||||
|
||||
**Files:** `src/AcDream.App/UI/UiRoot.cs:541-572`, `src/AcDream.App/UI/Layout/InventoryController.cs:404`, `src/AcDream.App/Rendering/GameWindow.cs` (`CloseRetailWindow`/`SyncToolbarWindowButtons`).
|
||||
|
||||
**Research:** `docs/research/2026-07-02-ui-architecture-review.md`.
|
||||
|
||||
**Acceptance:** closing the inventory window sends NoLongerViewingContents for the open side pack; reopening shows the main pack; no manual Sync call sites remain.
|
||||
|
||||
---
|
||||
|
||||
## #161 — Target-mode clicks: inventory grid cells bypass ItemInteractionController while the cursor says TargetValid
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** MEDIUM
|
||||
**Filed:** 2026-07-02
|
||||
**Component:** ui
|
||||
|
||||
**Description:** Target-mode interception is per-call-site opt-in. Toolbar, paperdoll, and the main-pack cell consult `ItemInteractionController` first; `InventoryController.AddCell` grid cells wire `Clicked = () => SelectItem(guid)` (and bags to `OpenContainer`) with no target-mode check — while `CursorFeedbackController.ResolveUseTargetGuid` returns `slot.ItemId` for ANY occupied slot, so the cursor shows the valid-target bullseye over cells whose click just selects.
|
||||
|
||||
**Root cause / status:** Review finding (theme T3). Fix direction: one chokepoint — `UiItemSlot` (or UiRoot) offers the click to `ItemInteractionController.AcquireTarget` first while target mode is active, before the per-window `Clicked` callback.
|
||||
|
||||
**Files:** `src/AcDream.App/UI/Layout/InventoryController.cs:307-308`, `src/AcDream.App/UI/UiItemSlot.cs:187-189`, `src/AcDream.App/UI/CursorFeedbackController.cs:240-254`.
|
||||
|
||||
**Research:** `docs/research/2026-07-02-ui-architecture-review.md`.
|
||||
|
||||
**Acceptance:** with a health kit armed, clicking any inventory item applies the kit to that item (or rejects per useability), matching what the cursor promised.
|
||||
|
||||
---
|
||||
|
||||
## #162 — Target-mode cursor is blind to world hover (always pending crosshair over world entities)
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** MEDIUM
|
||||
**Filed:** 2026-07-02
|
||||
**Component:** ui
|
||||
|
||||
**Description:** `CursorFeedbackController.Update(UiRoot)` builds `HoverTargetGuid` exclusively from the UI tree; hovering a world entity (e.g. a drudge with a health kit armed) shows the pending crosshair instead of valid/invalid. Retail keys the 0x28/0x29 cursors off the SmartBox target under the cursor — a world object (`ClientUISystem::UpdateCursorState` 0x00564630).
|
||||
|
||||
**Root cause / status:** Review finding (theme T7). Fix direction: inject a world-hover-guid provider (`Func<uint>`, from the existing world-pick machinery) into `CursorFeedbackController` and merge it into the snapshot when the UI pick misses.
|
||||
|
||||
**Files:** `src/AcDream.App/UI/CursorFeedbackController.cs:53-72`, `src/AcDream.App/Rendering/GameWindow.cs` (`UpdateRetailCursorFeedback`; world pick at the B.4b select path).
|
||||
|
||||
**Research:** `docs/research/2026-07-02-ui-architecture-review.md`.
|
||||
|
||||
**Acceptance:** hovering a valid world target in target mode shows the yellow bullseye (0x28); invalid shows the red blocked cursor (0x29).
|
||||
|
||||
---
|
||||
|
||||
## #163 — Character raise flow: adopt the pending/confirm/rollback ledger
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** MEDIUM
|
||||
**Filed:** 2026-07-02
|
||||
**Component:** ui / core
|
||||
|
||||
**Description:** Item moves reconcile optimistic state through `RecordPending`/`ConfirmMove`/`RollbackMove` (0x0022/0x0023/0x00A0); character raises apply optimistically (`CharacterSheetProvider.HandleRaiseRequest` → `ApplyLocalRaise`) with no pending snapshot and no rollback. A server-rejected raise leaves ranks/XP wrong until the next full property refresh. Register row AP-73.
|
||||
|
||||
**Root cause / status:** Review finding (theme T2); the spends now at least go through eventful store APIs (extraction commit). Fix direction: pending snapshot + confirm on the server's stat-update echo + rollback on failure, mirroring the item-move ledger.
|
||||
|
||||
**Files:** `src/AcDream.App/UI/Layout/CharacterSheetProvider.cs` (`HandleRaiseRequest`), `src/AcDream.Core/Player/LocalPlayerState.cs` (`Apply*Raise`).
|
||||
|
||||
**Research:** `docs/research/2026-07-02-ui-architecture-review.md`.
|
||||
|
||||
**Acceptance:** a raise the server rejects (e.g. insufficient XP race) visibly reverts within one echo round-trip; a confirmed raise never flickers.
|
||||
|
||||
---
|
||||
|
||||
## #164 — Migrate remaining retail-window mounts (vitals/chat/toolbar/inventory + MockupDesktop) to RetailWindowFrame
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** LOW
|
||||
**Filed:** 2026-07-02
|
||||
**Component:** ui
|
||||
|
||||
**Description:** `RetailWindowFrame.Mount` (extraction commit) is the shared nine-slice mount recipe; the character window uses it. Vitals, chat, toolbar, and inventory still inline the same block in `GameWindow.OnLoad`, and `Studio/MockupDesktop` hand-copies the recipes (already drifting). Each is a mechanical migration; do them one window at a time with visual confirmation (chat has Opacity + shrinkable MinWidth quirks).
|
||||
|
||||
**Root cause / status:** Review finding (theme T1).
|
||||
|
||||
**Files:** `src/AcDream.App/Rendering/GameWindow.cs` (~1973 chat, ~2120 toolbar, ~2290 inventory), `src/AcDream.App/Studio/MockupDesktop.cs:184`, `src/AcDream.App/UI/Layout/RetailWindowFrame.cs`.
|
||||
|
||||
**Research:** `docs/research/2026-07-02-ui-architecture-review.md`.
|
||||
|
||||
**Acceptance:** zero inline `new UiNineSlicePanel` window mounts left in GameWindow/MockupDesktop; all windows pixel-identical before/after (user visual check).
|
||||
|
||||
---
|
||||
|
||||
## #165 — Reconcile the UI design docs with the shipped D.2b shape
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** MEDIUM
|
||||
**Filed:** 2026-07-02
|
||||
**Component:** docs
|
||||
|
||||
**Description:** `docs/plans/2026-04-24-ui-framework.md` still says D.2b "remains design-only" and promises an `AcDream.UI.Retail` `IPanelRenderer` backend; `docs/architecture/acdream-architecture.md` still shows the swappable-backend diagram. Reality (acknowledged only in the 2026-06-14 panel-frame spec §0): the retail UI is the UiRoot tree in `src/AcDream.App/UI/`, the ViewModels are the shared seam, IPanel/IPanelRenderer is the devtools contract. The plugin UI story also fractured: `IUiRegistry.AddMarkupPanel` only renders under `ACDREAM_RETAIL_UI=1`, IPanel only under devtools — decide + document the plugin contract.
|
||||
|
||||
**Root cause / status:** Review findings (theme T8). One doc commit; CLAUDE.md requires the architecture doc never stay out of sync.
|
||||
|
||||
**Files:** `docs/plans/2026-04-24-ui-framework.md:7-8/244`, `docs/architecture/acdream-architecture.md:80-99`, `src/AcDream.Plugin.Abstractions/IUiRegistry.cs`.
|
||||
|
||||
**Research:** `docs/research/2026-07-02-ui-architecture-review.md`.
|
||||
|
||||
**Acceptance:** both docs describe the two-stack reality; the plugin markup-vs-IPanel decision is written down.
|
||||
|
||||
---
|
||||
|
||||
## #158 — Character window — deferred polish
|
||||
|
||||
**Status:** OPEN
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue