fix(tasks): preserve both cron-run session key shapes during maintenance#96352
Conversation
|
Codex review: needs changes before merge. Reviewed June 24, 2026, 9:52 AM ET / 13:52 UTC. Summary PR surface: Source +20, Tests +119. Total +139 across 2 files. Reproducibility: yes. Source inspection shows current main lowercases running cron ids while runtime producers can write slugged or custom cron-run session segments; I did not execute tests because this review is read-only. Review metrics: 1 noteworthy metric.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Copy recommended automerge instructionNext step before merge
Security Review findings
Review detailsBest possible solution: Derive the preserve set from the job id, Do we have a high-confidence way to reproduce the issue? Yes. Source inspection shows current main lowercases running cron ids while runtime producers can write slugged or custom cron-run session segments; I did not execute tests because this review is read-only. Is this the best way to solve the issue? No, not yet. Preserving raw, slugged, and Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against f1e38f2ed637. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +20, Tests +119. Total +139 across 2 files. View PR surface stats
Acceptance criteria:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
Session-registry maintenance keeps running cron jobs' session rows, but
readRunningCronJobIds built the preserve-set with job.id.toLowerCase() only.
Cron-run session keys carry two job-segment shapes: main-session runs use the
slugified segment (normalizeCronLaneSegment, e.g. "daily-report") while
default-isolated runs use the raw lowercased id ("daily report", built from
cron:${job.id} via toAgentStoreSessionKey, which lowercases but does not
slugify). The lowercase-only matcher preserved isolated runs but pruned
main-session runs of any non-slug job id (e.g. "Daily Report") as stale.
Preserve both shapes (raw lowercased id and slugified segment). This is
strictly more-preserving, so no live running cron session is dropped. Adds a
regression test seeding both a slug main-session run and a raw isolated run for
a non-slug job id, asserting both survive while a non-running job's run is still
pruned.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
95a0539 to
f5b8a9d
Compare
|
Merged via squash.
|
…nce (openclaw#96352) * fix(tasks): preserve both cron-run session key shapes during maintenance Session-registry maintenance keeps running cron jobs' session rows, but readRunningCronJobIds built the preserve-set with job.id.toLowerCase() only. Cron-run session keys carry two job-segment shapes: main-session runs use the slugified segment (normalizeCronLaneSegment, e.g. "daily-report") while default-isolated runs use the raw lowercased id ("daily report", built from cron:${job.id} via toAgentStoreSessionKey, which lowercases but does not slugify). The lowercase-only matcher preserved isolated runs but pruned main-session runs of any non-slug job id (e.g. "Daily Report") as stale. Preserve both shapes (raw lowercased id and slugified segment). This is strictly more-preserving, so no live running cron session is dropped. Adds a regression test seeding both a slug main-session run and a raw isolated run for a non-slug job id, asserting both survive while a non-running job's run is still pruned. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(tasks): match cron session keys to target shape * fix(tasks): preserve active cron aliases across retargeting * fix(tasks): retain explicit cron session aliases --------- Co-authored-by: ly-wang19 <ly-wang19@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
…nce (openclaw#96352) * fix(tasks): preserve both cron-run session key shapes during maintenance Session-registry maintenance keeps running cron jobs' session rows, but readRunningCronJobIds built the preserve-set with job.id.toLowerCase() only. Cron-run session keys carry two job-segment shapes: main-session runs use the slugified segment (normalizeCronLaneSegment, e.g. "daily-report") while default-isolated runs use the raw lowercased id ("daily report", built from cron:${job.id} via toAgentStoreSessionKey, which lowercases but does not slugify). The lowercase-only matcher preserved isolated runs but pruned main-session runs of any non-slug job id (e.g. "Daily Report") as stale. Preserve both shapes (raw lowercased id and slugified segment). This is strictly more-preserving, so no live running cron session is dropped. Adds a regression test seeding both a slug main-session run and a raw isolated run for a non-slug job id, asserting both survive while a non-running job's run is still pruned. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(tasks): match cron session keys to target shape * fix(tasks): preserve active cron aliases across retargeting * fix(tasks): retain explicit cron session aliases --------- Co-authored-by: ly-wang19 <ly-wang19@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
What Problem This Solves
openclaw tasks maintenanceprunes stale session-registry rows but preserves rows belonging to running cron jobs.readRunningCronJobIds(src/commands/tasks.ts) built that preserve-set withjob.id.toLowerCase()only. But cron-run session keys carry two job-segment shapes:normalizeCronLaneSegment(job.id)→agent:main:cron:daily-report:run:…(resolveMainSessionCronRunSessionKey).sessionKey): raw lowercased — built fromcron:${job.id}(src/cron/service/task-runs.ts) →resolveCronAgentSessionKey→toAgentStoreSessionKey, which lowercases but does not slugify →agent:main:cron:daily report:run:….So for any non-slug job id (e.g.
"Daily Report"), the lowercase-only matcher ("daily report") preserved the isolated run but pruned the live main-session run ("daily-report") as stale.Why This Change Was Made
The preserve-set now includes both shapes —
job.id.toLowerCase()(raw isolated) andnormalizeCronLaneSegment(job.id, "job")(slug main-session). Because it only adds to a preserve-set, it is strictly more-preserving: no live running cron session can be dropped. This supersedes #95319, which switched to slug-only and would have traded the main-session false-prune for an isolated-session false-prune.User Impact
tasks maintenance --applyno longer deletes the live session row of a running cron job whose id is not already a slug (contains spaces/uppercase/punctuation), for either the main-session or default-isolated run shape. No config or output-shape change.Evidence
oxfmt,oxlint,tsgo:coreall pass. New colocated regression test exercises the realtasksMaintenanceCommand({apply:true})against a real session store + cron store.Real behavior proof
Behavior addressed:
tasks maintenance --applypruned the live main-session cron-run session row of a running non-slug job id (e.g."Daily Report") because the running-job preserve-set used only the raw lowercased id, not the slugified session-key segment.Real environment tested: Ran the exported
tasksMaintenanceCommand({ json: true, apply: true })via the colocated Vitest harness (node scripts/run-vitest.mjs) on Node v22.22.1 against a real temp state dir — a realsessions.jsonstore and a real cronjobs.jsonstore written to disk — not mocks.Exact steps or command run after this patch: seed a running cron job id
"Daily Report"; write three stale (8-day-old) cron-run session rows — slugagent:main:cron:daily-report:run:old-run, rawagent:main:cron:daily report:run:old-run, and non-runningagent:main:cron:retired-job:run:old-run; runtasksMaintenanceCommand({apply:true}); thennode scripts/run-vitest.mjs src/commands/tasks.test.ts -t "preserves both slug and raw", plusnode scripts/run-oxlint.mjsandpnpm tsgo:core.Evidence after fix:
Observed result after fix: the running job's slug (
daily-report) and raw (daily report) cron-run session rows are both retained; the non-running job's stale row is still pruned. Reverting the one-line matcher change reproduces the prune (fail-before), confirming the test pins the fix.What was not tested: a full live gateway run that actually generates the isolated vs main-session keys end-to-end (no live gateway in this environment); the segment shapes are taken from the production key builders (
task-runs.ts,toAgentStoreSessionKey) and asserted at the maintenance-command level with on-disk stores.