developmentseed / developmentseed/titiler-covjson

`_resolve_unread_bands` counts an alpha band the read drops

Open
#105 1 comment 0 reactions 0 assignees View on GitHub
chore
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.