Commit Graph
188 Commits
Author SHA1 Message Date
Ben Barclay d96591fbc8 fix(config): route config_backend to the upgrade lane and fault-inject the seam's parser in the MoA read test
update_channel now writes through hermes_cli.config_backend, so the CI
classifier lists it as an update dependency. The MoA transient-read test
patched hermes_cli.config.fast_safe_load, which the seam no longer calls;
it now patches utils.fast_safe_load, the parser the FileBackend uses.
2026-10-25 18:54:09 -07:00
Teknium a80b413cd6 fix(git): graph refresh sweeps only object-store debris and lets git clean up
Review round on #144647 (head d016f04694d):

- CI routing: the refresh (slot claim, bounded runner, stale check, detached spawn) moves to
  hermes_cli/git_commit_graph.py, routed to e2e_upgrade with the update pipeline. The update path
  imports it instead of all of worktree_ops; worktree_ops keeps its repack seams and imports the
  shared slot claim and runner from it (no cycle).
- W1: the -w pass runs in whatever repo it was launched from, so its refresh sweeps only the
  object-store locks (clear_stale_git_locks(names=OBJECT_STORE_LOCK_NAMES)); index.lock / HEAD.lock
  there belong to the user's git. The install checkout's update sweep is unchanged.
- W2: timeout/exit reaping SIGTERMs the git tree first and SIGKILLs only after a 5 s grace
  (kill_process_tree(grace=), default unchanged for every other caller), so git deletes
  commit-graph-chain.lock and tmp_graph_*. The age-gated tmp sweep now also takes
  objects/info/commit-graphs/tmp_graph_*.
- N1: a breakaway-forbidding Windows job gets the no-breakaway retry, and a spawn that fails gives
  the 6 h slot back.
- N2: the detached child logs a failed write (git's fatal line) to the home's agent.log/errors.log.
- core.commitGraph=false in the target repo skips the write.
- N3: a successful no-op write stamps hermes-commit-graph.fresh, so an idle repo is not rewritten
  every slot.
- N4: test_update_finish's completion child and every in-process hermes_cli test stub the
  detached spawn; no writer outlives a test run.
- Greptile: the refresh test now runs on a treeless clone over a Bloom graph and asserts the
  write adds no pack (red when --no-changed-paths is dropped).
2026-10-25 17:51:21 -07:00
emozilla 443732a58b fix(update): hermes update rebuilds the Webapp bundle a home serves
hermes update rebuilt the TUI, the web UI and the desktop app but never apps/desktop/dist-webapp.
A gateway with webapp.enabled kept serving the bundle built before the update, which then talked
to the updated backend with an outdated contract.

The update now rebuilds that bundle when any home sharing this install has webapp.enabled, with
prepare_webapp_renderer, the function hermes webapp uses (a current bundle is reused). Like the
other products it is attempted on its own: a failure is reported with the rest at the end and
never skips another product.
2026-10-25 03:22:27 -07:00
Bear Huddlestonandemozilla b5eb5ee7a8 feat(webapp): carry the browser-hosted Desktop's server pieces from #93508
Carried from BearHuddleston's #93508 onto main. The Webapp relay and the
profile-incarnation fence stay out: carried code follows main's
named-profile rule and refuses a missing or deleted profile home.

- Webapp routes: one-use launch tickets, window handoff, and gateway
  WebSocket tickets minted for the signed-in browser
- Browser surface policy and the SPA document policy
- A host terminal for the browser that survives reconnects
- Staged browser uploads and file tickets; file.attach takes a staged upload
- hermes sessions adopt
- Webapp bundle build helpers and the renderer freshness check
- Regenerated gateway contracts

Co-authored-by: emozilla <emozilla@nousresearch.com>
2026-10-25 03:22:14 -07:00
Teknium f05df166b3 ci: route config_version_stamp to the upgrade suite
post_update now imports hermes_cli/config_version_stamp.py (it converts legacy
AGENT_BROWSER_* settings before stamping), so a change to it must start the
e2e_upgrade lane like every other module the update path imports.
2026-10-23 01:43:17 -07:00
Teknium 0f8bbed1ed fix(config): drop browser.extension_control (default and v52 migration)
Nothing reads the key since browser-extension control was removed; the existing v52 step (a
legacy-key step, so unstamped configs get it too) now strips it from user config.
2026-10-23 01:42:29 -07:00
ahrazzle a9376424e5 fix(desktop): prepare the locked Electron runtime explicitly before use
Electron 42 dropped the postinstall that unpacked its binary into
node_modules/electron/dist. The binary now appears on the first
require('electron'), so parallel vitest workers race to unpack it
("Text file busy" in #128267's CI), and `hermes desktop --source` finds
no path.txt to launch.

electron-runtime.mjs runs Electron's own install.js once: after npm ci
for the desktop workspace, and in CI before the parallel checks. It first
checks the installed package against the desktop pin and the lockfile,
and does nothing when the runtime is already in place. On the current
40.10.2 pin, whose postinstall still unpacks the binary, it is a no-op.

Salvaged from #137648 (the runtime-preparation subset only).
2026-10-22 16:17:57 -04:00
ethernet 0153a9e460 refactor(ci): simplify cache report state and rendering
Use one escaped HTML fragment for the report and review comment instead
of maintaining separate Markdown and HTML table builders. GitHub's
renderer preserves the same table text and all 39 real job/step links.

Remove the obsolete phase-generic accounting helper, redundant attempt
list and save-evidence flag, and unused collected-job counter. Append
main's saved column in one place.

Use urllib's unredirected Authorization header instead of a custom
redirect handler. The real HTTP redirect test still proves that only
the API request receives the token. Exercise PM formatting directly,
while retaining the actual stdlib-only CLI invocation test.

Verification: 696 CI tests pass, one native skip, and all 12 checks pass.
Saved real-log parser records and rendered values remain unchanged.
2026-10-22 11:55:58 -04:00
ethernet 4f53b89a47 ci: summarize cache hits with main-aware job details
put cache hits/attempts and restored/missed archive bytes above an expander.
show hit and miss job/step links in both Markdown and HTML. off main,
compare hits with main's latest measured archive and hide write figures;
on main, show saved bytes without self-comparison.

retain unknown outcomes and sizes instead of treating them as misses or
zero. miss-byte totals use main archive references off main, and newly
saved archive sizes on main. preserve the real run mode and step numbers
in the snapshot so artifact-only rendering keeps the same behavior.
2026-10-22 11:55:58 -04:00
ethernet 19ed6e147c ci: compare cache archive transfers in the review comment
Collect ordinary actions/cache job logs alongside the existing timing
snapshot and retain per-invocation restore/write receipts and archive bytes.
Compare each cache with main and show saved-minus-restored archive changes
in the review comment, Actions summary and complete HTML report.

Count successful writes only after their save receipt; transfer progress
supplies a size once, never a sum. Preserve unknown sizes, failed or missing
logs, lookup-only results and exact-hit save skips. Match content-keyed
writes to their restored paths, without inspecting cache contents or using
the GitHub inventory as a proxy for a runner provider's cache store.
2026-10-22 11:55:58 -04:00
ethernet f3ea0290e2 ci: show PM cache restore results and write policy
Print a compact tools/uv/npm summary from setup-pm, including the selected
restore outcome, exact-hit output, cache path, ref scope and save policy.
Keep actual archive sizes and upload results in the native cache logs.
Do not scan cache trees or add logging wrappers to non-PM cache actions.
2026-10-22 11:55:58 -04:00
yoniebans 3e6589fc34 ci: run the upgrade suite when hermes_state_fts.py changes
The hermes update search-index notice now reads the stored FTS layout through hermes_state_fts.fts_layout_drift, so the module is on the update path.
2026-10-21 04:14:08 -07:00
ethernet 58801c565b perf(ci): stop transporting node_modules in the desktop dependency snapshot
node-deps runs npm ci on every prepare (the receipt never matched across
runs in any sampled job), and npm ci deletes node_modules first. The
restored trees were GBs of tar/untar for nothing; npm's content cache
(npm/_cacache) is what lets npm ci skip downloads. The workspace path
validation only existed to guard those paths, so it goes too.
2026-10-19 12:30:42 -04:00
Teknium d2c6ca2300 test(desktop): E2E guard for turn state after a lost connection
apps/desktop/e2e/core/reconnect-turn-state.spec.ts, real Electron + real
gateway, only the LLM scripted:

1. primary socket blocked mid-turn (loopback proxy that resets and refuses);
   the turn finishes on the gateway while disconnected; after the redial the
   reply renders exactly once (transcript oracle) and no Stop/spinner stays.
2. socket drop while a held turn runs, then a Control+Enter follow-up right
   after the redial: both turns run in order, oracle holds, nothing spins.
3. gateway SIGKILL mid-turn: supervisor brings a new owner up, recovery
   fences the turn `unknown`; the lost-turn card + Discard are on screen
   with "1 Queued — paused"; a follow-up is queued ("2 Queued — paused")
   and does not run ahead; Discard lets it run; oracle holds.

The classifier now routes the queue panel to the core lane, since the
lost-turn card lives there.

Refs #134889 (NF2)
Refs #140337
2026-10-17 11:33:13 -07:00
Teknium 861a0299ed refactor(gateway): no re-export shims for the split status/base helpers; the lock split is one-way
The round-1 health offset moved safe_url_for_log and the scoped-lock
release pair into siblings but re-exported them from gateway.status /
gateway.platforms.base, and status_scoped_locks read gateway.status
privates at call time while gateway.status re-exported the sibling's
privates (_unusable_lock_dir, _warned_unusable_lock_dirs). AGENTS.md:
no re-export shims for internal moves.

- gateway/status_lock_dir.py: the unusable-lock-dir report
  (ScopedLockDirUnusable + public unusable_lock_dir / _recovered /
  reset / reported). gateway.status imports it; it imports nothing back.
- gateway/status_scoped_locks.py: only the release pair, reading
  gateway.status at call time; gateway.status no longer imports it.
- Every importer points at the real home: base.py, run_bootstrap.py,
  the Feishu and Slack adapters, and the tests that patch them
  (gateway.status_scoped_locks.release_*). safe_url_for_log comes from
  gateway.platforms.base_log_safety; base.py imports it only for its
  own use.
- classify_changes: status_lock_dir.py rides with gateway/status.py on
  the e2e_upgrade lane.

code_health: 0 blocking (status.py stays under its main value).

Review finding by @unsupportedpastels on #140490 (minor 4) and by
@alt-glitch on #140490 (suggestion 4)
Refs #134889 (W2)
Refs #140337
2026-10-17 08:03:53 -07:00
Teknium 11380ac90a ci(routing): route hermes_dir_acl.py to the e2e_upgrade suite
hermes_cli/update_cmd_maint.py and update_host_obligation.py import the new
root module, so the update path runs it; list it beside its root siblings
(hermes_bootstrap.py, hermes_constants.py) in the update owners.

Refs #134889 (W8)
Refs #140337
2026-10-17 08:03:52 -07:00
Teknium 275b15fc35 ci: catalog-only PRs run the catalog tests instead of the full suite
A PR that changes only plugin-catalog entry YAML (plus contributor email
maps) ran all 23k Python tests on Linux, macOS and Windows, ~25 min, and
unrelated core flakes kept blocking one-file catalog additions.

The classifier now has a `catalog` lane. A diff made only of catalog entry
data turns `python` off and `catalog` on; ci.yaml then runs
catalog-tests.yml (every test file that reads the catalog or the email
maps, discovered by scripts/ci/catalog_test_files.py), plus the contributor
check. The lane is required by all-checks-pass whenever detect selects it.
plugin-catalog/README.md keeps the full suite (a docs-page test mirrors
it), and any non-catalog file in the diff brings the suite back. The
structural and pinned-source admission gates in plugin-catalog-ci.yml are
unchanged.
2026-10-16 04:37:07 -07:00
Teknium 2cd0ec8686 Merge origin/main into feat/unified-gateway-runtime
215 commits from main (c70332f888). One textual conflict: the generated
apps/shared/src/gateway-contract.generated.ts, regenerated with scripts/gen_gateway_contracts.py
rather than hand-merged. Brings main's fix for the dated shared-metrics install-receipt test
(783637e370).
2026-10-13 05:15:48 -07:00
calvinnwq ec82a5643b ci: open an issue when Hermes Desktop cannot read the plugin catalog
Desktop's hermes://plugin/install?catalog= links fetch /docs/api/plugins.json cross-origin. The docs host answers with a 301 to GitHub Pages, and a browser fails the fetch at that hop unless it carries Access-Control-Allow-Origin. The skills-index watchdog probes with curl -L, which never checks CORS, so it stayed green while every catalog link failed.

scripts/ci/check_catalog_cors.py fetches the catalog hop by hop with Origin: null (what a packaged Desktop renderer sends) and fails when any response lacks the header. A new check-catalog-cors job in skills-index-freshness.yml runs it every 4 hours and files its own [plugin-catalog-cors-watchdog] issue, so its reports never land on a skills-index issue.

Refs #136483
2026-10-13 03:49:29 -07:00
Teknium a89f374d7c Merge origin/main (#45: 255 commits to 3b63f7b0a4) into feat/unified-gateway-runtime
Conflicts (2 files, 1 hunk each); every main-side change is kept, ported to
where the branch moved the code:

hermes_cli/kanban_db.py (build_worker_context helpers _ctx_cap .. _ctx_comments)
  main:   f5a6651231c/d56e357556f coerce foreign/text timestamps on read; in
          _ctx_role_history the "Recent work" stamp became
          _ctx_stamp(_to_epoch(row['ended_at']) or 0, now) instead of int().
  branch: moved the whole _ctx_* helper block into hermes_cli/kanban_db_context.py
          (kanban_db.py imports it back), deleting it from kanban_db.py.
  merged: kept the branch's deletion in kanban_db.py and applied main's change in
          kanban_db_context.py::_ctx_role_history as
          _ctx_stamp(_kb._to_epoch(row['ended_at']) or 0, now). Main's other
          timestamp coercions in kanban_db.py (Task/Run/Comment/Attachment/Event
          from_row, _TASK_EPOCH_COLUMNS, release_stale_claims,
          _extend_live_stale_claim, task_age) auto-merged unchanged.

hermes_cli/web_server.py (_lifespan)
  main:   d7830c6f42 reworded one comment in the free-tier bootstrap block
          ("the ONE place its identity is created" -> "the one boot-time creator
          of its identity"; guests are now also created on first connector use).
  branch: moved _lifespan's body into hermes_cli/web_server_app.py::app_lifespan.
  merged: kept the branch's relocation and applied main's comment rewording in
          web_server_app.py.

Merge-induced health fix (no conflict marker; the combination tripped the ratchet):
apps/desktop/src/app/session/hooks/use-cwd-actions.ts::changeSessionCwd
  main:   63ed3caa4ba/dbc538547fc grew the function (statusbar cwd change for the
          focused chat / tile runtime ids) to CC 20.
  branch: added the session_busy refusal mapping (sidebar.projects.moveBusy) in
          its catch, +1 branch -> CC 21 > target 20 (scripts/check health blocking).
  merged: both behaviours kept; the busy-error mapping moved verbatim into a
          module-level cwdChangeError(err) helper. Health back to 0 blocking.

Check: every line main added between 1fd1827726 and 3b63f7b0a4 (317 files) is
present in the merged tree.
2026-10-12 16:55:20 -07:00
Teknium a0a49926f4 fix(check): blob-size exempts untracked copies and reads --head's allowlist (review)
- An untracked file whose bytes the base tree already holds (git hash-object
  matches a base blob) is no longer an offender, matching what staging the
  same copy already did.
- With an explicit --head, the allowlist comes from that revision
  (git cat-file <head>:.github/blob-size-allowlist.txt; none = no
  exemptions), so `--base A --head B` judges B by B's own exceptions.
  Working-tree mode still reads the file from disk.
- Tests for both: untracked copies of a base binary and base text file pass
  while an edited one is still caught; --head honours head's list over a
  conflicting checkout, a head without the list exempts nothing, and
  working-tree mode reads the disk list.
2026-10-11 17:16:57 -07:00
Teknium db5e618205 feat(ci): reject PRs that add binaries or new files over 500 KiB
Every blob a merge adds stays in every clone forever. In the last 90
days main received a 2 MB PR screenshot, a 2 MB default.tar.gz, three
PR infographics, a Windows cache database written by a test and a 1 MB
fuzz corpus at the repo root; nothing looked at file size.

scripts/ci/check_blob_size.py judges each path changed base -> head:
a binary (git's own --numstat detection) whose new content is over
500 KiB, added or modified, and any newly added file over 500 KiB.
Edits to existing text files stay with the code-health FILE_LINES
ratchet. Content the base tree already holds (a pure move, a copy)
adds no bytes and is not judged. Exact-path exceptions live in
.github/blob-size-allowlist.txt (CODEOWNERS-reviewed), seeded with the
one generated asset over the limit that legitimately changes.

It runs as its own unconditional workflow, like the case-collision
check, because asset-only PRs skip the Python and frontend lanes.
2026-10-11 17:16:57 -07:00
Teknium cc5928bd73 Merge origin/main (#44: 15 commits to 1fd1827726) into feat/unified-gateway-runtime 2026-10-11 14:02:25 -07:00
Teknium 8f05f890c5 ci(remote-backends): debian 13 for the test sshd, container setup as a mounted script
Review nits from #136602: the sshd and docker-backend image moves to the
current stable debian:13-slim (digest-pinned index), and the inline bash -c
setup becomes scripts/ci/test_sshd_container_setup.sh, mounted read-only and
run in the container. The new script joins the remote_backends path gate.
2026-10-11 11:55:56 -07:00
Teknium 438d10200c ci: run the SSH and Docker terminal backends against a real sshd and daemon
The SSH backend's real-host tests skipped on every CI run (nothing set
TERMINAL_SSH_HOST), and every Docker backend test mocked subprocess or the
docker CLI, so no CI run had executed either backend end to end.

- remote-backends.yml: starts a throwaway sshd container on 127.0.0.1 with a
  per-run keypair (scripts/ci/start_test_sshd.sh) and runs
  test_ssh_environment.py plus the new test_docker_backend_real.py against it
  and the runner's Docker daemon with a digest-pinned debian:12-slim. A file
  that skips fails the job, so the lane cannot go green over zero coverage.
- New classifier lane `remote_backends` (tools/environments/, tools/terminal_tool*,
  the real tests, the sshd harness, run_tests.sh). ci.yaml calls the workflow
  only when it fires, plus every push to main; required_results makes a selected
  lane mandatory, like the update consumers.
- The real tests read HERMES_TEST_SSH_* / HERMES_TEST_DOCKER_IMAGE (forwarded
  by run_tests.sh), because the hermetic conftest blanks TERMINAL_SSH_KEY as a
  credential before any test can read it.
- New real SSH cases: exit code/stderr, cwd persistence with spaces vs per-call
  workdir, quoting across the ssh hop, SendEnv passthrough through a real
  AcceptEnv, file tools write/read on the remote.
- New real Docker cases: exec + exit codes, cwd vs workdir, exported env
  persistence, docker_env/docker_forward_env reach the container and
  nothing else does, quoting, file tools write/read, /root surviving a
  container replacement.
- The existing one-shot test is xfail(strict): TERMINAL_SSH_PERSISTENT=false
  is read into ssh_config["persistent"] but SSHEnvironment never consumes it,
  so every SSH session persists exported env. Its _cleanup also cleaned the
  raw task id, not the resolved env key, so one test's env leaked into the next.
2026-10-11 11:55:56 -07:00
Teknium 549e53fd72 Merge origin/main (#43: 73 commits to c0ef5af520) into feat/unified-gateway-runtime
Conflicts (5 files):
- gateway/run_notifications.py: main lifted completion ownership into a new
  GatewayNotificationOwnershipMixin (run_notifications_ownership.py); the branch had lifted the
  update watcher into GatewayUpdateNotificationsMixin. The mixin inherits both. Kept both sides
  of the completion-event metadata (the branch's automation identities + local display card,
  main's proven_session_id / completion_ids), and in the async-delegation group the branch's
  authority admission runs first, then main's terminal-parent drop. Neither function main moved
  was changed on the branch.
- gateway/run_turn.py: the branch moved _hmwa_resolve_session into run_turn_prepare.py; main's
  one changed line there (the resolver receives the proven session id and completion ids) is
  ported into run_turn_prepare.py.
- hermes_cli/subcommands/sessions.py: keep both main's lazy cmd_sessions and the branch's
  rename/discard parser helper.
- ui-tui: keep both canonicalEn and connectorsEn catalogs; keep the branch's interfaces import
  plus main's findSlashCommand import.
2026-10-11 11:24:19 -07:00
Teknium 7bc05085f0 fix(ci): docs drift handles repeated placeholders, scopes its warning filter
Review follow-ups: `providers.<id>.models.<model>.timeout_seconds` now
matches (a second <...> segment no longer ends the pattern), the YAML
warning filter is scoped with catch_warnings, and the slash-command list
drops a `hidden` filter CommandDef never had.
2026-10-11 05:09:46 -07:00
Teknium 4e8fe569e4 feat(ci): new config keys and slash commands must ship with docs
DEFAULT_CONFIG changed 183 times in 30 days and nothing checked that a new
key reached the docs; /pause (the global emergency stop) went undocumented
for two months.

scripts/ci/check_docs_drift.py lists every DEFAULT_CONFIG leaf and every
registered slash command and finds the ones the docs never mention. A key is
documented by its dotted path, a placeholder path in inline code
(`auxiliary.<task>.timeout`, `display.pet.*`), or a YAML example nesting it
under its parents; a slash command by a `/name` row in
reference/slash-commands.md.

The 132 keys undocumented today are baselined in docs_drift_baseline.json;
tests/ci/test_docs_drift.py fails only on NEW gaps, so it never blocks an
unrelated PR, and documenting a baselined key never fails. Deterministic,
stdlib + repo imports, ~1s.

/pause is documented here, so the slash-command baseline starts empty.
contributing.md says what to do when the test fails.
2026-10-11 05:09:46 -07:00
Teknium 82a0d2dc88 Merge origin/main (#42: 9 commits to 79b45d1647) into feat/unified-gateway-runtime
No conflicts. Brings in main's fixes for the reds release run 38120936161 inherited:
79b45d1647 (signed reasoning replays after resume on Anthropic/Bedrock Converse),
7831de8999 + d3bdf761b0 (network upgrade E2E follow the new main-channel default),
0aa764fedd (Desktop hand-off test expects no channel-record request on main).
2026-10-11 03:09:45 -07:00
Teknium c152ba5a82 docs(ci): prompt-surface changes need one core approval, not two
The prompt-surface-review ruleset was meant to require one other reviewer;
it is now set to one hermes-agent-core approval. CODEOWNERS, the CI comment,
the staleness-test message and the developer docs said two.
2026-10-11 02:26:46 -07:00
Teknium ae3598c7cd feat(ci): reviewers see every change to the system prompt and tool schemas
A one-line code change can rewrite what every session sends to the model -- a
guidance constant moving tiers, a toolset gaining a tool, a dynamic rewriter
editing a description -- without the diff showing it. The rendered prompt
surface is now committed and reviewed like code.

- scripts/ci/prompt_surface.py renders the system prompt
  (build_system_prompt_parts) and the agent's tools[] through the production
  code for nine surfaces (cli x claude/gpt/gemini/hermes, cli in a code
  workspace, desktop, telegram, discord, cron) into
  tests/fixtures/prompt_surface/. A fresh home in a child process; clock,
  host OS, network, tool availability, env probe and machine paths pinned,
  so a laptop and CI produce the same bytes. Each tool schema is stored once,
  with a per-surface copy only where a surface serves a different schema.
- tests/ci/test_prompt_surface.py fails when the committed snapshot is stale,
  so a surface change must carry the regenerated snapshot in the same PR.
- prompt-surface-diff.yml (advisory, PR-only, stdlib-only, no PR code runs)
  posts per-surface token deltas, prompt hunks and per-tool
  description/param changes into the unified review comment.
- CODEOWNERS requests hermes-agent-core on the snapshot; a new
  prompt-surface-review ruleset requires two of their approvals.
- Docs: prompt-assembly.md (how it works), contributing.md (what to do when
  the test fails).
2026-10-11 01:21:18 -07:00
Teknium b1ccce898b Merge origin/main (#38: 70 commits to c57331677d) into feat/unified-gateway-runtime
Conflicts: tests/hermes_cli/test_finite_chat_delegation.py and
tests/tools/test_completed_process_results.py, where main's lint sweep (0006a5e229) added
check=False to subprocess.run calls this branch had rewritten. Kept the branch's test bodies
and carried check=False onto their subprocess.run calls.
2026-10-10 17:47:35 -07:00
Maciej Lisiewski bda3aea496 ci: remove unused variables (linter) 2026-10-10 15:20:14 +02:00
Maciej Lisiewski 0006a5e229 ci: fix PLW1509, PLW1510, PLW2101 linter errors 2026-10-10 15:20:13 +02:00
Teknium 760912ea8c ci: run the native-reply crash recovery test in the messaging job
tests/gateway/test_native_reply_crash_recovery.py (81edebdb07) drives the
real python-telegram-bot SDK and skips in the ordinary pytest slices, which
omit the messaging extra. test_messaging_gated_selection requires every such
file to be named by the e2e job's "Run messaging-gated gateway cases" step
and to start the e2e lane when edited; add it to both.
2026-10-09 19:43:16 -07:00
Teknium 408cc0d12e Merge origin/main (#32: 36 commits to cf23a1a5cc) into feat/unified-gateway-runtime
17 conflicts, all from main's lint sweep (ruff UP007/UP017/UP022/UP028/UP031/UP037/UP041,
FURB188/FURB192); no other main commit touches a conflicted file. Resolution: the branch side
of each file plus main's exact autofix (ruff 0.15.10, main's ruff.strict.toml, --fix
--unsafe-fixes). ruff.strict.toml takes main's copy. The pool-retirement live fixture stays
deleted with the pooled backend this branch retires.
2026-10-09 10:24:04 -07:00
Maciej Lisiewski 32b70e9733 ci: FURB188, FURB192 linter fixes 2026-10-09 17:31:52 +02:00
Teknium 2f78c72345 ci: route hermes_state_holders.py to the upgrade suite
The round-7 downgrade guard (hermes_cli/update_downgrade_guard.py) is on the update path and reads
state.db through hermes_state_holders.read_only_db_uri, so an edit to it must start e2e_upgrade
(tests/ci/test_update_ci_routing.py).
2026-10-09 02:54:01 -07:00
Teknium 607a23e858 Merge origin/main (#30: 54 commits to 1744a19e0d) into feat/unified-gateway-runtime
8 conflicts, all from main's lint sweep (#135281 "Harder linter fixes" + the RUF series:
implicit-Optional, unused-unpacked-variable, next(...) for [...][0]). No other main commit touches
a conflicted file. Resolution: the branch side of each file plus main's exact autofix
(ruff 0.15.10, main's ruff.strict.toml, --fix --unsafe-fixes) on it. ruff.strict.toml takes main's
copy (the newly enabled rules). tests/cron/test_bot_chat_delivery_child_env.py stays deleted
(1cc9cb9199 retired its lane).
2026-10-08 21:38:54 -07:00
Teknium ffcd3621a9 ci: E2E suites run only on release builds
Pull requests and pushes to main no longer run any E2E suite: ci.yaml's detect gate
forces every e2e* lane off unless the run is a stable-release run (inputs.release) or a
manual dispatch, whatever the diff, the update-path classifier or the run-e2e label
selects. That covers the Python e2e and e2e-upgrade jobs, the Windows E2E and Windows
install + update journey in tests-os, and the Desktop core/update suites.

install-e2e.yml drops its pull_request (path-filtered `pr` route) and 12-hourly
schedule triggers; it runs from the stable-release gate (workflow_call) or by dispatch.
live-providers drops its nightly schedule and keeps the release-tag push + dispatch.

Why: a one-row change to left_core_migration.py held a PR for 40 minutes on the
Windows install + update E2E; the suites cost most of the larger-runner minutes and
the release gate already runs all of them strictly.
2026-10-08 19:48:31 -07:00
Teknium ab386ebd5f ci: run the messaging-gated gateway cases in the messaging-equipped e2e job
The ordinary `test` slices install no `messaging` extra, and the e2e job,
the only one that does, selects only tests/e2e. Four gateway cases probe for
the REAL Discord/Telegram distribution and skip without it, so they ran
nowhere: both tests in test_native_role_reauthorization.py,
test_telegram_fifo_unknown_and_current_authorization_survive_sigkill and
test_crash_mid_turn_then_platform_message_gets_one_pause_notice_and_reset_unpauses.

The e2e job gains a step that runs those three whole files (run_tests.sh drops
::node selectors) with -rs and fails when the summary reports any skip, so a
missing SDK can never read as green. The classifier starts the e2e lane when
one of them is edited. A CI test derives the gated set from the source (any
tests/gateway file probing PathFinder.find_spec for discord/telegram/slack)
so a new gated file must be added to the step.

Local run of the step: with the messaging venv 5 passed, 0 skipped (rc 0);
without it 1 passed, 3 skipped -> ::error:: and rc 1.

Review: https://github.com/NousResearch/hermes-agent/pull/106742#issuecomment-6067585232
2026-10-08 19:09:39 -07:00
Teknium 65bec86e37 Merge origin/main (#27: 19 commits to 517b5e10fe) into feat/unified-gateway-runtime
45 conflicts, all from #135177 (lefthook + `ruff check --fix` over 2,366 files). No other main commit
touches a conflicted file. Resolution: the branch side of each file, then main's exact autofix
(ruff 0.15.10, `--config ./ruff.strict.toml --fix`) on it — rewrites only (typing generics, noqa
drops, import forms), no import removed. tests/cron/test_bot_chat_cli_home.py stays deleted
(1cc9cb9199 retired its lane).
2026-10-08 12:09:24 -07:00
Maciej Lisiewski aa2d120cba ci: prefix unused variables with underscore (RUF059) 2026-10-08 19:22:03 +02:00
Maciej Lisiewski d76cce4f11 ci: apply all automatic linter fixes available 2026-10-08 17:22:54 +02:00
Teknium a06c82088f ci: route web_build_limits.py to the update e2e lanes
Main (#133931) made source_build.py import hermes_cli/web_build_limits.py
without adding it to _UPDATE_DEPENDENCIES, so tests/ci/test_update_ci_routing.py
is red for e2e_upgrade and e2e_desktop_update on every merge ref that includes
it. Same one-line route main's fix/ci-routing-web-build-limits (6b5a089a00e)
adds.
2026-10-07 16:29:16 -07:00
Teknium 134e08ca6d fix(ci): route web_build_limits.py to the update e2e lanes
#133931 made source_build.py import hermes_cli/web_build_limits.py but did not add it to
_UPDATE_DEPENDENCIES, so tests/ci/test_update_ci_routing.py has been red on main and on
every PR whose merge ref includes it: a change to the module would skip the
e2e_upgrade and e2e_desktop_update lanes that run the build it shapes.
2026-10-07 15:26:14 -07:00
Teknium 28cb481f28 ci: route backup_cron_prompts.py with the update-path backup modules
The code-health split moved restore_cron_prompt_fields_if_degraded out of backup.py;
update_cmd_config imports it, so the update E2E suite must start when it changes
(tests/ci/test_update_ci_routing.py).
2026-10-07 11:37:25 -07:00
Teknium 926b207b74 ci: route local-gateway.ts (gateway ensure code_sha check) where host-backend-attach was
The pool-era host-backend-attach.ts is deleted on the branch; the attach-time version check
it carried now lives in local-gateway.ts (ensure compares code_sha with the checkout).
2026-10-07 07:33:07 -07:00
alt-glitch cbffbeecf4 ci: package __init__ files on the update path start the update E2Es
Importing a/b/c.py runs a/__init__.py and a/b/__init__.py first. The
update-lane routing listed hermes_cli/local_runtime/processes.py (the
v2026.9.24 updater imports it after the pull) but not the package init
that import runs. #134116 changed what that init loads, its PR never ran
e2e-upgrade, and main went red until #134242.

classify_changes now routes the package inits above every module the
e2e_upgrade and e2e_desktop_update lanes own, and above each shared hub,
because a hub's inits run whenever the hub is imported. An init that is
itself a hub stays out. The routing guard's import walker counts the
package inits a module's imports run, so the next unrouted one fails it.
This routes eight inits that were missing: local_runtime, gateway, cron,
tools, tools/environments, plugins, hermes_platform,
hermes_cli/observability.
2026-10-06 20:30:06 -04:00
Teknium b5a5b9b086 ci(update): route the inline-source parser and retire the landed siblings' allowance
Two ratchets this suite arms for its own siblings fired once they landed:

- the Windows pause (#132338) now imports gateway/status_inline_source.py
  to recognise inline-bootstrapped gateways, so a change there starts the
  e2e_upgrade suite like gateway/status.py (only two importers: not a hub)
- the marker-corpus consumers #132345 and #132354 ship are on main, so
  _LANDS_IN_SIBLING_PR empties as its comment asks
2026-10-06 13:02:14 -07:00