A snapshot: read at commit 707a04c7ce8 on 2026-10-18T00:06:01Z by majordomus 0.29.0. Nothing on this page is read again. See it live
I2128
A lease is removed only by the process that holds it, and serve stop stops the server in order
Where it stands
devtask.issue- Readiness
- complete completion is recorded and every required evidence token is present
- Status
- DONE
- Can start
- not now
- Milestone
- Milestone status
- ACTIVE
- Wave
0- Waiting on
- none
- Holds back
- none
- Behind it in all
0- Evidence
3of3
Moves
plan.transitionWhat it is
- Objective
- Make every removal and every rewrite of the lease file conditional on the actor still holding it, and turn the SIGTERM that serve stop sends into the ordered stop the server already has.
- Why
- Three findings. The signal handler unlinks the lease whenever HELD is set and re-raises with SIG_DFL (apps/majordomus-cli/src/lease.rs:1164-1212, the unlink at 1197-1211), so between a takeover and the old owner's next 500 ms tick a SIGTERM to the old owner unlinks the new owner's lease. take_over reads, compares and then calls remove_file (apps/majordomus-cli/src/lease.rs:778-798) in three steps, so two electors that both judged one lease stale can interleave and the second unlinks the first's fresh lease; publish checks is_mine and then renames the fixed tmp name server.json.tmp (apps/majordomus-cli/src/lease.rs:1082-1107) with no fsync, so a takeover between the check and the rename is overwritten. serve stop sends SIGTERM (apps/majordomus-cli/src/commands/serve.rs:814,890-903) and SharedServer::stop (apps/majordomus-cli/src/shared.rs:282-289, closing episodes and draining the mesh) never runs; apps/majordomus-cli/tests/mcp_shared.rs::sigterm_removes_the_lease_before_the_process_dies asserts the process dies of signal 15, while the comment at apps/majordomus-cli/src/shared.rs:274-281 implies serve stop runs the ordered stop. Every serve stop leaves open episodes for recover_orphans and cuts in-flight answers. LeaseView.pid is documented as informational (apps/majordomus-cli/src/capability/builtin/server.rs:236) although liveness (apps/majordomus-cli/src/lease.rs:742), the spawn claim (apps/majordomus-cli/src/commands/serve.rs:354-356) and serve stop (apps/majordomus-cli/src/commands/serve.rs:814) decide from it. Baseline audit of 2026-10-09 at master 1fb8d6be44, lifecycle gaps 5 and 11, drift 5 and 6. Graceful termination of in-flight responses in the production container is I0906 (fly-deployment); this issue covers the lease and the episodes locally.
- Now
- Lease removal by the signal handler and by take_over does not re-check the token. serve stop is a hard kill that removes the lease first.
- Wanted
- The serve loop turns SIGTERM into a flag it polls, waits a bounded time for peers to leave and runs SharedServer::stop; only then is the lease released through the path that checks is_mine. take_over renames the stale file aside under its own token and confirms what it moved before claiming. publish writes a tmp file named for its token and syncs it before the rename. A second SIGTERM, or the bound passing, still ends the process.
- Done when
- unknown: the record declares no `completion`
- Risk
- unknown: the record declares no `risk`
Acceptance
- A SIGTERM to a server whose lease was taken over within the same tick leaves the new owner's lease file in place
- After serve stop, the stopped server's episodes are closed and recover_orphans finds none of them
- Two electors that both judged one lease stale end with exactly one lease, held by the process the file names
- The stopped process exits by its own return, not by signal 15, within serve stop's documented bound
- The comment at apps/majordomus-cli/src/shared.rs:274-281 and the LeaseView.pid doc describe what the code does
- Validation
bin/majordomus plan validatecargo test --test mcp_shared --test serve_lifecycle --test shared_unitsMJ_TEST_JOBS=4 bash test/run.sh 113_shared_server_survives_a_crash- Evidence required
sigterm_spares_a_successor_lease_testserve_stop_closes_episodes_testconcurrent_takeover_test- Evidence present
sigterm_spares_a_successor_lease_testserve_stop_closes_episodes_testconcurrent_takeover_test
Scope
- Touches
apps/majordomus-cli/src/lease.rsapps/majordomus-cli/src/shared.rsapps/majordomus-cli/src/commands/serve.rsapps/majordomus-cli/src/capability/builtin/server.rsapps/majordomus-cli/tests/mcp_shared.rsapps/majordomus-cli/tests/serve_lifecycle.rstest/casesdocs/MCP.md- Not
- unknown: the record declares no `non_scope`
- Depends on
- none
- Priority
- p1
- Profile
- implementation
- Parallel safe
- false
- Owner
- unknown: the record declares no `owner`
The work so far
- Branches
- none
- Merged
- none
- Commits
0- Trunk
- master
- Sessions
- none
- Created
- 2026-10-09
- Updated
- 2026-10-15T04:32:47Z
- Started
- 2026-10-15T04:32:23Z
- Verified
- 2026-10-15T04:32:30Z
- Completed
- 2026-10-15T04:32:47Z
Synchronisation
- Adapter
scripts/github-sync- Repository
- unknown: the derived plan's header carries no repository
- External issue
- unknown: a live GitHub state; this executable makes no network call, so only `scripts/github-sync --check` can answer it
- State there
- unknown: a live GitHub state; this executable makes no network call, so only `scripts/github-sync --check` can answer it
Findings
Nothing is wrong with these records.