Skip to content

I2700 — A lease probe asks a cheap liveness route, and a server holding another lease token is not taken for the leaseholder

Point the lease probe at a liveness route that answers without resolving the index and carries the repository id, the leaseholder and a digest of the lease token, and judge a process whose digest differs from the lease's not the leaseholder.

READY wave 1 · p1 · implementation profile · runs alone

Part of runtime-lifecycle — One usable server per checkout starts, attaches, stops and reports its state without races or hidden kills.

Ready. Every dependency is done, so majordomus plan start I2700 will be accepted.

Objective

Point the lease probe at a liveness route that answers without resolving the index and carries the repository id, the leaseholder and a digest of the lease token, and judge a process whose digest differs from the lease's not the leaseholder.

Why

Split from I2126 on 2026-10-14. I2126 delivered the busy-pool half (every request answered on a thread of its own up to MAX_HANDLERS) and its desired_state said 'Not done here' of the liveness probe route and the token check, while its acceptance criteria still required both, so it could never close. The probe still asks GET /, the most expensive route, and compares name, repository_id and leaseholder but not the lease token, pid or started_at, so another process answering GET / for the same repository is taken for the leaseholder. Baseline audit of 2026-10-09 at master 1fb8d6be44, the fencing row.

Current state

lease::ask (apps/majordomus-cli/src/lease.rs, behind lease::probe, lease::probe_reply and lease::probe_patiently) sends GET / and compares the index document's name, repository_id and leaseholder key. The lease document carries a token (apps/majordomus-cli/src/lease.rs, LeaseDocument.token) that no answer exposes. /api/v1/live and /api/v1/ready exist (apps/majordomus-cli/src/capability/builtin/health.rs) and the probe uses neither.

Desired state

The lease probe asks a liveness route that answers without resolving the index; the answer carries the repository id, whether the process holds the lease, and a digest of the lease token it holds, never the token itself; a probe that hears a digest other than that of the lease it read judges the answerer not the leaseholder. docs/MCP.md names the route and the comparison.

Scope

  • apps/majordomus-cli/src/lease.rs
  • apps/majordomus-cli/src/http/router.rs
  • apps/majordomus-cli/src/capability/builtin/health.rs
  • apps/majordomus-cli/tests/lease_busy.rs
  • test/cases
  • docs/MCP.md

Out of scope

  • How requests are handed to handler threads and MAX_HANDLERS, which I2126 delivered

Dependencies

Acceptance criteria

  • The lease probe asks a liveness route, not GET /, and the answer carries the repository id, leaseholder and a digest of the lease token
  • A process that answers the probe with a token digest other than the lease's is judged not the leaseholder

Validation

  • bin/majordomus plan validate
  • cargo test --test lease_busy --test mcp_shared

Evidence required

  • probe_compares_the_token_test

Evidence

None recorded. Every token above needs a command or an artifact behind it before this issue can be completed; narrative is refused.

Timeline

started
—
verified
—
completed
—

Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.

Canonical record: .ai/repo/project/issues/I2700.yaml. Read it back with majordomus plan show I2700.

Searches the titles and descriptions of every page this site publishes.