docs/BLACKROCK.md

RS-BLACKROCK: economy + world intelligence

The unified local app combines market research, persistent item/player watchlists and the existing Palantir world observer. It reads public game sources; it never buys, sells or operates characters.

Run and use

From this standalone package directory, run pnpm run start:blackrock, then open http://127.0.0.1:5197/ . Reuse the existing listener if already running. pnpm start without RS_BLACKROCK_ENABLED=1 permits on-demand research and local settings but disables recurring collection. Closing the browser leaves a running collector active. Stopping the process or sleeping the computer leaves observation gaps; no cron or login service is installed.

Search an item by name or ID, star it, and optionally enter an accumulation target. Search players and save them independently. Choose owned teams in Teams & data; nothing is assumed owned by default. Manual exact-name relationship corrections override assignments. Allies remain separate. Operations, Signals, Wealth, Catalog and Agent API remain under More. World retains the actual renderer, camera controls, independent monitors and shared observation area.

Every section distinguishes source fetch time from unknown source publication time. Public bank previews include at most 50 accounts and six item previews each. A missing account or item is unknown, not zero. Targets use observed owned quantities; an exact purchase deficit is never calculated from these previews. Changing ownership starts a new history scope; prior observations retain membership at collection time.

Shared agent interfaces

All three clients use the same loopback service/database:

sh
1pnpm run blackrock -- search 'steel bar'
2pnpm run blackrock -- watch-item 2353
3pnpm run blackrock -- target 2353 100000
4pnpm run blackrock -- item 2353
5pnpm run blackrock -- buy-demand 1629 --days 1
6pnpm run blackrock -- player ExampleMiner
7pnpm run blackrock -- research quote --identifier 2353 --days 7
8pnpm run blackrock -- research production --recipe smelt:cannonballs
9pnpm run blackrock -- collector
10pnpm run blackrock -- export
11pnpm run blackrock -- import saved-watchlist.json --dry-run
12pnpm run mcp

The MCP exposes the original 22 world tools, ten market research tools, and 16 additional watchlist/search/ownership/history tools (48 total). The standalone rs-market and rs-blackrock Python commands remain compatible and independent; their settings are not automatically synchronized with the unified app. Import the old report's JSON favorites through Teams & data. Do not copy another page's browser storage or assume it is shared.

HTTP contracts

Base /api/blackrock/v1. Success {schemaVersion:1,data}; error {schemaVersion:1,error:{code,message,retryAfterSeconds?}}. /research/* preserves the original engine payloads. Request JSON limit 8192 bytes. Local Host and Origin checks apply.

RouteMethod / input
/searchGET q
/watchlistGET
/watchlist/quotesGET ids=2,2353 (1–60 IDs); local saved observations only, active watches; bid/ask, sampled 24-hour bid change and independent read/source timestamps
/buy-demandGET itemId,days?,refresh?; aggregate demand, explicit unavailable buyer identity, illustrative net seller quote
/items/watchPOST {itemId,note?}; DELETE ?itemId=
/items/:idGET combined quote/holders/target
/items/:id/targetPUT `{quantity:positiveInteger
/playersGET name with public profile, bank preview and local dossier
/ownershipGET projection; PUT {name,relationship,note?}; DELETE ?name=
/owned-teamsPUT {teamIds:string[]}; empty array clears selection
/ownership/exportGET explicitly marked private ownership export
/collectorGET status, jobs, errors and budget
/refreshPOST `{kind:'item'
/historyGET kind,key,from,to,resolution?,sourceKind?,scopeKey?,cursor?,limit?
/history/exportSame filters, NDJSON capped at 100,000 rows with resume cursor
/trade-historyGET itemId,days; completed trades, not orders
/watchlist/exportGET versioned favorites/targets/notes, ownership excluded
/watchlist/importPOST versioned JSON or legacy {snapshotId,itemIds}, ?dryRun=true supported
/sprite/:id.pngGET allowlisted same-origin PNG fallback
/research/:operationGET lookup,quote,history,opportunities,conversion,time-value,recipes,production,bank with pinned engine arguments

/api/watches continues to manage player watches. Default export excludes ownership. Rich imports have at most 100 records per batch; legacy imports at most 1000 IDs. UI splits at record and byte boundaries and previews conflicts. Contradictory nonempty local settings are preserved. Successful earlier batches remain if a later batch fails; rerunning is idempotent.

Sources and collection

Market engine is vendored under tools/market with SHA-256 provenance; Python standard library only. Set RS_BLACKROCK_PYTHON if Python is not on PATH. The Bun service owns bank/profile parsing and the sole public-read coordinator, including legacy public profile/wealth requests. The collector calls services directly, never localhost HTTP, and does not activate the world feed.

Research requests share 120 starts per rolling five minutes, one in flight and at least one second between starts; starts persist across restart. Due collectors receive a turn after at most three interactive permits. Cached banks/profile pages remain cached five minutes, including manual refresh. Quote freshness expires after ten minutes; bank/profile freshness after fifteen minutes; original timestamps survive cache hits. A recent fetch does not make an old trade recent. Missing/future timestamps cannot be fresh. Operations ownership projection refreshes each minute from existing sources without forcing upstream refresh.

Each saved entity targets a five-minute cadence. Transient errors back off from five minutes to one hour with jitter and longer Retry-After honored. Schema/authentication/input errors suspend until manual retry. Whole research operations have a two-minute deadline; worker HTTP permits have a 25-second watchdog. Partial/failing source sections remain independently labeled.

History and recovery

Additive tables share data/intel.sqlite. First migration creates a consistent data/intel.sqlite.before-blackrock-v1.sqlite backup. Source backup was also taken before implementation. Do not copy a live SQLite file without its WAL or use a filesystem copy as a consistent backup.

Detail lasts 90 days; atomic daily rollup then deletion runs in batches of at most 1000 rows. Summaries expire strictly after UTC day end + 365 days. Settings, notes, watches and targets do not expire. Failed summarization retains detail and exposes retentionError. History is sampled evidence, not a complete transaction or ownership log. Scope keys distinguish source/query/ownership changes. Cursor conflicts return 409 and require restarting the history query. Explicit daily boundary buckets disclose when they include samples outside the requested interval.

Rollback: stop this observer, retain the current database and source backup, then restore the prior source if needed. New tables are additive; old world data remains. Disabling collection with RS_BLACKROCK_ENABLED=0 preserves all observations and settings. Never overwrite the current DB with the migration backup without separately preserving post-migration world observations.

Economic interpretation

Bid is a possible seller exit; ask is an acquisition quote. Aggregate buy/sell quantity includes all price levels and is not executable depth at the best price. Seller tax is included in the original engine. Completed trade history is available; individual historical orders, owners and depth are not. Definition GP in banks is not market value. Mixed-output acquisition and alternative production income matter; respawn alone is not bank-to-bank throughput. 400ms ticks are a source default, not measured live. No exposed source establishes monetary inflation or guaranteed rare-item appreciation.

Verification

pnpm run check checks TypeScript, backend/CLI/UI-model tests and the production build. pnpm run mcp:check initializes all tools and exercises read-only old/new routes. Python regressions: cd tools/market/scripts && python3 -m unittest discover -p 'test_*.py'. bun scripts/benchmark-blackrock.ts uses an isolated temporary database and disabled collection; never run fixtures against the real DB. See blackrock-benchmark.json and BLACKROCK-VALIDATION.md for actual measured results and browser checks.

Identify buying demand

market_buy_demand(item_id, days=1) returns best bid, aggregate requested quantity and committed GP, sell availability, completed volume/fills, source timestamps, and a conservative per-unit seller proceeds scenario. It cannot name buyers. The linked market hash item=1629 selects Uncut red topaz; days=1 selects 24-hour trade metrics, while sort=buyValue ranks outstanding committed GP, not completed buying or one buyer. offset changes the overview page only. range selects the chart range. No order-owner endpoint is exposed by the inspected public contract. Never infer a buyer from the bank leaderboard or a bank balance change.

Frosted modes and market charts

The application mode switch explicitly selects RS-PALANTIR (map/world, original runite logo) or RS-BLACKROCK (market/economy, owner's black image 2). Expanded map mode retains the Palantir logo and a Blackrock return button. The original world renderer and bridge protocols are unchanged.

Market analytics use the installed @whop/react/components Frosted cards, Radix-based segmented controls, selects, buttons, tooltips and tables. Recharts renders the plots; Frosted UI does not ship a chart renderer. No shadcn wrapper remains. Price/high/low and volume charts use completed UTC buckets with local-time labels; absent price buckets remain gaps. Open-interest bars toggle units/GP and represent aggregate quantities/values across all prices. Tracked bid/ask charts use the latest market-quote scope over 24 hours (maximum 1,000 samples), with gaps over 10 minutes and failed reads breaking the line. Item selection, 24H/7D/30D/90D controls, refresh, source fetch times and an exact trade-data table are available. Any researched item also has a Charts tab; the dashboard offers core supplies plus saved items.

Exchange navigation and market board

The persistent Frosted mode dock sits outside the native world chrome. Each mode remembers its last section for the current page session. Both workspace trees remain mounted when switching modes, preserving the research query, selected item/player, detail tab, chart controls and map renderer/camera. A context button returns directly to the other workspace. Item → holder research has a clickable trail; holder previews have a Locate in Palantir action, and map player dossiers have Research holdings. Switching is observation-only; it does not issue gameplay commands. These transient navigation states survive mode switches, not a full page reload.

The exchange board uses /api/blackrock/v1/research/overview?sort=buyValue&days=1&offset=0, a bounded 25-row read through the existing coordinator and Python worker. Available sorts: buyValue, volume, value, sellRecent, rises, falls. Days: 1, 7, 30, 90; offset: integer 0–10,000. The visible board auto-checks every 60 seconds, with a pause control, and respects existing source caches/rate limits. This is a timestamped public snapshot, not a tick-by-tick trading feed. Market rank sorts are source rankings, not investment recommendations. Aggregate quantities remain distinct from depth at the displayed bid/ask. Source updated/fetched times remain visible.

Holder concentration uses only exact item matches with numeric nonnegative quantities from returned public bank previews. Duplicate account names are counted once (largest observed matching quantity). The largest-holder share uses the observed sample as denominator, never the entire game economy. Private carried inventory and order-owner attribution remain unavailable.

Finding the original market tools

BLACKROCK defaults to Economic intelligence (#economy); Teams & data can set a preferred landing page. Six primary groups organize the existing tools: Intelligence; Exchange (orders, Opportunities, Charts & history); Watchlists; Supply & holders (Bank holders, Players & fleet); Production (recipes, Time & conversion); Research & data (Original report, API & data). See the implementation handoff for the code map, saved views and regression checklist. Explicit workspace navigation clears a hidden item selection/search so selecting Exchange always brings the market board back. Switching between Palantir and Blackrock still preserves research context.

Exchange searches all source items and pages its original bid/ask/quantity/value rows; it is not limited to favorites. Opportunities is a separate on-demand scan. Bank holders searches public Bank Hiscores directly without saving an entity. Time & conversion exposes acquisition time and the original ore-to-bar calculator. API & data lists the underlying JSON routes with CLI/MCP examples. Exchange pages and entity dossiers offer original JSON exports, preserving source timestamps and coverage.

The Original report destination now explains research export options. Personal historical captures are not bundled in this standalone distribution. Saved watches and locally generated exports belong to each installation.

Direct links /#economy, /#market, /#opportunities, /#charts, /#holders, /#production, /#economics, /#watchlists, /#fleet, /#reports and /#tools open their respective workspaces on initial load. Explicit ?follow= / ?cx= links retain Palantir entry behavior.

Shared Palantir fleet

Players & fleet reads GET /api/blackrock/v1/fleet, using the same cached friendlies() identity registry as /api/friendlies, plus explicit assignment members and saved watches. It defaults to Palantir friendlies; All known identities and Saved players only are separate roster scopes. Search covers the full roster; rendering is paged in groups of 60. Names use Palantir's normalized identity matching for roster deduplication, and conflicting aliases stay unclassified. A roster entry does not establish online status or subscribe the player to collection.

The friendly registry includes allies. My bots requires selected owned teams under Choose my teams / Teams & data, or manual relationship corrections. Watching does not assign ownership. Missing/stale assignment sources remain unknown, and source errors are displayed. No teams are selected automatically. Public profile/bank enrichment happens on selection or for existing saved watches, not for every roster row.

The same read is available as pnpm blackrock fleet and MCP research_fleet. /search also includes shared friendly identities, allowing discovery before a watch is created.

Exchange order views

The Exchange has Recent trades, Buy orders and Sell orders tabs. Buy orders use public buyValue ranking (outstanding committed GP); Sell orders use sellRecent (latest active sell listings). Recent trades show each item's latest completed trade, not an individual execution tape. Ask/bid prices, total quantities, committed/asking values, latest sell listing and trade timestamps come from the public overview. The window changes trade statistics, not the age of current open orders. Market-wide summary cards retain upstream totals even when an item query is active.

The table loads 25-row batches automatically as its bottom approaches the viewport, deduplicates item IDs across changing snapshots, keeps existing rows on a load failure and offers retry. The end of the returned result set is explicit. Switching query/tab/window resets the feed; opening an item and returning preserves it. Auto-check runs every 60 seconds only on the first batch at the top; multi-batch browsing is held until manual refresh to avoid reordering under the reader. Source timestamps and raw loaded pages remain available.

Last listed means the upstream lastSellAt; Last visited is a browser-local timestamp recorded when an Exchange item, holder link or chart is opened. Visits retain up to 2,000 item IDs and are not shared across accounts/devices. Public aggregate books do not expose trader names, individual orders or best-price depth. No orders are placed by these views.

Interactive Exchange and opportunity research

The ranking selector applies across the source API; column-header sorting applies to currently loaded rows and keeps missing values last. Category filters and rarity focus also operate on loaded rows; infinite scrolling continues to retrieve more. Research baskets distinguish selected clue rewards/collectibles, end-game gear and clue-farming supplies. The rarity guide documents editorial/name-based tags and pinned reward sources; no tag establishes deployed odds or total supply.

Watch/Unwatch in market and opportunity rows uses the shared service watchlist. Ask AI opens a prepared, editable question with current source evidence; it does not submit automatically. Search queries, selected item IDs, source times, filters and bounded candidate samples travel with that question. Existing drafts are preserved. Opportunity goals and an optional GP planning budget guide AI research when the user sends; the rule-based scan remains deterministic. Up to ten candidates per group are shown, with visible shortlist export and holders/chart shortcuts.

Economy, swarm research and mission simulator

See the intelligence guide for the new views and shared HTTP/CLI/MCP interfaces. Mission execution currently uses a simulator; live gameplay dispatch is unavailable.

Watchlist quote overview

Watchlists shows observed bid and ask, sampled 24-hour bid change, and read age directly in saved item rows. Visible items load in sequential batches of at most 60 and refresh from the local service every 30 seconds while the item watchlist is active. This endpoint does not request or schedule public-market data; the existing collector remains responsible for acquisition.

Change compares the latest usable bid with the closest same-scope sample at or up to 30 minutes before 24 hours earlier. The observation itself must also have been recorded near that historical window. It is a sampled quote comparison, not an executed-price return. Missing history, zero comparison bids, stale reads and errors produce Unknown, not an estimated percentage. Cached/failed refreshes retain original timestamps. Source update time may be unknown even when the local read was recent.