Files
OpenFUT/docs/PROJECT_STATE.md
T
funman300 63f02c4fb1 docs(state): Slice 7 — FUT squad read+write retail-validated on FIFA 17
Record the staged retail A/B: FIFA consumed the Rust squad path end-to-end
(userMassInfo overlay, in-game swap -> squad-replace {"id":0}, formation
f442->f433 persisted to Core, cold relaunch returned the persisted squad),
with Python rollback / Rust re-enable proven by host-log presence. Note the
OPENFUT_DEV_CONTENT_GAMES=fifa17 startup requirement (silent empty /collection
if omitted) as a needed deployment/preflight assertion.
2026-08-12 18:41:24 +00:00

167 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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/<persona-id>/`. 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_<asset>`), 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 010); 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.
## 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.