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>
395 lines
20 KiB
Markdown
395 lines
20 KiB
Markdown
# 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
|
|
|
|
```powershell
|
|
$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.
|