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

16 KiB
Raw Blame History

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 LogTextTypes, 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