docs(CT): CT1 fix round — sealed RowHighlightSprite verdict, verified resize mechanism, strengthened pins
Applies the Opus dual-lens review corrections to CT1's DAT ground-truth research (docs/research/2026-08-24-campaign-ct-dat-ground-truth.md): - Window constraints (BLOCKER): replaced the "likely a hardcoded ResizeTo/SetMinSize" guess with the verified mechanism — UIElement::ResizeTo clamps only via element attributes 0x3C-0x3F, nothing writes them at runtime, and retail resizes the SHARED gmPanelUI host (LayoutDesc 0x2100006E, slot 0x1000018E) rather than 0x2100002E's own content root. Flags the unresolved 300x600-vs-300x362 size tension for CT3/CT6 and marks the host elements NOT PROBED by CT1. - RowHighlightSprite upgraded from a flagged hedge to a SEALED VERDICT: the stat row's selected-state media is 0x06000F93 (gmAttributeUI::UpdateSelection -> InfoRegion::SetState on template 0x10000248), not 0x06001397 (which is legitimately the spellbook row's separate selected-overlay mechanism). Falsifies the matching comment in CharacterStatController.cs and dated-corrects the older 2026-06-26 doc at the spot that originated the wrong sprite id. - Replaced the "18px gutter + 7px = 25px" derived story with the bare authored rectangles (the numbers don't compose cleanly: 300-281=19, and the 282px row overlaps the 281px scrollbar band by 1px) — CT5 must implement the authored numbers directly, never a derived listWidth-18 formula. - Plan doc: corrected the UpdateButtons ghost rule (no selection -> Ghosted, not "ghosts when selected == current") and added the AddTitleToList row-write contract for CT3. - Pins: CharacterPanelLiveDatTests now honors ACDREAM_DAT_DIR first (matching InstalledDatFactAttribute and its sibling live-DAT test classes), hoists five vacuous bare-foreach assertions to counted .ToList() pins, and adds the stat ListBox + scrollbar rect pins that CT5/CT6 depend on. - Doc hygiene: marked several probe-session observations (header geometry "identical" claim, 0x06004CC2 characterization, the master-map/category-map dump) as unpinned inference vs. committed fact, corrected the 0x1000052D "throwaway container" mislabel, and stated the header table's parent-relative coordinate frame. - Recorded the CT5 gold this round found: InfoRegion::InfoRegion's icon-DID lookup (a third GetDIDByEnum consumer, category 0x10000002) and gmSkillUI::RebuildSkillList's section-header order confirmation, plus the RowHeight=22-vs-authored-20 divergence for attribute rows. Verified: ACDREAM_RUN_INSTALLED_DAT_TESTS=1 CharacterPanelLiveDatTests filter 9/9 green; hermetic App suite filter (CI's Lane exclusion list) 6111/6111 green. No production code changed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
d3877f1c0e
commit
e264d8392f
4 changed files with 297 additions and 65 deletions
|
|
@ -22,7 +22,8 @@ namespace AcDream.App.Tests.UI.Layout;
|
|||
public sealed class CharacterPanelLiveDatTests
|
||||
{
|
||||
private static string DatDirectory =>
|
||||
Path.Combine(
|
||||
Environment.GetEnvironmentVariable("ACDREAM_DAT_DIR")
|
||||
?? Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
|
||||
"Documents", "Asheron's Call");
|
||||
|
||||
|
|
@ -61,7 +62,14 @@ public sealed class CharacterPanelLiveDatTests
|
|||
Assert.Equal(Vector4.One, name.FontColor);
|
||||
}
|
||||
|
||||
foreach (var heritage in Flatten(tree!).Where(e => e.Id == CharacterStatController.HeritageId))
|
||||
// CT1 fix round: hoisted to .ToList() + an explicit count assertion.
|
||||
// A bare `foreach (x in seq.Where(...))` with no count check passes
|
||||
// vacuously if the importer ever returns an empty sequence — it
|
||||
// proves nothing about the two Attributes/Skills duplicate chains
|
||||
// actually being present.
|
||||
var heritageOccurrences = Flatten(tree!).Where(e => e.Id == CharacterStatController.HeritageId).ToList();
|
||||
Assert.Equal(2, heritageOccurrences.Count);
|
||||
foreach (var heritage in heritageOccurrences)
|
||||
{
|
||||
Assert.Equal(0x40000002u, heritage.FontDid);
|
||||
Assert.Equal(Vector4.One, heritage.FontColor);
|
||||
|
|
@ -70,7 +78,9 @@ public sealed class CharacterPanelLiveDatTests
|
|||
}
|
||||
|
||||
// Item 4: PK status line is authored PURE WHITE.
|
||||
foreach (var pk in Flatten(tree!).Where(e => e.Id == CharacterStatController.PkStatusId))
|
||||
var pkOccurrences = Flatten(tree!).Where(e => e.Id == CharacterStatController.PkStatusId).ToList();
|
||||
Assert.Equal(2, pkOccurrences.Count);
|
||||
foreach (var pk in pkOccurrences)
|
||||
{
|
||||
Assert.Equal(0x40000002u, pk.FontDid);
|
||||
Assert.Equal(Vector4.One, pk.FontColor);
|
||||
|
|
@ -79,7 +89,9 @@ public sealed class CharacterPanelLiveDatTests
|
|||
// Item 5: level color is a pale gold (~RGB 255/242/127) WITH an
|
||||
// authored outline — CharacterStatController.Gold (1, 0.82, 0.36, 1)
|
||||
// with no outline is a divergent hand-picked runtime color.
|
||||
foreach (var level in Flatten(tree!).Where(e => e.Id == CharacterStatController.LevelId))
|
||||
var levelOccurrences = Flatten(tree!).Where(e => e.Id == CharacterStatController.LevelId).ToList();
|
||||
Assert.Equal(2, levelOccurrences.Count);
|
||||
foreach (var level in levelOccurrences)
|
||||
{
|
||||
Assert.Equal(0x40000010u, level.FontDid);
|
||||
Assert.True(level.Outline);
|
||||
|
|
@ -89,9 +101,14 @@ public sealed class CharacterPanelLiveDatTests
|
|||
Assert.Equal(0.498f, level.FontColor!.Value.Z, precision: 2);
|
||||
}
|
||||
|
||||
foreach (var xpLabel in Flatten(tree!).Where(e => e.Id == CharacterStatController.XpNextLabelId))
|
||||
var xpLabelOccurrences = Flatten(tree!).Where(e => e.Id == CharacterStatController.XpNextLabelId).ToList();
|
||||
Assert.Equal(2, xpLabelOccurrences.Count);
|
||||
foreach (var xpLabel in xpLabelOccurrences)
|
||||
Assert.Equal(0x40000000u, xpLabel.FontDid);
|
||||
foreach (var xpValue in Flatten(tree!).Where(e => e.Id == CharacterStatController.XpNextValueId))
|
||||
|
||||
var xpValueOccurrences = Flatten(tree!).Where(e => e.Id == CharacterStatController.XpNextValueId).ToList();
|
||||
Assert.Equal(2, xpValueOccurrences.Count);
|
||||
foreach (var xpValue in xpValueOccurrences)
|
||||
Assert.Equal(0x40000000u, xpValue.FontDid);
|
||||
}
|
||||
|
||||
|
|
@ -119,6 +136,13 @@ public sealed class CharacterPanelLiveDatTests
|
|||
};
|
||||
foreach (ElementInfo listBox in listBoxes)
|
||||
{
|
||||
// CT1 fix round: authored ListBox rect — CT5's row alignment
|
||||
// and CT6's resize/scrollbar contract both depend on this.
|
||||
Assert.Equal(0f, listBox.X);
|
||||
Assert.Equal(112f, listBox.Y);
|
||||
Assert.Equal(300f, listBox.Width);
|
||||
Assert.Equal(160f, listBox.Height);
|
||||
|
||||
Assert.Equal(CharacterStatController.ListScrollbarId, listBox.ScrollbarElementId);
|
||||
Assert.Equal(5, listBox.TemplateList.Count);
|
||||
foreach (uint id in expected)
|
||||
|
|
@ -128,6 +152,17 @@ public sealed class CharacterPanelLiveDatTests
|
|||
t => t.TemplateLayoutId == 0x21000045u && t.TemplateElementId == id);
|
||||
}
|
||||
}
|
||||
|
||||
// CT1 fix round: the ListBox's own authored scrollbar rect — the
|
||||
// "always reserved" gutter CT5/CT6 both depend on.
|
||||
var scrollbars = Flatten(tree!).Where(e => e.Id == CharacterStatController.ListScrollbarId).ToList();
|
||||
Assert.Equal(2, scrollbars.Count);
|
||||
foreach (ElementInfo scrollbar in scrollbars)
|
||||
{
|
||||
Assert.Equal(281f, scrollbar.X);
|
||||
Assert.Equal(16f, scrollbar.Width);
|
||||
Assert.Equal(160f, scrollbar.Height);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -151,9 +186,13 @@ public sealed class CharacterPanelLiveDatTests
|
|||
Assert.Equal(20f, row.Height);
|
||||
Assert.Equal(0x06004CC2u, row.StateMedia["Normal"].File);
|
||||
// Row-template Highlight sprite (0x06000F93) — CharacterStatController's
|
||||
// current RowHighlightSprite private constant is 0x06001397, a
|
||||
// divergence flagged (not fixed) by CT1; see the research doc's
|
||||
// "Corrections to the plan" §3.
|
||||
// current RowHighlightSprite private constant is 0x06001397. CT1's
|
||||
// fix round upgraded this from a flagged divergence to a SEALED
|
||||
// VERDICT (gmAttributeUI::UpdateSelection SetState(6) ->
|
||||
// InfoRegion::SetState on this exact template); 0x06001397 belongs
|
||||
// to the spellbook row's separate selected-overlay mechanism. CT5
|
||||
// fixes RowHighlightSprite for the stat rows only; see the research
|
||||
// doc's "Corrections to the plan" §3.
|
||||
Assert.Equal(0x06000F93u, row.StateMedia["Highlight"].File);
|
||||
|
||||
ElementInfo icon = Assert.Single(row.Children, c => c.Id == 0x10000129u);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue