Add own-branch lock adoption / recovery path to gitea_lock_issue #442

Closed
opened 2026-07-07 12:39:16 -05:00 by jcwalker3 · 2 comments
Owner

Problem

gitea_lock_issue cannot reacquire an issue lock once the issue's own branch is already pushed. The branch-existence check (gitea_mcp_server.py, the already has matching branch guard) treats any remote branch containing issue-<n> as duplicate competing work (#400) and fails closed — including the issue's own intended branch.

This creates a recovery deadlock: if the in-memory issue lock is lost (e.g. MCP server restart) after the branch was pushed but before the PR was created, there is no non-destructive way to reacquire the lock. gitea_create_pr requires a live lock, gitea_lock_issue refuses because the branch exists, and the only remaining paths are destructive (delete/recreate the branch) or unsafe (hand-forge the shared lock file, which the safety layer correctly refuses).

Observed live on issue #420 / branch feat/issue-420-server-code-parity @ 934688a: branch valid and tested, no PR, issue open + status:in-progress, but PR creation blocked solely by the lock-reacquire refusal.

Distinct from #438 (atomic lock storage / concurrent-session clobbering): this is about recognizing an issue's own branch as adoptable rather than competing.

Required behavior

  1. If an existing remote branch matches the requested issue and exactly equals the requested branch_name, do not treat it as duplicate competing work — adopt it for lock reacquisition.
  2. Adoption is allowed only when all safety checks pass:
    • requested issue number matches the branch issue marker
    • requested branch_name exactly equals the existing remote branch name
    • no open PR already exists for that branch/issue
    • no live competing lock exists for a different branch/session
    • current profile has exact lock/acquire capability
    • current workspace/worktree is valid under the branches-only guard
  3. Continue to fail closed for:
    • a different branch name that merely contains the same issue number
    • another actor/session's competing branch
    • an existing open PR for that issue/branch
    • missing or ambiguous branch-ownership proof
    • a stale or invalid worktree path
  4. The adoption path must return clear proof: issue number, branch name, branch head commit, adoption reason, no-existing-PR proof, no-competing-live-lock proof, and lock file path/status.
  5. Normal #400 duplicate-work protection must remain intact for real competing branches.

Tests required

  1. Existing exact branch for same issue can be adopted.
  2. Existing different branch for same issue remains blocked.
  3. Existing open PR blocks adoption.
  4. Competing live lock blocks adoption.
  5. Missing/invalid worktree blocks adoption.
  6. Adoption result includes proof fields.
  7. Existing #400 duplicate-work behavior remains fail-closed for non-adoption cases.
  8. gitea_create_pr can proceed after a successful adopted lock (unit level).

Related

  • #438 — shared lock atomicity / concurrent-session clobbering (complementary; does not cover own-branch adoption).
  • Surfaced during recovery of #420 (feat/issue-420-server-code-parity). This fix must not modify or delete that branch.
## Problem `gitea_lock_issue` cannot reacquire an issue lock once the issue's own branch is already pushed. The branch-existence check (`gitea_mcp_server.py`, the `already has matching branch` guard) treats **any** remote branch containing `issue-<n>` as duplicate competing work (#400) and fails closed — including the issue's own intended branch. This creates a recovery deadlock: if the in-memory issue lock is lost (e.g. MCP server restart) **after** the branch was pushed but **before** the PR was created, there is no non-destructive way to reacquire the lock. `gitea_create_pr` requires a live lock, `gitea_lock_issue` refuses because the branch exists, and the only remaining paths are destructive (delete/recreate the branch) or unsafe (hand-forge the shared lock file, which the safety layer correctly refuses). Observed live on issue #420 / branch `feat/issue-420-server-code-parity @ 934688a`: branch valid and tested, no PR, issue open + `status:in-progress`, but PR creation blocked solely by the lock-reacquire refusal. Distinct from #438 (atomic lock storage / concurrent-session clobbering): this is about recognizing an issue's **own** branch as adoptable rather than competing. ## Required behavior 1. If an existing remote branch matches the requested issue **and** exactly equals the requested `branch_name`, do not treat it as duplicate competing work — adopt it for lock reacquisition. 2. Adoption is allowed only when all safety checks pass: * requested issue number matches the branch issue marker * requested `branch_name` exactly equals the existing remote branch name * no open PR already exists for that branch/issue * no live competing lock exists for a different branch/session * current profile has exact lock/acquire capability * current workspace/worktree is valid under the branches-only guard 3. Continue to fail closed for: * a different branch name that merely contains the same issue number * another actor/session's competing branch * an existing open PR for that issue/branch * missing or ambiguous branch-ownership proof * a stale or invalid worktree path 4. The adoption path must return clear proof: issue number, branch name, branch head commit, adoption reason, no-existing-PR proof, no-competing-live-lock proof, and lock file path/status. 5. Normal #400 duplicate-work protection must remain intact for real competing branches. ## Tests required 1. Existing exact branch for same issue can be adopted. 2. Existing different branch for same issue remains blocked. 3. Existing open PR blocks adoption. 4. Competing live lock blocks adoption. 5. Missing/invalid worktree blocks adoption. 6. Adoption result includes proof fields. 7. Existing #400 duplicate-work behavior remains fail-closed for non-adoption cases. 8. `gitea_create_pr` can proceed after a successful adopted lock (unit level). ## Related * #438 — shared lock atomicity / concurrent-session clobbering (complementary; does not cover own-branch adoption). * Surfaced during recovery of #420 (`feat/issue-420-server-code-parity`). This fix must not modify or delete that branch.
jcwalker3 added the status:in-progress label 2026-07-07 12:39:42 -05:00
Author
Owner

Issue claim heartbeat

<!-- gitea-issue-claim-heartbeat:v1 --> **Issue claim heartbeat** - kind: claim - issue: #442 - branch: feat/issue-442-lock-adoption - phase: claimed - profile: prgs-author - pr: none - blocker: none - next_action: create worktree and begin implementation
Author
Owner

Related enforcement wall filed as #447: own-branch recovery should be the sanctioned path, while manual /tmp/gitea_issue_lock.json seeding must be blocked/reported.

Related enforcement wall filed as #447: own-branch recovery should be the sanctioned path, while manual `/tmp/gitea_issue_lock.json` seeding must be blocked/reported.
sysadmin removed the status:in-progress label 2026-07-07 17:16:35 -05:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Scaled-Tech-Consulting/Gitea-Tools#442