docs: capture the unlisted transfer-list state and model the pile/auction boundary

Q2 measured, not guessed. The operator moved a card Club -> Transfer List without
listing it (PUT /item, no POST /auctionhouse) and the state was captured read-only.

Finding: we do not represent the unlisted state on the wire AT ALL. Such an item is
byte-identical to a club item -- itemState `free`, no `pile` field emitted, still
returned in /club and counted in clubPlayers -- while an actively-listed item is
correctly excluded from /club and present in tradePile. Only the host's own pile
store knows the difference. Trade pile held 6 items: 1 listed, 5 unlisted.

The FIFA 17 ENCODING of that state stays UNKNOWN on purpose: returned itemData.pile
is numeric with an unrecovered mapping, and tradeState is a closed table walk where
an unrecognised bidState is silently swallowed as `none`, so a wrong enum produces a
plausible-looking but wrong UI. The corpus warns `inactive` decodes but no client
path treats it specially. One client-only discriminator is recorded instead.

Also models the domain boundary both limbo bugs came from: pile membership and
auction lifecycle are separate facts requiring coordinated transitions. States the
testable invariant -- an item must never be simultaneously excluded from /club and
absent from /tradePile -- with the two ways it was reachable and the commits that
closed each.
This commit is contained in:
funman300
2026-08-17 20:01:51 +00:00
parent 4e31fb98a2
commit 7f37b37be3
5 changed files with 319 additions and 2 deletions
@@ -5,7 +5,7 @@
"buyNowPrice": 15000,
"coinsProcessed": 0,
"currentBid": 0,
"expires": 2220,
"expires": 1199,
"itemData": {
"assetId": 20801,
"attributeList": [