acdream/docs/plans/2026-08-11-fellowship-allegiance-campaign.md
Erik 511ba6e5d4 docs: FA1 review round -- register repoint, seams corrections, plan reconciliation
Applies the documentation-only MUST-FIX items from the blast review
(docs/research/2026-08-12-fa1-review-blast.md), plus mechanism SF-4:

Blast MF-1 / mechanism SF-4: register row AP-90
(retail-divergence-register.md) cited the deleted AllegianceTree class as
its evidence. Re-pointed to ClientCommandResponses.AllegianceProfileLookups
and the fellowship parsers FA1 added -- the deviation itself (radar
relationship state undelivered at runtime) is unchanged and NOT retired,
since FA2 hasn't wired a live owner yet.

Blast MF-2: corrected four falsified statements in the lane D research doc
(fa-acdream-seams.md), each marked with a dated, clearly-struck FA1
fix-round addendum rather than silently rewritten (it is a committed
research record):
  - :791 "wrapping existing AllegianceTree" -- class deleted; re-pointed to
    AllegianceProfileLookups.
  - :666/:672 `commands.Fellowship.SetOpen -> BuildFellowshipUpdate` -- that
    builder no longer exists; its renamed successor is panel visibility,
    not openness, and using it here would re-introduce the exact semantic
    bug FA1 fixed. Re-pointed to BuildFellowshipChangeOpenness (0x0291).
  - :429/:668 `BuildFellowshipCreate(seq, name, openness, shareXp)` -- the
    builder is now 3-arg; there is no wire openness field.
  - :854 open question 8 (trailing-pad rule) -- ANSWERED by FA1 (VC-3),
    closed with the answer instead of left open for re-derivation.

Blast MF-3: plan decision D9 and the FA1 slice-map row both asserted "the 8
missing fellowship WeenieError strings are added in FA1" -- FA1 shipped the
opposite, verified finding (no retail display text exists for any of the
8 ids). Both struck and annotated with the actual outcome.

Blast MF-4: reconciled the ledger's internally-inconsistent test-total row.
Direct measurement at the pre-fix-round tip (bc693728, stashed/restored
during this session to isolate it) confirms 13,149 passed / 4 skipped / 0
failed (13,153 total) -- the ledger's own prior number was actually
correct; the "baseline 13,103" and "net +50" framing next to it did not
reconcile with each other or with the diff-verified delta (+58 added / -9
deleted = net +49, one test of drift attributed to a different baseline
commit, not a further miscount). Also records this session's own +9 tests
and the blast SF-1 live-surface note (FA1 changed observable @allegiance
info output, not a purely-unwired slice).

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

202 lines
16 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: 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 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). 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 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 | 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 | — | | | |