fifa17-recon: route squad/mode/draft/state -- the root container is an ARRAY
Deser 0x180147070 (FutGetDraftCurrentStateServerResponse) discards tokens until it sees START_ARRAY. Handed a top-level OBJECT it never reaches its exit condition and spins in the inner `while (tok != END_OBJECT)` loop while the tokenizer returns EOF forever. Process alive, no crash dump, no dialog: exactly the signature observed live on 2026-08-03, when our generic /squad route answered this endpoint with a full active-squad object. The suffix composition `ut/%s/squad/mode` + `/draft/state?mode=...` makes the URL invisible to the request-template table, which is why /squad swallowed it. Fourth time a suffix endpoint has been invisible to that table, second time the generic /squad route has eaten one (/squad/list was the first). Verified at instruction level rather than by regex: 7 top-level atoms (4 int-getter calls, 3 string-getter, 0 bool, 2 skip) across the whole body [0x180147070, 0x1801475a3]. FUN_180135ff0 IS present, twice, so unknown keys are inert. NO ATOM COLLIDES with the squad object we were serving, which means the hang was purely the container level and not a per-field type desync. entranceCriteria(0x108) is now known to be an object of three int keys COINS/DRAFT_TOKEN/POINTS. It is OMITTED anyway: knowing a shape is not a reason to send it. A second agent independently simulated this exact body through the deserializer line by line and got a clean exit in 16 token reads, and separately refuted four claims in the first agent's report (a census undercount, a wrong .rdata address where 0x18021e7f4 is 'TFA' not the squad template, an incorrect stateParam2 typing argument, and a dangerous aside about a second array-root envelope). The body survived all of it. DEFAULT ON, a deliberate exception to "default to the live-proven value": the live-proven value here HANGS THE GAME, and there is no working screen to protect because Draft cannot be entered at all today. FUT_DRAFT_STATE=0 restores the old routing. 392 + 51 checks green; /squad/0 and /squad/list verified unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VUT92pz6RWKih9dSr8ZpxW
This commit is contained in:
@@ -863,6 +863,10 @@ ROUTES = [
|
||||
# full active-squad object; the list parser 0x180142260 recognises ONLY
|
||||
# squad(0x2cd) and skipped every one of those keys -> "MY SQUADS: 0".
|
||||
(re.compile(G + r"/squad/list"), lambda m, h: (200, squad_list_body())),
|
||||
# Same bug as /squad/list, second instance: `ut/%s/squad/mode` + `/draft/state`
|
||||
# is composed by appending a suffix, so it is invisible to the request-template
|
||||
# table, and the generic /squad route below was swallowing it. MUST precede it.
|
||||
(re.compile(G + r"/squad/mode/draft/state"), lambda m, h: draft_state_route(h)),
|
||||
(re.compile(G + r"/squad"), lambda m, h: squad_route(h)),
|
||||
(re.compile(G + r"/match/keepalive"), lambda m, h: (204, None)),
|
||||
# PUT ut/%s/match/reset = FutResetMatch. Seen live at boot (2026-08-03) as an
|
||||
@@ -1039,6 +1043,54 @@ def leaderboard_route(h):
|
||||
return 200, {"entries": []}
|
||||
|
||||
|
||||
# ---- Draft current state -----------------------------------------------------
|
||||
# GET ut/%s/squad/mode/draft/state?mode=ONLINE|SINGLE_PLAYER
|
||||
# -> FutGetDraftCurrentStateServerResponse, deser 0x180147070.
|
||||
#
|
||||
# THE ROOT CONTAINER IS A JSON ARRAY, not an object. That single fact is the whole
|
||||
# finding. The deserializer's prologue discards tokens until it sees START_ARRAY;
|
||||
# handed a top-level object it never reaches its exit condition and spins in the
|
||||
# inner `while (tok != END_OBJECT)` loop with the tokenizer returning EOF forever.
|
||||
# Process alive, no crash dump, no error dialog: exactly the signature observed live
|
||||
# on 2026-08-03 when our generic /squad route answered this with a full active-squad
|
||||
# object (23 slots, nested itemData, the 33-int `custom` string).
|
||||
#
|
||||
# Verified, not assumed:
|
||||
# * 7 top-level atoms, counted at instruction level (4 int-getter calls, 3
|
||||
# string-getter calls, 0 bool, 2 skip) over the whole body [0x180147070,
|
||||
# 0x1801475a3]. FUN_180135ff0 IS present (2 sites), so unknown keys are inert.
|
||||
# * NO ATOM COLLIDES with the squad object we were serving. The freeze was purely
|
||||
# the container level, not a per-field type desync.
|
||||
# * roundsInfo[] element parser FUN_180146eb0 (2477 chars, read in full): 7 scalar
|
||||
# atoms, all safe. Empty array is safest and is what we send.
|
||||
# * entranceCriteria(0x108) is an object of three int keys COINS/DRAFT_TOKEN/
|
||||
# POINTS. OMITTED here: knowing a shape is not a reason to send it.
|
||||
# * squadState(0x2d5) is a string enum. "DRAFTSQUAD_ON" from the old notes is NOT
|
||||
# an accepted spelling.
|
||||
#
|
||||
# A reviewer independently simulated this exact body through the deserializer line by
|
||||
# line: 16 token reads, clean exit, nothing left over.
|
||||
#
|
||||
# DEFAULT ON, which is a deliberate exception to "default to the live-proven value".
|
||||
# The live-proven value here HANGS THE GAME. There is no working screen to protect:
|
||||
# Draft cannot be entered at all today. FUT_DRAFT_STATE=0 restores the old routing if
|
||||
# this turns out to be wrong.
|
||||
DRAFT_STATE = os.environ.get("FUT_DRAFT_STATE", "1") == "1"
|
||||
|
||||
|
||||
def draft_state_route(h):
|
||||
if not DRAFT_STATE:
|
||||
return squad_route(h)
|
||||
return 200, [{
|
||||
"squadState": "INVALID", # 0x2d5 STRING enum
|
||||
"stateParam1": "INVALID", # STRING
|
||||
"stateParam2": "0", # STRING (the int getter also accepts it)
|
||||
"gamesWonCurrentMatch": 0, # INT
|
||||
"roundsInfo": [], # array of the 7-scalar element; empty is safe
|
||||
# entranceCriteria: OMITTED. Shape known, not needed, skip-safe.
|
||||
}]
|
||||
|
||||
|
||||
def champion_route(h):
|
||||
"""ut/%s/champion -- registration 0x18014980d (ack, no atoms),
|
||||
topX 0x18014a09d ({"entries":[]}), friends 0x18014b7ad ({} safe)."""
|
||||
|
||||
Reference in New Issue
Block a user