# Local Fleet Lifecycle Transitions

FCM-M3-001 uses the roster-v2 `lifecycle.enabled` and `lifecycle.desired_state` fields as the only desired-state authority. Systemd, tmux, generated environment files, and heartbeats are derived or observed state.

| Command                           | Desired-state write | Runtime effect                                                                                                             | Preconditions                                                                                                             |
| --------------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `fleet apply` / `fleet reconcile` | Never               | Rebuilds projections, then starts only enabled agents desired `running`; stops disabled or desired-`stopped` roster agents | Current generation; private managed paths; valid projections; proven holder ownership; no unmanaged named-socket sessions |
| `fleet start <name>`              | Never               | One-shot exact `mosaic-agent@<name>.service` start                                                                         | Current generation; exact enabled roster name; proven ownership                                                           |
| `fleet stop <name>`               | Never               | One-shot exact service stop                                                                                                | Current generation; exact roster name; proven ownership                                                                   |
| `fleet restart <name>`            | Never               | One-shot exact service restart                                                                                             | Current generation; exact roster name; proven ownership                                                                   |

A stopped roster agent is never started by `apply` or `reconcile`. Direct lifecycle commands are explicit one-shot actions and do not change persisted desired state. Use roster CRUD with the explicit persisted-start option to change that desired state.

All mutations require `--expected-generation <n>` and acquire one private roster-adjacent reconciliation lock before projection or lifecycle effects. Missing or stale generations and concurrent writers fail before effects; the lock is released after success, partial failure, or thrown lifecycle failure. Stale, ownership, unmanaged-session, unsupported-runtime, path, projection, and lifecycle-precondition failures return stable redacted JSON errors and a non-zero exit. No command targets a fuzzy tmux name, arbitrary socket, arbitrary command, channel, secret, or generated file as authority.
