diff --git a/fifa17-recon/docs/REBUILD_RESEARCH.md b/fifa17-recon/docs/REBUILD_RESEARCH.md index 8e3ba11..3c1f853 100644 --- a/fifa17-recon/docs/REBUILD_RESEARCH.md +++ b/fifa17-recon/docs/REBUILD_RESEARCH.md @@ -822,3 +822,74 @@ options body is exactly what would make the client proceed and ask for `/season` first time. So success on the first step arms the second risk. Expect it, watch for the busy-loop freeze rather than an error dialog, and be ready to answer `/season` minimally rather than fully. + +--- + +## 19. The MY CLUB counter: why it is not server-fixable (2026-08-04, measured) + +Three experiments in one session, and the answer is a negative with a mechanism behind +it rather than another candidate body. + +### What was tried + +| flag | what it changed | result | +|---|---|---| +| `FUT_CLUB_PAGE` | served 114 items to `GET /club?...count=11` | tile still `0 TOTAL PLAYERS` | +| `FUT_CLUBSTATS` | full stat set on every Stats2 mode, `players=114` | panel still `Players 0` | + +The bodies demonstrably went out. The log shows four `CLUBSTATS: ... 11 stat rows +(players=114)` responses at 14:20:19 and 14:20:23, and the panel was re-entered after. + +### The mechanism + +``` +FUN_18012fbe0 store+0x78 = request+0xc4 the mode tag is copied out of the + store+0x7c = request+0xc8 REQUEST that just completed + store+0x80 = request+0xcc +FUN_180043b90 switch (store+0x78) + case 1 +0x800(1)->PLAYERS_EMPLOYED +0x800(0x1e)->BALLS_EARNED + +0x800(0x28)->KITS_AVAILABLE +0x800(0x14)->STADIA_OWNED + +0x800(10)->STAFF_EMPLOYED +0x800(0x32)->TROPHIES_WON + case 3 per-nation: BRONZE/SILVER/GOLD/RARE_PLAYERS_EMPLOYED, KITS, BADGES + case 6 CARDS_NO_TRAINING_*, CARDS_NO_CONTRACT_*, CARDS_NO_FITNESS_* +``` + +The MY CLUB summary is **case 1**, which requires mode 1 (`club`). The real client +requests `/club/stats/staff`, `/club/stats/year` and `/club/stats/consumables`, and +**never** `/club/stats/club`, so the mode tag settles at 6 and case 1 is never +selected. Our values are stored correctly (contextId 1 forces contextValue 0, the +global bucket the `+0x800` getter reads) and case 1 reads exactly the six ids we set. +Nothing ever asks for them. + +**The mode is chosen client-side from the request URL.** No response body can change +it. That is why this is not a shape problem: there is no body that fixes it. + +### Two independent corroborations + +- Case 6 reads ids `0x3d` CONTRACTS, `0x3e` TRAINING and `0x40` FITNESS, which are + exactly the three ids the type-string map (`FUN_18012fd40`) **cannot produce**. The + consumables view is unsettable from this endpoint by construction, which is a + strange property unless the mode split is real. +- `FUT_CLUB_PAGE` eliminated the only other candidate: the tile is not a count of the + list we return. + +### Status + +`FUT_CLUBSTATS` stays implemented and **default off**. The body is correct against the +verified schema and would populate the moment a `club`-mode request occurred. Keeping +it costs nothing and throwing it away would lose the schema work. + +`FUT_CLUB_PAGE` stays default off; it answered its question. + +### What would still change this + +One thing, and it is not another body: find what makes the client issue +`/club/stats/club`. It is a request the client knows how to build (the URL builder +`FUN_18012f4f0` has a `club`(0x87) mode), so something reaches it. That decision is in +the front-end layer, same as Seasons. Until then, treat the MY CLUB counter as **not +server-fixable** and stop generating candidate bodies for it. + +An earlier note in this file argued the counter was server-supplied by +`/club/stats/`, and the live-evidence argument that the hub tile and the panel +read the same store (both said "players", both zero) was mine and was wrong in its +conclusion. The store is shared; the *selection* is not.