docs(market): close Gap 1 — active seller row under forSale is live-confirmed

The one claim the Fix B promotion left open: no active listing existed during
that session, so only the expired path had been exercised.

Closed with a disposable card (75 ST, res 212188, wire id 100000178 — one of
three identical copies, not in the squad) listed through the real FIFA 17 client
at 150/200 for 1h, so expiry arrives naturally. No timestamp touched.

Wire: itemState=forSale, tradeState=active, 12 atoms, prices intact, expires
3562 -> 3556 over a 6s sample (live clock), /trade/status coherent, counts
{count:1, selling:1}, coins unchanged, zero inactive rows (Fix A intact).

The decisive evidence is client-side, not ours: a read-only /proc/<pid>/mem
decode of the live trade-pile auction record returned
  itemState=5(forSale)
on the very field that read -1(<unrecognised>) under listFS. Direct A/B on the
only changed field, taken from the client's own memory.

Operator confirmed the row renders under LISTED ITEMS with correct prices, a
counting-down timer, normal art, and correctly non-actionable while active.

No code change required — the promoted implementation was already correct on the
active path. Claim boundary unchanged: this proves the client DECODES the token
and says nothing about the Flash action-gate term.
This commit is contained in:
funman300
2026-08-18 00:15:51 +00:00
parent 0c4aee6164
commit 0a007f4941
2 changed files with 242 additions and 1 deletions
+69 -1
View File
@@ -653,7 +653,7 @@ row `1000000155` (res 158023, 93 RW).
| `forSale` is FIFA 17-native, value 5 | **CONFIRMED** (12-row table at `0x180229cc0`) |
| An expired row carrying `forSale` is still ACTIONABLE, and Return to Club works | **LIVE-CONFIRMED** — operator returned the card; server verified below |
| The result is durable (a fresh session reconstructs it) | **CONFIRMED server-side**: `/tradePile` `total:0`, `/tradePile/counts` all zero, card present in `/club` (1965 → 1966 items, `itemState:"free"`), zero duplicate ids, listing `cancelled` in the store and projected as `closed` (4) on `/trade/status` |
| An ACTIVE seller row carrying `forSale` renders correctly | **NOT YET OBSERVED** — no active listing existed during the session; `/transfermarket` has always emitted `forSale` on active rows, so this is expected-safe but unverified |
| An ACTIVE seller row carrying `forSale` renders correctly | **LIVE-CONFIRMED** (Gap 1, 2026-08-17) — see the closure section below; the client decoded `CARD_OFFERSTATE = 5` out of its own auction record |
| `CARD_OFFERSTATE` is the Flash action-gate term | **STILL UNPROVEN** — this change does not test it, and the result does not bear on it |
What this rules out: `CARD_OFFERSTATE` is not a gate term that *requires* 1. An expired
@@ -689,6 +689,74 @@ revert and go to the AVM1 gate work — NOT to compensate with another field cha
the Flash decision tree; `STATE`, `CARD_OFFERSTATE` and `RESERVEDPRICE`/`MAX_CREDITS`
remain confounded.
### Gap 1 CLOSED — an ACTIVE seller row under `forSale` (2026-08-17)
The one thing the Fix B promotion could not test, because no active listing existed
during that session. Closed with a deliberately disposable card: a **75 ST**, resourceId
`212188`, wire id `100000178` — one of **three identical owned copies**, not in the
11-man squad, `untradeable: false`, discardValue 600. Listed **through the real FIFA 17
client** at Start 150 / Buy Now 200 for the shortest offered duration (1h), so expiry
would arrive naturally. No timestamp was touched.
Listing creation was entirely Rust-owned:
`PUT …/item` (club → pile) → `route=market-list POST item_id=100000178 listed=true
trade_id=1000000178``POST …/auctionhouse 200`, then the client polling
`GET …/trade/status?tradeIds=1000000178` (`requested=1 returned=1`) for the row it draws.
Wire, active row `1000000178`
(`docs/evidence/market-lifecycle-2026-08-17/gap1-active-forsale.json`):
| Field | Value |
|---|---|
| `itemState` | **`forSale`** |
| `tradeState` | `active` |
| `startingBid` / `buyNowPrice` / `currentBid` | 150 / 200 / 0 |
| `bidState` | `none` |
| `expires` | **3562 → 3556** over a 6-second sample — a live clock, not a frozen scalar |
| atom count | **12**, exactly what `0x18013e410` reads |
| `itemData` | full card, 6-entry `attributeList` |
| `/tradePile/counts` | `count 1, selling 1, offered 0, sold 0` |
| coins | 29,843,976 unchanged |
| Fix A | 0 `inactive` rows |
`/trade/status` stayed coherent with `/tradePile` throughout, agreeing on tradeId,
`active`, `forSale` and a decreasing `expires`.
**The decisive observation** is not the wire — it is what the client made of it. A
read-only `/proc/<pid>/mem` decode of the live trade-pile auction record (slide proven by
FNV control MATCH first; `O_RDONLY` + `pread` only) returned:
```text
tradeId=1000000178 state=1(active) bid=0(none) buyNow=200 start=150 cur=0 expires=3457
item CARD_ID=212188 cardType=1 tradeable=1 itemState=5(forSale) pile=0 rating=75
```
`itemState = 5(forSale)`. The same field read `-1(<unrecognised>)` under `listFS`. This is
the direct A/B on the only changed field, taken from the client's own memory rather than
from our response — the strongest form of this evidence available without AVM1 work.
`pile = 0` again, confirming pile is still never set from the wire.
Operator UI acceptance: card under **LISTED ITEMS** (not the TRANSFER LIST section), Start
150 / Buy Now 200 correct, **Time Remaining visibly counting down**, normal card art, no
malformed row, no duplicate, no premature Expired, no crash, and correctly
**non-actionable while active**. The client's container populating with exactly this row
(`rows=1`) independently corroborates that the Transfer List screen bound and drew it.
**No code change was required** — the promoted implementation was already correct on the
active path, which is what the test was designed to find out.
Two process notes worth keeping. First, an early capture reported "countdown NO"; that was
a bug in the capture script (it re-read a hardcoded copy id rather than the row it had
resolved), not a server fault — the same run's `/trade/status` already showed a lower
`expires` than `/tradePile`. Verify the instrument before believing a negative. Second,
the client's auction-record containers read **0 rows** while the operator was on any other
screen; they populate only while the Transfer List is bound. An empty container is not
evidence of an empty pile.
**Claim boundary unchanged:** this proves the client *decodes* the token. It says nothing
about the Flash action-gate term.
### Proving the gate (not yet done)
Disassemble the AVM1 action buffer of `tradepile.isInActiveAuction` (and
@@ -0,0 +1,173 @@
{
"gap": 1,
"test": "ACTIVE seller row under itemState=forSale",
"date": "2026-08-17",
"disposable_card": {
"wire_item_id": 100000178,
"resourceId": 212188,
"rating": 75,
"preferredPosition": "ST",
"copies_owned": 3,
"discardValue": 600,
"in_active_squad": false,
"untradeable": false
},
"pre_state": {
"club_items": 1966,
"coins": 29843976,
"tradePile_rows": 0,
"tradePile_counts": {
"count": 0,
"maxAuctionsAllowed": 100,
"offered": 0,
"selling": 0,
"sold": 0
}
},
"listing_creation_route_log": "utas-host owner=RUST route=market-list POST item_id=100000178 listed=true trade_id=1000000178",
"client_flow_observed_rust_owned": [
"PUT /ut/game/fifa17/item (club -> trade pile move)",
"POST /ut/game/fifa17/auctionhouse (ISStart) -> 200",
"GET /ut/game/fifa17/tradePile (repeated)",
"GET /ut/game/fifa17/trade/status?tradeIds=1000000178 -> requested=1 returned=1 (repeated poll)",
"GET /ut/game/fifa17/tradePile/counts"
],
"wire_active_row": {
"tradeId": 1000000178,
"tradeState": "active",
"itemState": "forSale",
"startingBid": 150,
"buyNowPrice": 200,
"currentBid": 0,
"bidState": "none",
"sellerName": "CAGE",
"sellerEstablished": 1,
"watched": false,
"coinsProcessed": 0,
"atom_count": 12,
"itemData_attributeList_entries": 6
},
"countdown_sample": {
"expires": [
3562,
3556
],
"delta_secs": 6,
"live": true
},
"trade_status_coherent_while_running": true,
"trade_status_rows": [
{
"bidState": "none",
"buyNowPrice": 200,
"coinsProcessed": 0,
"currentBid": 0,
"expires": 3556,
"itemData": {
"assetId": 212188,
"attributeList": [
{
"index": 0,
"value": 90
},
{
"index": 1,
"value": 70
},
{
"index": 2,
"value": 64
},
{
"index": 3,
"value": 78
},
{
"index": 4,
"value": 24
},
{
"index": 5,
"value": 62
}
],
"cardassetid": 212188,
"cardsubtypeid": 0,
"contract": 7,
"definitionId": 212188,
"discardValue": 600,
"fitness": 99,
"id": 100000178,
"itemState": "forSale",
"itemType": "player",
"leagueId": 19,
"nation": 21,
"owners": 1,
"playStyle": 250,
"preferredPosition": "ST",
"rareflag": 1,
"rating": 75,
"resourceId": 212188,
"teamid": 112172,
"untradeable": false
},
"sellerEstablished": 1,
"sellerName": "CAGE",
"startingBid": 150,
"tradeId": 1000000178,
"tradeState": "active",
"watched": false
}
],
"tradePile_counts_while_active": {
"count": 1,
"maxAuctionsAllowed": 100,
"offered": 0,
"selling": 1,
"sold": 0
},
"coins_unchanged": true,
"fix_a_inactive_rows": 0,
"CARD_OFFERSTATE_live_decode": {
"observed": true,
"method": "read-only /proc/<pid>/mem via fifa17-recon-derived auction_record_probe.py; slide proven by FNV control MATCH before any other read; O_RDONLY + pread only",
"client_pid": 29670,
"container": "model->vt[0x120] (trade pile), rows=1, +0x60 override=1",
"record": {
"tradeId": 1000000178,
"STATE_tradeState": "1(active)",
"YOURBID_bidState": "0(none)",
"MAX_CREDITS_buyNowPrice": 200,
"RESERVEDPRICE_startingBid": 150,
"currentBid": 0,
"expires": 3457,
"coinsProcessed": 0,
"IS_GLOW_flagB": 0,
"INBOX_flagA": 0,
"IS_WATCHED": 0
},
"item": {
"CARD_ID": 212188,
"CARD_TYPE": 1,
"tradeable": 1,
"rating": 75,
"CARD_OFFERSTATE_itemState": "5(forSale)",
"pile": 0
},
"ab_significance": "This is the direct A/B on the only changed field. Baseline `listFS` decoded to -1(<unrecognised>) in the client's own record; candidate `forSale` decodes to 5. Every other field in the record is unchanged in kind.",
"claim_boundary": "Proves the CLIENT DECODES the token correctly. Says nothing about the Flash action-gate term."
},
"ui_acceptance": {
"operator_report": "looks right",
"confirmed": [
"card renders under LISTED ITEMS (not the TRANSFER LIST section)",
"Start Price 150 and Buy Now 200 displayed correctly, Current Bid as expected",
"Time Remaining visibly counting down",
"card art renders normally; no malformed row, no duplicate, no premature Expired, no crash",
"row correctly non-actionable while active (established FIFA 17 behaviour, not a fault)"
],
"corroboration": "the client's trade-pile container populated with exactly this row (rows=1), so the Transfer List screen bound and drew it"
},
"verdict": "GAP 1 CLOSED \u2014 LIVE-CONFIRMED: an active seller auction with itemState=forSale renders correctly and is decoded by the client as CARD_OFFERSTATE=5",
"code_change_required": false
}