# Installable System Backlog

Detailed decomposition of
[`docs/proposals/installable-system-proposal.md`](../proposals/installable-system-proposal.md):
an installed, persistent capOS that boots from disk and keeps mutable system
configuration across reboots, composed with the immutable boot manifest.

`docs/tasks/README.md` links here. **Installable System** became the selected
milestone after the Device Driver Foundation closeout and is now closed for the
bounded local/QEMU installable-system contract. The behavior track below landed
through item 8, and item 9 reconciled the proposal/body wording to the landed
install, provision, update, and rollback contracts. This milestone does not pull
public L4 ingress, AWS/Azure live support, direct-remapping production hardware,
userspace smoltcp/L4 readiness, secure boot/signing, or production release
authority into selected scope.

## Landed Foundations (What This Builds On)

These contracts exist today and the track decomposes against them, not against
the proposal's projected shapes. Present tense is landed behavior.

| Building block | Landed contract | Source |
|---|---|---|
| `BlockDevice` | `readBlocks`/`writeBlocks`/`info`/`flush` over a real `cfg(qemu)` virtio-blk device; `blockDevice` grant source | `kernel/src/cap/block_device.rs`; proof `make run-virtio-blk` |
| Read-only filesystem | `CAPOSRO1` fixed superblock at LBA 0; `Directory.list`/`open`/`sub` + `File.read`/`stat`; mutating methods fail closed; `readOnlyFsRoot` grant source | `kernel/src/cap/readonly_fs.rs`; proof `make run-storage-fs` |
| Persistent content-addressed `Store` | `CAPOSST1` superblock at LBA 0; `put`/`get`/`has`/`delete` keyed by SHA-256 hash; superblock rewrite is the durable commit point; survives reboot; `persistentStore` grant source | `kernel/src/cap/persistent_store.rs`; reboot proof `make run-storage-persist` |
| Writable filesystem | `CAPOSWF1` superblock at LBA 256; full `Directory` mutation set + `File.write`/`truncate`/`sync`/`close`; fail-closed single-writer policy; `writableFsRoot` grant source | `kernel/src/cap/writable_fs.rs`; reboot proof `make run-storage-writable` |
| Co-located storage image | One disk co-locates `CAPOSST1` `Store` (LBA 0) and `CAPOSWF1` filesystem (LBA 256) so both survive reboot together | `tools/mkstore-image --writable` |
| Read-only packaged-image source fixture | QEMU-gated read-only `Directory`/`File` over the booted CD-ROM ISO 9660 `/boot/bins/` tree (`boot_iso` ATAPI reader); `installable_image_source` grant source; physically scoped to the ATAPI medium, cannot reach the writable target disk; not a general post-bootstrap filesystem service | `kernel/src/cap/installable_image.rs`; proof `make run-installable-image-source` |
| Default bootable disk image | Single hybrid BIOS+UEFI raw image with one GPT ESP (FAT32) carrying Limine, kernel, a name-only `manifest.bin`, and Limine module payloads under `/boot/bins/`; `make image`, `run-disk`, `run-disk-bios`; GCP/AWS provider packaging. | `tools/mkdiskimage.sh`, `tools/package-cloud-image.sh`; proof `make run-limine-disk-boot-modules` |
| `Namespace` | RAM-backed `resolve`/`bind`/`list`/`sub` name-to-hash bindings; **not persistent**; `namespace` grant source | `kernel/src/cap/namespace.rs` |
| Boot manifest / init | Baseline boot loads the manifest module. Default raw disk and cloudboot images resolve ordinary service binaries from checked Limine modules; default ISO build/run/smoke paths resolve ordinary service binaries from the name-only ISO `/boot/bins/` tree through `boot_iso`; the reserved `init` selector still uses the kernel-embedded init ELF. `run_init` parses `SystemManifest`, builds init's bootstrap caps, and enters `initConfig.init`. The installable data-region path additionally reads and validates `system/config/overlay.bin` when the data region mounts and the base manifest declares matching extension points | `kernel/src/main.rs`, `kernel/src/boot.rs`, proof `make run-installable-overlay`; `make run-smoke` |

## Divergences From The Proposal (Structural Reconcile Closed)

The proposal was written before the storage prerequisites landed and projects
shapes that differ from the landed contracts. The initial reconcile task
recorded the landed storage contracts and placement decisions before the
behavior track ran; the behavior track then landed through item 8 below. The
structural docs reconcile task updated the proposal's structure and body wording
to the landed install, provision, update, and rollback contracts without
broadening selected scope.

- **On-disk layout.** The proposal projected three partitions (boot / system /
  data) on the installed disk. The base `make image` raw boot image still
  produces a single hybrid BIOS+UEFI image with **one** GPT ESP, and the
  co-located `CAPOSST1` `Store` + `CAPOSWF1` writable filesystem remains
  available as a **separate** data-region image for the focused storage and
  early data-region smokes. The landed installable-system disk path no longer
  stops there: task 5 (`installable-bootable-disk-system-data-regions`) folds
  that co-located data-region image into the bootable disk as GPT partition 2
  at the fixed data-region LBA, so `make run-installable-disk` boots from one
  disk carrying both the ESP and the persistent data region. Tasks 2-4 describe
  the separate auto-mounted data-disk model they originally built on; item 5
  is the landed integrated single-disk packaging.
- **Persistent naming.** The proposal stores the overlay "under a well-known
  system `Namespace` root (`system/config/<generation>`)". The landed
  `Namespace` is **RAM-only** and does not survive reboot. Persistent naming and
  the `active`/known-good pointers are therefore grounded in the **landed
  writable filesystem** (`CAPOSWF1` paths and small marker files) plus the
  content-addressed persistent `Store` (`CAPOSST1`) for immutable generation
  objects. No new persistent-`Namespace` kernel cap is assumed.
- **Generations and epochs.** No landed `Store`, `Namespace`, or
  `SystemManifest` schema carries a system-generation/epoch field today (other
  caps such as `AccountRecord` and the DDF revocation generations do, but not the
  installable-system path). The monotonic epoch + content hash the proposal
  relies on for stale-write rejection and rollback are carried inside the
  overlay's own capnp object and the writable-filesystem marker files, not by
  extending `Store` or `Namespace`.
- **Composition machinery.** Landed in track item 3 (2026-05-26): the
  `SystemConfigOverlay` capnp object plus `SystemManifest.extensionPoints`, and
  init's read/decode/validate/compose with base-pins-win / overlay-adds-within-
  declared-extension-points / no-new-authority precedence and fail-closed
  base-floor fallback (`make run-installable-overlay`). Generation/rollback
  selection of *which* overlay is active landed in task 4, and the
  install/provision/update/rollback flows landed in tasks 6-8.

## Ordered Track

Each item names its acceptance and the landed APIs it builds on. Dispatchable
records live under `docs/tasks/` with the same ids.

1. **`installable-system-proposal-reconcile`** (docs). **Done 2026-05-26.**
   Reconciled `installable-system-proposal.md` to the landed contracts above:
   single hybrid
   ESP boot image (no three projected partitions), persistent config region
   grounded in the writable filesystem + content-addressed persistent `Store`,
   RAM-only `Namespace` (naming/pointers are writable-filesystem files), and
   no system-generation field on the `Store`/`Namespace`/`SystemManifest` path.
   Recorded the data/system region placement decision. The structural
   proposal/body wording update is closed by item 9. *Builds on:* all five
   storage/boot prerequisites.

2. **`installable-data-region-boot-mount`** (behavior). **Done 2026-05-26 02:02
   UTC.** Wires the persistent data region (the co-located `CAPOSST1` `Store` +
   `CAPOSWF1` writable filesystem) into the boot path: under the
   `installable_data_region` kernel feature, `run_init` best-effort calls
   `cap::grant_data_region`, which mounts the auto-attached data disk, scopes a
   writable `Directory` to the `system/config` subtree
   (`writable_fs::mount_config_root`), and grants init that `Directory`
   (`data-config`) plus the persistent `Store` (`data-store`) under well-known
   CapSet names -- granted together or not at all. It fails closed wholesale to
   the base manifest (caps unchanged, "no data region; base floor" diagnostic)
   when the disk is absent, has a malformed superblock, or is missing the
   `system/config` root; the disk caps stay out of the manifest so the
   fail-closed boots do not abort on a mandatory cap. No new kernel cap type or
   schema change. *Proof:* `make run-installable-data-region` boots the same ISO
   three times -- seeded disk (init prints the resolved `system/config`
   contents), no disk (base floor), and zeroed-superblock disk (base floor).
   *Builds on:* `writable_fs.rs`, `persistent_store.rs`, the co-located image
   tool (`--seed-config`), and `run_init`.

3. **`installable-config-overlay-schema-and-merge`** (behavior, schema). **Done
   2026-05-26 02:55 UTC.** Added the persistent `SystemConfigOverlay` capnp
   object (overlay version, monotonic epoch, SHA-256 content hash, additional
   services, network/runtime settings, account-store location) and the
   `SystemManifest.extensionPoints` declared extension points
   (`ManifestExtensionPoints`: additional-services allowance/count, allowed
   service caps, `minOverlayEpoch`, settings allowances -- closed by default).
   Init now reads `system/config/overlay.bin` from the granted config region,
   decodes it (`SystemConfigOverlay::from_capnp_bytes` re-validates the overlay
   version and content hash), and composes it over the base plan
   (`compose_onto`): base pins win (no base-service-name or `init` collision),
   overlay services name only base-shipped binaries and request only
   `allowedServiceCaps` (no new authority classes), `epoch >= minOverlayEpoch`,
   count `<= maxAdditionalServices`, and carried settings require their
   allowance. Any schema-invalid, version-mismatched, content-hash-mismatched,
   stale-epoch, extension-point-violating, or missing overlay is rejected whole;
   init boots the base floor and surfaces `[init] overlay rejected: <reason>`.
   Host encoder `tools/mkmanifest` `mkoverlay` bin emits the overlay bytes
   (filling the canonical hash); `tools/mkstore-image --writable --seed-overlay`
   seeds `system/config/overlay.bin`. *Proof:* `make run-installable-overlay`
   boots the same featured ISO three times -- valid overlay (the `overlay-extra`
   service runs), base-pin collision (rejected, base floor preserved), corrupt
   overlay (rejected, base floor). Did NOT add generations/rollback (task 4).
   *Builds on:* task 2, `capos-config` manifest validation,
   `schema/capos.capnp` `SystemManifest`.

4. **`installable-system-generation-rollback`** (behavior). **Done 2026-05-26
   03:41 UTC.** Userspace-only over the already-granted persistent `Store` +
   writable `system/config` `Directory`; no schema or kernel change. Represents
   system-config generations as content-addressed `Store` objects keyed by
   SHA-256 (immutable, deduped), tracks the known-good `active` pointer and a
   staged/`attempting` `candidate` pointer as monotonic-pointer-epoch marker
   files (`gen-active`/`gen-candidate`) in the writable config region, records a
   boot attempt durably *before* applying a candidate, and auto-falls-back to the
   known-good generation when a candidate is left unconfirmed (a boot that does
   not reach the health checkpoint) -- the brick-proofing guarantee. Also
   promotes a confirmed candidate, rolls config back to a retained prior
   generation (monotonic pointer advance pointing at older content), and rejects
   a stale/replayed (lower-or-equal-epoch) pointer. `init/src/main.rs`
   `run_generation_rollback_checks`, gated by a base service named
   `generation-proof`, exercises all of this end-to-end against the real durable
   primitives with observable `[gen] ...` assertions. Did NOT add the installer
   (task 6) or update flow (task 8). *Proof:* `make run-installable-generation`
   boots a `--seed-config` disk twice -- boot 1 exercises the full mechanism in
   one boot and durably leaves an unconfirmed `attempting` candidate; boot 2
   re-reads the committed markers from a fresh mount and proves across-reboot
   auto-fallback to the known-good generation. *Builds on:* task 3 and the
   persistent `Store`/writable filesystem durability.

5. **`installable-bootable-disk-system-data-regions`** (behavior). **Done
   2026-05-26 04:31 UTC.** One integrated bootable disk now carries the boot ESP
   (GPT partition 1) and the co-located `CAPOSST1` `Store` + `CAPOSWF1` writable
   data region (GPT partition 2), and boots through the landed task 2-4 path
   reading the data region from the same disk it booted from -- not a separate
   smoke-only drive. `tools/mkdiskimage.sh` gained `--data-image` /
   `--data-offset-bytes` (it folds the `tools/mkstore-image --writable` image
   into a second GPT partition) and derives the ESP size from `--esp-sectors`
   (the integrated disk uses the same 128 MiB ESP as the raw disk-image targets
   so a debug kernel fits). The kernel `installable_disk` feature (implies
   `installable_data_region`) adds a fixed data-region base LBA
   (`cap::data_region_base_lba` = 264192) applied at the single
   `persistent_store`/`writable_fs` `read_range`/`write_range` choke points; the
   kernel trusts that fixed tool/kernel layout contract rather than parsing the
   GPT, exactly as the superblock LBAs already are. *Proof:* `make
   run-installable-disk` builds one disk (boot ESP + seeded data region carrying
   a valid config overlay) and boots it as a single virtio-blk device; the gate
   is `data region: mounted` from the boot disk plus `[overlay-extra] started via
   overlay` -- a service only the data region supplies -- not a clean boot alone.
   Did NOT add the installer (task 6). *Builds on:* `mkdiskimage.sh`,
   `tools/mkstore-image --writable`, task 4.

5a. **`ddf-multi-virtio-blk-device-support`** (behavior, DDF milestone). Lift the
   single-virtio-blk limit (per-device driver instance, DMA pool key, interrupt
   route, PCI claim) and add a target-disk `BlockDevice`/`Store` grant source
   scoping a cap to a specific device. Owned by the Device Driver Foundation
   milestone (`docs/backlog/hardware-boot-storage.md` "Reusable Block-Device
   Path"); the install flow `depends_on` it. *Builds on:* the landed
   device-agnostic `transport` seam and per-queue-keyed DMA ledger.

5b. **`installable-userspace-image-source`** (behavior, **DONE 2026-05-26
   08:15 UTC**). Expose a userspace-readable read-only packaged-image source so a
   userspace installer can read the packaged boot/system bytes. *Chosen shape:*
   a QEMU-gated read-only `Directory`/`File` cap over the existing `boot_iso`
   ISO 9660 reader (`kernel/src/iso/`), not the boot-package payload
   alternative and not a general post-bootstrap filesystem service. The
   `installable_image_source` grant source (`KernelCapSource @45`) mounts the
   booted CD-ROM ISO 9660 `/boot/bins/` tree and serves `Directory.list`/`open`
   + `File.read`/`stat`; every mutating method fails closed. It is physically
   scoped to the ATAPI CD-ROM medium and **cannot** reach or mutate the writable
   virtio-blk target disk (`blockDeviceTarget`/`writableFsRoot`) -- that write
   authority belongs to the install flow (task 6). Offsets/lengths are validated
   against the file extent before any device access, reusing the driver's
   in-bounds checks; a past-EOF read clamps to empty and an absent name is
   rejected. Broader package browsing remains userspace-service work rather than
   an expansion of this fixture. *Proof:* `make run-installable-image-source`
   (kernel cap module `kernel/src/cap/installable_image.rs`; consumer demo
   `demos/installable-image-source/`; manifest
   `system-installable-image-source.cue`; harness
   `tools/qemu-installable-image-source-smoke.sh`). *Builds on:* task 5, the
   `boot_iso` ISO 9660 reader.

6. **`installable-system-install-flow`** (behavior). **Done 2026-05-26 10:12
   UTC.** The `capos-system-install` userspace service (`demos/installable-system-install/`)
   installs a bootable capOS onto a blank *target* disk using only two granted
   caps: the read-only `installable_image_source` `Directory` over the booted
   CD-ROM `/boot/bins/` and the target-scoped `block_device_target` `BlockDevice`
   selected by manifest PCI identity, never the boot disk. It copies the
   packaged bootable boot-region head (`BOOTHEAD.BIN`: protective MBR + primary
   GPT + the FAT ESP with Limine + release kernel + base manifest) to LBA 0,
   writes the backup GPT
   (`BOOTGPT.BIN`) at the LBA read from the primary GPT header (Limine validates
   it), and initializes an empty data region (`DATAIMG.BIN`: empty `CAPOSST1`
   Store + `CAPOSWF1` filesystem with just the `system/config` directory) at the
   fixed `cap::data_region_base_lba`. It validates every sector range before
   writing and verifies the read-back. The empty data region is the install
   floor; the operator's first non-empty config generation is provisioning
   (task 7), not install. *Proof:* `make run-installable-install` -- pass 1
   installs into the manifest-selected virtio-blk target disk; pass 2 boots that disk **standalone**
   (no CD-ROM) and reaches the base service with its data region mounted
   (`data region: mounted` + `[init] data-region mounted: system/config
   entries=0` + `[console-paths] Console paths ok.`), not a clean boot alone.
   The build packages the boot region split into head + backup GPT
   (`tools/split-boot-region.py`) so the installer reads only the populated
   ~15 MiB over the slow ATAPI PIO path rather than the whole FAT32 ESP. Did NOT
   add provisioning (task 7) or update/rollback (task 8). *Builds on:* task 5,
   the `BlockDevice` sector path, content-addressed `Store`, and the precursors
   5a `ddf-multi-virtio-blk-device-support` and 5b
   `installable-userspace-image-source`.

7. **`installable-system-provision-flow`** (behavior). **Done 2026-05-26 11:09
   UTC.** The `capos-system-provision` userspace service
   (`demos/installable-system-provision/`) runs as PID 1 over an installed
   system's persistent data region and performs the proposal's "Provision" flow,
   holding only three caps: a `Console`, the writable filesystem root
   (`writable_fs_root`, navigated to `system/config`), and the content-addressed
   persistent `Store` (`persistent_store`). On a disk whose `system/config`
   carries no active generation yet (the empty install floor task 6 leaves), it
   writes the operator's first non-empty `SystemConfigOverlay` generation
   (epoch 1: an operator `AccountRecord` stored as a content-addressed `Store`
   record named from the overlay's `accountStoreLocation`, a hostname, a log
   level, and one additional service), commits the generation object to the
   `Store`, writes `system/config/overlay.bin` (the shape init's
   `apply_config_overlay` consumes, proven by task 3), and advances the
   `gen-active` pointer. It dispatches on durable state: a second boot of the
   same disk re-reads the `gen-active` pointer, resolves the generation object
   and operator account from the `Store`, and verifies the provisioned
   account/settings are the active durable config that survived the reboot. Did
   NOT add the update/rollback flow (task 8); reuses the overlay object and the
   existing `AccountRecord` schema with no schema change. *Proof:*
   `make run-installable-provision` boots the same `--empty-config` disk twice --
   pass 1 provisions and commits, pass 2 verifies the active generation +
   operator account + settings survived; a clean boot alone is not the gate.
   *Builds on:* task 6 (the empty install floor), task 3 (the overlay object and
   merge), task 4 (the generation/`gen-active` representation), and the
   writable-filesystem + persistent-`Store` durability.

8. **`installable-system-update-rollback-flow`** (behavior). **Done 2026-05-26
   11:35 UTC.** The `capos-system-update` userspace service
   (`demos/installable-system-update/`) performs the proposal's "Update" flow on
   top of the landed generation/rollback mechanism (task 4), userspace-only over
   the same three caps provision holds (`Console`, `writable_fs_root` navigated
   to `system/config`, persistent `Store`); no schema or kernel change. It writes
   a *new* `SystemConfigOverlay` generation into the content-addressed `Store` as
   a new root hash (old generation objects remain; the shared operator
   `AccountRecord` dedups), stages it as an `attempting` `gen-candidate` pointer
   *without* advancing the known-good `gen-active` pointer, and on the next boot
   commits by advancing `active` only when the candidate reaches its health
   checkpoint -- otherwise the boot-attempt-vs-confirmed auto-fallback keeps the
   prior known-good. The overlay re-validation against the new base reuses the
   production `SystemConfigOverlay::compose_onto` against a base plan whose
   extension points revoked the overlay's authority, so an update whose new base
   no longer admits the overlay falls back to the base floor with a surfaced
   error rather than applying. The data region (operator account + active config)
   is carried across every transition. It dispatches on durable state
   (`update-phase` marker) so commit-on-success and auto-fallback are both proven
   across a REAL reboot, not one process. *Proof:* `make run-installable-update`
   boots the same `--empty-config` disk THREE times -- boot 1 provisions
   known-good gen1, rejects an overlay against a revoked-cap new base (kept base
   floor), and stages a healthy candidate gen2; boot 2 commits gen2 across the
   reboot and stages a failing candidate gen3; boot 3 auto-falls-back from gen3
   across the reboot to known-good gen2 -- distinct per-generation content hashes
   and a stable account hash on every line, the staged/commit/fallback/
   marker-survival/data-region-carried assertions, not a clean boot alone.
   *Builds on:* task 6 (the install floor), task 7 (the provision/overlay shape),
   task 4 (the generation/`gen-active`/`gen-candidate` representation), and task 3
   (overlay compose/validation).

9. **`installable-system-structural-doc-reconcile`** (docs-status). **Done
   2026-06-07 18:20 UTC through commit `12b8334a` (committed 2026-06-07 18:19
   UTC).** Reconciled
   [`docs/proposals/installable-system-proposal.md`](../proposals/installable-system-proposal.md)
   structural and body wording to the landed local/QEMU data-region, overlay,
   generation, install, provision, and update/rollback contracts. Preserved the
   RAM-only `Namespace` caveat and kept secure boot/signing, production release
   authority, public ingress, AWS/Azure live support, direct-remapping
   production hardware, userspace smoltcp/L4 readiness, and full durable account
   policy out of the closed Installable System scope.

## Design Grounding

- [`docs/proposals/installable-system-proposal.md`](../proposals/installable-system-proposal.md)
  -- the design being decomposed.
- [`docs/backlog/hardware-boot-storage.md`](hardware-boot-storage.md) -- the
  Local Disk Storage, Writable Local Storage, and Bootable Disk Image milestones
  the landed prerequisites came from.
- [`docs/backlog/local-users-management.md`](local-users-management.md) -- the
  account store, a consumer of the persistent-config region.
- [`docs/backlog/run-targets-and-init-policy.md`](run-targets-and-init-policy.md)
  -- the init mandate and boot-manifest policy any installed-system boot path
  must respect.
- [`docs/proposals/storage-and-naming-proposal.md`](../proposals/storage-and-naming-proposal.md)
  -- the `Store`/`Namespace`/`Directory`/`File` model, content-addressing, and
  attenuation the persistence layer reuses.
- [`docs/architecture/manifest-startup.md`](../architecture/manifest-startup.md)
  -- the immutable base manifest the persistent overlay composes with.
