# 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: ACTIVE — planned 2026-08-11. No slices landed yet.** **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). 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). 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. - **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. - **D8 — bot-vs-ACE gates are first-class.** A second ACE account/character (user-provided when FA6 arrives) + 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. - **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); 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`), monarch/patron/self blocks, flat vassal list with the reversal rule honored, swear/break/kick + confirmations, ACE zeroed-field presentation scoped honestly (register row) | 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 | CODE-COMPLETE 2026-08-12; dual-lens Opus review APPROVE-WITH-FIXES both lenses; fix-round applied 2026-08-12 | `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 | — | | | | | FA3 | — | | | | | FA4 | — | | | | | FA5 | — | | | | | FA6 | — | | | | | FA7 | — | | | |