Skip to content

deploy: atomically claim and own pending Agent Runtime operations #76

Description

@benagentai93-dot

Summary

Agent Runtime deployment operation state in v1.3.1 is a non-atomic read/modify/write record without an owner token. Two CLI processes can both pass the pending-operation check, start remote mutations, and overwrite or clear each other's deployment_metadata.json state.

Baseline: 5a306f8956cb1eeae69f9709de0e4d61b44e11e7 (v1.3.1).

Reproduction

  1. In one agent project, start two agents-cli deploy --no-wait processes at the same time.
  2. Both read the metadata before either writes its pending operation.
  3. Observe that both may submit a remote create/update, while the last metadata write wins.
  4. Also simulate:
    • local SDK request-config construction failing before remote submission;
    • remote create/update submission raising with an unknown outcome;
    • a delayed status/cleanup process running after a newer operation replaced the record.

Actual behavior

  • More than one remote mutation can start.
  • One process can overwrite or clear another process's pending operation.
  • A crash between remote submission and operation-name persistence is not represented safely.
  • Failure cleanup cannot distinguish known pre-mutation failure from outcome-uncertain remote submission.

Expected behavior

  • Exactly one process owns the right to start a mutation.
  • Ownership spans target revalidation, remote submission, status recording, completion, and cleanup.
  • Local preparation failure restores prior metadata byte-for-byte.
  • Once remote submission or identity creation may have happened, retain a fail-closed starting claim for manual reconciliation.
  • A stale owner must never clear a replacement owner's record.
  • Successful completion should merge current sibling metadata and remove the owned claim in one atomic transition.

Minimal fix

Use a cross-process lock around metadata read/modify/write, add a random claim ID, claim before remote mutation, revalidate the selected Runtime while holding ownership, and make clear/finish operations owner-aware. Split local request preparation from remote submission so only errors proven to precede mutation restore the previous bytes.

Reference implementation and regressions: fork Batch 4 branch.

Verification evidence

  • Thread and subprocess races each produced exactly one owner and exactly one mutation.
  • Replacement-owner, legacy-operation, atomic-finish, and sibling-metadata regressions passed.
  • Local request-config failure: zero mutation, byte-identical restoration, retry claim succeeds.
  • Remote submit and identity-create outcome-uncertain failures retain state=starting.
  • Fresh targeted review: 35 tests passed; full local suite: 92 passed.
  • ruff check src tests, ty check src, build, and Python 3.11/3.13 installed-wheel smoke tests passed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions