Opus review of CT5 (f532f28c) found 0 blockers, 4 SHOULD-FIX, 6 NOTEs; all
applied here.
SHOULD-FIX 1 (visible retail gap): unselected attribute/skill rows now draw
the row template's Normal-state media (0x06004CC2 — pinned by
CharacterPanelLiveDatTests.AttributeRowTemplate_...) instead of drawing
nothing. Independently decoded against the installed DAT: PFID_A8R8G8B8,
48x48, uniform (0,0,0,175) — a ~69%-opaque black tile the native-size
copy-or-tile blit repeats across the row. Wired at all three sites
(HandleRowClick, ApplySkillSelectionVisuals, AddRow). Selected rows keep
0x06000F93 (RowHighlightSprite) unchanged.
SHOULD-FIX 2: added Bind_AttributeRow_/Bind_VitalRow_/Bind_SkillRow_
geometry tests asserting the authored template pixels against BUILT rows
(not DAT pins) — width, height, icon/name/value column positions. The
skill-row case reproduces the real production scrollbar (X=281, per
CharacterPanelLiveDatTests.StatListBox_AuthorsFiveRowTemplatesInSharedLayout)
to prove the documented 281px clamp (scrollbar.Left - list.Left), one pixel
short of the attribute/vital rows' 282px ceiling.
SHOULD-FIX 3: AddRow's name-column Padding corrected from 1f to 0f — the
authored template carries no margin on 0x1000012A; Padding=1f re-created
the X=26 glyph-start bug this slice existed to fix.
SHOULD-FIX 4: reworded both UiPanel.BackgroundSprite doc comments — the
draw is a native-size copy-or-tile blit (UV-repeat), never a stretch.
Decoded 0x06000F93 as exactly 282x20 (matches the row natively, draws as a
plain copy) vs 0x06004CC2's 48x48 tile. Retail's UIRegion::SetImageByDID
(@0x0069F960) decompiles to a pure BlitMode selector switch — param_2==2 ->
Blit_3Alpha, ==3 -> Blit_4Alpha, else Blit_Normal — with no width/height
touched anywhere in the function, answering CT1's open "draw mode 3"
question: it's an alpha-blend selector, not a resize flag.
NOTEs:
a. AddRow's nameEl now sets OneLine=true so the authored VJustify=Center
takes the same single-line vertical-centering path the value column
already uses.
b. Tempered the "row width is 282" wording in the SkillContentWidth /
RowContentWidth doc comments — that's a ceiling attribute/vital rows
land on, not a fact true for skill rows (281, via SkillViewportWidth's
scrollbar-gutter measurement).
c. Reworded the section-header (RowPadX) comment — CT1 verified only the
four header SPRITES; the caption label's own authored margins were
never checked. Recorded as an open residual, not a cleared divergence.
d. AttrRows/VitalRows are now internal (InternalsVisibleTo("AcDream.App.Tests")
already covers AcDream.App.Tests); CharacterPanelLiveDatTests iterates
them directly instead of a re-typed duplicate array, and now also
asserts the vitals 2/4/6 current-enum aliasing claim the doc comment
made but never enforced.
e. Deleted the stale pre-CT5 0x06001397 narrative in
CharacterPanelLiveDatTests; the pin's comment now describes the
post-CT5 state (a regression guard, not an open bug).
f. Unified ApplySkillSelectionVisuals' selected-branch SpriteResolve
wrapper closure with HandleRowClick's direct assignment.
Build green; full hermetic solution suite green (Release,
Lane!=InstalledDat&...&Status!=KnownFailure filter); InstalledDat lane
green (ACDREAM_RUN_INSTALLED_DAT_TESTS=1, Lane=InstalledDat&Status!=KnownFailure).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>