Files
OpenFUT/openfut-utas-host/README.md
T
2026-08-18 17:29:24 +00:00

75 lines
4.2 KiB
Markdown

# 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/<n>` 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.