diff --git a/docs/plans/2026-08-11-fellowship-allegiance-campaign.md b/docs/plans/2026-08-11-fellowship-allegiance-campaign.md index 09a57609..3357f7db 100644 --- a/docs/plans/2026-08-11-fellowship-allegiance-campaign.md +++ b/docs/plans/2026-08-11-fellowship-allegiance-campaign.md @@ -301,7 +301,7 @@ before anything builds on them. | 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-COMPLETE 2026-08-12** — implementer pass done; dual-lens review and the user's connected gate (several steps `[TWO-CLIENT]`, deferrable to FA6) are owed | `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); this commit (register rows AD-80/AD-81 + AD-78 addendum, gate script §FA4, ledger) | owed | automated: Release build green throughout; full solution suite green at every commit. **Baseline 13,238/4/0 (13,242 total) → FA4 13,272/4/0 (13,276 total), +34 tests, arithmetic exact:** `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 (inline comment, not a register row). | +| FA4 | **FIX-ROUND CODE-COMPLETE 2026-08-12** — both dual-lens reviews' MUST-FIX/SHOULD-FIX/NIT items applied (5 MUST-FIX + 9 SHOULD-FIX + 4 NIT mechanism; 1 SHOULD-FIX blast); 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 | — | | | | | FA6 | — | | | | | FA7 | — | | | |