Skip to content

test(7/N): green up hermes_cli + cron + run_agent + plugins long tail#11

Merged
Bartok9 merged 1 commit into
mainfrom
fix/test-suite-green-7n-cli-cron-misc
May 30, 2026
Merged

test(7/N): green up hermes_cli + cron + run_agent + plugins long tail#11
Bartok9 merged 1 commit into
mainfrom
fix/test-suite-green-7n-cli-cron-misc

Conversation

@Bartok9

@Bartok9 Bartok9 commented May 30, 2026

Copy link
Copy Markdown
Owner

Context

PR #6 (1/N) merged; ~38 pre-existing failures remained on main. This PR cleans up the long tail — 10 failures across 7 files in hermes_cli, cron, run_agent, and plugins. Each was investigated independently; root causes are a mix of genuine production regressions, an intended behavior change, and test-side signature/value drift.

Tests fixed (10)

  1. tests/hermes_cli/test_model_validation.py::TestValidateCodexAutoCorrection::test_very_different_name_falls_to_suggestions
  2. tests/hermes_cli/test_model_provider_persistence.py::TestProviderPersistsAfterModelSave::test_lmstudio_provider_saved_when_selected
  3. tests/hermes_cli/test_model_provider_persistence.py::TestBaseUrlValidation::test_stepfun_provider_saved_with_selected_region
  4. tests/hermes_cli/test_tencent_tokenhub_provider.py::TestTencentTokenhubContextLength::test_hy3_preview_context_length
  5. tests/cron/test_cron_script.py::TestBuildJobPromptWithScript::test_script_empty_output_noted
  6. tests/cron/test_scheduler_mcp_init.py::test_run_job_calls_discover_mcp_tools_before_agent_construction
  7. tests/cron/test_scheduler_mcp_init.py::test_run_job_tolerates_discover_mcp_tools_failure
  8. tests/run_agent/test_concurrent_interrupt.py::test_running_concurrent_worker_sees_is_interrupted
  9. tests/run_agent/test_concurrent_interrupt.py::test_concurrent_interrupt_cancels_pending
  10. tests/plugins/test_achievements_plugin.py::test_evaluate_all_stale_cache_serves_stale_and_refreshes_in_background

Root cause per test

# Test Root cause Fix kind
4 hy3-preview context Round-number-stale assertion. The authoritative source (OpenRouter live metadata, consulted before the hardcoded fallback) reports 262144 = 256*1024 = true binary 256K. Test asserted the decimal 256000. test value + aligned hardcoded fallback in agent/model_metadata.py
1 very-different codex name validate_requested_model accepted any codex model name (proxy-friendly catch-all). prod: reject when no close-match suggestion exists (suggestions empty); keep accept-with-suggestions for near-misses
2 lmstudio persist Test drift: an existing API key triggers _prompt_api_key's [K]eep/[R]eplace/[C]lear input() prompt, so two prompts fire (K/R/C + base URL), not one. StopIteration on the exhausted side_effect list. test: provide both input values
3 stepfun region persist Same root cause as #2 — the K/R/C prompt read stdin in a non-interactive pytest context (OSError: reading from stdin while output is captured). test: patch builtins.input
5 script empty output _build_job_prompt returned None on empty script output, so .lower() hit NoneType. prod: note empty output in the prompt instead of dropping it; the wake-gate / no_agent layers still own the skip-the-AI decision
6, 7 cron MCP init discover_mcp_tools() was gated behind provider auth, which fails in the credential-stripped test env, so it ran after (or never reached) AIAgent construction. prod: move MCP discovery before provider resolution (it doesn't depend on the runtime); test: add the resolve_runtime_provider mock the tests were missing (every other run_job test stubs it)
8, 9 concurrent interrupt Test-fixture drift: the _Stub lacked _tool_guardrails + _append_guardrail_observation (added to _execute_tool_calls_concurrent after the fixture was written), and the fake-tool side_effects didn't accept the messages / pre_tool_block_checked kwargs the production call now passes. test: update fixture + fake-tool signatures
10 achievements stale-serves-stale Real race. evaluate_all() returned the _SNAPSHOT_CACHE module global by reference after kicking the background scan; a fast worker rebinds it to fresh data before the return, breaking stale-serves-stale. prod: capture the snapshot reference before starting the background scan

Validation

pytest -q tests/hermes_cli/ tests/cron/ tests/run_agent/ tests/plugins/:

  • This PR's 10 targets: all green.
  • 501/501 pass across the directly-touched files (tests/cron/, tests/plugins/test_achievements_plugin.py, tests/hermes_cli/test_tencent_tokenhub_provider.py, test_model_validation.py, test_model_provider_persistence.py, tests/run_agent/test_concurrent_interrupt.py).
  • The 19 remaining failures in the four directories belong to the 5 parallel PR clusters (gateway/systemd test_gateway_wsl + test_gateway_service, test_web_server PTY, test_model_switch_custom_providers, test_provider_parity, test_bedrock_model_picker, test_list_picker_providers) plus 2 tests/tools/test_mcp_* import errors — all confirmed pre-existing on main (verified by stashing this PR's diff).

Remaining-on-main count

This PR closes its 10-test cluster from the original 38. The remaining failures are accounted for by the other 5 parallel PRs; together they target all 38.

Ambiguity flags


Note

Low Risk
Changes are localized (cron prompt/MCP init order, stricter Codex name rejection, context metadata, achievements read path); no auth or payment paths touched.

Overview
This PR fixes a long tail of failing tests (~10) across hermes_cli, cron, run_agent, and plugins, with several production fixes alongside test updates.

Cron: Pre-run scripts that succeed with empty stdout now inject a short “no output” note into the job prompt instead of returning None (which broke callers). discover_mcp_tools() runs before provider resolution so MCP tools register even when auth/fallback would have blocked discovery later.

Models / metadata: hy3-preview context length is aligned to 262144 (binary 256K). OpenAI Codex validation rejects model names with no fuzzy-match suggestions instead of always accepting unknown slugs.

Achievements plugin: On stale cache + background refresh, the API snapshots the in-memory cache before starting the scan so concurrent updates don’t return fresh data when stale was intended.

Tests: Provider persistence flows stub extra input() prompts; cron MCP tests mock resolve_runtime_provider; concurrent-interrupt stubs add tool guardrails and updated fake-tool signatures.

Reviewed by Cursor Bugbot for commit add2e05. Bugbot is set up for automated code reviews on this repo. Configure here.

Fixes 10 long-tail test failures across 7 files. Each was investigated
independently; root causes mix genuine production regressions, intended
behavior changes, and test-side signature/value drift.

hermes_cli:
- test_hy3_preview_context_length: round-number-stale assertion. The
  authoritative source (OpenRouter live metadata, consulted before the
  hardcoded fallback) reports 262144 = 256*1024 = true binary 256K for
  hy3-preview. Updated the test to 262144 and aligned the hardcoded
  fallback value/comment in agent/model_metadata.py.
- test_very_different_name_falls_to_suggestions: validate_requested_model
  accepted ANY codex model name. Now rejects names too different to even
  offer a close-match suggestion (suggestions empty), while keeping the
  proxy-friendly accept-with-suggestions path for near-misses.
- test_lmstudio_provider_saved_when_selected: test drift. An existing
  API key triggers _prompt_api_key's [K]eep/[R]eplace/[C]lear input()
  prompt, so two interactive prompts fire, not one. Provided both values.
- test_stepfun_provider_saved_with_selected_region: same root cause -
  the [K]eep/[R]eplace/[C]lear prompt read stdin in a non-interactive
  pytest context (OSError). Patched builtins.input in the test.

cron:
- test_script_empty_output_noted: _build_job_prompt returned None on
  empty script output, so the test's .lower() hit NoneType. Empty output
  is now noted in the prompt ('no output') instead of dropping it; the
  wake-gate / no_agent layers still own the skip-the-AI-run decision.
- test_run_job_calls_discover_mcp_tools_before_agent_construction /
  ..._tolerates_discover_mcp_tools_failure: discover_mcp_tools() was
  gated behind provider auth, which fails in the credential-stripped test
  env, so it ran AFTER (or never reached) AIAgent construction. Moved MCP
  discovery before provider resolution (it doesn't depend on the runtime),
  and added the resolve_runtime_provider mock the tests were missing
  (every other run_job test stubs it).

run_agent:
- test_concurrent_interrupt (both): test-fixture drift. The _Stub lacked
  _tool_guardrails and _append_guardrail_observation (added to
  _execute_tool_calls_concurrent after the fixture was written), and the
  fake tool side_effects didn't accept the messages / pre_tool_block_checked
  kwargs the production call now passes. Updated the fixture + signatures.

plugins:
- test_evaluate_all_stale_cache_serves_stale_and_refreshes_in_background:
  real race. evaluate_all() returned the _SNAPSHOT_CACHE module global by
  reference AFTER kicking the background scan, so a fast worker could
  rebind it to fresh data before the return, breaking stale-serves-stale.
  Capture the snapshot reference before starting the background scan.

Validation: pytest -q tests/hermes_cli/ tests/cron/ tests/run_agent/
tests/plugins/ -> this PR's 10 targets all green; the 19 remaining
failures belong to the 5 parallel PR clusters (gateway/systemd, web_server
PTY, model_switch_custom_providers, provider_parity, bedrock, list_picker)
and are confirmed pre-existing on main.
@Bartok9
Bartok9 merged commit 75f5eb4 into main May 30, 2026
7 of 8 checks passed
@Bartok9
Bartok9 deleted the fix/test-suite-green-7n-cli-cron-misc branch May 30, 2026 07:04
@github-actions

Copy link
Copy Markdown

🔎 Lint report: fix/test-suite-green-7n-cli-cron-misc vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 7749 on HEAD, 7746 on base (🆕 +3)

🆕 New issues (6):

Rule Count
invalid-argument-type 5
unresolved-attribute 1
First entries
tests/run_agent/test_concurrent_interrupt.py:94: [unresolved-attribute] unresolved-attribute: Unresolved attribute `_append_guardrail_observation` on type `_Stub`
run_agent.py:12539: [invalid-argument-type] invalid-argument-type: Argument to function `_is_oauth_token` is incorrect: Expected `str`, found `str | dict[Unknown, Unknown] | Any | ... omitted 3 union elements`
run_agent.py:6649: [invalid-argument-type] invalid-argument-type: Argument to function `build_anthropic_client` is incorrect: Expected `str`, found `str | dict[Unknown, Unknown] | Any | ... omitted 3 union elements`
tests/run_agent/test_concurrent_interrupt.py:41: [invalid-argument-type] invalid-argument-type: Argument to constructor `NonCallableMock.__new__` is incorrect: Expected `bool | None`, found `MagicMock`
tests/run_agent/test_concurrent_interrupt.py:41: [invalid-argument-type] invalid-argument-type: Argument to constructor `NonCallableMock.__new__` is incorrect: Expected `bool`, found `MagicMock`
run_agent.py:12542: [invalid-argument-type] invalid-argument-type: Argument to function `len` is incorrect: Expected `Sized`, found `(str & ~AlwaysFalsy) | (dict[Unknown, Unknown] & ~AlwaysFalsy) | (Any & ~AlwaysFalsy) | ... omitted 3 union elements`

✅ Fixed issues (4):

Rule Count
invalid-argument-type 3
invalid-return-type 1
First entries
cron/scheduler.py:814: [invalid-return-type] invalid-return-type: Return type does not match returned value: expected `str`, found `None`
run_agent.py:6649: [invalid-argument-type] invalid-argument-type: Argument to function `build_anthropic_client` is incorrect: Expected `str`, found `str | dict[Unknown | str, Unknown | str | dict[str, str]] | Any | ... omitted 3 union elements`
run_agent.py:12539: [invalid-argument-type] invalid-argument-type: Argument to function `_is_oauth_token` is incorrect: Expected `str`, found `str | dict[Unknown | str, Unknown | str | dict[str, str]] | Any | ... omitted 3 union elements`
run_agent.py:12542: [invalid-argument-type] invalid-argument-type: Argument to function `len` is incorrect: Expected `Sized`, found `(str & ~AlwaysFalsy) | (dict[Unknown | str, Unknown | str | dict[str, str]] & ~AlwaysFalsy) | (Any & ~AlwaysFalsy) | ... omitted 3 union elements`

Unchanged: 4072 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.

Reviewed by Cursor Bugbot for commit add2e05. Configure here.

Comment thread cron/scheduler.py
prompt = (
"## Script Output\n"
"The pre-run script ran successfully but produced no "
"output (no output).\n\n"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant "no output" repeated in prompt message

Low Severity

The constructed prompt reads "The pre-run script ran successfully but produced no output (no output)." — the parenthetical (no output) is a verbatim repetition of what the sentence already states. This looks like an editing artifact where the parenthetical was likely meant to contain a different clarification (e.g., "stdout was empty" or "exit code 0") but accidentally duplicated the same phrase.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit add2e05. Configure here.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant