You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Found during board review of #163. Pre-existing and distinct from the version-comparability work that PR does, so filed rather than folded in.
What
refresh_server's "already up to date" short-circuit compares only version values. It never checks that the cached entry describes the same package:
cached = old-package @ 1.0.0
config = new-package @ 1.0.0 (same server name)
-> versions match -> "up to date" -> the OLD package's descriptions are returned
The short-circuit block never references existing_cache.package, and pkg_name is not resolved until after it (refresher.py, "Determine package info", below the early return).
refresh_all compounds it by looking up cache entries by server name only, so a server repointed at a different package keeps serving the previous package's tool descriptions indefinitely — there is no version change to trigger a refresh.
#163 fixes whether two versions can be ordered. This is about whether they describe the same thing in the first place. are_versions_comparable correctly answers "can 1.0.0 and 1.0.0 be compared?" — yes. The defect is that comparing them is meaningless when the packages differ.
The cross-ecosystem instance (npm cache vs docker config) is fixed by #163, because a version and a digest are incomparable. The same-ecosystem instance above is not, because both sides parse fine.
Fix sketch
Gate the short-circuit on package identity before comparing versions — resolve detect_package_type(...) / pkg_name above the early return and require it to match existing_cache.package. A mismatch should force a refresh, not a comparison.
Worth checking at the same time whether refresh_all's by-name cache lookup should carry the package identity too, so the check cannot be bypassed by a caller that assembles the pair itself.
refresh_server's short-circuit is now gated on _same_package (refresher.py:199), and detect_package_type/pkg_name resolution was moved above the early return so the comparison can consult identity — which is the specific ordering problem this issue named. The gate is applied at all three sites that pair a cached entry with a config by name (refresh_server, refresh_all, check_staleness), and the cached entry gained a package_type so npm foo and pypi foo are distinguishable.
Pinned by TestPackageIdentityGate and TestUnknownPackageForcesRefresh, both proved RED before the fix and mutation-tested after: a fail-open guard phrasing (unknown → skip the check) and a degenerate always-False gate each kill 5 tests.
One boundary this does not cover, tracked separately as #180: detect_package_type collapses distinct packages for registry:port/image and npm exec pkg forms, so the gate can falsely confirm for those command shapes.
Activity
ViperJuice commentedon Aug 25, 2026
Closed by v12 UPDPATH (#179,
e7907df).refresh_server's short-circuit is now gated on_same_package(refresher.py:199), anddetect_package_type/pkg_nameresolution was moved above the early return so the comparison can consult identity — which is the specific ordering problem this issue named. The gate is applied at all three sites that pair a cached entry with a config by name (refresh_server,refresh_all,check_staleness), and the cached entry gained apackage_typeso npmfooand pypifooare distinguishable.Pinned by
TestPackageIdentityGateandTestUnknownPackageForcesRefresh, both proved RED before the fix and mutation-tested after: a fail-open guard phrasing (unknown → skip the check) and a degenerate always-Falsegate each kill 5 tests.One boundary this does not cover, tracked separately as #180:
detect_package_typecollapses distinct packages forregistry:port/imageandnpm exec pkgforms, so the gate can falsely confirm for those command shapes.