Skip to content

fix(update): re-provision outdated managed Node on engine failure - #76558

Closed
teknium1 wants to merge 1 commit into
mainfrom
fix/managed-node-version-reprovision
Closed

fix(update): re-provision outdated managed Node on engine failure#76558
teknium1 wants to merge 1 commit into
mainfrom
fix/managed-node-version-reprovision

Conversation

@teknium1

@teknium1 teknium1 commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Summary

The EBADENGINE recovery now re-provisions a healthy-but-outdated managed Node tree, closing the loop the Node-26 floor bump opened: every install sitting on a managed Node 22 tree (all historical installs, plus everything #76464 healed onto 22 before the bump) was stuck in an unfixable retry loop that dead-ends the GUI installer/updater and hermes update.

Root cause: three deliberate behaviors composed into a trap after 713a983 raised engines.node to >=26:

  • heal_hermes_managed_node() only fires on broken trees — a runnable Node 22 tree is healthy, so heal never triggers.
  • bootstrap_hermes_managed_node() reused any healthy tree, so the recovery handed back the same Node 22 npm and the retry failed identically.
  • On the managed-npm path, a node-constraint failure was declared unfixable outright (correct before, wrong now that provisioning exists).

Changes

  • hermes_constants.py: _probe_node_major() + managed_node_meets_target(); bootstrap_hermes_managed_node(force=...) reuses a healthy tree only when its Node major ≥ _HERMES_NODE_TARGET_MAJOR, otherwise re-provisions in place at the current target.
  • hermes_cli/npm_engine.py: when the failing npm IS the managed one and the managed Node is below target, force a re-provision (followed by the usual npm-range upgrade) instead of looping on an npm-only upgrade or giving up.
  • tests/hermes_cli/test_npm_engine.py: new coverage for the outdated-tree re-provision (asserts force=True so the healthy-tree shortcut can't sneak back) and the still-correct "current Node, node-only mismatch → decline" path.

Validation

Before After
Managed Node 22, repo demands ≥26 EBADENGINE loop forever (GUI + CLI dead-end) tree re-provisioned to v26.5.1 + npm 12.0.2, retry succeeds
Managed Node current, node-only mismatch declared unfixable unchanged (correctly declines)
Current-major healthy tree reused reused (0.06s, no re-download)

E2E with real downloads in a temp HERMES_HOME: provisioned a v22.23.2 tree, replayed the GUI updater's node>=26 EBADENGINE against its npm → re-provisioned to v26.5.1 + npm 12.0.2 in 3.2s. Targeted tests: 92/92 across test_npm_engine.py, test_hermes_constants.py, test_cmd_update.py; ruff clean.

Infographic

Outdated managed Node re-provision

The Node-26 floor bump (713a983) re-broke every install that had
already self-healed onto a managed Node 22 tree — and every install the
installers put on Node 22 historically:

- The managed tree is HEALTHY (node/npm run fine), so heal never fires
  (it only repairs broken trees).
- bootstrap_hermes_managed_node() reused any healthy tree, so the
  EBADENGINE recovery handed back the same Node 22 npm and the retry
  failed identically — an unbreakable loop. GUI installer/updater and
  hermes update all dead-end.
- On the managed-npm path, a node-constraint failure was declared
  unfixable outright.

Fix: teach the recovery that a managed tree can be outdated, not just
broken.

- hermes_constants: _probe_node_major() + managed_node_meets_target();
  bootstrap_hermes_managed_node(force=...) now reuses a healthy tree
  only when its Node major >= _HERMES_NODE_TARGET_MAJOR, otherwise
  re-provisions in place at the current target.
- npm_engine: when the failing npm IS the managed one and the managed
  Node is below target, force a re-provision (then the usual npm-range
  upgrade) instead of declaring the failure unfixable or looping on an
  npm-only upgrade.

E2E (real downloads, temp HERMES_HOME): provisioned a v22.23.2 tree,
replayed the GUI updater's node>=26 EBADENGINE against its npm ->
tree re-provisioned to v26.5.1 + npm 12.0.2 in 3.2s, retry viable;
current-major tree reused in 0.06s (no gratuitous re-downloads).
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on bc1d911

ℹ️ Info

Desktop E2E visual evidence · View test artifacts · View job

3 visual diffs.

inline evidence upload failed.

Failed to upload diff-1508682a2ae8-boot-ready-diff.png with gh image (exit code 1): Error uploading /home/runner/work/_temp/e2e-evidence/diff-1508682a2ae8-boot-ready-diff.png: step 0 (get upload token): uploadToken not found on repo page — do you have write access to NousResearch/hermes-agent? (or, if NousResearch enforces SAML SSO, authorize at https://github.com/orgs/NousResearch/sso)

@teknium1 teknium1 added the area/install-update Installer, updater, packaging, wheels, doctor label Aug 2, 2026
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 2, 2026
@teknium1

teknium1 commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

Closing: #76562 returned the managed-Node target to 22, so no healthy managed tree is below target anymore and this re-provision path is dormant. If a Node-floor bump is re-attempted later, this can be revived — the outdated-tree gap it covers (heal only fires on broken trees) will exist again then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/install-update Installer, updater, packaging, wheels, doctor comp/cli CLI entry point, hermes_cli/, setup wizard P3 Low — cosmetic, nice to have sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants