Skip to content

fix(nisar): verify CMR UMM-JSON results against atom-JSON - #230

Merged
mgovorcin merged 1 commit into
opera-adt:mainfrom
mgovorcin:fix/cmr-umm-dropped-granules
Oct 22, 2026
Merged

mgovorcin merged 1 commit into
opera-adt:mainfrom
mgovorcin:fix/cmr-umm-dropped-granules

Conversation

@mgovorcin

Copy link
Copy Markdown
Collaborator

What

Since October 2026, CMR's granules.umm_json results are unreliable for the NISAR GSLC and GUNW collections:

  • Records counted in CMR-Hits are left out of the results.
  • Under some concept ids, UMM-JSON serves another granule's record. That granule then appears twice and the real one is missing. For example, G4246696294-ASF is NISAR_L2_PR_GUNW_023_055_D_066_... in atom-JSON and from search/concepts/, but UMM-JSON serves the record of ..._023_059_A_038_... under it.

On 2026-10-21, UMM-JSON served the wrong record for 13,769 of 155,910 provisional GSLCs and 12,607 of 89,932 GUNWs, and left out a further 198 and 6,024. The atom-JSON granules.json listing of the same query has every granule under its own name. The concepts endpoint returns the right record; echo10 does not.

This PR:

  • Adds fetch_cmr_pages(..., verify=True). It walks the same query in atom-JSON and drops UMM-JSON records whose GranuleUR disagrees with the atom title. It then re-fetches the missing and mislabelled ones: first from UMM-JSON by concept_id[], keeping only matching names, then from search/concepts/<id>. The result holds one record per granule name.
  • Adds CmrSearchReport, optional, which records the left-out, mislabelled, duplicate-name and unrecovered concept ids, for reporting them to CMR.
  • Retries CMR timeouts, dropped connections, 429 and 5xx with backoff, and gives every request a timeout. Previously requests had none.
  • Turns verification on for nisar.search and nisar.search_gunw. The DISP-S1 search is unchanged, because a sample of the newest 20,000 OPERA_L3_DISP-S1_V1 granules came back clean in both formats.

The same fix runs in opera-adt/nisar_db (#63, #65), which publishes the NISAR frame viewer.

Cost

Verification adds one atom-JSON page walk, plus one concepts-endpoint request per bad record. A California GUNW search (1,128 granules, 458 bad) took 138 s.

Verification

  • Live: search_gunw over California (-125, 32, -114, 42) returns all 1,128 granules. Without verification, UMM-JSON returned 1,096, and 426 of them carried another granule's record.
  • tests/test_cmr.py uses a fake CMR that leaves out, mislabels and duplicates records. It covers recovery, the report, keeping one record per name, retries, and non-retried 400s. The existing NISAR search tests switch the atom-JSON listing off with one fixture, since they check parsing and filtering.
  • pytest tests/test_cmr.py tests/test_nisar_search.py tests/test_disp_search.py: 42 passed; pre-commit clean. In my local pixi test environment, 13 unrelated tests fail identically on main without this change. They cover the projection library, stitching, the version check and aiohttp.

🤖 Generated with Claude Code

CMR's granules.umm_json leaves out NISAR records and serves another
granule's record under some concept ids (2026-10). fetch_cmr_pages(verify=True)
cross-checks names against granules.json, re-fetches the bad records by
concept id, keeps one record per name and can report CMR's errors; CMR
requests now retry timeouts and 429/5xx. Both NISAR searches use it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mgovorcin
mgovorcin merged commit bcddad9 into opera-adt:main Oct 22, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant