diff --git a/openfut-utas-host/ROUTE_AUTHORITY.md b/openfut-utas-host/ROUTE_AUTHORITY.md index 1c06013..9f2f42d 100644 --- a/openfut-utas-host/ROUTE_AUTHORITY.md +++ b/openfut-utas-host/ROUTE_AUTHORITY.md @@ -26,14 +26,14 @@ S2 live-staging defect where the v2 Store BUY escaped to Python. | Credits | `GET (/ut/game\|/ut/v2/game)//user/credits` | `Credits` | | Store catalogue | `GET …/store/purchasegroup[/…]` | `PurchaseGroup` | | **Store BUY** | `PUT …/store/transaction` **and** `PUT …/store/transaction/` (numeric, e.g. `…/store/transaction/0`) | `StoreBuy` | -| Pack open | `POST …/purchased` | `PackOpen` | -| Pack reveal | `GET …/purchased` | `PackReveal` | +| **Pack open** | `POST …/purchased` **and** `POST …/purchased/items` | `PackOpen` | +| **Pack reveal** | `GET …/purchased` **and** `GET …/purchased/items` | `PackReveal` | | Quick-sell (path) | `DELETE …/item/` | `QuickSellPath` | | Quick-sell (body) | `POST (/ut/delete/game\|/ut/v2/delete/game)//item` | `QuickSellBody` | | Move | `PUT …/item` | `MoveItems` | | Match end | `POST (/ut/delete/game\|/ut/v2/delete/game)//match` | `MatchEnd` | | Market list | `POST …/auctionhouse` \| `…/transfermarket` | `MarketList` | -| Market query | `GET …/tradePile` | `MarketQuery` | +| Market query | `GET …/tradePile` **and** `…/tradePile/counts` (CASE-INSENSITIVE: `tradepile` too) | `MarketQuery` | | Market buy | `…/trade/` | `MarketBuy` | | Market cancel | `DELETE (/ut/delete/game\|/ut/v2/delete/game)//trade/` | `MarketCancel` | @@ -44,6 +44,20 @@ basis: Python route table `utas_server.py:1420` matches the store family "regardless of /ut/game vs /ut/v2/game prefix"; all other economy routes are `G = /ut/game/[^/]+`-prefixed (v1-only) and the retail client uses v1 for them. +### Round-2 fix (retail `/purchased/items` + `tradePile` case) — candidate supersedes `47ced22` + +Live re-stage of `47ced22` showed the CONFIRMED retail Store BUY uses +`POST /ut/game/fifa17/purchased/items` (reveal `GET …/purchased/items`), which the +exact-tail `purchased` match missed → Python (Core coins unchanged = no debit). Fix: +`is_purchased_tail` accepts `purchased` AND `purchased/items` (bounded: rejects +`purchasedfoo`, `purchased/items/extra`); `is_tradepile_tail` matches the `tradepile` +family case-insensitively (`tradePile`, `tradepile`, `…/counts`) since the FUT hub tile +polls lowercase while the screen uses camelCase (oracle routes both via `re.I`). Audit +basis: oracle `utas_server.py:1428` bare `/purchased` regex matches `/purchased/items`; +`:1539-1540` `tradePile`/`tradePile/counts` are `re.I`. The full contract is the +machine-auditable `retail_route_matrix` unit test + the `pure_economy_routes` dispatch +matrix (NEVER-BOTH / no-fallback) + `retail_purchased_items_buy_debits_core_through_dispatch`. + ## E1 — CUTOVER READY (barrier `93a46d4`, superproject source-ready; NOT deployed) The economy authority barrier is committed: `Server::handle_with_ip` dispatches