Skip to content

hls2: enumerate granules by _stac.json instead of the .jpg browse image - #378

Merged
DerekTan1 merged 2 commits into
mainfrom
tanderek/hls2-s30-stac-json-enumeration
Aug 5, 2026
Merged

hls2: enumerate granules by _stac.json instead of the .jpg browse image#378
DerekTan1 merged 2 commits into
mainfrom
tanderek/hls2-s30-stac-json-enumeration

Conversation

@DerekTan1

@DerekTan1 DerekTan1 commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Description

hls2-s30 stopped receiving new STAC items on 2026-06-16 and was ~7 weeks stale when this was found. hls2-l30 was unaffected.

Root cause is upstream. LP DAAC stopped publishing the .jpg browse image for HLSS30 granules between 2026-06-16 and 2026-06-18. Confirmed against NASA CMR (8 granules sampled per day):

date HLSS30 granules with .jpg
2026-06-10 8/8
2026-06-14 8/8
2026-06-16 8/8
2026-06-18 0/8
2026-07-01 0/8
2026-08-01 0/8

HLSL30 still publishes one, which is why hls2-l30 stayed healthy.

Both hls2 collections discovered source granules with chunk_options.ends_with: .jpg, so every post-cutover S30 granule became invisible to enumeration — never chunked, never turned into an item, never ingested. A representative granule:

S30/06/W/XC/2026/08/01/HLS.S30.T06WXC.2026213T212519.v2.0/
  .B01..B12.tif  .B8A.tif  .Fmask.tif  .SAA/.SZA/.VAA/.VZA.tif  .cmr.xml  _stac.json

20 files present, no .jpg. The corresponding chunk list contained 161 rows, every one a .jpg under 2026/06.

Change

Switch enumeration to _stac.json, which is present on every granule for both products, and rework create_item accordingly:

  • derive the granule base path from the _stac.json suffix rather than string-replacing .jpg
  • treat the browse image as optional — set the thumbnail href only when the .jpg actually exists, otherwise drop the asset
  • collapse the duplicated S30/L30 asset-verification branches
  • iterate over list(item.assets) when popping, which previously mutated the dict during iteration

Dependencies / related

  • Companion change in the internal monorepo removes .jpg from HLS2Scene.blob_names for S30, so assets_exist() can return True again (it requires every listed asset, so S30 granules were being treated as permanently incomplete).
  • The hls2-ingestion-pipeline Airflow DAG fetches dataset.yaml and hls2.py from main at parse time, so merging this is sufficient there — no image rebuild.
  • The pctasks hls2-s30-update / hls2-l30-update workflows must be re-registered (pctasks dataset process-items ... --upsert) after merge: ends_with and the hls2.py code-blob hash are both baked in at registration time.

Fixes # (no issue filed)

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Behaviour note: items for S30 granules produced after the upstream cutover no longer carry a thumbnail asset, because the source image no longer exists. Existing items are unaffected.

How Has This Been Tested?

datasets/hls2/test_hls2.py, run against production blob storage — 3 passed:

  • test_hls2_landsat — existing L30 granule, updated to a _stac.json asset URI; still yields 16 assets including thumbnail
  • test_hls2_sentinel — existing pre-cutover S30 granule (2025-01-05); still yields 19 assets including thumbnail
  • test_hls2_sentinel_without_browse_imagenew, a post-cutover S30 granule (HLS.S30.T06WXC.2026213T212519.v2.0, 2026-08-01) that has no .jpg; yields 18 assets, no thumbnail, and passes item.validate()
cd datasets/hls2 && PYTHONPATH=. pytest test_hls2.py -q
3 passed

The third test is the direct regression test for this bug: on main that granule cannot be enumerated at all.

Checklist:

  • I have performed a self-review
  • Documentation has been updated — the storage-layout comment in dataset.yaml and the inline comments in hls2.py explain why enumeration keys on _stac.json
  • Unit tests pass locally — pytest datasets/hls2/test_hls2.py (3 passed). ./scripts/test was not run because it requires Docker, which is unavailable in this environment
  • Code is linted and styled — flake8 datasets/hls2/ goes from 11 violations on main to 7 with this PR; the 7 remaining are pre-existing and untouched (long S30_assets/L30_assets literals, E302 on existing definitions). black would reformat these files, but it also reformats them on main, so it is left alone to keep the diff reviewable

"Changelog has been updated" deleted — this repo has no changelog and dataset changes do not use one.

Derek Tan added 2 commits August 4, 2026 18:46
LP DAAC stopped publishing the .jpg browse image for HLSS30 granules
between 2026-06-16 and 2026-06-18. Confirmed against NASA CMR (8 granules
sampled per day): 8/8 have a .jpg on 06-16, 0/8 from 06-18 onward. HLSL30
is unaffected and still publishes one.

Both hls2 collections discovered source granules with
`chunk_options.ends_with: .jpg`, so every post-cutover S30 granule became
invisible to enumeration: never chunked, never turned into an item, never
ingested. hls2-s30 has had no new STAC items since 2026-06-16 (~7 weeks)
while hls2-l30 stayed current.

Switch enumeration to _stac.json, which is present on every granule for
both products, and rework create_item accordingly:

- derive the granule base path from the _stac.json suffix rather than
  string-replacing '.jpg'
- treat the browse image as optional: set the thumbnail href only when the
  .jpg actually exists, otherwise drop the asset
- collapse the duplicated S30/L30 asset-verification branches
- iterate over list(item.assets) when popping, which previously mutated the
  dict during iteration

Tests updated to pass _stac.json URIs, plus a new case covering a
post-cutover S30 granule that has no browse image. All 3 pass against
production blob storage.
Wrap the regex, add noqa/spacing on the new test, and add the missing
trailing newline. Pre-existing violations elsewhere in these files are
left alone to keep the diff focused: datasets/hls2 goes from 11 flake8
violations on main to 7 with this PR.
@DerekTan1
DerekTan1 merged commit e73b20e into main Aug 5, 2026
5 of 6 checks passed
@DerekTan1
DerekTan1 deleted the tanderek/hls2-s30-stac-json-enumeration branch August 5, 2026 14:40
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.

2 participants