Skip to content

One sourceless object image per object + on-device image download (ADR 0018)#502

Open
brickbots wants to merge 1 commit into
mainfrom
worktree-object-image-download-docs
Open

One sourceless object image per object + on-device image download (ADR 0018)#502
brickbots wants to merge 1 commit into
mainfrom
worktree-object-image-download-docs

Conversation

@brickbots

Copy link
Copy Markdown
Owner

What & why

Two coupled changes, fully designed in ADR 0018 and the Catalog glossary (docs/ax/catalog/CONTEXT.mdObject images):

  1. Refactor the object-image model from two source-suffixed files per object (M31_POSS.jpg, M31_SDSS.jpg) to one sourceless image per object (<digit>/<image_name>.jpg). The runtime only ever displayed POSS (DM_SDSS was defined but never assigned), so the second file was pure cost. Survey provenance becomes a recorded-but-not-runtime-branched curation directive in object_images.source.
  2. New feature: an on-device Download flow (Tools ▸ Download Images) that replaces the SSH / python -m PiFinder.get_images step.

Highlights

Shared core — object_image_store.py
Centralizes the on-disk/CDN layout, sourceless resolve_image_name (with the common-name fallback that maps e.g. M 31 → its canonical NGC224 image), worklist_for_scope (All / single-catalog via DB; filter / observing-list via live objects → object_id → canonical image_name), and a 404-tolerant download_object_image. Collapses path logic that was duplicated across cat_images, get_images and gen_images.

Runtime

  • cat_images.get_display_image drops the source concept; orientation/overlay logic (ADR 0003) untouched.
  • object_details: dead DM_SDSS display mode removed.

Data

  • object_images gains a nullable source TEXT column (schema + committed pifinder_objects.db via ALTER — all rows NULL = uncurated, the intended initial state; no on-device DB migration). The importer leaves it NULL; gen_images reads it (NULL→POSS) and publishes one sourceless image per object.

On-device Download

  • App-owned ObjectImageDownloader (background worker thread + start/cancel/progress controller, created in main.py, survives screen navigation).
  • Tools ▸ Download Images scope picker → All Objects / Current Filter / Observing List.
  • Pre-flight: WiFi-client gate, missing count + size estimate + a quick CDN reachability check, then Download/Cancel.
  • A global status line under the title bar shows progress on every screen while a download runs (per design discussion). BACK leaves it running in the background; an explicit Cancel stops it, keeping files already downloaded. Idempotent — re-running a scope skips existing files.

CLI & migration

  • get_images.py rewritten as a thin CLI over the core (All / --catalog NGC). audit_images.py retired.
  • migration_source/v2.7.0.sh + migrations/v2_7_0_sourceless_images.py: rename legacy _POSS/_SDSS → sourceless (POSS wins when both exist); stdlib-only, idempotent, version-gated by pifinder_post_update.sh.

Decisions / deviations (flagged)

  • Status line = global chrome (under the title bar, all screens) — confirmed with the maintainer; implemented as an overlay in the shared screen_update() that does not reflow each screen's content, drawn only while a download is active.
  • Worker concurrency = conservative constant (4), not user config (v1).
  • Single-catalog scope is exposed via the CLI (pure DB query); the on-device picker offers the three app-relevant scopes. The core supports single-catalog, so an on-device catalog picker can be added later.
  • i18n: all new UI strings are wrapped in _(). Running full babel here produces an unscoped mega-diff (the committed .po files are already missing many prior features' strings), so extraction is left to the project's controlled release-time pass, consistent with current practice.
  • Screenshot: docs/.../Image_download_001.png is reused as a placeholder and should be refreshed to the new screen.

Validation

  • ruff check ✅, ruff format --check ✅, mypy PiFinder ✅ (no issues, 140 files).
  • New unit tests: core store, downloader controller, migration idempotency (31 tests). Full test_ui_modules sweep (259) — which constructs & exercises the new screen for all scopes — passes; smoke+unit suite (717) passes.
  • Migration verified by hand on a sample tree (POSS wins, SDSS removed, SDSS-only renamed, existing target kept, second run a no-op).
  • Docs build cross-refs verified (Sphinx not installed in this env for a full build).

🤖 Generated with Claude Code

…nload

ADR 0018: store and display exactly one survey JPEG per object, named
without a survey suffix (<digit>/<image_name>.jpg). Survey provenance
becomes a recorded-but-not-runtime-branched curation directive in
object_images.source.

- New shared core object_image_store.py: on-disk/CDN layout, sourceless
  resolve_image_name, worklist_for_scope (All/catalog/filter/list) and
  404-tolerant download_object_image. Collapses path logic that was
  duplicated across cat_images / get_images / gen_images.
- cat_images: sourceless resolution; get_display_image drops the source
  concept (orientation/overlay logic unchanged, ADR 0003).
- object_details: remove the dead DM_SDSS display mode (never assigned).
- object_images gains a nullable source TEXT column (schema + committed
  DB via ALTER); the importer leaves it NULL (uncurated). gen_images
  reads it (NULL->POSS) and publishes one sourceless image per object.
- On-device Download feature: app-owned ObjectImageDownloader (background
  worker thread + controller), a Tools > Download Images scope picker
  (All / Current Filter / Observing List), a preflight (WiFi-client gate,
  missing count + size estimate + CDN reachability), a progress screen,
  and a global title-bar status line shown while a download runs.
- get_images: rewritten as a thin CLI over the core (All/single-catalog).
  Retire audit_images.py (dev-only, hardcoded path).
- v2.7.0 migration renames legacy _POSS/_SDSS files to the sourceless
  name (POSS wins when both exist); idempotent and version-gated.
- Tests for the core, the controller and the migration; user docs
  updated for the on-device flow.

New UI strings are wrapped in _(); .po extraction is deferred to the
project's controlled release-time babel pass (per repo i18n practice).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant