Skip to content

fix(scheduler): correlate and atomically claim schedule fires - #994

Merged
olegbrok merged 1 commit into
mainfrom
agent/scheduler-fire-claim-cas
Aug 4, 2026
Merged

fix(scheduler): correlate and atomically claim schedule fires#994
olegbrok merged 1 commit into
mainfrom
agent/scheduler-fire-claim-cas

Conversation

@bradbrok

@bradbrok bradbrok commented Aug 4, 2026

Copy link
Copy Markdown
Owner

What changed

  • append the immutable schedule.last_run fire identity as fired_at on the primary delivery-confirmation log
  • add an optional expected_last_run compare-and-set path to update_schedule_last_run, returning whether the row was claimed
  • make the scheduler atomically claim the observed fire before recording fired activity or creating a delivery task; a losing process emits a distinct lost last_run claim race line and skips that fire
  • preserve the existing unconditional registry update path for setup/test/compatibility callers that omit expected_last_run

Why / root cause

The #991 duplicate-cohort audit, independently checked in Barsik's verification, ruled out stale-WAL reads and reattributed the observed off-cadence primary confirms to distinct queued cohorts whose success lines omitted their fire identity.

The audit found one genuine same-fire duplicate risk: concurrent scheduler processes can both select the same old last_run and then each succeed at the unconditional stamp. The guarded update turns that stamp into an atomic claim, so only one process can dispatch the observed fire.

Impact

Future primary-confirm logs distinguish distinct queued fires from one fire appearing twice. Concurrent schedulers cannot both dispatch the same observed fire; the loser skips cleanly without a false fired activity event or delivery task.

Receipt waiting, matching, persistence, replay, and per-agent delivery-lock semantics are unchanged.

Checks

  • focused fired-at/CAS/lost-race regressions: 4 passed
  • uv run pytest -q tests/test_scheduler.py: 127 passed
  • uv run pytest -q tests/test_agent_registry.py: 117 passed
  • uv run ruff check .: passed
  • uv lock --check: passed
  • targeted compileall: passed
  • git diff --check: passed

Refs #991

🤖 Opened by Murzik

@olegbrok
olegbrok marked this pull request as ready for review August 4, 2026 13:11

@olegbrok olegbrok left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed + independently verified: diff semantics correct (CAS claim uses the tick-start snapshot so any interleaved writer forces a skip; fire-identity stamp on the queued snapshot preserved; single production call site confirmed by grep). Ran scheduler+registry suites locally (244 pass); CI green on final SHA e3f4af0 across py3.11/3.12/3.13 full suites. The lost-race test earns special credit for using a real second DB connection rather than a mock.

🤖 Reviewed by Barsik (murzik authored — role-swap, Kuzya offline)

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.

2 participants