# OpenFUT — Project State > **Canonical source:** `../OpenFUT-Vault/06 Agent Memory/Project State.md` > This file is a mirror. If the two disagree, the vault wins. Update the vault first. Factual snapshot. Prefer this over the stale root `README.md`/`CLAUDE.md` status tables (FIFA 23). Last compiled from repository evidence during context initialization. ## Working - **FIFA 17 offline FUT stack, end-to-end.** Proven 2026-08-01: auth → Blaze login → device-trust → the FUT hub. Brought up by `fifa17-recon/tools/openfut-fut.sh start`. Evidence: `FUT-RUNBOOK.md`, `fifa17-recon/README.md`, the five responder scripts, gate-ladder troubleshooting table. - **ProtoSSL cert-pin defeat** — two live `/proc/PID/mem` patches (`autopatch.py`), VAs stable across launches. gdb-verified which gate was the wall. - **LSX / Origin layer** — crypto handshake reversed byte-exact and confirmed against the repack's own emu disassembly (`docs/REPACK_INTEL.md`); Origin login gates cleared. - **Blaze redirector + Fire2/Heat2** — both hops defeated; preAuth/login/personas answered. - **UTAS/RS4 FUT API** — `ut/auth` + boot calls + device-trust reach the hub with hand-authored JSON. - **Persistent FIFA 17 account selection** — the launcher synchronizes one configured EA persona to the Python backend before starting LSX/FIFA. LSX, Blaze, POW/EASFC, and UTAS then share that identity, while FUT coins, inventory, squads, progression, and unopened packs persist in an isolated save beneath `fifa17-recon/docker/state/accounts//`. The POW level/XP/funds shown in FIFA's general account bar are account-scoped but remain distinct from FUT club coins. A reversible server test on 2026-08-09 verified profile switching, POW values, a 400-coin pack debit, five awarded items, and restoration of the original profile. - **Account-scoped FUT security compatibility** — launcher account synchronization initializes a persisted `securityQuestion` verification record in that persona's FIFA 17 profile. The UTAS PHISHING handler returns the complete CardsDLL trusted-console response (`changed`, `exists`, `locked`, `trusted`), accepts only well-formed legacy setup/validate requests under `X-UT-SID`, and never stores or logs the client-transformed answer. This is server-side emulation; the hook and launcher do not contain an answer or add UI automation. Automated contract coverage is in `fifa17-recon/docker/ctx/tools/test_security_question.py`; live first/repeat-launch acceptance is partially complete: the first launch entered FUT without a security dialog on 2026-08-09; a second fresh-process FUT entry is still required to close persistence acceptance. - **Safe responder diagnostics** — ordinary LSX logs redact challenge/session/auth-code attributes; ordinary Blaze logs redact auth/session keys and no longer emit raw Fire2 hex, decoded TDF, or config values. Forensic Blaze capture remains available only with the explicit `OPENFUT_BLAZE_DUMP_FRAMES=1` opt-in. LSX and Blaze self-tests cover the new defaults. - **OpenFUT Core** — Rust FUT economy backend, feature-complete for its scope and tested: profiles, clubs, coins, packs, cards, squads, chemistry styles, SBCs, objectives, matches, market (NPC), draft, FUT Champs, seasons, statistics, achievements, events, daily check-in, division leaderboard, market trade history. 13 migrations. Integration suite (`tests/integration_test.rs`, 96 test fns) runs against in-memory SQLite; CI (fmt/clippy/build/test) green on `openfut-core`. ## Partially implemented - **FIFA 17 FUT hub depth** — reaching the hub is proven, but how much of FUT is fully navigable beyond it (playing matches, pack opening, SBC submission through the *game* UI vs. spinner/error states) is not documented as complete. The runbook's gate ladder lists failure modes still guarded against. Treat "past the hub" as unverified. - **Pack opening through the game UI** — proven live on 2026-08-09 with the recovered CAGE test profile: purchase, reveal, item assignment/quick-sell, wallet refresh, and return from the reveal all completed. The Python transaction path also passes its 446-check contract suite. FIFA's hardcoded post-reveal `mypacks` return is supported by a short-lived active grace record for every opened pack; it is excluded from unopened-pack counts and retired at the next hub request. - **FIFA 17 FUT match lifecycle** — CardsDLL static analysis and isolated responder tests now cover CREATE→READY→PLAY→END. Bare `/match` requests carrying body `matchId` are classified as PLAY instead of accidentally allocating another match; READY returns the verified scalar `matchId` and `opponentPersonaId` fields; END persists W/D/L, matches played, and coin rewards per account. The implementation is deployed and `test_match_lifecycle.py` passes, but no football match has started or completed in FIFA yet. The READY opponent `items` contract and client mode-entry gate remain unresolved; `FUT_MODES` therefore stays off by default. - **Core ↔ emulation integration** — the two halves exist and wiring has **started**. First slice (2026-08-11): the My Squad owned-player search. `openfut-core` gained a semantic, game-independent owned-inventory query (`services::inventory::{OwnedItemQuery, apply_query}` + a `Quality` tier) that filters (AND) → orders deterministically → paginates, wired into `GET /collection`; `openfut-adapter-fifa17::fut::owned_query` parses the FIFA17 `/club` wire query and resolves numeric league/nation/team ids → semantic names (unknown id = hard error, no raw-id passthrough). Intentional fix, not parity: Python applies only `league`+`team` and ignores `level`/`rare`/`position`/`nation`/`start`/`count` (the request-amplification bug); Core applies all proven filters and paginates. `rare=SP` semantics UNKNOWN, unimplemented. Slice 2 (2026-08-11): `openfut-utas-host` — the first live UTAS host. Serves `GET …/club` from Core through the adapter and reverse-proxies every other UTAS route verbatim to the Python oracle (`utas_server.py`); plaintext HTTP/1.1 keep-alive, classify-before-execute, no python-fallback after a Core error. `CoreAccess` is a host-owned boundary (the adapter stays transport-agnostic). 11 host + 22 adapter tests; 10/10 mutations killed; fmt/clippy clean. Slice 3 (2026-08-11, `3ef3bc3`): the real `Fifa17IdentityResolver` — catalog (card id → real asset id) + persistent `openfut-identity` store (owned instance → stable/reversible wire int) + wire-id policy, replacing all placeholders (one production path). Wire-id namespace is globally monotonic within `(fifa17, owned-item)`, not per-account (Core owned ids are UUIDs → unambiguous reverse). Slice 4 (2026-08-11, core `36abd4b`): a curated 32-card real FIFA17 dev content pack (`data/games/fifa17/dev/cards.json`, ids `fifa17_`), loaded only via opt-in `Config.dev_content_games`; `seed-dev` grants a `game_id=fifa17` profile+club real `OwnedCard`s (no FIFA wire ids — the resolver mints those at request time), idempotent, default content untouched. Slice 5 (2026-08-11, `5276dd2`): the host sends `X-OpenFUT-Game: fifa17` so `/club` resolves the all-mapped fifa17 profile — **composition proven live** over HTTP (real Core+host, no FIFA client): FIFA wire query → real `resourceId`s (catalog) + stable/reversible wire `id`s (store); 33 renderable, gold=22, Premier League=18, pagination page1=11/page2=7/overlap=0 (clean paging, no drops). **The only remaining gate is the live retail FIFA A/B** (no FIFA client in the build env; runbook `openfut-utas-host/README.md`). See the vault UTAS Endpoint Map + Known Issues (incl. "identity resolution is NOT authorization" for later mutations). **Slice 6 (2026-08-11): `/club` RUNTIME VALIDATED on retail FIFA 17** — operator-assisted live A/B (`.105` client → `.120` backend via a source-scoped NAT redirect into a staged `36abd4b` Core + `openfut-utas-host`). Every checkpoint passed on the real client: transport, per-route Python fallback, Python-negative `/club`, Core `X-OpenFUT-Game` scoping, real card + persistent owned-item identity (incl. the two-copy fixture), no-filter/Gold/position/nation/league/team/combined-AND filtering, retail pagination with no amplification, card selection, identity stability across relaunch, Python rollback, and Rust re-enable (identity store byte-identical across the cycle, 0 reallocation). Live findings: the retail client steps `start += 10` with `count=11` (sometimes bulk `count=100`) — Core honours `offset` and terminates; the My Club UI nests team under league; the "~1900" club counter is Python `userMassInfo`, not `/club`. Remaining is operational only (promote the staged stack to a durable deployment). - **Slice 7 (2026-08-12): FUT squad authority (read + write) RUNTIME VALIDATED on retail FIFA 17.** Staged operator-assisted A/B (`.105` retail client → `.120`, source-scoped utas switch `:8099→:8199` into `openfut-utas-host` over a staged `615c5fd` Core seeded by `seed-dev` with the dev 33-card inventory). FIFA itself consumed the Rust squad path end-to-end: FUT boot served `RUST_OVERLAY userMassInfo` (squad overlay) and the squad screen rendered the dev XI; a controlled in-game squad edit issued `PUT …/squad/0` → host `squad-replace` → Core → `{"id":0}`; an in-game formation change f442→f433 persisted to Core (canonical fingerprint changed, `position_index` remapped 0–10); a FULL FIFA relaunch cold-fetched and rendered the persisted f433 squad (no client cache). Reversibility proven on the exact client path by log presence, not response data (both backends coincidentally hold the same dev squad — the Python oracle `fifa17_profile.json` was seeded from the same `squad_put_f442.json` capture): disarmed `.105:8099` reached Python (absent from host log), re-armed reached Rust (`route=club limit=Some(9)` present); the persistent identity store survived the cycle with 0 reallocation. Non-migrated routes (`/ut/auth`, `account/sync`, `accountinfo`, `settings`, `hub`, store txn) correctly Python-fallback. NEW startup requirement: the Core server loads dev card defs only for games in env `OPENFUT_DEV_CONTENT_GAMES` (comma-sep); omitting `fifa17` makes `get_collection` silently drop every owned card (empty `/collection`, "no squad") despite a successful seed — MUST become a deployment/preflight assertion. Preceded the same day by a staged two-process parity gate (real Core+host over HTTP, no FIFA) confirming byte- shape parity of `userMassInfo.squad` vs the captured oracle. Next milestone: real-data Core import / profile strategy → production Rust UTAS. Blaze deferred. - **Slice 8 (2026-08-12): REAL-DATA staged retail A/B PASS (import + club + squad).** The real FIFA 17 profile was imported into a staged Core via the two-store protocol (`openfut-import-fifa17 --apply`: generic transactional Core import + `openfut-identity` seeding, idempotent), then FIFA itself consumed it end-to-end over the source-scoped utas switch (`.105`→`.120:8199`). Imported population 1949 of 1962 player instances (13 Legend/special assets deferred as unnameable — 9 NoName + the 4 copies of `169193`), every original Python wire id preserved (set-equal, 0 minted/dropped), each owned instance an opaque Core UUID. On the retail client: real club rendered (1949, not the 33-card dev XI); `/club` pagination clean (paged==full, no loop/overlap/drop); the `Special` quality filter returned only specials (1665, 0 base leaked) and paginated the filtered set; a squad edit persisted to Core (canonical + opaque extension atomically, fingerprint recomputed) and survived a full cold relaunch; rollback→Python→Rust re-enable proven on the exact client path (disarm reached Python, re-arm returned the imported club + edited squad; identity store 0 reallocation). Three real-data fidelity gaps the base-only dev fixture had hidden were found on the live client and fixed: (1) `e187cd4` versioned `resourceId` — `shape_item` emitted the base assetId as `resourceId`, collapsing every special onto its base card art; `Fifa17Identity` now carries the versioned `resource_id`. (2) `626c972` observed `rareflag` — `shape_item` hardcoded `rareflag=1`, so all specials rendered as basic rare; `rareflag` now flows through the FIFA catalog and onto the wire (wire distribution == source exactly). (3) `6f16a23` `rare=SP` Special filter — previously a no-op ("semantics UNKNOWN"), now grounded as `rareflag > 1` and applied host-side (Core has no rareflag). Also `44fcf24`: nation/league/team proven to be INSTANCE metadata (not definition identity — the 4 copies of `169193` are identical but for club), so the definition-consistency gate now compares identity only (no `--defer-conflict` needed; no majority-vote). PRODUCTION NOT READY: the 13 deferred Legends are unnameable from the `.120` client dump (absent/placeholder in `players.json`; DLC/Legends name tables empty) — honest names require the FIFA 17 Legends locale data from the `.105` client. Next: resolve the 13 names → re-import to 1962/0 → full-fidelity gate → gitlink reconcile → production Rust UTAS. ## Stubbed / planned - **`fifa-blaze`** (Rust) — Milestone 1 capture stub only. Two TLS listeners that log packets; no FIFA 23 component/command handlers. Its own README says IDs are unknown. Superseded in practice by the Python FIFA 17 responders, kept as the intended FIFA 23 implementation surface. - **`openfut-launcher` legacy controls** — core/bridge and FIFA 23 setup controls belong to a superseded plan. The launcher now also owns the live FIFA 17 client flow: server/hook config, account synchronization, local LSX, privileged autopatch, and game launch. - **`tools/`** (file-watch-diff, squad-injector, exporters) — helpers for the FLE-Lua-bridge idea in `docs/direction.md`. Not part of the live FIFA 17 path. - **`docs/foundational-xi-injection-test.md`** — a planned (not executed) test procedure for the FLE bridge route. ## Stubbed / blocked (FIFA 23 lineage) - **`openfut-bridge`** — in-process `version.dll` hook on ProtoSSL. Git history: injection works but the effort hit an "architectural wall" (async event-driven gate, not a poll). Superseded first by the FLE-bridge pivot, then by the FIFA 17 route. Its `CLAUDE.md` task list is historical. ## Unknown / requires investigation - Whether the FIFA 17 hub supports actually **playing a FUT match** offline and getting results back. - Whether FUT actions beyond the now-verified pack reveal/assignment flow (submit SBC, transfer market buy/sell, matches) round-trip correctly through `utas_server.py`. - The exact division of FUT state ownership once Core is wired in (who is source of truth). - Degree of FIFA 23 wire-format identity — asserted ("identical wire format") but the FIFA 23 client has not been re-tested against these responders in this repo's evidence. ## Known technical debt / hazards - **Root docs are stale.** `README.md`, `CLAUDE.md`, `openfut-bridge/CLAUDE.md` all describe FIFA 23 as the target and mark FIFA 23 integration as the open item — they predate the FIFA 17 success. - **All host state is volatile** across reboot except the `/etc/hosts` line — re-run `openfut-fut.sh start`. Requires `ptrace_scope=0` + root arming (security-relevant). - **Whole stack rides on EAAC staying neutralized** and game updates being off; a client update can break the memory patches (VAs) and cert bypass. - **`fifa17-recon/tools/lsx_responder_v2.py` is currently modified in the working tree** (uncommitted). - `33068179` / `CAGE` remains the responder fallback, but the launcher now blocks one-button launch until an explicit persona is configured and synchronized across LSX, Blaze, POW, and UTAS.