3 Decisions
Chad Russell edited this page 2026-10-15 11:56:35 -04:00

Locked design decisions

# Decision
1 Build/store unit = one OCI image → one composefs descriptor
2 Composition = rootless overlayfs-over-FUSE in a userns (spiked, works)
3 Entrypoint = declarative TOML (no code-executing escape hatch; bind.create = true covers state-dir seeding). The one narrow exception is the devshell init — a project script auto-sourced via a fixed helper (#12, Devshells §6).
4 Dotfile authoring out of scope (lives in cn); dotfile/unit deployment IS in scope — declarative [[files]]/[[units]] in profile.toml, reconciled by apply into store-symlinks (Phase B/C home management)
5 Decomposition is demand-driven (split a package when a 2nd tool needs it)
6 Conflicts = main-package-wins (topmost overlay lower)
7 Source model: package (Containerfile) + entrypoint (TOML)
8 Pull = anonymous HTTPS (reqwest); Push = S3 (aws-sdk-s3) or --stage-dir
9 Implementation = single Rust binary; bash retired
10 Lockfiles: profile.lock pins the realized closure (GC-and-Generations); per-blob verify deferred
11 Sources (specs: local + git) + caches (binaries) — source add infers the form; per-install URL + recorded provenance (no registry); cache serves the default entrypoint; overrides deep-merge and live under ~/.config/bubblebox.
12 Devshell = an entrypoint whose binary is a shell (no new top-level concept); stacking = base inheritance via stack_merge (append), distinct from deep_merge (replace); project devshells = git-tracked bubblebox.toml; init hook = constrained auto-source of a project script (the only bend of #3). See Devshells.

| 13 | Bind destinations must pre-exist in the image; the engine validates and fails fast rather than auto-creating mountpoints. Auto-creation was rejected: the FUSE server is the pinned upstream composefs-fuse serving an immutable EROFS image — creating dirs would mean forking it or prerendering per-run images, for a case fully under the package author's control. (Engine PR #1, 2026-09-24.) | | 14 | Providers are built-in, files first. State that lives in another tool's database (flatpak installs) is managed by a built-in Rust provider: a profile.toml section, a read-only live query for plan, a diff, and convergent apply. Generations record the declared set, and ownership mirrors [[files]]: remove only what a previous generation declared; never-declared items are reported extras unless prune = true. No TOML-defined command providers (would break #3). Anything a program can layer or read from a drop-in directory is done with [[files]]/[[units]] instead (e.g. dconf: keyfile → file-db under the user-db via DCONF_PROFILE, cn #72). First provider: [flatpak] (engine PR #7, v0.4.0). |