Back to Worldmonitor

Trade Policy

docs/panels/trade-policy.mdx

2.10.07.7 KB
Original Source

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):

Tab idShows
restrictionsActive trade restrictions — the default tab on mount.
tariffsTariff trends (TariffDataPoint[]) and EffectiveTariffRate series.
flowsMerchandise trade flows, reporter versus World — GetTradeFlowsResponse.
barriersNon-tariff barriers — GetTradeBarriersResponse.
revenueUS Treasury customs revenue — monthly data with FYTD year-over-year comparison and spike highlighting.
comtradeFull Comtrade bilateral flow search — ListComtradeFlowsResponse.

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.

TabMethod + routeFeeds
restrictionsGET /api/trade/v1/get-trade-restrictionsWTO restrictions list with country filters and upstream-unavailable state.
tariffsGET /api/trade/v1/get-tariff-trendsPremium MFN applied tariff-rate timeseries for a reporting country (WTO TP_A_0010).
flowsGET /api/trade/v1/get-trade-flowsMerchandise trade-flow rows and year-over-year context, reporter versus World.
barriersGET /api/trade/v1/get-trade-barriersSPS/TBT barrier notifications filtered by country or measure type.
revenueGET /api/trade/v1/get-customs-revenueUS Treasury customs duties revenue; bootstrap-first via customsRevenue.
comtradeGET /api/trade/v1/list-comtrade-flowsPremium UN Comtrade strategic commodity flow search with anomaly flags.

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_:

SuffixupstreamUnavailableMeaning
UNSPECIFIEDfalseRows served.
NOT_COVEREDfalseWell-formed, but this reporter/partner pair is outside seeded coverage. Nothing is broken; retrying will not help.
SEED_MISSINGtrueThe pair is inside coverage but its cache entry is gone.
COVERAGE_UNKNOWNtrueThe coverage manifest could not be read, so neither of the above can be ruled out.
CACHE_UNAVAILABLEtrueThe cache read itself failed.
INVALID_REQUESTfalseCodes were malformed (only reachable where request validation is bypassed).

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_):

SuffixupstreamUnavailableMeaning
UNSPECIFIEDfalseDatapoints served.
NOT_COVEREDfalseWell-formed, but this reporter/sector combination is outside seeded coverage.
SEED_MISSINGtrueThe reporter is inside coverage but its cache entry is gone.
COVERAGE_UNKNOWNtrueThe coverage manifest could not be read.
CACHE_UNAVAILABLEtrueThe cache read itself failed.
INVALID_REQUESTfalseCodes were malformed (only reachable where request validation is bypassed).

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.