feat(host): migrate flag-off UTAS reads (season/tournament/champion/clubUser/user-list) to Rust

FUT modes (Seasons/Tournaments/FUT Champions) and the club-identity service are
disabled in this emulator, so these GET reads return {} verbatim from the Python
oracle. Serve them directly from Rust via a new Route::FeatureOffEmpty +
non_economy::feature_off_body() -> {} (byte-identical to the flag-off oracle),
reducing the proxied Python surface.

- The mutating club rename (user/club) stays on Python (needs a Core write).
- Enabling a mode later requires a real Rust handler here, never a Python
  fallback (no split authority).
- classify tests: 5 routes owned + user/club/wrong-method lookalikes stay
  Passthrough; updated the stale clubUser assertion.
- Deployed to prod-host 2026-08-17; verified owner=RUST 200 {} for all five.

Docs: PRODUCTION_AUTHORITY_MATRIX + PYTHON_RETIREMENT_PLAN updated.
This commit is contained in:
funman300
2026-08-17 16:10:53 +00:00
parent e06fd57211
commit 33e9118329
4 changed files with 50 additions and 8 deletions
+3 -2
View File
@@ -53,16 +53,17 @@ Legend: owner R = Rust/Core, P = Python oracle (:8199 proxied via PYTHON_FALLBAC
| GET /club/stats/{year,consumables,staff,country,league,team} | R | Core aggregation; context buckets keyed nation/league/team (owned=1982); staff={} |
| GET /store, /match/keepalive, /captcha, /tfa, /livemessage, /activeMessage | R | unconditional constant acks (byte-identical to the oracle; StaticAck route) |
| GET /watchList (+ PUT/POST/DELETE) | R | empty watch list + authoritative Core credits; add/remove is a no-op ack (oracle persists none) |
| GET /season, /tournament, /champion, /clubUser, /user/list | R | FUT modes + club-identity off → `{}` (FeatureOffEmpty; byte-identical to the flag-off oracle). Migrated + deployed 2026-08-17 |
| POST /ut/.../match/end (DestroyMatch) | R | economy reward (coins credited via Core grant_reward) |
### NON-ECONOMY — still Python (PYTHON_FALLBACK)
| Method/path | Owner | Reason |
|---|---|---|
| GET /item/resource, /defid | P | `item_def(rid)` shapes `{itemData:[…]}` from `PLAYER_DEFS` (asset=rid&0xffffff → name/rating/pos/attrs) + consumable defs, placeholder fallback ("Player",75,attrs 70). Faithful Rust needs those def tables in the host. Shape captured: `docs/evidence/route-shapes-2026-08-17/defs_resource.json` |
| GET /clubUser, /user/list, /user/club | P | club identity (off→{}, flag-gated) + rename (mutating); Core has `clubs` but rename needs a Core write |
| POST /user/club (rename) | P | mutating club rename; Core has `clubs` but rename needs a Core write (deferred). Reads `clubUser`/`user/list` are now Rust. |
| GET /squad/<n> (n≠0, non-active) | P | no multi-squad Core model (Rust owns squad/0, squad/active, /squad/list, PUT) |
| /squad/mode/draft/* | P | FUT Draft mode |
| GET /season, /tournament, /champion, /leaderboards, /sbs/* | P | mode-gated (FUT_MODES/_SBC off by default → `{}`); real behavior needs the mode logic ported |
| GET /leaderboards, /sbs/* | P | mode-gated (FUT_MODES/_SBC off `{}`/content; `/sbs/sets` ships content); real behavior needs the mode logic ported. `season`/`tournament`/`champion` are now Rust. |
| GET /marketdata (+ /marketdata/pricelimits) | P | suggested pricing; freeze-risk (array vs object container); Python-correct, constant band 150..15000 |
| POST /ut/.../match (CREATE), /match/ready (READY), /match (PLAY) | P | match handshake legs; no match ever played in-game (see docs/MATCH_LIFECYCLE.md) |