fix(concurrency): make lifecycle and durable state transitions ownership-safe — concurrent actors can corrupt state or act on reused identities - #766
Closed
unohee wants to merge 4 commits into
Conversation
This was referenced Sep 26, 2026
unohee
pushed a commit
that referenced
this pull request
Sep 28, 2026
…hip-safe Salvages the unique work of draft PRs #766 and #767 into one change. - fileLock: add withFileLockSync (Atomics wait) for sync RMW callers, with the ownership-safe stale reclaim and ENOTEMPTY-tolerant unlink; lock waits use the real timer so a test that fakes setTimeout cannot freeze lock hand-off. - pairPipeline: replace the per-instance abortSignal/stuckDetector with an AsyncLocalStorage RunControl, so concurrent run() calls on one instance cannot observe or overwrite each other's cancellation state. - processRegistry: taskId+spawnedAt identity ownership on activity, close and health-check, plus a SIGKILL escalation timer that is unref'd, cancelled on child close, and cleared by a force kill. - store: tryClaimTaskAdmission claims a task in one locked read-modify-write; stale-lock reclaim tolerates ENOTEMPTY; main's updateTaskLinearState lock invariant is preserved. - runnerState: cross-process locks on the rejection, decomposition, pace, project-selection and pipeline-history RMW paths; main's withRunnerStateLock and reserveDailyCreations are kept, and the daily reset runs outside the decomposition lock because withFileLockSync is not reentrant. - decisionEngine: admission claims on the auto-execute paths and an in_progress filter; file-locked engine state and backlog appends. - oauthStore, dev, logRotation, codex, reembed, taskParser, gitInfo, locale: the locked or scoped variant of the same invariant. Dropped: telemetry.ts (main has withTelemetryLock), workflow.ts (owned by another salvage), prProcessor.ts (its state lock cannot fit the repo's 1500-line gate, which main's copy already sits on), task_state_model.py, agt3420-probe.txt, and package.json/lock version churn.
unohee
pushed a commit
that referenced
this pull request
Sep 28, 2026
…hip-safe Salvages the unique work of draft PRs #766 and #767 into one change. - fileLock: add withFileLockSync (Atomics wait) for sync RMW callers, with the ownership-safe stale reclaim and ENOTEMPTY-tolerant unlink; lock waits use the real timer so a test that fakes setTimeout cannot freeze lock hand-off. - pairPipeline: replace the per-instance abortSignal/stuckDetector with an AsyncLocalStorage RunControl, so concurrent run() calls on one instance cannot observe or overwrite each other's cancellation state. - processRegistry: taskId+spawnedAt identity ownership on activity, close and health-check, plus a SIGKILL escalation timer that is unref'd, cancelled on child close, and cleared by a force kill. - store: tryClaimTaskAdmission claims a task in one locked read-modify-write; stale-lock reclaim tolerates ENOTEMPTY; main's updateTaskLinearState lock invariant is preserved. - runnerState: cross-process locks on the rejection, decomposition, pace, project-selection and pipeline-history RMW paths; main's withRunnerStateLock and reserveDailyCreations are kept, and the daily reset runs outside the decomposition lock because withFileLockSync is not reentrant. - decisionEngine: admission claims on the auto-execute paths and an in_progress filter; file-locked engine state and backlog appends. - oauthStore, dev, logRotation, codex, reembed, taskParser, gitInfo, locale: the locked or scoped variant of the same invariant. Dropped: telemetry.ts (main has withTelemetryLock), workflow.ts (owned by another salvage), prProcessor.ts (its state lock cannot fit the repo's 1500-line gate, which main's copy already sits on), task_state_model.py, agt3420-probe.txt, and package.json/lock version churn.
Collaborator
Author
|
Closing: superseded — the salvageable work in this draft was rebased onto current main, verified, and re-published as a reviewed PR: absorbed into #791 (salvage/concurrency-locking). Closing the stale draft instead of merging it, because it was 170-250 commits behind, carried scratch files, and (in several cases) reverted main's later hardening. |
unohee
deleted the
swarm/AGT-3430-fix-concurrency-make-lifecycle-and-durab
branch
September 28, 2026 07:02
unohee
pushed a commit
that referenced
this pull request
Sep 28, 2026
…hip-safe Salvages the worthwhile work from draft PRs #766 and #767 (both 'failed 4 times … very likely incomplete', 174-247 commits behind) into one change, rebased onto current main. Kept: unified withFileLockSync (Atomics.wait + ownership-safe reclaim + ENOTEMPTY tolerance); AsyncLocalStorage per-run RunControl in pairPipeline; processRegistry taskId/spawnedAt ownership + cancellable unref'd timer; taskState tryClaimTaskAdmission + ENOTEMPTY reclaim; decisionEngine admission claims + in_progress filter; taskParser zod schemas; cross-process locks in memoryCore/codex/reembed/runnerState; gitInfo enrichment now persists via graph.addNode+saveGraph; locale AsyncLocalStorage scope; oauthStore refresh serialized on a store lock with reload-under-lock. Also updates the duck-typed AuthProfileStore double in codexResponses.test.ts (reloadProfileFromDisk/setProfileUnlocked) so it implements the interface its declared collaborator now requires — the adapter's tests are the only caller that is not a real AuthProfileStore instance.
unohee
added a commit
that referenced
this pull request
Sep 28, 2026
…hip-safe (#766 + #767) (#791) * fix(concurrency): make lifecycle and durable state transitions ownership-safe Salvages the unique work of draft PRs #766 and #767 into one change. - fileLock: add withFileLockSync (Atomics wait) for sync RMW callers, with the ownership-safe stale reclaim and ENOTEMPTY-tolerant unlink; lock waits use the real timer so a test that fakes setTimeout cannot freeze lock hand-off. - pairPipeline: replace the per-instance abortSignal/stuckDetector with an AsyncLocalStorage RunControl, so concurrent run() calls on one instance cannot observe or overwrite each other's cancellation state. - processRegistry: taskId+spawnedAt identity ownership on activity, close and health-check, plus a SIGKILL escalation timer that is unref'd, cancelled on child close, and cleared by a force kill. - store: tryClaimTaskAdmission claims a task in one locked read-modify-write; stale-lock reclaim tolerates ENOTEMPTY; main's updateTaskLinearState lock invariant is preserved. - runnerState: cross-process locks on the rejection, decomposition, pace, project-selection and pipeline-history RMW paths; main's withRunnerStateLock and reserveDailyCreations are kept, and the daily reset runs outside the decomposition lock because withFileLockSync is not reentrant. - decisionEngine: admission claims on the auto-execute paths and an in_progress filter; file-locked engine state and backlog appends. - oauthStore, dev, logRotation, codex, reembed, taskParser, gitInfo, locale: the locked or scoped variant of the same invariant. Dropped: telemetry.ts (main has withTelemetryLock), workflow.ts (owned by another salvage), prProcessor.ts (its state lock cannot fit the repo's 1500-line gate, which main's copy already sits on), task_state_model.py, agt3420-probe.txt, and package.json/lock version churn. * fix(concurrency): make lifecycle and durable state transitions ownership-safe Salvages the worthwhile work from draft PRs #766 and #767 (both 'failed 4 times … very likely incomplete', 174-247 commits behind) into one change, rebased onto current main. Kept: unified withFileLockSync (Atomics.wait + ownership-safe reclaim + ENOTEMPTY tolerance); AsyncLocalStorage per-run RunControl in pairPipeline; processRegistry taskId/spawnedAt ownership + cancellable unref'd timer; taskState tryClaimTaskAdmission + ENOTEMPTY reclaim; decisionEngine admission claims + in_progress filter; taskParser zod schemas; cross-process locks in memoryCore/codex/reembed/runnerState; gitInfo enrichment now persists via graph.addNode+saveGraph; locale AsyncLocalStorage scope; oauthStore refresh serialized on a store lock with reload-under-lock. Also updates the duck-typed AuthProfileStore double in codexResponses.test.ts (reloadProfileFromDisk/setProfileUnlocked) so it implements the interface its declared collaborator now requires — the adapter's tests are the only caller that is not a real AuthProfileStore instance. --------- Co-authored-by: SalvageA <salvage@local>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Published because this run stopped and needs a human: autonomous execution failed 4 times
It has not been reviewed and is very likely incomplete — this PR is a draft on purpose. It exists so the work is reviewable instead of sitting on a branch that was never pushed.
Change shape
423 file(s): 212 source · 191 test · 3 docs · 17 other
Base freshness
Branch base is 171 commit(s) behind
mainat publication.⚠ Conflicts with
mainin:src/agents/pairPipeline.ts,src/agents/pairPipelineTypes.ts,src/automation/runnerState.ts,src/memory/memoryCore.ts,src/orchestration/workflow.ts,src/support/fileLock.ts,src/taskState/store.test.ts,src/telemetry/telemetry.tsGitHub runs no
pull_requestworkflows on a PR it cannot merge, so any green checks here are not the verification gate. Opened as a draft; rebase before review.This branch changes files that other open PRs / active branches also touch. Coordinate before merging to avoid divergent parallel edits (INT-2388 #3):
src/adapters/processRegistry.ts,src/support/dev.tssrc/automation/prProcessor.ts,src/automation/runnerState.ts,src/orchestration/workflow.ts,src/support/dev.ts,src/taskState/store.test.ts,src/taskState/store.tssrc/orchestration/workflow.ts,src/telemetry/telemetry.tssrc/support/fileLock.tssrc/memory/memoryCore.ts,src/orchestration/workflow.tssrc/automation/runnerState.ts,src/memory/memoryCore.ts,src/orchestration/workflow.ts,src/taskState/store.test.ts,src/taskState/store.ts,src/telemetry/telemetry.tssrc/agents/pairPipeline.tssrc/agents/pairPipeline.ts,src/agents/pairPipelineTypes.tssrc/agents/pairPipeline.ts,src/agents/pairPipelineTypes.tssrc/telemetry/telemetry.tssrc/telemetry/telemetry.tssrc/automation/prProcessor.tsLinear
Closes AGT-3430
🤖 Generated with OpenSwarm