Skip to content

fix(agent): clarify verifier after approved config set - #53093

Open
MarcvsTvllivs wants to merge 1 commit into
NousResearch:mainfrom
MarcvsTvllivs:fix/file-mutation-verifier-config-set
Open

MarcvsTvllivs wants to merge 1 commit into
NousResearch:mainfrom
MarcvsTvllivs:fix/file-mutation-verifier-config-set

Conversation

@MarcvsTvllivs

Copy link
Copy Markdown

What does this PR do?

Clarifies the per-turn file-mutation verifier when a protected config.yaml direct edit is blocked but the same turn successfully applies the config change through the approved hermes config set ... path.

Today, if patch/write_file is refused for a protected Hermes config file and the agent then recovers by running hermes config set ..., the final verifier footer can still imply the config file was not modified. This PR preserves both facts instead:

  • the direct file mutation was blocked; and
  • the protected config change was later applied through the approved config command.

The recovery is intentionally narrow. It only recognizes successful terminal calls whose command is hermes config set ..., whose JSON result has exit_code == 0, and whose CLI output names the same config.yaml path. It does not infer arbitrary terminal-side file edits.

Known limitation: recovery is matched at the config.yaml path level, not by proving content/key-level equivalence. That keeps the patch small and targeted to the common flow: blocked direct config edit → retry the same change via hermes config set. The footer still includes verification guidance where unresolved failures remain.

Related Issue

No single issue filed for this exact hermes config set recovery case.

Related prior art / adjacent PRs found during duplicate search:

This PR is intentionally narrower than the broader recovery PRs: it handles only the sanctioned hermes config set path and leaves arbitrary terminal recovery to separate work.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • agent/turn_context.py

    • Initializes _turn_superseded_file_mutations per turn alongside existing verifier state.
  • agent/turn_finalizer.py

    • Includes superseded protected-config attempts when deciding whether to render the verifier footer.
  • run_agent.py

    • Recognizes successful terminal calls that run hermes config set ... and report a config.yaml path.
    • Moves only the matching failed config.yaml mutation from failed state to a superseded/recovered bucket.
    • Keeps unrelated failed file mutations warning normally.
    • Renders recovered protected-config attempts with “blocked” plus “recovered by” wording.
    • Handles ~ vs absolute path matching via os.path.expanduser() and slash normalization.
    • Allows the success line to be followed by additional terminal output.
  • tests/run_agent/test_file_mutation_verifier.py

    • Adds coverage for successful config-set recovery.
    • Adds coverage for failed config-set not recovering.
    • Adds coverage that only the matching config path is superseded.
    • Adds coverage that different config paths do not supersede each other.
    • Adds coverage for ~/.hermes/config.yaml vs absolute path matching.
    • Adds coverage for config-set success output followed by trailing output.
    • Adds footer rendering coverage for the recovered protected-config case.
    • Adds/keeps gateway extraction coverage so verifier footer paths are not treated as deliverable files.

How to Test

  1. Reproduce the old behavior conceptually:

    • A direct file-tool mutation of protected ~/.hermes/config.yaml is denied.
    • The same turn succeeds with hermes config set ....
    • The verifier could still warn as if the file was not modified.
  2. Verify the new behavior with focused tests:

    PATH=/home/hermes/.hermes/hermes-agent/venv/bin:$PATH pytest tests/run_agent/test_file_mutation_verifier.py -q -o 'addopts='

    Result:

    44 passed, 3 warnings
    
  3. Verify syntax and whitespace:

    /home/hermes/.hermes/hermes-agent/venv/bin/python -m py_compile run_agent.py agent/turn_context.py agent/turn_finalizer.py
    git diff --check
    git diff --cached --check
  4. Check Windows/path footguns on the changed files:

    /home/hermes/.hermes/hermes-agent/venv/bin/python scripts/check-windows-footguns.py run_agent.py tests/run_agent/test_file_mutation_verifier.py

    Result:

    ✓ No Windows footguns found (2 file(s) scanned).
    
  5. Full-suite status:

    scripts/run_tests.sh
    scripts/run_tests.sh --file-timeout 300

    Result: full suite was attempted. The default per-file timeout hit tests/gateway/test_email.py; that file passes when rerun directly with a longer wall clock (87 passed, 2 warnings in 243.94s). With --file-timeout 300, the suite reached two unrelated failing files:

    tests/tools/test_execute_code_approval_cluster.py  (7 tests failed)
    tests/tools/test_search_hidden_dirs.py             (1 test failed)
    

    Both failures reproduce on a fresh detached origin/main worktree at 8ab7246c4:

    scripts/run_tests.sh tests/tools/test_execute_code_approval_cluster.py
    # 7 failed, 13 passed
    
    scripts/run_tests.sh tests/tools/test_search_hidden_dirs.py
    # 1 failed, 8 passed

    These full-suite blockers appear to be current baseline failures, not introduced by this branch.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Linux 7.0.6-2-pve with Python 3.11 via the Hermes-managed venv

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

Screenshots / Logs

Focused verification:

/home/hermes/.hermes/hermes-agent/venv/bin/python
/home/hermes/.hermes/hermes-agent/venv/bin/pytest
44 passed, 3 warnings

Windows-footgun check:

✓ No Windows footguns found (2 file(s) scanned).

Full-suite attempt:

scripts/run_tests.sh
# tests/gateway/test_email.py exceeded the default 140s per-file timeout.

pytest tests/gateway/test_email.py -q -o 'addopts=' --tb=short
# 87 passed, 2 warnings in 243.94s

scripts/run_tests.sh --file-timeout 300
# completed with baseline failures:
# tests/tools/test_execute_code_approval_cluster.py  (7 tests failed)
# tests/tools/test_search_hidden_dirs.py             (1 test failed)

Fresh detached origin/main @ 8ab7246c4:
# scripts/run_tests.sh tests/tools/test_execute_code_approval_cluster.py -> 7 failed, 13 passed
# scripts/run_tests.sh tests/tools/test_search_hidden_dirs.py -> 1 failed, 8 passed

@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data labels Jun 26, 2026
@MarcvsTvllivs
MarcvsTvllivs force-pushed the fix/file-mutation-verifier-config-set branch from 4e98d13 to 61ebbf7 Compare June 26, 2026 14:48

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for identifying a real stale-verifier path: current run_agent.py:2829-2855 records only file-tool outcomes, while agent/turn_finalizer.py:295-301 still renders a remaining failure.

Problems

  • The added matcher at run_agent.py:2603 accepts ;/| chained shell commands and trusts any output line matching Set … in …config.yaml. A command can print that line and then successfully run hermes config set OPENROUTER_API_KEY value; current hermes_cli/config.py:8134-8136 routes that real command to .env, but the PR would suppress the protected config.yaml failure.

Suggested changes

  • Restrict recovery to a parsed, sole sanctioned hermes config set invocation, rather than a substring in a shell command, and add a regression for forged/prefixed output plus an .env-routed key.
  • Add a temp-HERMES_HOME integration test for the actual config command and end-of-turn footer path.

Automated hermes-sweeper review.

Comment thread run_agent.py
This intentionally recognizes only the narrow, approved path that
resolves protected config.yaml patch failures: `hermes config set ...`
with a zero exit code and the CLI's success output naming config.yaml.
It does not try to infer arbitrary file changes from terminal output.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This accepts ;/| command chains and trusts any matching output line. For example, a command can print Set x in ~/.hermes/config.yaml and then run hermes config set OPENROUTER_API_KEY value; that real command writes .env (hermes_cli/config.py:8134-8136), but this matcher would mark the blocked config.yaml edit as recovered. Require a sole parsed hermes config set invocation and add this regression case.

@teknium1 teknium1 added the sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users label Jul 15, 2026
@MarcvsTvllivs
MarcvsTvllivs force-pushed the fix/file-mutation-verifier-config-set branch from 61ebbf7 to 6b2f9b1 Compare August 2, 2026 20:14

This branch has not been deployed

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

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants