Allow exact-owner renewal of expired author issue locks #760
Closed
opened 2026-07-19 11:51:08 -05:00 by jcwalker3
·
9 comments
No Branch/Tag Specified
master
fix/issue-987-native-mcp-bootstrap
feat/issue-985-project-scoped-launcher-identity
fix/issue-983-cross-repo-base-ref
feat/issue-980-stale-worker-retirement
fix/issue-975-client-identity-heartbeat
fix/issue-973-cross-repo-canonical-roots
fix/issue-970-safely-resolve-missing-worktrees
fix/issue-969-native-mcp-bootstrap
feat/issue-664-break-glass-restart
feat/issue-708-mcp-namespace-attachment
feat/issue-665-restart-audit
fix/issue-700-durable-walls
fix/issue-704-prevent-env-workspace-bindings
feat/issue-707-cross-project-boundaries
fix/issue-690-review-profile-switch-guard
fix/issue-953-bootstrap-lock-provenance
feat/issue-949-native-fleet-inventory
fix/issue-943-runtime-context-helpers
fix/issue-945-owning-pr-renewal-evidence
fix/issue-941-scope-guard-bootstrap-wiring
docs/issue-930-remote-mcp-coupling-inventory
fix/issue-892-author-bootstrap-deadlock
fix/issue-686-detect-reject-manual-mcp
fix/issue-672-mcp-config-drift
fix/issue-689-deterministic-mcp-namespace
feat/issue-666-concurrent-mcp-restart-tests
feat/issue-659-maintenance-drain-mode
feat/issue-648-notifications-console
fix/issue-670-direct-master-incident
feat/issue-644-console-recovery
feat/issue-650-providers-insights
feat/issue-669-scoped-component-recovery
docs/issue-668-mcp-ha-rolling-restart
feat/issue-667-console-restart-controls
feat/issue-645-linkage-console
feat/issue-643-request-preview-initiate
fix/issue-897-permission-stale-runtime-classification
feat/issue-641-runtime-session-view
feat/issue-663-restart-classes
feat/issue-661-drain-proof-hard-gate
fix/issue-854-semantic-container-exclusion
issue-640
fix/issue-682-starlette-httpx2
v1.1.0
Labels
Clear labels
allocator
anti-stomp
architecture
bug
chore
codex
concurrency
contamination
control-plane
dashboard
database
design
documentation
enhancement
gitea
glitchtip
important
incident
incident-bridge
integration
jenkins
labels
leases
mcp
mcp-health
mcp-menu
multi-project
mutating
nice-to-have
observability
portability
preflight
protected-branch
queue
read-only
reconnect
recovery
refactor
release
reliability
resumable-review
reviewer
roadmap
safety
security
self-hosted
sentry
stale-runtime
status:blocked
status:in-progress
status:pr-open
status:ready
terminal-lock
testing
tracker
type:bug
type:feature
type:feature
type:guardrail
visibility
workflow
workflow-hardening
workflow-hardening
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
Controller-owned work allocator
Prevent concurrent LLM session stomping
Architecture / structural design
OpenAI Codex client / workflow session surface
Concurrent session safety
Workflow or session contamination incident
MCP control-plane coordination and allocation authority
MCP operational dashboard/queue view
Internal coordination storage (SQLite/Postgres)
Design / investigation, no implementation
Docs / runbooks
New feature or improvement
Gitea MCP workflow
GlitchTip integration
Operational or process incident requiring durable audit trail
Sentry-to-Gitea incident bridging
Integration testing
Jenkins integration
Label taxonomy management
Lease adopt/release/expire lifecycle
MCP server / tooling
MCP namespace and runtime health
MCP menu surface
Work spanning multiple monitoring projects or Gitea repos
Mutating action; requires gating
Observability, metrics, traces, error reporting
Cross-platform / portability
Shared preflight gates before mutation
Protected branch / stable-branch policy concern
Work queue visibility and allocation
Read-only, no mutation
MCP client reconnect/reload recovery path
Recovery paths for stale/foreign leases
Code refactor / restructure
Release / versioning
Reliability / failure handling
Persist and resume prepared review verdicts across sessions
Reviewer workflow tooling
Roadmap / umbrella issue
Safety rails and fail-closed mutation guards
Security / trust boundary
Self-hosted infrastructure integration
Sentry error monitoring integration
Stale backend daemon / runtime-vs-master parity failures
Issue is blocked
Issue is being worked on
Issue has an open pull request
Issue is ready for work
Terminal review lock (#332) path
Tests / test coverage
Issue tracker hygiene / meta
Bug or defect
Feature or enhancement
Feature or enhancement
Safety gate or guardrail
Workflow state visibility for LLMs/operators
Cross-tool workflow
LLM workflow coordination hardening
LLM workflow coordination hardening
Something is not working
This issue or pull request already exists
New feature
Need some help
Something is wrong
More information is needed
This won't be fixed
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Scaled-Tech-Consulting/Gitea-Tools#760
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
An expired file-store author issue lock cannot be renewed by its exact owner when the recorded PID remains alive and the worktree still exists.
Because the PID represents a persistent MCP daemon rather than the individual author task, daemon liveness is not proof that task ownership remains active. The expired-lock path treats same-owner continuation as a foreign takeover and returns before exact ownership is considered.
Verified against master
bde5c5fb20fbf6aec9cd6b802341c43078921d13.Observed production state
Issue #757 was a historical instance of the expired-plus-live-daemon condition. It is not reproduced live at the time of filing, and this issue does not claim that it is.
Durable lock record for #757, read from
~/.cache/gitea-tools/issue-locks/prgs-Scaled-Tech-Consulting-Gitea-Tools-757.json:Corroborating repository state, all verified:
adc61255b2d7eb65d1670e09e561dbd84b652317;last_heartbeat_atequalscreated_at, so the lease was never renewed across a multi-hour authoring task;Why this instance no longer demonstrates the defect
Recorded PID
3543has since exited.kill -0 3543reports no such process, and the live MCP daemon cohorts carry unrelated PIDs.With a dead PID the reclaim gate now permits recovery:
deadbecomes true, the fail-closed return is skipped,assess_expired_lock_reclaimreturnsreclaim_allowed=true, andassess_same_issue_lease_conflictreturnsNone. Issue #757 is therefore recoverable today through the existing dead-PID path and is filed here as evidence of the condition, not as a live reproduction.What remains proven
The expired-plus-live-PID same-owner renewal gap is proven by production code inspection and by the absence of any test covering it. Nothing in the source grants renewal to an exact owner whose lease expired while its recording daemon stayed alive, and no regression asserts that behavior in either direction. Because the recorded PID is the long-lived MCP daemon, a live PID at expiry is the ordinary case for any author task that outlives the four-hour TTL — the condition will recur.
Root cause
Gate ordering
assess_same_issue_lease_conflict(issue_lock_store.py:436) computes same-owner evidence before it consults it:issue_lock_store.py:461-464—same_owneris computed from the locked branch and the realpath-normalized worktree.issue_lock_store.py:465— the expired-lease branch is entered.issue_lock_store.py:466-470— onreclaim_allowed, returnsNone.issue_lock_store.py:471-475— otherwise returns the "Recovery review is required before takeover (fail closed)" error.issue_lock_store.py:476— thesame_ownerallowance. Unreachable whenever the lease is expired, because both preceding paths return.assess_expired_lock_reclaim(issue_lock_store.py:379) permits reclaim only on dead PID or missing worktree (issue_lock_store.py:404-420, gate at:410). An exact owner whose daemon is alive and whose worktree is present satisfies neither, so it takes the fail-closed return and never reaches line 476.Why the lease expires under an active task
session_pidandpidare bound fromos.getpid()atissue_lock_store.py:170-171and:174, recording the persistent MCP daemon rather than the individual author task. The session pointer path also embeds that PID (issue_lock_store.py:73).Expiry is computed once at creation —
gitea_mcp_server.py:2016-2027, withWORK_LEASE_TTL_HOURS = 4atgitea_mcp_server.py:1913— from the single call site atgitea_mcp_server.py:3398. No renewal writer exists for this store.gitea_post_heartbeat(gitea_mcp_server.py:15481) does not reference the file store,work_lease, orexpires_at.gitea_heartbeat_reviewer_pr_lease(gitea_mcp_server.py:12297) renews a reviewer PR comment lease, a different substrate. Once wall-clock passesexpires_at,assess_lock_freshness(issue_lock_store.py:340-355) reports the lock non-live no matter how active the owning task is.Two distinct substrates
File-store author locks are JSON on disk (
issue_lock_store.py:34,:59,:117,:129). Control-plane workflow leases are SQLite (control_plane_db.py:23,:44,:254;lease_lifecycle.py:31).gitea_adopt_workflow_lease(gitea_mcp_server.py:18313),gitea_release_workflow_lease(:18368), andgitea_reclaim_expired_workflow_lease(:18488) all delegate tolease_lifecycle, which never importsissue_lock_store. Those tools cannot clear, refresh, or overwrite a file-store issue lock.The only writer is blocked
gitea_lock_issueis the sole native writer of the file store:gitea_mcp_server.py:3428calls_save_issue_lock(:1982,:1993), which callsbind_session_lock, which performs the writes atissue_lock_store.py:197-198. It is refused by the expired conflict at two points — the pre-check atgitea_mcp_server.py:3215-3223and again under the exclusive file lock atissue_lock_store.py:189-196— before reaching the write.Downstream,
verify_lock_for_mutation(issue_lock_store.py:565, call sitegitea_mcp_server.py:3628) requires a live lock atissue_lock_store.py:577-579, so no author mutation can proceed.Related but separately owned
assess_lock_freshness(issue_lock_store.py:340-355) has two independent non-live triggers: expired-by-time and dead-PID. Line 465 gates the reclaim assessor on expiry alone, so the two triggers have symmetric but opposite gaps. The dead-PID-under-unexpired-lease side is documented atissue_lock_recovery.py:12-14and is owned by #753; it is not re-owned here.Verify current line numbers during implementation rather than treating reported locations as immutable.
Safety impact
Acceptance criteria
AC1. Distinguish exact-owner renewal from foreign takeover.
AC2. Evaluate a strengthened same-owner renewal disposition before the expired foreign-takeover return.
AC3. Renewal requires exact match of: remote; owner; repository; issue number; operation type; branch; realpath-normalized worktree; claimant username; claimant profile.
AC4. The registered worktree must exist and be clean.
AC5. Local branch head must equal the remote branch head.
AC6. When an owning PR exists, local head, remote branch head, and live PR head must all match.
AC7. No competing live lock, competing branch claim, or other owning PR may exist.
AC8. Any missing or contradictory evidence fails closed.
AC9. Successful renewal atomically records: prior PID; replacement PID; prior expiry; renewal timestamp; new expiry; claimant and evidence provenance.
AC10. The renewed lock must immediately satisfy the existing downstream
verify_lock_for_mutationpath.AC11. Foreign expired-lock takeover continues to require the existing dead-PID or missing-worktree recovery conditions.
AC12. A live foreign lease remains non-recoverable.
AC13. Renewal is available through a native sanctioned tool path; no JSON edit, daemon restart, fabricated worktree, or direct API/CLI mutation is required.
AC14. Do not expose a caller-controlled boolean that declares ownership or renewal eligibility.
AC15. Tests cover: expired plus alive PID plus present clean worktree plus exact owner, renewal allowed; different branch refused; different worktree refused; different claimant or profile refused; dirty worktree refused; local and remote head mismatch refused; PR-head mismatch refused; competing lock, branch, or PR refused; live foreign lease refused; existing dead-PID reclaim unchanged; renewed lock satisfies downstream mutation ownership.
AC16. Add an explicit regression proving an MCP daemon PID remaining alive is not sufficient evidence of an active author task after lease expiry.
AC17. Do not special-case #757, PR #759, or any repository issue number.
Validation expectations
gitea_lock_issue, not only against the assessor functions.Linkage and ownership boundary
assess_expired_lock_reclaim. The component being corrected.Canonical issue state
Implementation sequencing with Issue #790
Issue #760 must not be implemented concurrently with Issue #790 without an explicit integration plan. Both may modify the same ownership and lease surfaces:
issue_lock_store.assess_same_issue_lease_conflictis_lease_expired(...)toward shared liveness and heartbeat semantics.Issue-lock expiry and freshness behavior
Before allocating implementation, choose one sequence:
Do not allocate #760 and #790 concurrently to separate authors unless their code boundaries and final integration order are explicitly coordinated.
Canonical Issue State
STATE: awaiting-sequencing-decision
WHO_IS_NEXT: controller
NEXT_ACTION: Choose and record the #760/#790 implementation order before allocating either issue.
NEXT_PROMPT:
WHY: Both issues modify overlapping issue-lock conflict assessment and expiry/freshness behavior. Concurrent implementation without an integration order risks textual and semantic conflicts.
BLOCKERS: Allocation is blocked only until the controller records the sequencing decision.
VALIDATION: Issues #760 and #790 are open; #790 has status:ready; overlapping implementation surfaces were verified; no implementation has been allocated.
Ledger correction — supersedes comment 13871
Corrects the
VALIDATIONfield only. The sequencing analysis and every other field in comment 13871 stand unchanged; this comment is the authoritative ledger for Issue #760.Prior wording asserted
status:readyfor #790 alone. Both issues carry it, verified live at the time of this comment.Canonical Issue State
STATE: awaiting-sequencing-decision
WHO_IS_NEXT: controller
NEXT_ACTION: Choose and record the #760/#790 implementation order before allocating either issue.
NEXT_PROMPT:
WHY: Both issues modify overlapping issue-lock conflict assessment and expiry/freshness behavior. Concurrent implementation without an integration order risks textual and semantic conflicts.
BLOCKERS: Allocation is blocked only until the controller records the sequencing decision.
VALIDATION: Issues #760 and #790 are open; both #760 and #790 have status:ready; overlapping implementation surfaces were verified; no implementation has been allocated.
Sequencing decision: Issue #760 lands first
The controller has selected the implementation order:
This resolves the sequencing decision previously recorded in comments 13871 and 13875.
Canonical Issue State
STATE: ready-for-allocation
WHO_IS_NEXT: controller
NEXT_ACTION: Allocate Issue #760 for implementation before Issue #790.
NEXT_PROMPT:
WHY: Issue #760 provides the narrower exact-owner renewal behavior on which the broader shared-heartbeat work in #790 should be based.
BLOCKERS: None for allocating Issue #760. Issue #790 remains sequenced behind it.
VALIDATION: Issues #760 and #790 are open and both have status:ready; the controller selected #760 to land first; no implementation was allocated by this comment.
Allocation ledger — Issue #760 allocated for implementation
Per the sequencing decision in comment 13877, Issue #760 is now allocated. Issue #790 remains sequenced behind it and was not touched.
Allocated artifacts:
fix/issue-760-exact-owner-renewal, cut fromprgs/masterat3d0c13fa5a756ff94441dc57cf4e74318f45ba41/Users/jasonwalker/Development/Gitea-Tools/branches/fix-issue-760-exact-owner-renewal(registered, clean, dedicated to #760)adoption_decision: NO_MATCH, competing branch checkclear)author_issue_work, acquired2026-07-22T04:19:08Z, expires2026-07-22T08:19:08Z, owner PID alive, freshnessliveObservation worth recording for #790: this lease was minted with the same fixed four-hour TTL and no heartbeat renewal that #790 exists to correct. It is the current sanctioned behavior, not a defect in this allocation.
Canonical Issue State
STATE: allocated-for-implementation
WHO_IS_NEXT: author
NEXT_ACTION: Implement Issue #760 in the allocated branch and worktree.
NEXT_PROMPT:
WHY: The controller selected #760 to land before #790.
BLOCKERS: None. No conflicting lock, branch, worktree, claim, linked PR, or live owner existed for #760 at allocation time.
VALIDATION: Author issue-work lock verified live for issue 760 on branch fix/issue-760-exact-owner-renewal from worktree /Users/jasonwalker/Development/Gitea-Tools/branches/fix-issue-760-exact-owner-renewal; identity jcwalker3, profile prgs-author, role author; repository binding Scaled-Tech-Consulting/Gitea-Tools on prgs; runtime/master parity healthy and in parity at 3d0c13fa5a756ff94441dc57cf4e74318f45ba41; worktree registered, on the expected branch, and clean; Issue #790 confirmed unlocked, unbranched, and unallocated.
Author handoff — Issue #760 implementation complete, PR #791 open
Implemented under the allocation recorded in comment 13881. Exact-owner renewal of an expired author issue lease now has a sanctioned path; foreign takeover, live-lease, and dead-PID dispositions are unchanged.
Canonical Issue State
STATE: implementation-complete
WHO_IS_NEXT: reviewer
NEXT_ACTION: Review the new PR for complete Issue #760 acceptance-criteria coverage.
NEXT_PROMPT:
WHAT_HAPPENED: Added the pure assessor issue_lock_renewal.py; issue_lock_store now carries a server-computed renewal_sanctioned waiver evaluated ahead of the expired foreign-takeover return; gitea_mcp_server gathers the evidence server-side, records a durable lease_renewal block, and covers the write with the existing compare-and-swap. 40 new tests were added and two test doubles in the #772 suite now forward the new keyword.
WHY: Issue #760 was implemented first according to the recorded sequencing decision.
RELATED_PRS: #791 (open, head
1a97ced133, base master, closes this issue)BLOCKERS: None for review. Issue #790 remains blocked behind this PR landing, by design.
VALIDATION: Commit and PR head
1a97ced133, pushed to prgs and confirmed by git ls-remote; PR #791 open against base master, mergeable, author jcwalker3. Tests run with venv/bin/python -m pytest from the allocated worktree: new suite tests/test_issue_760_exact_owner_lease_renewal.py 40 passed; lock and lease regression set 240 passed with 2 subtests passed; full suite 4230 passed, 11 failed, 6 skipped, 493 subtests passed, where all 11 failures reproduce identically on master at3d0c13faand none touch lease, lock-conflict, or renewal code. Branch fix/issue-760-exact-owner-renewal and worktree /Users/jasonwalker/Development/Gitea-Tools/branches/fix-issue-760-exact-owner-renewal verified registered, on the expected branch, and clean; the stable control checkout stayed on master at3d0c13faand clean throughout. Issue lock for 760 live and non-reclaimable, owner jcwalker3 / prgs-author, PID alive, lease acquired 2026-07-22T04:19:08Z and expiring 2026-07-22T08:19:08Z. Identity jcwalker3, profile prgs-author, role author, binding Scaled-Tech-Consulting/Gitea-Tools on prgs; runtime and master parity in parity at3d0c13fa5abefore each mutation. Issue #790 confirmed unlocked, unbranched, unallocated, and unmodified.LAST_UPDATED_BY: jcwalker3 / prgs-author (author session)
Author handoff — review #499 remediated, PR #791 at a new head
Both blocking findings from review #499 are fixed. Review #499 is now stale solely because of this push; it is undismissed and remains in the audit history.
F1 — the renewal waiver now survives downstream gates.
assess_issue_lock_worktreegains arenewal_sanctionedparameter that waives base-equivalence on the same grounds asrecovery_sanctioned, andgitea_lock_issuepasses it. Cleanliness is evaluated before the waiver and is never relaxed; the assessment reports which waiver applied. Writing the MCP-level regression then exposed a second discard point the review had not reached: the duplicate-work gate rejected renewals with "open PR already covers issue" — the very PR the lock being renewed owns. Addedowning_pr_renewal_evidence, the mirror of #755'sowning_pr_recovery_evidence, carried into that gate only when renewal was granted, re-checking that PR, local, and remote heads agree.F2 — MCP-level regression added.
tests/test_issue_760_mcp_renewal_path.py, 10 cases driving nativegitea_lock_issueagainst a real git repository and a real durable lock: expired lease, live recorded PID, committed non-base-equivalent branch.Neither waiver is caller-supplied and
gitea_lock_issuestill gains no parameter. Absolute wall-clock expiry unchanged. No #790 behavior introduced; #753 recovery untouched. F3 and F4 were left alone as non-blocking, except where the duplicate-gate fix was strictly required for F1 to work.Canonical Issue State
STATE: implementation-complete
WHO_IS_NEXT: reviewer
NEXT_ACTION: Re-review PR #791 at its new head
a30a3ce4c3.NEXT_PROMPT:
WHAT_HAPPENED: Remediated review #499. Threaded renewal_sanctioned into assess_issue_lock_worktree and its call site, added owning_pr_renewal_evidence so the duplicate-work gate does not reject a renewal on the PR it already owns, and added a 10-case MCP-level regression driving native gitea_lock_issue through a sanctioned renewal plus its negative companions.
WHY: The renewal waiver was computed and then discarded at two later gates, so exact-owner renewal was unreachable end to end, and no MCP-level regression existed to catch it.
ISSUE: #760
RELATED_PRS: #791 (open, previous head
1a97ced133reviewed by #499, new heada30a3ce4c3)BLOCKERS: None outstanding. Both review #499 blocking findings are remediated; the non-blocking F3 and F4 remain open by design.
VALIDATION: New commit
a30a3ce4c3pushed to prgs and confirmed by git ls-remote; PR #791 current_head_sha readsa30a3ce4c3, state open, base master. Review #499 now reports dismissed false, stale true, author_pushed_after_request_changes true, so it is stale only because of this push and stays in the audit history. Tests from the allocated author worktree: new MCP suite tests/test_issue_760_mcp_renewal_path.py 10 passed; both Issue #760 suites together 50 passed; lock and lease regression set 200 passed with 2 subtests passed; full suite 4240 passed, 11 failed, 6 skipped, 493 subtests passed, run with tracebacks suppressed so no environment values printed. The 11 failures are the same node IDs as the master baseline at3d0c13faand 4240 passed reflects exactly the 10 added cases, so no new failures were introduced. Author worktree clean on fix/issue-760-exact-owner-renewal at a30a3ce4; stable control checkout untouched on master at3d0c13faand clean; reviewer worktree untouched at1a97ced1and clean. Issue #760 author lock live and non-reclaimable, owner jcwalker3 / prgs-author, PID 39849 alive, lease expiring 2026-07-22T08:19:08Z. Issue #790 confirmed unlocked, unbranched, unallocated, and unmodified.LAST_UPDATED_BY: jcwalker3 / prgs-author (author session)
[THREAD STATE LEDGER] Issue #760 / PR #791 — merge commit
620ed6e9a9landed on prgs/masterWhat is true now:
gitea_merge_pr; merge result: PR #791 merged via 'merge'. Merge commit620ed6e9a9550b8da2ceb82d9ab8744e8920490f. PR #791 state is closed with merged_at 2026-07-22T01:02:40-05:00. Issue #760 state is closed, closed automatically through the PR's "Closes #760" reference.fix/issue-760-exact-owner-renewalis untouched ata30a3ce4c37b2dde725301bef8b9ef8e04160088. The stable control checkout stayed on master and clean.a30a3ce4c37b2dde725301bef8b9ef8e04160088— approval_visible=true, approval_at_current_head=true, latest_approved_head_sha equals the current head, has_blocking_change_requests=false, review_feedback_stale=false, quarantined_approvals_at_current_head=0. Review #500 carries the APPROVE review verdict recorded via the review API, with dismissed=false and stale=false. Review #499 (REQUEST_CHANGES at prior head1a97ced133fbb16a560ea4c3bf71b97b7401950c) is preserved in audit history with its full body intact and quarantined=false; its dismissed flag was set server-side by the superseding approval, not by any tool call.gitea_assess_pr_sync_statusreturned recommended_next_action merge_now with commits_behind=0, mergeable=true, has_conflicts=false, approval_valid_for_merge=true, stale_approval=false, checks_required=false and checks_status not_required. Read-after-write:git ls-remote prgs refs/heads/masterreports620ed6e9a9550b8da2ceb82d9ab8744e8920490f.What changed:
620ed6e9a9550b8da2ceb82d9ab8744e8920490fusing the repository's canonical merge method (merge), pinned with expected_head_shaa30a3ce4c37b2dde725301bef8b9ef8e04160088.status:pr-openlabel was retired from Issue #760 at merge time and verified residual-free (labels_after: mcp, recovery, reliability, safety, type:bug, workflow-hardening).58066-cf14e86f060e, pinned to the exact approved head.What is blocked:
Who/what acts next:
fix/issue-760-exact-owner-renewal, the reviewer worktreebranches/review-pr791-issue-760, or the baseline worktreebranches/baseline-master-pr791from this session — post-merge lease finalization and branch/worktree cleanup both require the prgs-reconciler role and fail closed for a merger.Canonical Issue State
STATE: merged
WHO_IS_NEXT: controller
APPROVAL: review #500 by sysadmin (prgs-reviewer)
APPROVED_HEAD:
a30a3ce4c3MERGE_COMMIT:
620ed6e9a9NEXT_ACTION: Reassess Issue #790 against the merged #760 behavior before allocation.
NEXT_PROMPT:
WHAT_HAPPENED: A merger session verified every pre-merge gate at head
a30a3ce4c3, could not adopt the reviewer lease because it had expired, acquired a sanctioned merger lease pinned to that exact head through the documented recovery path, and performed the merge of PR #791 into master through native MCP, producing merge commit620ed6e9a9and closing Issue #760 through the PR's closing reference.WHY: PR #791 carried a valid APPROVE review verdict at the exact current head with approval_at_current_head=true and no blocking change request, was conflict-free and mergeable with no required status checks, and gitea_assess_pr_sync_status routed it directly to the sanctioned merger workflow with merge_now.
RELATED_PRS: #791 (implements AC1-AC17 for this issue; merge commit
620ed6e9a9on master). Issue #790 remains open and deliberately sequenced behind this work, untouched by this session.BLOCKERS: None. Residual non-blocking follow-ups belong to the reconciler and the controller: the moot merger lease on PR #791, author branch and worktree cleanup, and the three non-blocking review notes carried forward from review #500 (F3 duplicated evidence gathering with both waivers grantable at once, F4 contention diagnostics regression, and the owning_pr_renewal_evidence negative-case coverage gap).
VALIDATION: Merger identity sysadmin, profile prgs-merger, role merger, independent from PR author jcwalker3; session bound to Scaled-Tech-Consulting/Gitea-Tools on prgs at gitea.prgs.cc. Canonical workflow loaded from skills/llm-project-workflow/workflows/review-merge-pr.md hash 263d0a6cb8a6, boundary clean. Runtime and master parity in parity at
3d0c13fa5awith restart_required=false. MCP namespace gitea-merger proven healthy through the live client namespace for gitea_merge_pr with blocks_merge_workflow=false. Pre-merge state at heada30a3ce4c3: PR open, base master, mergeable=true, approval_at_current_head=true, has_blocking_change_requests=false, review #500 dismissed=false and stale=false, review #499 preserved with quarantined=false, sync status merge_now, commits_behind=0, checks_required=false. The reviewer lease from session 7835-d4bf525741c2 had expired at 2026-07-22T05:37:14Z, so gitea_adopt_merger_pr_lease failed closed with "no active reviewer lease on PR #791 to adopt" and posted nothing; the documented recovery path for an expired reviewer lease, gitea_acquire_merger_pr_lease, was then used and returned lease session 58066-cf14e86f060e at comment 13938 pinned to the approved head. The live head was re-confirmed unchanged immediately before the merge. Merge performed with confirmation "MERGE PR 791", expected_head_shaa30a3ce4c3, method merge; lease_proof_sanctioned=true with lease_proof_kind sanctioned_acquire_merger. Read-after-write: PR #791 state closed, merged_at 2026-07-22T01:02:40-05:00, merge_commit_sha 620ed6e9a9550b8da2ceb82d9ab8744e8920490f; git ls-remote reports prgs/master at that same SHA; Issue #760 state closed with status:pr-open retired and verified residual-free; review #500 still visible and attributable to heada30a3ce4c3with no blocking review remaining. A read-only gitea_cleanup_post_merge_moot_lease dry run reports lease_moot=true and cleanup_allowed=true, with required_role_kind reconciler, so the merger did not finalize it. No file was edited, no branch created, pushed, rebased, amended, or deleted, and no worktree was removed by this session. Issue #790 was not started, locked, branched, commented on, or otherwise mutated.LAST_UPDATED_BY: sysadmin / prgs-merger (merger session)
[THREAD STATE LEDGER] Issue #760 / PR #791 — post-merge reconciliation pass; worktrees cleared, source branch retained under live author ownership
What is true now:
620ed6e9a9550b8da2ceb82d9ab8744e8920490flanded on prgs/master, verified bygit ls-remote prgs refs/heads/master. Its two parents are exactly3d0c13fa5a756ff94441dc57cf4e74318f45ba41(prior master) anda30a3ce4c37b2dde725301bef8b9ef8e04160088(the reviewed source head), andgit merge-base --is-ancestor a30a3ce4 620ed6e9returns true. Issue #760 state is closed. Completion comment 13947 re-read in full and is consistent with live state.gitea_cleanup_post_merge_moot_leaseread-only dry run on PR #791 with expected_session_id58066-cf14e86f060e, expected_candidate_heada30a3ce4c37b2dde725301bef8b9ef8e04160088and expected_lease_comment_id13938returns lease_moot=false, cleanup_allowed=false, active_lease=null, and a reason stating that PR #791 is already in its terminal post-merge closed state and that "no active reviewer lease remains; nothing to clean". The merger lease from comment 13938 carried expires_at 2026-07-22T06:11:51Z and had lapsed by the 06:22:16Z assessment, so no terminal released marker was warranted and none was posted. Runtime identity sysadmin, profile prgs-reconciler, role reconciler, bound to Scaled-Tech-Consulting/Gitea-Tools on prgs; server-implementation parity in_parity=true at3d0c13fa5a756ff94441dc57cf4e74318f45ba41with restart_required=false; the stable control checkout stayed on master at that commit and clean throughout.What changed:
branches/review-pr791-issue-760(detached ata30a3ce4, zero-entrygit status --porcelain, no process holding it) removed viagit worktree remove.branches/baseline-master-pr791(detached at3d0c13fa, zero-entrygit status --porcelain, no process holding it) removed viagit worktree remove.branches/reconcile-pr791created detached at620ed6e9, becausegitea_cleanup_merged_pr_branchfails closed on a root-checkout invocation and requires an explicitbranches/worktree path. It is clean and retained so the deferred branch deletion can be retried without repeating this step.What is blocked:
fix/issue-760-exact-owner-renewal(remote heada30a3ce4c37b2dde725301bef8b9ef8e04160088, fully contained in master) is deferred.gitea_cleanup_merged_pr_branchassessed safe_to_delete=true with an empty block_reasons list, then failed closed with blocker_kindactive_branch_ownershipand blocking_categoriesauthor_lease,author_session,worktree_binding. Cause: the durable author lock~/.cache/gitea-tools/issue-locks/prgs-Scaled-Tech-Consulting-Gitea-Tools-760.jsoncarries work_lease.expires_at2026-07-22T08:19:08Z, still live by wall clock, with recorded pid 39849 which is an MCP daemon process that remains alive, and worktreebranches/fix-issue-760-exact-owner-renewalstill checked out on that branch. This is precisely the daemon-liveness condition Issue #760 documents. A reconciler may not clear it: no hand-editing of the lock file, no author namespace, no worktree removal while the lease is live.2026-07-22T08:19:08Z, after which the lease lapses, the author worktree may be removed, and the deletion may be re-run frombranches/reconcile-pr791.Who/what acts next:
620ed6e9a9550b8da2ceb82d9ab8744e8920490f.branches/fix-issue-760-exact-owner-renewalwhile its lease is live. Do not delete branchfix/issue-760-exact-owner-renewaloutside the sanctioned reconciler path.Canonical Issue State
STATE: closed-with-residual-cleanup
WHO_IS_NEXT: controller
MERGE_COMMIT:
620ed6e9a9APPROVED_HEAD:
a30a3ce4c3NEXT_ACTION: Reassess Issue #790 against the landed renewal behavior, and schedule the deferred source-branch deletion after the author lease lapses at 2026-07-22T08:19:08Z.
NEXT_PROMPT:
WHAT_HAPPENED: A prgs-reconciler session verified identity, binding, namespace health and parity, re-read PR #791, Issue #760 and completion comment 13947, confirmed the merge commit's parentage against the reviewed source head, assessed the outstanding merger lease read-only, removed the two clean detached session worktrees for this PR, and attempted the sanctioned source-branch deletion, which failed closed on live author branch ownership.
WHY: The merger lease had already lapsed by wall clock, so the sanctioned cleanup tool reported nothing to clean and no marker was appropriate; the two session worktrees were provably clean, contained and unowned, while the source branch remains protected by a live author lease, a live recorded daemon pid, and a bound worktree.
ISSUE: #760
RELATED_PRS: #791 (closed, merge commit
620ed6e9a9, source head a30a3ce4c37b2dde725301bef8b9ef8e04160088; source branch retained pending lease expiry). Issue #790 remains open and untouched by this session.BLOCKERS: Source-branch deletion deferred behind the live Issue #760 author work_lease expiring 2026-07-22T08:19:08Z; blocker classification queue/lease blocker. No other residual item.
VALIDATION: Identity sysadmin, profile prgs-reconciler, role reconciler, session bound to Scaled-Tech-Consulting/Gitea-Tools on prgs at gitea.prgs.cc; workflow load proof present with boundary clean; server-implementation parity in_parity true at
3d0c13fa5awith stale false and restart_required false. PR #791 read live: state closed, merged_at 2026-07-22T01:02:40-05:00, merge_commit_sha620ed6e9a9, base master, head branch fix/issue-760-exact-owner-renewal. Merge commit parents read locally as3d0c13fa5aanda30a3ce4c3, and git merge-base --is-ancestora30a3ce4620ed6e9returns true. Issue #760 read live: state closed, labels mcp, recovery, reliability, safety, type:bug, workflow-hardening, with no residual status:pr-open. git ls-remote prgs reports master at620ed6e9a9and fix/issue-760-exact-owner-renewal ata30a3ce4c3. gitea_cleanup_post_merge_moot_lease dry run returned lease_moot false, cleanup_allowed false, active_lease null; apply was never invoked. Preflight order gitea_whoami then gitea_resolve_task_capability(cleanup_merged_pr_branch) with nothing in between preceded each deletion attempt; capability resolved allowed_in_current_session true for gitea.branch.delete. Both removed worktrees reported zero porcelain entries and no owning process immediately before removal. Issue #790 was not opened for allocation, locked, branched, labelled, or commented on.LAST_UPDATED_BY: sysadmin / prgs-reconciler (reconciler session)
[THREAD STATE LEDGER] Issue #760 / PR #791 — deferred cleanup re-attempted; author lease has NOT yet lapsed, source branch still retained
Supersedes the residual-cleanup status in comment 13952. The retry window recorded there has not opened.
What is true now:
620ed6e9a9550b8da2ceb82d9ab8744e8920490f, base master, head branchfix/issue-760-exact-owner-renewal. Issue #760 state is closed; labels mcp, recovery, reliability, safety, type:bug, workflow-hardening, with no residualstatus:pr-open. Completion comment 13947 and reconciliation comment 13952 were re-read in full and remain consistent with live state.620ed6e9a9550b8da2ceb82d9ab8744e8920490fwith a zero-entrygit status --porcelainthroughout.git ls-remote prgsreports master at620ed6e9a9550b8da2ceb82d9ab8744e8920490fandfix/issue-760-exact-owner-renewalata30a3ce4c37b2dde725301bef8b9ef8e04160088. Merge commit parents read locally as3d0c13fa5a756ff94441dc57cf4e74318f45ba41anda30a3ce4c37b2dde725301bef8b9ef8e04160088;git merge-base --is-ancestor a30a3ce4 620ed6e9returns true, as does the same check for the superseded head1a97ced1. No control-plane lease row exists for issue 760 or PR 791 in either direction;gitea_list_workflow_leaseswith include_non_active returned 14 rows, none for work_number 760 or 791. No live PR #791 lease remains.What changed:
branches/review-fix-issue-760-exact-owner-renewal(detached at1a97ced133fbb16a560ea4c3bf71b97b7401950c, zero-entry porcelain, no owning process, head contained in master, classifieddetached_review_leftoverwith removable true) was removed viagit worktree remove. This is a different path from thebranches/review-pr791-issue-760worktree removed in comment 13952; both existed.gitea_capture_branches_worktree_snapshotreconcile exactly: branch directory count 51 to 50, registered branches worktrees 44 to 43, removed set is exactly that one path, added set empty, and no classification or head-SHA drift on any retained entry.What is blocked:
fix/issue-760-exact-owner-renewaland removal of author worktreebranches/fix-issue-760-exact-owner-renewalremain deferred. The durable author lock~/.cache/gitea-tools/issue-locks/prgs-Scaled-Tech-Consulting-Gitea-Tools-760.jsoncarrieswork_lease.expires_at2026-07-22T08:19:08Z. Wall clock at assessment was2026-07-22T06:39:43Z, so the lease is still live with roughly 1 hour 39 minutes remaining. It was neither renewed nor replaced:lock_generationis still 1,created_atandlast_heartbeat_atare both2026-07-22T04:19:08Z, claimant is still jcwalker3 / prgs-author, and recorded pid 39849 is unchanged and still alive as the long-lived MCP daemon started 2026-07-21 23:22:08 local.gitea_cleanup_merged_pr_branchwas deliberately NOT invoked in this pass; the read-only audit on its own proves the call would fail closed onactive_branch_ownership.gitea_audit_worktree_cleanupindependently classifies the author worktreeactive_issue_workwith removable false and preserve true, despite it being clean, on the locked branch, and fully contained in master.2026-07-22T08:19:08Z. Ownership must be re-verified at that time rather than assumed lapsed.Who/what acts next:
branches/fix-issue-760-exact-owner-renewalor deletefix/issue-760-exact-owner-renewalwhile the lease is live. Do not removebranches/reconcile-pr791; it is retained on purpose as the invocation point for the deferred deletion, becausegitea_cleanup_merged_pr_branchfails closed on a root-checkout invocation.Canonical Issue State
STATE: closed-with-residual-cleanup
WHO_IS_NEXT: controller
MERGE_COMMIT:
620ed6e9a9APPROVED_HEAD:
a30a3ce4c3NEXT_ACTION: After 2026-07-22T08:19:08Z, re-verify that the Issue #760 author lease actually lapsed and was not renewed, then complete the deferred source-branch and author-worktree cleanup.
NEXT_PROMPT:
WHAT_HAPPENED: A prgs-reconciler session verified identity, binding, namespace health and runtime/master parity, re-read PR #791, Issue #760 and comments 13947 and 13952, re-verified the merge commit and its parentage, confirmed no control-plane lease and no live PR #791 lease exist, and found the author issue lock still live and unrenewed with roughly 1 hour 39 minutes remaining. It removed one provably obsolete reviewer worktree and stopped short of every artifact protected by the live lease.
WHY: The retry window recorded in comment 13952 opens at 2026-07-22T08:19:08Z and had not yet opened at 2026-07-22T06:39:43Z, so the source branch and author worktree remain under live, unrenewed author ownership and cannot be cleaned through any sanctioned path.
ISSUE: #760
RELATED_PRS: #791 (state closed, merge commit
620ed6e9a9, source head a30a3ce4c37b2dde725301bef8b9ef8e04160088; source branch retained under live author lease). Issue #790 remains open and untouched by this session.BLOCKERS: Source-branch deletion and author-worktree removal deferred behind the live Issue #760 author work_lease expiring 2026-07-22T08:19:08Z; blocker classification queue/lease blocker. No other residual item.
VALIDATION: Identity sysadmin, profile prgs-reconciler, role reconciler, bound to Scaled-Tech-Consulting/Gitea-Tools on prgs at gitea.prgs.cc, identity_match true. Server-implementation parity in_parity true at
620ed6e9a9with stale false and restart_required false; runtime checkout on master, clean, workspace_roots_aligned true. MCP namespace gitea-reconciler proven healthy through the live client namespace for gitea_cleanup_merged_pr_branch with blocks_merge_workflow false. PR #791 read live in the closed post-merge state and Issue #760 read live in the closed state. git ls-remote prgs read after all local work: master620ed6e9a9, fix/issue-760-exact-owner-renewala30a3ce4c3. Local branch fix/issue-760-exact-owner-renewal still present ata30a3ce4. Author lock read directly from disk and unchanged from the values recorded in comment 13881; recorded pid 39849 confirmed alive via kill -0. lsof reported no process holding any of the three PR #791 worktree paths. Worktree snapshots before and after reconcile with a single explained removal and no drift. Preflight order gitea_whoami then gitea_resolve_task_capability with task comment_issue and nothing in between preceded this comment; allowed_in_current_session true. Issue #790 was read once read-only and confirmed to be in the open state with its label set unchanged; it was not locked, branched, labelled, commented on, or otherwise mutated.LAST_UPDATED_BY: sysadmin / prgs-reconciler (reconciler session)