Files
OpenFUT/docs/PYTHON_RETIREMENT_PLAN.md
T
funman300 33e9118329 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.
2026-08-17 16:10:53 +00:00

3.7 KiB

Python Retirement Readiness (post-P1)

Classification of every Python component still present. Evidence: prod-host owner= dispatch log (OBSERVED), AuxServiceMap/PythonContractMap scouts, container entrypoint.sh. P2 rollback stays hot regardless (do NOT remove rollback-to-python-p2.sh, :p2-rollback image b1b929953f, profile 39bb3e83).

A. LIVE PRODUCTION REQUIRED (still owns behavior in the live flow)

Component Role Rust status Retire when
oracle utas_server.py (:8199) NON-ECONOMY remaining: item-defs (item/resource,defid), user/club rename, non-active squad/, draft, marketdata, mode-gated leaderboards + /sbs/* Most non-economy migrated 2026-08-17 (account/sync, auth, userMassInfo, user, clientdata, hub, club/stats/*, settings, accountinfo, phishing, match/reset, leaderboards/options, watchList, static acks, and the flag-off empty reads season/tournament/champion/clubUser/user/list → {} — all Rust). See PRODUCTION_AUTHORITY_MATRIX remaining tail migrated (needs live captures for the data routes; mode-logic port for the gated ones) OR mode-gated ones kept Python
blaze_responder_v3b.py (:42130 Blaze) FUT Blaze transport Rust openfut-blaze-host COMPLETE, gate-proven (Gate 10) container cutover (operator-gated deploy)
blaze_responder_v3b.py (:42127 redirector TLS) first-hop TLS redirect Rust openfut-redirector-host COMPLETE (OpenSSL) container cutover + cert consistency
roster_server.py (:8081) roster-update XML Rust openfut-roster-host COMPLETE (unit-only) container cutover
pow_server.py (:8094/:8080) Proof-of-Work / content NO Rust crate; 58 templates, bodies un-reversed needs Rust host + body RE (BLOCKED)

B. ORACLE ONLY (reference / differential, not production authority)

  • utas_server.py economy handlers: now oracle-only (economy is Rust; Python economy hits = 0). Used by economy_differential.rs as the parity oracle. KEEP.
  • fut_store.py / fut_accounts.py / fut_consumables.py: reference models + Ghidra-derived taxonomy source. KEEP.

C. MIGRATION TOOL ONLY (offline)

  • scripts/.py (seed_fifa17_cards.py, utas-observe/mutate/diff, check-). KEEP (dev tooling).
  • fifa17-recon/tools/db_dump.py etc.: table extraction. KEEP.

D. ROLLBACK ONLY (hot, DO NOT REMOVE)

  • rollback-to-python-p2.sh; image openfut-fut-backend:p2-rollback (b1b929953f) + :dev; profile 39bb3e83; compose/env backup; tuple OPENFUT_SERVERS="blaze roster utas pow".

E. DEAD (advertised but not followed in current FIFA17 flow)

  • Nucleus /connect/token stub (:42131): 0 live hits across Gate 5-10 (client never POSTs). Keep the ADVERTISED URL so the client can't reach real EA, but no migration needed. No Rust listener required.
  • fifa-blaze (FIFA23 capture stub), openfut-bridge (FIFA23): retired lineage, not in FIFA17 flow.

Retirement gating

  1. Mostly DONE (2026-08-17): account/sync, ut/auth (Rust SID mint), userMassInfo (full), clientdata, club/stats/{country,league,team}, watchList, static acks, and the flag-off empty reads (season/tournament/champion/clubUser/user/list → {}) migrated + deployed. Remaining on Python: item-defs, user/club rename, non-active squad/, draft, marketdata (freeze-risk), and mode-gated leaderboards + /sbs/* (need the mode logic ported). Migrate the data ones once live shapes are captured.
  2. Deploy Rust blaze/roster/redirector via container cutover (operator-gated) — then those Python responders are class D/E only.
  3. POW: build Rust host + reverse bodies (largest blocker) OR keep Python POW as class A indefinitely.
  4. Only after a long stable window: consider retiring the P2 rollback (separate explicit decision — NOT now).