Commit graph

729 commits

Author SHA1 Message Date
Erik
e77ebf100f 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>
2026-08-15 13:10:24 +02:00
Erik
5eaad2c88c feat(net,runtime): Campaign CC CC2 — CharacterCreate wire, 0xF643 correlation, creation status events
Wire (Core.Net):
- CharacterCreate.cs: outbound 0xF656 builder, byte-exact port of
  Proto_UI::SendCharGenResult@0x00546a70 -> ACCharGenResult::Pack@0x005c7570
  -> CG_Pack@0x005c7200. Account String16L first (packed outside CG_Pack),
  then the constant-1 u32, heritage/gender, 14 appearance strip/style/color
  u32s, 6 f64 shades (skin/hair/headgear/shirt/trousers/footwear, retail
  order), template, 6 attributes, slot, classId, numSkills + exactly 55
  u32 skill-advancement classes (ReadOnlySpan validated ==55, throws
  ArgumentException otherwise — ACE terminates the session on any other
  count via PlayerFactory.CreateResult.ClientServerSkillsMismatch), name
  String16L, startArea, isAdmin, isEnvoy, and a trailing checksum whose
  exact 19-term accumulation set (heritage+gender+3 strips+hairColor+
  eyeColor+hairStyle+headgearStyle+shirtStyle+trousersStyle+footwearStyle+
  template+6 attributes) is read byte-for-byte off CG_Pack's decompiled
  accumulator (0x005c7213-0x005c74c3) — headgearColor/shirtColor/
  trousersColor/footwearColor/shades/slot/classId are deliberately absent
  from the sum despite sitting adjacent on the wire. Cross-checked against
  ACE's CharacterCreateInfo.Unpack/Appearance.Unpack and holtburger's
  CharacterCreateRequestData (types.rs:236-369), which agree on every
  field and order. Retail routes via SendToLogon — the same queue
  CharacterDelete already uses.
- CharGenVerificationResponse.cs (new): promotes the shared 0xF643 parse
  out of CharacterRestore — full Code enum (Undef..AdminPrivilegeDenied=7,
  ACE's CharacterGenerationVerificationResponse) plus the conditional
  Ok-only identity payload (guid/String16L name/u32 secondsGreyedOut).
  CharacterRestore.Parse now delegates to it; CharacterRestore's public
  Parsed shape, Parse signature, and every existing test expectation are
  UNCHANGED.
- PacketWriter.WriteDouble: f64 little-endian helper for the shade fields.

WorldSession dispatch (Core.Net):
- Added an awaiting-request latch (None/Restore/Create), armed by
  SendRestoreCharacter/the new SendCharacterCreation immediately before
  each send (SendCharacterCreation builds the body first so a skill-count
  throw never arms the latch for a request that was never sent), cleared
  the instant a matching 0xF643 is dispatched (success OR parse failure —
  a malformed reply must never wedge the latch open) and on Dispose.
  0xF643 now routes to CharacterRestoreReceived or the new
  CharacterCreateResponseReceived (Action<CharGenVerificationResponse.Parsed>)
  by that latch; an unexpected 0xF643 with nothing outstanding logs once
  and is dropped, never misattributed. Fixed
  WorldSessionCharacterSelectionTests' restore-dispatch test, which
  previously fed a bare CharacterRestore response with no preceding
  SendRestoreCharacter — that shape is now the "no outstanding request"
  drop path by design.

Status events (Runtime + Launcher.Core, contract first):
- Amended docs/plans/2026-08-14-launcher-campaign.md §LA1's pinned status
  vocabulary to add characterCreated{guid,name} (Ok reply identity, named
  to mirror CharGenVerificationResponse's own fields and to read distinct
  from enteredWorld — retail logs a freshly created character straight in
  without a fresh characterList) and creationFailed{code,name} (raw Code
  value + its enum member name).
- SessionStatusWriter.CharacterCreated/CreationFailed implement that
  contract.
- Launcher.Core: CharacterCreatedStatusEvent/CreationFailedStatusEvent +
  StatusEventParser cases, in lockstep.

Tests: CharacterCreateTests (byte-exact layout incl. checksum term-set,
55-slot fixture, wrong-count throws), CharGenVerificationResponseTests
(every Code value), WorldSessionCharacterCreationTests (create-then-
response routes correctly, restore unaffected, no-outstanding drop,
second-response-after-consumed drop, Dispose clears the latch, a builder
throw never arms it), SessionStatusWriterTests + Launcher.Core
StatusEventParserTests/StatusFileTailerTests (pinned shape + tailer
round-trip) for the two new events.

Verified: dotnet build AcDream.slnx -c Release — 0 errors. Full solution
test run green (Core.Net.Tests 993/993, Runtime.Tests 1667/1667,
Launcher.Core.Tests 323/323, plus every other project in the solution).
WSL Ubuntu: Core.Net.Tests 993/993, Runtime.Tests 1667/1667.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 12:49:52 +02:00
Erik
ee80138fba docs: Campaign CC plan — retail character creation, slices CC1-CC7
Recon-grounded (three parallel sweeps 2026-08-15): full retail flow
(gmCharGenMainUI mode 0x1000000b, six ECGProgress pages with every widget
id), byte-exact 0xF656 layout incl. the trailing checksum ACE never reads,
0xF643 create semantics (local roster append + retail logs straight in; no
fresh CharacterList), the chargen DAT table shape, the preview rig
(gmCG3DView over CreatureMode - Appearance/Summary pages only), and every
acdream seam to reuse (generic layout resolver, fixed canvas, offscreen
viewport pipeline, RuntimeCharacterSelectionState as the J-owner template,
the 0xF643 correlation landmine). Slice order CC1 data / CC2 wire (parallel)
then CC3 Runtime owner, CC4/CC5 form pages, CC6a/b appearance+preview
staged, CC7 end-to-end + user gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 12:28:33 +02:00
Erik
36c14902a8 docs: Campaign LA gate round 2 — char-select matrix USER-PASSED
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 12:07:04 +02:00
Erik
936077d576 docs: Campaign LA gate round 2 record — retail-UI product default + JPEG background decode
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 09:13:45 +02:00
Erik
981e168fb9 fix(launcher): Campaign LA gate-round-1 review findings F1-F6 + hardening
F1: the crash reporter comment claimed the launcher never holds a password
in any field - false (ProfileEditorDialogViewModel, AccountProfile.Password,
StartRequest.Password). Reworded to the true, narrower invariant (no throw
site interpolates a credential VALUE into an exception message) and pinned
it with CrashReportNeverContainsAStoredPassword: a real STJ failure over a
profiles document containing a known password, corrupted after the
credential, must yield a crash file with the stack and without the value.

F2: the co-deploy Inputs covered only Bake own sources; a Content edit
never refreshed the 83 MB exe. Now the full reference closure. Fixing it
surfaced two more incrementality traps, both fixed and comment-documented:
SkipUnchangedFiles left the output older than the triggering input (target
re-ran forever - added an explicit Touch), and %(Item.Metadata) in a plain
Include does not batch (the literal percent-text became a permanently
out-of-date phantom input - globs are now spelled per project). Verified:
Core edit retriggers, then two consecutive clean incremental builds.

F3: RID publishes ran BOTH co-deploy paths (two self-contained bake
publishes). Build-time target now guarded on _IsPublishing; verified a
real win-x64 publish runs zero build-target co-deploys and still ships
both exes.

F4: comment misattributed PublishBakeTool=false to CI lanes; it is
target-local recursion guarding. F5: the x:Name reflection sweep now walks
the markup as XML and tolerates template-scoped names (no generated field
exists for those). F6: dead using removed. Hardening: the crash reporter
positional --data-dir fallback requires a fully-qualified path so a
relative or flag-shaped value cannot create ./crash-reports at an
arbitrary CWD.

Launcher 67/67, Launcher.Core 317/317.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 08:19:23 +02:00
Erik
1f87acf1af docs: Campaign LA gate round 1 record — #398 closed, #399 merged-closed, bake co-deploy
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 07:58:41 +02:00
Erik
c25545e8d6 docs(launcher): prepare Campaign LA user gate 2026-08-15 02:16:41 +02:00
Erik
a22f54117b docs(launcher): record Campaign LA11 automated closeout 2026-08-15 02:08:18 +02:00
Erik
d39f3098d5 merge: Campaign LA LA11 - automated closeout review-closed
# Conflicts:
#	docs/plans/2026-08-14-launcher-campaign.md
2026-08-15 02:07:39 +02:00
Erik
134edabed2 feat(launcher): complete Campaign LA11 pre-gate support 2026-08-15 00:02:04 +02:00
Erik
0ac8bf6171 docs(launcher): close Campaign LA10 2026-08-14 23:50:23 +02:00
Erik
da4fb3de19 merge: Campaign LA LA10 - updater review-closed 2026-08-14 23:47:25 +02:00
Erik
f881e5b467 feat(launcher): prepare Campaign LA11 user gate 2026-08-14 23:42:30 +02:00
Erik
09d84387a8 fix(launcher): verify self-update rollback sources 2026-08-14 23:41:55 +02:00
Erik
1955ca8ab5 fix(launcher): harden updater crash recovery 2026-08-14 23:12:15 +02:00
Erik
2d2a5b5046 feat(launcher): implement verified atomic updates 2026-08-14 22:09:34 +02:00
Erik
df824f366c docs(launcher): close Campaign LA6 LA8 and LA9 2026-08-14 21:18:05 +02:00
Erik
2bb8ccb6b6 merge: Campaign LA LA6 - login commands review-closed 2026-08-14 20:48:42 +02:00
Erik
41b15efd4d feat(runtime): share chat commands and run login sequence 2026-08-14 20:27:45 +02:00
Erik
267804465e docs(launcher): close Campaign LA4 LA5 and LA7 2026-08-14 19:36:00 +02:00
Erik
f820eb258d fix(plugins): close LA5 ownership races 2026-08-14 19:28:14 +02:00
Erik
6c4cd2bbc6 docs(launcher): close Campaign LA2 integration 2026-08-14 17:31:33 +02:00
Erik
e01b2cd12f merge: Campaign LA LA2 - probe and idle review-closed
# Conflicts:
#	docs/plans/2026-08-14-launcher-campaign.md
#	src/AcDream.Headless/Hosting/HeadlessSessionHost.cs
2026-08-14 17:30:07 +02:00
Erik
1c5e66c05b fix(launcher): Campaign LA close LA2 review findings 2026-08-14 17:20:02 +02:00
Erik
3313577dcc docs(launcher): Campaign LA close LA1 and LA3 2026-08-14 17:17:56 +02:00
Erik
890cf267fc docs(launcher): record Campaign LA LA1 fix-round gates 2026-08-14 17:00:46 +02:00
Erik
d511e4c348 fix(launcher): close Campaign LA LA1 review findings 2026-08-14 17:00:09 +02:00
Erik
000ea979d5 test: Campaign LA finish LA2 probe and idle gates
Prove idle play remains passive and live until cancellation, then converges through one truthful status teardown. Keep probe mode string-only so numeric enum aliases cannot expand the pinned v1 contract, and record the Windows/WSL gates.
2026-08-14 16:49:51 +02:00
Erik
498f1c1182 docs: Campaign LA ledger — LA7a DONE+merged (fa2de1c4); LA1 implemented, review dispatching
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 16:08:45 +02:00
Erik
db9ad53c1c docs: Campaign LA — pinned launch-contract schema COMMITTED into plan LA1
The LA3 Opus review process note was right: the contract both sides
implement lived only in orchestrator prompts, which is exactly the drift
mode the pin exists to prevent (and it produced the paths-key CRITICAL).
The schema, field rules, probe-mode discriminator, and status vocabulary
are now a binding plan section; amendments change this text first,
implementations second. Ledger: LA3 fix round dispatched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 16:04:32 +02:00
Erik
0bcc7ba3a3 docs: Campaign LA — spec §11.4 corrected per LA7a review; LA7b hazards recorded
The spec seeded the wrong claim (restore extra strings = decompiler
artifact, no register row needed); the LA7a Opus review decoded the
PDB-paired binary and showed the two constant-string arguments are real,
making our guid-only request an adaptation — AD-97 filed on the LA7a
branch. Plan LA7 now carries the review-surfaced LA7b hazards (ACE
silent no-reply restore path, SendToLogon/SendToControl routing,
NumErrors sentinel).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 16:02:20 +02:00
Erik
205b09cf32 docs: Campaign LA ledger — LA3 implemented (37d74e44), LA7a implemented (6a32f375), both reviews in flight
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 15:50:41 +02:00
Erik
7a839cba71 docs: Campaign LA LA0 DONE — ledger closed; arch-doc wording nit from narrow re-review
The re-review closed all six findings and flagged one docs-only nit: the
Platform layer block described App as reaching Platform transitively when
the same commit made the reference direct, and spoke of the launcher in
the present tense. Both corrected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 15:32:52 +02:00
Erik
a49e92df3a fix(platform): Campaign LA LA0 review fixes — CI Linux lanes, arch doc, self-guard
Opus dual-lens review of cb6502c8 passed with six findings; this lands
the fix round:
1. headless-portability.yml: AcDream.Platform src/tests join both path
   triggers and the presentation-free build/test arrays — the moved XDG
   tests run on ubuntu-latest again (they had fallen out of every Linux
   lane).
2. acdream-architecture.md: AcDream.Platform gets its own layer block;
   Runtime may-reference clause updated (the guard changed in cb6502c8,
   its human-readable twin had not).
3. PlatformDependencyBoundaryTests: the BCL-only contract (zero
   project/package references) is now enforced, not just observed.
4. memory/project_linux_graphical.md canonical seam renamed.
5. Plan LA0 recon corrected: the K0 Headless guard was never the guard
   needing amendment (it asserts Headless own refs); Runtime own-refs
   guard was — the commit did the right thing, the plan text now says so.
6. App declares its AcDream.Platform reference explicitly per its own
   convention instead of riding transitivity.

Platform.Tests: 4 passed (3 moved + the new guard).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 15:30:04 +02:00
Erik
7f24af1a37 docs: Campaign LA Linux posture — full launcher stack Linux-tested; GUI waits for Slice L
User decision 2026-08-14: everything the launcher does ships Linux-tested
in this campaign (launcher UI, install/update with manual DAT picker,
headless launches with plugins + login commands, probe, per-slice Linux
test runs, Linux connected-gate section at LA11). GUI client launches
stay Windows-only until Slice L resumes later; the launcher renders GUI
modes disabled on Linux with an explicit note, and the host-agnostic
session-config contract means Slice L lights them up with no launcher
changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 15:17:53 +02:00
Erik
9b0bb25581 docs: Campaign LA plan — slices LA0-LA11, recon-grounded; spec corrections
Plan doc with twelve slices, dependencies, review protocol (Opus
dual-lens: architectural + retail-faithful), and ledger. Three parallel
recon reports grounded the slice bodies:

- Retail select screen is gmCharacterManagementUI: flat listbox +
  Enter/Delete/Restore + dialogs. NO 3D preview (that machinery is
  chargen-only gmCG3DView) — the spec 3D-preview slice is deleted, the
  old retail-ui/05-panels.md pedestal claim is uncited and wrong.
  Restore + CharacterError join scope; delete sends account+slot.
- Chat-command core (parser/router/catalog/ChatVM) is dependency-clean
  BCL+Core; extraction to Runtime is a move, not a rewrite.
- Probe reuses the NoCharacters early-exit shape (graceful teardown at
  the CharacterList stage exists today); roster plumbing is new.
- Bake tool needs --progress-json + explicit --out; no whole-file SHA
  exists — launcher records/verifies its own.
- UI Studio is deleted (Campaign V) — stale references corrected.

Roadmap + CLAUDE.md Current state carry the campaign pointer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 15:10:39 +02:00
Erik
0f15c74147 chore: secure-trade closeout - strip [trade] gate probes, roadmap ledger
The two-client user gate PASSED 2026-08-14 (open both ways, stage with
the retail trading marker, accept/decline, executed swap, Clear All,
cancel text). Every TEMPORARY [trade] probe line from gate rounds 1-2 is
stripped (ItemInteractionController, SelectionInteractionController,
SecureTradeUiController, LiveSessionCommandRouter, WorldSession,
RuntimeTradeState). Roadmap gains the shipped-trade ledger row.

Suites after strip: App 4,992/3, Runtime 1,626 - green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-14 12:48:31 +02:00
Erik
028920420d docs: FA7 closeout — Campaign FA CODE-COMPLETE
The retail four-tab social panel (Fellowship & Allegiance) is
code-complete: all six slices landed and reviewed (dual-lens Opus review
-> fix round -> narrow re-review each). Fellowship two-session flow proven
live (FA6 bot gate PASSED). Closeout bookkeeping:
- register AD count 66 -> 67 (AD-87, the deferred allegiance bot gate);
- plan status flipped to CODE-COMPLETE with the OWED connected gates +
  #384 (allegiance-swear ACE non-response) called out;
- CLAUDE.md Current-state gains the Campaign FA paragraph
  (per feedback_claude_md_staleness), pointing at the memory digest.

Owed: the user's connected gates (§FA3-§FA6 of
docs/research/2026-08-12-campaign-fa-test-script.md) and #384's
ACE-console disambiguation. Full suite 13,304/4/0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 10:30:19 +02:00
Erik
01fafe7b37 docs: FA6 — ledger row + gate script §FA6 (fellowship PASSED live, allegiance deferred)
Plan ledger: fellowship two-session automated gate PASSED live 2026-08-12
(five of six runs reproduced the decisive cross-session assertion); the
allegiance bot gate is DEFERRED behind AllegianceGateEnabled=false pending
docs/ISSUES.md #384, with commit citations for every fix this slice landed
(confirmation relay, name-matched proximity, the fellowship-only
finalization).

Gate script §FA6: the fellowship automated-gate recipe + actual PASSED
result (the two-session config, the six proof points per stage, the
literal decisive-assertion log lines), the allegiance deferral writeup,
and a new [TWO-CLIENT] manual step (25) the user's own connected gate can
run to help disambiguate #384 (ACE-side rule vs wire-builder defect vs
harness-specific drop) using two real graphical clients instead of the
testaccount/testaccount2 pair.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 10:26:19 +02:00
Erik
3dde2dc149 docs: FA5 CODE-CLOSED — dual review + SF-1 fix + baseline off-by-one corrected
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 09:08:41 +02:00
Erik
bc29a1dbdb docs(fa5): register rows AD-84/AD-85/AD-86 + AD-82 addendum, gate-script SFA5, ledger
Register:
- AD-84 -- Swear button's missing "target is a player" enable-rule gate,
  same class as AD-83's Recruit-button gap.
- AD-85 -- the unported StringInfo variable-substitution engine (AD-81's
  same root cause) extended to the Allegiance page's numeric-only
  followers/rank/experience-passed-up fields and its three local
  confirmation dialogs (verbatim-or-bare-name, never invented).
- AD-86 -- ACE's deliberate zeroing of seven AllegianceProfile/
  AllegianceData fields (officers, officer titles, MOTD, MOTD-set-by,
  name-last-set-time, lock, approved vassal, timeOnline, allegianceAge),
  dropped past acdream's own parse layer to match retail's own
  gmAllegianceUI, which has no widget for any of them either.
- AD-82 addendum: the vassal-row click-target-only selection shares
  point (3)'s limitation, but NOT the invented leader/selection tints
  (point 1/2) or the Fellowship-only world-selection sync (point 4) --
  Allegiance's list-selection message has no SetSelectedObject call.

Gate script: new docs/research/2026-08-12-campaign-fa-test-script.md
SFA5 section, mirroring SFA4's structure -- the CF-1 subscription steps
(including the reconnect-while-closed MF-3-REOPEN analogue), the SF-7
per-relationship monarch/patron steps, vassal-list steps, swear/break/
kick with their confirmations, the ACE-zeroed-field honesty note, and
full "what to report"/"explicitly not in scope" lists.

Plan ledger: FA5 row filled in against 7ed79eaf with per-item summary,
directly-measured totals (13,296/4/0, +11 net from FA4's 13,285/4/0),
and the two primary-source resolutions this slice needed beyond the
research docs (the self-rank field's live buffed-quality source, and
"your follower count" == _total_vassals, confirmed by a fresh targeted
decompile of UpdatePlayerData rather than inferred).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 08:41:10 +02:00
Erik
f5bd3e5621 docs: FA4 CODE-CLOSED — MF-3 re-fix (04161def) + re-review (06dbf1cf) closed
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 08:03:42 +02:00
Erik
f041b09b7c docs(fa4): ledger FA4 row records the fix-round SHAs, per-finding dispositions, and final totals
FA4 row now names all six fix-round commits (290f9b58, 5499f058, df000306,
300d8189, 55b17e15, 1d743277) alongside the original landing's three, and
records: build/test green at every commit; the +13/0-deletion test delta
broken down per file; the final directly-measured 13,285 passed / 4
skipped / 0 failed (13,289 total); every MUST-FIX/SHOULD-FIX/NIT applied;
and the corrected dimmed-row arithmetic (35 -> 31 FA4-original -> 34
fix-round final, net one row). Also corrects item (4) of the
"contradictions/deferrals" list, which called the missing Recruit
is-a-player register row an acceptable inline comment -- MUST-FIX 5 named
that the wrong call; it is now register row AD-83.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 07:36:03 +02:00
Erik
1d74327771 docs(fa4): fix-round register rows AD-82/AD-83, AD-78 count correction, gate-script SF-7/MUST-FIX-1/3 corrections
Register (docs/architecture/retail-divergence-register.md):
- AD-78: the Character-tab dimmed count had drifted stale through two
  campaigns (still read "35" after FA4 shipped 31; now 34 after the fix
  round's three reversions). Addendum explains the full D6/SF-8 chain.
  Blast review's own SHOULD-FIX 1.
- AD-82 (new): the invented leader-tint/selection-tint colors, the
  name-text-only row click target, and the page-local (not generic
  UiTemplateListBox) world->panel selection sync -- MUST-FIX 4's
  disposition plus two items MUST-FIX 5 named as owed rows.
- AD-83 (new): the Recruit button's missing "target is a player" gate,
  previously an inline comment, not a register row -- MUST-FIX 5's third
  item. Section header bumped 61 -> 63 active rows.

Gate script (docs/research/2026-08-12-campaign-fa-test-script.md):
- SF-7: fixed step 3's self-contradiction ("only Quit" then "Disband and
  Open should ALSO be enabled").
- MUST-FIX 3: new reconnect step after the existing close/reopen step.
- MUST-FIX 4: new world-selection step under the recruit/dismiss/quit
  section.
- MUST-FIX 1: new HARD-check step for the 6/8-fellow 44%/34% truncation
  (distinct from the existing SOFT 9-member ACE-divergence note).
- MUST-FIX 2 correction: the old invite steps tested whether acdream's
  CLIENT gates the dialog on the option bits -- a mechanism that never
  existed in retail and no longer exists in acdream. Rewritten to test
  the corrected behavior (the dialog always shows regardless of the
  target's own checkbox state) and to explain what ACE-side filtering
  would look like if the local server implements it, so a tester doesn't
  misattribute ACE's behavior to a client bug.
- Renumbered steps 9-22 to 9-25 to fit the two new steps; updated the
  "what to report" section's step cross-references and rewrote its
  invite/dimming bullets to match the corrected mechanism.

Plan (docs/plans/2026-08-11-fellowship-allegiance-campaign.md):
- D7 addendum: SF-8's further correction (FellowshipShareLoot reverts
  too; only FellowshipShareXP survives as genuinely live).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 07:34:09 +02:00
Erik
e6d97516e5 docs: FA4 review — correct D6/D7 (server-side invite filter) + record D8 account/proximity
D6 asserted the client consumes IgnoreFellowshipRequests/
FellowshipAutoAcceptRequests on the invite path; the FA4 mechanism review
(913e35cd MUST-FIX 2) byte-verified retail reads NEITHER bit client-side
(Handle_Character__ConfirmationRequest @0x005640A0, RecvNotice_
FellowshipRequest @0x00490880, MakeFellowRequestDialog @0x00490620) — ACE
filters both server-side. Same class as the D2 reset-lifetime correction.
D6/D7 corrected in-place with dated addenda: the client-side intercept is
removed, the invite dialog always shows, and the two un-dims revert
(dimmed 31->33). D8 records the user-provided second account
(testaccount2/testpassword2) and the recruit-proximity requirement.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 07:06:22 +02:00
Erik
38f08314c7 docs(fa4): register rows AD-80/AD-81, AD-78 addendum, gate script section, ledger
Register: AD-80 files the D5 XP-share display divergence between
retail's byte-decoded table (acdream renders it verbatim) and the
currently-targeted ACE server's slightly different actual grant (.3 vs
.3111111 at 9 fellows, no 10-fellow row, wrong out-of-range default) --
an ACE-vs-retail gap, not an acdream-vs-retail one, filed because it is
directly user-visible through this panel. AD-81 files the two unported
retail text-composition primitives the fellowship page's mechanism
needs (StringInfo variable substitution, ACCharGenData::FormatName) and
what acdream renders instead (plain numeric composites, the raw typed
name). AD-78's derivation table gains its D7 addendum: 4 of the 35
store-only rows (IgnoreFellowshipRequests/FellowshipAutoAcceptRequests/
FellowshipShareXP/FellowshipShareLoot) moved to the Live bullet with
their new consumers named.

Gate script: new §FA4 section covering create (name + shareXP), the
open/close caption swap, button-enable rules, and the D5 display -- all
solo-testable -- plus roster/recruit/dismiss/leader-handoff/invite-
dialog steps marked [TWO-CLIENT] with an honest note that they defer to
FA6's bot-vs-ACE gate if a second account isn't available for this
connected gate. Corrects FA3's now-stale "these six buttons/four
checkboxes are INERT" claims in steps 11-12 to point at the new
section instead of leaving a wrong claim in place.

Ledger: FA4 row CODE-COMPLETE with both commit SHAs, the reconciled
13,238->13,272 (+34) test-count arithmetic, the live-DAT verification
summary (ACDREAM_PROBE_LIVE_MOUNT=1 against real installed DATs,
including the structural finding that retail's own frame-visibility
swap already gates the Create-flow controls away from the roster view
with no extra code needed), and the four scoped
deferrals/simplifications this slice made (the StringInfo/FormatName
gap, the proportional-share omission, the Recruit button's
superset-of-retail enable rule).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 04:41:53 +02:00
Erik
afb3223c9b docs: FA3 CODE-CLOSED (re-review bf07b70e) — carry-forwards folded into FA4
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 03:53:07 +02:00
Erik
c5f73744f0 docs(fa3): update plan ledger with fix-round SHAs and final totals
Records the FA3 fix-round closure: both dual-lens reviews' findings
(mechanism 2 MUST-FIX/9 SHOULD-FIX, blast 1 MUST-FIX/6 SHOULD-FIX/1 NIT)
applied across four commits (9afa05b5/35c40a9b/ae772709/a5553904).
Baseline 13,233/4/0 (13,237 total) -> fix-round 13,238/4/0 (13,242
total), +5 tests, arithmetic verified directly against all 9 test
project totals. FA3 still owes the user's connected gate against the
now-corrected script.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 03:46:10 +02:00
Erik
35c40a9b56 fix(ui): allegiance page — hoist per-frame LinesProvider allocation, document the coarser empty-state gate
Mechanism SHOULD-FIX 2 / blast SHOULD-FIX 4 (same finding, both reviews):
SocialAllegiancePageController.Tick() closed over a local `lines` on
every call — `() => lines` allocated a display class plus a delegate on
EVERY frame, unconditionally, at ~2,000 allocations/second at the
profile's measured FPS, in a hot loop the Modern Runtime slices spent
whole commits driving to 0 B/frame. Hoisted two static readonly
Func<IReadOnlyList<UiText.Line>> providers (BlankLineProvider/
NoLinesProvider); Tick() now assigns the cached delegate reference —
zero allocation while idle or active.

Mechanism SHOULD-FIX 7: FA3's empty-state gate is coarser than the
retail mechanism it is contracted against — gmAllegianceUI::UpdateMonarchData
@0x00491B40 hides the monarch/patron blocks per-relationship (monarch
block also hides when the monarch IS the viewer; patron block on the
analogous test), while this shell gates both blocks on the single
HasProfile flag. Not a MUST-FIX for FA3 (MF-2 in the same review means
HasProfile is effectively always false for the whole FA3 gate, so
nothing wrong is visible during this slice's own gate) — recorded
instead as an explicit FA5 acceptance line in the plan's FA5 row so the
gap cannot be silently lost, plus a class-doc note that FA5's real
monarch/patron population must also change Tick()'s unconditional
LinesProvider reassignment in the same commit or its content will be
overwritten the next frame.

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