The remaining code-bearing findings from the round review, F4-F16 minus
the doc-only items (batched separately):
- F4: three client-wide UiButton corpus sweeps (LabelBox path — exactly
the 4 Town buttons, confined to chargen; conflicting custom-selection-
pair + standard Normal/Highlight media — zero found, no gate
tightening needed; per-state label-color map — 209 matches beyond
chargen, confirming AP-222's mechanism has always been broadly active
since it shipped generically in DatWidgetFactory).
- F5/F6: LayoutImporter's Batch C un-consumed-children carve-out now
honors a child's own AuthoredInvisible flag (a narrow honor scoped to
exactly that carve-out, not the general #408 client-wide one) — the
chat transcript's new-text indicator (0x1000048C) was building as a
visible phantom element retail never shows; verified both directions
against the gold-frame pieces, which do not author Invisible.
- F7: BoundedProcessOutputCapture.AppendLine combines the line text and
its trailing newline into one buffer and one file open/write/close
instead of two.
- F9: corrected a stale comment in RuntimeSettingsTargets — #407 split
DisplayModeCatalog's Resolutions/WindowedResolutions in two, so the
fullscreen validator's own narrower list is now DELIBERATELY different
from the Config dropdown's fuller offering, not the "must match" bug
the comment described.
- F10: documented (not changed) why the LabelBox path's default 3px
inset and the face-relative +4px gap in DatWidgetFactory.BuildButton
are deliberately different numbers — neither carries a retail
citation, and moving either to match the other would be an unfounded
guess on a button that currently works correctly.
- F11: Heritage/Profession/Summary/Town description pages now compose
DatRichText.Compose's result ONCE inside their already revision-gated
Refresh, caching the built line list instead of re-wrapping on every
draw call.
- F14: documented (not changed) why PrivateEntityViewportRenderer's
_animatedIds set carrying a reserved-but-never-drawn backdrop id is
harmless — BuildDrawEntities already excludes a null/empty backdrop
from the actual draw list, so the id is never looked up.
- F16: the Summary preview now uses its own render-id pair
(SummaryPreviewRenderId/SummaryPreviewBackdropRenderId, 0xDA11D035/
0xDA11D036) instead of sharing the Appearance page's
(0xDA11D032/0xDA11D034) — confirmed by tracing
FixedEntityTextureOwnerLease through TextureCache to
CompositeTextureArrayCache's shared owner tracker that both pages'
previews share ONE process-wide TextureCache, so sharing render ids
was a real cross-page texture-release collision (either page's own
re-dress or disposal could release the OTHER page's still-active
textures), not a theoretical one.
F3's own register bookkeeping (AP-229 addendum) and F12's register/AD
header-count corrections land in the docs-only commit alongside F15.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Commit 2/3: CLIENT-WIDE blast radius — un-consume media-bearing dat
children on UiText/UiField.
UiText.ConsumesDatChildren (true unless a state authors PassToChildren)
and UiField.ConsumesDatChildren (true, unconditional) used to drop
EVERY dat child at import time, including ones that carry their own
renderable media — retail's UIElement_Text/Field genuinely composites
those as real chrome/controls (frame pieces, linked scrollbars), not
swallowed caption/face art the way a Button's or Meter's children are.
LayoutImporter.BuildWidget gains a new carve-out (mirroring the
existing UiMeter one): when a UiText/UiField's ConsumesDatChildren is
true, build any child whose OWN StateMedia is non-empty (it carries a
real sprite/track) instead of dropping it outright. Purely structural/
property-only children (StateMedia.Count == 0) stay dropped exactly as
before — this is additive, not a relaxation of the PassToChildren gate.
Independently re-derived blast-radius sweep (walks every installed
LayoutDesc via DatCollection.GetAllIdsOfType<LayoutDesc>, new
LayoutImporterMediaBearingChildSweepTests): 37 distinct (layout,
element) pairs — 41 raw tree positions, since a handful of element ids
recur at multiple subtree positions within the same layout — across 15
layouts. Full list:
0x21000005/0x10000011 (x5 tree positions — chat-adjacent template
reused across the layout), 0x21000005/0x1000059A [MAIN GAME UI],
0x21000006/0x10000011, 0x2100000F/0x1000059A,
0x21000038/{0x100003AB,0x100003BA,0x100003C4,0x100003E0,0x100003EC,
0x100003F6,0x100003FA,0x100003FD,0x100003FF,0x10000402,0x10000404,
0x10000405,0x10000409} [character creation],
0x21000043/0x10000362,
0x21000046/0x100003C4, 0x21000047/{0x100003E0,0x100003EC},
0x21000048/{0x100003F6,0x100003FA,0x100003FD},
0x21000049/{0x100003AB,0x100003BA}, 0x2100004A/0x10000409,
0x2100004B/{0x100003FF,0x10000402,0x10000404,0x10000405},
0x2100004C/{0x100002DD,0x100002E5,0x100002E6},
0x2100005B/0x10000011, 0x21000068/0x1000059A,
0x2100006F/0x10000011 [CHAT INPUT].
(This is an independent re-derivation, not a re-statement of the
investigation's earlier "42/14" estimate — the small difference is
expected from measuring with this commit's own criteria.)
New tests: the sweep itself (pins the two flagged landmarks —
MAIN GAME UI 0x21000005/0x1000059A and CHAT INPUT 0x2100006F/
0x10000011 — plus the three chargen boxes), a build-through regression
test confirming those two landmarks' children resolve as real widgets
post-fix, and a chargen-scoped test confirming the eight gold-frame
pieces + linked scrollbar on all three description boxes now resolve
via UiElement.FindDescendant.
Full App suite (Debug and Release, live-DAT): 5304 passed / 0 failed /
3 skipped — ZERO regressions across the whole client, including every
existing chat and main-UI test. Runtime suite: 1735/0, unaffected
(this is an App-layer-only change).
FLAG FOR THE LEAD: automated coverage cannot catch a purely VISUAL
regression (a frame drawing in the wrong place, a scrollbar overlapping
text). Chat and the main game UI both got new dat children rendered for
the first time this commit — schedule the user's own visual check of
both before considering this closed, per the campaign's oracle
discipline.
The scrollbar linkage (wiring the description boxes' UiScrollbar to
actual text scrolling) is NOT done in this commit — the scrollbar
widget now BUILDS, but CharacterCreationHeritagePage/TownPage/
ProfessionPage/SummaryPage do not yet bind its ScalarChanged to
UiText.Scroll. Filed as follow-up (see report).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>