BucketStorageRoot.fetch() compares remote and mirrored ETags at src/hflow/storage.py:550, and sync_into_mirror() may download an entire missing append-only tree at src/hflow/storage.py:610. Both can perform substantial network work without reporting why the local mirror changed.
Add module-level standard logging with bounded cardinality. Cache-layer decisions belong to HFlow because obstore cannot explain why HFlow chose a GET after its HEAD and sidecar comparison. Keep obstore transport and retry diagnostics in the underlying client.
Emit one DEBUG record when fetch() downloads because the payload is missing or stale, and no record for a cache hit. Emit at most one INFO summary from each sync_into_mirror() call that transferred one or more objects. The summary should report object count, bytes transferred, and elapsed duration. Do not log chunks, credentials, store_options, signed URLs, ETags, object names at INFO, or one INFO record per object.
Follow the logger and message style in src/hflow/ffmpeg/_binary.py:49 and its download record at src/hflow/ffmpeg/_binary.py:177. Extend the bucket behavior coverage in tests/test_storage.py. fsspec cache implementations are the nearby ecosystem pattern: cache decisions use a dedicated logger and cache statistics track hits, misses, and requested bytes.
Definition of done:
- A fresh or stale
fetch() emits one DEBUG refresh record; an ETag cache hit emits none.
- Synchronizing N missing objects emits one
INFO record containing N, total transferred bytes, and elapsed duration; synchronizing an already warm mirror emits no INFO record.
- Per-object and per-chunk work does not produce
INFO records, so log volume remains bounded per public operation.
- HFlow does not duplicate obstore request, response, or retry logging.
- Logging does not change locking, ETag sidecars, atomic publication, or return values.
- Tests assert observable levels, fields, and bounded record counts without testing logging-library internals.
- Run
uv run ruff check --fix, uv run ruff format, uv run ty check, and uv run pytest -q.
BucketStorageRoot.fetch()compares remote and mirrored ETags atsrc/hflow/storage.py:550, andsync_into_mirror()may download an entire missing append-only tree atsrc/hflow/storage.py:610. Both can perform substantial network work without reporting why the local mirror changed.Add module-level standard logging with bounded cardinality. Cache-layer decisions belong to HFlow because obstore cannot explain why HFlow chose a GET after its HEAD and sidecar comparison. Keep obstore transport and retry diagnostics in the underlying client.
Emit one
DEBUGrecord whenfetch()downloads because the payload is missing or stale, and no record for a cache hit. Emit at most oneINFOsummary from eachsync_into_mirror()call that transferred one or more objects. The summary should report object count, bytes transferred, and elapsed duration. Do not log chunks, credentials,store_options, signed URLs, ETags, object names atINFO, or oneINFOrecord per object.Follow the logger and message style in
src/hflow/ffmpeg/_binary.py:49and its download record atsrc/hflow/ffmpeg/_binary.py:177. Extend the bucket behavior coverage intests/test_storage.py. fsspec cache implementations are the nearby ecosystem pattern: cache decisions use a dedicated logger and cache statistics track hits, misses, and requested bytes.Definition of done:
fetch()emits oneDEBUGrefresh record; an ETag cache hit emits none.INFOrecord containing N, total transferred bytes, and elapsed duration; synchronizing an already warm mirror emits noINFOrecord.INFOrecords, so log volume remains bounded per public operation.uv run ruff check --fix,uv run ruff format,uv run ty check, anduv run pytest -q.