Skip to content

fix(server): scheduler writes no longer overwrite concurrent task edits - #12529

Closed
saphid wants to merge 573 commits into
pingdotgg:t3code/codex-turn-mappingfrom
saphid:work/pr11592-split-2-scheduler-writers
Closed

saphid wants to merge 573 commits into
pingdotgg:t3code/codex-turn-mappingfrom
saphid:work/pr11592-split-2-scheduler-writers

Conversation

@saphid

@saphid saphid commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #11592. Until that merges, this diff also shows its commit; review only fix(server): scheduler writes no longer overwrite concurrent task edits.

Problem

Run completion, stuck-run release, and dispatch each re-read the task and then wrote in a separate statement. An edit committed between the two had its next_run_at overwritten from the older schedule, and a pause, postpone, or delete landing after the dispatch re-read could still fire.

Fix

Each re-read and its write now share one transaction, with the contention retry from #11592. The missed-run reschedule is guarded on the next_run_at it was computed from, so it loses to an edit instead of overwriting it.

Tests

ScheduledTaskService.test.ts: the due-read to dispatch gap (pause, postpone, delete, and the no-edit case), an edit committed mid-run on both the success and interrupted paths, and a contended completion write that retries instead of stranding the task as running. The retry test fails with the retry disabled. Server typecheck: 0 errors.

Split from the original #11592 by Claude Fable 5.1 via Claude Code; original implementation with SWE-2 High via Devin CLI. One complete independent review by SWE-2 Max; its findings were fixed, and the fixes were then reviewed by Claude Fable 5.1 only.

🤖 Generated with Claude Code

juliusmarminge and others added 30 commits September 18, 2026 17:45
Restores main features dropped by the policy replay: pingdotgg#8569 theme wiring,
settings search rework, pingdotgg#8803 workspace-mutation refresh (v2-adapted),
video + image previews (web and mobile, v2-adapted), pingdotgg#8862 Expo glass,
and the round's docs. Timeline thinking rows (pingdotgg#8984) stay on the v2
work-live system.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The v2 equivalents of main's pingdotgg#8984 and pingdotgg#8922: a "Working for ..." header
anchors the active run, the trailing live tool row survives between
actions in past tense instead of vanishing, and a shimmering Thinking
row marks reasoning gaps. During workspace preparation the header shows
"Setting up worktree..." (driven by the local dispatch flag or the v2
run's preparing status, so remote viewers see it too), the composer
footer span is gone, and draft promotion waits until the run starts or
startup fails instead of navigating mid-preparation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adopts the round's main features into the v2 architecture: the pingdotgg#9023
media rework (streamed videos, media-file assets, protocol-relative
links), pingdotgg#9098 shared live-activity row folded into the v2 working and
thinking rows, the pingdotgg#9084/pingdotgg#9078 Claude model catalog for v2 consumers,
a native pingdotgg#9005 OpenCode child-session abort in the v2 adapter, pingdotgg#9013's
landed LegendList patch, and per-environment sidebar provider entries.
For pingdotgg#8600 the server-side pieces land, but auto-settle evaluation stays
client-side (reading the new server-owned settings) until the v2
orchestrator grows its own settlement reactor; main's v1-only reactor
and coalescer additions are dropped with the rest of the v1 path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ator

Ports pingdotgg#8600's server-owned settlement to orchestration v2 instead of
keeping client-side evaluation. A ThreadSettlementService sweep runs at
startup, on auto-settle settings changes, and once per minute: it
evaluates inactivity and merged or closed pull requests over v2 thread
shells and dispatches the new guarded thread.auto-settle command, which
rejects threads that changed after the sweep's snapshot or carry any
explicit override, then reuses the orchestrator's settle lifecycle.
With the server deciding, the clients drop their effectiveSettled
evaluation and partition on the persisted settledOverride like main.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adopts main's round-19 features into the v2 stack: payload-budgeted
orchestration replay (pingdotgg#8992), sidebar row subscription leases (pingdotgg#9052),
tool group virtualization and scroll anchoring (pingdotgg#9106), repeated-command
and browser-group presentation, inline assistant citations (pingdotgg#9146),
per-cwd provider skills discovery (pingdotgg#8778), Claude composer skill
dispatch (pingdotgg#9128), grok health probe and model negotiation (pingdotgg#9154), and
the failed-tool thinking fallback (pingdotgg#9165).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round 17 adopted main's pingdotgg#8850 ComposerBanner.Attachment (mx-auto plus the
standalone drawer-inset width) without main's matching mounts, so the
stash tab's ml-auto lost to the attachment's auto right margin and the
tab centered over the composer. Column now spans its attachments like
main does, the stash tab zeroes the right margin, and the stash menu
keeps the full dock width.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The branch had drifted from main's composer and work-log design in ways
unrelated to orchestration v2: a pre-revert "Working for" shoulder tab
on the composer (main reverted pingdotgg#8693 and re-landed pingdotgg#8734 without it),
an inline stash variant plus in-flow stash menu, expanded tool rows that
hid their icons, an unmounted woke-thread banner, a composer scroll
observer main never had, and a right-panel toggle that lost its
showRightPanelControl gate so it rendered twice with the panel open.

ChatComposer and its satellites now start from main's files with only
the v2 delta re-applied (dispatch modes, queued-message editing, runtime
request ids, response capability). Background tasks surface as a
ChatView banner in main's backgroundLiveness shape instead of a
composer tab. SimpleWorkEntryRow takes main's PlainWorkEntryRow body
with the V2ItemInspector kept behind the expander.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Renumbers the v2 migrations 044-052 to 045-053 behind main's
044_ClearAutomaticProjectModelDefaults, and adopts main's sticky
new-thread selection (pingdotgg#9164), local-only worktree bases in the v2 launch
path (pingdotgg#8751), the PR summary read for settlement (pingdotgg#9176), Claude per-cwd
skills (pingdotgg#9210), the provider editor redesign with the branch's dedicated
environment fields re-grafted (pingdotgg#8508), and the client half of
continue-threads-across-restart (pingdotgg#9167). The server-side continuation
markers stay unported: they live in the v1 session directory, and v2
recovery terminalizes running runs on restart, so the capability is
withheld until the v2 runtime carries them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Index event sequence lookups, recover only threads with pending work, and page projection verification and rebuilds. Bound provider event logging and omit turn histories when resuming Codex threads.

Allow delegated thread identifiers through relay routes. Add focused regression coverage and document the performance constraints.
Retain main's composer, work-log, settings, mobile and performance changes through c8f77e0 while preserving v2 runs, queued messages, provider handoffs and durable history.

Port native compaction and logout, asynchronous Codex questions, provider usage accounting, automatic settlement and PR refresh into the v2 services. Bound live event retention during replay and delivery, measure thread replay before decoding, and read checkpoint metadata without loading transcripts or patches.

Keep main migrations through 047 and move the v2 migrations to 048–058. Preserve the existing branch history and the pre-rebase backup.

Model: GPT-6. Harness: Codex.
- Preserve Codex turn identity while suppressing duplicate diff notifications
- Optimize settlement projections and isolate thread visit handling
- Add concurrency and regression coverage across server and mobile
Restore the completed work timer divider and text size from main. Keep todo-list progress in the composer and omit it from web and mobile timeline entries, including completed task lists.

Verified pending, running, and completed task projection; 187 focused web tests and 35 mobile tests pass. Web and mobile typechecks pass.
Show Send when a running thread has draft content. Separate submission follow
from first-message anchoring so later sends do not reserve extra blank space.
Restore Android initial composer insets and iOS focus-aware dictation insets.

Keep opening and final assistant replies visible around completed folds,
anchoring Worked for at the first hidden item while preserving v2 relationship
cards and execution-attempt behavior.

Validation: 107 focused tests and the mobile typecheck pass. Formatting passes;
scoped lint and React Doctor report warnings but no errors. No simulator run.
…rk (pingdotgg#4793)

Co-authored-by: Julius Marminge <julius0216@outlook.com>
Retain main's changes while preserving v2 orchestration, queue/steer controls,
composer-only tasks, timeline timers, and mobile scrolling fixes.

Port opt-in restart continuation through durable v2 effects, with shutdown
race guards, activation gating, retry deduplication, and native Codex resume.
Use narrow projection reads for control effects and runtime-request replies.
Surface Claude fallback notices without failing the turn or hiding the notice.
Report missing workspace folders before provider startup.

Carry over custom models and prices, bounded client caches and stream cleanup,
lazy image loading, persistent changed-file trees and sidebar filters, Safari
cookie import, theme fixes, POSIX file-link case, private-host favicon filtering,
native provider update paths, and platform portability updates.
Migration ids remain unchanged.

Validated scoped typechecks and focused server, web, mobile, client-runtime,
contracts, desktop, shared, SSH, script, and resource-monitor tests. Preserved
all 347 original commits and checked the final tree against both saved tips.

Model: GPT-6. Harness: Codex.
Worktree preparation previously exposed only a generic fetch failure. Classify
known authentication, network, repository access, and reference-lock errors
using stable Git diagnostics, without retaining raw output or credentials.
Unknown failures keep the existing generic message.

Cover failure classification and redaction, a real missing local remote, and
propagation into a failed prepared run without creating a worktree or running
setup. The launch test waits for the persisted failure event.

Validation: 38 focused tests, server typecheck, and scoped lint passed.
Carry main's session refresh, provider maintenance, runtime diagnostics,
composer focus, preview, usage, and mobile outbox fixes into the v2 branch.
Keep queue/steer submission, composer-only task progress, v2 subagent cards,
and LegendList scroll ownership.

Project thread and shell events before transport buffering while retaining
full durable history. Dismiss native questions when provider turns finish,
with a transaction guard that preserves answers submitted concurrently.
Port Claude limit notices and Codex file approval details to v2 adapters.

Validated with focused server, web, mobile, client-runtime, shared, desktop,
and marketing tests; affected package typechecks and scoped lint pass.
All 349 branch commits retain their authors and messages. Migration files
and the previous worktree-fetch, stash, panel, and mobile inset fixes remain
unchanged.
Offline CLI and HTTP project removal dropped force and left native v2 threads
behind. Move the nonempty-project guard and durable child cleanup into the
shared project service, and forward force from CLI, HTTP, and WebSocket calls.

Reuse the thread deletion planner and command lock, hydrate migrated history
before attachment cleanup, and validate child receipts. Commit the project
deletion after its children so failed cleanup can be retried safely.

Validation covers CLI deletion with active and archived threads, missing
workspaces, durable cleanup, partial retries, migrated attachments, receipt
collisions, and concurrent thread updates. Scoped server tests, typecheck, and
lint pass.

Implemented with Codex (GPT-6).
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com>
…dotgg#9930)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com>
juliusmarminge and others added 18 commits September 18, 2026 17:45
…pingdotgg#12514)

Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Sep 19, 2026
@macroscopeapp

macroscopeapp Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This production change spans MCP task mutation semantics, scheduler dispatch gating, run-state transactions, and SQLite contention retries across existing runtime paths. Its scope is broader than a self-contained bug fix, particularly because it changes when scheduled work is suppressed, so human review is warranted.

You can add or adjust custom eligibility rules. Learn more.

github-actions Bot and others added 2 commits September 19, 2026 12:48
updateScheduledTask listed every task, merged a stale snapshot into a
full-row upsert, and wrote it back. Concurrent disjoint edits clobbered each
other, and an edit racing a delete could resurrect the task.

Add ScheduledTaskService.update: a scoped read plus a targeted column UPDATE
in one transaction. Only supplied fields are written, the UPDATE can never
insert, and a missing or cross-project task returns Option.none, which the
MCP layer maps to task_not_found. next_run_at is recomputed only when
schedule or enabled actually change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Run completion, stuck-run release, dispatch, and setEnabled each re-read the
task and then wrote in a separate statement, so an edit committed between the
two had its next_run_at overwritten from the older schedule, and a pause or
delete landing after the dispatch re-read could still fire.

Put each re-read and its write in one transaction with the contention retry,
and guard the missed-run reschedule on the next_run_at it was computed from.

Tests pin the due-read to dispatch gap (pause, postpone, delete, and the
no-edit case), an edit committed mid-run on the success and interrupted
paths, and a contended completion write retrying instead of stranding the
task as running.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@saphid
saphid force-pushed the work/pr11592-split-2-scheduler-writers branch from 7a96ce2 to a2a6ef7 Compare September 19, 2026 02:48
@juliusmarminge
juliusmarminge force-pushed the t3code/codex-turn-mapping branch 3 times, most recently from a1f8051 to 0337dd6 Compare September 21, 2026 05:40
@juliusmarminge

Copy link
Copy Markdown
Member

Closing. The current head of #11592 (f19067f3fc) re-absorbed this split, so the scheduler-writer transactions, retryContended, and the "pause committed after the due read" / "contended completion write retries" tests all live there now. I'd rather review #11592 as one PR than the same change in two shapes. If you would prefer to keep the split, drop the content from #11592 first and re-stack this on it.

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

Labels

size:L 100-499 changed lines (additions + deletions). 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.

8 participants