Skip to content

feat(v2): restrict scheduled tasks to days, hours, and run caps - #92

Open
saphid wants to merge 1 commit into
base/ov2-standalone-20260918from
feat/schedule-restrictions
Open

saphid wants to merge 1 commit into
base/ov2-standalone-20260918from
feat/schedule-restrictions

Conversation

@saphid

@saphid saphid commented Sep 28, 2026

Copy link
Copy Markdown
Owner

What Changed

Scheduled tasks can now be limited to certain days and hours and capped after a number of runs. An interval schedule accepts three optional fields:

  • weekdays: days it may run on ([1,2,3,4,5] is Monday to Friday).
  • window: a local time range such as {start:'09:00', end:'17:00'}. Runs outside it wait for the next opening. A run that comes due while the app was closed or asleep and lands outside the window is skipped forward, not fired late. Windows never cross midnight; a window opening inside a DST spring-forward gap skips that day.
  • maxRuns: a total-run cap, also valid on fixed-time schedules. The run that reaches it pauses the task in the same write and the row reads "Run limit reached (16/16)". Editing the schedule so the cap is raised or removed resumes it; an explicit enabled in the same update wins.

So {type:'interval', everyMs:1800000, weekdays:[1,2,3,4,5], window:{start:'09:00', end:'17:00'}, maxRuns:16} means "check every half hour during weekday business hours, at most 16 checks".

Surfaces: contracts, server scheduler, web editor and task rows, mobile editor and task rows, the schedule_task / update_scheduled_task MCP schemas and descriptions, and docs/user/scheduled-tasks.md. Existing tasks and callers are unaffected because every field is optional. Providers, checkpointing and the v1 path are untouched. Base is base/ov2-standalone-20260918 because the scheduler only exists there.

Why

Recurring automations either ran forever at their cadence or had to be paused by hand. Audit and babysitter tasks ("check every half hour, only while the office is open") need runs confined to working hours and a natural end, or a forgotten automation burns runs overnight and at weekends. This keeps the two-mode schedule model: no cron syntax, no new schedule types.

UI Changes

Editing a task before the change: the interval editor had only "Run every N minutes", and a stored task's row shows only "Every 30 min" (same stored task, rendered by the base build).

Before (base): interval editor and task row with no restriction controls

After: day toggles, an "Only between" window, and a "Stop after" run cap. The row reads Every 30 min · weekdays · 09:00–17:00 · 16 runs max.

After (candidate): Mon to Fri, 09:00 to 17:00 window, stop after 16 runs

Capture conditions: web client (headless Chrome, 900px viewport) against a disposable dev server and empty state. Both GIFs are sampled frames of real captures, not real-time recordings, so they show states rather than timing. The mobile editor mirrors these controls but was not run in a simulator.

Verification

Independent review by GPT-6 Astra (high) found five defects, all fixed here: web edits dropped restrictions (the edit path used a second, unaware builder), overdue runs fired outside the window after downtime, a DST gap could produce out-of-window runs, raising the cap did not resume a paused task, and capped rows showed "Paused" instead of the limit.

  • apps/server vp test run src/scheduledTasks/ src/mcp: 260 passed across 23 files. New cases: window snapping and weekday skips, empty masks, dispatch-time restriction check, New York spring-forward gap, cap pause on the reaching run, resume by raising or clearing the cap.
  • apps/web vp test run src/components/settings/: 546 passed (including restriction edit patches through the builder the component imports).
  • apps/mobile vp test run src/features/settings: 79 passed. packages/contracts src/scheduledTask.test.ts: passed.
  • tsc --noEmit clean for apps/web and apps/mobile; apps/server shows only the CheckpointDiffQuery.test.ts error that also fails on the base. vp lint and vp fmt clean on touched files.
  • Not tested: mobile in a simulator; DST fall-back overlap has no dedicated test.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes (sampled-frame GIF, disclosed above)

Implementation by GLM (xlarge) in T3 Code; audit fixes and verification by Claude Sonnet 5.5 in Claude Code; independent review by GPT-6 Astra.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Sep 28, 2026
@github-actions

Copy link
Copy Markdown

Thread transfer impact

⚠️ The latest CI run did not produce a thread transfer result for cabd2fd.

This comment will update automatically after the next completed run.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant