Skip to content

fix(cron): honor profile wrap_response during delivery - #36274

Closed
mzkarami wants to merge 1 commit into
NousResearch:mainfrom
mzkarami:auto/nightly-cron-wrap-response-profile-20260601
Closed

fix(cron): honor profile wrap_response during delivery#36274
mzkarami wants to merge 1 commit into
NousResearch:mainfrom
mzkarami:auto/nightly-cron-wrap-response-profile-20260601

Conversation

@mzkarami

@mzkarami mzkarami commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • read cron.wrap_response from a cron job's runtime profile during delivery
  • preserve scheduler-profile storage/output behavior by scoping only the delivery config lookup
  • add regression coverage for profile jobs delivering raw output when their profile sets wrap_response: false

Notes

Test Plan

  • uv run --extra dev pytest tests/cron/test_cron_profile.py tests/cron/test_scheduler.py::TestDeliverResultWrapping tests/hermes_cli/test_gui_command.py tests/hermes_cli/test_model_catalog.py::TestManifestMatchesInRepoLists::test_in_repo_lists_match_manifest -q
  • uv run --extra dev ruff check cron/scheduler.py tests/cron/test_cron_profile.py tests/hermes_cli/test_gui_command.py
  • git diff --check
  • Fork PR CI: fix(cron): honor profile wrap_response during delivery mzkarami/hermes-agent#3 is green

Refs #36248
Refs #36215

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cron Cron scheduler and job management labels Jun 1, 2026

@tonydwb tonydwb 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.

Review: APPROVE ✅

This is a clean, focused fix for a real bug in cron delivery.

The Problem

When a cron job runs under a different Hermes profile (via job.profile), run_job() uses _job_profile_context() to temporarily switch to that profile. However, _deliver_result() calls load_config() after the profile context has been restored, so it reads cron.wrap_response from the scheduler's config instead of the job's runtime profile config. This means profile-scoped jobs that set wrap_response: false get wrapped output they didn't ask for.

The Fix

Wrap the load_config() call inside _deliver_result() with _job_profile_context(job.get("id", "?"), job.get("profile")): — the same context manager already used by run_job(). This is a 1-line addition (+ 1 indent) in production code. Minimal, correct, no side effects.

Edge Cases Handled

  • No profile on job: _job_profile_context yields None immediately → load_config() uses scheduler profile as before. Zero behavioral change for non-profile jobs.
  • Exception during load: Already caught by the existing try/except block; wrap_response defaults to True (safe).
  • Missing profile: _job_profile_context logs a warning, yields None → falls back to scheduler config. Safe.

Tests

42 lines of new test coverage verifying:

  • Separate scheduler config (wrap_response: true) and profile config (wrap_response: false)
  • After delivery, content is NOT wrapped (clean output matches)
  • Environment is properly restored after delivery

The test uses the existing isolated_cron_profile_home fixture and proper mocking.

Ancillary Changes

  • Two small test fixture additions in test_gui_command.py — aligning with upstream main changes (mentioned in PR body as CI compatibility fixes)
  • Model catalog timestamp/version bump — harmless data sync

Verdict

Approve. This is a textbook bug fix: clear problem, minimal change, proper test, backward compatible, well-documented. No security concerns or pipe-to-interpreter patterns.

@tonydwb tonydwb 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.

Code Review Summary

Verdict: Approved

Context

Fix for cron jobs: _deliver_result() should read cron.wrap_response from the job's runtime profile config, not the scheduler profile. This is a targeted 5-line change in cron/scheduler.py.

Review

  • Correctness: Wraps load_config() in _job_profile_context() so delivery reads the job's profile config. Correct scoping — delivery is the only affected path.
  • Testing: New regression test verifies the fix end-to-end with mocked delivery. GUI test patches keep CI green.
  • Code quality: Minimal diff, clear intent, no edge cases exposed.

Reviewed by Hermes Agent

@mzkarami
mzkarami force-pushed the auto/nightly-cron-wrap-response-profile-20260601 branch from 1ee762d to 1f20f80 Compare June 1, 2026 09:09
@iamfoz

iamfoz commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Nice fix. I've just opened #37736, which adds a per-job wrap_response override on top of this. They compose cleanly into a precedence chain: per-job (mine) > profile (this PR) > global default. My per-job None case falls through to the same global read you are correcting here, so once this merges I will rebase so the inherited value resolves from the job's profile. Flagging it so the relationship is clear to anyone reviewing either one.

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused regression coverage. This branch predates a deliberate cron-profile design change on current main.

Problems

  • The added _job_profile_context(...) call is no longer available. Commit 7d8d000b1921cb1c14aa137a41bd96203992e2c0 removed per-job cron profiles, including that helper and tests/cron/test_cron_profile.py.
  • On HEAD, _deliver_result() still catches configuration-lookup exceptions at cron/scheduler.py:1446-1450; therefore a literal salvage would swallow the missing-helper NameError and leave wrapping enabled.

Suggested changes

  • Please re-scope only if a mismatch reproduces under the current active-profile model. Current cron execution resolves its active profile dynamically at cron/scheduler.py:543-552, and delivery reads config at cron/scheduler.py:1447-1448.

This is an automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
@mzkarami

Copy link
Copy Markdown
Contributor Author

Closing this because the affected per-job cron-profile path was removed from current main, including _job_profile_context() and tests/cron/test_cron_profile.py. The original report in #36248 was also closed after the behavior was traced to duplicate YAML keys, while current active-profile delivery already reads cron.wrap_response from the active configuration. The earlier approvals were valid for the old architecture, but the patch is no longer applicable. Thanks to everyone who reviewed and discussed it.

@mzkarami mzkarami closed this Jul 17, 2026
@teknium1 teknium1 added the area/profiles Multi-profile isolation, HERMES_HOME scoping label Jul 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/profiles Multi-profile isolation, HERMES_HOME scoping comp/cron Cron scheduler and job management P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants