test: add unit tests for 8 untested core modules - #60
Merged
Conversation
Add comprehensive test coverage for: - cron/jobs.py: schedule parsing, job CRUD, due-job detection (34 tests) - tools/memory_tool.py: security scanning, MemoryStore ops, dispatcher (32 tests) - toolsets.py: resolution, validation, composition, cycle detection (19 tests) - tools/file_operations.py: write deny list, result dataclasses, helpers (37 tests) - agent/prompt_builder.py: context scanning, truncation, skills index (24 tests) - agent/model_metadata.py: token estimation, context lengths (16 tests) - hermes_state.py: SessionDB SQLite CRUD, FTS5 search, export, prune (28 tests) Total: 210 new tests, all passing (380 total suite).
These tests documented the macOS symlink bypass bug with platform-conditional assertions. The fix and proper regression tests are in PR NousResearch#61 (tests/tools/test_write_deny.py), so remove them here to avoid ordering conflicts between the two PRs.
linxule
added a commit
to linxule/hermes-agent
that referenced
this pull request
Apr 27, 2026
…k variant Parity port from linxule/hermes-kimi-plugin@93476f5 — same four fixes plus the NousResearch#60 fold-in: 1. connect# off-by-one: counter + ts now bumped pre-dispatch in _group_subscribe_once so the gap log inside _on_group_event reads the correct connect# (matches the subscribe-stream-live log emitted moments later). Subscribe-live log + backoff clamp stay post-dispatch as the operator-visible recovery announcement. 2. Monotonic clock: arrival-time tracking + since-reconnect correlation now use time.monotonic() (immune to NTP/leap-second/VM-suspend). 3. _BoundedLRU shared cap: _last_arrival_time_per_room gets its own _ARRIVAL_TIME_CACHE_DEFAULT_MAX (10000), so eviction can't blind Phase 0 gap detection under cardinality pressure. 4. Anchor-only-on-first-page in list_group_messages: pageToken and start_message_id/end_message_id are now mutually-exclusive cursoring modes. Fold-in (NousResearch#60): _fetch_group_message uses max_pages=2 for tight-range pagination resilience. Tests: 200 passing on fork (194 unit + 6 plugin-integration). Same +10/-1 delta as standalone. Existing handler-exception test updated to reflect new pre-dispatch state semantic. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
angelburgosrosado
pushed a commit
to angelburgosrosado/hermes-agent
that referenced
this pull request
Apr 27, 2026
test: add unit tests for 8 untested core modules
MickaelV0
added a commit
to Roxabi/hermes-agent
that referenced
this pull request
May 24, 2026
The upstream image entrypoint runs as root and tries to `su hermes`,
which fails under our DropCapability=all (no CAP_SETUID). Force the
container to start as uid 10000 directly via User= alongside UserNS=.
The earlier comment ("starts directly as hermes") was inaccurate —
verified 2026-05-22 on digest 9d0a12c0… that removing User= produces
"error: failed switching to 'hermes': operation not permitted" and a
crashloop.
Also update CLAUDE.md provider wiring: llmcli now joins roxabi.network
(llmCLI NousResearch#60 resolved), so the canonical path is `llmcli:18091` via
container-name DNS — not `host.containers.internal:18091`, which is no
longer reachable from bridge containers (curl returns 000).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Implemented in commit d997e70 ( What changed:
Verification:
Remaining gates: no live Telegram canary or prod MCP packet replay was run. Renderer aliases may need a small follow-up if kb-engine emits a packet type spelling outside the tested set. |
|
Implemented in commit 64c2f20a0 (AFK-V2: #60 V2 Response Finalizer). All acceptance criteria met:
|
ohungerCH
added a commit
to ohungerCH/hermes-agent
that referenced
this pull request
Jun 28, 2026
…enqueue v2 -> cronjob/create_job/scheduler -> Codex) Lane-neutral: web-only/model/provider/repeat-Pins bleiben hartkodierte Modul-Literale (Threat F). reasoning_effort ist das EINZIGE input-honored Feld; unbekannte/getamperte Werte clampen auf "high". Worker akzeptiert enqueue v1 UND v2 (abwaertskompatibel). Engine-Smoke gruen gegen den Worktree. NICHT deployt (Image-Rebuild = morgens mit Owner). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ohungerCH
added a commit
to ohungerCH/hermes-agent
that referenced
this pull request
Jun 28, 2026
…job uebergeben (Codex-Stream-Stall) "high"/"xhigh" lassen Codex' Stream lange stumm denken -> der 12s-no-events->Reconnect- Watchdog killt den Stream -> Broken-Pipe-Endlosschleife (Job haengt ewig auf running). Recherche faellt bewusst auf den Provider-Default (config '') zurueck = bewaehrtes Verhalten, unabhaengig vom App-ui_hints-Selektor. Plumbing bleibt dormant; reaktivieren NACH einem Reconnect-Watchdog-Fix der langes Denken toleriert (Folge-Task der NousResearch#60). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
waefrebeorn
pushed a commit
to waefrebeorn/slermes
that referenced
this pull request
Jul 2, 2026
test: add unit tests for 8 untested core modules
ohungerCH
added a commit
to ohungerCH/hermes-agent
that referenced
this pull request
Jul 11, 2026
…s-Merge, Differenzierer erhalten Standard-3-Wege-Merge (KEIN Rebase/Force): Eltern[1]=21b01cb50 (Prä-Update-HEAD), Eltern[2]=v2026.7.7.2 (b7751df, Upstream-Release "chore: release v0.18.2"). fork/main bewegt sich nur vorwärts -> Codex zieht per FF. Baseline gepinnt auf den Release-Tag, nicht den driftenden origin/main. Mechanik/Analyse: docs/llm/2026-07-11_PLAN_hermes-018-migration.md. WARUM Standard-Merge statt M3-read-tree: _config_version 30->33 trägt Upstream-Migrations- Funktionen; ein Wholesale-checkout hätte die lautlos verworfen. merge-tree: 60/78 auto-merge, 18 echte Konflikte (via Workflow aufgelöst + adversarial verifiziert), 41 our-only unverändert. DIFFERENZIERER ERHALTEN (Vollständigkeits-Gate + Symbol/Marker-Survival-Sweep: 100 Symbole + 35 Marker überleben): Vault (tools/vault/*, 9 Dateien), trusted_surface, stt_redaction, research_enqueue_worker, threat_patterns (4-Tupel + DE-Muster), wrap-escape (NousResearch#34), untrusted_origin (kanban Deprivilege), Recall-Passthrough (memory/tool_executor/runtime_helpers). SICHERHEITS-KORREKTUREN (zwei echte Silent-Drops, vom Testlauf gefangen — der Resolve-Workflow + adversariale Verifikation sahen sie NICHT): * no_mcp-Boden (hermes_cli/tools_config.py): der blosse Config-Pin `api_server: []` GENÜGT in 0.18.2 NICHT — ohne no_mcp-Sentinel schleust _get_platform_tools alle MCP-Server + (bewiesen) 16 Toolsets inkl. computer_use/code_execution/browser auf den untrusted Voice-Pfad (RCE). Fix: In-Code-Output-Backstop `if platform in FAIL_CLOSED_PLATFORMS: return set()` am Funktions-Ausgang (churn-robust). ADR-0039 Invariante 1. Zur Laufzeit bewiesen. * _kanban_worker_skill_available (hermes_cli/kanban_db.py): Merge droppte Funktion + Aufrufstelle (upstream refaktorierte drumherum). Restauriert (Def + Call vor `if task.skills:` in _default_spawn). 32 Deprivilege-Tests wieder grün. BEWUSSTE DROPS (Fork-Lock-Reduktion): §8b-Vault-Seed aus DEFAULT_CONFIG (Kern-Edit -> gehört in externes config_file, Fabel-5); no_mcp-Kern-Clamp (ersetzt durch Output-Backstop). BEWUSSTE DIVERGENZEN / QUARANTÄNEN (test-only, jede dokumentiert; Produktionscode unberührt): write_approval NousResearch#46783 (unser origin-konditionales Gate vs Upstreams unbedingtes Staging -> approval.py-Reconciliation deferred an Fabel-5); api_server-Boden-Tests (Upstream nimmt api_server=tool-tragend an, wir klemmen ihn — 2 skip + 1 zur Regressionswache adaptiert); reasoning_effort-Forwarding (schon bei HEAD deaktiviert, e57d515/NousResearch#60 Codex-Stream-Stall); kanban-subscribe Test-Isolations-Leak (reset_session_vars); cron-ticker->housekeeping-Refactor; stale -worktree-Pfad -> runtime/hermes-main; hook-handler skip-if-absent (externes Deploy-Artefakt). VERIFIKATION: 1578 passed / 32 skipped (betroffene Bereiche: §6-Drift-Stellen, Vault, alle Differenzierer, Touched-Files). uv.lock via `uv lock` regeneriert (psycopg/asyncpg/cryptography). DEFERRED (nicht "in the tree"-blockierend): ruff/ty-Lauf; Externalisierung der Sicherheits- Schichten auf native Hooks; Bahn-A-Mount der hochpriv-Tools (Fabel-5-Aktivierung). Rollback: Tag backup/pre-018 @ 21b01cb; Vorwärts `git revert -m 1 <merge-commit>` (NIE reset). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Meraniya
pushed a commit
to Meraniya/hermes-agent
that referenced
this pull request
Aug 6, 2026
…ealing fallback (NousResearch#60) generate_launchd_plist() now routes launchd through gateway-wrapper.sh when present + executable, so ~/.hermes/.env is sourced into the process environment (launchd has no native EnvironmentFile) and the preflight stale-gateway reaper runs before every start. The wrapper execs the python + module args passed after it, preserving --profile end-to-end. Falls back to the direct-python form if the wrapper is missing/non-executable, so the gateway never fails to start under KeepAlive (self-heal). Fixes the intermittent Slack-enablement drop (DAN-1491): SLACK_BOT_TOKEN is now in os.environ at launch via the wrapper, independent of ~/.hermes/.env file state at the startup instant, so the registry-driven is_connected gate (NousResearch#31116) no longer silently leaves Slack disabled when .env is momentarily missing/empty/mid-replacement during a config/secret restore. Refs DAN-1522..DAN-1527 (Hermes launchd wrapper-entrypoint project). Co-authored-by: Claude <noreply@anthropic.com>
Soju06
added a commit
to Soju06/hermes-agent
that referenced
this pull request
Aug 13, 2026
nekwo
added a commit
to nekwo/hermes-agent
that referenced
this pull request
Aug 17, 2026
…stead of fighting it Two daemon threads raced from `ready`: the read-model build the launcher's canvas is waiting on, and ~5-8s of provider warmup CPU (OpenAI SDK import ~1.7s, SSL context / CA verification ~0.7s, and since BW-H3 the `model_tools` import plus the discovery/check_fn storm ~1.2s+). Under the GIL the second is subtracted from the first, and NOTHING the provider warmup produces is consumable before the canvas is authoritative — its purpose is the first chat turn's latency, which is after. Two independent investigations derived this same fix (HY-H2 = HC-H3); adopted once. - one daemon thread, sequential: `snapshot_prewarm()` then `_prewarm_provider_runtime()`, each step exception-isolated so a build that raised still leaves the providers warm (the property two threads had for free and a naive `then` would silently drop); - the thread still starts BEFORE the `ready` emit, untouched: only the build that started first can be shared, so a warmup started after that frame loses the race to the launcher's first request and queues a redundant second build. The invariant the old comment block asserted — "the read-model build must not queue behind this one's ~3s SDK import" — is now provable rather than raced, because that import has not started yet; - `_prewarm_provider_runtime` becomes an injectable `serve_loop` parameter with the same contract `snapshot_prewarm` has (HC-H3), wired at the real entry point. It was an unconditional `Thread.start()` inside the loop, which meant every unit test of the loop imported the OpenAI SDK to observe a ready frame. The brief's one-line version of this fix — reorder the two `Thread.start()` calls — stays REJECTED as a no-op, not as wrong-direction: starts issued microseconds apart schedule nothing, and both measured boots reached `model_tools` ~5s in regardless of order. Both sources refused it independently for the same mechanism. Cost named rather than hidden: a chat turn sent inside the (now shorter) boot window pays the cold SDK import inline, exactly as every turn did before the prewarm existed — best effort by the prewarm's own contract, and the canvas is not yet authoritative in that window. If receipts show first-turn warmup misses, the refinement is "provider prewarm starts at first-request-enqueue OR build-completion, whichever is first", not a revert. Tests (tests/agent_runtime/test_harness_serve.py, 3 new + 2 tightened): the gate-ordering witness — a snapshot-prewarm fake parked on a gate the TEST holds, with the provider recorder asserted EMPTY at that instant (the BW-L5 never-completing-fake pattern; the mutant cannot un-append and cannot release the gate); `ready` still on the wire before either prewarm completes, read off the frames after the loop returns with the gate STILL held; a failed build still warms the providers; and HC-H3's injectable-parameter contract at the entry point. Ordering, counts and emptiness only — the seconds are read off EG-2.1's receipts (plan NousResearch#60), never asserted in a test. Mutations run and reverted: restore the two parallel threads (2 red), join the prewarm thread before ready (1), drop the per-step isolation (1), drop the entry-point wiring (1). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
nekwo
added a commit
to nekwo/hermes-agent
that referenced
this pull request
Aug 18, 2026
…nd the office settle waits for the hydrate instead of for a frame
Two checkpoint-reddening defects, both mine, both from the MC-4 commits.
1. THE INVENTORY GATE WALKED THE VIRTUALENV.
`test_the_pin_covers_every_production_call_site_there_is` used `rglob("*.py")`
with two string exclusions. Measured: 10,112 files found, 7,121 OPENED and
AST-parsed on every run, 5,802 of them third-party code under `.venv-ci/`
(~51 MiB). Two independent defects, not one:
* CORRECTNESS. The claim is "every production `stream_frames` caller in THIS
repo". A vendored package defining anything of that name would red the gate
for a reason nobody here owns, and the message would send the reader hunting
a caller they cannot edit. The docstring said "outside `tests/`"; `.venv-ci/`
is outside `tests/` and is exactly what it did not mean.
* IT HUNG THE CHECKPOINT. A virtualenv is not a stable tree — it can be written
while it is read — and the full run timed out inside this walk, blocked on
opening a file under `.venv-ci`.
The scope now comes from `git ls-files --cached --others --exclude-standard`.
Both halves are load-bearing: tracked-only would go quietly VACUOUS in the
window an author is adding a caller not yet `git add`-ed — the gate reporting
success on a set missing the file it exists to catch — and `--exclude-standard`
is what removes the vendored trees. This is NOT the hand-typed-denylist defect
MCF-2 recorded: there is one authority, `.gitignore`, already the repo's own
answer to what is its own code, and a new vendored directory is visible either
way — ignored and out of scope, or unignored and loud in `git status`. A
denylist would admit it silently. A git failure raises rather than falling back
to the walk, which would restore the old behaviour when nobody was watching.
Files opened and parsed: 7,121 -> 1,292 (5.5x fewer; 28.3s -> 12.0s as context
only, per ruling NousResearch#60 the assertion is the count). Same answer both ways.
Two kills, because the scope and the inventory are two claims (C30): a real
third caller added to a tracked production file reds it; and a planted
git-ignored file (under `.pytest_cache/`, outside `tests/`, so it is not
excluded twice) calling `stream_frames` must NOT red it — reverting the scope to
the walk reds that one, with `.venv-ci` paths in the failure message.
2. THE OFFICE SETTLE WAITED ON A PROXY THAT ARM 2 INVALIDATED.
The coordinator's first checkpoint failed at
`test_unsubscribe_stops_delivery_against_the_real_producer`. It is NEITHER a
delivery regression NOR a deadline that lost a race, and both framings would
have led to a wrong fix.
`_settled_subscription` waited on `frames_delivered >= 1` as a proxy for "the
mandatory re-hydrate has landed" — exact only while the hydrate was necessarily
a generation's FIRST frame. Arm 2 ended that: the boot build now emits liveness
on the cadence, this fixture runs at 0.25s, and the office sink turns a
heartbeat into no notification at all. So the settle returned while the producer
was STILL BUILDING, the test's write landed before the hydrate was built, was
absorbed into it, and reached the sink as one `runtime.office.resync` instead of
the `runtime.office.patch` awaited.
Proven by holding the boot build, which reproduces it deterministically: peer
methods `[]` at settle, `['runtime.office.resync']` at the deadline AND three
seconds past it. The patch was never coming, so widening the deadline would have
fixed nothing and hidden this.
The fix synchronises on the EVENT rather than on a count that used to imply it:
the fixture records the frame types each producer generation yields, and the
settle waits for the hydrate to have been produced AND delivered (its 1-based
position in that list is exactly the delivered count that means "the sink has
run for it", the pump being FIFO). A new case pins it, holding the build on a
`threading.Event` released by evidence — that liveness was actually emitted —
so a build too fast to heartbeat cannot make it pass vacuously. Reverting the
settle to the old proxy reds that case with `['heartbeat']`, which is the
mechanism itself.
Goldens byte-identical, fence unchanged, no production code touched.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Modules Tested
cron/jobs.pytools/memory_tool.pytoolsets.pytools/file_operations.pyagent/prompt_builder.pyagent/model_metadata.pyhermes_state.pyTest plan
uv run pytest tests/ -v— 380 passed, 3 skipped (croniter optional), 0 failed