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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user