# openfut-utas-host The FIFA 17 UTAS migration boundary. It accepts the client-visible HTTP surface, serves migrated routes from Rust/Core plus host-owned durable stores, and proxies only the unclassified tail to the Python behavioral oracle. ``` FIFA 17 ──HTTP──▶ openfut-utas-host ├── migrated route ──▶ Rust adapter / Core / host stores └── unclassified tail ──▶ Python UTAS oracle ``` `src/lib.rs::classify` is the route-level source of truth. The current Rust surface includes club/squad/user reads, club rename, auth/session/client data, Store/economy, packs, owned-item moves, market/trade-pile, and the observed hub support routes. ## Safety model - Classification happens exactly once before execution. There is no "try Rust then Python"; a mutation cannot be double-applied. - A route classified to Rust never falls back to Python on a Core/store/projection failure. Each handler uses its captured fail-closed or honest-empty wire contract. - `PUT …/club` and `PUT|POST …/user/club` atomically update the shared account JSON. Every input returns the required zero-atom `200 {}` response; rejection and persistence failures remain visible in logs. - Numeric `GET …/squad/` returns the one Core-backed current squad, matching the Python oracle's single-current-squad behavior. - Python remains the behavioral oracle and rollback backend for routes not yet classified to Rust. New economy behavior belongs in Rust/Core, never Python. ## Configuration (env) | Var | Required | Default | Meaning | |---|---|---|---| | `OPENFUT_UTAS_HOST_ADDR` | yes | — | client-visible host listen address | | `OPENFUT_UTAS_PYTHON_URL` | yes | — | Python oracle base for the unclassified tail; must differ from this host | | `OPENFUT_FIFA17_CATALOG` | yes | — | FIFA 17 definition identity catalog | | `OPENFUT_IDENTITY_STORE` | yes | — | persistent owned-instance ↔ wire-id store | | `OPENFUT_PERSONA_ID` | yes | — | non-zero FIFA persona id shared by LSX/Blaze/POW/UTAS | | `OPENFUT_MARKET_DB` | yes | — | durable host-owned transfer-market SQLite DB | | `OPENFUT_PILE_DB` | yes | — | durable host-owned item-pile SQLite DB | | `OPENFUT_CORE_URL` | no | `http://127.0.0.1:8080` | OpenFUT Core base | | `OPENFUT_FIFA17_TABLES_DIR` | no | `fifa17-recon/data/tables` | FIFA entity tables | | `OPENFUT_CLIENTDATA_DB` | no | identity-store sibling `clientdata.json` | durable opaque client-data JSON | | `OPENFUT_ACCOUNT_PATH` | no | `FUT_ACCOUNT_PATH`, then identity-store sibling `active_account.json` | shared FIFA account/club JSON | Startup fails if required identity or durable economy state cannot be opened. No placeholder production identity source is substituted. ## Identity model (resolved) FIFA renders an owned card by resolving `resourceId & 0xffffff` against the client's **own local players table**; an invented id renders a **blank generic card** (proven live — `fut_cards.py:11-21`). Two distinct identities, never conflated, are resolved by [`Fifa17IdentityResolver`] (the single production path): - **Definition identity** (`resourceId`/`assetId`) — the card's real FIFA asset id, from the versioned `OPENFUT_FIFA17_CATALOG`. An unmapped definition is **dropped and counted**, never faked. - **Instance identity** (`id`) — a stable, persistent, reversible wire integer from the generic `openfut-identity` store under the FIFA 17 wire-id policy (monotonic from `100_000_001`). The same owned instance keeps its id across restart and reverses exactly; two copies of one definition share a `resourceId` but get distinct `id`s. The namespace is globally monotonic within `(fifa17, owned-item)` — no per-account column is needed because Core owned-instance ids are globally-unique UUIDs. Production has a frozen post-P1 baseline and a hot Python rollback. A source change passing local tests is **not** deployment approval. Build verification, staging, host restart, and live-client promotion remain operator-gated; the current state and promotion evidence live in the OpenFUT Obsidian vault. Logs are safe by construction: no auth/session/device/token material — only owner, route, filter summary, counts, status.