acdream/docs/plans/2026-08-11-fellowship-allegiance-campaign.md
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

334 lines
52 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 U3U10 |
| `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 34 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 | — | | | |