acdream/docs/research/2026-08-25-campaign-ct-test-script.md
Erik 996cd73675 fix(CT6): fix round — chrome-inclusive host clamp (BLOCKER B1) + 372px mount default
Opus dual-lens review of CT6 (ec50455a) found 1 blocker, 4 should-fix, 5
notes. All applied:

BLOCKER B1 — the shared gmPanelUI host (0x100005FE) IS retail's own
outer window frame, not a content element: its authored 310/372/310/1000
already include the 5px bevel on every side. RetailWindowFrame.Mount was
adding the NineSlice wrapper's OWN 10px chrome inset on top of that
already-chrome-inclusive source, clamping MinWidth to 320 while the
window's actual mounted outer width stayed 310 — silently below its own
minimum until RetailWindowManager.ResizeTo forcibly widened it despite
ResizeX=false. Fixed with a new
RetailWindowFrame.Options.DatConstraintSourceIsOuterFrame opt-out
(chrome inset = 0 for constraint resolution only, value stays
DAT-sourced); MountCharacter sets it true. Mounted clamp is now exactly
the host's four raw values: width fixed 310, height 372..1000. Added a
mount-time invariant (throws if the mounted outer extent falls outside
its own just-computed clamp) that would have caught this at the first
test run.

S4 (campaign-lead ruling) — the window must MOUNT at retail's authored
default, outer 372 (content 362, matching the host's own content parent
0x10000180), not 0x2100002E's own 300x600 content-authoring canvas
(which produced a stale 610px default pre-fix: 600 + 10 chrome inset).
372 is exactly the host's own authored MinHeight — retail opens at its
resize floor and can only be dragged taller. MountCharacter now sets
ContentHeight=362f explicitly. At this default the 9 attribute/vital
rows (180px) overflow the 160px list immediately — retail-correct, not
a regression.

S2 — 0x1000023E and 0x10000533 both author property 0x79
(HideWhenDisabled) TRUE (fixture-verified: BoolValue=true on both). A
fitting list HIDES the scrollbar entirely; it does not draw a full-track
"disabled" thumb. The code was already correct; four wrong descriptions
(plan ledger, CharacterStatController comment, CT7 script, test comment)
are corrected, plus a new IsPresentationVisible assertion pair in the
resize test.

S3 — CharacterTitlesController's `if (listBox.LayoutPolicy is null)`
Anchors fallback was unreachable on both the real DAT and the fixture
(0x10000532/0x10000539 both author HasOriginalParentSize=true, so
LayoutPolicy is always assigned). Deleted; added an InstalledDatFact pin
guarding the deletion against DAT drift.

N4 — renamed NineSlice_ChatShapedConstraints_... to
NineSlice_ContentShapedConstraints_InsetArithmeticClampsProgrammaticResize
(it tested inset arithmetic on a content-shaped source, not chat's real
contract) and added a true chat-contract pin mounting Chrome=Imported
with chat's real 300/100/2000/2000 constraints, asserting no inset
applies.

N5 — corrected the "nothing inferred, no register row" sentences in the
ground-truth doc and plan ledger: they were false pre-fix (the mounted
clamp WAS an inferred double-counted composition); true now that B1
removes the composition.

CT7 script §4 rewritten with exact clamps (no "≈"), the corrected
default-overflow scrollbar behavior, and an absolute starting-height
statement.

Verified: full hermetic solution suite green (15,441 tests, Release,
Lane exclusions per the release gate), InstalledDat lane green across
the whole solution (414 tests, ACDREAM_RUN_INSTALLED_DAT_TESTS=1,
Status!=KnownFailure) including two new pins
(TitlesListAndPage_AuthorHasOriginalParentSize,
Imported_ChatContract_ClampsAtAuthoredBoundsWithNoChromeInset).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 02:53:57 +02:00

156 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Campaign CT — connected gate script (CT7, user-driven)
**Purpose:** live verification of the character-panel parity campaign
(CT1CT6) against ACE. Launch: the normal connected launch
(`ACDREAM_RETAIL_UI=1`, live ACE at `127.0.0.1:9000`,
`ACDREAM_PAK_PATH=<worktree>\artifacts\owner-gate\acdream-v5.pak`).
Open the character panel (F9 / toolbar). Retail side-by-side comparison
is the oracle for every visual item.
Useful ACE console helpers: title grants come from quests/admin — check
`@acecommands` for a title-grant command; `@grantxp` for levels.
---
## 1. Header identity block (CT4) — Attributes AND Skills tabs
1. **Name line**: the plain character name (rankless characters — the
allegiance rank prefix is a registered deferral, AP-109).
2. **Heritage line**: "<Gender> <Heritage> <DisplayTitle>" — e.g.
"Female Aluvian War Mage" when a display title is set; just
"Female Aluvian" when none. PASS: matches retail's composition and
spacing exactly; a title beginning with "The" shows unmangled.
3. **PK line**: "Non-Player Killer" (or "Player Killer" / "Player
Killer Lite" on a PK/PKL character) in PURE WHITE. PASS: correct
text + color on BOTH the Attributes and Skills tabs.
4. **Level number**: pale gold with outline (authored color — compare
against retail's level display side-by-side; the owner reported ours
was previously off).
5. **Luminance pair**: on a sub-200 character, NO luminance caption or
value renders. (A level ≥ 200 character with MaximumLuminance shows
"Luminance:" and "<available> / <maximum>" — verify only if such a
character is available.)
6. **Live update**: set a display title (see §2) — the heritage line
updates the moment the server confirms, with no relog and no panel
re-open.
## 2. Titles tab (CT3)
1. Click the **Titles** tab. PASS: the page shows "Current Display
Title:" + the current title (or "Unknown" only when the server's
title id fails to resolve — normally a real title or the authored
empty state), the "All Available Titles:" list, and the
"Set as Display Title" button.
2. **List content**: every earned title, alphabetically sorted,
readable rows. With few titles the scrollbar shows retail's
full-track thumb; with many (if available) the thumb sizes
proportionally and scrolls.
3. **Ghost rule**: with NOTHING selected the button is ghosted. Select
the title that IS the current display title — button stays ghosted.
Select a DIFFERENT title — button un-ghosts.
4. **Set round trip**: click Set as Display Title. PASS: the display
title text updates on the server's confirmation, the selection
CLEARS (row highlight goes dark — retail behavior), the button
re-ghosts, and the §1 heritage line updates live.
5. **Row selection visual**: the selected row highlights with retail's
row highlight art (full-row background swap), not a synthesized bar.
## 3. Attribute/skill rows (CT5)
1. **Icon alignment**: row icons sit flush left (20x20 at the row's
left edge), matching retail — the previous inset/smaller icons are
gone. Compare a few rows side-by-side against retail.
2. **Value gutter**: the numbers column ends with a visible margin
before the panel border (the scrollbar band) — retail's 7px gutter.
3. **Row height**: rows are retail-height (slightly tighter than
before); section headers (Trained/Untrained/Unusable) unchanged.
4. **Selection highlight**: clicking a row highlights with the retail
full-row art; the spellbook's selection visuals are UNCHANGED
(regression check — open the spellbook and select a spell).
5. **Raise buttons / tooltips / footer**: regression sweep — raise ×1
and ×10 still work with correct ghosting, skill tooltips still show
formula + description wrapped correctly, the footer numbers update.
## 4. Resize + scrollbar (CT6)
Ground truth (2026-08-25 live probe against layout `0x2100006E`, host
`0x100005FE``docs/research/2026-08-24-campaign-ct-dat-ground-truth.md`
§CT6, corrected by the CT6 fix round's BLOCKER B1): the resize clamp is
authored on the SHARED `gmPanelUI` host, not the character content
itself, and the host IS retail's own outer window frame — its authored
values are chrome-INCLUSIVE, not a content size our own chrome adds on
top of. Host authors **MinWidth=MaxWidth=310** (fixed width — no
horizontal Resizebar) and **MinHeight=372, MaxHeight=1000**. The
MOUNTED window's outer bounds are EXACTLY those same numbers: width
fixed **310px**, floor **372px**, ceiling **1000px** — no inset is
added on top (`RetailWindowFrame.Options.DatConstraintSourceIsOuterFrame`
now tells the mount path this source already includes the bevel).
**Starting height:** the window OPENS at retail's authored default,
**372px** — its own resize floor. It cannot open any shorter; it can
only be dragged taller.
1. **Grab the bottom edge and drag up (shrink).** PASS: the window
stops shrinking at its authored floor (372px outer / the point where
further dragging has no visible effect) — since the window already
OPENS at that floor, this step should show no shrink at all (there
is no room below the default to shrink into). It does NOT collapse
arbitrarily small. Retail comparison: drag retail's own Character/
Skills window down from its own default; it should likewise refuse
to shrink further immediately.
2. **Keep dragging down (grow).** PASS: the window keeps growing until
its authored ceiling (1000px outer) — same side-by-side comparison
against retail's own ceiling.
3. **Left/right edges do not resize.** Only the bottom edge (and top
Dragbar for moving, not resizing) responds — matches retail's
fixed-width authoring (no horizontal Resizebar).
4. **Scrollbar hand-off, Attributes tab.** At the default window size
(372px) the 9 attribute/vital rows (180px content) OVERFLOW the
160px list — the scrollbar is ACTIVE (visible + interactive)
IMMEDIATELY on open, not after shrinking. PASS: this is the owner's
item 2 fix — previously the scrollbar never appeared on Attributes
at all. Grow the window until the rows fit without scrolling: the
bar DISAPPEARS entirely (0x1000023E authors 0x79 hide-when-disabled
TRUE — a fitting list hides the bar, it does not leave a full-track
"disabled" thumb visible). Shrink back down and the bar reappears.
5. **Scrollbar hand-off, Skills tab.** Same immediate-overflow-at-
default check (a longer skills list only makes the overflow more
obvious); grow until it fits and confirm the bar disappears the same
way.
6. **Scrollbar hand-off, Titles tab.** With several earned titles, the
Titles list (authored 455px, inside the 575px page) is scroll-clipped
into the same 372px-default window and its own scrollbar
(`0x10000533`, also hide-when-disabled — fixture-verified) takes over
the same way: active when titles overflow, hidden when the window is
grown enough that they all fit.
7. **Footer stays bottom-docked.** While shrinking/growing on the
Attributes/Skills tabs, the footer (raise buttons / selected-stat
info) stays pinned to the bottom edge — it does not float mid-window
or get clipped early.
8. **Grow back restores.** Drag back down to the original default
(372px): the lists return to their default OVERFLOWING state
(scrollbar reactivates — this is the default, not "all rows fit")
and the window returns to its original proportions.
9. Other windows (chat, social) still clamp at their own authored
minimums — regression check (chat: min 300×100, max 2000×2000 per
`CharacterPanelLiveDatTests.ChatWindowRoot_AuthorsExplicitSizeConstraints`).
## 5. Regression sweep (5 minutes)
- Attributes/Skills tab switching unaffected; CA5 behaviors intact
(raise round trips, live run-speed update on Quickness).
- Logout/login: titles and display title persist; the header matches
PlayerDescription's values.
- Chat window: the CH-round fixes hold (input rails on focus, "Gen"
caption, button flick, no vibrating text while dragging).
---
## Report back
Per section: PASS/FAIL plus anything odd. The three answers that matter
most:
1. §2.4 — does the set-title round trip clear the selection and update
the header live?
2. §3.1/§3.2 — do icons and the value gutter now match retail
side-by-side?
3. §1.3 — is the PK line present, white, and correct on both tabs?