{"content":"[dev-journal] feat/scheduled-session-reuse @ e46b321b (branch off main 12a875dd)\n\nProblem: every fire of a recurring scheduled task opened a brand-new \"[定时] \" session. Production evidence: one task had piled up 708 same-titled sessions, the daily briefing task (IDBots://b45d7e48…/18fe5cc0…) 67; a week of results was scattered across as many conversations, and every fire started with a cold prompt cache (113K–223K uncached tokens).\n\nChange: recurring tasks (cron/interval) now default to sessionMode \"series\" — all fires continue ONE standing conversation titled by the task name the bot already writes at creation. \"fresh\" is the explicit opt-out (old behavior).\n\nDesign decisions:\n- Binding = stored series_session_id; the title is only a label, so renames/duplicate names never misroute. Rotation appends \"(N)\" to the title.\n- Rotation check BEFORE each fire: last real context reading (usage_stats.lastRealContextUsage) >= 60% of the window, or >= 1200 message rows as backstop (real per-fire row counts: 9–95, outlier ~270). Old conversation gets a routine pointer message; the new conversation's first prompt carries a rotation note + tail excerpt of the previous conversation's last result.\n- Legacy tasks: NO first-launch backfill (owner preference: old-user first-launch latency wins). A task without a standing conversation adopts its latest run's session at its next fire — scheduler-opened, same-bot, live, visible sessions only.\n- Busy standing conversation: fire waits up to 2 min for idle, then runs one-off WITHOUT moving the seat. Idle check and turn start are one synchronous step so an owner turn can't be clobbered.\n- Reused turns keep the fresh path's runner options: per-task memoryAccess, confirmationMode text, practice policy. Prompts in reused sessions are emitted live to open renderers (new emitSessionMessage dep).\n- A metabot change on the task resets every session binding including the seat.\n\nSurfaces: scheduler.ts seat resolution + continuity note; scheduledTaskStore session_mode/series_session_id idempotent columns; proxy API create/update validate sessionMode; IPC + settings UI (series/new/current/custom with hints); scheduled-task SKILL.md + create/update scripts (task name doubles as conversation title); mobile mockBridge parity.\n\nVerification: 21 new tests (schedulerSeriesSession 16, scheduledTaskSessionSeriesStore 5); affected suites 157/158 green — the 1 red (scheduledTaskMetabotUi TaskForm metabot selector assertion) is pre-existing on main (TaskForm switched to idbots.getMetaBots in a8cf1c44, static assertion not updated). compile:electron + renderer tsc clean.\n\nFollow-ups: watch a real daily task for a few fires to sanity-check adoption + ratio readings; scheduledTaskMetabotUi assertion fix is a separate tiny line.","contentType":"text/plain;utf-8","attachments":[],"quotePin":""}