feat: add profile-aware cron panel#1352
Conversation
|
Thanks @NocGeek, this fills a real gap. The cron panel only ever showing the active profile's jobs has been a usability cliff for anyone running cronbot alongside a default profile — you'd see "no jobs" and have no way to inspect or trigger the cronbot ones from the WebUI. Profile-aware listing with a What I like
Questions
Follow-ups (don't block this PR)
This is a solid, well-tested change. I'll do a closer line-level pass on the API routing changes shortly. |
On hold — needs rebase + scope discussionThanks @NocGeek for the substantial work on profile-aware crons. Putting this on hold for now while we sort out a few things. Why on hold1. Merge conflict against 2. CI hasn't run yet. No status checks present on this PR. After rebase, GH Actions will trigger automatically — please verify all 3 Python versions go green ( 3. Scope — at +447/−103 across 5 files this is a substantial architectural change introducing per-profile cron filtering, a Scheduled Jobs visible-profile selector with
What I'd want to see before un-holding
What's goodThe @NocGeek tagging — happy to discuss any of the above, especially the rebase strategy if you'd like a hand. The cron paths in |
** Just for reference cronbot is a second profile i use so i just use that in my description. if you prefer in the future i could say altprofile or 2ndprofile if it adds clarity **
I can add this tomorrow I did not think to test that as I have never actually created a job in the UI would you want that as a separate additional PR or would you want to decline this one and have me resubmit as a new PR i just saw the hold notes Ill work on updating and redoing it again tomorrow |
Manual WebUI cron runs previously called cron.scheduler.run_job(job) and then only cleared the in-memory running flag. That meant output could be dropped and job metadata like last_run_at / last_status was not updated after a manual run. This PR matches the scheduled cron path (cron/scheduler.py:1334-1364) exactly: - Save manual-run output via save_job_output - Mark manual runs complete via mark_job_run - Treat empty final_response as a soft failure with the same error string as the scheduled path - Record manual-run failures in job metadata via mark_job_run(False) - Keep _run_cron_tracked self-contained for worker-thread execution Includes 2 behavioral regression tests using monkeypatch.setitem on sys.modules to mock cron.scheduler.run_job + cron.jobs helpers — the right test pattern (exercises the real _run_cron_tracked code path). Split out from #1352 (the larger profile-aware-cron-panel PR that's on hold) per pre-release-review feedback. Self-contained, doesn't touch the held PR's profile-filtering scope. Co-authored-by: NocGeek <[email protected]>
Opus pre-release findings on #1370 applied: SHOULD-FIX 1: Tightened parent_session_id exposure to only emit when the parent's end_reason is in {compression, cli_close}. Without this, two distinct WebUI sessions sharing a non-continuation parent (e.g. 'user_stop') would get clustered by frontend's _sessionLineageKey (which falls through to parent_session_id when _lineage_root_id is missing) and incorrectly collapsed into a single sidebar row. Updated assertions in: - tests/test_session_lineage_metadata_api.py:: test_non_compression_state_db_parent_does_not_create_sidebar_lineage - tests/test_pr1370_lineage_metadata_perf_and_orphan.py:: test_non_compression_parent_does_not_extend_lineage SHOULD-FIX 2: Chunked the IN-clause to 500 vars to stay under SQLITE_MAX_VARIABLE_NUMBER. Python 3.9 ships sqlite 3.31 with the default limit of 999. A power user with 2000+ sessions in the sidebar would hit OperationalError, the silent except-wrapper would swallow it, and lineage collapse would never work. Added test_in_clause_chunked_for_large_session_set with SQL interception to lock the invariant in source. PR addition (per user directive — Opus + my review, no second independent review round needed for combined batch): #1372 from @NocGeek — fix: persist manual cron run results. Self-contained 89 LOC fix split out from the held #1352. Mirrors the scheduled-cron path (cron/scheduler.py:1334-1364) exactly: saves output, marks job complete, treats empty response as soft failure with matching error string. 2 behavioral tests using sys.modules monkeypatch to mock cron.scheduler.run_job. CI not yet attached because branch is brand-new; ran the new tests + adjacent suites locally — all pass. Final test count: 3471 passing, 0 failed. Also adds 2 more regression tests for the perf-fix invariants: - test_in_clause_chunked_for_large_session_set - test_two_children_sharing_non_continuation_parent_not_collapsed
Closed — superseded by #1372 (shipped) + #1374 (architectural piece on hold)Thanks @NocGeek for the original work on this. Closing #1352 as it has now been superseded by two focused successor PRs:
The Option A split I recommended in this PR's hold comment worked exactly as intended — thanks for the rebase + clean re-write. The manual-run fix shipped fast in v0.50.251 (which is the bug fix) while the architectural piece gets the careful review it deserves in #1374 (which is the feature). @NocGeek tagging — happy to discuss the architectural coordination questions on #1374 anytime. |
Manual WebUI cron runs previously called cron.scheduler.run_job(job) and then only cleared the in-memory running flag. That meant output could be dropped and job metadata like last_run_at / last_status was not updated after a manual run. This PR matches the scheduled cron path (cron/scheduler.py:1334-1364) exactly: - Save manual-run output via save_job_output - Mark manual runs complete via mark_job_run - Treat empty final_response as a soft failure with the same error string as the scheduled path - Record manual-run failures in job metadata via mark_job_run(False) - Keep _run_cron_tracked self-contained for worker-thread execution Includes 2 behavioral regression tests using monkeypatch.setitem on sys.modules to mock cron.scheduler.run_job + cron.jobs helpers — the right test pattern (exercises the real _run_cron_tracked code path). Split out from nesquena#1352 (the larger profile-aware-cron-panel PR that's on hold) per pre-release-review feedback. Self-contained, doesn't touch the held PR's profile-filtering scope. Co-authored-by: NocGeek <[email protected]>
…rsistence Opus pre-release findings on nesquena#1370 applied: SHOULD-FIX 1: Tightened parent_session_id exposure to only emit when the parent's end_reason is in {compression, cli_close}. Without this, two distinct WebUI sessions sharing a non-continuation parent (e.g. 'user_stop') would get clustered by frontend's _sessionLineageKey (which falls through to parent_session_id when _lineage_root_id is missing) and incorrectly collapsed into a single sidebar row. Updated assertions in: - tests/test_session_lineage_metadata_api.py:: test_non_compression_state_db_parent_does_not_create_sidebar_lineage - tests/test_pr1370_lineage_metadata_perf_and_orphan.py:: test_non_compression_parent_does_not_extend_lineage SHOULD-FIX 2: Chunked the IN-clause to 500 vars to stay under SQLITE_MAX_VARIABLE_NUMBER. Python 3.9 ships sqlite 3.31 with the default limit of 999. A power user with 2000+ sessions in the sidebar would hit OperationalError, the silent except-wrapper would swallow it, and lineage collapse would never work. Added test_in_clause_chunked_for_large_session_set with SQL interception to lock the invariant in source. PR addition (per user directive — Opus + my review, no second independent review round needed for combined batch): nesquena#1372 from @NocGeek — fix: persist manual cron run results. Self-contained 89 LOC fix split out from the held nesquena#1352. Mirrors the scheduled-cron path (cron/scheduler.py:1334-1364) exactly: saves output, marks job complete, treats empty response as soft failure with matching error string. 2 behavioral tests using sys.modules monkeypatch to mock cron.scheduler.run_job. CI not yet attached because branch is brand-new; ran the new tests + adjacent suites locally — all pass. Final test count: 3471 passing, 0 failed. Also adds 2 more regression tests for the perf-fix invariants: - test_in_clause_chunked_for_large_session_set - test_two_children_sharing_non_continuation_parent_not_collapsed
Summary
profile=and comma-separatedprofiles=queries.profileon cron jobs and route cron detail/action endpoints through the owning profile.localStorage, while keeping active profile semantics for new job creation.last_run_at/last_status.Tests
python3 -m py_compile api/routes.py tests/test_cron_profile_visibility.pynode --check static/panels.jsgit diff --check origin/master..HEAD/home/nocmadman/.hermes/hermes-agent/venv/bin/python -m pytest tests/test_cron_profile_visibility.py tests/test_sprint3.py::test_crons_list tests/test_sprint3.py::test_crons_list_has_required_fields tests/test_sprint3.py::test_crons_output_requires_job_id tests/test_sprint3.py::test_crons_run_nonexistent tests/test_sprint7.py::test_cron_update_unknown_job_404 tests/test_sprint7.py::test_cron_delete_unknown_404 tests/test_sprint10.py::test_crons_output_limit_param tests/test_cron_refresh_button_835.py tests/test_issue1140_cron_badge_per_job.pyResult: 25 passed.
Manual Verification
hermes cron listshows default jobs.cronbot cron listshows cronbot jobs./api/crons?profiles=default,cronbotreturns jobs from both profiles withprofilefields.[default]and[cronbot]rows when both are selected.last_run_at/last_status.Notes
ARCHITECTURE.mdandTESTING.mdcould be updated in a follow-up to document the new profile-aware cron query/body parameters and manual visible-profile checklist.