fix(actas): recover abandoned reclaim mutexes safely - #522
Open
yui-stingray wants to merge 2 commits into
Open
Conversation
yui-stingray
marked this pull request as ready for review
July 29, 2026 00:01
6 tasks
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
Replace the abandoned
.reclaim.dcleanup proposed in #68 with a crash-safe,fail-closed serialization protocol for actas lock deletion.
The original age-based cleanup is not safe: a live mutator can be paused past
any threshold, and a delayed collector can remove a newly-created directory at
the same pathname. This change therefore never age-deletes a legacy marker.
What changed
(lock_key, holder_pid, 128-bit holder_generation).exact lock state, and ends with
exec rm, so killing the helper cannot leavean untracked destructive child running after its mutex appears stale.
mutation protocol.
current. A paused live holder is never timed out.
on the normal free-claim path.
live-held, and infrastructure/reclaim errors; they never subscribe or write
role affinity after a failed claim.
prevents cleanup, callers report
rollback=incompletewith the exactpercent-encoded retained pairs instead of deleting without serialization or
claiming an atomic group rollback.
.reclaim.dmarkers in SessionStart and document the safetransition: stop/restart every old mutator, validate each affected empty
marker, remove only that marker manually, then retry.
run/directory;relative, trailing-slash, and symlinked installation spellings converge on
the same mutex key.
Scope and follow-up
This is a same-user concurrency-correctness primitive, not a security boundary
against arbitrary hostile same-UID filesystem/database mutation.
It intentionally does not add a per-claim generation to the actas record.
Same-owner successor fencing and the complete generation-bearing compare/delete
contract remain in #519. That follow-up can build on this mutex helper without
changing the #68 rollout boundary.
Because this replaces rather than implements #68's age-based acceptance text,
maintainer agreement on the recovery and rollout contract is requested before
merge. It addresses #68 but does not auto-close it.
Validation
despawn, Claude template): 163/163 passed
git diff --check: passedNo CI/workflow file is changed. The existing Windows job does not execute this
actas suite, so native Git Bash
exec/PID and SQLite path behavior remains aplatform validation gap; I have left workflow changes out of this PR.
Rollout and rollback
have sourced the old mkdir-based mutator.
.reclaim.dmarker based on age. Remove only a reported,validated empty marker after all old mutators are stopped.
run/actas-reclaim.dbwhile a helper may be active.the runtime DB unless its rows have been verified inactive.
Addresses #68. Related: #65, #519.