r34.0: merge upstream v2026.9.24 (Hermes 0.21.5) — fork semantics re-expressed, ledger - #362
Conversation
…ls MCP entry modules Both run as their own `python -m` processes (the dashboard compute host, the codex hermes-tools MCP server) and write os.environ while threads resolve hosts, so they need the same never-free environ guard as the other entry points.
…n -m codex_runtime, codex_app_server and the runtime migration import this module for HERMES_TOOLS_MCP_SERVER_NAME, so a module-level import of hermes_bootstrap exported TMPDIR/TMP/TEMP/HERMES_SCRATCH_DIR into every library importer (gateway.relay's read-only relay_fronted_platforms included; caught by tests/gateway/relay/test_cold_opt_out.py).
…s side-effect free tui_gateway.compute_host is also imported by tests, so the module-level hermes_bootstrap import exported TMPDIR/TMP/TEMP/HERMES_SCRATCH_DIR into the importer, the same defect as the hermes-tools MCP server. The new test imports agent.auxiliary_client, gateway.relay and tui_gateway.compute_host in a clean interpreter and asserts no bootstrap and no env change (red at b278fb7).
… of the C environ Every ctypes call in the wrapper is audited, and a hook may write os.environ re-entrantly under the RLock. The ctypes.addressof reads after the live array was walked let such a write land, and the outer publish then overwrote it (200/200 nested names lost on glibc 2.39). Store each array's address with it, and redo the read when a publish generation changed underneath.
…r spin the environ retry loop ctypes.addressof(fresh) was the one audited call inside the retry loop, so a hook writing os.environ on every ctypes event bumped the generation each pass and the loop never exited (hung past 20 s on glibc 2.39 with a full array). ctypes.cast(...).value reads the same address unaudited, leaving no audited call in the loop. Stress on glibc 2.39 (8 threads x 50k writes, 2 native getenv readers, 2,100 nested hook writes), twice: 0 crashes, 0 lost, C == os.environ.
… still reaches the picker catalog; unbind the terminal scope a test leaked Two cross-file test leaks in tests/tui_gateway/, found by pairwise bisection after a broad -k selection went red on pristine main. One was the harness, one was a product bug the harness had been hiding. 1. hermes_cli.models_catalog_static admitted plugin providers into CANONICAL_PROVIDERS once, at import. A profile registered after that import — a plugin whose own imports pull hermes_cli.models in mid-_discover_providers(), or a runtime register_provider() — never reached list_available_providers / _PROVIDER_LABELS, so the picker, hermes model, /model and Desktop model.options omitted it until restart. hermes_cli.auth already closes this window for PROVIDER_REGISTRY (NousResearch#102123); the catalog snapshot never did. providers. _sync_auth_registry now re-admits into both snapshots via sync_plugin_provider_catalog(), idempotent by slug, built-in rows untouched. Exposed as test_auto_continue.py (imports hermes_cli.models) then test_external_process_picker.py (registers a profile) failing. 2. test_release_resets_every_scope_when_one_reset_fails swaps reset_terminal_scope for one that raises — that IS the scenario — and left profile B's terminal scope bound on the main thread for every later test (test_profile_terminal_scope_entrypoints asserts it is None). The test now unbinds with the saved real reset after the release; the assertion it makes about the other scopes is unchanged. Red on main / green here: tests/hermes_cli/test_models_catalog_late_plugin_provider.py, and the two polluter+victim pairs (3 failed → 30 passed). tests/tui_gateway serial: 2041 passed, 4 failed that pass isolated and in their own files (640/640) — bisected separately.
…w/Slider/SearchField Appearance was the only page drawing booleans as an Off | On segmented control, and two rows hand-wrapped their control in items-end, so the same kind of setting sat in a different place depending on the page. ListRow now owns the action slot's alignment (left when stacked, right when wide) and every on/off preference is a ToggleRow; the two hand-rolled range inputs share a Slider, the three boxed search inputs use SearchField, and the rows that cannot be a ListRow lay out on the exported LIST_ROW_COLUMNS token.
… Settings The Bots group dialog hand-rolled a label + hint + Switch row; it now uses the same ToggleRow, and the SDK surfaces the two row primitives next to ToolsetConfigPanel.
The palette's Appearance entries were a hand-maintained list that had fallen nine rows behind the page (In-App Tips, Guided Tours, Reopen Last Chat, Session List Density, Tab Strip, Floating Composer, Message Reactions, Vibe Hearts, Collapse thinking). One manifest now owns each row's id, subpage, copy and keywords; the page, the router and the search catalog all derive from it, a test pins the contract, and a subpage named after its single setting no longer shows up twice.
The published image had no Xvnc/Xfce because nothing set the Dockerfile's HERMES_BOT_DESKTOP argument, and a hosted instance (unprivileged, no sudo, sealed /opt/hermes) cannot install at run time. The image layer is the only delivery path. - docker.yml: variant axis [slim, desktop]. :latest / :main / :v* stay the image they are today; :latest-desktop / :main-desktop / :v*-desktop carry the packages plus Playwright's headed Chromium. Slim owns the build cache scope; one manifest per variant so a desktop publish failure never skips slim's :latest. - Dockerfile / stage2-hook.sh: XDG_RUNTIME_DIR=/tmp/hermes-runtime seeded 0700 as hermes (containers have no logind; the $HOME/.cache fallback was the shared /opt/data volume), refused when foreign-owned; deterministic Chromium discovery exporting the headless shell for ordinary browsing. - bot_desktop: memory gate reads the cgroup working set (usage minus inactive_file) so it cannot tighten over uptime and refuse to restart a screen idle-stop just stopped; installable() gives three distinct dead-end messages instead of a sudo line nobody there can run; env_for_agent replaces a headless-shell pin so agent and dock share one Chromium. Squash of IAvecilla/hermes-agent:bot-desktop-cloud-image (NousResearch#112381, 13 commits), which GitHub auto-closed when its base branch merged as NousResearch#108914. Review fixes from pefontana (cache scope, per-variant merge, red browser test) are included. Co-authored-by: pefontana <pefontana@users.noreply.github.com>
… ratchet installable() asks whether the gateway host can run the package manager at all (root, or sudo present) so a hosted instance gets 'needs a newer image' instead of a sudo line it cannot run. The probe is on the control host and never installs or starts anything.
…unction-shortcuts feat(desktop): make function-key voice shortcuts rebindable
…ve-subagent registry
Mechanism: tests/tui_gateway/test_subagent_snapshot.py::runtime reset the
registries with monkeypatch.setattr(delegate_tool_registry, "_active_subagents", {})
(same for _recent_subagents and async_delegation._records). Rebinding the module
attribute forks the registry: tools.delegate_tool_progress binds _active_subagents
BY NAME at import (`from tools.delegate_tool_registry import _active_subagents`),
so once that module is loaded, _ChildProgressRelay._on_tool_started writes
last_tool/tool_count into the ORIGINAL dict while _register_subagent and
subagent.list read the replacement. Run alone, the victim imports
delegate_tool_progress inside the test body, AFTER the patch, so both names point
at the new dict. Any earlier test that imports run_agent (test_auto_continue does)
pre-loads delegate_tool_progress with the original binding, and the projection
reads last_tool=None.
Fix at the seam: the fixture now empties the shared registries in place
(clear() + restore snapshot on teardown), so every by-name alias sees the same dict,
exactly as in production where the dict is never rebound.
Harness-only: production never rebinds these module attributes; a real second
session mutates the one shared dict through the same alias.
Repro (base): python -m pytest -q -p no:cacheprovider \
tests/tui_gateway/test_auto_continue.py tests/tui_gateway/test_subagent_snapshot.py \
-k "auto_continue or only_this_sessions" -> 1 failed (last_tool None == 'read_file')
Fixed: 21 passed; both files whole 27 passed; each file alone green.
…earch-titles fix(desktop): ⌘K session search honours renames and groups pinned sessions first
…row-consistency fix(desktop): one shared row primitive per control kind across Settings; every Appearance row searchable
…thand
`_resolve_agent_model_runtime` builds the pre-agent fallback notice from
`(_load_cfg().get("model") or {}).get("provider")`. `load_user_config_effective`
keeps the `model: <id>` string shorthand as a string (every other reader —
gateway/run.py, cron/scheduler.py, hermes_cli/main.py — accepts it), so a
primary AuthError on such a config raised `'str' object has no attribute
'get'` inside the fallback branch: `setup.runtime_check` answered ok=False
("'str' object has no attribute 'get'") and `_make_agent` failed, on a
backend whose configured fallback chain was perfectly usable.
Repro: `tests/tui_gateway/test_pre_agent_fallback_notice.py::
test_fallback_build_survives_model_string_shorthand` (red on base).
Surfaced as the cross-file leak `test_protocol.py::test_config_roundtrip`
(writes `model: test/model` into a home left bound on `server._hermes_home`)
→ `test_tui_gateway_server.py::test_setup_runtime_check_agrees_with_
session_fallback_chain`.
…h transport module Two harness leaks, both in tests/tui_gateway/test_protocol.py: 1. `test_config_roundtrip` did `server._hermes_home = tmp_path` by direct assignment; the `server` fixture never restores it, so every later `_load_cfg()` in the process (any file after it) read that test's `model: test/model` config. Victims: `test_setup_runtime_check_agrees_with_ session_fallback_chain` (fallback branch → product bug, fixed in the previous commit) and `test_notification_poller_live_loop_drops_addressed_ orphan` (the per-turn config sync tried to switch a stub agent to `test/model` and emitted `error` events). monkeypatch.setattr restores it. 2. The `server` fixture's `patch.dict(sys.modules)` window drops every module FIRST imported inside it; `tui_gateway.transport` was one, so when test_protocol ran first in a process, a test's own `from tui_gateway.transport import bind_transport` got a fresh module whose ContextVar the server's `current_transport()` never read — `client.capabilities` advertised `_stdio_transport` instead of the test's WS peer and `send()` failed fast (`test_server_request_waits_for_a_ws_client_that_advertised` red alone, green after any test that imported transport). Pre-import it like server_requests. Repro (base): `python -m pytest -q -p no:cacheprovider tests/tui_gateway/test_protocol.py tests/tui_gateway/test_tui_gateway_server.py::test_setup_runtime_check_agrees_with_session_fallback_chain` → 1 failed; `python -m pytest -q tests/tui_gateway/test_protocol.py:: test_server_request_waits_for_a_ws_client_that_advertised` → 1 failed.
A plugin that lives in a monorepo subdirectory (the Hindsight catalog entry: vectorize-io/hindsight#hindsight-integrations/hermes) was cloned with every file in the repository even at --depth 1: 170 MB for a 2 MB plugin folder. On a slow link that exceeds any reasonable deadline, so `hermes update`'s Hindsight migration failed with "Git clone timed out" every time. Subdirectory installs now do a blobless clone (--filter=blob:none --no-checkout) and a sparse checkout of just that folder, written as the classic info/sparse-checkout file so older Git clients work too. Servers without partial-clone support ignore the filter and fall back to the old download. Because a partial clone downloads file contents at checkout time, the checkout step (pinned and unpinned) now gets the configured network deadline and the credential fallback, same as clone and fetch. Every timeout error names plugins.clone_timeout_seconds so users can find the knob. Existing test fakes of _clone_plugin_repo accept the new subdir argument.
…ly that folder Desktop's own Git plugin probe and install (cloneToTemp) had the same full-tree clone and a hard-coded 60 s deadline, so pasting vectorize-io/hindsight/hindsight-integrations/hermes into Desktop failed exactly like the CLI did. A subdirectory identifier now takes the same blobless clone + sparse checkout of that folder, and the Git deadline matches the backend default of 300 s. The timeout message names the Git verb that actually ran.
…ette Only Appearance rows were searchable; ~20 preference rows across Advanced, Chat, Keyboard, Notifications, Archived Chats, Gateways and About had no palette entry at all (Keep Awake, Disable F12, pool limits, Quick Entry, attachment limit, Chat/Terminal Font, every notification toggle, Completion Sound, Auto-archive, gateway mode/keychain/diagnostics, Automatic updates). One manifest (`settings-manifest.ts`) now owns every hand-built row's id, subpage, copy, keywords and platform availability. Row element ids, deep-link routing (`?setting=<view>.<key>`) and the palette catalog all derive from it, and a contract test walks the whole manifest: each row routes to a real subpage, resolves copy in every locale, and reaches the palette. `useSettingDeepLink(view, show)` replaces the per-page highlight hooks; the HUD modifier special case folds into the manifest as `keybinds.hud-modifier`.
…search-manifest feat(desktop): every hand-built settings row is searchable in the command palette
…f-cwd fix(relay): include cwd in session and turn scopes
`_usage_from_metadata` (agent/gemini_native_adapter.py:476) read
`candidatesTokenCount` for `completion_tokens` and never read
`thoughtsTokenCount`; a repo-wide grep found that field nowhere. Gemini
reports hidden thinking in its own counter — `candidatesTokenCount` covers
visible output only, while `totalTokenCount` already includes thoughts. So on
any thinking turn the emitted usage contradicted itself: prompt + completion
did not add up to total.
Both the non-streaming assembly (translate_gemini_response) and the streaming
one (the finish chunk in translate_stream_event) share this helper, so both
under-billed identically. `normalize_usage` takes `completion_tokens` for
`output_tokens` and looks for reasoning under
`completion_tokens_details.reasoning_tokens`, which the adapter never set, so
the reasoning column read 0 for models whose spend is mostly reasoning.
Thoughts are now folded into `completion_tokens` (OpenAI's counter includes
reasoning) and surfaced under `completion_tokens_details.reasoning_tokens`,
matching the nesting the adapter already uses for
`prompt_tokens_details.cached_tokens`. The field is absent on non-thinking and
older responses; those count 0 and their numbers do not move.
Live: for usageMetadata {prompt 10, candidates 200, thoughts 5000, total 5210}
the adapter emitted completion_tokens=200 (10 + 200 != 5210) and
normalize_usage returned output_tokens=200, reasoning_tokens=0. It now emits
completion_tokens=5200 (10 + 5200 == 5210) with
completion_tokens_details.reasoning_tokens=5000, and normalize_usage returns
output_tokens=5200, reasoning_tokens=5000.
Keep the non-streaming invariant (prompt + completion == total, thoughts surfaced as reasoning_tokens) and the no-thoughts control; the streaming case exercised the same _usage_from_metadata helper and added no new property.
…ider setup The model picker reads its catalog with the backend target profile, but Add provider reused that name as the setup owner. For SSH aliases this changed the registry scope key and could dial a second pooled backend. Pass the Desktop route profile separately for the setup handoff.
An explicit scope carrying only connectionId routed OAuth REST to that connection while readiness stayed on the ambient gateway. Select the scoped dispatcher whenever a connection is pinned.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 23e17286a7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ry before the discovery lock, shared-file write-through for the quota-probe rotation, ledger) — 10 files
There was a problem hiding this comment.
Walkthrough
PR: #362 - r34.0: merge upstream v2026.9.24 (Hermes 0.21.5) — fork semantics re-expressed, ledger
Head: b56c1a32c159c13842f0ded7b2fc77dda63e3e85 into main. Review event: COMMENT.
Estimated review effort: 5/5 (~70 min)
Changed Files
| File | Status | Churn | Purpose | Risk |
|---|---|---|---|---|
.dockerignore |
modified | +1/-2 | Changed file | Low |
.env.example |
modified | +0/-8 | Changed file | Low |
.github/scripts/run-workspace-checks.mjs |
modified | +3/-1 | Changed file | Low |
.github/workflows/ci.yaml |
modified | +13/-7 | Changed file | Low |
.github/workflows/deploy-site.yml |
modified | +11/-0 | Changed file | Low |
.github/workflows/docker.yml |
modified | +46/-19 | Changed file | Low |
.github/workflows/docs-site-checks.yml |
modified | +13/-0 | Changed file | Moderate: validated P2 finding |
.github/workflows/e2e-desktop-core.yml |
added | +102/-0 | Changed file | Moderate: validated P2 finding |
.github/workflows/installer-tests.yml |
modified | +8/-0 | Changed file | Low |
.github/workflows/js-tests.yml |
modified | +14/-0 | Changed file | Low |
.github/workflows/lint.yml |
modified | +37/-0 | Changed file | Low |
.github/workflows/live-providers.yml |
added | +137/-0 | Changed file | Low |
.github/workflows/osv-scanner.yml |
modified | +4/-93 | Changed file | Low |
.github/workflows/plugin-catalog-ci.yml |
modified | +15/-4 | Changed file | Moderate: validated P2 finding |
.github/workflows/skills-index.yml |
modified | +28/-2 | Changed file | Low |
.github/workflows/tests-os.yml |
modified | +3/-3 | Test coverage | Low |
.github/workflows/tests.yml |
modified | +181/-8 | Test coverage | Low |
.github/workflows/windows-venv-e2e.yml |
modified | +1/-1 | Changed file | Low |
.gitignore |
modified | +82/-2 | Changed file | Low |
AGENTS.md |
modified | +48/-7 | Documentation | Low |
COMPAT_MANIFEST.md |
modified | +0/-11 | Documentation | Low |
CONTRIBUTING.es.md |
modified | +1/-1 | Documentation | Low |
CONTRIBUTING.md |
modified | +7/-2 | Documentation | Low |
Dockerfile |
modified | +56/-8 | Changed file | Low |
acp_adapter/commands.py |
modified | +59/-38 | Changed file | Low |
2975 additional changed files omitted from this walkthrough.
Review Signal
Validated inline findings: 3 (P0: 0, P1: 0, P2: 3, P3: 0).
Dropped findings before posting: 0. High-severity findings: 0.
Maintainer Analysis
Changed behavior:
- Adds desktop, Python E2E, upgrade, and live-provider CI lanes, with the fork's upstream E2E lanes guarded by RUN_UPSTREAM_E2E.
- Adds a catalog policy check intended to reject self-updating plugins.
- Adds generated-doc and cross-page-link checks.
- Builds and publishes separate slim and desktop Docker variants.
- Moves OSV scanning from per-PR CI to scheduled/manual scanning.
Affected invariants:
- Catalog plugins must not update their own installed code outside the reviewed pin.
- Required acceptance gates must execute rather than report green through a skipped inner job.
- Generated documentation committed to the repository must match all generator outputs, including new files.
Evidence:
- .github/workflows/plugin-catalog-ci.yml:140 pipes URL-matching files into the write-operation grep.
- .github/workflows/e2e-desktop-core.yml:27 guards the workflow's only job with an opt-in repository variable.
- .github/workflows/docs-site-checks.yml:51 omits website/i18n from the intent-to-add paths while line 52 includes it in git diff.
Limitations:
- The supplied patch was truncated for most changed files.
- Per instruction, no shell commands, project code, tests, builds, or package scripts were run.
- Findings are limited to defects directly validated from the visible diff.
No-finding rationale: No additional issue was reported where the visible patch did not establish a concrete failing path or invariant violation.
Risk Taxonomy
- CI/build: 2
- Security boundary: 1
Validation and Proof
3 required validation/proof recommendation(s) selected from changed files.
- required: Unity editor or Play Mode smoke - Unity asset/script/project files changed. Proof: Unity editor smoke; Play Mode log; scene/prefab screenshot or recording.
- required: TypeScript/web build or CI proof - Runtime TypeScript/web files or package/config files changed. Proof: npm run build; typecheck; focused Vitest; green GitHub check.
- required: CI/release smoke proof - CI, release, launchd, or package metadata changed. Proof: green GitHub check; release-status; coverage-audit; rollback note.
Proof status: missing - 2 required validation/proof recommendation(s) missing from PR metadata.
Related Context
Related issues/PRs: #336, #348, #352, NousResearch#479, #321, #363, #344, #355.
Pre-merge checklist
- Inline comments target current RIGHT-side diff lines.
- No secret-like content survived into posted inline comments.
- REQUEST_CHANGES is only used when eligible P0/P1 findings survive validation.
- Required behavior proof is present or not applicable.
💡 Codex ReviewevaOS-hermes-desktop-app-adapter/hermes_cli/update_cmd_maint.py Lines 257 to 259 in b56c1a3 When a user upgrades an r33 Git installation in place with AGENTS.md reference: hermes_cli/AGENTS.md:L176-L184 evaOS-hermes-desktop-app-adapter/tui_gateway/agent_callbacks.py Lines 167 to 169 in b56c1a3 For a Desktop session that negotiates protocol 1, including a legacy client that omits the protocol marker, AGENTS.md reference: tui_gateway/AGENTS.md:L21-L32 ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…viewer's own peer only, FanoutTransport two-viewer test, ledger) — 10 files
There was a problem hiding this comment.
Walkthrough
PR: #362 - r34.0: merge upstream v2026.9.24 (Hermes 0.21.5) — fork semantics re-expressed, ledger
Head: 2efd369b9fbb03851c431d992a28c1204110c1ce into main. Review event: COMMENT.
Estimated review effort: 5/5 (~70 min)
Changed Files
| File | Status | Churn | Purpose | Risk |
|---|---|---|---|---|
.dockerignore |
modified | +1/-2 | Changed file | Low |
.env.example |
modified | +0/-8 | Changed file | Low |
.github/scripts/run-workspace-checks.mjs |
modified | +3/-1 | Changed file | Low |
.github/workflows/ci.yaml |
modified | +13/-7 | Changed file | Moderate: validated P2 finding |
.github/workflows/deploy-site.yml |
modified | +11/-0 | Changed file | Low |
.github/workflows/docker.yml |
modified | +46/-19 | Changed file | Low |
.github/workflows/docs-site-checks.yml |
modified | +13/-0 | Changed file | Moderate: validated P3 finding |
.github/workflows/e2e-desktop-core.yml |
added | +102/-0 | Changed file | Moderate: validated P2 finding |
.github/workflows/installer-tests.yml |
modified | +8/-0 | Changed file | Low |
.github/workflows/js-tests.yml |
modified | +14/-0 | Changed file | Low |
.github/workflows/lint.yml |
modified | +37/-0 | Changed file | Low |
.github/workflows/live-providers.yml |
added | +137/-0 | Changed file | Low |
.github/workflows/osv-scanner.yml |
modified | +4/-93 | Changed file | Low |
.github/workflows/plugin-catalog-ci.yml |
modified | +15/-4 | Changed file | Low |
.github/workflows/skills-index.yml |
modified | +28/-2 | Changed file | Low |
.github/workflows/tests-os.yml |
modified | +3/-3 | Test coverage | Low |
.github/workflows/tests.yml |
modified | +181/-8 | Test coverage | Low |
.github/workflows/windows-venv-e2e.yml |
modified | +1/-1 | Changed file | Low |
.gitignore |
modified | +82/-2 | Changed file | Low |
AGENTS.md |
modified | +48/-7 | Documentation | Low |
COMPAT_MANIFEST.md |
modified | +0/-11 | Documentation | Low |
CONTRIBUTING.es.md |
modified | +1/-1 | Documentation | Low |
CONTRIBUTING.md |
modified | +7/-2 | Documentation | Low |
Dockerfile |
modified | +56/-8 | Changed file | Low |
acp_adapter/commands.py |
modified | +59/-38 | Changed file | Low |
2975 additional changed files omitted from this walkthrough.
Review Signal
Validated inline findings: 3 (P0: 0, P1: 0, P2: 2, P3: 1).
Dropped findings before posting: 0. High-severity findings: 0.
Maintainer Analysis
Changed behavior:
- Adds desktop and Python end-to-end lanes, but gates them behind RUN_UPSTREAM_E2E.
- Removes OSV scanning from pull-request CI and retains only scheduled/manual scanning.
- Adds generated documentation parity and cross-page link checks.
- Builds and publishes separate slim and desktop container variants.
Affected invariants:
- A required CI gate should prove that its named tests executed, not pass through an opt-in skip.
- Dependency changes should receive vulnerability analysis before merge.
- Generated-document parity checks must detect both tracked changes and untracked generated files.
Evidence:
- .github/workflows/e2e-desktop-core.yml:27
- .github/workflows/tests.yml:216
- .github/workflows/ci.yaml:263
- .github/workflows/docs-site-checks.yml:51
Limitations:
- Most source patches were omitted from the supplied diff because of prompt truncation.
- Per instruction, no shell commands, project tests, builds, app commands, or additional checkout inspection were performed.
- Repository-variable state and current GitHub check results were not available, so the E2E finding addresses the workflow's explicit opt-in/default behavior.
No-finding rationale: The remaining visible workflow, Docker, ignore-file, and documentation changes did not establish another concrete current-path failure from the supplied evidence; omitted patches were not assessed speculatively.
Risk Taxonomy
- CI/build: 2
- Dependency: 1
Validation and Proof
3 required validation/proof recommendation(s) selected from changed files.
- required: Unity editor or Play Mode smoke - Unity asset/script/project files changed. Proof: Unity editor smoke; Play Mode log; scene/prefab screenshot or recording.
- required: TypeScript/web build or CI proof - Runtime TypeScript/web files or package/config files changed. Proof: npm run build; typecheck; focused Vitest; green GitHub check.
- required: CI/release smoke proof - CI, release, launchd, or package metadata changed. Proof: green GitHub check; release-status; coverage-audit; rollback note.
Proof status: missing - 2 required validation/proof recommendation(s) missing from PR metadata.
Related Context
Related issues/PRs: #336, #348, #352, NousResearch#479, #321, #363, #344, #355.
Pre-merge checklist
- Inline comments target current RIGHT-side diff lines.
- No secret-like content survived into posted inline comments.
- REQUEST_CHANGES is only used when eligible P0/P1 findings survive validation.
- Required behavior proof is present or not applicable.
💡 Codex ReviewWhen an existing secondary profile's evaOS-hermes-desktop-app-adapter/tui_gateway/agent_callbacks.py Lines 167 to 169 in 2efd369 In a mixed-viewer session, the session-level AGENTS.md reference: tui_gateway/AGENTS.md:L3-L5 evaOS-hermes-desktop-app-adapter/gateway/run_profile_reconcile.py Lines 149 to 152 in 2efd369 When a newly discovered profile raises This change expands the test's filesystem scan from the component subtree to all of AGENTS.md reference: AGENTS.md:L426-L433 ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…viewer entry, mixed-source tests, ledger) — 5 files
There was a problem hiding this comment.
Walkthrough
PR: #362 - r34.0: merge upstream v2026.9.24 (Hermes 0.21.5) — fork semantics re-expressed, ledger
Head: d00b0fe6f811706d6b958a8fcffb2c557378446f into main. Review event: COMMENT.
Estimated review effort: 5/5 (~70 min)
Changed Files
| File | Status | Churn | Purpose | Risk |
|---|---|---|---|---|
.dockerignore |
modified | +1/-2 | Changed file | Low |
.env.example |
modified | +0/-8 | Changed file | Low |
.github/scripts/run-workspace-checks.mjs |
modified | +3/-1 | Changed file | Low |
.github/workflows/ci.yaml |
modified | +13/-7 | Changed file | Moderate: validated P2 finding |
.github/workflows/deploy-site.yml |
modified | +11/-0 | Changed file | Low |
.github/workflows/docker.yml |
modified | +46/-19 | Changed file | Low |
.github/workflows/docs-site-checks.yml |
modified | +13/-0 | Changed file | Low |
.github/workflows/e2e-desktop-core.yml |
added | +102/-0 | Changed file | Low |
.github/workflows/installer-tests.yml |
modified | +8/-0 | Changed file | Low |
.github/workflows/js-tests.yml |
modified | +14/-0 | Changed file | Low |
.github/workflows/lint.yml |
modified | +37/-0 | Changed file | Low |
.github/workflows/live-providers.yml |
added | +137/-0 | Changed file | Low |
.github/workflows/osv-scanner.yml |
modified | +4/-93 | Changed file | Low |
.github/workflows/plugin-catalog-ci.yml |
modified | +15/-4 | Changed file | Low |
.github/workflows/skills-index.yml |
modified | +28/-2 | Changed file | Low |
.github/workflows/tests-os.yml |
modified | +3/-3 | Test coverage | Low |
.github/workflows/tests.yml |
modified | +181/-8 | Test coverage | Moderate: validated P2 finding |
.github/workflows/windows-venv-e2e.yml |
modified | +1/-1 | Changed file | Low |
.gitignore |
modified | +82/-2 | Changed file | Low |
AGENTS.md |
modified | +48/-7 | Documentation | Low |
COMPAT_MANIFEST.md |
modified | +0/-11 | Documentation | Low |
CONTRIBUTING.es.md |
modified | +1/-1 | Documentation | Low |
CONTRIBUTING.md |
modified | +7/-2 | Documentation | Low |
Dockerfile |
modified | +56/-8 | Changed file | Low |
acp_adapter/commands.py |
modified | +59/-38 | Changed file | Low |
2975 additional changed files omitted from this walkthrough.
Review Signal
Validated inline findings: 2 (P0: 0, P1: 0, P2: 2, P3: 0).
Dropped findings before posting: 0. High-severity findings: 0.
Maintainer Analysis
Changed behavior:
- Python and Desktop core E2E jobs now run only when
RUN_UPSTREAM_E2Eis explicitly enabled. - OSV scanning was removed from per-PR CI and retained only for scheduled or manual execution.
- Docker publishing now builds separate slim and desktop variants for amd64 and arm64.
Affected invariants:
- Integration-sensitive changes should exercise a real end-to-end path before merge.
- Dependency changes should receive timely vulnerability feedback before entering the default branch.
Evidence:
.github/workflows/tests.yml:216gates the Python E2E job onvars.RUN_UPSTREAM_E2E == 'true'..github/workflows/e2e-desktop-core.yml:27applies the same opt-in gate to Desktop core E2E..github/workflows/ci.yaml:263documents removal of OSV from per-PR CI.
Limitations:
- Most file patches were omitted from the supplied diff because of prompt truncation, so their implementation details could not be reviewed.
- No shell commands, project tests, builds, package scripts, or PR code were executed, as requested.
- Only the visible diff hunks were assessed.
No-finding rationale: No additional defect was validated from the visible hunks with sufficient evidence; omitted patches were not treated as evidence.
Risk Taxonomy
- CI/build: 1
- Dependency: 1
Validation and Proof
3 required validation/proof recommendation(s) selected from changed files.
- required: Unity editor or Play Mode smoke - Unity asset/script/project files changed. Proof: Unity editor smoke; Play Mode log; scene/prefab screenshot or recording.
- required: TypeScript/web build or CI proof - Runtime TypeScript/web files or package/config files changed. Proof: npm run build; typecheck; focused Vitest; green GitHub check.
- required: CI/release smoke proof - CI, release, launchd, or package metadata changed. Proof: green GitHub check; release-status; coverage-audit; rollback note.
Proof status: missing - 2 required validation/proof recommendation(s) missing from PR metadata.
Related Context
Related issues/PRs: #336, #348, #352, NousResearch#479, #321, #363, #344, #355.
Pre-merge checklist
- Inline comments target current RIGHT-side diff lines.
- No secret-like content survived into posted inline comments.
- REQUEST_CHANGES is only used when eligible P0/P1 findings survive validation.
- Required behavior proof is present or not applicable.
💡 Codex ReviewWhen When a git installation updates from the immediately preceding r33 tree to this revision, AGENTS.md reference: hermes_cli/AGENTS.md:L176-L184 evaOS-hermes-desktop-app-adapter/tui_gateway/agent_callbacks.py Lines 166 to 167 in d00b0fe For goal continuations, auto-continue turns, and notification turns, AGENTS.md reference: AGENTS.md:L87-L88 When ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…ssion source, ledger receipt) — 2 files
There was a problem hiding this comment.
Walkthrough
PR: #362 - r34.0: merge upstream v2026.9.24 (Hermes 0.21.5) — fork semantics re-expressed, ledger
Head: c348ccf78e2b58a8efe300681acc740d1b5fc2f7 into main. Review event: COMMENT.
Estimated review effort: 5/5 (~70 min)
Changed Files
| File | Status | Churn | Purpose | Risk |
|---|---|---|---|---|
.dockerignore |
modified | +1/-2 | Changed file | Low |
.env.example |
modified | +0/-8 | Changed file | Low |
.github/scripts/run-workspace-checks.mjs |
modified | +3/-1 | Changed file | Low |
.github/workflows/ci.yaml |
modified | +13/-7 | Changed file | Low |
.github/workflows/deploy-site.yml |
modified | +11/-0 | Changed file | Low |
.github/workflows/docker.yml |
modified | +46/-19 | Changed file | Low |
.github/workflows/docs-site-checks.yml |
modified | +13/-0 | Changed file | Low |
.github/workflows/e2e-desktop-core.yml |
added | +102/-0 | Changed file | Moderate: validated P2 finding |
.github/workflows/installer-tests.yml |
modified | +8/-0 | Changed file | Low |
.github/workflows/js-tests.yml |
modified | +14/-0 | Changed file | Low |
.github/workflows/lint.yml |
modified | +37/-0 | Changed file | Low |
.github/workflows/live-providers.yml |
added | +137/-0 | Changed file | Low |
.github/workflows/osv-scanner.yml |
modified | +4/-93 | Changed file | Low |
.github/workflows/plugin-catalog-ci.yml |
modified | +15/-4 | Changed file | Low |
.github/workflows/skills-index.yml |
modified | +28/-2 | Changed file | Low |
.github/workflows/tests-os.yml |
modified | +3/-3 | Test coverage | Low |
.github/workflows/tests.yml |
modified | +181/-8 | Test coverage | Low |
.github/workflows/windows-venv-e2e.yml |
modified | +1/-1 | Changed file | Low |
.gitignore |
modified | +82/-2 | Changed file | Low |
AGENTS.md |
modified | +48/-7 | Documentation | Low |
COMPAT_MANIFEST.md |
modified | +0/-11 | Documentation | Low |
CONTRIBUTING.es.md |
modified | +1/-1 | Documentation | Low |
CONTRIBUTING.md |
modified | +7/-2 | Documentation | Low |
Dockerfile |
modified | +56/-8 | Changed file | Low |
acp_adapter/commands.py |
modified | +59/-38 | Changed file | Low |
2975 additional changed files omitted from this walkthrough.
Review Signal
Validated inline findings: 1 (P0: 0, P1: 0, P2: 1, P3: 0).
Dropped findings before posting: 0. High-severity findings: 0.
Maintainer Analysis
Changed behavior:
- Adds a desktop core E2E reusable workflow and includes it in the CI aggregate gate.
- Expands Docker publishing to slim and desktop variants.
- Moves OSV scanning from per-PR CI to a weekly/manual workflow.
- Adds and expands CI checks for docs, platform behavior, plugin validation, SQLite WAL support, and upgrade paths.
Affected invariants:
- Required CI gates must not report success when their underlying validation never ran.
- Desktop transcript integrity, backend lifecycle, and interactive approval paths require executable end-to-end coverage.
Evidence:
- .github/workflows/ci.yaml adds
e2e-desktop-coreto the gate dependencies. - .github/workflows/e2e-desktop-core.yml:27 skips the workflow's only job unless
vars.RUN_UPSTREAM_E2E == 'true'.
Limitations:
- Most file patches were omitted from the supplied diff because of prompt limits.
- Per instruction, no shell commands, tests, builds, package scripts, or PR code were executed.
No-finding rationale: No additional issue was reported because the remaining visible changes did not establish a concrete supported-path failure, and omitted patches could not be inspected without prohibited shell access.
Risk Taxonomy
- CI/build: 1
Validation and Proof
3 required validation/proof recommendation(s) selected from changed files.
- required: Unity editor or Play Mode smoke - Unity asset/script/project files changed. Proof: Unity editor smoke; Play Mode log; scene/prefab screenshot or recording.
- required: TypeScript/web build or CI proof - Runtime TypeScript/web files or package/config files changed. Proof: npm run build; typecheck; focused Vitest; green GitHub check.
- required: CI/release smoke proof - CI, release, launchd, or package metadata changed. Proof: green GitHub check; release-status; coverage-audit; rollback note.
Proof status: missing - 2 required validation/proof recommendation(s) missing from PR metadata.
Related Context
Related issues/PRs: #336, #348, #352, NousResearch#479, #321, #363, #344, #355.
Pre-merge checklist
- Inline comments target current RIGHT-side diff lines.
- No secret-like content survived into posted inline comments.
- REQUEST_CHANGES is only used when eligible P0/P1 findings survive validation.
- Required behavior proof is present or not applicable.
… startup_failure on its rerun)
There was a problem hiding this comment.
Walkthrough
PR: #362 - r34.0: merge upstream v2026.9.24 (Hermes 0.21.5) — fork semantics re-expressed, ledger
Head: 81659bb69e00f44065cf645f3163b059e5075183 into main. Review event: COMMENT.
Estimated review effort: 5/5 (~70 min)
Changed Files
| File | Status | Churn | Purpose | Risk |
|---|---|---|---|---|
.dockerignore |
modified | +1/-2 | Changed file | Low |
.env.example |
modified | +0/-8 | Changed file | Low |
.github/scripts/run-workspace-checks.mjs |
modified | +3/-1 | Changed file | Low |
.github/workflows/ci.yaml |
modified | +13/-7 | Changed file | Moderate: validated P2 finding |
.github/workflows/deploy-site.yml |
modified | +11/-0 | Changed file | Low |
.github/workflows/docker.yml |
modified | +46/-19 | Changed file | Low |
.github/workflows/docs-site-checks.yml |
modified | +13/-0 | Changed file | Low |
.github/workflows/e2e-desktop-core.yml |
added | +102/-0 | Changed file | Moderate: validated P2 finding |
.github/workflows/installer-tests.yml |
modified | +8/-0 | Changed file | Low |
.github/workflows/js-tests.yml |
modified | +14/-0 | Changed file | Low |
.github/workflows/lint.yml |
modified | +37/-0 | Changed file | Low |
.github/workflows/live-providers.yml |
added | +137/-0 | Changed file | Low |
.github/workflows/osv-scanner.yml |
modified | +4/-93 | Changed file | Low |
.github/workflows/plugin-catalog-ci.yml |
modified | +15/-4 | Changed file | Low |
.github/workflows/skills-index.yml |
modified | +28/-2 | Changed file | Low |
.github/workflows/tests-os.yml |
modified | +3/-3 | Test coverage | Low |
.github/workflows/tests.yml |
modified | +181/-8 | Test coverage | Low |
.github/workflows/windows-venv-e2e.yml |
modified | +1/-1 | Changed file | Low |
.gitignore |
modified | +82/-2 | Changed file | Low |
AGENTS.md |
modified | +48/-7 | Documentation | Low |
COMPAT_MANIFEST.md |
modified | +0/-11 | Documentation | Low |
CONTRIBUTING.es.md |
modified | +1/-1 | Documentation | Low |
CONTRIBUTING.md |
modified | +7/-2 | Documentation | Low |
Dockerfile |
modified | +56/-8 | Changed file | Low |
acp_adapter/commands.py |
modified | +59/-38 | Changed file | Low |
2975 additional changed files omitted from this walkthrough.
Review Signal
Validated inline findings: 2 (P0: 0, P1: 0, P2: 2, P3: 0).
Dropped findings before posting: 0. High-severity findings: 0.
Maintainer Analysis
Changed behavior:
- The desktop core E2E workflow is added to the CI dependency graph but its sole job runs only when
RUN_UPSTREAM_E2Eis true. - OSV scanning is removed from per-PR CI and retained only as scheduled/manual scanning.
- Docker publishing now builds and publishes slim and desktop variants for amd64 and arm64.
- Several new lint, documentation, installer, and CI checks are introduced.
Affected invariants:
- Required CI coverage must execute rather than pass through a skipped reusable-workflow job.
- Dependency changes should be checked for newly introduced known vulnerabilities before merge.
Evidence:
- .github/workflows/e2e-desktop-core.yml:29 gates the only E2E job on a repository variable.
- .github/workflows/ci.yaml:263 documents removal of OSV from every PR.
- .github/workflows/osv-scanner.yml removes
workflow_call, preventing selective invocation by PR CI.
Limitations:
- The supplied patch was truncated for most changed files, so those changes could not be reviewed at diff-line granularity.
- Per instruction, no shell commands, tests, builds, package scripts, or PR code were executed.
- Repository-variable values and live GitHub branch-protection behavior were not available from the checkout.
No-finding rationale: Beyond the two concrete CI coverage regressions above, the visible diff did not prove another current-path correctness, security, data-loss, release, or build failure without relying on omitted patches or runtime execution.
Risk Taxonomy
- CI/build: 1
- Dependency: 1
Validation and Proof
3 required validation/proof recommendation(s) selected from changed files.
- required: Unity editor or Play Mode smoke - Unity asset/script/project files changed. Proof: Unity editor smoke; Play Mode log; scene/prefab screenshot or recording.
- required: TypeScript/web build or CI proof - Runtime TypeScript/web files or package/config files changed. Proof: npm run build; typecheck; focused Vitest; green GitHub check.
- required: CI/release smoke proof - CI, release, launchd, or package metadata changed. Proof: green GitHub check; release-status; coverage-audit; rollback note.
Proof status: missing - 2 required validation/proof recommendation(s) missing from PR metadata.
Related Context
Related issues/PRs: #336, #348, #352, NousResearch#479, #321, #363, #344, #355.
Pre-merge checklist
- Inline comments target current RIGHT-side diff lines.
- No secret-like content survived into posted inline comments.
- REQUEST_CHANGES is only used when eligible P0/P1 findings survive validation.
- Required behavior proof is present or not applicable.
True two-parent merge of upstream tag
v2026.9.24(f97608f178, Hermes 0.21.5) intomain, with every conflict resolved, fork semantics re-expressed where upstream moved the behaviour, and the ledgerdocs/r34-managed-delta.md. PR-1 of 3 (PR-2 = old-client prompt shim, PR-3 = CI compat-source move + paired-release doc). Claim class:branch_verified(source qualification only; no release, box or customer claim).Merge commit
1320bfe883has parents006e26669f(main) andf97608f178(tag). It carries the conflict markers; the group commits after it resolve one conflict group each, so only the branch head is a runnable tree.origin/main(5ce867985c, docs-only) was merged in afterwards. Merge with a merge commit — never squash or rebase.Conflict groups
5aaac773cb34c5e0ac586c6e1b80a0,3503dba901,7b370294338fdfaf1fb596c3bfc06ea96714d8b07073ba2b2c600bf6cb840f4ecb49061ef5753e6cCensus: 202 conflicted paths (174 UU, 10 AA, 11 AU, 7 UD); 429 hunks default style (recon ~372, +15%). Per-file decisions:
docs/r34-managed-delta.md§Resolutions.RISK
disablednever read; v45 connections not appended — intended; v44 defaults in code; v43 key inert)_bind_session_attachment, disarming the orphan reap)[uvloop]extra present; pyproject/uv.lock identical to tagdesktop_ui_protocol) and reload.env/reload.mcp (profile); 207 recorded es.9 shapes replay with zero 4000s exceptconnectors.list/connectors.connect(STOP-AND-REPORT: es.9 sends{session_id}, tag requiresowner— PR-2 shim). #321 TIMEOUT_RESPONSE carriedState DB rollback check: fork → r34 → fork on one state.db reads, appends and searches every row (upstream FTS storage v3).
Tests
uv lock --checknpm run test:managed(264)npm run typecheck/npm run test:ui(8710)vitest run src/components/boot-failure-overlay(11)npx playwright test e2e/managed-boot.spec.ts --fail-on-flaky-tests(6)npm run test:desktop:platformsmacos-sysroot-nativefailure, the same on the raw tagscripts/run_tests.sh -j 8atb61ee8c80723e17286a7(run 36146225838)test_process_heartbeattiming flake, same test and code as the tag).All required checks passis red only onreview-labels; the three opt-in e2e jobs are skipped and count as not failede2e,e2e-upgrade,Desktop core E2ERUN_UPSTREAM_E2Euntil #363 is triaged. They never passed on the fork. First run at19878db641:e2eMCP parity calls refused by the fork-only approval gate;e2e-upgrader33 → r34 in-placehermes updatescope_homeTypeError (NON_BLOCKING for the fleet: PCS stages release dirs, never updates in place);Desktop core E2E7/7 specs red.CI-sensitive changes for review (also in the ledger): the PR-slice
HERMES_TEST_FILE_TIMEOUTis 600s; thetest_compute_hosthello wait is 10s;e2e,e2e-upgradeandDesktop core E2Erun onubuntu-latest(notubuntu-latest-32-core); and those three jobs are behind theRUN_UPSTREAM_E2Eopt-in gate.How the local suite failures were dispositioned:
origin/mainor on the raw tag, per file (macOS host): voice and transcription, ripgrep search, code kernel, approval, delegate, cua overlay, session recovery, cross-VM WAL refusal, guest durability barriers, bot desktop resources, swap-file lock retry, compaction prompt rebuild, kanban db, plugin validate, update import guard,update_interrupted_pull(localgit clonecopy error, also on the raw tag).web_server_approvals_broadcastteardown, fixed in77c71e19e8.Refs #344 and the r34.0 source-qualification issue #355.