Skip to content

fix(cron): list_cron_job_runs opens job's own profile state.db - #52018

Open
performacia wants to merge 1 commit into
NousResearch:mainfrom
performacia:fix/cron-runs-cross-profile-session-db
Open

fix(cron): list_cron_job_runs opens job's own profile state.db#52018
performacia wants to merge 1 commit into
NousResearch:mainfrom
performacia:fix/cron-runs-cross-profile-session-db

Conversation

@performacia

Copy link
Copy Markdown

Problem

When a cron job's jobs.json lives in one profile (e.g. default) but the job carries profile='gerente_agente_de_compras', run sessions are written into the named profile's state.db — not the default one.

The GET /api/cron/jobs/{id}/runs endpoint was always opening the wrong state.db, so the UI showed stale or empty run history even though runs existed on disk.

Root Cause

_annotate_cron_job() overwrote the job's original profile field (which names the profile whose state.db holds the run sessions) with the name of the profile that owns jobs.json. The original value was permanently lost after annotation.

list_cron_job_runs() then called _open_session_db_for_profile(selected) where selected was the jobs.json owner — always the wrong DB for cross-profile jobs.

Fix

  • _annotate_cron_job() now copies the raw profile field from jobs.json into a new scheduler_profile key before overwriting profile with the jobs.json-owner name. This preserves the scheduler-stamped value without changing the existing profile semantics the UI relies on.

  • list_cron_job_runs() reads scheduler_profile from the resolved job and opens that profile's state.db when it differs from the jobs.json owner, ensuring run sessions written by the scheduler are always found.

Test

Regression test added to tests/hermes_cli/test_web_server_cron_profiles.py:

  • Creates a job in the default jobs.json tagged with profile='worker_alpha'
  • Writes a real run session into worker_alpha/state.db
  • Asserts that list_cron_job_runs() returns that run (previously returned 0)

All 8 tests in the file pass; test_cron.py and test_cron_fire_dashboard.py (10 tests) also pass unchanged.

When a cron job's jobs.json lives in one profile (e.g. 'default') but
the job carries profile='gerente_agente_de_compras', run sessions are
written into the named profile's state.db — not the default one.

The endpoint was calling _open_session_db_for_profile(selected) where
selected came from _find_cron_job_profile() (the jobs.json owner), so
it always opened the wrong database and returned stale/empty run history.

Root cause: _annotate_cron_job() overwrote the job's original 'profile'
field (which names the profile whose state.db holds the runs) with the
name of the profile that owns jobs.json. The original value was lost.

Fix:
- _annotate_cron_job() now preserves the raw 'profile' field from
  jobs.json into a new 'scheduler_profile' key before overwriting
  'profile' with the jobs.json-owner name.
- list_cron_job_runs() reads 'scheduler_profile' and opens that profile's
  state.db when it differs from the jobs.json owner, ensuring run
  sessions written by the scheduler are always found.

Regression test added: creates a job in 'default' jobs.json tagged with
profile='worker_alpha', writes a run session into worker_alpha/state.db,
and asserts the endpoint returns that run (not zero).
Copilot AI review requested due to automatic review settings June 24, 2026 17:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Fixes cron run-history retrieval in the dashboard by ensuring /api/cron/jobs/{id}/runs opens the state.db belonging to the profile the scheduler ran the job under (not the profile that owns jobs.json), and adds a regression test for cross-profile cron jobs.

Changes:

  • Preserve the scheduler-stamped job execution profile during cron job annotation (scheduler_profile).
  • Update list_cron_job_runs() to select the correct profile database for run-session lookups.
  • Add a regression test covering cross-profile run history retrieval.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
hermes_cli/web_server.py Preserves the job’s scheduler profile during annotation and uses it to open the correct profile’s state.db for run history.
tests/hermes_cli/test_web_server_cron_profiles.py Adds a regression test to ensure run history is read from the job’s execution profile DB.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +202 to +203
@pytest.mark.asyncio
async def test_list_cron_job_runs_reads_job_profile_state_db(isolated_profiles, tmp_path):
Comment on lines +213 to +217
import json
import time

from hermes_state import SessionDB
from hermes_cli import web_server
if j.get("id") == job_id:
j["profile"] = "worker_alpha"
break
jobs_file.write_text(json.dumps(data if isinstance(data, list) else data))
Comment thread hermes_cli/web_server.py
Comment on lines 7749 to +7755
job = _call_cron_for_profile(selected, "get_job", job_id)
if job and job.get("id"):
canonical = str(job["id"])
if isinstance(job, dict):
if job.get("id"):
canonical = str(job["id"])
sched_prof = job.get("scheduler_profile", "")
if sched_prof and sched_prof != selected:
db_profile = sched_prof
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/dashboard Web dashboard / control panel UI (dashboard/, landing) comp/cron Cron scheduler and job management labels Jun 24, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the focused regression test. I found a blocker against current main's cron model.

Problems

  • Current cron is intentionally per-profile: a job lives and executes under the same profile HERMES_HOME (cron/jobs.py:54-64; tests/cron/test_cron_profile_isolation.py:3-17).
  • create_job has no profile argument (cron/jobs.py:1033-1051), and the added test manually injects job["profile"] into another profile's jobs.json. That is not a current supported scheduler record.

Suggested changes

  • Please obtain maintainer direction before re-scoping this as a legacy-migration case. A fix should preserve the current profile-isolation boundary rather than route run-history reads from an arbitrary per-job field.

Automated hermes-sweeper review.

Comment thread hermes_cli/web_server.py
# The scheduler stamps job["profile"] with the profile the job runs under
# (where its run sessions are written); _annotate_cron_job then overwrites
# ``profile`` with the jobs.json owner. Keeping the original in
# ``scheduler_profile`` lets endpoints that need to open the correct

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Current main does not persist a scheduler-stamped per-job profile: cron/jobs.py:create_job has no such parameter, and cron is intentionally per-profile. This new field is therefore populated only by an unsupported/hand-edited record and would reintroduce cross-profile session lookup.

for j in (data if isinstance(data, list) else data.get("jobs", [])):
if j.get("id") == job_id:
j["profile"] = "worker_alpha"
break

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This manually creates the cross-profile record that current main deliberately avoids: tests/cron/test_cron_profile_isolation.py:3-17 requires jobs to live and execute under one profile. Please replace this with an approved legacy-migration fixture or remove the unsupported scenario.

@teknium1 teknium1 added sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data 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 area/profiles Multi-profile isolation, HERMES_HOME scoping labels Jul 15, 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 comp/dashboard Web dashboard / control panel UI (dashboard/, landing) P3 Low — cosmetic, nice to have 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-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants