Problem
The Python client (`clients/python/src/mat_vis_client/client.py:539-559`) caches `release-manifest.json` on disk under `<cache_dir>//.manifest.json` and never revalidates. Once present, the cached manifest is served forever. JS/Rust/shell follow the same per-tag-cache pattern.
The implicit contract is "release tags are immutable" — but the v0.6.0 cut against `gerchowl/mat-vis@v2026.04.2` mutated the tag multiple times mid-release:
A user who pinned `MatVisClient(tag="v2026.04.2")` early has a stale 3-source / 2-tier manifest on disk and won't see the additions until they manually wipe `~/.cache/mat_vis_client/v2026.04.2/`.
`check_updates` (line 565+) only polls the GH releases API for "is there a newer tag" with a 24h TTL — it has no signal for "the SAME tag mutated."
Proposal
Two independent layers; both worth landing:
1. Policy: immutable tags
Codify in CHANGELOG + docs that once published, a release tag must not be mutated. New data ⇒ new CalVer (the v2026.05.1 branching pattern we discussed for KTX2 in #214 phase-7 chat). The release-cut PR for v0.6.0 should ship with this stated.
Acceptance:
2. Mechanism: ETag-aware cache (defense in depth)
`HfApi` returns ETags on every `resolve` GET. Wire `MatVisClient.manifest` to:
- Send `If-None-Match: ` on every property access in a fresh client lifecycle (not per-call within one process — `self._manifest` in-memory cache stays).
- On 304 → serve cached value.
- On 200 → overwrite cache + ETag.
Cost: one conditional GET per client lifecycle. ~50 ms with cache hit, free thereafter via in-memory cache.
Acceptance:
Severity
Not a v2026.04.2 ship blocker — that tag's mutations are now stable and a one-shot `rm -rf` is the operator workaround. But shipping v0.6.0 client packages without fixing this means the broken contract becomes a public API for the lifetime of the major. File for v0.6.x patch follow-up; should land before the next CalVer release that mutates a tag (v2026.05.1 KTX2 add, v2026.05.x 2k add per #257, etc.).
Out of scope
- Cache-busting via query string (`?cb=`) — that defeats HF's CDN.
- Removing the cache entirely — would burn unnecessary bandwidth on repeat fetches.
Problem
The Python client (`clients/python/src/mat_vis_client/client.py:539-559`) caches `release-manifest.json` on disk under `<cache_dir>//.manifest.json` and never revalidates. Once present, the cached manifest is served forever. JS/Rust/shell follow the same per-tag-cache pattern.
The implicit contract is "release tags are immutable" — but the v0.6.0 cut against `gerchowl/mat-vis@v2026.04.2` mutated the tag multiple times mid-release:
A user who pinned `MatVisClient(tag="v2026.04.2")` early has a stale 3-source / 2-tier manifest on disk and won't see the additions until they manually wipe `~/.cache/mat_vis_client/v2026.04.2/`.
`check_updates` (line 565+) only polls the GH releases API for "is there a newer tag" with a 24h TTL — it has no signal for "the SAME tag mutated."
Proposal
Two independent layers; both worth landing:
1. Policy: immutable tags
Codify in CHANGELOG + docs that once published, a release tag must not be mutated. New data ⇒ new CalVer (the v2026.05.1 branching pattern we discussed for KTX2 in #214 phase-7 chat). The release-cut PR for v0.6.0 should ship with this stated.
Acceptance:
2. Mechanism: ETag-aware cache (defense in depth)
`HfApi` returns ETags on every `resolve` GET. Wire `MatVisClient.manifest` to:
Cost: one conditional GET per client lifecycle. ~50 ms with cache hit, free thereafter via in-memory cache.
Acceptance:
Severity
Not a v2026.04.2 ship blocker — that tag's mutations are now stable and a one-shot `rm -rf` is the operator workaround. But shipping v0.6.0 client packages without fixing this means the broken contract becomes a public API for the lifetime of the major. File for v0.6.x patch follow-up; should land before the next CalVer release that mutates a tag (v2026.05.1 KTX2 add, v2026.05.x 2k add per #257, etc.).
Out of scope