docs+tools: dump the CardsDLL route table; narrow Q2 to one candidate by elimination
Re-entry discriminator came back a CONFIRMED BUG: an unlisted transfer-list item does not survive a fresh FUT session, so our representation cannot reconstruct trade-pile membership. Evidence acquisition per instruction, corpus and PE first, no guessing. Adds route_table_dump.py: static read-only dump of CardsDLL's route table from the on-disk PE, resolving VA->file offset through the real section table instead of assuming a single .text mapping. Output preserved as evidence. It settles "is /tradePile the only relevant route?" -- the table holds 45 routes plus 3 empty admin slots, and row 30 `ut/%s/tradePile` is the ONLY trade-pile route. There is no trade-pile items route. That plus three existing PE facts narrows the representation to exactly one candidate by ELIMINATION rather than choice: the route carries only twelve-atom auction records; `pile` (0x226) has no arm in the item deserializer so membership is conferred by the owning list and cannot be added as a field; of the twelve atoms only tradeState expresses lifecycle; and tradeState's closed vocabulary (active=1 inactive=2 expired=3 closed=4) has exactly one value not already spoken for. So an unlisted item can only be an auctionInfo record with tradeState "inactive". Tagged INFERRED-BY-ELIMINATION, not CONFIRMED: the remaining unknown is whether the Flash Transfer List RENDERS such a record in the unlisted section. Records the acceptance test (survive a full FUT reload) and the revised invariant that a transition is complete only when a fresh session reconstructs the same visible state. No behaviour change in this commit.
This commit is contained in:
@@ -396,3 +396,73 @@ state, and it is reachable in two ways, both now closed:
|
||||
Tests: `returning_an_expired_listing_to_the_club_ends_its_auction`,
|
||||
`a_pile_move_never_disturbs_a_sale_in_flight`,
|
||||
`club_excludes_listed_items_and_paginates_the_visible_set`.
|
||||
|
||||
---
|
||||
|
||||
## Q2 representation — narrowed to ONE candidate by elimination (2026-08-17)
|
||||
|
||||
Re-entry discriminator result: **CONFIRMED BUG.** After fully leaving and re-entering
|
||||
FUT, the active auction reconstructs correctly under LISTED ITEMS, but the unlisted
|
||||
TRANSFER LIST section is **empty** — item `100000059` does not survive. The
|
||||
immediate post-move visibility was client-local only, so our representation cannot
|
||||
durably reconstruct trade-pile membership.
|
||||
|
||||
The representation is now pinned by elimination over PROVEN facts, not chosen:
|
||||
|
||||
1. **Only one route can own a trade-pile list.** The complete CardsDLL route table
|
||||
(`.rdata 0x18021df80`, 45 routes + 3 empty admin slots) is dumped verbatim at
|
||||
`docs/evidence/market-lifecycle-2026-08-17/cardsdll-route-table.txt` via
|
||||
`fifa17-recon/tools/route_table_dump.py` (static, read-only, VA→offset resolved
|
||||
through the real PE section table). Row 30 `ut/%s/tradePile` is the ONLY
|
||||
trade-pile route. There is no trade-pile *items* route.
|
||||
2. **That route carries only auction records.** `FutGetTradePile` (`0x180170810`)
|
||||
deserializes the shared IS-list body (`0x18013e7f0`), whose `auctionInfo`
|
||||
elements go through `0x18013e410` — the twelve-atom auction record.
|
||||
3. **`pile` cannot be set from the wire.** `pile` (atom 0x226) has NO arm in the item
|
||||
deserializer `FUN_18013fe00` (checked in all four dispatch forms); `item+0x60` is
|
||||
assigned by the OWNING LIST, reading 1 for every `/club` item and 6 for every
|
||||
`/purchased` item. So membership is conferred by *arriving in the list*, never by
|
||||
a field we can add.
|
||||
4. **Of the twelve atoms, only `tradeState` can express lifecycle.**
|
||||
5. **`tradeState`'s vocabulary is closed and has exactly one unused value.** The table
|
||||
walk at `0x180229e40` decodes `active=1 inactive=2 expired=3 closed=4`, anything
|
||||
else `-1`. `active`, `expired` and `closed` are all already spoken for by the
|
||||
observed lifecycle.
|
||||
|
||||
**Therefore an unlisted trade-pile item can only be an `auctionInfo` record with
|
||||
`tradeState: "inactive"`.** That is the sole encoding the client's own parser can
|
||||
accept for "in the pile, no auction" — reached by elimination, not invention.
|
||||
|
||||
Status: **INFERRED-BY-ELIMINATION**, not yet CONFIRMED. One binary question remains,
|
||||
and it is about client *rendering*, not encoding: does the Flash Transfer List place
|
||||
an `inactive` record in the unlisted section? The corpus's warning that "`inactive`
|
||||
decodes but no client path treats it specially" was established for the market
|
||||
PRESENTATION function (`flagA`/`flagB`), where `inactive` is indeed unremarkable —
|
||||
that is consistent with, and does not contradict, using it for list membership.
|
||||
|
||||
Ruled out on evidence, do not retry: adding `itemData.pile` (inert, no deserializer
|
||||
arm), a second route (none exists), and `tradeId: 0` / invented `itemState` values
|
||||
(unnecessary — `tradeState` alone carries the distinction).
|
||||
|
||||
### Acceptance test for whatever lands
|
||||
|
||||
```text
|
||||
move item Club -> Transfer List
|
||||
leave FUT entirely
|
||||
re-enter FUT
|
||||
item appears in the unlisted TRANSFER LIST section
|
||||
item can be returned to Club
|
||||
no auction exists unless explicitly listed
|
||||
```
|
||||
|
||||
Plus the active lifecycle must remain unchanged: active listing under LISTED ITEMS,
|
||||
`expires` counting down, active non-selectable, expiry making it actionable, relist
|
||||
working.
|
||||
|
||||
### Revised domain invariant
|
||||
|
||||
Core pile membership is NOT equivalent to `/tradePile` visibility. Core ownership/pile
|
||||
state and auction lifecycle are separate authoritative facts; the wire may expose them
|
||||
through different FIFA 17 resources. **A transition is complete only when a fresh FIFA
|
||||
session can reconstruct the same user-visible state** — re-entry is the acceptance
|
||||
test, not the immediate post-mutation response.
|
||||
|
||||
Reference in New Issue
Block a user