Repository navigation
feat(thumbnailer): add opt-in ujust toggle for the ffmpeg thumbnailer daemon - #1234
sramkrishna wants to merge 6 commits into
Conversation
|
CI is red at 66b9089, and both failures come from this PR, not from main. Other PRs on the same main (for example #1230 at 068a7c5) passed both jobs this morning.
I reproduced the second one locally: on a machine with podman installed, The rest of the diff reads well to me. The unit names match what #1226 ships ( I have not tested the mask on a real system with #1226 installed, so I can't yet confirm that masking the quadlet-generated units stops the image pull. |
hanthor
left a comment
There was a problem hiding this comment.
- CI is red: bats reports
not ok 39 status-ffmpeg-thumbnailer: degrades when podman is absent, and pre-commitend-of-file-fixermodified files. - This depends on #1226, which isn't merged and has open changes requested.
shared.just"Disable" masks the units but leavesenvironment.d/10-ffmpeg-thumbnailer.confin effect, so the shim still owns video MIME types. That makes the "video thumbnails fall back to the in-sandbox thumbnailer" message untrue: without host ffmpeg, thumbnails will just fail. Disable needs to remove or override the env drop-in too.- There are also conflicts with #1190 in
shell-scripts/SKILL.mdanddocs/skills/index.json.
|
Status update: |
castrojo
left a comment
There was a problem hiding this comment.
I checked whether this can land ahead of #1226. It can't, as far as I can see.
Dependency on #1226. On current main (12e3114), git grep -i ffmpeg matches nothing. None of the units toggle-ffmpeg-thumbnailer / status-ffmpeg-thumbnailer operate on exist yet: ffmpeg-thumbnailer-daemon.service, and ffmpeg-thumbnailer.service / ffmpeg-thumbnailer-nvidia.service, which quadlet generates from the .container files. Neither do 01-ffmpeg-thumbnailer.preset or environment.d/10-ffmpeg-thumbnailer.conf. #1226 adds all of them, and it is on hold with changes requested. If this merged first, users would get a ujust recipe that masks and unmasks units that aren't there. Please keep this on hold until #1226 lands, or until its unit and drop-in names are final, then rebase.
CI failures, both caused by this PR (main is green for both workflows):
test(run 36099836930):not ok 39 status-ffmpeg-thumbnailer: degrades when podman is absentfails attests/test_shared_just.bats:557. The recipe output doesn't containpodman is not installedwhen podman is missing from PATH. Either the status recipe prints a different message on that path, or the stubbed PATH still resolves a podman. Please fix the recipe to match the intended behavior rather than loosening the assertion.validate(run 36099836919):end-of-file-fixerrewrotetests/test_shared_just.bats, which is missing its final newline.pre-commit run --files tests/test_shared_just.batsfixes it.
hanthor's review is still open, and I agree with it. The main point is correctness: the disable path in shared.just masks the units but leaves usr/lib/environment.d/10-ffmpeg-thumbnailer.conf in effect. The shim therefore still owns the video MIME types, and the message "video thumbnails fall back to the in-sandbox thumbnailer" is wrong. On hosts without ffmpeg, thumbnails will just fail. Disable needs to override that drop-in for the user, for example with a same-named file in ~/.config/environment.d/ that resets the variables, and enable needs to remove the override. Note that environment.d changes only take effect at the next login, so the message should say so. The tests should assert both the override and its removal.
Conflicts. The PR is CONFLICTING with main, including #1190's changes to docs/skills/shell-scripts/SKILL.md and docs/skills/index.json. Both this PR and #1226 also edit .github/workflows/unit-tests.yml. I didn't push a rebase: the commit touches a workflow file, and the fix for the env drop-in depends on what #1226 finally ships. The author will need to do the rebase once #1226 is settled.
The direction is right: an opt-out for a default-on 111 MB container is worth having. Outstanding: #1226 must land first, then the author needs to rebase and address hanthor's changes-requested review (env drop-in on disable, the bats failure, EOF, conflicts).
Danathar
left a comment
There was a problem hiding this comment.
Following up on my 25 Sep comment with a patch I tested. In the two tests that delete stubs, pass PATH="${WORKDIR}/bin" to _run_thumbnailer, e.g. _run_thumbnailer status-thumbnailer.sh PATH="${WORKDIR}/bin" XDG_CACHE_HOME="${WORKDIR}/cache" at line 554, and the same with MOCK_STATE_FAIL=1 at line 577. env takes the later PATH, and the status recipe needs nothing outside bash builtins and the stubs. With that and the trailing blank line removed, bats tests/test_shared_just.bats passes 42/42 on a machine that has /usr/bin/podman. When you rebase: main already runs this file in its "Run bats (shared.just)" step (#1249), so drop the step this PR adds to unit-tests.yml or it runs twice. The skill-index conflicts go away by rerunning scripts/generate_skill_index.py --write.
|
Status at head 66b9089: blocked on #1226. The units, preset and Once #1226 is settled, @sramkrishna, these are the mechanical items for one push:
Both red checks ( |
Addresses review feedback on PR #1226 (hanthor CHANGES_REQUESTED, Danathar review). Opt-in rollout (hanthor's default-on concern #1): the thumbnailer no longer turns on for every user on every image. Removing the three default-on mechanisms Danathar specified: - delete user-preset/01-ffmpeg-thumbnailer.preset (no auto-enable), - delete the static graphical-session.target.wants symlink, - drop WantedBy=default.target from both *.container units, leaving them static so neither container starts at boot. ManagedOOM key (Danathar): ManagedOOMMemory=kill is not a systemd key and warned on every unit. Renamed to ManagedOOMMemoryPressure=kill in the two container units and the daemon service. Still open, flagged to maintainers (need a decision or hardware/ version testing, not guessable here): - environment.d MIME shadowing (hanthor #3): the global XDG_DATA_DIRS prepend stays and still hides gst for non-opt-in users; gating it behind opt-in is a separate decision. - FFT_HWACCEL is never set (daemon defaults to "none"); NVIDIA decode path is untested without hardware. - podman 5.8 quadlet location: /usr/share/containers/systemd/users is parsed as root system units on 5.8; needs a 5.8-readable shipped location or a version gate. - Opt-in enablement: the daemon lacks Wants= on the container units, so the ujust toggle (#1234) must start the container unit too.
… daemon
The rootless ffmpeg video thumbnailer ships enabled for every graphical
session through its user preset. That is the wrong default for constrained
systems, metered connections (the container image is 111 MB), and hosts that
already have a working hardware thumbnailer.
Add two recipes to shared.just:
- toggle-ffmpeg-thumbnailer: `enable` / `disable` / `cancel` ACTION plus an
interactive gum prompt. Disable stops the units and then masks all three
(daemon and both container quadlets); enable unmasks, reloads, and starts
them again.
- status-ffmpeg-thumbnailer: read-only report of unit state, container,
daemon socket, and recent journal activity.
Mask, not disable. The daemon is pulled in by a static
graphical-session.target.wants symlink shipped in /usr/lib, which
`systemctl --user disable` cannot remove, and the container units are
quadlet-generated so they carry no install state for systemctl to edit.
Both recipes probe for the daemon unit before touching anything, so images
that do not ship the thumbnailer (Aurora) report "not installed" instead of
masking units that do not exist.
Tests: 28 new bats cases in tests/test_shared_just.bats stub systemctl,
podman, journalctl, and gum, and run the extracted recipe bodies so the
control flow is exercised rather than grepped. tests/test_shared_just.bats
is now wired into unit-tests.yml, which never ran it before.
Docs: new docs/skills/systemd-user-units.md records the mask-vs-disable
rule for image-shipped systemd user units and quadlets;
shell-scripts/references/bats-patterns.md gains the name-anchored recipe
extraction pattern and the `{{ }}` interpolation gotcha.
Hive-Run: projectbluefin#1229
Hive-Plan: ujust toggle for ffmpeg thumbnailer daemon (no plan artifact supplied)
Hive-Spec: projectbluefin#1229 (no spec artifact supplied)
Co-Authored-By: Claude Code <noreply@anthropic.com>
Assisted-by: Claude Code (deepseek-v4.1-flash) via litellm
Signed-off-by: sramkrishna <sramkrishna@users.noreply.github.com>
66b9089 to
42930dc
Compare
|
Rebased onto main and fixed the test issues on head
PR remains blocked on the upstream architectural rollout decision on PR #1226 (systemd units and drop-in configuration). |
|
Re-checked at 42930dc against my review at 66b9089. The PATH fix and the end-of-file fix are in, the extra #1226 went opt-in at dd9be26: no preset, and no
The |
Masking the units left /usr/lib/environment.d/10-ffmpeg-thumbnailer.conf in effect, so the shim stayed first in XDG_DATA_DIRS for video MIME types and thumbnails failed instead of falling back. Disable now writes a same-named user drop-in in ~/.config/environment.d (which overrides the system one); enable removes it. The message notes it applies at next login. Per hanthor's review. Assisted-by: Claude via omp Signed-off-by: castrojo <castrojo@users.noreply.github.com>
|
Addressed hanthor's third point in b56ccbf. "Disable" masked the units but left |
There was a problem hiding this comment.
Reviewed at head b56ccbf.
correctness
system_files/shared/usr/share/ublue-os/just/shared.just:121: 🔴 bug:SOCKET_PATHdefaults to…/gstreamer-1.0/ffmpeg-thumbnailer.sock, but the daemon from #1226 (headd30d404,usr/libexec/ffmpeg-thumbnailer/ffmpeg-thumbnailer-daemon,SOCK_PATH = os.path.join(GST_CACHE_DIR, "ffmpeg-thumbnailer", "sock")) binds…/gstreamer-1.0/ffmpeg-thumbnailer/sock.status-ffmpeg-thumbnailerwill always print "missing (daemon not running)" on a real install. Tests pass only becausetests/test_shared_just.bats_SOCKET_RELmirrors the recipe's wrong path, not the daemon's. Fix: default to${XDG_CACHE_HOME:-${HOME}/.cache}/gnome-desktop-thumbnailer/gstreamer-1.0/ffmpeg-thumbnailer/sockand update_SOCKET_REL.
docs-currency
docs/skills/systemd-user-units.md:55,63-64,72,117andshared.just:79-81: describe a shippedusr/lib/systemd/user-preset/01-ffmpeg-thumbnailer.presetand a staticgraphical-session.target.wants/ffmpeg-thumbnailer-daemon.servicesymlink as the reasonmaskis required. Neither exists onmainatb56ccbfnor in #1226's file list; the daemon unit has only[Install] WantedBy=graphical-session.target default.target. Mask is still the right verb (quadlet units have no install state), but the doc/comment rationale points at files that do not exist. Rewrite aroundWantedBy=+ quadlet generator, or drop the preset/wants claims.
intent-alignment
- PR body "Testing": "The suite is now wired into
.github/workflows/unit-tests.yml… no CI step ran it."unit-tests.yml:201andJustfile:48already runtests/test_shared_just.batsonmain; the diff touches neither file. Body overstates the change; no action needed beyond correcting the description.
No findings from: security, style.
Confidence: 3/5 (needs attention) — 2 medium findings
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
…t the unit docs `status-ffmpeg-thumbnailer` defaulted SOCKET_PATH to .../gstreamer-1.0/ffmpeg-thumbnailer.sock, but the daemon binds .../gstreamer-1.0/ffmpeg-thumbnailer/sock (GST_CACHE_DIR + "ffmpeg-thumbnailer" + "sock"), so the report always said "missing (daemon not running)". The bats helper mirrored the same wrong path, so the suite could not catch it. Fix both and pin the default with a regression test that greps the extracted recipe body. docs/skills/systemd-user-units.md described a usr/lib/systemd/user-preset/01-ffmpeg-thumbnailer.preset file and a static graphical-session.target.wants symlink. Neither is shipped: the daemon unit only carries [Install] WantedBy=graphical-session.target default.target and the container units are quadlet-generated with no [Install] at all. Rewrite the enable/disable rationale around what is actually in the tree. Mask is still the right verb, for the real reasons: the quadlet units have no install state to disable, and a plain disable on the daemon is not durable. Hive-Fix-Attempt: 1/6 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Reviewed at head 891d6c9 (diff + shared.just, new bats, new skill doc, and the #1226 tree at d30d404 the recipes target).
docs-currency
- (low) The disable branch does more than mask units:
shared.just:86-87writes a comment-only~/.config/environment.d/10-ffmpeg-thumbnailer.confto shadow/usr/lib/environment.d/10-ffmpeg-thumbnailer.confand drop the shim fromXDG_DATA_DIRS; enable removes it at:97. Neither the newdocs/skills/systemd-user-units.md(no mention ofenvironment.d) norstatus-ffmpeg-thumbnailer(shared.just:113-146) surfaces this file, so a user who deletes the mask by hand and still gets no ffmpeg thumbnails has nothing to point them at the leftover override. Please add a short note to the skill doc (and ideally a line in the status report).
intent-alignment
- (info) Two PR-body claims don't match the tree: (1) "The suite is now wired into
.github/workflows/unit-tests.yml" — that file is not in this diff, andmainalready runsbats tests/test_shared_just.batsatunit-tests.yml:200-201. (2) The mask rationale citesusr/lib/systemd/user-preset/01-ffmpeg-thumbnailer.presetand a staticgraphical-session.target.wants/symlink; #1226 atd30d404ships neither — only[Install] WantedBy=graphical-session.target default.targetinffmpeg-thumbnailer-daemon.service. Your own doc (systemd-user-units.md:58-62) already says "common ships no preset for it", so only the body needs correcting. Mask remains the right call for the quadlet-generated units regardless.
No findings from: correctness, security, style.
Confidence: 3/5 (needs attention) — 1 perspective requested changes
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
The disable branch of `toggle-ffmpeg-thumbnailer` writes a comment-only `~/.config/environment.d/10-ffmpeg-thumbnailer.conf` to shadow the system drop-in and keep the shim out of `XDG_DATA_DIRS`. Nothing told the user about it: the skill doc covered only masking, and `status-ffmpeg-thumbnailer` never mentioned the file. A user who unmasked the units by hand got no video thumbnails and no pointer to the leftover override. - `status-ffmpeg-thumbnailer` now prints an "Environment override" section reporting whether the file is present, what it does, and how to remove it. Its path is derived the same way as the toggle's, and a test pins the two literals together so they cannot drift. - `docs/skills/systemd-user-units.md` gains a section on why masking alone is not enough for a session environment variable, the shadow-by-name mechanism, a matching red flag, and a `cat-config` verification command. Hive-Fix-Attempt: 2/6 Assisted-by: Claude Opus 5 via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Reviewed at head 74a40d5 against #1229.
correctness
- (low) Enable path promises thumbnails "before the next login", but only the units come back immediately. When the user disabled, logged out, and later runs
enable, the current session'sXDG_DATA_DIRSstill lacks/usr/share/ublue-os/thumbnailer—rm -f "${ENV_OVERRIDE}"(shared.just:97) only takes effect at the next login, the same caveat the disable branch already prints (shared.just:90). The enable message (shared.just:101-103) should say to log out/in for the shim to be picked up, otherwise users will read "first thumbnail may fail while the pull completes" and keep waiting.
intent-alignment
- (info) PR body says "on
maintoday both recipes report 'not installed'". Only the toggle probes (shared.just:44);status-ffmpeg-thumbnailer(shared.just:113-127) has no probe and printsunknown/absentrows on images without the thumbnailer. Behaviour is acceptable (tested by "reports unknown state instead of failing"), but the body overstates it; consider a one-line "not installed" short-circuit for parity.
No findings from: security, style, docs-currency.
Confidence: 3/5 (needs attention) — 1 perspective requested changes
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
…s parity The enable branch of `toggle-ffmpeg-thumbnailer` removes the user `environment.d` override, but `environment.d` is only read at login. The old message said thumbnails worked immediately and blamed the container pull, so a disable -> relogin -> enable cycle left the user with active units, no shim in `XDG_DATA_DIRS`, no thumbnails, and a misleading explanation. The disable branch already stated the caveat; enable now does too. `status-ffmpeg-thumbnailer` also gains the toggle's `systemctl --user cat` probe and short-circuits with the same "not installed" line, instead of printing unknown/absent rows for a thumbnailer that is not on the system. Tests cover both branches' re-login wording and the status short-circuit; the skill doc records why the enable side is deferred too. Hive-Fix-Attempt: 3/6 Assisted-by: Claude Opus 5 via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Reviewed at head 4851f33 (50/50 bats in tests/test_shared_just.bats pass locally against the extracted recipe bodies).
correctness
shared.just:100—systemctl --user start "${THUMBNAILER_UNITS[@]}"has no--no-blockand its output is sent to/dev/null. The quadlets carryTimeoutStartSec=900and pull the 111 MB image on firstpodman run, so on a fresh/masked hostujust toggle-ffmpeg-thumbnailer enablesits silent for up to 15 min. The message at:105("The container image is also pulled on first use…") describes the opposite of what:100does. Either add--no-block(making:105true) or keep it synchronous and drop the redirect so the pull is visible. The bats stubs cannot see this (test_shared_just.bats:378asserts only the command line).- Limit: the install probe at
shared.just:43(systemctl --user cat "${DAEMON_UNIT}") is what gates theenablebranch after adisable. I believesystemctl catprints# Unit … is masked.and exits 0 for a masked unit, but only stubs exercise it here — please confirm on a live session thatdisable→enableround-trips.
docs-currency
docs/skills/systemd-user-units.md:69says the two quadlets "are started on demand or by another unit's dependency". In #1226 head (d30d404)ffmpeg-thumbnailer-daemon.serviceonly hasAfter=on them (ordering, not a pull-in), and neither the daemon nor the shim starts a container. The only thing that starts them is this recipe's:100. State that, or the skill teaches a mechanism that does not exist.
style
shared.just:34— "Order matters: the daemon is stopped first" is misleading::79stops all three in onesystemctl stopcall, where array order has no effect. Stop order comes from the daemon'sAfter=on the containers in #1226's unit file. Reword or split into twostopcalls if the order is meant to be guaranteed here.
No findings from: security, intent-alignment.
Confidence: 3/5 (needs attention) — 2 perspectives requested changes
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
|
Hive filed out-of-scope review findings as backlog issues so they do not block this PR:
Cap: 3 backlog issue(s) per PR. |
`ujust toggle-ffmpeg-thumbnailer enable` started the container quadlets with a blocking `systemctl --user start` and discarded its output. The quadlets carry TimeoutStartSec=900 and pull a 111 MB image on first start, so the recipe could sit silently for minutes. Start them (and the daemon) with --no-block and say that the pull now runs in the background, pointing at status-ffmpeg-thumbnailer to check on it. Also make the install probe survive a `systemctl --user cat` that fails on a masked unit by falling back to `is-enabled`, in both the toggle and status recipes, and correct two comments/doc claims: the unit array's order is cosmetic because stop/mask take all three units in one call (the daemon's After= is what sequences the stop), and nothing in the image pulls the container quadlets in, so this recipe is their only starter. Hive-Fix-Attempt: 4/6 Assisted-by: Claude Opus 5 via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
HUMAN DECISION NEEDED — @sramkrishna is the thumbnailer opt-out (then #1226 needs a user-preset/wants for ffmpeg-thumbnailer-daemon.service) or opt-in (then the issue/PR premise and this PR's default-state wording are wrong)? Reviewed head 2a09d4b.
intent-alignment
- #1229 and the PR body say the daemon "ships enabled by default … via systemd user presets" and "takes over video thumbnailing for every graphical session". #1226 (head
d30d404) ships nouser-presetand no*.wants/symlink for it, and both.containerfiles have no[Install]. This PR's own doc says so:docs/skills/systemd-user-units.md:61("commonships no preset for it") and:70("the sole starter today is theenablebranch ofujust toggle-ffmpeg-thumbnailer"). The recipes match what the issue asked for, but the problem the issue describes does not exist as #1226 stands, and the doc's "sole starter" claim becomes false the moment #1226 grows a preset. Needs a decision across the two PRs, not a code fix here.
correctness
shared.just:68-72— the interactive prompt reports "currently enabled" whenever the daemon is notmasked. On a system where the daemon is merelydisabled(the state #1226 delivers today, see above), the user is told the thumbnailer is enabled. Derive the state from theis-enabledoutput (enabled/disabled/masked) oris-activeinstead of the mask check alone.shared.just:103-108—enable --now --no-blockandstart --no-blockdiscard output and|| true, then "has been enabled" prints unconditionally. A failedenable(e.g. daemon-reload race, missing[Install]) is reported as success; at least surface a warning whenenablereturns non-zero.
docs-currency
docs/TESTING.md:134still describestests/test_shared_just.batsas covering onlypowerwashandtoggle-tpm2; the row needs the two new recipes.docs/skills/systemd-user-units.md:160("Never write{{in the body") and:172(red flag: "A recipe body containing{{ ... }}") contradict the recipe they document —shared.just:31isACTION_VALUE="{{ ACTION }}", which is deliberate just interpolation and is what_extract_toggle_recipein the bats file substitutes. The PR body's "No{{ ... }}appears in either recipe body" is likewise inaccurate. Reword to: only literal braces meant for the shell (e.g.podman --format '{{.Status}}') must be escaped as{{{{.
No findings from: security, style.
Confidence: 3/5 (needs attention) — 2 medium findings
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
|
At 2a09d4b the environment.d override, the socket path and |
bluefin-common PR
What does this change?
Adds
ujust toggle-ffmpeg-thumbnailerandujust status-ffmpeg-thumbnailertosystem_files/shared/usr/share/ublue-os/just/shared.just, giving users asupported way to switch the rootless ffmpeg video thumbnailer off (and back on)
without editing image files.
Why?
Closes #1229
The thumbnailer introduced in #1226 ships an
[Install] WantedBy=graphical-session.target default.targeton its daemon, plus ausr/lib/environment.d/10-ffmpeg-thumbnailer.confdrop-in that puts its shimfirst in
XDG_DATA_DIRSfor video MIME types, so it takes over videothumbnailing for every graphical session. That default is wrong for users on constrained systems, on metered connections (the container
image is 111 MB), or on hosts that already have a working hardware thumbnailer.
Implementation notes
toggle-ffmpeg-thumbnailertakesenable/disable/cancel(case-insensitive) as
ACTION, matching thetoggle-updatesidiom, and fallsback to a
gum chooseprompt that reports the current state.quadlet-generated (
ffmpeg-thumbnailer.service,ffmpeg-thumbnailer-nvidia.service), so there is no install state forsystemctl --user disableto edit. On the daemondisabledoes work, but itis not durable: a preset added downstream, or a later
enable, reinstates thewants symlink.
systemctl --user maskwrites a per-user symlink to/dev/null(nosudo) that outranks the image and generator locations, andit blocks the container quadlets so the image is never pulled again while the
toggle is off.
environment.ddrop-in.XDG_DATA_DIRSis setat login, not by a unit, so masking alone would leave the shim first in the
search path. Disable writes a comment-only
~/.config/environment.d/10-ffmpeg-thumbnailer.conf, which outranks thesame-named
/usr/libfile; enable removes it. It takes effect at the nextlogin.
SIGTERMinsteadof leaving a stale socket path behind.
daemon-reload, enables the daemon, and starts thecontainer quadlets so thumbnails work before the next login.
systemctl --user cat ffmpeg-thumbnailer-daemon.servicefirst.
shared.justis also consumed by images that do not ship thethumbnailer (Aurora), where the toggle reports "not installed" and exits 0
rather than masking units that do not exist.
status-ffmpeg-thumbnaileris strictly read-only: unit enabled/active state,container state via
podman, whether theenvironment.doverride is present,the daemon socket, and the last 15 journal lines for the daemon unit. The
override line exists so a user who unmasks the units by hand is told why they
still get no thumbnails.
{{ ... }}appears in either recipe body —justwould interpolate itbefore the shell saw it.
Testing
tests/test_shared_just.bats: 32 new bats cases covering both recipes. Theyextract the real recipe bodies and run them against
systemctl,podman,journalctl, andgumstubs onPATH, asserting the exact command lines andtheir order, the graceful paths (mask/unmask failure, missing unit, absent
podman, failed journal), and that the status recipe never mutates unit state.
maskfordisablein the recipe fails five ofthe new cases.
just checkpasses, as do the pytest suites in theJustfileand the rest ofthe bats suites locally (
test_brew_preinstall.batsneedssystemd-analyze,which this sandbox lacks; the failure is environmental and pre-existing).
justbinary against stubbed units, notonly through the test extraction.
Docs
docs/skills/systemd-user-units.md: how common ships systemd user units,presets, and rootless quadlets, why a per-user toggle must mask rather than
disable, and why masking alone does not cover a session variable set through
environment.d. Includes a Verification section that re-derives the unitsearch path, enable state, and
environment.dresolution from a live system.docs/skills/shell-scripts/references/bats-patterns.md: name-anchored recipeextraction,
{{ ... }}substitution before running an extracted body, and theliteral-
{{parse failure.docs/SKILL.md;index.json/index.mdregeneratedwith
scripts/generate_skill_index.py --write.Merge-order note
#1226 (the thumbnailer itself) is still open, so on
maintoday both recipesreport "not installed" and change nothing. That is the intended degradation —
this PR can land before or after #1226.
Checklist
fix:,feat:,docs:,ci:,refactor:, etc.)just checkpassespre-commit run --all-filespasses (run piecewise: pre-commit is not installed in this sandbox, so the individual hooks it configures were run directly — skill front-matter, skill index, doc links, YAML/JSON validity, trailing whitespace, EOF newline)docs/skills/skill-improvement.md)AGENTS.md/docs/SKILL.md/docs/skills/links remain valid (scripts/check-doc-links.shclean)gh run list --repo projectbluefin/common --limit 5— to be confirmed by the reviewer/CIAI attribution
— hive: backend=litellm model=deepseek/deepseek-v4.1-flash
🤖 Generated with Claude Code
🐝 Hive Agent:
contributor| SHA:66b9089