acdream/docs/research/2026-08-16-campaign-cc-test-script.md
Erik 2176ba768e fix(chargen): Campaign CC CC7 review fix round — F1-F9 — REVIEW-CLOSED
Both dual-lens reviewers of `9cf6c522`+`ddcbf1fb` returned PASS-with-items.
This round closes all nine findings:

F1 files AP-229 for the screen-layering divergence (retail destroys/
reconstructs the current UI framework via UIFlow::UseNewMode; acdream
keeps both CharacterManagementUiController and CharacterCreationUiController
mounted for the whole lifetime and reveals/occludes) plus its narrow
residual risk (the shared RetailDialogFactory can hand UiRoot.Modal to a
dialog opened by the still-ticking, occluded management screen on an
inbound CharacterError) and what already matches retail (selection/
world-name persistence, click-through isolation, one coherent Modal
stack).

F2 rewrites the connected-gate script's roster-full step with the exact
`@modifylong max_chars_per_account` recipe and the pending-delete-counts
note. F3 adds AP-221's console-diagnostic lines to the known-gaps
paragraph. F4 adds an empty-name/AP-227 step. F9 notes that a uniform
Random pick over 13 heritages can repeat.

F5 adds an App-layer source-text pin
(GameWindowLiveSessionOwnershipTests.LiveSessionRuntimeFactoryBinds
CharacterCreatedAndCreationFailedToTheStatusWriter) for the delegate
wiring the reviewer proved was deletable without breaking any test — no
practical seam exists to construct LiveSessionRuntimeFactory without a
GameWindow, so this follows the file's own established source-text-pin
pattern; the payload shape is already pinned separately at
SessionStatusWriterTests.

F6 corrects the CC7 ledger's checksum-assertion wording (it is a
round-trip purity check, not an independent golden — the golden is
CharacterCreateTests.ComputeChecksum_ExactRetailAccumulationSet) and
cross-references it from the test's own doc comment.

F7 corrects the CC7 ledger's fixture-ordering claim (it had chargen
constructing first, backwards from RetailUiRuntime.Tick's real
management-then-chargen order) and reorders CharacterScreensFixedCanvas
ArbiterTests to match production, adding ClickThrough/ZOrder assertions
that pin the occlusion the reviewer previously verified only by hand.

F8 records a known flake (RuntimeCollisionReportingStateTests.
WarmedSteadyContactRefreshDoesNotAllocate, allocation-assertion load
sensitivity, pre-existing) seen under full-solution parallel load on
both reviewer runs.

Campaign status: all seven slices (CC1-CC7) are REVIEW-CLOSED; the
campaign is CODE-COMPLETE pending the user's own connected gate.

Runtime 1735/0 (unchanged), App 5257/3 skips (+1: the new F5 pin).
Full Release build: 0 warnings, 0 errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 03:13:02 +02:00

20 KiB

Campaign CC connected-gate test script

Status: the campaign is CODE-COMPLETE (CC1-CC7) and this script is its connected-gate contract. Every step below is the user's own eyes on the running client — nothing here was run automatically. No automated live character creation has been run against ACE (see §CC-Not-Automated) — the first LIVE create is deliberately left to this gate.

This script covers TWO ways to reach the chargen screen: the real launcher flow (Campaign LA's product path) and the developer shortcut (ACDREAM_RETAIL_UI=1 + ACDREAM_OPEN_CHARGEN=1, still available and still useful for a fast create-only iteration loop). Both land on the exact same screen and Runtime owner — there is no second code path being tested.

Local ACE connection details (per CLAUDE.md): host 127.0.0.1, port 9000, account testaccount / testpassword. Use a FRESH character name per attempt (ACE does not forget names within a session) — CC-<yourinitials>-<n> is a good scheme, e.g. CCAB1, CCAB2.


§CC1 — reaching the screen

Path A — the launcher (product path)

  1. Launch AcDream.Launcher (already installed/updated per Campaign LA's own gates — this script does not re-run first-run setup or the update flow; see docs/research/2026-08-14-campaign-la-test-script.md if either is in question).
  2. Open Check for updates. Confirm it reports the client already current (no install prompt) — Campaign LA's own gates already proved the install/update mechanics; this step just confirms nothing is stale before the character-creation gate.
  3. Confirm (or create) a profile pointed at 127.0.0.1:9000, testaccount / testpassword.
  4. Click GUI — character select. The retail character-management screen (gmCharacterManagementUI) opens — the flat character list, World name, Enter/Delete/Restore buttons, and the Create button.

Path B — the developer shortcut

$env:ACDREAM_DAT_DIR   = "$env:USERPROFILE\Documents\Asheron's Call"
$env:ACDREAM_RETAIL_UI = "1"
$env:ACDREAM_LIVE      = "1"
$env:ACDREAM_TEST_HOST = "127.0.0.1"
$env:ACDREAM_TEST_PORT = "9000"
$env:ACDREAM_TEST_USER = "testaccount"
$env:ACDREAM_TEST_PASS = "testpassword"
dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Release

Confirm the SAME character-management screen appears. ACDREAM_OPEN_CHARGEN=1 (add it to the block above) is the CC4-era interim seam that opens the chargen screen directly on startup, skipping the Create click — still useful for a fast create-only loop, but Path A/B above is now the REAL path and should be exercised at least once per gate.

The Create button

  1. With at least one free character slot (roster count below the account's allowed slot count — most test accounts have several free slots), confirm Create is ENABLED (not greyed out).
  2. Click Create. The chargen screen (gmCharGenMainUI) opens directly on the Heritage page — no confirmation, no loading screen. The character-management screen you were just on is not closed or hidden; it simply sits behind the new screen (this matters for the Exit step below).
  3. If your account's roster is completely full (rare on a fresh test account — every slot occupied), confirm Create is instead GREYED OUT and does nothing when clicked. This is retail's own gate (gmCharacterManagementUI::UpdateButtons) — a full roster ghosts Create exactly like Enter/Delete grey out for an unselected row. A fresh test account is unlikely to be full on its own (ACE's default max_chars_per_account is 11) — force this state instead of waiting for it:
    1. From the ACE server console (or a GM-privileged in-game @ command), run @modifylong max_chars_per_account 2 to lower the ceiling below your current roster count.
    2. Reconnect (a fresh CharacterList only arrives on a new connection — the client does not re-fetch it live) and confirm Create is now GREYED OUT.
    3. Restore the default afterward: @modifylong max_chars_per_account 11, then reconnect again and confirm Create is enabled once more.
    4. The count includes pending-delete (greyed) characters — a character mid-deletion still occupies a roster slot both in ACE's GameMessageCharacterList and in acdream's own gate (RuntimeCharacterSelectionState.BuildButtons's _entries.Length < _slotCount, which counts every roster entry regardless of pending-delete state) — matching retail's own RebuildCharacterList, which walks the same full set. If you have a pending-delete character sitting around, it still counts toward the ceiling above.

Leaving the screen (Back-at-Heritage and Exit)

  1. On the Heritage page (the first page), click Back. Confirm a confirmation dialog appears asking whether to leave character creation (same text/shape as the Exit button below — Back-at-Heritage and Exit share retail's one DoExit confirmation).
  2. Click Exit (top of the screen, available on every page). Confirm the SAME confirmation dialog appears.
  3. Confirm the dialog (accept). The chargen screen closes. You are back at the character-management screen you started from — roster, World name, and any prior selection are exactly as you left them (character management was never hidden, so there is nothing to "restore").
  4. Click Cancel on a repeat Exit attempt instead — confirm the dialog closes and chargen stays open, untouched.

What to report for §CC1

  • Create's enabled/greyed state matching the free-slot count you actually have.
  • Whether clicking Create opens chargen with no lag/flash/black frame.
  • Whether returning from Exit shows the character list exactly as it was (no re-flicker, no lost highlight, no stale World name).

§CC2 — the six-page create flow

The screen does NOT open blank. gmCharGenMainUI's own constructor rolls a full random character (heritage, gender, appearance, clothing, template, start area) before the Heritage page ever draws — acdream ports this faithfully (AP-214, retired). Expected retail quirk: the gender shown on the Appearance page is the FLIP of the roll — the Appearance page's own init code reads the just-rolled gender and immediately swaps it to the opposite one. If you open chargen and see (say) a female Aluvian with the Appearance page showing "Male" selected, that is CORRECT, not a bug — do not report it.

Heritage page

  1. Confirm one of the 13 heritage buttons is already highlighted (the opening roll) — Human heritages (Aluvian/Gharu'ndim/Sho/Viamontian), Tumerok, Gearknight, Lugian, Empyrean, Penumbraen, Shadowbound, Undead, Olthoi, and OlthoiAcid should all be selectable and each show its own description text (starting skills, bonus-skills paragraph where retail has one — Lugian/Olthoi/OlthoiAcid have none, that's retail-correct).
  2. Click Random. Confirm the highlighted heritage changes to a uniformly-picked one of the 13 — this is AP-212's documented approximation (retail's own Heritage-page Random rolls with retail's own distribution; acdream picks uniformly over every installed heritage). A uniform pick over 13 can land back on the heritage you already have — click a few times if the first click looks like a no-op; occasional repeats are expected, not a bug. Not a bug to report unless the button does nothing or crashes across several clicks.
  3. Select Olthoi or OlthoiAcid. Confirm the Profession, Skills, and Town tabs are hidden (Olthoi variants skip straight to a fixed Custom template with no attribute/skill/town choices) and the screen auto-advances past them.

Profession page

  1. Select a NON-Olthoi heritage. Confirm 7 template buttons (Custom + 6 presets) and 6 attribute sliders (Strength/Endurance/Coordination/ Quickness/Focus/Self).
  2. Drag a slider. Confirm the numeric readout updates live and the Available-credits counter decreases/increases correspondingly.
  3. Click a preset template (not Custom). Confirm all 6 sliders jump to that preset's values and Available credits updates to match.
  4. Click Random. Confirm heritage/template selection changes (AP-212 — uniform pick, not retail's own weighted roll).

Skills page

  1. Confirm ONE flat listbox of skills, each row showing name, current level, and train/specialize costs (AP-213 — retail groups these into four sorted buckets; acdream's flat list is a presentation simplification, not a rules difference — do not report the flat ordering as a bug).
  2. Click a trainable row. Confirm it advances (Untrained -> Trained -> Specialized) and the skill-credits meter decreases; a second click on an already-Specialized row does nothing further (no fourth state).
  3. Confirm Random is disabled/greyed on this page (retail's RandomizeSkills primitive is unported — AP-212's own documented gap).

Appearance page

  1. Confirm Face and Clothes sub-tabs, nine spin controls (hair, eyes, nose, mouth, skin under Face; headgear, shirt, trousers, footwear under Clothes), nine color swatches, a shade scrollbar, zoom/rotate buttons, and a live 3D preview playing an idle animation loop.
  2. Click a spin's left/right arrow zones. Confirm the selected style index advances/retreats and the preview model updates.
  3. Click a color swatch. Confirm the swatch shows a highlighted "selected" ring/border (AP-215 — acdream's own selection indicator, not retail's overlay mechanism; functionally equivalent).
  4. Click Zoom In. Confirm the preview freezes its pose (idle animation stops) and the camera tweens closer over about half a second. Click Zoom Out — animation resumes, camera tweens back out.
  5. Click Rotate Clockwise/Counter-Clockwise. Confirm the model spins continuously at a steady rate (about 3 seconds per full turn); clicking the SAME direction again stops it, clicking the OPPOSITE direction reverses it.
  6. Click Random (on either sub-tab). Confirm hair/eyes/nose/mouth/skin (Face) or headgear/shirt/trousers/footwear (Clothes) all re-roll together — this IS retail's real RandomizeAppearance/ RandomizeClothing primitive (CC5 ported it verbatim, not approximated).
  7. Select Gearknight, Olthoi, or OlthoiAcid on the Heritage page, then return to Appearance. Confirm the Clothes sub-tab and its four spins are unreachable, Nose/Mouth spins are hidden, and Eyes' arrows are disabled (fixed eyes for these forms).

Known cosmetic gaps on this page — expected, do not report as bugs unless noticeably worse than described: swatches show static art rather than the actual color they represent (AP-216); the gradient circle art next to the swatches never repaints to reflect the current color (AP-217); the four icon-only spins (hair/eyes/nose/mouth) show a plain number instead of an icon thumbnail, while the four clothing spins show real names (AP-215/ AP-218); on Olthoi/OlthoiAcid/Gearknight the Skin spin does not slide up to close the gap left by the hidden Nose/Mouth spins (AP-219); switching heritage INTO or OUT OF Gearknight does not automatically re-roll appearance/clothing the way retail does on that exact transition (AP-220); the currently-selected spin shows no distinct highlighted state versus the other eight (AP-222 — this is a MEASURED gap in acdream's own art, not yet attributed to a specific missing asset; report clearly if you can visually compare with retail here).

Known session-permanent gap (AP-221) — check the console before reporting a dead preview. On an unlucky frame where the DAT/GPU resource read backing the 3D preview isn't ready at the client's single composition pass, the Appearance page's zoom/rotate controls can go dead for the rest of the session (or the Summary page's preview can simply never render), with no on-screen error — the only evidence is a console line: [UI] chargen preview viewport unavailable at composition time... (or the Summary-page sibling, [UI] summary preview viewport unavailable at composition time...). If zoom/rotate stop responding or a preview stays blank, check the console for one of these lines FIRST. If it's there, restart the client and retry before reporting a bug — this is a known, already-registered gap, not a new one.

Town page

  1. Confirm four town buttons: Holtburg, Shoushi, Yaraq, Sanamar (not id order — that's retail's own literal ordering, ported faithfully), each with descriptive text.
  2. Click a town. Confirm it highlights and the description text updates.

Summary page

  1. Confirm a listbox showing Profession, Gender, Heritage, and Starting Town lines, an "Attributes" header, then Strength/Endurance/ Coordination/Quickness/Focus/Self/Health/Stamina/Mana/Skill Credits as paired rows, then Specialized and Trained skill name lists (retail also lists the two Untrained buckets; acdream's Summary omits them — AP-224, same class of cut as the Skills page's own AP-213).
  2. Confirm a static 3D preview of the character (no zoom/rotate controls on this page — retail has none here either).
  3. Click the name field and type a name. Confirm only letters, spaces, apostrophes, and hyphens are accepted (other characters are silently rejected keystroke-by-keystroke).
  4. Click Random on this page. Confirm a confirmation dialog appears first ("are you sure you want to randomize?"); confirming it re-rolls the ENTIRE character (heritage through name) using retail's real RandomizeCharacter primitive — the same one the screen-open roll uses.

What to report for §CC2

  • Any page that fails to render a control listed above, or where a control visibly does nothing when clicked.
  • Anything from the "known cosmetic gaps" list that looks MORE broken than described (e.g. a spin that doesn't advance at all, not just a missing highlight).
  • Any crash, freeze, or console error while navigating pages or the tabs.

§CC3 — Finish and its dialogs

Use a fresh, never-before-used character name for the happy path. For every scenario below, watch the console/log for [UI]/[CC]-prefixed lines — they help distinguish "nothing happened because the click didn't register" from "the request went out and ACE is thinking about it."

Happy path

  1. Complete a legal character (heritage, gender, template with credits fully spent, at least a default set of skills, a town, a fresh name).
  2. Click Finish on the Summary page. Confirm the screen closes almost immediately (no visible "please wait" dialog for a normal accept — ACE's Ok reply is fast) and you land DIRECTLY in the world as the new character — no return to character management, no fresh character list, matching retail's own "log straight in" behavior.
  3. If you back out to character management instead (e.g. via a later logout), confirm the new character now appears in the roster alongside any pre-existing ones, in the correct slot.

NameInUse (duplicate name)

  1. Create a SECOND character using the EXACT name you just used above.
  2. Click Finish. Confirm the ID_Character_Err_NameReserved dialog appears ("that name is in use" / similar text) and you stay on the chargen screen — Finish is clickable again afterward.
  3. Expected log noise (register AD-100): ACE sends the NameInUse rejection TWICE for the same request (a real ACE double-send bug, not an acdream defect). The FIRST reply drives the dialog above; the SECOND logs something like unexpected CharacterGenerationVerificationResponse in the console. That log line is EXPECTED here — do not report it as an error.

The credit-warning confirm flow

  1. Select the Custom template on the Profession page (leaves several attribute credits unspent) and complete the rest of the character.
  2. Click Finish. Confirm a warning dialog appears about unspent attribute credits, and Finish does NOT send anything yet.
  3. Confirm the dialog. Confirm the request now sends anyway, with the unspent credits — this is retail-correct (DoFinish's own confirm-arm skips the credit check entirely; ACE accepts an under-spent build).

The randomize warning flow

Already covered in §CC2's Summary-page step 4 above — confirm the warning appears BEFORE any randomization happens, and Cancel leaves the character completely untouched.

The exit warning flow

Already covered in §CC1's "Leaving the screen" section above.

NameTooLong

  1. On the Summary page, type or paste a name longer than 32 characters and commit it (press Enter, or click elsewhere to move focus away from the field).
  2. Confirm the ID_CharGen_NameTooLong dialog appears and the field reverts to its previous (shorter) value — the field itself does not cap your typing at 32 characters as you go; the rejection only fires on commit. That is retail-correct, not a bug.

Empty name (AP-227, an acdream/retail divergence — expected)

  1. On the Summary page, select all the text in the name field and delete it entirely, then blur the field (click elsewhere) without typing a replacement.
  2. Click Finish. Confirm the NoName/ID_CharGen_NoNameWarning dialog appears — acdream clears its internal name state the instant the field is emptied, so Finish sees an empty name and refuses. This is NOT what retail does: retail's own commit handler only acts when the field's length is greater than 1 (NUL-inclusive, so an empty field's length is exactly 1) — an emptied-then-blurred field is a silent no-op in retail, and the character's internal name stays whatever it was BEFORE you cleared the field, even though the field visually shows empty. A real retail client would create the character under that old, uncleared name here instead of showing a dialog. Expect acdream's dialog, not retail's silent keep-old-name behavior — register AP-227.

What to report for §CC3

  • Whether the happy path truly lands you in-world with no intermediate screen.
  • The exact dialog text shown for each rejection (useful for a later string-table audit even if it looks right).
  • Any case where Finish appears to do nothing at all (no dialog, no console line, no world entry) — that would be a real regression, not one of the documented cosmetic gaps above.

§CC4 — ACE-side landmines (not acdream defects)

  • Heritage-priced skill over-deduction — LATENT, will not fire with the installed EoR DAT. ACE's PlayerFactory.CreatePlayer has a real overcharge bug when specializing a skill priced by the active heritage's own skill list (versus the global skill table). It was measured against the installed EoR data and found unreachable — every heritage's one priced skill (Arcane Lore) has a heritage NormalCost of 0, which makes ACE's overcharge exactly zero. You should NOT be able to trigger a FailedToSpecializeSkill rejection from a retail-legal build during this gate. If you somehow do, that is worth flagging immediately — it would mean the installed DAT's costs differ from what was measured.
  • Disabled-Olthoi create -> Pending -> NameDBDown dialog is retail-correct. If your local ACE has Olthoi character creation disabled (a server config option), attempting to create an Olthoi/ OlthoiAcid character will surface the ID_Character_Err_NameDBDown dialog via a Pending response code. This is retail's OWN behavior (ACE's olthoi_play_disabled branch sends Pending, and retail's dispatch has no silent branch for it) — not a "the client swallowed my request" bug.

§CC-Not-Automated

No automated test in this repository has created a character against a LIVE ACE server. Every field-shape and response-code assertion in Campaign CC's test suite runs against a real WorldSession and hand-built response packets (see tests/AcDream.Runtime.Tests/Session/LiveSessionControllerCharacterCreationTests.cs) — the wire bytes and the state machine are proven byte-for-byte, but the FIRST character ever created against a real, running ACE process is whatever you create during this gate. Server state (what names exist, what heritages are enabled, what the account's slot count is) is entirely yours to observe; this script deliberately does not assume any of it in advance.