EssayArticle / 001

What a Safe Update Costs

Why atomic updates are never free, and why Chartreuse chooses informed generations over a second package substrate.

The previous post said Chartreuse would resume here. The last essay about the distribution described its requirements. This one asks what existing systems charge for meeting the update requirement.

Every distribution described as immutable, transactional, or atomic is answering the same question: how can a running system change without making the running system the test environment for that change?

The available answers are serious, and several work very well. The useful distinction is not which one provides safety. It is what else must be accepted in order to obtain it.

The ostree family, including Fedora Silverblue and CoreOS, charges in the unit of change. The operating system becomes a versioned deployment. An update creates another deployment, and rollback selects the previous one. This is a strong model, especially across fleets, because the machine can move between known system trees rather than mutating itself package by package.

The price is that the deployment becomes the center of the system. Package installation becomes layering over that deployment, local modification becomes a special case with its own vocabulary, and the surrounding architecture reflects the needs of image-oriented management. None of this is a defect. It is a coherent answer to the problem these systems chose. It is simply a large amount of model to accept when the requirement is safe change on one workstation.

openSUSE MicroOS charges differently. It retains a conventional package manager and uses Btrfs snapshots, applying updates inside a new snapshot before the machine boots into it. This is much closer to the ordinary workstation model, and the storage mechanism provides a real path back when an update fails.

The remaining weakness is not reversibility, but explanation. The rollback decision is still centered on snapshots: identifiers, timestamps, and the operator's memory of when the system was last healthy. Those facts can help locate a target, but they do not by themselves describe the cumulative package and service consequences of selecting it. The machine can go backward. It does not first explain, in system terms, what backward means.

NixOS and Guix charge the most, and return the most. Their declarative configurations, isolated stores, and retained generations provide a degree of reproducibility and rollback that conventional package systems do not. When the inputs are fixed, the resulting system can be accounted for as a value rather than reconstructed from the history of changes made to a live root.

The price is the substrate itself. The user adopts a store that conventional software does not expect, an evaluation language, a service or module model, and a package universe adapted to those assumptions. For someone managing reproducible systems across many machines, this may be the correct trade. For one hardened workstation, it means that the answer to safe package installation begins by replacing the usual meaning of a package and much of the system around it.

Void represents the conventional base. XBPS is fast, coherent, and pleasant to operate, and it can plan and apply package transactions cleanly. Those transactions still change the active root, however, and XBPS does not turn the complete system into retained, bootable generations. When an upgrade damages the machine, recovery depends on backups, manual repair, or whatever additional snapshot discipline the operator created outside the package manager.

The package manager is not the problem. The missing system-level transaction boundary is.

Placed together, these models reveal an unoccupied seam among the projects above. It is possible to want a conventional package manager because most software is built for one; an inactive root for package operations because the live system should not be the test environment; rollback described in package and service terms because reverting a workstation is a decision that deserves evidence; and an init layer whose supervision and policy remain separately inspectable.

The ostree family provides strong deployments but makes the deployment the primary unit. MicroOS keeps conventional packages and snapshots, but the rollback decision remains centered on snapshot identity. NixOS and Guix provide the strongest account of generations by adopting a different substrate. Void keeps the conventional substrate without providing system generations around it.

Chartreuse is being built in that seam.

XBPS remains the only package system. Supported package operations occur inside a Btrfs snapshot through a chroot rather than against the running root. A successful transaction becomes a numbered generation, and the generation receives structured metadata recording the package changes, the relevant service-definition changes, and whether that state was later confirmed healthy. The bootloader exposes retained generations as labeled entries, allowing a machine that cannot boot the newest state to select an earlier one without first repairing the failed system.

The metadata is the point. A snapshot can preserve bytes without explaining them. Chartreuse treats the explanation as part of the transaction.

Before a rollback is applied, the tooling derives the cumulative change between the current generation and the selected target. It states which packages will be removed, which will be downgraded and to what version, which service definitions will return, and whether the target was ever confirmed healthy. The target may be any retained generation, not only the one immediately before the current state.

The user is therefore not approving a timestamp. The user is approving a described system change.

This does not provide what NixOS or Guix provides. A manifest records declared intent, but it is not a content-addressed definition of the complete result, and two machines applying the same intent at different times may diverge. That gap is accepted. Closing it would require adopting much of the second substrate Chartreuse is deliberately avoiding.

The trade is narrower: retain the conventional package model, move supported changes off the live root, and make every retained state explainable before it is selected. For a single workstation, this is the balance Chartreuse is attempting to hold.

A safe update is never free. Chartreuse pays for it in metadata, validation, retained generations, and maintenance work rather than in a second package universe. That is the cost it chooses.

The next post concerns the other half of the seam: why Chartreuse uses s6, and what a distribution must build around an init system that refuses to become the whole system.