docs: record the LIVE-CONFIRMED inactive UI contract and the expired->Club transition

Operator confirmed in the real client that a tradeState "inactive" row lands under the
right-hand TRANSFER LIST section and renders Start Price 0 with Buy Now, Current Bid
and Time Remaining all absent, while an active row in the same body continued to
render separately under LISTED ITEMS. That is the Q2 representation confirmed live,
with the token itself dumped from the client's own string table rather than guessed.

Records the observed wire->UI contract as a table plus a fixture
(inactive-row-live-confirmed.json), and names the regression tests that pin it,
including the two guards that the row is never emitted for an item outside the trade
pile and never duplicates a real auction.

Also records the expired->Club coupled transition verified server-side: the listing
went to `cancelled`, the pile went to `club`, /tradePile dropped the item, /club
regained it, and clubPlayers went 1964 -> 1965. That is durable store state rather
than a client-local view, so it survives a session boundary by construction; tagged
pending the operator's final exit/re-enter confirmation.

Adds the counts observation table. `count` currently tracks AUCTION entries and not
total Transfer List membership; semantics deliberately left unchanged until the full
state set has been observed.

No behaviour change in this commit.
This commit is contained in:
funman300
2026-08-17 20:31:20 +00:00
parent a2bd048ace
commit b6398c44e6
2 changed files with 194 additions and 0 deletions
+65
View File
@@ -466,3 +466,68 @@ state and auction lifecycle are separate authoritative facts; the wire may expos
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.
---
## Q2 — LIVE-CONFIRMED: `tradeState: "inactive"` is the unlisted representation
Operator-observed in the real FIFA 17 client, 2026-08-17, with the bounded one-item
probe (`OPENFUT_FIFA17_UNLISTED_PROBE`). Fixture:
`docs/evidence/market-lifecycle-2026-08-17/inactive-row-live-confirmed.json`.
### The observed `inactive` UI contract
| Wire | Client presentation |
|---|---|
| `tradeState: "inactive"` | row placed under the right-hand **TRANSFER LIST** section, NOT under LISTED ITEMS |
| `startingBid: 0` | Start Price = `0` |
| `buyNowPrice: 0` | Buy Now Price = `-` (absent) |
| `currentBid: 0` | Current Bid = `-` (absent) |
| `expires: 0` | Time Remaining = `-` (no timer) |
| `bidState: "none"` | no bid presentation |
| `itemData.itemState: "free"` | renders as a normal owned card |
An `active` row in the same body continued to render separately under LISTED ITEMS,
so the two sections are driven by `tradeState` and the experiment did not disturb the
known-good active path.
Token provenance: dumped from the client's own `{const char*, int}` table at
`0x180229e40` (`active=1 inactive=2 expired=3 closed=4`) — see
`cardsdll-vocab-tables.txt` and `fifa17-recon/tools/vocab_dump.py`. Nothing here was
guessed.
Regression test: `market::tests::unlisted_candidate_is_a_non_active_pile_row` pins the
whole tuple, plus that the row is never emitted for an item outside the `trade` pile
and never duplicates a real auction
(`unlisted_candidate_never_duplicates_a_real_auction`).
### Expired -> Club coupled transition, verified
Operator returned the naturally-expired Ronaldo to the club. Server state after:
```
listing 1000000097 state = cancelled (the coupled transition fired)
pile Ronaldo = club
/tradePile Ronaldo absent
/club Ronaldo present, itemState free
hub clubPlayers 1964 -> 1965, auctionCount 1
counts {count 1, selling 1, sold 0}
```
All of that is durable store state rather than a client-local view, so it survives a
session boundary by construction. Pending the operator's final exit/re-enter
confirmation before this is tagged CONFIRMED.
### Counts observations so far (semantics still UNCHANGED and unresolved)
| State | `count` | `selling` | `sold` |
|---|---|---|---|
| 1 active | 1 | 1 | 0 |
| 2 active | 2 | 2 | 0 |
| 1 active + 1 inactive (probe) | 1 | 1 | 0 |
| unlisted pile items (no probe) | not counted | not counted | 0 |
So `count` currently tracks AUCTION entries, not total Transfer List membership. Do
not change this until the full state set (empty / unlisted / active / expired / sold /
mixed) has been observed — it remains an open question whether FIFA 17 expects
`count` to include non-active pile members.
@@ -0,0 +1,129 @@
{
"auctionInfo": [
{
"bidState": "none",
"buyNowPrice": 15000,
"coinsProcessed": 0,
"currentBid": 0,
"expires": 2674,
"itemData": {
"assetId": 158023,
"attributeList": [
{
"index": 0,
"value": 89
},
{
"index": 1,
"value": 90
},
{
"index": 2,
"value": 86
},
{
"index": 3,
"value": 96
},
{
"index": 4,
"value": 26
},
{
"index": 5,
"value": 61
}
],
"cardassetid": 158023,
"cardsubtypeid": 0,
"contract": 7,
"definitionId": 158023,
"discardValue": 1500,
"fitness": 99,
"id": 100000155,
"itemState": "listFS",
"itemType": "player",
"leagueId": 53,
"nation": 52,
"owners": 1,
"playStyle": 250,
"preferredPosition": "RW",
"rareflag": 1,
"rating": 93,
"resourceId": 158023,
"teamid": 241,
"untradeable": false
},
"sellerEstablished": 1,
"sellerName": "CAGE",
"startingBid": 150,
"tradeId": 1000000155,
"tradeState": "active",
"watched": false
},
{
"bidState": "none",
"buyNowPrice": 0,
"coinsProcessed": 0,
"currentBid": 0,
"expires": 0,
"itemData": {
"assetId": 158023,
"attributeList": [
{
"index": 0,
"value": 89
},
{
"index": 1,
"value": 90
},
{
"index": 2,
"value": 86
},
{
"index": 3,
"value": 96
},
{
"index": 4,
"value": 26
},
{
"index": 5,
"value": 61
}
],
"cardassetid": 158023,
"cardsubtypeid": 0,
"contract": 7,
"definitionId": 158023,
"discardValue": 1500,
"fitness": 99,
"id": 100000059,
"itemState": "free",
"itemType": "player",
"leagueId": 53,
"nation": 52,
"owners": 1,
"playStyle": 250,
"preferredPosition": "RW",
"rareflag": 1,
"rating": 93,
"resourceId": 158023,
"teamid": 241,
"untradeable": false
},
"sellerEstablished": 1,
"sellerName": "CAGE",
"startingBid": 0,
"tradeId": 1000000059,
"tradeState": "inactive",
"watched": false
}
],
"credits": 29843976,
"duplicateItemIdList": [],
"total": 2
}