feat(automations): scheduled cycles, grouped runs, and run details UI#438
Conversation
|
@Soju06 i don't envy your position... having to review a 27k line PR great feature though. i can't wait :) |
8c2b071 to
625d067
Compare
|
What's the status on this PR? |
|
We’re waiting for a review from @Soju06 |
|
Hey @Soju06, sorry for the ping but would you be willing to review this PR? |
|
@codex review |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@Soju06, could you please take a look at this PR when you have a moment? A lot of people seem to be waiting for this automation-related change, and the PR has been ready for review for a while now. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8436ea498d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
That’s fair if we frame this PR only as a generic cron UI, but I don’t think #737 fully replaces the use case here. #433 explicitly asks for optional idle warmup: lightweight background requests that intentionally start rolling 5-hour windows earlier, with each account warmed at most once per cycle and multi-account warmups staggered across the 300-minute window. That is the behavior this PR targets: activating idle account windows in a controlled way so they are ready before real traffic arrives. From my reading, #737 is mostly a quota-aware planner and routing layer with selective warmup decisions. It is conservative by default ( I see these as different layers: #737: planner, routing, selective decision-making Warmup is just the first job type on top of this infrastructure. Later, the same run-cycle, snapshot and diagnostics layer could support other operational jobs too, for example detecting unexpected quota resets before the expected 7-day boundary or surfacing account anomalies. In the future, the planner could drive this execution layer, but I don’t think it replaces the need for the layer itself. |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c304540db8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
@codex review |
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
Hello, what's the status on this PR? |
# Conflicts: # app/modules/dashboard/api.py # frontend/src/test/mocks/handlers.ts
|
@codex review |
1 similar comment
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3efb906f8f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| async def _normalize_create_input(self, payload: AutomationJobCreateInput) -> AutomationJobCreateInput: | ||
| name = _normalize_non_empty(payload.name, field_label="name", code="invalid_name") | ||
| model = _normalize_non_empty(payload.model, field_label="model", code="invalid_model") |
There was a problem hiding this comment.
Reject source-only models for automation jobs
When model sources are configured, /api/dashboard/models includes enabled source-only slugs for API-key allowlists, but automation runs always call the ChatGPT compact endpoint with an account token and never look up ModelSource routing. Since creation only checks that model is non-empty here, the UI/API can persist a job with a source-only model; every manual/scheduled run for that job will then fail upstream instead of being rejected at save time. Please restrict automation models to ChatGPT-routable registry entries or add source routing before accepting them.
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7d3a74831a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| case( | ||
| (cycle_agg.c.has_manual_trigger == 1, cycle_agg.c.visible_accounts), | ||
| else_=cycle_agg.c.snapshot_expected_accounts, | ||
| ).label("expected_accounts"), |
There was a problem hiding this comment.
Apply eligibility when filtering scheduled cycle statuses
When a scheduled cycle has completed one account and a later snapshot account becomes rate-limited or deleted before its dispatch time, _build_scheduled_cycle_summary omits that account from totals, so the unfiltered runs page can display effectiveStatus: "success". The SQL status filter here still uses the stale cycle_expected_accounts for scheduled cycles, so /api/automations/runs?status=success excludes that same row until the dispatch-time cleanup runs, making filters disagree with the status shown to operators.
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8cb607d391
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| cycle = await self._repository.create_run_cycle( | ||
| cycle_key=cycle_key, | ||
| job_id=job.id, | ||
| trigger=AUTOMATION_RUN_TRIGGER_MANUAL, | ||
| cycle_expected_accounts=len(dispatch_plan), | ||
| cycle_window_end=cycle_window_end, | ||
| accounts=dispatch_plan, | ||
| include_paused_accounts=job.include_paused_accounts, |
There was a problem hiding this comment.
Make manual cycle placeholder creation recoverable
When a manual run is triggered with delayed or multi-account dispatch, this commits the cycle snapshot before the per-account automation_runs placeholders are all created. If the request is cancelled or the process exits after this commit but before the loop below finishes inserting placeholders, the scheduler cannot recover the missing manual accounts because _run_due_manual_runs only scans existing automation_runs rows, so those snapshot-only accounts remain pending forever (or the cycle remains invisible if no run row was created). Consider creating the manual placeholders atomically with the cycle or teaching the scheduler to materialize missing manual snapshot rows.
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8cb607d391
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
1 similar comment
|
@codex review |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review |
1 similar comment
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 810e93264c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| AutomationRun.cycle_key == AutomationRunCycleAccount.cycle_key, | ||
| AutomationRun.account_id == AutomationRunCycleAccount.account_id, |
There was a problem hiding this comment.
Associate completed slots by slot key
When a scheduled cycle slot for account A fails over to account B before B's delayed slot is due, the completed run keeps A's slot_key but is stored with account_id=B. If A is later deleted or becomes ineligible, this join counts that completed A slot as B's snapshot account, so /api/automations/runs can report the cycle as terminal with no pending B slot while run details still show B pending. The grouped status query needs to associate runs to snapshot accounts using the same slot-key logic as _resolve_scheduled_cycle_run_account_id, not only the terminal account_id.
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d836a56938
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| def _cycle_account_slot_key(*, job_id: str, trigger: str, account_id: str, scheduled_for: datetime) -> str | None: | ||
| if trigger != "scheduled": | ||
| return None | ||
| return _scheduled_slot_key(job_id, account_id=account_id, due_slot=scheduled_for) |
There was a problem hiding this comment.
Store scheduled snapshot keys from the cycle due slot
When thresholdMinutes > 0, scheduled_for is the randomized per-account dispatch time, while scheduled run rows are claimed with a slot key derived from the cycle's original due slot. Persisting the snapshot slot_key from the offset time makes the grouped-history joins that match AutomationRun.slot_key to AutomationRunCycleAccount.slot_key miss completed runs after the account FK is nulled, such as when a completed account is deleted, so thresholded cycles can report wrong totals/pending/status.
Useful? React with 👍 / 👎.
|
@codex review |
1 similar comment
|
@codex review |
|
Codex Review: Didn't find any major issues. More of your lovely PRs please. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Maintainer refresh (2026-06-04, migration merge)
9fe67dc6bb1e6d072fbf9fd93103b0ff483d56caafter CI exposed two Alembic heads on the rebased branch.20260604_010000_merge_automations_and_reauth_status_headsto merge the automations head with20260604_000000_add_reauth_required_account_statusfrom currentmain.uv run pytest tests/unit/test_db_migrate.py -quv run pytest tests/unit/test_automations_service.py tests/integration/test_automations_api.py -quv run ruff check app/db/alembic/versions/20260604_010000_merge_automations_and_reauth_status_heads.py tests/unit/test_db_migrate.py tests/unit/test_automations_service.py tests/integration/test_automations_api.pyuv run ty check app/db/alembic/versions/20260604_010000_merge_automations_and_reauth_status_heads.py tests/unit/test_db_migrate.py tests/unit/test_automations_service.py tests/integration/test_automations_api.pygit diff --checkMaintainer refresh (2026-06-04)
mainand pushed the conflict repair to5ed264e9f8fcce02eea7bb63f50960ab06a9e290.mainconflicts by preserving current quota-planner/request-log/index behavior and keeping the automations scheduler, API, UI mocks, and migration tests.uv run ruff check app/core/config/settings.py app/db/models.py app/main.py app/modules/automations tests/unit/test_db_migrate.py tests/unit/test_automations_service.py tests/integration/test_automations_api.pyuv run pytest tests/unit/test_db_migrate.py::test_automation_run_cycle_snapshot_migration_normalizes_legacy_manual_keys tests/unit/test_db_migrate.py::test_quota_planner_migration_repairs_preexisting_request_kind_column tests/unit/test_automations_service.py -quv run pytest tests/integration/test_automations_api.py -quv run ty check app/core/config/settings.py app/db/models.py app/main.py app/modules/automations tests/unit/test_db_migrate.py tests/unit/test_automations_service.py tests/integration/test_automations_api.pyuv run openspec validate add-automations-scheduled-pings --strictcd frontend && bun run typecheckcd frontend && bun run lintcd frontend && bun run test -- src/features/automations/hooks/use-automations.test.ts src/features/automations/schemas.test.ts src/features/automations/time-utils.test.ts src/features/automations/account-display.test.ts src/__integration__/automations-flow.test.tsxgit diff --checkSummary
Related issue
Problem
The project did not yet have a dedicated automations subsystem.
That meant there was no built-in way to:
Changes
New backend automations module
202 Accepted)runningpartialsuccessfailedDatabase and run-cycle snapshot model
automation_run_cyclesautomation_run_cycle_accountsNew Automations UI
Request Logs visibility
OpenSpec
openspec/changes/add-automations-scheduled-pings/:automationsdelta specfrontend-architecturedelta specScreenshots
Testing
Added or updated coverage for:
Validation
openspec validate --specsuvx ruff check .uvx ruff format --check .uv run ty checkuv run pytestcd frontend && bun run lintcd frontend && bun run typecheckcd frontend && bun run test:coverageupgrade -> downgrade -> upgradeLatest local backend result:
1824 passed, 7 skipped, 4 warningsFrontend coverage result:
src/features/automationscoverage:91.89%statements79.51%branches91.78%linesResult
This PR introduces a new Automations subsystem with scheduling, grouped run cycles, stable cycle snapshots, per-account execution diagnostics, and dedicated UI management flows,
while partially delivering the functionality described in #433.