Fix commodity comparison data completeness, freshness, and evidence claims

Author: koala73Created Sep 10, 2026Updated Sep 10, 2026

Outcome

Make the Country Brief commodity comparison use complete, traceable trade evidence and accurately disclose missing data and route-model coverage. The current feature can omit major exporters and present old, incomplete, or overly broad commodity evidence. It must not imply procurement readiness from a rendered comparison.

Related: #7982 introduced the comparison; #7985 repairs presentation and adds labelled UI screenshots. Neither PR repairs the data defects below.

Evidence and limits

Audit date: 2026-09-10. Findings below combine source inspection with read-only production Redis GETs through the existing loadEnvFile / readSeedSnapshot helpers. No cache writes, refreshes, or seed runs were performed. These are dated cache observations, not proof of the deployed authenticated API response. Re-read the current state before implementing or claiming recovery.

The screenshots on the related PRs use controlled e2e/country-brief-design-fixtures.ts values (US 30%, Qatar 60%, unknown origin 10%, year 2024). They prove rendering/export behavior only, not live shares, freshness, or completeness.

1. Confirmed: country-code mapping silently drops real suppliers

  • Japan HS2804, observation year 2024: cached partner 842 has empty partnerIso2 and share 0.392 (39.2% of import value).
  • scripts/seed-comtrade-bilateral-hs4.mjs resolves partners using UN_TO_ISO2[pc.padStart(3, '0')] ?? '' from scripts/shared/un-to-iso2.json. That registry uses standard code 840 for US, while Comtrade uses 842 in this response.
  • scripts/shared/comtrade-reporter-overrides.json already records US=842, FR=251, NO=579 (and additional overrides), but that knowledge is not applied to this partner projection.
  • buildCommodityBrief in src/utils/decision-brief.ts discards rows without a two-letter uppercase ISO code. Consequently this comparison omits the real 39.2% US row. Cached France and Norway examples also have empty ISO codes.

Required repair:

  • Establish one correct Comtrade partner normalization path using verified provider semantics; preserve standard-code behavior and handle special/aggregate partners explicitly. Do not blindly treat all numeric codes as countries or assume every reporter override is valid for every partner record without checking.
  • Trace both scheduled and lazy producers and all readers needed by this comparison. Fixing future seeds alone is insufficient: existing cached rows must recover safely through a compatible reader or a documented, verified cache migration/refresh.
  • Retain the original partner code and provenance. Report unresolved/excluded coverage rather than silently presenting the surviving rows as a complete comparison.
  • Do not renormalize the remaining displayed shares to 100% and hide the missing denominator.

2. Confirmed: country/product coverage and freshness are uneven

Observed cache state:

Country Country cache fetched at (UTC) Heading count Relevant coverage
Japan 2026-09-01 06:05:21 36 HS2804 present, trade year 2024
US 2026-09-01 06:03:36 36 HS2804 present, trade year 2024
Germany 2026-07-27 16:47:53 20 HS2804 and HS2836 absent; wheat observations from 2023

seed-meta:comtrade:bilateral-hs4 reports 160 country keys and status ok; Germany appears in preserveStreaks. Aggregate key count/health does not establish country/product completeness. An older trade year is not by itself a provider failure; distinguish publication lag from stale fetching and missing requested headings.

Required investigation and repair:

  • Reproduce why Germany retained the older, smaller result. Trace batching, fallback periods, freshness gates, preservation, and lazy retrieval. Do not assume the cause from metadata alone.
  • Preserve last-good data on provider/cache errors. Distinguish valid empty results, unavailable upstream, missing product coverage, malformed rows, and preserved older data.
  • Carry observation year, retrieval time, source, and usable coverage through the actual reader/service/capture path. Show these distinctions in the preview and exports, without interpreting missing data as zero trade/exposure.
  • Make health/diagnostics reveal persistent country/product gaps. Do not weaken freshness/coverage gates to obtain a green aggregate status.

3. Confirmed: “Unknown route” is a model gap, not absence of trade

src/utils/supplier-route-risk.ts obtains modeled paths by intersecting importer/exporter nearestRouteIds. The current US and Japan sets do not intersect, so a real US–Japan trade relationship has no modeled route.

Required work:

  • Measure route coverage for the actual candidate origins in representative selections, including US–Japan and Qatar–Japan.
  • Add or correct paths only where geography, transport assumptions, and supporting evidence justify them. Keep unresolved pairs explicitly unknown and distinguish modeled paths from observed shipments.
  • Do not label an unmodeled route safe. Absence of the selected chokepoint from a modeled path does not establish a usable alternative or spare capacity.
  • Keep the origin-blockage constraint: a downstream Suez/Cape detour cannot bypass an origin blocked at Hormuz. Do not imply that an unordered set of modeled chokepoints is an observed transit sequence.
  • If broader route coverage cannot be established in the first repair, document the measured residual coverage and leave that acceptance item open; do not hide it with a generic safe-route default.

4. Confirmed: HS2804 cannot establish helium-specific supplier shares

The cache description is Helium, but HS2804 is a broader customs basket. Its value shares cannot establish helium-specific supply or hospital procurement shares. The builder has a caveat, and #7985 makes the mapping caveat visible beside the title; the underlying evidence remains broad.

Required work:

  • Review each exposed commodity-to-heading mapping, including helium, wheat, and lithium, for scope and specificity.
  • Use an accurate basket description, units, observation period, and mapping qualification consistently in the source data, preview, action text, and HTML/JSON exports.
  • Investigate whether a sufficiently specific provider series is available for helium. If not, retain an explicitly labelled proxy and prevent helium-specific share claims. Do not fabricate a more specific estimate from HS4 totals.
  • Recorded origin-country trade is not a qualified vendor list. Capacity, material qualification, price, transport mode, and delivery time remain unknown unless separately sourced. Do not invent these fields to fill empty UI sections.

Implementation entry points

  • Producer and mappings: scripts/seed-comtrade-bilateral-hs4.mjs, scripts/shared/un-to-iso2.json, scripts/shared/comtrade-reporter-overrides.json.
  • Reader/lazy path: server/worldmonitor/supply-chain/v1/get-country-products.ts, server/worldmonitor/supply-chain/v1/_bilateral-hs4-lazy.ts. Inspect downstream consumers before changing the shared cached shape.
  • Capture and claims: src/services/decision-brief.ts, src/utils/decision-brief.ts, src/types/decision-brief.ts, src/components/CountryBriefOutput.ts.
  • Routes: src/utils/supplier-route-risk.ts and the route/port-cluster registries it consumes.
  • Health: api/seed-health.js and existing bilateral-HS4 metadata/health contracts.

Agent execution plan

  1. Refresh main/head, read AGENTS.md and CONTRIBUTING.md, run the appropriate preflight, and reproduce each defect with sanitized fixtures before changing shared behavior.
  2. Fix partner normalization and existing-cache compatibility first. Then diagnose and repair preserved/missing coverage and freshness propagation. Keep each change reviewable; split dependent PRs if needed and link them here.
  3. Correct commodity claims and address supported route coverage. Preserve explicit unknowns for unavailable evidence.
  4. Run focused tests, then required affected checks. Inspect the real rendered comparison with the repaired service payload, not only hand-authored UI fixtures.
  5. Document the cache recovery procedure, its validation and rollback. Production writes, seed runs, merge, and deployment require separate explicit authorization; this issue is not authorization for those actions.
  6. After authorized recovery/deployment, attach dated, sanitized evidence from the actual API/UI path and compare it with the cache/source. Keep locally verified, CI passed, deployed, and live acceptance separate.

Acceptance checklist

  • US 842, France 251, Norway 579, standard codes, unknown codes, and aggregate partners have behavior tests; no real country is silently lost because of a known provider-code mismatch.
  • A legacy cached JP2804 fixture with empty ISO/842 preserves the US row and its original 39.2% share through reader → capture → builder → preview/export. New ingestion produces the correct ISO.
  • Missing/excluded coverage is explicit; shares retain their original denominator and are not inflated by filtering.
  • Germany's smaller preserved cache is explained and the demonstrated recovery defect is fixed. Missing headings, valid empty data, provider failure, and stale preserved data remain distinct.
  • Trade observation year and fetch age are independently visible/traceable. Health can identify persistent country/product gaps despite an aggregate ok.
  • US–Japan and other representative route gaps are measured; supported repairs have evidence. Unresolved paths remain unknown, not safe, and Hormuz-origin blockage cannot be bypassed by a downstream detour claim.
  • Commodity basket/proxy limitations apply to labels, shares, actions, and exports. No unsupported helium-specific or procurement-readiness claims remain.
  • Existing HTML/JSON snapshot parity, mobile/desktop themes, accessible disclosure controls, and missing-data states still pass. Attach reviewed screenshots for any UI changes and label fixture versus live evidence.
  • Final report lists any unresolved route/provider/commercial-data limitations. Do not close the issue as fully accepted while checklist items remain unverified; link follow-up work explicitly.

Verification starting points

Use the existing relevant tests: tests/comtrade-bilateral-hs4.test.mjs, tests/comtrade-period-and-coverage.test.mjs, tests/seed-comtrade-bilateral-freshness-gate.test.mjs, tests/seed-comtrade-5xx-retry.test.mjs, tests/decision-brief.test.mts, tests/dom/decision-brief.test.mts, and e2e/country-brief.spec.ts. Add focused behavior coverage for the defects above, not source-string assertions that merely mirror the implementation. Run affected typechecks/boundaries and required repository checks using Node 24.

No credentials, raw environment values, or private user payloads should be included in evidence. The numerical cache observations above were explicitly authorized for publication in this issue by the repository owner.