feat(host): name unclaimed requests, and record the FUT task vocabulary
Milestone 2 groundwork. The passthrough arm forwarded to Python without ever recording WHAT was asked for, so on staging -- where the upstream is deliberately dead -- an unhandled request produced an anonymous 502. It now logs method, path and body length before forwarding, which is how the next unclaimed route gets identified: utas-host owner=PYTHON route=passthrough method=GET path=/ut/... body_len=0 Also records the FUT TASK vocabulary read out of the live client. The client drives UTAS through named tasks held in a CardsDLL .rdata table of 0x20-byte MixedCase/UPPERCASE slots, with a .data descriptor table giving each a task id: ApplyCard 0x0d, ApplyCardByRes 0x0e, ConsumeCard, ActivateCard, AssingCard(sic), MoveCard, MoveCardByRes, SwapCard, DiscardCard, DiscardCardByRes, ViewCards, ... So consumable application IS a first-class client action even though the route table contains no /apply endpoint -- it must ride an existing route. The descriptor's function pointer is a `mov [rip+flag], cl; ret` setter, not a request builder, so the request is assembled elsewhere keyed by task id; that is cheaper to answer with one live capture than with more static tracing. Search tooling carries mandatory positive controls (tradePile, ut/%s/item, squad -- all FOUND), so the "no /apply route" result is a valid negative rather than a failed scan. Host 120 lib tests, fmt and clippy clean.
This commit is contained in:
@@ -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
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user