fix(fifa17): map market resource ids to authoritative Core card ids
Closes the market correctness gap: handle_market_list recorded listing.card_id from the raw FIFA wire resourceId, so a synthetic buy minted a card_id Core could not resolve — it survived the immediate response but Core's content preflight rejected it on reboot. - catalog.rs: keep the by_resource reverse index (was built then discarded) and expose `card_id_for_resource(resource_id) -> Option<&str>` — exact reverse of the card_id->asset catalog, no heuristics, unknown => None. - lib.rs: `impl MarketCardResolver for Fifa17IdentityResolver` delegates to the same catalog /club shaping uses; Core never sees a FIFA resource id. - market_store.rs: listings now carry BOTH `card_id` (authoritative Core content, what a buy MINTS) and `wire_resource_id` (the FIFA wire id, echoed in the auction record). New column; create_listing takes both; row/Listing updated. - market.rs: `MarketCardResolver` trait; handle_market_list resolves resourceId -> Core card_id and fails closed (persists nothing) on an unmappable resource; auction_record emits `resourceId` from wire_resource_id. Dispatch passes the resolver. Tests: list_unknown_resource_fails_closed_no_listing (B), list_persists_core_card_and_wire_resource_across_reopen (C), catalog reverse lookup; and the dispatch E2E now RESTORES the full Core+store restart (economy_full_sequence_through_dispatch_and_restart) — the synthetic buy mints a real reverse-mapped card_id, so Core's content preflight passes on reboot (A+D). market 23 lib + catalog 15 + 2 integration green; clippy -D warnings + fmt clean.
This commit is contained in:
@@ -863,6 +863,17 @@ impl SquadWireResolver for Fifa17IdentityResolver {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reverse a FIFA wire `resourceId` to the authoritative Core `card_id`, via the
|
||||
/// same catalog `/club` shaping uses — so a synthetic market buy mints real Core
|
||||
/// content, never the raw FIFA number. Out-of-range or unmapped → `None`
|
||||
/// (fail closed; Core never sees a FIFA resource id).
|
||||
impl crate::market::MarketCardResolver for Fifa17IdentityResolver {
|
||||
fn card_id_for_resource(&self, resource_id: i64) -> Option<String> {
|
||||
let rid = u32::try_from(resource_id).ok()?;
|
||||
self.catalog.card_id_for_resource(rid).map(str::to_string)
|
||||
}
|
||||
}
|
||||
|
||||
// ───────────────────────────── /club handler ────────────────────────────────
|
||||
|
||||
/// Safe, structured summary of a handled `/club` request (no auth/session/device
|
||||
@@ -1914,12 +1925,22 @@ impl Server {
|
||||
})
|
||||
}
|
||||
EconomyRoute::MarketList => {
|
||||
let (bridge, market, econ) =
|
||||
(svc.bridge.clone(), svc.market.clone(), svc.econ.clone());
|
||||
let (bridge, market, econ, resolver) = (
|
||||
svc.bridge.clone(),
|
||||
svc.market.clone(),
|
||||
svc.econ.clone(),
|
||||
self.resolver.clone(),
|
||||
);
|
||||
let (m, body) = (method.to_string(), body.to_vec());
|
||||
bridge.block_on(async move {
|
||||
crate::market::handle_market_list(&m, &body, econ.as_ref(), market.as_ref())
|
||||
.await
|
||||
crate::market::handle_market_list(
|
||||
&m,
|
||||
&body,
|
||||
econ.as_ref(),
|
||||
market.as_ref(),
|
||||
resolver.as_ref(),
|
||||
)
|
||||
.await
|
||||
})
|
||||
}
|
||||
EconomyRoute::MarketQuery => {
|
||||
|
||||
Reference in New Issue
Block a user