developmentseed / developmentseed/titiler-covjson
`_resolve_unread_bands` counts an alpha band the read drops
- Dominant language
- Python
- Stars
- 1
- Forks
- 1
- Avg merge
- 2d 1h
- Merged PRs (30d)
- 12
Description
`_resolve_unread_bands` derives band metadata from `info.band_descriptions`, which covers every band in the dataset. A read does not: `rio_tiler.reader.read` does `if indexes is None: indexes = non_alpha_indexes(dataset)`, dropping an alpha band. So on an alpha source with no band selector the two resolvers disagree about which bands exist.
## Measured
On a 4x4 RGBA COG (red, green, blue, alpha), no band selector:
```text
_resolve_unread_bands (all-outside multipoint path): ['b1', 'b2', 'b3', 'b4']
_resolve_read_bands (every successful read): ['b1', 'b2', 'b3']
```
## Why it matters
The two resolvers are the only sources of band metadata, and which one runs depends on the outcome of the read rather than on the request. `_resolve_read_bands` runs for every successful read; `_resolve_unread_bands` runs for a `MULTIPOINT` on `/position` that sampled every position outside the dataset, where there is no read to resolve bands from.
So the same request against the same RGBA dataset yields a coverage with three parameters when at least one position lands inside, and four when none do. The extra `b4` is all-`null`, so nothing is mis-served, but a client diffing two responses sees a parameter appear and disappear based on where the points fell.
## Fix
`non_alpha_indexes` needs the open dataset, not `info`, so `_resolve_unread_bands` has to take the dataset (or the already-filtered indexes) to make the same exclusion. `_selected_band_count` already does this for the ceiling and can be read as the precedent.
Worth checking at the same time whether `band_info_from_reader_info` (`src/titiler_covjson/input.py`) should make the same exclusion, since it is the shared helper that walks `band_descriptions`.
## Test
Add an RGBA fixture and assert the two resolvers agree on it with no selector. The existing parity test (`test_unread_band_names_match_resolved_read_bands`) covers the two-band fixture across selectors and would extend naturally; it does not catch this today because no fixture has an alpha band.
## Priority
Low. It needs an alpha source, no band selector, and a multipoint that misses the dataset entirely; the divergent field is all-`null` either way.
Found while fixing #100, where the same `info`-vs-read gap caused the cell ceiling to over-count an RGBA read by one band and reject reads that fit. That half is fixed; this half is band *metadata* rather than the ceiling, with a different consumer, so it is filed separately rather than widened into that change.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with _resolve_unread_bands, _resolve_read_bands, and non_alpha_indexes, then read the existing test_unread_band_names_match_resolved_read_bands parity test. Add an RGBA fixture and check both resolvers with no selector and an all-outside multipoint. Done means both report the same non-alpha bands, including through the shared band metadata path if it requires the same exclusion.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend-api-design, testing
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 82/100