Files
OpenFUT/openfut-utas-host/Cargo.toml
T
OpenFUT Agent 4d2b8b9be3 economy(fifa17): land Store + Market writer handlers + pack generator (unrouted)
Implements the FIFA17 economy WRITER cluster on top of the landed Core
economy authority + host CoreEconomy client + identity/item-shaper infra.
Handlers are pub, unit-tested, and NOT yet routed: classify() and
ROUTE_AUTHORITY are untouched — the classifier barrier is a later single
coherent flip. No stubs; real Core-backed behavior; fail-closed on CoreError.

Pack generator (adapter fut/pack_content.rs):
  generate_pack_contents(&PackDef, &mut impl Rng, &[GeneratedCandidate])
  -> Vec<GeneratedCard>. Pure, seeded (deterministic), gold-tier split +
  special_chance gate as documented OPENFUT PLACEHOLDER policy (Python
  open_pack/_pack_body parity note inline). Fail-closed empty on empty pool.

Store/item writers (host economy_store.rs), matching oracle wire shapes:
  - handle_store_buy   PUT /store/transaction -> purchase_items (debit+mint N)
    -> createPackResponse; cancel/unknown/owned_only -> 200 {}; insufficient
    -> 461 {reason,credits}; CoreError -> 503.
  - handle_pack_open   POST /purchased -> owned_only consumes the unopened
    entitlement (redeem_entitlement, consume-once); normal packs debit+mint.
  - handle_quick_sell{_path,_body}  DELETE .../item/<id> + POST /ut/delete/.../item
    -> reverse-resolve wire->Core id (SquadWireResolver) -> sell_item ->
    {items:[{id}],totalCredits}; not-owned skipped.
  Production OwnedItemLookup = CoreItemLookup over CoreAccess.

Market (host market_store.rs / pile_store.rs / market.rs), synthetic-seller:
  - MarketStore over sqlx SQLite (WAL-once + busy_timeout=5s + BEGIN IMMEDIATE
    for writes, mirroring openfut-core::db). listings(active/reserved/sold/
    cancelled), owner-checked cancel, CAS reserve/complete_sale/rollback.
    Typed errors NotFound/Sold/Cancelled/WrongOwner/Conflict.
  - PileStore: durable pile/location metadata keyed by Core item id.
  - handle_market_{list,query,cancel,buy} + handle_move_items. Buy-now =
    reserve (CAS) -> balance precheck (461) -> Core purchase_item (mint+debit)
    -> complete_sale; any Core failure rolls the reservation back active.
    Two concurrent buyers -> exactly one sale + one debit.

Deps (additive): rand 0.8 (adapter+host), sqlx 0.7 sqlite/runtime-tokio (host).
Tests: adapter +7 (pack_content), host +43 (economy_store 20, market/store 23
incl two_reservers_exactly_one_wins, two_buyers_exactly_one_sale_one_debit,
state_survives_reopen, move_persists_across_reopen). All green; clippy
-D warnings clean; rustfmt clean.
2026-08-13 20:47:57 +00:00

34 lines
1.6 KiB
TOML

[package]
name = "openfut-utas-host"
version = "0.1.0"
edition = "2021"
license = "MIT"
description = "FIFA 17 UTAS migration host: serves implemented routes (/club) from OpenFUT Core, transparently proxies everything else to the Python UTAS oracle"
publish = false
[dependencies]
openfut-adapter-fifa17 = { path = "../openfut-adapter-fifa17" }
openfut-http = { path = "../openfut-http" }
openfut-identity = { path = "../openfut-identity" }
serde_json = "1"
# Plain-HTTP client for Core queries and Python passthrough. UTAS is plaintext
# HTTP (worker D: no wrap_socket, no cert), so no TLS backend is linked.
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json"] }
# Durable FIFA-specific market listing + item-pile state. These are host-owned
# FIFA policy stores (NOT generic Core inventory), backed by their own SQLite
# file, opened exactly like openfut-core/src/db.rs::init_pool (WAL-once +
# foreign_keys + busy_timeout, BEGIN IMMEDIATE for writes).
sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio"] }
# Seeded RNG for the Store pack-content generator injected into the economy
# writer handlers (`economy_store`). Production seeds it from entropy (so minted
# Core instance ids never collide); tests seed a fixed value for reproducibility.
rand = "0.8"
[dev-dependencies]
parking_lot = "0.12"
# Real host<->Core integration harness: spawn Core (axum) against a disposable
# temp-file SQLite and drive the real CoreEconomy transport (no fakes).
openfut-core = { path = "../openfut-core" }
tokio = { version = "1", features = ["rt-multi-thread", "macros", "net"] }
axum = "0.7"