docs: freeze the known-good auction state and mark tradeOwner DISPROVEN
Records the live-client resolution so the market shape is now a fixture rather than folklore, and so a future agent cannot burn deployments on tradeOwner again. Confidence notes updated: tradeOwner remains FIFA17-HISTORICAL (it does exist in the FIFA 17-era API) but "required by FIFA17.exe Transfer List Actions" is now DISPROVEN for this client path -- it is not among the twelve atoms the client's auctionInfo deserializer reads, and it was implemented, deployed, observed inert and removed. The real blockers are recorded as CONFIRMED live-client findings: trade/status polling is load-bearing, `expires` must EVOLVE with wall-clock time (a frozen value is structurally valid and behaviourally broken), and relist must persist through the PK conflict that FIFA's re-sent ISStart necessarily causes. Freezes the known-good bodies under docs/evidence/market-lifecycle-2026-08-17/ with a machine-checkable countdown proof (_index.json._countdown_proof records expires decrementing, frozen:false) rather than asserting the clock in prose. States the general rule this cost us: a response can pass differential parity and render perfectly while still being wrong, because FIFA expects an evolving server-side state machine, not a static object that resembles one.
This commit is contained in:
@@ -196,3 +196,76 @@ moved and an auction could never run out. Now derived from `created_at + duratio
|
|||||||
(duration taken from the `ISStart` body), clamped at 0, with an aged-out active
|
(duration taken from the `ISStart` body), clamped at 0, with an aged-out active
|
||||||
listing projecting as `expired`/`none` — FIFA 17's relistable state. Verified live:
|
listing projecting as `expired`/`none` — FIFA 17's relistable state. Verified live:
|
||||||
the standing listing correctly reads `expires: 0` once past its hour.
|
the standing listing correctly reads `expires: 0` once past its hour.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## RESOLVED against the live client — 2026-08-17 (supersedes the tags above)
|
||||||
|
|
||||||
|
Driven by the real FIFA 17 client end to end: list → expire → **relist** → active,
|
||||||
|
with the operator confirming each UI state. Live-client behaviour OUTRANKS both the
|
||||||
|
Python oracle and contemporaneous Web App implementations wherever they disagree.
|
||||||
|
|
||||||
|
### `tradeOwner` — do not re-litigate this
|
||||||
|
|
||||||
|
```text
|
||||||
|
tradeOwner exists in the FIFA 17-era FUT API:
|
||||||
|
FIFA17-HISTORICAL
|
||||||
|
|
||||||
|
tradeOwner required by FIFA17.exe Transfer List Actions:
|
||||||
|
DISPROVEN for the current client path
|
||||||
|
```
|
||||||
|
|
||||||
|
It is absent from the twelve atoms FIFA 17's `auctionInfo` deserializer
|
||||||
|
(`0x18013e410`) reads, so the client value-SKIPs it at `0x180135ff0`. It was
|
||||||
|
implemented, deployed, observed to change nothing, and REMOVED. A future agent
|
||||||
|
rediscovering the old Web App sources will find this note before spending
|
||||||
|
deployments on it again.
|
||||||
|
|
||||||
|
### What actually gated the Actions panel — all lifecycle/state bugs
|
||||||
|
|
||||||
|
```text
|
||||||
|
CONFIRMED — FIFA17.exe live client
|
||||||
|
|
||||||
|
Own Transfer List interactivity does NOT depend on tradeOwner in this path.
|
||||||
|
|
||||||
|
trade/status polling is LOAD-BEARING for Transfer List state. The tail carries no
|
||||||
|
numeric id, so it fell through the `trade…` buy/view arm and answered every poll
|
||||||
|
with an empty auctionInfo. Route is ISVIEWTRADE:
|
||||||
|
GET ut/{ns}/trade/status?tradeIds=a,b,c
|
||||||
|
|
||||||
|
auctionInfo.expires is SECONDS REMAINING *and must evolve with wall-clock time*.
|
||||||
|
A structurally valid but FROZEN value breaks lifecycle behaviour: the auction never
|
||||||
|
ages into expired/relistable, which is the state where Re-list appears.
|
||||||
|
|
||||||
|
Relisting must PERSIST. FIFA 17 relists by re-sending ISStart (POST /auctionhouse)
|
||||||
|
for an item that already has a listing row, so the primary-key conflict IS the
|
||||||
|
relist. Swallowing it as success left the stale expired row intact and produced a
|
||||||
|
client-visible lifecycle failure behind an HTTP 200.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Known-good own active auction (frozen fixture)
|
||||||
|
|
||||||
|
Captured at `docs/evidence/market-lifecycle-2026-08-17/`, including
|
||||||
|
`_index.json._countdown_proof` which records `expires` decrementing (`frozen:
|
||||||
|
false`) so the live clock is machine-checkable rather than asserted in prose.
|
||||||
|
|
||||||
|
```text
|
||||||
|
tradeState = active
|
||||||
|
bidState = none
|
||||||
|
expires = decrementing (seconds remaining)
|
||||||
|
sellerName = CAGE
|
||||||
|
auction record = 12 atoms
|
||||||
|
response envelope = 4 members (auctionInfo, credits, duplicateItemIdList, total)
|
||||||
|
ISViewTrade body = 2 members (auctionInfo, credits)
|
||||||
|
pricelimits = BARE ARRAY (container type is load-bearing)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Do not "improve" this shape without a live-client retest.**
|
||||||
|
|
||||||
|
### The development rule this established
|
||||||
|
|
||||||
|
A response can be structurally plausible, pass differential parity, and render
|
||||||
|
perfectly while still being behaviourally wrong, because FIFA expects an **evolving
|
||||||
|
server-side state machine** rather than a static object that looks like one. The
|
||||||
|
frozen `expires` is the canonical example: every field was the right name, type and
|
||||||
|
vocabulary, and the feature was still broken.
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"_countdown_proof": {
|
||||||
|
"delta": -4,
|
||||||
|
"expires_after_4s": 2216,
|
||||||
|
"expires_first": 2220,
|
||||||
|
"frozen": false
|
||||||
|
},
|
||||||
|
"auctionhouse-browse": {
|
||||||
|
"container": "object",
|
||||||
|
"path": "/auctionhouse",
|
||||||
|
"status": 200
|
||||||
|
},
|
||||||
|
"marketdata-pricelimits": {
|
||||||
|
"container": "array",
|
||||||
|
"path": "/marketdata/pricelimits?defId=20801",
|
||||||
|
"status": 200
|
||||||
|
},
|
||||||
|
"trade-status-filtered": {
|
||||||
|
"container": "object",
|
||||||
|
"path": "/trade/status?tradeIds=1000000097",
|
||||||
|
"status": 200
|
||||||
|
},
|
||||||
|
"trade-status-unfiltered": {
|
||||||
|
"container": "object",
|
||||||
|
"path": "/trade/status",
|
||||||
|
"status": 200
|
||||||
|
},
|
||||||
|
"tradePile": {
|
||||||
|
"container": "object",
|
||||||
|
"path": "/tradePile",
|
||||||
|
"status": 200
|
||||||
|
},
|
||||||
|
"tradePile-counts": {
|
||||||
|
"container": "object",
|
||||||
|
"path": "/tradePile/counts",
|
||||||
|
"status": 200
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"auctionInfo": [
|
||||||
|
{
|
||||||
|
"bidState": "none",
|
||||||
|
"buyNowPrice": 15000,
|
||||||
|
"coinsProcessed": 0,
|
||||||
|
"currentBid": 0,
|
||||||
|
"expires": 2220,
|
||||||
|
"itemData": {
|
||||||
|
"assetId": 20801,
|
||||||
|
"attributeList": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"value": 92
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 1,
|
||||||
|
"value": 92
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 2,
|
||||||
|
"value": 81
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 3,
|
||||||
|
"value": 91
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 4,
|
||||||
|
"value": 33
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 5,
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cardassetid": 20801,
|
||||||
|
"cardsubtypeid": 0,
|
||||||
|
"contract": 7,
|
||||||
|
"definitionId": 20801,
|
||||||
|
"discardValue": 1500,
|
||||||
|
"fitness": 99,
|
||||||
|
"id": 100000097,
|
||||||
|
"itemState": "forSale",
|
||||||
|
"itemType": "player",
|
||||||
|
"leagueId": 53,
|
||||||
|
"nation": 38,
|
||||||
|
"owners": 1,
|
||||||
|
"playStyle": 250,
|
||||||
|
"preferredPosition": "LW",
|
||||||
|
"rareflag": 1,
|
||||||
|
"rating": 94,
|
||||||
|
"resourceId": 20801,
|
||||||
|
"teamid": 243,
|
||||||
|
"untradeable": false
|
||||||
|
},
|
||||||
|
"sellerEstablished": 1,
|
||||||
|
"sellerName": "CAGE",
|
||||||
|
"startingBid": 150,
|
||||||
|
"tradeId": 1000000097,
|
||||||
|
"tradeState": "active",
|
||||||
|
"watched": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"count": 0,
|
||||||
|
"credits": 29843976,
|
||||||
|
"duplicateItemIdList": [],
|
||||||
|
"maxAuctionsAllowed": 100,
|
||||||
|
"offered": 0,
|
||||||
|
"selling": 1,
|
||||||
|
"sold": 0,
|
||||||
|
"total": 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"defId": 20801,
|
||||||
|
"maxPrice": 15000,
|
||||||
|
"minPrice": 150
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"auctionInfo": [
|
||||||
|
{
|
||||||
|
"bidState": "none",
|
||||||
|
"buyNowPrice": 15000,
|
||||||
|
"coinsProcessed": 0,
|
||||||
|
"currentBid": 0,
|
||||||
|
"expires": 2220,
|
||||||
|
"itemData": {
|
||||||
|
"assetId": 20801,
|
||||||
|
"attributeList": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"value": 92
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 1,
|
||||||
|
"value": 92
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 2,
|
||||||
|
"value": 81
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 3,
|
||||||
|
"value": 91
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 4,
|
||||||
|
"value": 33
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 5,
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cardassetid": 20801,
|
||||||
|
"cardsubtypeid": 0,
|
||||||
|
"contract": 7,
|
||||||
|
"definitionId": 20801,
|
||||||
|
"discardValue": 1500,
|
||||||
|
"fitness": 99,
|
||||||
|
"id": 100000097,
|
||||||
|
"itemState": "listFS",
|
||||||
|
"itemType": "player",
|
||||||
|
"leagueId": 53,
|
||||||
|
"nation": 38,
|
||||||
|
"owners": 1,
|
||||||
|
"playStyle": 250,
|
||||||
|
"preferredPosition": "LW",
|
||||||
|
"rareflag": 1,
|
||||||
|
"rating": 94,
|
||||||
|
"resourceId": 20801,
|
||||||
|
"teamid": 243,
|
||||||
|
"untradeable": false
|
||||||
|
},
|
||||||
|
"sellerEstablished": 1,
|
||||||
|
"sellerName": "CAGE",
|
||||||
|
"startingBid": 150,
|
||||||
|
"tradeId": 1000000097,
|
||||||
|
"tradeState": "active",
|
||||||
|
"watched": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"credits": 29843976
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"auctionInfo": [
|
||||||
|
{
|
||||||
|
"bidState": "none",
|
||||||
|
"buyNowPrice": 15000,
|
||||||
|
"coinsProcessed": 0,
|
||||||
|
"currentBid": 0,
|
||||||
|
"expires": 2220,
|
||||||
|
"itemData": {
|
||||||
|
"assetId": 20801,
|
||||||
|
"attributeList": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"value": 92
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 1,
|
||||||
|
"value": 92
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 2,
|
||||||
|
"value": 81
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 3,
|
||||||
|
"value": 91
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 4,
|
||||||
|
"value": 33
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 5,
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cardassetid": 20801,
|
||||||
|
"cardsubtypeid": 0,
|
||||||
|
"contract": 7,
|
||||||
|
"definitionId": 20801,
|
||||||
|
"discardValue": 1500,
|
||||||
|
"fitness": 99,
|
||||||
|
"id": 100000097,
|
||||||
|
"itemState": "listFS",
|
||||||
|
"itemType": "player",
|
||||||
|
"leagueId": 53,
|
||||||
|
"nation": 38,
|
||||||
|
"owners": 1,
|
||||||
|
"playStyle": 250,
|
||||||
|
"preferredPosition": "LW",
|
||||||
|
"rareflag": 1,
|
||||||
|
"rating": 94,
|
||||||
|
"resourceId": 20801,
|
||||||
|
"teamid": 243,
|
||||||
|
"untradeable": false
|
||||||
|
},
|
||||||
|
"sellerEstablished": 1,
|
||||||
|
"sellerName": "CAGE",
|
||||||
|
"startingBid": 150,
|
||||||
|
"tradeId": 1000000097,
|
||||||
|
"tradeState": "active",
|
||||||
|
"watched": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"credits": 29843976
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"count": 1,
|
||||||
|
"maxAuctionsAllowed": 100,
|
||||||
|
"offered": 0,
|
||||||
|
"selling": 1,
|
||||||
|
"sold": 0
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"auctionInfo": [
|
||||||
|
{
|
||||||
|
"bidState": "none",
|
||||||
|
"buyNowPrice": 15000,
|
||||||
|
"coinsProcessed": 0,
|
||||||
|
"currentBid": 0,
|
||||||
|
"expires": 2220,
|
||||||
|
"itemData": {
|
||||||
|
"assetId": 20801,
|
||||||
|
"attributeList": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"value": 92
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 1,
|
||||||
|
"value": 92
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 2,
|
||||||
|
"value": 81
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 3,
|
||||||
|
"value": 91
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 4,
|
||||||
|
"value": 33
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 5,
|
||||||
|
"value": 80
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"cardassetid": 20801,
|
||||||
|
"cardsubtypeid": 0,
|
||||||
|
"contract": 7,
|
||||||
|
"definitionId": 20801,
|
||||||
|
"discardValue": 1500,
|
||||||
|
"fitness": 99,
|
||||||
|
"id": 100000097,
|
||||||
|
"itemState": "listFS",
|
||||||
|
"itemType": "player",
|
||||||
|
"leagueId": 53,
|
||||||
|
"nation": 38,
|
||||||
|
"owners": 1,
|
||||||
|
"playStyle": 250,
|
||||||
|
"preferredPosition": "LW",
|
||||||
|
"rareflag": 1,
|
||||||
|
"rating": 94,
|
||||||
|
"resourceId": 20801,
|
||||||
|
"teamid": 243,
|
||||||
|
"untradeable": false
|
||||||
|
},
|
||||||
|
"sellerEstablished": 1,
|
||||||
|
"sellerName": "CAGE",
|
||||||
|
"startingBid": 150,
|
||||||
|
"tradeId": 1000000097,
|
||||||
|
"tradeState": "active",
|
||||||
|
"watched": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"credits": 29843976,
|
||||||
|
"duplicateItemIdList": [],
|
||||||
|
"total": 1
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user