CC2 review fix round: latch scope narrowed, AD-100, creationFailed reason key

F1 (MEDIUM): the correlation-latch docs claimed replies are never
misattributed; in truth an overlapping send OVERWRITES the latch and the
first reply routes to the newest request's event. Narrowed all three doc
sites to the exact contract (single outstanding request; overlap refusal
is CC3's Runtime verification gate, retail's DoFinish UNDEF-state rule)
and pinned the overwrite behavior with
OverlappingSend_OverwritesTheLatch_ReplyRoutesToNewestRequest.

F2 (LOW): filed register AD-100 for the drop-unless-armed deviation —
retail's Handle_CharGenVerificationResponse@0x0055E8B0 has no armed gate
and processes whatever arrives against its persistent verification state.

F3 (LOW): doc note in CharacterCreate.cs — ACE double-sends NameInUse
(IsCharacterNameAvailable runs twice; the first callback's return exits
only the lambda), so the second reply hitting the drop path during a
connected gate is EXPECTED, not a defect.

F4 (LOW): creationFailed's enum-member key renamed name -> reason and the
ATTEMPTED character name added as name, before any consumer shipped —
one status vocabulary must not give the same key two meanings
(characterCreated.name is a character name). Contract, writer, tailer,
and shape-pinning tests updated in lockstep.

F5 (LOW): the thread-id probe-note pointer now cites
ProbeNetLogOutbound's doc comment, where the note actually lives.

Fidelity fold (reviewer's positive note): the latch is retail's OWN
discriminator one layer down — 0x0055E8B0 case 1 branches on
GetVerificationState()==PENDING (create) vs not (restore) — now cited in
both the latch doc and CharGenVerificationResponse.cs.

Core.Net 994, Runtime 1667, Launcher.Core 324, all green Release.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-15 13:10:24 +02:00
parent 5eaad2c88c
commit e77ebf100f
12 changed files with 143 additions and 32 deletions

View file

@ -25,6 +25,13 @@ namespace AcDream.Core.Net.Messages;
/// from "create response" by opcode or shape alone — <c>WorldSession</c>
/// disambiguates by tracking which outbound request (restore vs. create) it
/// is awaiting a reply to (see <c>WorldSession</c>'s awaiting-request latch).
/// That latch is not merely a reasonable design — it is retail's OWN
/// mechanism: <c>Handle_CharGenVerificationResponse@0x0055E8B0</c> case 1
/// branches on the client's persistent chargen state,
/// <c>GetVerificationState() == PENDING</c> → new <c>CharacterIdentity</c>
/// + <c>AddIdentity</c> (a create it initiated), else → unpack into the
/// existing identity at <c>slot</c> (a restore). Same discriminator, one
/// layer down (CC2 review's fidelity note).
/// </para>
///
/// <para>

View file

@ -123,6 +123,20 @@ namespace AcDream.Core.Net.Messages;
/// warns about for restore. <c>WorldSession</c>'s awaiting-request latch
/// must never assume a reply is coming.
/// </para>
///
/// <para>
/// <b>ACE double-sends <c>NameInUse</c> (CC2 review F3).</b>
/// <c>CharacterHandler.CharacterCreateEx</c> calls
/// <c>IsCharacterNameAvailable</c> TWICE — once at the top and once after
/// <c>PlayerFactory.Create</c> — and the first callback's <c>return</c>
/// exits only the lambda, so a duplicate name yields TWO <c>0xF643</c>
/// <c>NameInUse</c> replies. The first consumes the latch; the second hits
/// <c>WorldSession</c>'s unrequested-response drop path (register AD-100)
/// and logs "unexpected CharacterGenerationVerificationResponse". During a
/// connected gate against ACE that log line is EXPECTED after a
/// duplicate-name rejection, not an acdream defect — and CC3's verification
/// gate must not treat the second reply as an error.
/// </para>
/// </summary>
public static class CharacterCreate
{