Skip to content

Serialise integration with the repository lock

Anything that moves or undoes a lane of a repository (replaying an attempt's commits and fast-forwarding the lane, or rolling an attempt back and removing its worktree) must run under the repository's integration lock. The warden and the tribunal dev graphs (dev.work.exec, the land graph) take this one lock, so they never interleave on the same repository.

Python
from axm_git.core.lock import RepositoryLockTimeoutError, repository_lock

try:
    with repository_lock(worktree_path, timeout=300.0) as lock_file:
        ...  # replay, fast-forward or roll back
except RepositoryLockTimeoutError:
    ...  # another integrator kept the lock past the timeout
Symbol Contract
repository_lock(repo_path, *, timeout) Context manager; waits at most timeout seconds (0 tries once), yields the lock file's Path
repository_lock_path(repo_path) The lock file of the repository holding repo_path, None outside git
RepositoryLockTimeoutError Subclass of TimeoutError, raised when the wait runs out
INTEGRATION_LOCK_NAME "axm-integration.lock"

repository_lock raises ValueError when repo_path is not inside a git repository. The symbols are also re-exported from axm_git.core.

The protocol

The lock is an advisory exclusive flock(2) on axm-integration.lock inside the repository's common git directory (git rev-parse --path-format=absolute --git-common-dir):

  • every worktree of one repository resolves to the same file, so they contend;
  • distinct repositories never contend;
  • the kernel releases the lock when its holder exits, so a crashed holder leaves no stale lock behind (the file itself stays, harmlessly);
  • it is not re-entrant: taking it again from the same process while held times out, so hold it once around the whole critical section.

Any process, in any language, that takes an exclusive flock on that file excludes and is excluded by repository_lock. The file name is part of the protocol: renaming it requires migrating every holder at once.