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:
funman300
2026-08-22 00:14:11 +00:00
parent 0a7c4e129c
commit db5fb37980
2 changed files with 43 additions and 1 deletions
+12 -1
View File
@@ -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![(