Commit Graph

17 Commits

Author SHA1 Message Date
teknium1 37e4cd5faa fix(updater): a probe that cannot be spawned stays advisory instead of failing the update
bounded_probe_run collapses spawn failure and timeout into one None, so a venv
interpreter that exists but cannot be executed (PermissionError, ENOEXEC, fork
failure) was reported as "timed out before reporting import health" -- a bogus
warning on the git path and sys.exit(1) on the ZIP path -- and the
`except OSError: return {}` branch beneath it was dead. Let the Popen error
propagate (opt-in flag, default unchanged for the other probes) so "we could not
run our own probe" says nothing about the checkout and no longer blocks the
update, while a spawned child that hangs is still a verdict.

Restores the non-fatal test the earlier rewrite dropped, now driving the real
bounded_probe_run/Popen: red on the previous head, green here.

Review finding: spawn failure of the import probe reported as a fatal timeout.
2026-09-15 04:11:11 -07:00
KoNit-K e74c29de55 fix(updater): bound import probe teardown 2026-09-15 04:11:11 -07:00
Teknium 4cd4f395ea test: isolate missing first-party import guard fixture 2026-09-08 03:06:30 -07:00
Teknium ba030bc0db fix(test-seams): monkeypatch.setattr facade aliases — also patch the defining module (57 files)
Tests did monkeypatch.setattr(<facade module>, name) where name is now defined in a
sibling module and the production path reads the sibling's binding. Where production
reads through BOTH bindings the setattr is duplicated onto the defining module (import
added next to the existing alias import); where only the sibling reads it the target is
repointed. Seams whose production readers go through the facade are left alone.
2026-09-03 19:33:28 -07:00
Teknium 0e78694c72 simplify(compat): hermes_cli.main — drop 198 re-exports/aliases (155 eager + 45 lazy PEP 562 + _warn_stale_dashboard_processes alias + _time/_self/_LAZY_* machinery), repoint 17 source callers + 91 test files 2026-09-03 15:07:39 -07:00
HexLab98 85118cc9d4 test(cli): cover mixed-config ImportError recovery hint on chat startup (#96900) 2026-09-01 00:26:55 +05:30
fangliquanflq 915ec169a0 fix(update): verify failed restore cleanup 2026-08-31 10:04:56 -07:00
fangliquanflq 53cf38c3b8 fix(update): fail closed on incomplete restore checks 2026-08-31 10:04:56 -07:00
fangliquanflq 3e4dc5f2c3 fix(update): preserve unknown restore cleanup state 2026-08-31 10:04:56 -07:00
fangliquanflq 8236b51878 fix(update): authenticate import health markers 2026-08-31 10:04:56 -07:00
fangliquanflq 6c608e2f59 fix(update): reject terminated import probes 2026-08-31 10:04:56 -07:00
fangliquanflq 7b958b3575 fix(update): detect restored import-time failures 2026-08-31 10:04:56 -07:00
kshitij 15cb86eba3 refactor(update): one definition of "first-party module"
/simplify-code reuse reviewer (HIGH): the probe and the user-facing hint
each carried their own hand-written list of first-party package roots,
and they had already diverged on day one —

  module      probe   hint
  cli         False   True    <- rollback with no explanation
  hermesx     True    False   <- third-party blamed on our updater

Hoist a single FIRST_PARTY_MODULE_ROOTS + is_first_party_module() into
hermes_constants (import-safe, no new imports) and have both consume it;
the probe gets the set injected into its source rather than re-typing it.
Also completes the roster — cron, utils, run_agent, model_tools,
toolsets, tui_gateway, acp_adapter were missing from both copies.

Verified by executing the real probe source against 19 module roots:
0 disagreements. Added a test that fails if either side grows a private
copy again.
2026-08-01 16:09:27 +05:30
kshitij bf18710a54 fix(update): make the git-path import check non-destructive
Phase 2 review (C2) and /simplify-code findings.

C2 — the git path ran the import guard before `_clear_bytecode_cache`,
wired into the syntax guard's `git reset --hard` rollback. But
`cannot import name 'X'` is ALSO the documented signature of the
stale-bytecode class (#6207, #60242, see
_sweep_stale_bytecode_if_checkout_changed), which the very next steps —
and the launch-time sweep — already self-heal. A false positive there
would destroy a good update over a state that fixes itself.

Remove the guard from the rollback path entirely and re-add it at the
end of the git path, after bytecode sweep + dependency reinstall + lazy
refresh, as a WARNING only. By then every benign source of a transient
ImportError has run, and we never reset the user's checkout.

W6 — the headline regression test was vacuous: it patched
`hermes_main._UPDATE_CRITICAL_FILES`, but the syntax guard reads
`update_cmd`'s global, so the stub files were never examined and the
(True, None, None) came from "no files found" rather than "parses
clean". Patch the right module; mutation-checked (the test now fails
when the guard is disabled).

S5 — `startswith(("tools","agent","hermes","gateway"))` also matched
third-party `agents`/`agentops`/`toolsets`. Compare the first dotted
segment against an exact set instead.

S6 — hoist the per-line ChatConsole() instantiation.
2026-08-01 16:09:27 +05:30
kshitij 822571fa8e fix(update): don't roll back a good update over uninstalled deps
Phase 2 review caught a false-rollback I introduced: on the git path the
import guard runs at the post-pull syntax check, which is BEFORE the
dependency sync. A release that adds a new third-party requirement would
fail the probe and trigger `git reset --hard` on a perfectly good update.

Rather than reorder the git path (the guard belongs with the rollback it
feeds), make the probe ignore a missing module that isn't ours. A missing
third-party package means deps aren't installed yet; a missing first-party
module means the update dropped a file, which IS the skew we're hunting.

This also makes the ZIP path's ordering non-load-bearing.

Verified: third-party absent -> (True, None, None); first-party absent ->
flagged; and the original TODO_INJECTION_HEADER skew is still caught.
2026-08-01 16:09:27 +05:30
kshitij aa5d4fd6ee fix(update): probe the venv interpreter, not the driving one
Self-review against the sibling probe `_venv_core_imports_healthy`
surfaced this: that helper deliberately resolves the project venv's
python rather than using `sys.executable`, because `hermes update` may
be driven by a different interpreter than the install's own.

The new import guard had the same requirement and missed it. Probing
`sys.executable` would validate a tree the user never actually runs —
and that divergence is most likely on Windows, the exact platform this
guard was added for.

Falls back to the running interpreter when there is no venv (normal in
a dev checkout). Regression test asserts the venv python is chosen; it
fails when the fix is reverted.
2026-08-01 16:09:27 +05:30
kshitij baecc840e5 fix(update): catch partially-updated trees that parse but can't import
A Windows user reported every startup dying with `ImportError: cannot
import name 'TODO_INJECTION_HEADER' from 'tools.todo_tool'`. The symbol
exists on main; their tree had the new `agent/context_compressor.py`
(which imports it at module level) alongside a pre-update
`tools/todo_tool.py`.

The post-update guard missed it. `_validate_critical_files_syntax` only
py_compiles files, and every file in a skewed tree parses fine — it is
the combination that is broken. The guard reported success and the
update completed over an install that could not start.

The ZIP-update path (Windows-only, used when git file I/O is broken)
is where the skew comes from: its copy loop replaces top-level entries
one at a time in `os.listdir` order, so `agent/` lands at index 13 and
`tools/` at index 66. Any failure between them leaves exactly this
mismatch — and that path had no post-copy validation or rollback at all.

- Add `_validate_critical_modules_import`: imports the four startup
  modules in a subprocess (~0.4s) so cross-module breakage is caught.
  Non-import errors (config/env) are ignored; a probe that cannot spawn
  is non-fatal so we never block an update on our own tooling.
- Run it after the syntax guard on the git path, reusing the existing
  auto-rollback.
- Run it on the ZIP path after dependency install (so a genuinely-new
  requirement is not misreported as a partial copy), and make the ZIP
  failure message state the install may be half-updated.
- Add `partial_update_hint()` and print it under "Failed to initialize
  agent", so users see "re-run hermes update" instead of a bare
  ImportError. Stays silent for ModuleNotFoundError and third-party
  imports, which need different remediation.

Verified by simulating the exact skew: the syntax guard returns ok=True
while the import guard returns the user's error verbatim.
2026-08-01 16:09:27 +05:30