diff --git a/fifa17-recon/docs/CLIENT_ROUTE_SURFACE.md b/fifa17-recon/docs/CLIENT_ROUTE_SURFACE.md index 5cab575..a6e34aa 100644 --- a/fifa17-recon/docs/CLIENT_ROUTE_SURFACE.md +++ b/fifa17-recon/docs/CLIENT_ROUTE_SURFACE.md @@ -105,3 +105,34 @@ So applying a consumable is **not** a dedicated server route. If it reaches the server at all it must ride `PUT ut/%s/item`, and L5/L6 should be pursued by capturing that PUT's payload while applying a card — not by looking for an endpoint that does not exist. + +## FUT task vocabulary (2026-08-21, live) + +The client drives UTAS through named TASKS, not just URLs. The task-name table +lives in CardsDLL `.rdata` as 0x20-byte inline slots holding MixedCase/UPPERCASE +pairs (`tools/apply_route_search.py`, controls `tradePile`/`ut/%s/item`/`squad` +all FOUND): + +``` +ViewCards AssingCard(sic) ApplyCard ApplyCardByRes +ActivateCard ConsumeCard DiscardCard DiscardCardByRes +DiscardACard MoveCard MoveCardByRes SwapCard +CreateMatch MatchReady DestroyMatch PlayGame ResetMatch KeepAlive +LoadCategoryDetails LoadSetChallenges StartChallenge LoadSquadChallenge +SaveSquadChallenge SubmitChallenge TagSets SetSbcData +TournamentList TournamentTeams SetUserInfo GetHistorical SetTutData ... +``` + +A descriptor table in `.data` pairs each name with a task id and a small setter +thunk, e.g. `ApplyCard` id **0x0d** at `0x1802cb170`, `ApplyCardByRes` id **0x0e** +at `0x1802cb1a0`. The thunks are `mov [rip+flag], cl; ret` (a per-task flag), NOT +request builders, so the request is assembled elsewhere keyed by task id. + +**So consumable application IS a first-class client action (`ApplyCard` / +`ApplyCardByRes` / `ConsumeCard`), even though no `/apply` URL exists.** It +therefore rides an existing route. Which one is a one-capture question, and the +host now names every unclaimed request: + +``` +utas-host owner=PYTHON route=passthrough method=GET path=/ut/... body_len=N +``` diff --git a/openfut-utas-host/src/lib.rs b/openfut-utas-host/src/lib.rs index 7cbdeb8..e75802c 100644 --- a/openfut-utas-host/src/lib.rs +++ b/openfut-utas-host/src/lib.rs @@ -4022,10 +4022,21 @@ impl Server { Route::MarketData => self.handle_marketdata(path, target), Route::SecurityQuestion => self.handle_security_question(method, target, headers), Route::Passthrough => { + // Name the request BEFORE forwarding. On staging the upstream is + // deliberately dead, so this line is the only record of what the + // client asked for -- which is exactly how an unclaimed route is + // discovered (see docs/CLIENT_ROUTE_SURFACE.md). Bodies are not + // logged; the path and method are enough to identify a route. + eprintln!( + "utas-host owner=PYTHON route=passthrough method={method} path={target} body_len={}", + body.len() + ); let resp = match self.pass.forward(method, target, headers, body) { Ok(r) => r, Err(e) => { - eprintln!("utas-host ERROR passthrough to Python failed: {e}"); + eprintln!( + "utas-host ERROR passthrough failed method={method} path={target}: {e}" + ); WireResponse { status: 502, headers: vec![(