Conversation
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tracing the stale-summary distinction and adding a focused regression test. The list-path fix is valid on current main, but the execution truth is still inconsistent across cron-tool response paths.
Problems
tools/cronjob_tools.py:590copieslatest_executiononly if the input already has it. Main enriches onlylist_jobs()results (cron/jobs.py:1491-1504), whileget_job()andupdate_job()return plain job records (cron/jobs.py:1444-1450,cron/jobs.py:1602-1604). The formatted pause/resume/update/run responses can therefore returnlatest_execution: nulldespite an existing newer ledger record.
Suggested changes
- Route every formatted cron-tool job response through a shared ledger-enrichment path, and add a non-list action regression test.
Automated hermes-sweeper review.
| # Keep the occurrence ledger beside the historical completion summary. | ||
| # Without it, a prior last_status="ok" can be mistaken for the result | ||
| # of a newer claimed/running/failed/unknown attempt. | ||
| "latest_execution": job.get("latest_execution"), |
There was a problem hiding this comment.
list_jobs() is the only current supplier of this field (cron/jobs.py:1491-1504). Other _format_job() callers receive records from get_job()/update_job(), which do not attach ledger state, so those responses emit null even when an execution exists. Please use a shared enriched-job path for all formatted action responses.
There was a problem hiding this comment.
Updated in commit 3169e489. The list result retains the existing batch enrichment, while action responses now lazily resolve ledger truth through the shared _format_job() seam. The list and pause regressions plus related cron checks passed: 103 tests passed. The full canonical suite was unavailable because the shared Hermes environment selected by scripts/run_tests.sh lacks pytest.
What does this PR do?
_format_job()drops thelatest_executionfield when it builds a job's public shape, so consumers only see the historical completion summary (last_status,last_run). When a newer attempt is claimed, running, failed or in an unknown state, that summary still reports the previous outcome — a stalelast_status="ok"reads as the result of the newer attempt.This adds
latest_executionalongside the existing summary fields, so the occurrence ledger travels with the job and a caller can tell "the last completed run was ok" apart from "the current attempt is ok".Four lines plus a regression test. No behavior change for callers that ignore the field.
Related Issue
No existing issue — this surfaced while reading cron job state in a dashboard, where a job that was mid-failure kept presenting as healthy.
Searched before filing: no open or merged PR mentions
latest_execution. The closest existing work is #48072 (feat(cron): 3-state last_status), which reshapes the summary field. This PR does not touchlast_statusand does not conflict with that approach — it exposes the ledger that already exists in the job dict.Type of Change
Changes Made
tools/cronjob_tools.py—_format_job()now carrieslatest_executionthrough to the formatted job (+4 lines, including the comment explaining the stale-summary trap).tests/cron/test_execution_ledger.py— addstest_cronjob_formatter_exposes_newer_unknown_attempt_over_stale_success, which constructs a job whoselast_statusisokwhile a newer attempt is unknown, and asserts the formatter exposes the newer attempt (+40 lines).How to Test
_format_job(). Before this change the result reportslast_status="ok"and nothing about the newer attempt.latest_executionis present and describes the newer attempt.Automated:
Falsifier — reverting only the
tools/cronjob_tools.pyhunk makes the new test fail withKeyErrorattest_execution_ledger.py:359, so the test genuinely covers the fix rather than passing either way.Note on the checklist below: I ran the cron suite (
pytest tests/cron/ -q, 748 passed) rather than the wholetests/tree, because the full run can touch a realHERMES_HOMEon this machine and I did not want it reaching a live install. Happy to post a full-suite run from a clean environment if you want it before merge.Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests pass — ranpytest tests/cron/ -q(748 passed); see the note aboveDocumentation & Housekeeping
docs/, docstrings) — or N/A (N/A: internal formatter, comment added inline)cli-config.yaml.exampleif I added/changed config keys — or N/A (N/A: no config keys)CONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/A (N/A)