Skip to content

I2163 — A client never attaches to a server of another version without saying so, and a newer client replaces an older server

Make the election compare versions through the one standing verdict: a newer client takes over in an ordered hand-off, an older client attaches and says it is older.

DONE wave 1 · p1 · implementation profile · runs alone

Part of safe-self-update — Every mesh node follows the published release by itself, versions meet safely, and a release's provenance can be checked.

Objective

Make the election compare versions through the one standing verdict: a newer client takes over in an ordered hand-off, an older client attaches and says it is older.

Why

lease::elect and ask compare name, repository_id and leaseholder, never the version (apps/majordomus-cli/src/lease.rs:896-920). The superseded check covers only a binary replaced at the same path (apps/majordomus-cli/src/lease.rs:695-709); the installer puts each version in its own directory under ~/.local/share/majordomus/versions/<v>/, so an upgrade changes the path and nothing is superseded. A new client then attaches to the older server, and the mismatch is reported only as an Outdated warning by server::standing_at (apps/majordomus-cli/src/capability/builtin/server.rs:410-424, apps/majordomus-cli/src/capability/builtin/health.rs:606), which MCP clients never see. docs/MCP.md:49 presents supersession as covering yesterday's code. Baseline audit of 2026-10-09 at master 1fb8d6be44, failure gap 3, premise 3 and drift 7.

Current state

After an upgrade through the installer, new clients are served by the old version until it idles out.

Desired state

ask treats a lease whose version differs from crate::VERSION through the verdict server::standing_at already gives: a newer client takes over in an ordered hand-off, the old server's sessions moving on as I2127 makes them; an older client attaches and reports the difference in its initialize answer; docs/MCP.md says what each case does.

Scope

  • apps/majordomus-cli/src/lease.rs
  • apps/majordomus-cli/src/capability/builtin/server.rs
  • apps/majordomus-cli/src/mcp/protocol.rs
  • apps/majordomus-cli/src/commands/serve.rs
  • apps/majordomus-cli/tests/serve_lifecycle.rs
  • test/cases
  • docs/MCP.md

Dependencies

Acceptance criteria

  • A client of version N+1 started beside a server of version N installed at another path ends with one server of N+1 and the old server's sessions re-attached
  • A client of version N-1 attaching to a server of version N reports the difference in its initialize answer
  • One function decides the version verdict for elect, serve ensure and server.status

Validation

  • bin/majordomus plan validate
  • cargo test --test serve_lifecycle --test server_status
  • MJ_TEST_JOBS=4 bash test/run.sh <the case this issue adds>

Evidence required

  • newer_client_replaces_older_server_test
  • older_client_told_test

Evidence

coverstypecommandresultat commit
newer_client_replaces_older_server_testcigh run view 38626102499 --log --job 116065669794 (validate on master e8505a431d, rust (3): cargo test --test serve_lifecycle)tests/serve_lifecycle.rs newer_client_replaces_older_server_test ... ok and an_older_client_leaves_a_newer_server_alone_and_says_so ... ok in validate run 38626102499 (success) at e8505a431d; delivered by 383309ae06cc0e3585
older_client_told_testcigh run view 38626102499 --log --job 116065669775 (validate on master e8505a431d, rust (2): cargo test --lib)commands::mcp::tests::older_client_told_test ... ok in validate run 38626102499 (success) at e8505a431d; delivered by 383309ae06cc0e3585

Timeline

started
2026-10-14T22:14:26Z
verified
2026-10-14T22:14:44Z
completed
2026-10-14T22:15:01Z

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/I2163.yaml. Read it back with majordomus plan show I2163.

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