fix(lazy_deps): stop an exact pin on a shared transitive dep from downgrading the core - #68008
Closed
spiky02plateau wants to merge 1 commit into
Closed
Conversation
…r huggingface-hub An exact ==1.2.3 pin on huggingface-hub (feature tool.trace_upload) force-downgraded the shared venv on every lazy refresh whenever the core embedding stack (transformers/sentence-transformers, used by local/local_embedded Hindsight) had installed a newer version — transformers 5.x requires huggingface-hub>=1.5,<2.0, so the downgrade made sentence_transformers unimportable and the embedded Hindsight daemon abort at startup (silent memory loss until noticed). Two layers: - Track the compatibility range the trace-upload client actually needs (>=1.5,<2.0) instead of an exact pin, so an already-healthy shared version satisfies the spec and is left alone. - Add a general no-downgrade guard in _is_satisfied: a lazy, opt-in backend must never move an already-installed package backwards; treat 'installed newer than the pin allows' as satisfied and warn to widen the pin. Legitimate upgrades (installed below the spec) are unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MN8RMDLwxCfFxwtADoEJJf
This was referenced Jul 23, 2026
Contributor
|
Thanks @spiky02plateau — your PR had the sharpest analysis of the class-level problem (an exact pin on a SHARED transitive dep letting a lazy refresh downgrade the core), and the no-downgrade guard is a thoughtful backstop. The merged resolution in #72320 went a different route per maintainer policy: exact pins stay (no ranges — every version change must be code-reviewed), and the tree converges on ONE hub version ( |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
LAZY_DEPS["tool.trace_upload"]pinnedhuggingface-hub==1.2.3.huggingface-hubis not private to the trace-upload feature — it is a shared transitive
dependency of the embedding stack (
transformers/sentence_transformers)that the local / local_embedded Hindsight memory backend needs.
transformersrequires
huggingface-hub>=1.5.0,<2.0.Because the pin is an exact
==, it satisfies nothing but itself:_is_satisfiedreturns
Falsefor any other installed version. So the moment the feature is"active" (its package present) and
hermes updateruns itsrefresh_active_featureslazy-refresh pass, pip reinstalls — i.e. DOWNGRADES — huggingface-hub back to
1.2.3, even though the core just resolved a newer one it depends on. That
silently breaks
import sentence_transformers, and the local Hindsight embeddeddaemon aborts at startup on every retain/recall. The existing
_is_satisfiedversion guard cannot prevent this: an
==pin is a downgrade instructionwhenever the installed version differs.
This PR fixes it in two layers:
Range, not exact pin for
tool.trace_upload:huggingface-hub>=1.5,<2.0,which brackets what the trace-upload client needs and what the embedding
stack requires, so an already-healthy shared version is left untouched.
A general no-downgrade guard in
_is_satisfied. When the installedversion is outside a spec but every upper bound in that spec sits below the
installed version — i.e. satisfying the spec would require going backwards —
the guard treats the already-installed higher version as satisfied, leaves it
in place, and logs a
warningtelling the maintainer to widen the pin. Thisbackstops the whole failure class: no lazy, opt-in backend can ever silently
downgrade a package the core (or another backend) already installed at a
higher version. Legitimate upgrades (installed below the floor) are
unaffected — those still install. It is pure local version arithmetic; no
network, no behavior change for specs that are already satisfied.
Reproduction
With
transformers/sentence_transformersinstalled (pullinghuggingface-hub≥1.5), activate the trace-upload feature and run the update refresh pass (or
ensure("tool.trace_upload")): huggingface-hub is downgraded to 1.2.3 andpython -c "import sentence_transformers"then raisesImportError: huggingface-hub>=1.5.0,<2.0 is required ... but found huggingface-hub==1.2.3.Related Issue
No existing issue — found during an operational memory-outage investigation and
reproduced directly against
main.Type of Change
Notes for maintainers
tools/lazy_deps.pymodule docstring / TTS comment references a"no-ranges policy to match pyproject extras." That policy is right for
feature-private packages; the point of this change is that
huggingface-hubis not feature-private. If you prefer to keep the literal pin exact, the
no-downgrade guard alone still prevents the outage — but the range is the more
honest description of the real constraint.
LAZY_DEPSfor other exact pins on packagesthat also appear in the core dependency tree (
aiohttp,starlette,numpy,Pillow); those already carry security rationale, but the samedowngrade risk applies if the core ever floats above the pinned version.
🤖 Generated with Claude Code
https://claude.ai/code/session_01MN8RMDLwxCfFxwtADoEJJf