Skip to content

Persistent cron rotation starts a new chat, preserving the old one#167

Merged
pufit merged 1 commit into
mainfrom
pufit/cron-rotation-new-chat
Jul 6, 2026
Merged

Persistent cron rotation starts a new chat, preserving the old one#167
pufit merged 1 commit into
mainfrom
pufit/cron-rotation-new-chat

Conversation

@pufit

@pufit pufit commented Jul 6, 2026

Copy link
Copy Markdown
Member

Investigation

The suspicion was that persistent-cron auto-rotation loses the previous chat history. Findings:

  • No data was ever deleted. Rotation only cleared sdk_session_id/connected_at on the stable cron:{job_id} session and scheduled memU indexing. E.g. a long-lived inbox-processor session holds ~10.7K messages spanning 4 months of daily rotations — all still in the DB.
  • But the history was effectively invisible. Every context epoch piled into one endless chat, rotation boundaries were invisible, and the chat view only loads the most recent messages (default fetch limit, no pagination) — so after a rotation the old history appeared lost.

Change

Persistent jobs now run in generation chats:

  • Each generation is its own session (cron:{job_id}:{timestamp}); the job's current generation is tracked in channel_sessions under the key cron:{job_id}.
  • Rotation retires the current chat and mints a fresh one instead of resetting context in place. The retired chat keeps its full history, messages, per-turn usage, and run-log links; it stays browsable (and resumable) in the UI and ages out via the normal session-archival policy.
  • Retiring also: schedules memU indexing (as before), cancels the session's pending wakeups (a retired thread must not resurrect itself alongside the new generation), stamps rotated_at in metadata, and retitles the chat with its end date (Cron: {job_id} (until 2026-07-05)).
  • Rotation triggers are unchanged (context_rotate_hours, context_rotate_at, manual rotate). connected_at still marks the SDK context epoch.
  • Manual rotate (POST /api/cron/jobs/{id}/rotate) now retires + mints eagerly, and returns old_session_id/new_session_id.
  • Upgrade path: legacy stable-id sessions (cron:{job_id}) are adopted as the current generation on the first run after upgrade — SDK context carries over seamlessly — and move to the generation scheme at their next rotation. A rotated-out legacy session is never re-adopted.
  • run_persistent_cron accepts the resolved session_id from the cron service (falls back to the legacy id when omitted).

Reminder mode, run-log session linking, notification session-label suppression (prefix-matched), and the CronPage chat link (get_latest_cron_session_id) all work unchanged with generation ids.

Tests

  • Reworked rotation tests + new coverage: new-chat minting, old-chat preservation, wakeup cancellation + retitle/stamp, legacy adoption (and non-re-adoption), archived-mapping recovery, manual rotate (incl. no-session noop), reminder-mode across rotation.
  • Full suite: 1379 passed, 2 skipped. Frontend builds clean.

Generated by Nerve

Rotation used to reset the SDK context in place: every context epoch piled
into one endless cron:{job_id} chat, and since the chat view only loads the
most recent messages, pre-rotation history was effectively invisible.

Now each persistent job runs in a generation chat (cron:{job_id}:{ts})
tracked via channel_sessions. Rotation retires the current chat untouched
(history, usage, and run-log links preserved; browsable like any session),
cancels its pending wakeups, stamps/retitles it, and mints a fresh chat for
subsequent runs. Legacy stable-id sessions are adopted on first run so
existing installs keep their context.
@pufit pufit merged commit c39c765 into main Jul 6, 2026
2 checks passed
@pufit pufit deleted the pufit/cron-rotation-new-chat branch July 6, 2026 02:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant