Trade & store logistics: host-agnostic trade watchers (meets WatchTradeFeed/Display) #52
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
Trade watchers under the DiscordLink-replacement epic (#37), on the trades-ledger foundation (#6). DiscordLink ships
WatchTradeFeed(event stream to a DM) andWatchTradeDisplay(self-updating snapshot), plusUnwatchTradeFeed/DisplayandListTradeWatchers. Kai's epic thesis is that this read-only info belongs on the website, not Discord DMs, so this meets the watcher feature and exceeds it by making it host-agnostic.No-reset spine
Watchers evaluate against the
CurrencyTradehistory the server already exports - each poll diffs the newest trades against stored watch queries. No new C# mod, no server reset. Persist watchers in a small SQLite store, mirroring the fair-price cache pattern (~/.cache/eco-mcp-app/).Scope
The agent builds a host-agnostic trade-watcher subsystem:
WatchTradeFeed/ListTradeWatchers/UnwatchTradeFeed./traderoute (sibling) and are queryable via MCP, so a URL-connected host like claude.ai can ask "what did my watchers catch." No Discord dependency.DiscordLink parity
Meets
WatchTradeFeed,WatchTradeDisplay,UnwatchTradeFeed/Display, andListTradeWatchers. Exceeds by delivering to the website and MCP instead of Discord DMs, and by allowing a price-threshold predicate, not just a name match.Acceptance
ward exec smokepasses.respx-mocked unit tests for match logic and the last-seen advance.ward exec test/ward exec lintgreen.docs/FEATURES.mdupdated.Dependencies
Foundation: #6. Parent: #37. Surfaced in the
/tradeSPA route (sibling).🔒 Reserved by
ward agent --driver claude— containerengineer-claude-eco-app-52on hostKAI-DESKTOP-TOWERis carrying this issue (reserved 2026-07-05T03:27:44Z). 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 - host-agnostic trade watchers (eco_trade_watchers MCP tool + SQLite store + /trades SPA sidebar), landed on main, closes #52.
This one went smoothly, mostly because the trades-ledger foundation (#6) had already done the hard part. Watchers are just a stored query diffed against
ledger.tradeseach poll, so the whole subsystem is a pure match function plus a small SQLite store mirroring the fair-price cache. The feed-vs-display split fell out naturally: feed = matches newer than a last-seen mark, display = the current matching set, and the mark advance is the only stateful bit worth testing hard.The one real design call was where the last-seen mark gets consumed. I made MCP
evaluateadvance it (the feed semantic) but the SPA/preview/watchers.jsonpeek inadvance=falsemode, so browsing the website never eats a feed hit. That felt right but it's the part I'd want a second pair of eyes on.What fought back was purely mechanical:
mainmoved three times under me while I worked (stores #50, then market #49), so I resolved conflicts twice - once hand-resolving interleavedpreview_*_jsonhandlers and dispatch blocks in server.py/http_app.py, once a clean auto-merge. All green after each: 347 pytest, 38 vitest, smoke, ruff, mypy, precommit.Confidence is high on the logic and persistence. Rough edges / follow-ups worth filing: (1) watchers evaluate against one server's ledger per call - the stored
serverfield is metadata, not yet used to fan out per-server; (2) no SPA affordance to create/remove a watcher (MCP-only by design, but a small form could be nice); (3) the ledger is capped at the newest 4000 rows, so a long-quiet watcher's feed is bounded by that window, not truly unbounded.