docs(route-authority): async bridge + dispatch wiring + real E2E landed (580d80a)
Records the AsyncBridge + classify_economy + try_handle_economy dispatch (unrouted) and the economy_full_sequence_through_dispatch E2E, the reqwest-blocking-in-async fix (off_runtime), and narrows Remaining to: Python differential, host concurrency matrix, failure injection, importer, then the from_config attachment + classifier barrier + reachability proofs. Flags the two market-handler gaps (resourceId->card_id mapping; GET /purchased reveal cache).
This commit is contained in:
@@ -113,17 +113,38 @@ Landed (Core authority + transport + several handlers; classifier NOT yet flippe
|
||||
`two_buyers_exactly_one_sale_one_debit`, `state_survives_reopen`,
|
||||
`move_persists_across_reopen`. clippy -D warnings + rustfmt clean.
|
||||
|
||||
- **Async runtime bridge + dispatch** (`580d80a`, `async_bridge.rs`, unrouted):
|
||||
`AsyncBridge` (one process-lifetime multi-thread Tokio runtime, nested-safe
|
||||
`block_on`) + `classify_economy` + `EconomyServices` + `Server::try_handle_economy`
|
||||
wire ALL the handlers into real dispatch. `classify()` is untouched (handler
|
||||
wiring ≠ authority cutover). Load-bearing fix: the async market handlers call the
|
||||
BLOCKING reqwest Core client, which panics if run while a runtime is entered
|
||||
(`reqwest::blocking::wait::enter`) — the `FakeEconomy` unit tests missed this;
|
||||
`market::off_runtime` hops each Core call to a plain OS thread.
|
||||
- **Real dispatch E2E** (`economy_full_sequence_through_dispatch`): drives the whole
|
||||
cluster through `try_handle_economy` + the bridge against a live in-process Core
|
||||
(fifa17 dev content, 100k coins) over the real blocking client, no fakes — Store
|
||||
BUY (pool+shape+debit+mint 5), credits, quick-sell, match WIN, market
|
||||
list→query→buy→query(sold)→second-buy-fails, cancel, move, + durable store reopen.
|
||||
|
||||
**Not flipped:** `classify()` still routes every economy route to Python. Per the
|
||||
single-writer rule the flip is one coherent barrier once ALL writers+readers are
|
||||
implemented and Core is seeded — a partial flip would desync coins.
|
||||
proven — a partial flip would desync coins.
|
||||
|
||||
**Remaining before barrier:** (1) sync↔async **Server wiring** for the new handlers
|
||||
(market/store handlers are `async` over sqlx `runtime-tokio`; the host `Server` is
|
||||
sync — needs a tokio runtime bridge in dispatch) + `classify()` routes for the new
|
||||
writers/readers; (2) real host↔Core **writer E2E** in `tests/economy_integration.rs`
|
||||
(Store BUY/open/quick-sell/market-buy/move against a live Core + disposable DB,
|
||||
extending the existing reader/match harness); (3) **Python-oracle differential**
|
||||
runner (subprocess, isolated fixture, 13 ops); (4) **host-level concurrency matrix**
|
||||
across the new handlers; (5) importer disposable-DB apply/restart/idempotency; then
|
||||
the single **classifier barrier** + no-Python-fallback / writer-unreachable /
|
||||
stale-reader proofs. Retire in-memory `ProfileEconomy` from any prod path.
|
||||
**Remaining before barrier:** (1) **Python-oracle differential** runner (subprocess,
|
||||
isolated fixture, all ~13 ops, PARITY / DIFFERENT-BY-DESIGN); (2) **host-level
|
||||
concurrency matrix** through real dispatch (two-BUY / dup-open / dup-sell /
|
||||
two-buyers / reward+BUY / move+sell / id-collision, 50–100 iterations); (3)
|
||||
**failure-injection** seams (Core failure at each step → no debit/grant/double);
|
||||
(4) **importer** disposable-DB apply / idempotency / restart; (5) `from_config`
|
||||
attachment of `EconomyServices` + `classify()` barrier flip; then no-Python-fallback
|
||||
/ writer-unreachable / stale-reader / NEVER-BOTH proofs. Retire in-memory
|
||||
`ProfileEconomy` from any prod path.
|
||||
|
||||
**Two market-handler correctness gaps to close before the barrier:** (a) the
|
||||
synthetic-seller buy mints `listing.card_id`, which `handle_market_list` sets to the
|
||||
numeric wire `resourceId` string — a real Core `card_id` requires a resourceId→card_id
|
||||
mapping (Core's content preflight rejects an unmapped mint on reboot); (b) `GET
|
||||
/purchased` reveal needs a last-opened cache (POST returns metadata; items are polled
|
||||
via GET) — Store BUY (open-on-buy) already returns items inline, so this only affects
|
||||
owned reward-pack (pack 70) opens.
|
||||
|
||||
Reference in New Issue
Block a user