Address review findings on the listAssets contract PR:
- Empty `?hash=` no longer collapses to "no filter" (which returned a full
unfiltered page); it now stays "" and is matched exactly, yielding an
empty page — consistent with the documented "malformed -> empty page"
contract. Omitting the param entirely still disables the filter.
- Guard `list_references_page` on `asset_hash is not None` (page + count)
so the present-empty vs omitted distinction is preserved.
- Add tests for hash normalization (uppercase/whitespace) and for the
explicit-empty -> empty-page behavior.
- Clarify the `include_public` comment: core reads are owner-scoped with no
separate public pool, so the flag is inert here; cloud enforces it in its
own service layer.