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>
334 lines
52 KiB
Markdown
334 lines
52 KiB
Markdown
# Campaign FA — the retail social panel: Fellowship & Allegiance
|
||
|
||
> **For agentic workers:** slices are executed by ONE Sonnet implementer at a
|
||
> time against this contract, then dual-lens Opus-reviewed, per §7/§8. The
|
||
> four research docs in §1 are the spec's data appendix — implementers MUST
|
||
> read the cited sections before coding; every table this plan references is
|
||
> committed there in full.
|
||
|
||
**Status: CODE-COMPLETE 2026-08-12 — all six slices landed and reviewed
|
||
(FA7 closeout done). The retail four-tab social panel
|
||
(Friends / Allegiance / Fellowship / Squelch, host slot `0x1000018F`,
|
||
id 12) mounts via the OP3 recipe; the Fellowship and Allegiance pages are
|
||
live end-to-end (real wire, Runtime-owned state, F3/F4 open paths); the
|
||
fellowship two-session flow is PROVEN over the live wire (FA6's automated
|
||
bot-vs-ACE gate PASSED — the recruited bot's own `RuntimeFellowshipState`
|
||
flips). Each slice went through dual-lens Opus review → fix round →
|
||
narrow re-review; three design calls were corrected in-flight with dated
|
||
addenda (D2 reset-lifetime, D6/D7 server-side invite filter, the CF-1
|
||
`0x001F` subscription). OWED: the user's connected gates over §FA3-§FA6
|
||
of `docs/research/2026-08-12-campaign-fa-test-script.md` (several
|
||
`[TWO-CLIENT]` steps), and ISSUES #384 — the allegiance-swear bot gate is
|
||
deferred/disabled because ACE returns nothing to the `0x001D` swear
|
||
(needs ACE-console disambiguation; the swear CODE is done+reviewed, only
|
||
its automated two-session proof is unverified; register AD-87). Final
|
||
full suite 13,304/4/0.**
|
||
|
||
**History: planned 2026-08-11. FA1 CLOSED 2026-08-12; FA2 CLOSED
|
||
2026-08-12 (dual APPROVE-WITH-FIXES → fix round `4272ad0e`/`ded23067`/
|
||
`ed8b3ec9` → narrow re-review CLOSED `cc1a319c`, no reopen; CF-1 folded
|
||
into the corrected FA5 slice row). FA3's dual-lens review landed
|
||
APPROVE-WITH-FIXES on both lenses (mechanism: 2 MUST-FIX/9 SHOULD-FIX;
|
||
blast: 1 MUST-FIX/6 SHOULD-FIX/1 NIT) → fix round CLOSED 2026-08-12
|
||
(`9afa05b5`/`35c40a9b`/`ae772709`/`a5553904`) with every finding applied,
|
||
including two corrections to the connected-gate script itself (the
|
||
refuted tab x-order, and a false-defect trigger that could not fire).
|
||
FA3's narrow re-review CLOSED `bf07b70e` 2026-08-12, no reopen — FA3 is
|
||
CODE-CLOSED; the user's connected gate is OWED
|
||
(`docs/research/2026-08-12-campaign-fa-test-script.md`, corrected). The
|
||
re-review's four non-blocking carry-forwards are folded into FA4's
|
||
contract: the `Flush()` scroll-position reset under FA4's
|
||
per-vitals-tick roster rebuilds; a production-resolver test for the new
|
||
template cache; scrollbar-id literals promoted to the authored
|
||
`ScrollbarElementId`; the bounded per-frame retry on a permanently
|
||
unresolvable template. **FA4 CODE-COMPLETE 2026-08-12 (`357d2032`
|
||
Runtime, `5bdd0528` App+tests) — implementer pass done, all four FA3
|
||
carry-forwards closed in this same slice; the dual-lens review (§7) and
|
||
the user's connected gate (`docs/research/2026-08-12-campaign-fa-test-script.md`
|
||
§FA4, several steps explicitly need a second account/character and are
|
||
marked `[TWO-CLIENT]`, deferrable to FA6's bot gate) are OWED.**
|
||
**FA5 CODE-COMPLETE 2026-08-12 (`7ed79eaf` code, this commit register/
|
||
gate-script/ledger) — implementer pass done: CF-1's corrected `0x001F`
|
||
subscription at retail's three arming points, the SF-7 per-relationship
|
||
monarch/patron gate, the vassal roster, and swear/break/kick with their
|
||
confirmations. The dual-lens review (§7) and the user's connected gate
|
||
(`docs/research/2026-08-12-campaign-fa-test-script.md` §FA5, several
|
||
steps `[TWO-CLIENT]`, deferrable to FA6) are OWED; the live-mount probe
|
||
extension has not been run against real DATs in this worktree (none
|
||
installed here).**
|
||
|
||
**Goal:** retail's social panel — the four-tab `gmPanelUI` member at host
|
||
slot `0x1000018F` (panel id **12**): **Friends / Allegiance / Fellowship /
|
||
Squelch** — with the Fellowship and Allegiance pages fully live
|
||
retail-faithful end-to-end (authored LayoutDescs, real wire, Runtime-owned
|
||
state, live consumers), the Friends and Squelch pages bound read-only to
|
||
the state Runtime already owns, and automated bot-vs-ACE gates for the
|
||
two-session flows. Campaign directive: the 2026-08-11 /goal (Campaign FA).
|
||
|
||
**Architecture:** one panel mounted exactly like Campaign OP's Options
|
||
panel (the OP3 recipe: `LayoutImporter.ImportInfos(dats, 0x2100006E,
|
||
0x1000018F)`, Type-8 tab host + `ActivateTabBehavior`, per-page scoped
|
||
controllers, `RetailPanelCatalog` id 12, F3/F4 keybinds). Fellowship and
|
||
allegiance state live in TWO new sibling Runtime owners under
|
||
`GameRuntime` per the Slice-J pattern. ~~(different lifetimes: fellowship is
|
||
session-scoped; allegiance survives reconnect behind a seed latch)~~
|
||
**[FA2 fix-round addendum, 2026-08-12: corrected — both owners are
|
||
session-scoped and clear at every generation reset; see D2's addendum
|
||
below for the full three-way evidence citation.]** Wire
|
||
parsers/builders live in `AcDream.Core.Net` beside the H.2 scaffolding
|
||
they connect, repair, or replace. Both graphical and headless hosts are
|
||
served by the single inbound wiring site.
|
||
|
||
---
|
||
|
||
## 1. Research base (committed; the spec's data appendix)
|
||
|
||
| Doc | What it pins |
|
||
|---|---|
|
||
| `docs/research/2026-08-11-fa-panel-structure.md` (lane A + coordinator addendum §10) | The social-panel mount (slot `0x1000018F`, id 12, four pages with `RegisterElementClass` identities), both element inventories, the row-template mechanism, the five confirmation dialogs, empty states, F3/F4 open path, the 16-slot host table, unknowns U3–U10 |
|
||
| `docs/research/2026-08-11-fa-fellowship-wire.md` (lane B) | 31-feature master table; per-message field order (golden-vector source); the byte-decoded `IsFull >= 9` and the x87 XP-share table (1.0…0.28, 2.8× cap); four pinned ACE divergences (share `.3`, 900 s vs 600 s lock, dual `shareLoot` encodings, zeroed cp/lum); the two latent acdream builder defects; the `0x00A6`-gates-vitals prerequisite; accept/decline = the shared confirmation triple (type 4); dead `0x01C9`/`0x01CA`; 8 missing WeenieError strings |
|
||
| `docs/research/2026-08-11-fa-allegiance-wire.md` (lane C) | 27 C→S + 5 S→C binary-verified messages; `AllegianceProfile`/`AllegianceHierarchy` layout with ELEVEN version gates; tree-assembly rules (orphan record ⇒ whole-message discard; sibling order REVERSES); ACE's deliberately-zeroed profile fields; the reuse verdict on `ParseAllegianceInfoResponse` and the DELETE verdict on `Core/Allegiance/AllegianceTree.cs`; the retail-faithful permanent dimming of the two allegiance notification bits |
|
||
| `docs/research/2026-08-11-fa-acdream-seams.md` (lane D) | The H.2 scaffolding inventory (11 event ids, 5 fellowship builders, swear/break, LogTextTypes, F3/F4 actions — all unreachable); the two-sibling-J-owner recommendation with the 8-edit template; the ONE inbound registration site; the six dimmed rows + their pinning tests; the panel-mount template; bot-gate requirements (second ACE account, role-discriminated policy, 7 commands, 7 assertions); `0x027C` already has a handler to share |
|
||
|
||
## 2. Design decisions (stated per the campaign directive; reactable at gates)
|
||
|
||
- **D1 — one social panel, all four tabs ship.** The DAT authors ONE
|
||
four-page panel; mounting only two pages would be an invented divergence.
|
||
Fellowship + Allegiance pages are this campaign's core (fully live).
|
||
Friends + Squelch pages bind READ-ONLY to `RuntimeCommunicationState`'s
|
||
existing friends/squelch owners (J4.1) for display; their mutation
|
||
actions (add/remove friend, squelch edit) are wired only if their wire
|
||
is already served by ACE and trivially pinned in-slice — otherwise the
|
||
action buttons are honest INERT with register rows (the OP3 precedent),
|
||
completed post-campaign.
|
||
- **D2 —** ~~two sibling Runtime owners. `RuntimeFellowshipState`
|
||
(session-scoped, cleared at reset like external-container) and
|
||
`RuntimeAllegianceState` (survives reconnect behind a `HasServerSeed`-
|
||
style latch).~~ **[FA2 fix-round addendum, 2026-08-12: shipped the
|
||
OPPOSITE finding for `RuntimeAllegianceState` — the "survives reconnect"
|
||
half is proven wrong by three-way evidence
|
||
(docs/research/2026-08-12-fa2-review-mechanism.md MUST-FIX 1):
|
||
(1) **the retail hook** — `ClientAllegianceSystem::
|
||
OnEndCharacterSession @0x00569FA0` tail-calls `AllegianceProfile::Clear`
|
||
at exactly the per-character-session boundary this owner's reset would
|
||
run at, mirroring the sibling `ClientFellowshipSystem::
|
||
OnEndCharacterSession @0x005690A0` Fellowship already honored — FA2's
|
||
fellowship half was byte-faithful, the allegiance half was the exact
|
||
inverse of retail's behavior at the same hook;
|
||
(2) **the cited precedent's actual behavior** —
|
||
`RuntimeCharacterOptionsState.ResetSession`
|
||
(`src/AcDream.Runtime/Gameplay/RuntimeCharacterState.cs:1007-1017`),
|
||
the very `HasServerSeed`-style latch this decision named as its
|
||
justification, CLEARS and re-latches on every reset; it does not
|
||
persist. Its own doc comment names the exact hazard this row then walked
|
||
into verbatim: "a stale seed surviving a session boundary could let a
|
||
flush ship the PRIOR character's words over the new one's";
|
||
(3) **the no-character-selector connect path** —
|
||
`SessionPlayerComposition.cs:1127-1132` constructs
|
||
`LiveSessionConnectOptions` with no character field, so
|
||
`LiveSessionController.StartCore` falls through to
|
||
`CharacterList.TrySelectFirstAvailable`: which character enters world at
|
||
generation N+1 is resolved fresh from a server-supplied list, and
|
||
nothing in `RuntimeAllegianceState` keyed on character identity. The
|
||
process model does NOT preclude a cross-character reset on the
|
||
graphical host, so a stale allegiance tree surviving reset could present
|
||
as the WRONG character's monarch/rank/vassal list.
|
||
**Corrected semantics:** `RuntimeAllegianceState` is now ALSO a
|
||
`RuntimeGenerationReset` stage (`RuntimeGenerationResetStage.Allegiance`)
|
||
with the identical clear-and-relatch shape as `RuntimeFellowshipState`
|
||
and the `RuntimeCharacterOptionsState` precedent — the profile clears
|
||
AND `HasServerSeed` drops to `false` at every generation reset, not just
|
||
at terminal `Dispose`. The `HasServerSeed` latch's remaining job is
|
||
exactly what its name says: distinguishing "no profile has arrived THIS
|
||
generation" from "genuinely no allegiance" WITHIN a session — it is a
|
||
within-session rendering gate, not a cross-reconnect persistence
|
||
mechanism. The two owners remain separate classes (not merged into one)
|
||
because fellowship and allegiance are independent retail systems with
|
||
independent wire families, not because their lifetimes differ anymore.]**
|
||
Lane D's 8-edit template per owner; consumers poll via
|
||
`Snapshot.Revision` — no `IRuntimeEventObserver` member is added (that
|
||
would break all five bot policies + the trace recorder).
|
||
- **D3 — the H.2 scaffolding is connected, repaired, or deleted — never
|
||
trusted.** Connect: the 11 `GameEventType` ids, `AllegianceRequests`
|
||
swear/break, both `LogTextType`s, F3/F4 actions. REPAIR: the fellowship
|
||
builders (lane B: `BuildFellowshipCreate` invents an `openness` field
|
||
ACE silently misreads as inverted `shareXP`; `BuildFellowshipUpdate`
|
||
mislabels `0x00A6`; the real openness action `0x0291` and leader-quit
|
||
`0x0290` are missing) with their wrong-shape tests re-pinned to the
|
||
verified field order. DELETE: `Core/Allegiance/AllegianceTree.cs` + its
|
||
tests (passup formula ~1000× wrong and locked in by test; tree model
|
||
contradicts the wire). REUSE: `ClientCommandResponses.
|
||
ParseAllegianceInfoResponse` extended with the eleven version gates —
|
||
no second profile parser.
|
||
- **D4 — `0x00A6` (panel-open declaration) is wired to real panel
|
||
visibility.** ACE streams fellow vitals ONLY while the panel is
|
||
declared open; without it the roster freezes at join. Sent on the
|
||
fellowship page's show/hide through the page-visibility seam OP3
|
||
already exposes.
|
||
- **D5 — parse defensively where ACE is internally inconsistent; display
|
||
retail's own numbers.** `shareLoot` is read as raw uint `!= 0` (ACE
|
||
encodes it two incompatible ways). The XP-share percentage column uses
|
||
retail's byte-decoded table (1.0/.75/.6/.55/.5/.45/.4/.35/.3111111/.28,
|
||
default 0.0) — one register row records the knowing display divergence
|
||
vs ACE's `.3`-at-nine-fellows server math.
|
||
- **D6 — confirmations ride the existing dialog seam.** Swear/accept-
|
||
swear/break/kick/fellow-invite are plain Confirmation dialogs
|
||
(`0x0274`/`0x0275`/`0x0276`, type 1 = allegiance, 4 = fellowship);
|
||
acdream's `RetailDialogFactory`/`GameplayConfirmationController`
|
||
already match the constants and its own comment names these types as
|
||
awaiting FA. The missing third message of the triple is completed in
|
||
FA1. ~~The invite-receive path consumes `IgnoreFellowshipRequests` /
|
||
`FellowshipAutoAcceptRequests` (auto-decline / auto-accept before the
|
||
dialog), giving those two dimmed rows their real consumers.~~ **[FA4
|
||
mechanism-review correction, 2026-08-12 (`913e35cd` MUST-FIX 2): retail's
|
||
client does NOT read either option bit on the invite/confirmation path —
|
||
byte-verified across `Handle_Character__ConfirmationRequest @0x005640A0`,
|
||
`RecvNotice_FellowshipRequest @0x00490880`, and `MakeFellowRequestDialog
|
||
@0x00490620` (whose ONLY guard is `m_fellowRequestContext`), plus a
|
||
whole-file sweep of both accessors: zero option reads anywhere on the
|
||
path. ACE filters both bits SERVER-SIDE. So there is NO client-side
|
||
auto-response: the fellow-invite dialog (type 4) always shows through the
|
||
generic `GameplayConfirmationController`, exactly as retail does. The
|
||
client-side intercept FA4 shipped is removed. `IgnoreFellowshipRequests`
|
||
defaults TRUE, so a client-side intercept would additionally have
|
||
silently swallowed real invites against any server that didn't filter —
|
||
a real hazard, not just a fidelity nit.]**
|
||
- **D7 — dimming resolves per lane-C/D verdicts.** Un-dim (with the AD-78
|
||
conformance-test flow) exactly the rows that gain consumers:
|
||
~~`IgnoreFellowshipRequests`, `FellowshipAutoAcceptRequests` (D6), and~~
|
||
the fellowship share rows consumed by the create flow/panel display.
|
||
`IgnoreAllegianceRequests` and `DisplayAllegianceLogonNotifications`
|
||
stay dimmed PERMANENTLY and faithfully — retail's own client has no
|
||
consumer for either (pure server-side filters); AD-78's register row
|
||
gains an addendum saying so. **[FA4 mechanism-review correction,
|
||
2026-08-12: following D6's correction, `IgnoreFellowshipRequests` and
|
||
`FellowshipAutoAcceptRequests` ALSO stay dimmed PERMANENTLY and
|
||
faithfully — they are pure server-side filters exactly like the two
|
||
allegiance bits, with no client consumer. FA4's un-dim of these two
|
||
REVERTS (dimmed count 31 → 33 of 50); only the fellowship SHARE rows the
|
||
create flow/panel genuinely reads stay un-dimmed. AD-78's addendum names
|
||
the corrected set.]** **[FA4 FIX-ROUND further correction, 2026-08-12
|
||
(mechanism review SF-8): "the fellowship SHARE rows... genuinely reads"
|
||
above overstated it — only `FellowshipShareXP` is actually READ back by
|
||
acdream (the Create-flow click sends it as the `shareXP` wire bit).
|
||
`FellowshipShareLoot`'s claimed consumer, "a second live checkbox
|
||
surface on the fellowship page," is not a consumer at all: nothing in
|
||
acdream ever reads the stored value back (`FormatStatsText` uses
|
||
`snapshot.ShareXp` only; the `0x00A2` Create builder carries `shareXP`
|
||
alone), and the live-DAT dump confirms its checkbox is a child of the
|
||
NOT-in-fellowship frame — invisible whenever you actually have a
|
||
fellowship to loot-share within. `FellowshipShareLoot` REVERTS to
|
||
dimmed too (dimmed count 33 → 34 of 50; net ONE row un-dimmed from the
|
||
pre-FA4 baseline of 35, not four). AD-78's addendum names this final
|
||
corrected set.]**
|
||
- **D8 — bot-vs-ACE gates are first-class.** A second ACE
|
||
account/character + a role-discriminated headless policy let one bot
|
||
recruit/swear at another, with the decisive assertion on the RECRUITED
|
||
bot's own snapshot. All six FA option names are already tier-1
|
||
allow-listed. **[User-provided 2026-08-12: the second account is
|
||
`testaccount2` / `testpassword2` on the same local ACE. RECRUIT REQUIRES
|
||
PROXIMITY — the recruiting character must be quite close to the recruit
|
||
target, so the FA6 bot gate must position the two bot characters near
|
||
each other (same landblock/adjacent) BEFORE the recruit command, or the
|
||
recruit fails; the FA4 §FA4 [TWO-CLIENT] recruit step notes the same for
|
||
the manual path.]**
|
||
- **D9 —** ~~the 8 missing fellowship WeenieError strings are added in FA1
|
||
(two are on ACE's live send paths today; all resolve from the DAT
|
||
string tables, never invented).~~ **[FA1 fix-round addendum, 2026-08-12:
|
||
shipped the OPPOSITE finding — `5f9aa16f` verified from primary source
|
||
(case-label walk + `else if` chain sweep + whole-file sweep + decimal
|
||
forms, `docs/research/2026-08-12-fa1-review-mechanism.md` §2(a)) that
|
||
retail's Sept-2013 client has NO display text for any of the 8 ids.
|
||
Inventing English for them would have been the exact failure mode the
|
||
WeenieError table's no-default-case rule exists to prevent. acdream's
|
||
existing silence for the two ACE actually sends
|
||
(`0x0417 FellowshipIgnoringRequests`, `0x04DB FellowshipDeclined`) is
|
||
already retail-faithful; no strings were added, and none are owed. The
|
||
conformance `[Theory]` at `WeenieErrorMessagesTests.cs:390-393` (8
|
||
`InlineData` rows, each asserting `Resolve()` returns null) is the
|
||
correct artifact in place of the string additions this decision
|
||
originally called for. No register row is owed either — the register
|
||
tracks acdream-vs-retail deviation, and this finding is that acdream
|
||
already matches retail.]**
|
||
|
||
## 3. Slice map
|
||
|
||
Dependencies: FA1 → FA2 → (FA3 → FA4/FA5) and FA2 → FA6; FA6 also needs
|
||
FA4 (recruit) + FA5 (swear). FA7 closes. Default execution order: FA1,
|
||
FA2, FA3, FA4, FA5, FA6, FA7.
|
||
|
||
| Slice | Contract (summary) | Gate |
|
||
|---|---|---|
|
||
| FA1 | Core.Net truth: repair fellowship builders + re-pin golden vectors; add `0x0290`/`0x0291`/`0x00A6`/`0x001F`; the allegiance action set the panel needs (swear/break/kick/info at minimum; the rest of the 27 as builders only where ACE serves them); parsers for the 11 S→C events incl. the profile version gates (extending `ParseAllegianceInfoResponse`) and the tree discard/reversal rules; complete the confirmation triple; ~~add the 8 WeenieError strings~~ **[FA1 fix-round addendum, 2026-08-12: shipped as CONFIRM-ABSENT instead — see D9's addendum. The 8 ids have no retail display text; acdream's silence is already faithful and a conformance test pins it.]**; DELETE `AllegianceTree` | automated only |
|
||
| FA2 | `RuntimeFellowshipState` + `RuntimeAllegianceState` (lane D's 8-edit template each); single-site inbound wiring serving BOTH hosts; typed commands/views; snapshot revisions; reset/reconnect semantics (~~session-scoped vs seed-latched~~ **[FA2 fix-round: both session-scoped — see D2's addendum]**); bot event surface via polling | automated only |
|
||
| FA3 | The social panel shell: mount slot `0x1000018F` (catalog id 12), F3/F4 handlers, fixture dump of the slot (closes U3/U4/U6/U7/U10), tab activation, all four pages' empty states, Friends/Squelch read-only binding to J4.1 state | user (connected) |
|
||
| FA4 | Fellowship page live: roster rows (adds `UiTemplateListBox` Flush/selection/row-instance-id — lane A sized this), the `0x00A6` show/hide declaration + vitals stream, create dialog (inline name field, shareXP), recruit/dismiss/quit/disband/leader + confirmations, share display per D5, option-row un-dims per D7 | user (connected) + bot |
|
||
| FA5 | Allegiance page live: ~~profile parse on show (`0x027B`)~~ **[FA2 re-review CF-1 correction, 2026-08-12: the DATA subscription is `0x001F AllegianceUpdateRequest(on)` — retail arms it at `PostInit`, `RecvNotice_PlayerDescReceived`, and the panel's visible branch, and `0x0020 AllegianceUpdate` is the sole owner-seeder after the FA2 MF-2 fix; `0x027B`'s response is text-only chat. FA5 wires `0x001F(on)` at those lifecycle points (off on hide per retail's visible branch) or the panel opens with chat text and no data]**; monarch/patron/self blocks, flat vassal list with the reversal rule honored, swear/break/kick + confirmations, ACE zeroed-field presentation scoped honestly (register row). **[FA3 fix-round addendum, 2026-08-12 (mechanism SF-7): FA3 shipped a COARSER empty-state gate than retail's own — both the monarch and patron blocks hide/show together on the single `RuntimeAllegianceSnapshot.HasProfile` flag. Retail's `gmAllegianceUI::UpdateMonarchData @0x00491B40` gates PER-RELATIONSHIP: the monarch block additionally hides when the monarch IS the viewer, and the patron block hides on the analogous test. FA5 MUST widen `SocialPanelController.Callbacks.AllegianceSnapshot` (today `Func<RuntimeAllegianceSnapshot>`) to reach the per-relationship data `IRuntimeAllegianceView.TryGetMonarch`/`TryGetPatron` already expose (`GameRuntimeGameplayViews.cs:200-204`) and implement the real gate — a monarch character must NOT see an empty, visible monarch block, and a patron-of-the-monarch character must NOT see an empty, visible patron block. `SocialAllegiancePageController.Tick` also reassigns `LinesProvider` UNCONDITIONALLY every frame today — FA5's real name population must change this method in the same commit or its content is overwritten the next frame.]** | user (connected) + bot |
|
||
| FA6 | Bot-vs-ACE automated gates: second-account config (USER PREREQUISITE), role-discriminated policy, the 7 Runtime commands + 7 named assertions (decisive: the recruited/sworn bot's own snapshot flips), reconnect-idempotence | automated + bot-vs-ACE run |
|
||
| FA7 | Closeout: register reconciliation, ISSUES sweep, CLAUDE.md Current-state paragraph, memory digest, the connected-gate test script (the campaign's stop condition) | user's final connected matrix |
|
||
|
||
## 4. What is explicitly OUT of scope
|
||
|
||
- Friends/Squelch mutation wire beyond D1's trivially-pinnable bar
|
||
(post-campaign completion; register rows).
|
||
- Allegiance officer/MOTD/banlist management UI — ACE zeroes or ignores
|
||
most of it (lane C §ACE-caveats); builders may exist from FA1 but no
|
||
panel surface beyond what the authored layout carries.
|
||
- XP passup FORMULAS client-side — `_cp_tithed` arrives pre-computed; the
|
||
deleted `AllegianceTree` transcription is not replaced.
|
||
- The `0x01C9`/`0x01CA` dead opcodes (COMDAT-folded no-ops in retail).
|
||
|
||
## 5. Verification discipline
|
||
|
||
Per commit: `dotnet build -c Release` + FULL Release suite green
|
||
(baseline at plan time: 13,103 / 4 skips / 0 failures at `28bef4e0`+the
|
||
gate-4 fixes). Golden byte vectors for every wire builder against the
|
||
lane-B/C field-order sections. Conformance pins for every panel
|
||
inventory and the tab table. The live-DAT probe harness
|
||
(`ACDREAM_PROBE_LIVE_MOUNT=1`) extended per slice — fixture-green alone
|
||
is NOT acceptance for anything mounted (the #372/#375/#378 lesson).
|
||
Register rows in the same commit as the deviation. No user-visible
|
||
invented English ever.
|
||
|
||
## 6. Campaign OP lessons imported as binding rules
|
||
|
||
From `claude-memory/project_settings_options_digest.md`'s DO-NOT-RETRY
|
||
table and the gate rounds: pass the string resolver to EVERY
|
||
`LayoutImporter.Build`; same-layout template-list prototypes are skipped
|
||
by the importer (verify for this layout's templates); activate the Type-8
|
||
host or pages stack; seed lazily-created fill-anchored children with
|
||
their parent extent; scoped `FindDescendant` for every id that repeats
|
||
across pages (lane A: `0x10000492` twice INSIDE the allegiance page);
|
||
popups get pointer priority via the UiRoot popup registration; straddling
|
||
rows clip (never whole-cull); BN literal-0 operands are byte-verified
|
||
before use.
|
||
|
||
## 7. Review protocol
|
||
|
||
Dual-lens Opus review per slice (mechanism-faithfulness ×
|
||
regression/blast-radius), fixes applied by the implementer; REJECT →
|
||
focused re-review; TWO failures → Fable fixes directly. Findings
|
||
persisted to a committed doc BEFORE any fixer/re-reviewer dispatch.
|
||
|
||
## 8. Process rules (binding, inherited from Campaign OP)
|
||
|
||
Max 3–4 agents in parallel INCLUDING children; every agent prompt
|
||
carries an explicit no-subagent clause; ONE builder/tester on the tree
|
||
at a time (read-only research may overlap); agents never launch the
|
||
graphical client (headless bot-vs-ACE runs are allowed); the user runs
|
||
connected gates; ledger placeholders anchored per-row; decomp claims
|
||
byte-verified against the PDB-paired binary; stalled agents resumed via
|
||
SendMessage before any redo; agent claims spot-verified at the seams
|
||
before anything builds on them.
|
||
|
||
## 9. Ledger
|
||
|
||
| Slice | Status | Commit(s) | Review | Gate |
|
||
|---|---|---|---|---|
|
||
| FA1 | **CLOSED 2026-08-12** — narrow re-review verdict CLOSED, no reopen (`96df892d`, §7 of the mechanism findings doc: all 7 mechanism dispositions re-derived in the diffs, all 6 blast dispositions spot-verified, suite claim corroborated on post-fix binaries); re-review carry-forward CF-1 (two further stale `AllegianceTree` citations in the seam map's FA2 guidance, `:128`/`:214`) closed by coordinator addenda in the same commit as this ledger update — FA2 was contracted not to start before that | `7be86f47` (builders), `6bedbc47` (parsers), `5f9aa16f` (WeenieError), `4281750b` (delete AllegianceTree); fix-round: `ed308087` (mechanism+blast MUST/SHOULD-FIX code+tests), this commit (register/plan/seams doc corrections) | mechanism `docs/research/2026-08-12-fa1-review-mechanism.md` (2 MUST-FIX, 5 SHOULD-FIX, all applied); blast `docs/research/2026-08-12-fa1-review-blast.md` (4 MUST-FIX, 5 SHOULD-FIX, all applied). **Live-surface note (blast SF-1):** FA1 changed the observable output of the ALREADY-LIVE `@allegiance info` command in two retail-faithful ways — vassal print order reversed (now pinned by a 3-vassal test through `FormatAllegianceInfoLines`) and a malformed tree now prints nothing instead of a partial roster (now pinned at the `GameEventWiring` layer) — not a "purely unwired" slice. | automated: Release build + full suite green throughout. **Reconciled totals (blast MF-4):** the ledger's own prior figure (13,149/4/0) is CONFIRMED correct by direct measurement at the pre-fix-round tip `bc693728` (13,153 total = 4+916+1559+15+130+119+4856+877+4677 across all 9 test projects); the campaign-start baseline in §5 is 13,103/4/0, and the diff-verified FA1 delta is **+58 added / −9 deleted (deleted `AllegianceTreeTests.cs`) = net +49**, i.e. 13,103+49=13,152 — one test of drift against the directly-measured 13,153/13,149 baseline, attributed to the §5 baseline being captured at a different point in git history than the FA1 diff's actual parent, not a further miscount. This fix round adds a further **+9 tests** (2 golden vectors for the new `0x001F` builder, 1 D5 `<<1` pin at the `0x02C0` site, 4 MF-1/SF-1 boundary tests, 2 blast SF-1 live-surface pins) — **final: 13,158 passed / 4 skipped / 0 failed (13,162 total), directly measured.** |
|
||
| FA2 | **FIX-ROUND CLOSED 2026-08-12** — both reviews' MUST-FIX/SHOULD-FIX findings applied; automated gate only, per contract | `RuntimeFellowshipState`/`RuntimeAllegianceState` (2 new sibling J-owners, `src/AcDream.Runtime/Gameplay/`), the full 8-edit template applied twice (`GameRuntime.cs`, `RuntimeGenerationReset.cs`, `RuntimeGameplayOwnership.cs`/`RuntimeSimulationOwnership.cs`, `GameRuntimeGameplayViews.cs`, `GameRuntimeCommands.cs`, `GameRuntimeEvents.cs`, `GameRuntimeViews.cs`), ~~12 new `WorldSession.Send*` wrappers, 15 new `GameEventWiring.WireAll` delegate holes~~ **[FA2 fix-round addendum, 2026-08-12 (docs/research/2026-08-12-fa2-review-blast.md SHOULD-FIX 3): both counts were wrong. `WorldSession.cs:2318-2404` adds **11** new `Send*` wrappers (7 fellowship + 4 allegiance) — `SendAllegianceInfoRequest` pre-dates FA2; the **12** figure belongs to a different count, `cced83b4`'s `*RuntimeCmd` records / `LiveSessionCommandBindings` send delegates. `GameEventWiring.cs:107-120` adds **10** delegate holes (9 new + the `0x027C` fold), not 15 — matching the "11 S→C events" the seam doc's §2.3 table names, of which 2 (`0x01C9`/`0x01CA`) are correctly left unregistered (dead COMDAT-fold no-ops) and 1 (`0x027C`) was already registered pre-FA2.]** registered at the single site (`LiveSessionEventRouter.cs`), both `LiveSocialSessionBindings` construction sites updated (`LiveSessionRuntimeFactory.cs`, `HeadlessSessionHost.cs`), `IRuntimeFellowshipCommands`/`IRuntimeAllegianceCommands` implemented on both host command adapters (`DirectGameRuntimeCommandAdapter`, `CurrentGameRuntimeCommandAdapter` + its `LiveSessionCommandRouter`/`LiveSessionCommandBindings` App-bus plumbing), divergence register rows TS-81 (filed) + TS-80 (narrowed); fix-round: `4272ad0e` (mechanism MUST-FIX 1/2 + blast MUST-FIX 1/2 + blast SF-1 + mechanism SF-2 — allegiance reset semantics, 0x027C stops seeding, teardown-ledger off-by-one, conditional delegate holes, disposed-checks-inside-lock), `ded23067` (mechanism SF-3/4/5/6 + blast SF-4/5/7 — RecalculateEvenXPSplitting, locked/departed admission gate, AllegianceProfileLookups reuse, non-null checkpoint defaults, router self/other-quit test, ResetSession disposed-guard parity, GetVassals allocation doc), this commit (register/plan/seams doc corrections) | mechanism `docs/research/2026-08-12-fa2-review-mechanism.md` (2 MUST-FIX, 6 SHOULD-FIX, all applied); blast `docs/research/2026-08-12-fa2-review-blast.md` (2 MUST-FIX, 7 SHOULD-FIX, all applied). **Allegiance register-row re-evaluation (blast SF-6):** the design blast SF-6 asked to be either dropped or given a register row is now fully retired by MF-1's fix — `RuntimeAllegianceState` clears at every generation reset exactly like `RuntimeFellowshipState` and exactly like retail's `OnEndCharacterSession` hook, so there is no remaining acdream-vs-retail deviation for allegiance persistence to name a row for. No register row added; conclusion recorded here per the fix-round contract. | automated: Release build + full suite green throughout. **Pre-fix-round baseline 13,201/4/0 (13,205 total, measured at `12053e61` by the blast review) → fix-round 13,215/4/0 (13,219 total), +14 tests, arithmetic exact:** `RuntimeAllegianceStateTests.cs` net +2 (−1 deleted `ApplyInfoResponseSelf_...`, +3 new `ResetSession_*`), `RuntimeFellowshipStateTests.cs` +10 (1 `ResetSession_AfterDispose_...` + 3 `[Theory]` cases for `RecalculateEvenXPSplitting` + 1 `ShareXp`-off case + 1 full-update-never-recomputes case + 4 locked/departed admission-gate cases), `GameRuntimeTests.cs` +1 (`CompletedTeardownStagesAccumulatesExactlyOneFlagPerStage`), `Session/LiveSessionEventRouterTests.cs` +1 (`FellowshipQuit_RoutesSelfGuidToClearAndOtherGuidToRemove`); `RuntimeGenerationResetTests.cs` and `GameEventWiringTests.cs` each renamed one test in place (net 0); `GameRuntimeContractTests.cs` gained two trailing constructor arguments at its sole positional `RuntimeStateCheckpoint` site (compile-fix only, no new test). |
|
||
| FA3 | **FIX-ROUND CLOSED 2026-08-12** — both reviews' MUST-FIX/SHOULD-FIX/NIT findings applied; still owes the user's connected gate (script: `docs/research/2026-08-12-campaign-fa-test-script.md`, itself corrected by this fix round — see MF-1/MF-2 below). | `0a9ca2f1` (`SocialPanelController` + 4 per-page controllers + `SocialPanelRowText`, `UiTemplateListBox.Flush`, `RetailPanelCatalog.SocialPanel`/`WindowNames.SocialPanel`, `RetailUiRuntime` Mount/Tick/F3/F4 wiring, `InteractionRetainedUiComposition`'s `SocialRuntimeBindings`, register row AD-79); `74c3d85d` (fixture generator entry + committed `social_panel_2100006E_1000018F.json`, `SocialPanelLiveMountProbeTests`, `SocialPanelControllerTests`, `RetailPanelCatalogTests` additions, `FixtureLoader` additions); `b6a25110`/`d7e1cffd` (gate script + ledger + research addendum). Fix-round: `9afa05b5` (blast MF-1 scrollbar wiring + blast SF-2/SF-3 rebuild discipline/revision-latch ordering + mechanism SF-1 F3/F4 relabel + mechanism SF-8 disposed guard, code+tests), `35c40a9b` (mechanism SF-2/blast SF-4 allegiance per-frame allocation hoist + mechanism SF-7 coarser-gate FA5 acceptance line), `ae772709` (mechanism SF-4 fellowship checkbox count + mechanism SF-9 row-text doc + blast SF-5 Flush doc + mechanism SF-3 probe assertions), `a5553904` (mechanism MF-1/MF-2 gate-script corrections + mechanism SF-4 gate-script hedge fix + blast N-8 two new gate steps + blast SF-6 #383 timing correction + blast SF-7 bold-marker fix + mechanism SF-1 research-doc U11), this commit (ledger update). | mechanism `docs/research/2026-08-12-fa3-review-mechanism.md` (2 MUST-FIX, 9 SHOULD-FIX, all applied); blast `docs/research/2026-08-12-fa3-review-blast.md` (1 MUST-FIX, 6 SHOULD-FIX, 1 NIT, all applied). **Live-DAT finding (corrects the coordinator addendum, §10):** the real authored `0x2E` tab table pairs button `0x1000028C` ("Allegiance" caption) with page `0x10000291` as the DEFAULT entry — NOT Friends, which the addendum's x-order guess implied; each page's own `P0x57` independently corroborates (Allegiance page `P0x57=0x1000000E` == `ToggleAllegiancePanel`/F3, Fellowship page `P0x57=0x1000000F` == `ToggleFellowshipPanel`/F4). See `SocialPanelController`'s class doc for the full corrected table. **Unrelated fixture drift caught and reverted:** the `ACDREAM_REGENERATE_UI_FIXTURES=1` run used to produce the new fixture also silently regenerated `keyboard_config_21000009.json` and `options_2100002B.json` with large diffs against this machine's currently-installed DAT (pre-existing environment drift, not FA3-caused) — both were `git checkout`'d back to HEAD before committing; only the new fixture is included; the fix round's blast SF-6 correction narrows this drift to exactly those two OP-era fixtures (git timestamps put the drift window at ~18-21h, same day, not "days ago" as originally filed) and adds the mechanism reviewer's independent no-drift confirmation for the new social-panel fixture itself. Friends/Squelch action buttons are honest INERT per D1 (register row AD-79, one row covering both pages' seven controls, not one per button — now cited BY NAME in both page controllers' own doc comments, mechanism SF-6). The fix round's two connected-gate corrections (mechanism MF-1/MF-2) matter most for the still-owed user gate: the script previously carried a REFUTED tab x-order into step 1/9/10 (priming the user to report the correct Allegiance-left-most layout as wrong) and sent the user to a `@allegiance info`-reveals-the-panel trigger that cannot fire post-FA2 (told to report it as a bug when it correctly did nothing) — both are corrected to state the true FA3 expectation. | automated: Release build green throughout; full solution suite green at every commit. **Pre-fix-round baseline 13,233/4/0 (13,237 total) → fix-round 13,238/4/0 (13,242 total), +5 tests, arithmetic exact:** `SocialPanelControllerTests.cs` +5 (`Friends_ScrollbarModel_IsWiredToListBoxScroll`, `Squelch_ScrollbarModel_IsWiredToListBoxScroll`, `Friends_LongRoster_IsReachableViaScrollbar`, `Squelch_LongRoster_IsReachableViaScrollbar`, `Friends_RevisionBumpWhileHidden_DoesNotRebuild_ButRebuildsOnShow`); `SocialPanelLiveMountProbeTests.cs` gained two new assertions inside its existing single env-gated `[Fact]` (net 0 new test count — trivially passes without `ACDREAM_PROBE_LIVE_MOUNT=1`, same as before); two existing `SocialPanelControllerTests.cs` tests were extended in place (`FriendsAndSquelchActionButtons_AreClickable_ButHaveNoHandler` now also covers `0x1000052C`; `Friends_ReactsToRevisionChange_OnTick` now calls `OnShown()` to match the new visibility gate) — net 0 new tests from those two. Directly measured per-project: Cli 4, UI.Abstractions 916, Runtime 1607, Bake 15, Content 130, Headless 119, App 4876/3 skip, Core.Net 895, Core 4676/1 skip — sum 13,238 passed / 4 skipped / 0 failed. |
|
||
| FA4 | **CODE-CLOSED 2026-08-12, connected gate OWED** — both dual-lens reviews' items applied (5 MUST-FIX + 9 SHOULD-FIX + 4 NIT mechanism; 1 SHOULD-FIX blast), narrow re-review CLOSED with ONE REOPEN (MF-3 0x00A6 placed pre-world), coordinator re-fix `04161def` (latch-advances-only-on-Accepted + RedeclareAfterWorldEntry wired to the post-world EnteredWorld seam; RED-verified regression pins), re-review of the re-fix CLOSED `06dbf1cf` (seam ordering traced: RestoreLayout fires after _inWorld=true + command activation). Final full suite 13,286/4/0. The user's connected gate (several steps `[TWO-CLIENT]`, deferrable to FA6) remains owed. | Original: `357d2032` (Runtime: `IRuntimeFellowshipView.GetMembers`, `SelectionChangeSource.Social`, +4 `RuntimeFellowshipStateTests`); `5bdd0528` (App: `SocialFellowshipPageController` roster/D4/create/actions/checkboxes rewrite, `RowTemplateResolver` extraction, `UiTemplateListBox.FlushPreservingScroll`, `RetailUiRuntime` D6 intercept + `MountSocialPanel` rewiring, Friends/Squelch scrollbar carry-forward 3, `CharacterOptionsPageController` D7 un-dim, extended `SocialPanelLiveMountProbeTests`, +30 tests); `38f08314` (register rows AD-80/AD-81 + AD-78 addendum, gate script §FA4, ledger). **Fix round** (`docs/research/2026-08-12-fa4-review-mechanism.md` + `-blast.md`): `290f9b58` (MUST-FIX 2 — delete `TryAutoRespondToFellowshipInvite`; type-4 dialog test); `5499f058` (MUST-FIX 1 D5 truncation + MUST-FIX 4 world→panel selection sync + SF-1/SF-2/SF-3/N-0/N-1/N-2/N-3, all in `SocialFellowshipPageController.cs`); `df000306` (MUST-FIX 3 panel-level 0x00A6 reconnect re-arm + SF-4 `Dispose` unsubscribe, `SocialPanelController.cs`); `300d8189` (D6/D7/SF-8 dimming reversal — `IgnoreFellowshipRequests`/`FellowshipAutoAcceptRequests`/`FellowshipShareLoot` revert to `StoreOnly`, only `FellowshipShareXP` stays `Live`); `55b17e15` (SF-6 live-mount-probe assertions); `1d743277` (register AD-82/AD-83 + AD-78 count correction, gate-script SF-7/MUST-FIX-1/3/4/2 corrections, plan D7 SF-8 addendum); this commit (ledger). | owed | automated: Release build green throughout; full solution suite green at every commit, both original and fix round. **Original baseline 13,238/4/0 (13,242 total) → FA4-original 13,272/4/0 (13,276 total), +34 tests.** **Fix-round delta: +13 tests, 0 deletions** (the D6 intercept had no dedicated tests to remove) — `SocialFellowshipPageControllerTests.cs` +8 (2 new `[InlineData]` cases on the existing D5 theory for 6/8-fellow truncation, +6 new `[Fact]`: member-leaves/selection-clear, row-build-failure-doesn't-retry, Recruit-reads-membership, world-selects-fellow, world-selects-non-fellow-keeps-selection, optimistic-caption); `SocialPanelControllerTests.cs` +4 (`[Fact]`: D4 panel-level conjunction, reconnect re-arms, reconnect stays silent when not open, Dispose unsubscribes); `GameplayConfirmationControllerTests.cs` +1 (`[Fact]`: type-4 dialog verbatim + accept). `CharacterOptionsPageControllerTests.cs` (dimming set content changed, count 31/19 → 34/16, net 0 new tests) and `SocialPanelLiveMountProbeTests.cs` (assertions added inside its existing env-gated `[Fact]`, net 0 new tests) extended in place. **Final: 13,285 passed / 4 skipped / 0 failed (13,289 total), directly measured** (13,272 + 13 = 13,285; 4 skips unchanged; arithmetic exact). Per-finding disposition: MUST-FIX 1/2/3/4/5 fixed; mechanism SHOULD-FIX 1-9 and NIT N-0/N-1/N-2/N-3 all applied; blast SHOULD-FIX 1 (AD-78 stale count) fixed. Dimmed-row count: 35 (pre-FA4) → 31 (FA4-original, incorrect) → **34 of 50 (fix-round final, correct)** / 16 live — net ONE row (`FellowshipShareXP`) un-dimmed from the pre-FA4 baseline, not four.** `RuntimeFellowshipStateTests.cs` +4 (`GetMembers_*`); `RowTemplateResolverTests.cs` +3; `UiTemplateListBoxFlushPreservingScrollTests.cs` +4; `SocialFellowshipPageControllerTests.cs` +23 (new file — roster build/diff/rebuild, D5 formatting, create-flow gating, member-action wiring, button-enable rules, checkbox wiring, D4 idempotency). `CharacterOptionsPageControllerTests.cs`/`SocialPanelControllerTests.cs`/`SocialPanelLiveMountProbeTests.cs` extended in place (net 0 new tests from those three — one existing assertion's expected counts changed, one probe test gained assertions inside its existing single env-gated `[Fact]`). **Live-DAT verification (`ACDREAM_PROBE_LIVE_MOUNT=1`, real installed DATs, not a fixture):** the fellowship name-entry field builds as `UiField` (Editable=1 confirmed authored), all 11 buttons/checkboxes resolve as `UiButton`, the ListBox's sole template pair (`0x21000030`/`0x10000281`) resolves through the production `RowTemplateResolver` with all 5 checked row fields at the right widget types, every checkbox label/tooltip resolves to real retail English (`ID_PlayerOption_*` in `0x23000003`), the Open/Close captions resolve to `"Open"`/`"Close"` (`ID_Fellowship_*` in `0x23000001`), and a full production-path `SocialFellowshipPageController.Bind()` against the live layout emits zero "not found" console warnings. **Structural finding (not a bug, a design confirmation):** the live dump shows the name field, Create button, and all four checkboxes are children of `0x1000026B` (the NOT-in-fellowship frame) — retail's Create-flow controls are visible ONLY while you have no fellowship, never simultaneously with the roster; the existing empty/full frame-visibility swap already produces this for free (child visibility cascades from an invisible ancestor — `UiElement.cs:486/540/573/586`), so no extra gating code was needed. **Contradictions/deferrals:** (1) the retail `StringInfo` variable-substitution engine (`StringInfo::InqString` → `StringTableMetaLanguage::UnescapeString`) is unresolved in this campaign's decomp scope — row/stats/vitals text renders as numeric composites, not retail's exact sentence (AD-81); (2) `ACCharGenData::FormatName` is unported — the Create flow sends the raw typed name, not retail's canonicalized form (also AD-81); (3) the D5 percentage table's proportional (non-even-split) branch needs a per-level XP-to-next-level table acdream does not have — that branch omits the percentage rather than computing one (documented in `FormatStatsText`'s own doc, not a separate register row); (4) the Recruit button's enable rule does not gate on "target is a player" (retail does) — acdream's UI layer has no cheap classification for this, and the server refuses a non-player target the same way retail's own click-handler silently no-ops, so this is a superset-of-retail enable rule, not a wire-behavior gap. **[FIX-ROUND CORRECTION: item (4)'s "inline comment, not a register row" disposition was itself the wrong call under the register rule (MUST-FIX 5) — filed as register row AD-83 in the fix round.]** |
|
||
| FA5 | **CODE-CLOSED 2026-08-12, connected gate OWED** — dual-lens review APPROVE-WITH-FIXES (mechanism `f12aefe9`: 1 LOW SHOULD-FIX + nits, **live-mount probe RAN + PASSED against real installed DATs** incl. the scoped doubled-`0x10000492` `NotSame` check — the anti-fixture-green safeguard the implementer couldn't run; blast `b6c4a4fa`: 1 doc-only SHOULD-FIX + 2 nits, all structural axes clean) → coordinator SF-1 fix `eac28dc1` (removed the invented offline-vassal name-grey — retail's cue is the authored `0x100004AA` marker alone; pinned by `Allegiance_OfflineCue_IsTheMarkerOnly_NameStaysWhite`; AD-82 addendum + AD-86 count corrected; the blast doc-only baseline off-by-one fixed in this row below). Full suite **13,297/4/0**. The user's connected gate (several steps `[TWO-CLIENT]`, deferrable to FA6) remains owed. **[Original implementer pass:]** The allegiance page is fully live against FA1's parser and FA2's already-shipped `RuntimeAllegianceState`/`IRuntimeAllegianceCommands` (no Runtime-layer changes needed this slice — FA2 had already built `SetUpdateSubscription`, `Swear`, `Break`, `Kick`, and the full `IRuntimeAllegianceView` accessor set). CF-1's corrected `0x001F` subscription is wired at all three retail arming points (`Bind`'s PostInit attempt, the post-world `EnteredWorld` seam via `RedeclareAfterWorldEntry` — UNCONDITIONAL, explicitly NOT edge-triggered, to avoid repeating FA4's MF-3-REOPEN bug class — and the visible-branch toggle via `SetPageVisible`, folded into `SocialPanelController`'s existing window-shown+active-tab conjunction). Monarch/patron/self blocks implement fix-round SF-7's per-relationship gate (fresh decompile of `UpdatePlayerData`/`UpdateMonarchData`/`UpdatePatronData` pinned every field source: `0x10000251` is the ALLEGIANCE's own name not the viewer's, followers are `TotalVassals`/`TotalMembers-1` straight off the wire, `0x10000492`'s doubled instances are the viewer's own `CpTithed`). The vassal roster reuses FA4's `FlushPreservingScroll` diff pattern in the wire's already-reversed order. Swear/Break/Kick each open a local confirmation dialog before sending (Swear targets the WORLD selection via the same `ClientObjectTable` name resolver `ToolbarRuntimeBindings.ResolveName` uses; Break targets the current patron; Kick targets the panel-local selected vassal row, no world-selection sync, lane A §6.2); the server-driven "accept incoming swear" (`ConfirmationType` 1) needed no new code since `GameplayConfirmationController` already handles every type generically — a new test verifies this explicitly rather than assuming FA4's blast review's claim. Four new register rows: AD-84 (Swear's missing IsPlayer gate, mirrors AD-83), AD-85 (the unported `StringInfo` gap extended to Allegiance's numeric fields + three confirmation dialogs, mirrors AD-81), AD-86 (ACE's seven zeroed profile fields, dropped past acdream's own parse layer to match retail's own no-widget presentation), and an addendum bracket on AD-82 (the vassal-row click-target limitation recurs, but NOT its invented tint colors or its Fellowship-only world-sync). | `7ed79eaf` (code: Runtime command wrapper (`InteractionUiRuntimeSources.cs`), `SocialRuntimeBindings`/`MountSocialPanel` widening (`RetailUiRuntime.cs`), the Allegiance projection delegates (`InteractionRetainedUiComposition.cs`), `SocialPanelController`'s CF-1 wiring, the full `SocialAllegiancePageController.cs` rewrite, plus 10 new `SocialPanelControllerTests.cs` tests, 1 new `GameplayConfirmationControllerTests.cs` type-1 test, and the `SocialPanelLiveMountProbeTests.cs` production-mount extension); this commit (register rows AD-84/AD-85/AD-86 + AD-82 addendum, gate-script §FA5, ledger) | owed | automated: Release build green throughout; full solution suite green. **Baseline 13,286/4/0 (FA4's TRUE close after the MF-3 re-fix `04161def` added the widget test — blast SF-1 corrected the FA5 pass's "13,285/+11" citation, which used FA4's pre-re-fix intermediate figure) → FA5 implementer pass 13,296/4/0, +10 tests net** (`SocialPanelControllerTests.cs` nets +9: the old coarse-gate `Allegiance_HasProfile_ShowsBothBlocks` is REMOVED and replaced by 4 SF-7 per-relationship tests, 1 roster-population test, 3 swear/break/kick wiring tests, and 2 CF-1 subscription-arming tests — 10 added, 1 removed; `GameplayConfirmationControllerTests.cs` +1 the type-1 verification test; `SocialPanelLiveMountProbeTests.cs` extended in place, net 0). **Coordinator SF-1 fix `eac28dc1`: +1 test** (`Allegiance_OfflineCue_IsTheMarkerOnly_NameStaysWhite`; `OfflineNameColor` removed, no test deletion) → **final 13,297/4/0, directly measured.** **Live-DAT verification RAN + PASSED at the mechanism review** (`ACDREAM_PROBE_LIVE_MOUNT=1`, real installed DATs, `Passed:1 Failed:0`): the scoped `0x10000492` dual-resolution `NotSame`, `passupCount==2`, the vassal row template/checkbox/five confirmation-label strings resolving non-empty, and a full production `SocialAllegiancePageController.Bind()` with zero "not found" — the safeguard the implementer's own worktree lacked the DATs to run. **Contradictions/deferrals:** (1) the self-rank field (`0x10000253`) retail-sources from a LIVE buffed-quality query (`CBaseQualities::InqInt(qualities, 0x1e)`, i.e. `PropertyInt.AllegianceRank`) plus a 20-table title lookup (`AllegianceData::GetTitle`) neither of which this controller has a seam for — substitutes the numerically-equivalent `RuntimeAllegianceSnapshot.Rank` from the same `0x0020` message, rendered bare (documented in the class doc, not a separate register row since it is a data-source substitution rather than a presentation gap); (2) "your follower count" (`0x10000252`) was NOT explicitly formula-cited in the panel-structure research doc — a targeted fresh decompile of `UpdatePlayerData` (`pseudo_c:157629`) confirmed `_total_vassals` directly, resolving the ambiguity from primary source rather than inferring it. | `docs/research/2026-08-12-campaign-fa-test-script.md` §FA5 (new, mirrors §FA4's structure: CF-1 subscription steps, the SF-7 per-relationship steps, vassal-list steps, swear/break/kick with their confirmations, `[TWO-CLIENT]` tags deferrable to FA6, ACE-zeroed-field honesty, full "what to report"/"explicitly not in scope" lists) |
|
||
| FA6 | **FELLOWSHIP AUTOMATED GATE PASSED LIVE 2026-08-12; ALLEGIANCE BOT GATE DEFERRED** — six live runs against local ACE (`testaccount`/`+Acdream` as Leader, `testaccount2`/`+Horan` as Recruit). The decisive two-session fellowship assertion (the RECRUITED bot's own `RuntimeFellowshipState` — a separate process's canonical Runtime owner, not the Leader's local echo — flipping `IsInFellowship=true`, `MemberCount=2`, `LeaderGuid=0x5000000A`) passed identically in five of the six live runs (1, 3, 4, 5, 6 — every run except run 2, which hit the wrong-target bug below before the fix); the D4 panel-open declaration and recruit-vitals presence (`maxHealth=201`) were confirmed alongside it. Two real live-run findings were fixed in-slice: run 1's fellowship pass then stalled waiting on the allegiance swear, which investigation traced to headless hosts dropping every server-driven confirmation (`OnConfirmationRequest: null`), fixed by wiring a single-slot confirmation-relay latch on `HeadlessSessionHost`; run 2 found a stray third player character on the shared ACE dev instance (`+Je`, `0x50000001`) could be nearer than the actual Recruit bot after `@teleallto`, fixed by `RuntimeFriendlyTargetQuery.FindPlayerByName` (name-matched via `FellowshipAllegianceGateCoordinator`, which carries the Recruit bot's own discovered name — the D8 "discover it live" mechanism) replacing the ambiguous "nearest any player" query. The ALLEGIANCE swear never completes over the wire: ACE returns nothing at all to `Event_SwearAllegiance (0x001D)` — no `0x0274` confirmation, no `0x0020`, no error — confirmed at 0.005 m separation (run6's distance diagnostic), ruling out retail's 2.0 m swear-distance gate. Filed `docs/ISSUES.md` #384 and register row AD-87; `AllegianceGateEnabled` (both policy classes) is `false` by default, keeping every allegiance stage (Leader's `WaitForVassal`; Recruit's `Swear`/`WaitSwornSeed`/`Break`/`WaitBrokenSeed`) written, wired, and ready to re-enable once #384 closes. Per user direction, no further live iteration on the allegiance blocker this slice — deferred to the user's own connected gate (manual swear between two graphical clients). | `6b8e29cd` (`RuntimeFriendlyTargetQuery` + 4 tests), `28255890` (role-discriminated policy + the two-bot gate policy pair), `11641597` (confirmation relay, targeting the LEADER per the wire research's "Target (would-be patron)" step 4 — independently re-verified against `docs/research/2026-08-11-fa-allegiance-wire.md` §1.3 primary source during this slice, which settles that the confirmation belongs on the patron's client, not the swearer's), `ab79b91f` (name-matched proximity + `FindPlayerByName` + 3 tests), `5244e46d` (fellowship-only finalization: `AllegianceGateEnabled` flag, permanent diagnostics), `022b1844` (docs: #384 + AD-87) | none (automated + bot-vs-ACE only, per the plan's own Gate column) | automated + bot-vs-ACE run: `dotnet build -c Release` and the full solution suite green at every commit (final **13,304 passed / 4 skipped / 0 failed**, baseline 13,297/4/0 + 7 new `RuntimeFriendlyTargetQueryTests`). Six live bot-vs-ACE runs against local ACE `127.0.0.1:9000`; every session ended with ACE-confirmed graceful per-character logout (`[session] graceful logout confirmed`) except run 1's very first `idle`-policy probe of `testaccount2`, which an external `timeout` wrapper hard-killed before this slice adopted self-terminating policy runs — the ~3-minute ACE stale-session wait that followed is the only deviation from clean teardown across the whole slice. |
|
||
| FA7 | — | | | |
|