Trade & store logistics: live store-offer exporter mod [reset-gated, offline shell-harness build] #55
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
The one reset-requiring piece of the trade & store logistics push under the DiscordLink-replacement epic (#37), deliberately isolated so nothing else waits on a server restart. DiscordLink reads live store shelves in-process (it enumerates active
StoreComponentinstances and theirTradeOffer/Stackobjects). eco-app's server exports only historical trade events, not the current shelf, so fullTrades <item>parity ("what is listed right now, at what price, how much stock") needs a new in-game exporter. Every sibling issue is built to work from history today and to sharpen to live automatically once this lands.Why this is off the 2-hour clock
Loading a new C# plugin requires restarting the Eco server, which is exactly what Kai wants to avoid for a couple of hours of continuous play. This issue is therefore built and tested entirely offline against a C# shell harness, mirroring the pattern the jobs mod already uses (
mods/jobsships "a C# shell harness mirroring the API shape for local dev"). No live server is touched during development. The built DLL deploys at the next natural server restart, out of band, per the existing mod rollout pattern (#31 is the precedent for a mod-side push). Development can complete fully while the server keeps running.Scope
The agent builds
mods/stores(name the agent's call), a C# Eco server plugin that:StoreComponentinstances (viaWorldObjectManager.ForEach, the defensive pattern the telemetry mod already uses) and emits currentTradeOfferstate: item, buy vs sell, price, stock quantity, currency, store name, store owner, and location.GET /api/v1/stores- authed with the sameX-API-Keythe other admin surfaces use, returning JSON in a documented DTO. The DTO is the contract the Python store-directory and logistics siblings upgrade to./api/v1/stores(likemods/jobs) so the Python side and this plugin can be developed and tested with no live server.mods/stores/docs/and links it from the sibling issues so they can wire the live path.DiscordLink parity
This is the piece that takes the store-directory, logistics-engine, and watcher siblings from history-derived to shelf-accurate, fully matching DiscordLink's live
Trades <item>and live watch feeds - and still exceeding it, since the same data now feeds the website, MCP, arbitrage, and fair-value surfaces, not just a Discord embed.Acceptance
build-mod-*ward verb./api/v1/storesshape for local dev.mods/stores/docs/and cross-linked from the store-directory and logistics siblings.docs/FEATURES.mdupdated with the new mod.Dependencies
Independent to build (offline, shell-harness). Parent: #37. Deploy precedent: #31. Upgrades the store-directory, logistics-engine, and watcher siblings once deployed.
🔒 Reserved by
ward agent --driver claude— containerengineer-claude-eco-app-55on hostKAI-DESKTOP-TOWERis carrying this issue (reserved 2026-07-05T01:40:42Z). Concurrentward agentruns are blocked until it finishes or the reservation goes stale (2h0m0s TTL);--forceoverrides.Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).
— Claude (she/her), via
ward agent🔓 Reservation released by
ward container reap— containereco-app(--driver claude) exited without launching the agent (smoke-test death, ward#222/#264), so the hold it took is retracted. A plainward agentretry no longer needs--force.— Claude (she/her), via
ward agent🔒 Reserved by
ward agent --driver claude— containerengineer-claude-eco-app-55on hostKAI-DESKTOP-TOWERis carrying this issue (reserved 2026-07-05T02:54:43Z). Concurrentward agentruns are blocked until it finishes or the reservation goes stale (2h0m0s TTL);--forceoverrides.Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).
— Claude (she/her), via
ward agentWARD-OUTCOME: done - mods/stores live store-offer exporter (GET /api/v1/stores) + shell harness + DTO doc landed on main, cross-linked to #50/#51.
The agent leaned hard on the existing mods/jobs skeleton, so the scaffolding (two-project solution, shared DTOs, shell harness, ward/Makefile verbs) went down fast and clean, and every pre-commit hook passed first try. The one real decision was the real mod's StoreScanner: with no dotnet in the container the agent could not compile against Eco.ReferenceAssemblies, and the gaming-eco-investigation case library flags this exact StoreComponent -> TradeOffer -> Stack.Item chain as where orphaned stores and removed items throw NREs. So the agent wrote the walk as reflection by member name, fully null- and exception-tolerant, which both dodges API-name drift the agent could not verify and directly implements the documented skip-and-continue defense. That is the honest soft spot: the exact Eco member names (AllOffers vs Offers, CurrencyName vs Currency.Name, Buying, Position) are best-guess with fallbacks, so first contact with a live server may need a member name added to a candidate list. Reasonably confident the shell harness and DTO contract are correct and the reflection walk degrades gracefully rather than crashing. Deploy stays out of band at the next natural restart, exactly as the reset-gate intended. Follow-up worth filing: a quick member-name confirmation pass against the running server once it restarts.