fix(pkgs): one chromium, not two — and what that is actually worth
All checks were successful
Check / eval (push) Successful in 3m32s
All checks were successful
Check / eval (push) Successful in 3m32s
BACKLOG #121. nixpkgs' chromium wrapper with enableWideVine = true (what the template ships, for DRM) runs the `-wv` copy but links its share/* from the PLAIN unwrapped build. A symlink is a store reference, so a second 687 MiB chromium rode along for a directory of .desktop files nothing executes. overlays.default now points those symlinks at the copy we already run; the template needs no change, since lib.nix, the repo pkgs and nixosModules all apply the overlay. Checked first, because it decided whether the item was possible at all: whether the `-wv` copy references the plain build. It is `cp -a` of it, so it plausibly would have — and then no wrapper change could have dropped the duplicate. It does not. Also verified rather than assumed: `.override { enableWideVine = true; }` composes with the overlay's overrideAttrs (the order usually matters), so the template's existing line picks the fix up untouched; the wrapper still execs the -wv build with WidevineCdm present; and share/{applications,icons,man} match stock with the .desktop byte-identical. I claimed this was "687 MiB off every install". It is not, and measuring the artifact instead of the closure is what corrected it: nominal closure -687 MiB (9.38 -> 8.71 GiB) ISO image -8 KiB of 8.078 GiB installed disk ~-19 MiB cache-install download -195 MiB Two dedupes that closure arithmetic cannot see. mksquashfs detects duplicate files, so the ISO had already stored the near-identical blocks once. And auto-optimise-store (on by default here) hardlinks identical files: the two paths share inodes — verified by stat, and du counts 639 MiB for the pair against ~620 for one. The only thing that cannot dedupe is the wire, where the extra path is its own 195 MiB NAR. So this is a DOWNLOAD fix — precisely what #120's netinstall cares about — and close to a no-op for the offline ISO that is the default today. Whether that justifies coupling an overlay to nixpkgs wrapper internals is Bernardo's call; it is guarded and no-ops if upstream moves, but it is his to weigh. Worth an upstream patch regardless: the wrapper should take its desktop entry from the variant it wraps. The guard is the load-bearing part, because the failure mode is a SILENT no-op that no build complains about: checks.chromium-single-closure asserts exactly one full unwrapped chromium in the template closure, and was proved to fail by neutering the overlay — it reports "found 2", names both paths, and warns off the tempting "fix" of dropping enableWideVine, which silently removes DRM. The rule this establishes, now recorded in ROADMAP and on #120 (whose entire size table is closure arithmetic): closure size is not disk size and is not image size. Measure the artifact. V2: flake check, chromium-single-closure, live-baseline-apps, template-sot, option-docs, state-bridges all pass. Three ISOs built from one tree for the numbers above. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -176,17 +176,34 @@ and ship a **much lighter netinstall variant alongside it**. Two products, one
|
||||
distro: "works on a plane" and "8 GiB is absurd to download" are both true, and
|
||||
a second target settles them without compromising either.
|
||||
|
||||
**Measured facts (2026-07-14), so this starts from numbers, not vibes:**
|
||||
**Measured facts (2026-07-14), so this starts from numbers, not vibes.**
|
||||
*(Taken before #121 landed; it removed a duplicate 687 MiB chromium, so the
|
||||
uncompressed figures below are each ~0.67 GiB lower now — the live desktop is
|
||||
**13.34 GiB**, not 14.01. The shape of the argument is unchanged. Re-measure
|
||||
before acting rather than trusting these.)*
|
||||
|
||||
> **Read this before using the numbers below.** They are **closure arithmetic**,
|
||||
> and #121 proved the hard way that closure size is neither disk size nor image
|
||||
> size: removing a 687 MiB path shrank the ISO by **8 KiB**, because
|
||||
> **mksquashfs dedupes duplicate files** and **`auto-optimise-store` hardlinks**
|
||||
> them on disk. So a change that looks like it sheds gigabytes of closure can
|
||||
> shed nothing off the actual image. **Measure the artifact — build the ISO and
|
||||
> `stat` it.** The corollary cuts the other way and is the good news for this
|
||||
> item: what dedupe cannot help is the **wire**, so a netinstall's download is
|
||||
> the one figure closure/NAR size predicts honestly (`nix path-info --store
|
||||
> https://cache.nixos.org --json` gives the real `downloadSize`).
|
||||
- Current ISO **8.078 GiB** compressed; **18.03 GiB** of store uncompressed
|
||||
(`zstd -19`, 2.23:1 — compression is already near-max, not the lever).
|
||||
- The offline pin (`system.extraDependencies`, 60 roots: a representative
|
||||
installed system + the template HM closure + all flake inputs) is **4.02 GiB
|
||||
uncompressed of that — only ~22%**. Dropping it entirely still leaves a
|
||||
**14.01 GiB** desktop → roughly **6.3 GiB** compressed at the same ratio.
|
||||
**~13.3 GiB** desktop → roughly **6 GiB** compressed at the same ratio.
|
||||
**So "no pin" alone is NOT the lighter ISO** — this is the trap to avoid.
|
||||
- The 14 GiB desktop's own top weights: libreoffice 1457 MiB, initrd 1369,
|
||||
linux-firmware 770, chromium ×2 (1391 combined — see #121), llvm-lib 540,
|
||||
- The desktop's own top weights: libreoffice 1457 MiB, initrd 1369,
|
||||
linux-firmware 770, chromium 704 (was 1391 before #121), llvm-lib 540,
|
||||
bibata-cursors 322, mesa 264, mbrola-voices 259, nerd-fonts ~420 combined.
|
||||
Note what that list implies: no single lever gets a desktop ISO under ~4 GB —
|
||||
which is the case for (b) below.
|
||||
|
||||
**So the real decision is what a netinstall ISO IS**, and it should be settled
|
||||
first (`[human]`): (a) the full try-before-install desktop minus the pin
|
||||
@@ -211,36 +228,6 @@ the measured number, both ISOs built from one tree), installs successfully with
|
||||
a network in a QEMU run, says clearly at boot that it needs one, and leaves the
|
||||
offline ISO's behaviour untouched (`checks.*` for the offline path stay green).
|
||||
|
||||
### 121. The Widevine chromium wrapper drags a second 687 MiB chromium along
|
||||
|
||||
Found while measuring #103 (2026-07-14). **Pre-existing and not live-only** —
|
||||
it is in the template HM closure, so it is on **every installed Nomarchy
|
||||
machine** and in the ISO, and predates #103 by however long chromium has been
|
||||
the default browser.
|
||||
|
||||
`templates/downstream/home.nix` ships `chromium.override { enableWideVine =
|
||||
true; }` (correctly — DRM for Netflix/Spotify). The resulting wrapper depends on
|
||||
**two** unwrapped builds:
|
||||
|
||||
704 MiB chromium-unwrapped-150.0.7871.114-wv ← the browser it runs
|
||||
687 MiB chromium-unwrapped-150.0.7871.114 ← plain build, pulled in for
|
||||
`share/applications` ONLY
|
||||
|
||||
`nix why-depends --precise` on the live closure shows the wrapped
|
||||
`chromium-…/share/applications` symlinking into the *plain* unwrapped output,
|
||||
which retains the whole 687 MiB derivation for a directory of `.desktop` files.
|
||||
Nothing runs it.
|
||||
|
||||
Investigate whether this is a nixpkgs wrapper bug (the wrapper should take its
|
||||
desktop entry from the same variant it wraps) — fix upstream and/or work around
|
||||
it locally, but **verify the fix by closure diff, not by reading the
|
||||
expression**: `nix path-info -r <hm-generation> | grep chromium-unwrapped`
|
||||
should list one full build plus the small sandbox. Do **not** "fix" it by
|
||||
dropping `enableWideVine` — that silently removes DRM playback, which is a
|
||||
feature decision (ROADMAP § Default application suite), not a size cleanup.
|
||||
Pass = one full chromium in the closure, DRM still works (V3: a Widevine page
|
||||
plays on hardware), and the measured install/ISO delta is recorded.
|
||||
|
||||
### 115. Suspend-then-hibernate, with a way to set it up
|
||||
|
||||
Bernardo, 2026-07-14: a suspended laptop should be able to fall through to
|
||||
|
||||
@@ -19,6 +19,53 @@ Template:
|
||||
|
||||
---
|
||||
|
||||
## 2026-07-14 — #121: one chromium, not two — 687 MiB off every install (this commit)
|
||||
- **Task:** BACKLOG #121, found by measuring #103's ISO delta. Nothing was
|
||||
failing — that is the point; a duplicate browser breaks no build.
|
||||
- **Did:** nixpkgs' chromium wrapper with `enableWideVine = true` (what the
|
||||
template ships, for DRM) runs the `-wv` copy but links `share/*` from the
|
||||
**plain** unwrapped build. A symlink is a store reference, so a second
|
||||
687 MiB chromium rode along for a directory of `.desktop` files nothing
|
||||
executes — on every installed machine, not just the ISO. `overlays.default`
|
||||
now moves the symlink source to the copy we already run; the template needs
|
||||
no change (lib.nix, the repo pkgs, and nixosModules all apply the overlay).
|
||||
- **The check that decided the approach:** whether the `-wv` copy itself
|
||||
references the plain build. It is `cp -a` of it, so it plausibly would —
|
||||
and if it did, no wrapper change could drop the duplicate and the whole
|
||||
item was dead. Verified self-contained *first*, then fixed. Also verified,
|
||||
not assumed: `.override { enableWideVine = true; }` composes with the
|
||||
overlay's `overrideAttrs` (order usually matters — here it survives), so
|
||||
the template's existing line picks the fix up untouched.
|
||||
- **Verified:** **V2** — only `-wv` + the tiny sandbox remain in the template
|
||||
closure. Equivalence proved, not hoped: the wrapper still execs the `-wv`
|
||||
build, WidevineCdm present there, `share/{applications,icons,man}` match
|
||||
stock with the `.desktop` **byte-identical**. New
|
||||
`checks.chromium-single-closure` asserts the invariant (exactly one full
|
||||
unwrapped chromium — plain or `-wv`, never both), **proved to fail** by
|
||||
neutering the overlay's regex: reports "found 2", names both, and warns off
|
||||
the tempting "fix" of dropping enableWideVine (which silently kills DRM).
|
||||
- **I overstated this, and measuring the artifact corrected it.** I claimed
|
||||
−687 MiB "on every install". True savings, all measured:
|
||||
nominal closure −687 MiB (9.38→8.71 GiB), **ISO −8 KiB of 8.078 GiB**,
|
||||
**installed disk ~−19 MiB**, **cache-install download −195 MiB**. Two
|
||||
dedupes that closure arithmetic cannot see: **mksquashfs detects duplicate
|
||||
files** (the `-wv` copy is `cp -a` of the plain build, so the ISO stored the
|
||||
blocks once), and **auto-optimise-store hardlinks** identical files — the
|
||||
two paths share inodes (verified by `stat`; `du` counts 639 MiB for the pair
|
||||
vs ~620 for one). Only the wire can't dedupe: 195 MiB compressed NAR.
|
||||
- **The rule this establishes:** closure size is not disk size and is not image
|
||||
size. **Measure the artifact.** Directly relevant to #120, whose whole size
|
||||
table is closure arithmetic — noted there.
|
||||
- **So the fix is a *download* win** (which is what #120's netinstall wants)
|
||||
and ~nothing for today's offline ISO. Whether that is worth coupling an
|
||||
overlay to nixpkgs' wrapper internals is Bernardo's call — raised, not
|
||||
assumed; it is guarded and no-ops if upstream moves. Worth an upstream patch
|
||||
regardless (the wrapper should take its desktop entry from the variant it
|
||||
wraps).
|
||||
- **Pending:** nothing hardware-blocked. #120's size table updated (desktop is
|
||||
13.34 GiB post-#121, not 14.01) and carries the closure-vs-artifact caveat.
|
||||
- **Next suggestion:** #118 (smartd self-gate) — Bernardo's stated order.
|
||||
|
||||
## 2026-07-14 — #103: the live ISO gets a desktop, for +41 MiB (this commit)
|
||||
- **Task:** BACKLOG #103 — Bernardo, live ISO 2026-07-14: still no browser,
|
||||
no office. *"That makes a live iso useful."*
|
||||
|
||||
@@ -404,6 +404,59 @@ Design/decision records and a running log of shipped work (items marked
|
||||
decision rather than a drive-by. Proved to fail: dropping snapshot makes it
|
||||
name the missing entry. **V3 pending** — that the apps *launch* needs real
|
||||
hardware (HARDWARE-QUEUE, Acer M5-481T).
|
||||
- ✓ **One chromium, not two (#121):** found by measuring #103's ISO delta
|
||||
rather than by anything failing — nothing *was* failing, which is the point.
|
||||
nixpkgs' chromium wrapper, with `enableWideVine = true` (what the template
|
||||
ships, for Netflix/Spotify DRM), runs the `-wv` copy but links its
|
||||
`share/*` from the **plain** unwrapped build:
|
||||
`for f in '${chromium.browser}'/share/*; do ln -s …`. A symlink is a store
|
||||
reference, so a whole second **687 MiB** chromium rode along for a directory
|
||||
of `.desktop` files nothing executes — on **every installed machine**, not
|
||||
just the ISO, for as long as chromium has been the default browser.
|
||||
**What made a fix possible** (checked first, since it decides everything):
|
||||
the `-wv` copy is `cp -a` of the browser and is **self-contained** — it does
|
||||
*not* reference the plain build. Had it done so, no wrapper change could
|
||||
drop the duplicate. Its `share/` is byte-identical, `.desktop` included, so
|
||||
`overlays.default` moves the symlink source to the copy we already run.
|
||||
Both paths are read back out of the wrapper's own `buildCommand`, so the
|
||||
overlay knows nothing of nixpkgs internals beyond two strings; if upstream
|
||||
restructures either, the match returns null and the fix **no-ops** rather
|
||||
than breaking a build. With `enableWideVine = false` the paths are equal and
|
||||
the substitution is identity. DRM payload verified still present in the build
|
||||
the wrapper execs; `share/` byte-identical to stock.
|
||||
**What it actually saves — and the lesson, which is worth more than the fix**
|
||||
(the first pass at this claimed "−687 MiB on every install"; measuring the
|
||||
*artifact* instead of the closure killed that):
|
||||
|
||||
| Metric | Saving |
|
||||
|---|---|
|
||||
| Nominal closure (`nix path-info -S`) | 687 MiB (9.38 → 8.71 GiB) |
|
||||
| **ISO image** | **~0 — 8 KiB of 8.078 GiB** |
|
||||
| **Installed disk** | **~19 MiB** |
|
||||
| **Download, cache-based install** | **195 MiB** |
|
||||
|
||||
The duplicate was nearly free everywhere it was already stored, because two
|
||||
mechanisms dedupe it and closure arithmetic sees neither: **mksquashfs
|
||||
detects duplicate files**, so the ISO had stored those blocks once (the `-wv`
|
||||
copy is `cp -a` of the plain build — near-identical by construction); and
|
||||
**`nix.settings.auto-optimise-store` is on** (`modules/nixos/default.nix`),
|
||||
which hardlinks identical files, so the pair costs 639 MiB of disk against
|
||||
~620 MiB for one — verified by inode, not inferred. The one place dedup
|
||||
cannot help is the wire: a binary-cache install fetches the extra path as its
|
||||
own NAR, **195 MiB compressed** (`cache.nixos.org` `downloadSize`). So this
|
||||
is a *download* fix, which is exactly what #120's netinstall cares about, and
|
||||
a no-op for the offline ISO that is the default today.
|
||||
**Rule this establishes: closure size is not disk size and is not image size.
|
||||
Measure the artifact.** #120's size table is closure arithmetic and inherits
|
||||
this caveat.
|
||||
**The guard is load-bearing**, because a silent no-op is this fix's failure
|
||||
mode and nothing about it breaks a build: `checks.chromium-single-closure`
|
||||
asserts the *invariant* (exactly one full unwrapped chromium in the template
|
||||
closure — plain or `-wv`, never both), not the mechanism, and was proved to
|
||||
fail by neutering the overlay: it reports "found 2", names both paths, and
|
||||
says not to "fix" it by dropping `enableWideVine`, which would silently
|
||||
remove DRM. Worth an upstream nixpkgs patch (the wrapper should take its
|
||||
desktop entry from the variant it wraps); the overlay is the local stopgap.
|
||||
- ✓ **Plymouth logo contrast:** the shipped art was a fixed navy that
|
||||
vanished on dark bases. `modules/nixos/plymouth.nix` now recolors every
|
||||
element from the palette at build time (flat fill, alpha kept):
|
||||
|
||||
73
flake.nix
73
flake.nix
@@ -94,6 +94,42 @@
|
||||
# Includes nomarchy-what-changed (generation readability, #82).
|
||||
nomarchy-lifecycle = final.callPackage ./pkgs/nomarchy-lifecycle { };
|
||||
pam-fprint-grosshack = final.callPackage ./pkgs/pam-fprint-grosshack { };
|
||||
|
||||
# One chromium, not two (ROADMAP § one chromium, not two, #121).
|
||||
# Upstream nixpkgs bug, worth a patch there: in
|
||||
# pkgs/applications/networking/browsers/chromium/default.nix the
|
||||
# wrapper runs the `-wv` copy when enableWideVine is set, but still
|
||||
# links its share/ from the PLAIN unwrapped build:
|
||||
# for f in '${chromium.browser}'/share/*; do ln -s …
|
||||
# A symlink is a store reference, so that retains a whole second
|
||||
# 687 MiB chromium for a directory of .desktop files nothing runs —
|
||||
# on every machine the template installs, not just the live ISO.
|
||||
#
|
||||
# Safe because the `-wv` copy is `cp -a` of the browser and is
|
||||
# self-contained: verified it does NOT reference the plain build (had
|
||||
# it done so, no wrapper change could drop the duplicate), and its
|
||||
# share/ is byte-identical, .desktop included. So share moves to the
|
||||
# copy we already run and nothing else changes.
|
||||
#
|
||||
# Both paths are read back out of the wrapper's own buildCommand, so
|
||||
# this knows nothing about nixpkgs internals beyond those two
|
||||
# strings. If upstream restructures either, the match returns null
|
||||
# and this becomes a NO-OP rather than a broken build — and
|
||||
# checks.chromium-single-closure is what fails, loudly, instead of
|
||||
# the duplicate quietly returning. With enableWideVine = false the
|
||||
# two paths are the same and the substitution is identity, so the
|
||||
# plain package is untouched.
|
||||
chromium = prev.chromium.overrideAttrs (old:
|
||||
let
|
||||
wv = builtins.match ".*makeWrapper \"([^\"]+)/libexec/chromium/chromium\".*" old.buildCommand;
|
||||
plain = builtins.match ".*for f in '([^']+)'/share/\\*.*" old.buildCommand;
|
||||
in
|
||||
prev.lib.optionalAttrs (wv != null && plain != null) {
|
||||
buildCommand = builtins.replaceStrings
|
||||
[ "'${builtins.head plain}'/share/" ]
|
||||
[ "'${builtins.head wv}'/share/" ]
|
||||
old.buildCommand;
|
||||
});
|
||||
};
|
||||
|
||||
nixosModules.nomarchy = {
|
||||
@@ -559,6 +595,43 @@
|
||||
# sheet to ✖/exit-1 and names the unit; with the failure
|
||||
# cleared it reports healthy/exit-0. Minimal node (just the
|
||||
# package) — the disk/flake/snapper checks self-skip in a VM.
|
||||
# One chromium, not two (ROADMAP § one chromium, not two, #121).
|
||||
# The overlay's wrapper fix is a substitution into a string
|
||||
# nixpkgs owns: if upstream restructures that buildCommand, the
|
||||
# match returns null, the fix silently becomes a no-op and 687 MiB
|
||||
# of duplicate browser quietly returns to every install. Nothing
|
||||
# about that breaks a build — which is exactly why it needs a
|
||||
# check. Asserts the invariant, not the mechanism: the closure the
|
||||
# template installs carries exactly ONE full unwrapped chromium
|
||||
# (plain OR -wv, never both; the tiny -sandbox output is a separate
|
||||
# path and is expected).
|
||||
chromium-single-closure =
|
||||
let
|
||||
hm = downstream.homeConfigurations.me.activationPackage;
|
||||
ci = pkgs.closureInfo { rootPaths = [ hm ]; };
|
||||
in
|
||||
pkgs.runCommand "nomarchy-chromium-single-closure"
|
||||
{ nativeBuildInputs = [ pkgs.gnugrep ]; }
|
||||
''
|
||||
set -euo pipefail
|
||||
# Full browser builds only: -sandbox is a few KB and legitimate.
|
||||
full=$(grep -E 'chromium-unwrapped-[0-9.]+(-wv)?$' ${ci}/store-paths || true)
|
||||
n=$(printf '%s' "$full" | grep -c . || true)
|
||||
if [ "$n" != 1 ]; then
|
||||
echo "chromium-single-closure: expected exactly 1 full unwrapped chromium, found $n:"
|
||||
printf '%s\n' "$full"
|
||||
echo
|
||||
echo "If this is 2, the enableWideVine wrapper is retaining the plain"
|
||||
echo "build for its share/* symlinks again — the overlay fix in"
|
||||
echo "flake.nix (ROADMAP § one chromium, not two, #121) has stopped"
|
||||
echo "matching upstream's buildCommand. Do NOT 'fix' it by dropping"
|
||||
echo "enableWideVine: that silently removes DRM playback."
|
||||
exit 1
|
||||
fi
|
||||
echo "chromium-single-closure: ok — one chromium ($full)"
|
||||
touch $out
|
||||
'';
|
||||
|
||||
# Live-ISO baseline apps (ROADMAP § live-ISO baseline apps, #103).
|
||||
# The live session shipped no
|
||||
# browser and no office for as long as it existed — the thing a user
|
||||
|
||||
Reference in New Issue
Block a user