Skip to content

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

An enrolled mesh node follows the stable release by itself through the one installer, forward only, activating in order and rolling back a failed activation (ADR 0161); a newer client replaces an older server in an ordered hand-off and an older client is told it is older; a change to any wire or on-disk schema needs a version bump; a released archive carries a provenance attestation the installer checks.

ACTIVE 3 of 11 issues done

ready
3
blocked
5
active
0
verify
0
done
3
cancelled
0

Problem

The pack assumes a self-updater and signed releases. Both premises are refuted. `majordomus update` regenerates provider projections from policy (lib/update.sh:4); there is no self-update command, and docs/DISTRIBUTION.md:416-439 says so; to upgrade, a person reruns install.sh with --version. Artifacts are checksummed, not signed: sha256 and size in releases/<tag>.json are checked by site/static/install.sh:478 (called at :706), and docs/DISTRIBUTION.md:151-153 defers signing on purpose. What exists is compatibility risk: the superseded check covers only a binary replaced at the same path (apps/majordomus-cli/src/lease.rs:695-709), while the installer uses one directory per version, so a new client attaches to an older server and only an Outdated warning records it (apps/majordomus-cli/src/capability/builtin/server.rs:410-424). version-surface prices the public surface only; mesh discovery and link versions (apps/majordomus-cli/src/mesh/protocol.rs:36-40, apps/majordomus-cli/src/mesh/link.rs:50-53), the lease schema and journal events are outside it. Measured in the runtime baseline audit of 2026-10-09 at master 1fb8d6be44 (plan/RUNTIME_BASELINE.md).

Outcome

An enrolled mesh node follows the stable release by itself through the one installer, forward only, activating in order and rolling back a failed activation (ADR 0161); a newer client replaces an older server in an ordered hand-off and an older client is told it is older; a change to any wire or on-disk schema needs a version bump; a released archive carries a provenance attestation the installer checks.

Current state

Implemented: install.sh verifies checksum and size, refuses traversal and non-HTTPS; release-verdict gates the release on CI; version-surface covers capabilities, routes, tools, commands and schemas; MCP protocol negotiation. Absent: a reader of the stable pointer on any node (every node is upgraded by hand), cross-path version hand-off, wire-schema pricing, a v1 advertisement fixture, provenance.

Desired state

The compatibility matrix in plan/RUNTIME_BASELINE.md lists adjacent client/server and mesh versions with a test for each pair, and docs/DISTRIBUTION.md states what each install path verifies. The owner decided on 2026-10-14 that a background update check is wanted (ADR 0161): every enrolled node follows releases/latest.json through self update, which re-runs install.sh, and the mesh shows each node's version (I2720-I2724).

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/release
  • apps/majordomus-cli/src/mesh/protocol.rs
  • apps/majordomus-cli/src/mesh/link.rs
  • scripts/ci/version-matches-surface
  • .github/workflows/release.yml
  • site/static/install.sh
  • test/fixtures
  • test/cases
  • docs/DISTRIBUTION.md
  • docs/MCP.md
  • docs/MESH.md
  • apps/majordomus-cli/src/mesh
  • .ai/repo/mesh/majordomus.yaml

Out of scope

  • A second installer or updater; install.sh stays the one path (pack M11), and self update re-runs it (ADR 0161).
  • A network fetch on entering a repository.
  • Restarting a client's server while it has work in flight; hand-off goes through I2127's session move.

Acceptance criteria

  • An enrolled, following node is on the version releases/latest.json names within one check interval of a release, with no person on it
  • A failed activation rolls back to the previous version by itself and the board names node, version and failed check
  • A client of version N+1 beside a server of version N at another path ends with one server of N+1 and no lost session
  • A wire or lease or journal schema change without a version bump fails version-surface
  • Each release archive carries an attestation that verifies for this repository

Validation

  • bin/majordomus plan validate
  • cargo test --test serve_lifecycle
  • MJ_TEST_JOBS=4 bash test/run.sh 85_installer 743_release_version_answers_with_the_contract

Evidence required

  • version_hand_off_test
  • wire_versions_gated
  • node_follows_stable_pointer_test
  • hub_rolls_back_failed_version_test
  • release_attestation

Risks

  • A hand-off between versions depends on the old server ending its sessions (I2127); landing I2163 first would strand clients on the old server.
  • Following automatically raises the cost of a bad archive; I2165 (attestation) is raised to p1 with ADR 0161.
  • Attestation needs repository permissions in the publish job; the release workflow's permissions block changes with it.

Issues

Each one is an execution contract with its own acceptance criteria, validation command and required evidence. The wave column is the layer of the dependency graph it sits in.

issuestatuswavedepends ontitle
I2163 DONE 1 I2127 A client never attaches to a server of another version without saying so, and a newer client replaces an older server
I2165 DONE 0 — A released archive carries a provenance attestation the installer can check
I2720 READY 0 — majordomus self update re-runs the published installer, and never reimplements it
I2721 BLOCKED 1 I2720 An enrolled mesh node follows the stable pointer by itself
I2722 BLOCKED 1 I2720 A hub activates a new version under its service manager, checks its health and rolls back by itself
I2723 READY 0 — The mesh shows each node's version and how far a release has rolled out
I2724 BLOCKED 1 I2720, I2165 A node without a route to the site takes the archive from a peer and still verifies it itself
I2826 READY 0 — A GitHub release carries the tool's own changelog for its tag, never GitHub's generated notes
I2829 DONE 0 — An alpha is published as a pre-release end to end, and never becomes the latest release anywhere
I3177 BLOCKED 1 I2723 Two nodes one release apart keep linking, and what the older cannot answer is shown unavailable
I3178 BLOCKED 2 I2720, I2722 A self update killed at any stage leaves a usable installation

The graph

safe-self-update dependency graphfrom .ai/repo/project
flowchart LR
    I2163["I2163<br/>A client never attaches to a server of another version without saying so, and a newer client replaces an older server"]:::done
    I2165["I2165<br/>A released archive carries a provenance attestation the installer can check"]:::done
    I2720["I2720<br/>majordomus self update re-runs the published installer, and never reimplements it"]:::ready
    I2721["I2721<br/>An enrolled mesh node follows the stable pointer by itself"]:::blocked
    I2722["I2722<br/>A hub activates a new version under its service manager, checks its health and rolls back by itself"]:::blocked
    I2723["I2723<br/>The mesh shows each node's version and how far a release has rolled out"]:::ready
    I2724["I2724<br/>A node without a route to the site takes the archive from a peer and still verifies it itself"]:::blocked
    I2826["I2826<br/>A GitHub release carries the tool's own changelog for its tag, never GitHub's generated notes"]:::ready
    I2829["I2829<br/>An alpha is published as a pre-release end to end, and never becomes the latest release anywhere"]:::done
    I3177["I3177<br/>Two nodes one release apart keep linking, and what the older cannot answer is shown unavailable"]:::blocked
    I3178["I3178<br/>A self update killed at any stage leaves a usable installation"]:::blocked
    I2165 --> I2724
    I2720 --> I2721
    I2720 --> I2722
    I2720 --> I2724
    I2720 --> I3178
    I2722 --> I3178
    I2723 --> I3177
    classDef done stroke:#16a34a,fill:#dcfce7,color:#14532d,stroke-width:2px
    classDef active stroke:#2563eb,fill:#eff6ff,color:#1e3a8a,stroke-width:2px
    classDef verify stroke:#7c3aed,fill:#f5f3ff,color:#4c1d95,stroke-width:2px
    classDef ready stroke:#0891b2,fill:#ecfeff,color:#164e63,stroke-width:2px
    classDef planned stroke:#0891b2,fill:#ecfeff,color:#164e63,stroke-width:2px
    classDef blocked stroke:#b45309,fill:#fffbeb,color:#78350f,stroke-width:2px
    classDef cancelled stroke:#6b7280,fill:#f9fafb,color:#374151,stroke-width:2px
    classDef superseded stroke:#6b7280,fill:#f9fafb,color:#374151,stroke-width:2px

Canonical record: .ai/repo/project/milestones/safe-self-update.yaml. Read it back with majordomus plan show safe-self-update.

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