Skip to main content
The Trade Policy panel (internal id trade-policy) is the dashboard’s go-to surface for live trade-policy context — what’s getting restricted, where tariffs are moving, how flows are shifting, what barriers exist, and how US customs revenue is tracking as a real-time signal of tariff pass-through.

What the panel shows

Six tabs across one data-dense panel (defaultRowSpan: 2): TabId is the union 'restrictions' | 'tariffs' | 'flows' | 'barriers' | 'revenue' | 'comtrade' (src/components/TradePolicyPanel.ts:17). Panel id is trade-policy; canonical component is src/components/TradePolicyPanel.ts. Title resolves from i18n (panels.tradePolicy).

How you reach it

  • Cmd+K: type trade, tariff, or customs.
  • Availability by variant: registered and enabled by default in the full/geopolitical (priority: 1), finance (priority: 1), and commodity (priority: 1) variants. Not present in the tech or happy variants. Source: 'trade-policy' entries in FULL_PANELS, FINANCE_PANELS, COMMODITY_PANELS of src/config/panels.ts.

Data sources

Six response shapes from @/services/trade, each backed by a generated sebuf REST RPC in TradeService. The panel shell is free; tariff trends and Comtrade calls use premiumFetch because those two paths are premium transport paths, while restrictions, flows, barriers, and customs revenue use the public client. Customs revenue also checks the bootstrap cache key customsRevenue before falling back to the RPC. The revenue tab’s US-Treasury feed is particularly sensitive — see the changelog entry for “US Treasury customs revenue in Trade Policy panel” (#1663).

Trade-flow coverage

get-trade-flows is served entirely from the Railway seed; it never calls WTO per request. What that seed contains is the whole supported space:
  • Reporter — any 3-digit UN M49 code the WTO /reporters endpoint advertises. Empty defaults to 840 (United States).
  • Partner000 (World) only. The WTO indicators behind these rows, ITS_MTV_AX and ITS_MTV_AM, publish a World total and answer HTTP 204 for every named partner, so no bilateral pair is obtainable. Empty defaults to 000.
  • Years130, inclusive of both endpoints (years=10 returns 11 calendar years). The seed holds the full 30-year window per reporter and the handler slices it, so every lookback is served from the same fetch. 0 selects the default of 10.
A malformed code or an out-of-range years is rejected with HTTP 400 rather than silently replaced by a default. A well-formed request the seed cannot answer returns empty flows plus an unavailableReason from a closed vocabulary, so a coverage gap is distinguishable from a fault: unavailableReason is the TradeFlowUnavailableReason enum, so the closed set is discoverable from the OpenAPI schema rather than only from prose. Values are prefixed TRADE_FLOW_UNAVAILABLE_REASON_: Fleet-level coverage is published as the tradeFlows entry in /api/health, whose records count is the number of reporter/World pairs actually seeded; a shortfall reads COVERAGE_PARTIAL, while a stopped seeder reads STALE_SEED.

Tariff-trend coverage

get-tariff-trends is also seed-backed (premium path). The Railway seeder pre-fetches WTO MFN applied averages (TP_A_0010) and this API serves slices of that history — it never calls WTO per request.
  • Reporter — any 3-digit UN M49 code the WTO /reporters endpoint advertises. Empty defaults to 840 (United States).
  • Partner — accepted for forward compatibility; TP_A_0010 is an MFN applied average for the reporting economy and has no partner dimension, so this field never changes the answer.
  • Product sector — empty or all selects the All-products aggregate, which is the only sector currently covered. Any other value is answered NOT_COVERED.
  • Years130, inclusive of both endpoints (years=10 returns 11 calendar years). The seed holds the full 30-year window per reporter and the handler slices it. 0 selects the default of 10.
A malformed code or an out-of-range years is rejected with HTTP 400 rather than silently replaced by 840 / 10. A well-formed request the seed cannot answer returns empty datapoints plus an unavailableReason from the TariffTrendUnavailableReason enum (prefixed TARIFF_TREND_UNAVAILABLE_REASON_): Fleet-level coverage is published as the tariffTrendsUs entry in /api/health (the series name is historical; the probe is the fleet seed-meta:trade:tariffs record). A shortfall against the min-record floor reads COVERAGE_PARTIAL; a stopped seeder reads STALE_SEED.

Refresh cadence

Per-tab fetches on mount and on tab switch; no polling. Upstream seeders run on varying cadences per dataset (tariffs daily, Comtrade monthly).

Tier & gating

Panel shell is free. No premium flag in variant registrations. The generated REST service is mixed: restrictions, flows, barriers, and customs revenue are public; get-tariff-trends and list-comtrade-flows are premium RPC paths and degrade to empty data without an entitled session or API key.

API reference

  • Trade service — full schemas and query parameters for the six tab-backing RPCs.