Skip to content

feat: surface the pinned container image in the CLI and UI - #486

Merged
cswaney merged 3 commits into
mainfrom
feat/surface-image-version
Aug 21, 2026
Merged

feat: surface the pinned container image in the CLI and UI#486
cswaney merged 3 commits into
mainfrom
feat/surface-image-version

Conversation

@cswaney

@cswaney cswaney commented Aug 21, 2026

Copy link
Copy Markdown
Member

Summary

  • CLI: adds a VERSION column to blackfish ls and blackfish batch ls showing the image tag, and the full repo:tag to blackfish details <id>. Tag only in the tables because batch ls --all already renders at 141 chars — past a standard 120-wide terminal — and the full reference would add ~45 more. Named VERSION rather than IMAGE since IMAGE in the services table already means the service type (text_generation).
  • UI: adds an Image row to the service summary and the batch job details panel. image_ref is NULL for anything created before the migration or never launched, so every site falls back to a dash. Memory gets its own CircleStackIcon, since Image now uses the cube it was previously sharing.
  • Presentation only. Both GET endpoints already serialize image_ref (full ORM objects, no DTO), and every CLI command fetches over the HTTP API — so no backend, serializer, or migration work was needed.

Second commit aligns the job-detail value rows: revision now gets the same monospace/truncated treatment as model and image, and the cutoff widens 200px → 320px. At text-xs monospace a commit SHA is ~264px and a full image reference ~271px, so both were truncating at a width originally sized for repo_id (~152px), inside a 768px panel.

Part of #212. Follow-ups: GET /api/images discovery (#482) and the launcher selectors (#483).

Test plan

  • uv run just lint / just test — 923 passed, 7 skipped; MyPy strict clean. Coverage unchanged at 70%.
  • npm run lint / npm test — 513 passed, 0 lint errors (one pre-existing warning in an untouched file).
  • New UI tests: the service summary renders the tag with the full reference as a title, and a dash when unset; the job panel shows the row for a pinned job and omits it when nothing was recorded. ServiceSummary snapshots updated — reviewed the diff to confirm it is purely the added row, in both the loaded and no-profile branches.
  • Verified against live data rather than fixtures only. The local database has both populated and NULL rows, so the fallback is exercised for real:
0b87cc9d-2974   detect       0.1.1   facebook/detr-resnet-50   ...   detect - test
2af13d86-9b9a   chat         -       google/gemma-3-4b-it      ...   chat-gemma-3-4b-it
$ blackfish details 6e363ef2-...
    "image": "text_generation",
    "image_ref": "vllm/vllm-openai:v0.20.0",

Worth noting: two existing services already show v0.20.0 because they were launched after #480 merged — the backfill populated them in normal use, so this confirms the record is being written as well as displayed.

  • Both tables remain readable at the new width (147 / 151 chars), and NULL renders as - rather than None or an empty cell.

Closes #481.

Add a VERSION column to `blackfish ls` and `blackfish batch ls` showing
the image tag, and the full repo:tag to `blackfish details`. Both tables
are already near terminal width, so they show the tag only.

Add an Image row to the service summary and the batch job details panel,
falling back to a dash where no image was recorded (rows predating
image_ref, or never launched).

Give Memory its own CircleStackIcon, since Image now uses the cube.

Closes #481.
Give revision the same monospace, truncated treatment as model and
image, and widen the cutoff from 200px to 320px. A commit SHA (~264px)
and a full image reference (~271px) both truncated at the old width,
with 768px of panel to spare.
@cswaney cswaney added this to the v1.0.0 milestone Aug 21, 2026
@cswaney cswaney added the enhancement New feature or request label Aug 21, 2026
@claude

claude Bot commented Aug 21, 2026

Copy link
Copy Markdown

Review

Clean, well-scoped change — presentation-only as described, and the reasoning in the PR body (column widths, IMAGE vs VERSION naming, truncation widths) is easy to follow and matches what's actually in the diff. A few notes:

Test coverage gap

format_image_version (lib/src/blackfish/server/utils.py:276) has no direct unit test. It's a small pure function, but it has three distinct branches worth pinning down:

  • None/empty image_ref"-"
  • well-formed repo:tag → tag only (via ImageSpec.parse)
  • malformed value (no :) → falls back to the raw string, per the docstring

test_format_datetime in lib/tests/unit/test_utils.py:134 is right there as a pattern to follow — a test_format_image_version alongside it covering these three cases would close the gap cheaply. The CLI list/details commands that call it are marked # pragma: no cover, so this function is currently the only place that logic could be verified at all.

Minor: duplicated tag-parsing logic

ServiceSummary.jsx derives the tag with service.image_ref.split(":").pop() (web/src/components/ServiceSummary.jsx:148), which duplicates (in a simpler form) what ImageSpec.parse/format_image_version does on the Python side. They happen to agree for well-formed refs, including registry:port cases (last :-segment is still the tag), so this isn't a bug today — just something to keep in sync if the repo:tag parsing rules ever change, since there's no shared source of truth across the CLI/UI boundary. Not blocking given this is presentation-only and the API doesn't expose a pre-parsed tag field.

Everything else looks solid

  • ImageSpec.parse's rsplit(":", 1) handles registry:port/repo:tag correctly (splits on the last colon), so both the Python and JS tag extraction are correct for the documented formats.
  • Fallback-to-dash behavior for NULL image_ref (pre-migration/never-launched rows) is consistent and tested across CLI ("-"), ServiceSummary (dash + no title), and JobDetailsPanel (row omitted entirely — arguably the best of the three, since it doesn't imply "no image" for something else unknown).
  • Icon swap (CircleStackIcon for Memory, freeing CubeTransparentIcon for Image) is a nice touch to avoid duplicate icons, and the snapshot diff is exactly what you'd expect from that change plus the new row — no unrelated snapshot churn.
  • JobDetailsPanel revision/image width fix (200px → 320px) is well justified with concrete pixel measurements in the commit message, and both new/changed rows follow the existing monospace/truncate/title pattern already used for repo_id.
  • No backend/serializer/migration changes needed since both GET endpoints already serialize image_ref — correctly scoped as presentation-only.

No security or performance concerns — this is read-only display of existing data.

The CLI commands that call it are pragma: no cover, so this is the only
place the tag/dash/fallback branches can be verified.
@cswaney

cswaney commented Aug 21, 2026

Copy link
Copy Markdown
Member Author

Triage of the automated review:

Addressed — no unit test for format_image_version (8994d28). Confirmed the gap: no test existed, and since the CLI list/details commands that call it are # pragma: no cover, this function was the only place that logic could be verified at all. Added test_format_image_version alongside test_format_datetime covering all three branches — well-formed ref → tag, NULL/empty → -, unparsable → raw value. Coverage 70% → 71%.

Not actioned — tag-parsing duplicated in ServiceSummary.jsx. The review notes this is not a bug today and explicitly flags it as non-blocking; both forms agree for well-formed refs including registry:port/repo:tag, since each takes the last :-segment. Sharing a single source of truth across the Python/JS boundary would mean either exposing a pre-parsed tag field from the API or duplicating ImageSpec semantics in JS — both disproportionate for one split(":").pop() in a presentation-only change. Worth revisiting if #483 adds richer image handling to the frontend, where a shared parser would actually earn its keep.

924 tests passing; lint and MyPy strict clean.

@cswaney
cswaney merged commit f879a86 into main Aug 21, 2026
11 checks passed
@cswaney
cswaney deleted the feat/surface-image-version branch August 21, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Surface the pinned image version in CLI and details views

1 participant