OS Rollback & A/B Root — transactional userspace live-update

The rollback-capable transactional-root mechanism that kodix-RFC-002 (§Decision, §Migration) deferred to "kodix-RFC-003 when written", now also framed by the owner-declared full-live-system objective (#081): the userspace/image half (#082) of "update ANY component with zero physical reboot". Scores three A/B-root candidates — btrfs subvolume snapshots, systemd-sysupdate A/B partitions, ostree/bootc — against RFC-002's five criteria plus reuse-first. Recommended path: **btrfs subvolume A/B (snapshot → atomic default-switch → healthcheck → rollback)**, because Kodix root is already btrfs (#068/#070), so it needs no FS reorg (unlike ostree's `/usr` rdonly) and no doubled root partitions (unlike sysupdate, which also fights the #070 raid1-split layout). FINAL adoption is gated on RFC-002's measurement gate (≥3 months of v0 apt failure-rate telemetry) + owner sign-off — recommendation now, ratification on data (D12: no decision on an unmeasured premise).

Version: 0.1.0 — Draft Status: Proposed (2026-06-04) Owner: Koder Kodix WG (infra/linux/kodix) Discussion tickets: infra/linux/kodix #082 (userspace half), #081 (umbrella)

Abstract

kodix-RFC-002 shipped OS updates v0 as apt-only over Koder Hub (koder-os-update, #018 DONE) and explicitly deferred the rollback story: *"Defer the rollback story to v1+ as a separate RFC that picks between A/B partitions … and ostree … (see kodix-RFC-003-os-rollback when written)"*. This is that RFC. It is also the userspace/image half (#082) of the owner-declared full-live-system objective (#081) — "update ANY component, incl. kernel, with zero physical reboot". A/B root is therefore not merely a rollback nicety: it is the transactional substrate that lets the OS image itself be replaced atomically and rolled back without a re-flash, the userspace complement to the kernel live-update half (#078#079#080).

Relationship to prior decisions (don't re-litigate)

  • RFC-002 stands. v0 apt-only is the transport for routine package

    upgrades and is not replaced. This RFC adds the *transactional-root + rollback* layer underneath/around apply, keeping the koder-os-update CLI surface (checkapplyrollback) stable — only rollback stops returning ENOTSUP.

  • Distinct from snapshots-RFC-001. That RFC is user-environment

    backup/restore (declarative capture via Koder ID + Drive, #047). This RFC is the OS root itself. They share the word "snapshot" and the btrfs primitive, nothing else; they must not be conflated.

  • Root is btrfs (#068 default; #070 raid1-split keeps root a btrfs

    filesystem, subvolume-capable). This is the dominant fact for the choice.

Candidate mechanisms

Scored on RFC-002's five criteria (cost / rollback / bandwidth / ops / forward-migration) plus reuse-first (does it leverage the btrfs root we already ship, or demand a new layout/paradigm?).

Root lives in a btrfs subvolume (@). An update snapshots @@_candidate, applies the new image/packages into the candidate, then atomically switches the default subvolume (btrfs subvolume set-default) so the next boot — or a live switch-root where feasible — runs the candidate. A boot-time/post-activation healthcheck promotes or rolls back (set-default back to the known-good snapshot). Old snapshots are retained per a GC budget.

  • Pros: reuses the existing btrfs root — zero new partition scheme, zero

    FS reorg, composes with the #070 raid1 root (snapshots inherit the mirror). CoW makes snapshots near-free until divergence (hyperscale/lean). Atomic activation + native instant rollback. Keeps the mutable "edit `etckodix