Skip to content

Latest commit

 

History

History
494 lines (462 loc) · 29.1 KB

File metadata and controls

494 lines (462 loc) · 29.1 KB

Changelog

All notable changes to the Margine bootc image build are recorded here. Image tags follow stable, stable.YYYYMMDD, YYYYMMDD. Semantic versioning (v0.X.Y) will start once the first user-facing stable release is cut.

[Unreleased]

Changed (2026-07-11)

  • The public product name is "Margine OS" (fixed together with the DistroWatch submission). os-release NAME/PRETTY_NAME/VERSION/VARIANT now say "Margine OS" (GNOME About, hostnamectl, BLS boot entries), the About panel's Website link points at https://margine.dev (was GitHub), the Archive ISO titles read "Margine OS ... Linux ISO", and README leads with the full name. "Margine" stays as the short form in running text; the technical identifiers (VARIANT_ID=margine for countme, margine-* names, Archive identifiers, the image name) are deliberately unchanged. Naming policy recorded in docs/BRANDING.md.
  • Reverse-DNS namespace moved to dev.margine. The last identifiers derived from the old domain are gone: the ISO-builder GUI app id is now dev.margine.IsoBuilder (.desktop, D-Bus name, Justfile, DESIGN.md, renamed together), and the never-produced place.the-empty.margine.kernel status label became a real dev.margine.kernel OCI label, stamped at rechunk from the built rootfs, so /status reads the kernel from the image instead of a curated carry-over. The redundant spec-ref labels (equal to org.opencontainers.image.revision and dropped by rechunk anyway) are deleted, which finally makes the 2026-07-05 "spec-ref label is gone" changelog claim true.
  • The project domain is now margine.dev. Every living reference moved over: os-release URLs, margine-status/update, the docs-open helper, the offline-docs mirror source (verified live: 35 pages + 89 assets, zero failures), the CI publishers (status.json, countme.json, ISO date bump), README/SECURITY/issue templates and the spec docs. Historical entries keep the old margine.the-empty.place URLs; a 301 redirect keeps them working.

Added (2026-07-10)

  • Update watchdog + ujust margine-update-unblock. Extra-data Flatpaks (Reaper) download their real binary from the vendor at update time; flatpak's fetch has no timeout, and a dropped CDN connection wedged the nightly uupd run and the system flatpak lock (Bazaar included) for days, twice in 12 days (2026-06-28, 2026-07-08). The existing 30-min kill only bounded each cycle (and only in awake time: systemd timeouts freeze across suspend), so the retry loop persisted (73 cycles observed). Now uupd's OnFailure= fires margine-update-watchdog: it identifies the in-flight extra-data app from the journal and, at 2 strikes in 7 days, flatpak masks it so unattended updates complete again. The user gets a session notification and ujust margine-update-unblock updates the app in the foreground and re-includes it. OS updates were never starved: uupd stages the system image before touching flatpaks.

Fixed (2026-07-10)

  • margine-status no longer lies on systems with a pending update. The layered-deployment fallback read deployments[0], which is the STAGED deployment, so the tool showed the staged version as "your deployment, up to date" while the machine was running the previous one. It now selects booted==true, shows a Staged (applies at next boot) line, a "staged, reboot to apply" verdict, unattended-update health and any watchdog-excluded apps.
  • Update notifications now actually reach the user. The post-reboot "Now running: X" toast ran at default.target (before the session's notification daemon exists) and recorded itself as delivered even when notify-send failed; it also crashed on layered deployments (bootc omits booted.image there). Moved to graphical-session.target, state advances only after a successful notify, rpm-ostree fallback added. The staged- update timer only counted monotonic time (frozen across suspend, so it effectively never fired on a laptop); it now fires on the wall clock (OnCalendar + Persistent=true) and also announces a newly staged deployment right away, once, instead of only nagging after 2 days.

Removed (2026-07-10)

  • Reaper is no longer preinstalled (still one click away in Bazaar). Policy: no extra-data apps in the preinstall set; their vendor download is exactly the unattended-update hang above. Existing installs keep Reaper and are protected by the watchdog.

Changed (2026-07-05)

  • One repo. margine-fedora-atomic (the spec: the configure-* / validate-* scripts, declarations.yaml, branding assets, ADRs, and the handbook) was merged into margine-image with its full history preserved, then archived read-only. The build no longer fetches anything at build time: scripts and declarations install from build_files/40-spec-scripts/, branding from build_files/50-branding/assets/, and the spec docs live in docs/spec/. MARGINE_REPO / MARGINE_REF, the build-start "resolve spec ref to SHA" step, the --build-arg MARGINE_REF, and the spec-ref OCI label are gone. Every image is now byte-reproducible from the single margine-image commit it was built from (org.opencontainers.image.revision). This fixes two long-standing problems: forks could not build (CI resolved <owner>/margine-fedora-atomic and 404'd on a fork), and every change used to need coordinated PRs across two repos. The archived companion stays readable at its old URL, so already-installed systems' DOCUMENTATION_URL keeps resolving.

Added (2026-07-06)

  • ujust margine-darktable-opencl enables GPU OpenCL in the preinstalled darktable Flatpak via the host Mesa rusticl driver (no ROCm/CUDA). Opt-in, idempotent, per-user.
  • ujust margine-report collects a diagnostic bundle (image version, hardware, Secure Boot, Flatpak health, this boot's errors) into ~/margine-report.txt and opens the GitHub issue chooser, so bug reports land in one searchable place.
  • ujust margine-netflix-1080p installs the AMO-signed "Netflix 1080p UA" extension into the Zen Browser profile (opt-in) so Netflix serves 1080p on Linux. Widevine already works on Margine's Zen; this only presents an Opera-on-Linux user agent to Netflix.
  • ujust margine-blender-gpu turns on GPU (HIP) rendering in the preinstalled Blender Flatpak on AMD by exposing the host's ROCm runtime (which the Flatpak lacks) to Blender's library path. Verified on a Radeon 760M: a Cycles GPU render completes, no HSA override needed.
  • /status "Devices running Margine" chart, sourced weekly from Fedora's public Count Me dataset (Margine ships VARIANT_ID=margine, so it appears there with no telemetry of our own).
  • Shared bash history across terminal windows (issue #278): a /etc/profile.d drop-in appends each command to the history file and pulls in other sessions' lines, so up-arrow works across multiple Ptyxis windows instead of each keeping a private, clobbered history.

Fixed (2026-07-07)

  • ujust bluefin-cli works again (issue #291): the branding strip was deleting /usr/bin/ublue-bling together with Bluefin's fastfetch binaries, but the inherited bluefin-cli recipe still calls it, so it failed with "command not found". The bling toggle now stays (only the fastfetch branding is stripped) and the strip validator no longer flags it.
  • Recycling a test VM no longer deletes the ISO it booted from. Every margine-test-* teardown (the margine-test-vm recycle, margine-test-vm-remove, margine-test-vm-clean, the dev Justfile and the ISO-builder GUI) used virsh undefine --remove-all-storage, which removes every attached volume including the cdrom ISO. Since rebuilds reuse the same output/Margine-Live.iso path (a session storage pool), re-testing a fresh build deleted it. Teardowns now remove only the VM's writable scratch disks; the GUI also reports a failed VM launch instead of toasting success.

Fixed (2026-07-06)

  • The offline manual now shows its images. The offline-docs scraper rewrote page links but never downloaded the referenced assets, so screenshots, fonts and favicons were blank offline. It now localizes <img>, srcset and CSS url() assets into the mirror (build seed and the runtime refresh both, since they share the scraper).
  • Security audit remediation. Closed a path-traversal in the offline-docs scraper (a hostile or MITM'd docs origin could make the root-run build-time writer place a file outside the mirror); SHA-pinned the grype installer and the MoreWaita icon fetch, pinned internetarchive in the IA-credential jobs, added input validation to the scheduler-apply pkexec helper, made recipe-argument handling injection-safe ($-exported params, quoting), and removed a stray committed .pyc that shipped into /usr/libexec.
  • The ISO publish no longer hangs on a wedged upload. The Internet Archive step used ia upload, whose retries only fire on error responses, so a dead socket blocked a multi-GB upload until the job timed out. It now uses a stall-aware curl uploader (aborts a transfer that sits under 10 KB/s, retries on a fresh connection, HEAD size+md5 verify so re-runs resume) that also waits out a global Internet Archive rationing event within a wall-clock budget. build-disk concurrency now queues same-variant dispatches instead of cancelling an in-flight publish.

Fixed (2026-06-28)

  • Fresh-install Flatpaks were empty on every real install (take 2, reverses PR #222). The installer baked the default Flatpaks into the bare dedicated /var btrfs subvol (/mnt/sysimage/var), but on a bootc/ostree first boot the booted /var is the per-deployment stateroot checkout seeded from the image commit — not that subvol — so the baked repo was lost and every flatpak op failed (CyberOto, forum 12247). install-flatpaks.ks now bakes into $deployment.0/var/lib via ostree rev-parse … ostree/0/1/0, byte parity with upstream Bluefin/Aurora (which use the same dedicated-/var partitioning). flatpak-preinstall.service stays enabled (Margine DEFERs GIMP/Inkscape/darktable/OBS + Reaper to it; Reaper cannot be baked), with a restorecon ExecStartPre so a bake-lost fallback can't leave a mislabeled repo stub. The install gate (verify-install-disk.sh) now asserts the bake LOCATION, and the check-flatpak-fixes.sh regression guard (which had inverted to assert the old target) is corrected.

Fixed (2026-06-19)

  • EasyEffects now actually starts hidden. The autostart used only --service-mode, which in EasyEffects 8.x (Qt) still pops the window open at login (user-reported). Add --hide-window so it starts as a background service with the window closed; re-open it from Activities (it attaches to the running service). Effects stay inert until a preset is enabled.

Added (2026-06-18)

  • ujust install-koofr (alias ujust koofr) — installs the Koofr Desktop sync client natively and rootless from upstream's self-updating tarball into ~/.koofr-dist (no Flatpak/RPM/Distrobox; never layered, since it auto-updates inside $HOME). Autostarts hidden to the system tray at login via the binary's -silent flag, with silentStart:true persisted in ~/.koofr/config.json as belt-and-suspenders (guarded so it never clobbers a running client); a manual menu launch still opens the window. remove uninstalls the three artifacts and kills the process.
  • ujust margine-test-vm (+ margine-test-vm-remove) — throwaway VM to test a Margine ISO on the real secure path: UEFI Secure Boot with Microsoft keys pre-enrolled (so MOK enrollment is exercised) + an emulated TPM 2.0 (for LUKS auto-unlock). Rootless qemu:///session; an ISO arg boots a ready VM, no arg defines a clone template.
  • EasyEffects autostarts headless — system /etc/xdg/autostart entry runs EasyEffects in --service-mode (no window) on login.

Changed (2026-06-18)

  • Super+arrows now move the focused window within the o-tiling layout (gaps preserved) via tile-move-*-global; the GNOME gapless built-ins that used to eat the chord are cleared. Focus stays on Super+hjkl.

Fixed (2026-06-18)

  • Plymouth graphical boot on fresh installs and in VMs. Three causes, all baked into /usr/lib/bootc/kargs.d/10-margine-plymouth.toml + the theme: (1) the bootc/titanoboa ISO didn't set rhgb quiet, so fresh installs booted to a text console with the LUKS prompt amid kernel logs — now rhgb quiet. (2) The real blocker in VMs: the installer adds console=ttyS0 (the guest has a serial device), which Plymouth treats as headless and so it skips the graphical splash entirely — now plymouth.ignore-serial-consoles. Plymouth then renders via the EFI framebuffer (efifb, built-in); no extra GPU module in the initramfs is needed (an attempt to force virtio_gpu in was dropped — it was unnecessary and the build container's dracut wouldn't resolve it anyway). (3) The early-KMS→real-GPU mode switch mid-boot left the wordmark + LUKS prompt off-centre — the theme now re-centres the logo and the dialog on a resolution change (margine.script refresh_callback). The theme itself was never at fault; the host (no serial console, real GPU) was unaffected throughout.
  • o-tiling gap defaults now actually apply. gap-inner/gap-outer (and the active-hint border radius/width) are uint32 keys, but the dconf default wrote them as bare ints (gap-inner=2), which the db stored as int32 — a type mismatch the gschema rejects, so they silently fell back to o-tiling's own defaults (gap 4) on fresh installs (user-reported). Tagged them uint32 in 03-margine-o-tiling. Also aligned the o-tiling cosmetic defaults with the intended config: title-bar min/max + close buttons on, skip-overview on, workspace-number-indicator on, smart-gaps/snap-to-grid off.

Added (2026-06-15)

  • Safe TPM2-unlock + autologin helpersujust margine-tpm-unlock (status/enable/disable) and ujust margine-autologin (status/on/off). The TPM helper is lockout-proof by construction: auto-detects the LUKS device backing root, refuses to enroll unless a passphrase/recovery keyslot survives, only ever wipes the tpm2 slot, confirms + post-verifies. Both authored + adversarially reviewed to approval. Documented in the handbook (first-boot).
  • /status freshness dashboard producerbuild-status-json.sh + publish-status-json.sh + status-json.yml keep the site's Fedora → Bluefin → Margine version/health page current after every build / smoke / ISO and daily; org.opencontainers.image.base.digest label added so the page can flag whether Margine is built on the latest Bluefin. Plus ujust margine-status / margine-update + the /usr/bin/margine-status helper.
  • Soft user-smoke gate — a warn-only identity probe in the smoke-boot VM (kernel is CachyOS/BORE, o-tiling enabled, keybindings present, search-light absent, gaming recipe shipped, zz1 gschema applied). Annotates the run; never blocks candidate→:stable promotion.
  • AI / local-LLM layer documented + validated — handbook page + homepage card for ujust margine-ai (Alpaca); validate-flatpak-refs.yml checks every recipe Flatpak app ID against Flathub on PRs + weekly.
  • GHCR cleanup — daily prune of untagged orphan image versions (keep-n-untagged), plus host benchmark/diagnostic tools under tools/bench/ (kernel scheduler, gaming FPS, non-HiDPI check).

Changed (2026-06-15)

  • Site ISO-date bump now pushes straight to the website's main (the repo is private/free, so the old PR + auto-merge path silently stranded the bump and the site advertised the previous ISO).
  • Renovate now tracks the o-tiling release pin (no more silent staleness) and the config was migrated; actions/checkout bumped to v6.

Fixed (2026-06-08) — ISO MOK enrollment timing

  • Fresh ISO installs now submit the Margine MOK import request from Anaconda before the first post-install reboot, mirroring Bluefin's ISO Secure Boot flow so shim can open MOK Manager before the installed system boots.
  • Rebase recovery path remains unchanged: mok-enroll.service still runs on first Margine boot when the Anaconda path was not available or the user missed the firmware MOK prompt.

Fixed (2026-06-08) — Round-1 blocker audit

  • GNOME extension defaults now live in the system dconf database (/etc/dconf/db/distro.d/) instead of a gschema override, so extension settings are applied through the backend GNOME Shell actually reads at first login.
  • Installer partitioning is declared in the Anaconda kickstart: zerombr, clearpart, a 4 GiB ESP, a growing btrfs root, and the single-disk ignoredisk shim for safer fresh installs.
  • bootc-image-builder in build-disk.yml is pinned to an @sha256 digest instead of a moving tag.
  • GNOME branding assets overwrite Fedora's hard-coded logo pixmaps instead of deleting them, so GNOME About renders the Margine logo again.
  • sched_ext controls were rewritten as an opt-in Zenity picker: scx_loader stays off by default, scheduler changes go through scxctl/D-Bus/polkit, and tuned profile hooks now gate on active service state instead of enabled state.
  • README install guidance now recommends rebasing from Bluefin DX while the fresh-install ISO path is being hardened.
  • Launcher icons now use a MoreWaita system icon for the scheduler app and a custom Margine documentation icon.
  • Documentation launcher now uses /usr/bin/margine-docs-open: it opens the live docs when /healthz responds and falls back to /usr/share/margine/offline-docs/index.html offline.

Added (2026-06-07) — ujust margine-ai (optional local-AI workflow)

  • New ujust margine-ai recipe in build_files/60-custom.just installs Alpaca (com.jeffser.Alpaca) — a Flatpak GUI for local LLMs that bundles its own Ollama backend. No host install, no daemon-running, models downloaded on demand. Recipe also prints distrobox setup pointer for RamaLama CLI power users. ujust margine-ai-remove reverses it.
  • README "What you get" gets a 🤖 Optional AI workflow row.
  • Spec yaml (margine-fedora-atomic/declarations/margine-atomic.yaml) gets a new top-level ai_workflow: section documenting the opt-in model, recommended starter models (llama3.1:8b / qwen2.5-coder:7b / mistral:7b / phi3.5:3.8b), and hardware floor (8 GB VRAM comfort, 16 GB RAM minimum for CPU-only).

Added (2026-06-07) — ujust margine-gaming-native (RPM-layered gaming)

  • New ujust margine-gaming-native recipe layers Steam + Lutris + RetroArch as native RPMs from RPM Fusion (Heroic / Bottles / Protontricks / ProtonPlus stay Flatpak — no official RPM upstream). For users needing maximum Proton/Wine compatibility — anti-cheat (EAC / BattlEye), VR, Steam Link, NVIDIA proprietary + Mesa-git side-by-side. Cost: +30-60s per bootc upgrade to re-apply the larger layer.
  • Default Flatpak ujust margine-gaming stays unchanged for occasional gamers.
  • README Option C section rewritten to document both paths with the explicit trade-off. Spec yaml gaming_runtime.opt_in now has default: and native: sub-keys.
  • Inspired by RakuOS's "Native Gaming. Not Flatpak." stance — same trade-off, kept as opt-in second path so the default Margine experience stays upgrade-friendly.

Documentation (2026-06-07) — ADR 0007: Sealed Bootable Container Images tracker

  • margine-fedora-atomic/docs/adr/0007-sealed-bootable-images-tracker.md: long-form ADR tracking Fedora's sealed bootable container images direction (systemd-boot + UKI + composefs/fs-verity, Secure-Boot- signed end-to-end). Covers 5 action triggers + 9-step migration plan for when production stable arrives (~6-12 months).
  • margine-fedora-atomic/scripts/check-upstreams.sh watchlist gets travier/fedora-atomic-desktops-sealed so the monthly cron flags activity in the test-image repo.
  • Tracker issue #32 on margine-fedora-atomic with checkbox list of triggers + steps.

Removed (2026-06-06) — Margine Gaming ISO + OCI variant retired

  • ghcr.io/.../margine-gaming:stable OCI image — no longer built or published. The dedicated build-gaming.yml workflow, the Containerfile.gaming, the build_files/gaming/ directory, and installer/flatpaks-gaming are all deleted.
  • Gaming Anaconda ISObuild-disk.yml no longer matrixes over margine + margine-gaming; only the single margine ISO is built and uploaded to Internet Archive. No more margine-gaming-anaconda-iso-YYYYMMDD items.
  • Option C — Switch between Margine and Margine Gaming install section in README — replaced with Option C — Add the gaming layer (one ujust margine-gaming step on top of base Margine).
  • Rationale: same gaming stack reachable from base Margine via the already-existing ujust margine-gaming recipe (rpm-ostree layer + Flatpaks). Two parallel paths to the same gaming setup was extra surface area to maintain — separate ISO build (60 min CI), separate IA upload (~6 GB / build), separate Containerfile, separate preinstall list, separate ISO download UI on the site. Keeping only the ujust path cuts that whole pipeline. Trade-off: the result is a layered (not ostree-canonical) deployment, which is the same trade-off the recipe already had before this change.

Added (2026-06-03)

  • 11 GNOME core Flatpaks added to the preinstall set (Calculator, Calendar, clocks, Contacts, Weather, Maps, TextEditor, baobab, Characters, Logs, font-viewer). Closes the visible gap "the standard GNOME utility set isn't here" against a vanilla Fedora Silverblue install — Silverblue ships these as RPM in /usr, Bluefin DX intentionally strips them, so we restore the set as Flatpaks (atomic-friendly, ~120 MB cumulative thanks to shared org.gnome.Platform runtime). EXPECTED_FLATPAKS in margine-fedora-atomic updated in lockstep.

Added (2026-06-02, part 2)

  • 9 Flatpaks added to the preinstall set (Thunderbird ESR, GNOME Snapshot/Showtime/Papers/Loupe/SoundRecorder, Blanket, Fragments, Pinta). The previous list was an incomplete starter set — users on a fresh install were surprised to find no camera / video player / PDF reader / image viewer / sound recorder / mail client (the latter despite being declared as the system mail handler in declarations/margine-atomic.yaml). The validator's EXPECTED_FLATPAKS in margine-fedora-atomic is updated in lockstep so the post-boot acceptance test catches any regression on this set.

Added (2026-06-02)

  • Margine Gaming OCI variant — a separate, signed image at ghcr.io/daniel-g-carrasco/margine-gaming:stable. Built FROM the already-validated margine:stable and adds the gaming host stack (gamescope, MangoHud, vkBasalt, GameMode, goverlay, steam-devices, input-remapper, tuned, tuned-ppd, rom-properties-gtk) at image-build time plus a Flatpak preinstall list (Steam, Lutris, Heroic, Bottles, Protontricks, ProtonUp-Qt, RetroArch). End-user switch: sudo bootc switch ghcr.io/daniel-g-carrasco/margine-gaming:stable. Identifies itself as VARIANT_ID=gaming, PRETTY_NAME="Margine Gaming". Files: Containerfile.gaming, build_files/gaming/{install.sh, stamp-os-release.sh,margine-gaming.preinstall}.
  • build-gaming.yml workflowbuild_push → sign → promote_to_stable → notify. Triggers on workflow_dispatch, workflow_run after a successful Smoke-boot published image (so the variant rebuilds automatically when a new base :stable is promoted), and weekly Sun 05:00 UTC. No MOK secrets needed: the kernel is already signed in the base layer. Promotes :candidate → :stable immediately after signing (the base was smoke-booted; the variant only adds RPMs + Flatpak declarations, no boot-path changes that warrant a second 25-min QEMU test).
  • build-disk.yml matrix on image — produces 4 disk artifacts in parallel (margine + margine-gaming × qcow2 + anaconda-iso) and publishes both ISOs to Internet Archive under per-variant identifiers (margine-anaconda-iso-YYYYMMDD, margine-gaming-anaconda-iso-YYYYMMDD).
  • RPMFusion enabled in the gaming variant — the base image strips RPMFusion after using it transiently for the CachyOS kernel install; the gaming variant re-enables free + nonfree and keeps them, since the entire gaming RPM stack lives there and users will need the same repo set for dnf upgrade / rpm-ostree upgrade.
  • Trade-off note in ujust margine-gaming — the existing ujust recipe (rpm-ostree overlay) now prints, before its confirmation prompt, what the layering choice implies (LayeredPackages branch, slower upgrades, occasional file-conflict rebases) and points users to the variant image as the ostree-canonical alternative.

Added (2026-06-01)

  • Candidate → stable promotion model: build.yml now publishes only :candidate + :candidate.YYYYMMDD; smoke-boot.yml boots that candidate in QEMU and only on success skopeo copy --preserve-digests to :stable + :stable.YYYYMMDD + :YYYYMMDD. Eliminates the class of "build green, boot red" leaks.
  • Layer A systemd-analyze verify default.target: ordering-cycle detection at build time, catches regressions like the one that put a deployment into emergency.target on 2026-06-01.
  • Pre-build GHCR login: authenticated base-image pull (5000 req/h instead of 100/h anonymous), fixes intermittent 403 on bluefin-dx:stable after cache reset.
  • OCI archive intermediate for the move-to-root-storage step (replaces the podman save | sudo podman load pipe which corrupted blobs under memory pressure on the degraded-ZFS host).
  • build-disk.yml: ISO + qcow2 builder, publishes via Internet Archive (torrent + 3 HTTP mirrors, seeded forever) + HTML index on files.the-empty.place. No origin upload bandwidth for binaries.
  • ntfy push notifications: build/smoke-boot/disk-build outcomes
    • click-to-open-run URL. Topic via NTFY_TOPIC_URL secret.
  • margine-staleness.timer + margine-upgrade-notify.service: client-side awareness of stale upstream and post-upgrade events, installed via /etc/skel user-systemd.
  • margine-configure-zen-browser: per-profile user.js setting DuckDuckGo as default search engine.
  • GNOME extensions added: o-tiling (binary-tree auto-split, replaces Tiling Shell as default tiling), Hide Cursor, Caffeine.
  • build_files/build.sh now stamps /usr/lib/os-release with Margine identity (NAME=Margine, ID=margine, VARIANT_ID=margine, ID_LIKE="fedora bluefin"). This makes cat /etc/os-release, hostnamectl, and GNOME About all report "Margine", and lets margine-validate-atomic-layout succeed on the actual deployment.

Changed (2026-06-01)

  • System-wide Flatpak preinstall moved from /etc/ublue-os/system-flatpaks.list (legacy uBlue path, no longer honored by Bluefin) to /usr/share/flatpak/preinstall.d/margine-defaults.preinstall (systemd's standard preinstall API).
  • configure-gnome-extensions is now replace-style rather than additive: builds the full enabled-extensions list from the declaration and writes it directly via gsettings set, dropping anything no longer declared (e.g. tilingshell after the switch to o-tiling). Uses an on-disk presence check rather than gnome-extensions list (which only reflects the running shell).
  • margine-seed-etc-passwd.service ordering: After=local-fs-pre. target (was local-fs.target → ordering cycle → emergency.target).
  • Plymouth + boot fallback colors: pure black #000000 background everywhere (was warm brown).
  • GDM logo: empty string (was a 2400x700 banner image that got upscaled fullscreen by GNOME 50 greeter).
  • App folders: 6 folders (Office / Graphics / Photography / Audio / Video / System). The folder set started as Italian-labeled (Grafica/Foto/Sistema) and was renamed to English on 2026-06-01 so existing in-the-wild deployments may briefly show either set until configure-gnome-app-folders runs again.

Changed

  • Dropped the kitty Flatpak preinstall (build.sh) and the kitty default-terminal gschema override. Bluefin's Ptyxis stays as default.
  • gschema favorite-apps updated to org.gnome.Ptyxis.desktop.

Notes (carried over from prior unreleased state)

  • custom-kernel/install.sh installs sbsigntools up-front so sbsign is available when signing vmlinuz (fixed exit 127).
  • v4l2loopback is built best-effort; failures do not block the image (Universal Blue cache-mount limitation, documented inline).
  • mok-enroll.service is written + enabled; runs once at first boot, marks completion with /var/.mok-enrolled. Recovery procedure for a missed MOK Manager confirmation is documented in margine-fedora-atomic/docs/07-secure-boot-tpm2.md.

[Phase 1 — initial publish]

First successful build pushed to ghcr.io/daniel-g-carrasco/margine:stable (commit 74449fc, build 2026-05-26): Bluefin DX + MOK-signed CachyOS kernel + Margine Flatpak preinstalls + Margine GNOME defaults.