Skip to content

The failure notifier is unreachable on a first install #12

Description

@phmatray

What happens

On a first install, any daemon that fails before install.sh reaches its last section cannot reach the failure notifier:

macarchy-auto-appearance.service: Triggering OnFailure= dependencies.
macarchy-auto-appearance.service: Failed to enqueue OnFailure= job, ignoring:
    Unit macarchy-failed@macarchy-auto-appearance.service.service not found.

The template that would have answered is installed at install.sh:425, in "Wiring the machine's own health report" — the second-to-last section. The three units that name it in OnFailure=%n are installed and started far earlier:

Unit Named in Installed by
macarchy-auto-appearance.service macarchy-core/systemd/…:8 install.sh ~line 250
macarchy-bar-contrast.service macarchy-core/systemd/…:16 install.sh ~line 250
macarchy-touchbar.service macarchy-touchbar/systemd/…:14 install.sh ~line 260

doctor.sh:82 reports ok failure notifier throughout, because it only tests that ~/.config/systemd/user/macarchy-failed@.service exists — never that a unit naming it can reach it. So the check is green precisely when the notifier is useless.

The consequence is the one the notifier exists to prevent. From macarchy-touchbar's own README rationale: a dead bar is invisible — it looks like a bar with nothing on it. The notifier is what turns that into a toast. On a first install it is not there, and a Touch Bar daemon that exhausts StartLimitBurst=10 dies in silence.

Second and later runs are fine — the template is on disk by then. That is why it survived: the maintainer's laptop and CI's second install.sh pass both have it.

What should happen

The notifier template is on disk before any unit that names it is installed, so the very first failure is announced. And doctor.sh reports the notifier as ok only when it is genuinely reachable.

Reproduction

  1. On a clean aarch64 machine (or tests/clean-machine.sh, one pass only), run install.sh.
  2. Make macarchy-auto-appearance fail — a machine without coordinates does it by itself.
  3. journalctl --user -u macarchy-auto-appearance.service → Failed to enqueue OnFailure= job … not found.
  4. ./doctor.sh → ok failure notifier.

Seen in CI run 33925266524, journals quoted in #9's evidence comment.

Area

install

Related: #9, #10

🧠 Brainstorm

Problem / context

install.sh is written as a sequence of converging steps, and its ordering rationale is stated inline wherever it matters (macos-dynamic-wallpaper is "ordered before the themes on purpose"; the legacy migration documents at length why working copies are renamed before anything is removed). The notifier's placement is the one that was never reasoned about: it sits with macarchy-doctor.service under "Wiring the machine's own health report" because both are health-reporting units, which is a tidy grouping and the wrong constraint.

This is the same defect shape #10 just fixed twice: an artifact installed after the thing that consumes it. There it was the theme's wallpapers landing after the unit that reads them; here it is the notifier template landing after the units that name it. Worth noting because it suggests the ordering constraint is worth stating explicitly rather than rediscovering per artifact.

No ADRs in this repo — nothing to check against (docs/adr/ absent; the profile records none).

Approaches

A. Move the template install to the top, before the repo loop. Three lines move. The template is a static file in this repo, depends on nothing, and needs no omarchy — there is no reason for it to be late. Smallest possible diff; fixes the cause.

B. Have each component repo ship its own notifier template. Removes the cross-repo ordering dependency entirely, but duplicates one file across three repos and makes macarchy-install no longer the owner of the health-report story. Trades a one-line ordering fix for a synchronisation problem.

C. Only strengthen the doctor check, leave the ordering alone. The doctor would report the truth, which is an improvement — but it would report a MISS on every first install for a condition the installer could simply have avoided. Fixing the diagnosis without fixing the disease.

Recommendation

A, plus the doctor half of C — they answer different questions. A makes the notifier reachable; the strengthened check makes the doctor able to notice if it ever stops being reachable, which is what would have caught this in the first place. B is rejected: one file, one owner.

📋 Spec

Goal

The notifier template is installed before any unit that names it in OnFailure=, and doctor.sh can tell a reachable notifier from a merely present file.

Scope

  • install.sh — move the macarchy-failed@.service install ahead of the component installs.
  • doctor.sh — the failure notifier check verifies reachability, not just existence.

Non-goals

  • Changing which units declare OnFailure=, or the notifier's own behaviour.
  • Moving macarchy-doctor.service; only the template has an ordering constraint.

Design

flowchart TD
    A[sanity + packages] --> B[install macarchy-failed@.service]
    B --> C[repo clone loop]
    C --> D[macarchy-core: auto-appearance, bar-contrast]
    D --> E[macarchy-touchbar]
    E --> F[…]
    F --> G[macarchy-doctor.service stays here]
Loading

The template is a static file in this repo's systemd/. It needs no clone, no omarchy, no session — so it can be installed immediately after the sanity checks, before anything that could fail while naming it.

The doctor's check becomes: for each unit on disk that declares OnFailure=macarchy-failed@…, the template it resolves to must exist. systemctl --user show -p CanStart on an instance is not usable here (an instance of a template is always startable in principle); reading the OnFailure= declarations and checking the template file is the honest test, and it is what a human would do.

Edge cases

  • No unit declares OnFailure= at all → the check has nothing to verify, and says so rather than passing silently.
  • A unit names a different notifier template → reported by name, not assumed to be ours.
  • The template exists but systemd --user has not reloaded → out of scope; install.sh already runs daemon-reload.

Assumptions

  • macarchy-doctor.service has no ordering constraint of its own — it is enabled, not started, at install time. Unverified; if it turns out to need late placement, only the template moves, which is what this spec says anyway.

Acceptance criteria

  1. On a one-pass clean install, journalctl --user -u macarchy-auto-appearance.service contains no Failed to enqueue OnFailure= job line.
  2. install.sh installs macarchy-failed@.service before the first component install; grep -n shows its line number below the sanity section and above the repo loop.
  3. doctor.sh reports MISS when a unit on disk declares OnFailure=macarchy-failed@… and the template is absent.
  4. doctor.sh still reports ok on a correctly installed machine, and names what it verified.
  5. Two install.sh passes remain idempotent — the template install converges, it does not re-copy noisily.

Testing decisions

Seams under test: doctor.sh's MISS/ok output lines, and install.sh's ordering as read by grep -n — the same text-level seams tests/test_doctor_noop_signals.sh and tests/test_doctor_touchbar_modules.sh already assert through.
Prior art: tests/test_doctor_noop_signals.sh — temp HOME, PATH stubs, a fixture the stub replays.
A good test here: a temp HOME holding one unit file that declares OnFailure=macarchy-failed@%n.service, with and without the template beside it, asserting the check flips.

Out of scope

  • Any change to macarchy-core's or macarchy-touchbar's unit files.
  • Making the notifier itself more informative.

🛠️ Implementation plan

For agentic workers: execute this plan task-by-task with implement-issue (subagent-per-task for broad plans, inline for small ones). Steps use checkbox (- [ ]) syntax for tracking.

Goal: the notifier is reachable from the first failure, and the doctor can tell reachable from merely present.
Architecture: plain bash — install.sh, doctor.sh, tests/*.sh; suites are hermetic (temp HOME + PATH stubs) and CI runs tests/test_*.sh plus bash -n.
Tech stack: bash 5, systemd user units, GitHub Actions on ubuntu-24.04-arm.

Seams under test: doctor.sh's MISS/ok output lines, and install.sh's ordering as read by grep -n.

Global constraints

  • Hermetic suites only: temp HOME, PATH stubs, no compositor, no Apple hardware. CI globs tests/test_*.sh — a new suite must match it.
  • bash -n must pass on install.sh, boot.sh, doctor.sh and tests/*.sh.
  • Never silence a check a real laptop would legitimately report; a skip states its reason and is gated on a condition false on the laptop.
  • Conventional Commit PR title decides the release bump; commits below use fix.
  • Commit trailer: Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>.

Task 1: install the notifier template before anything can name it

Files: modify install.sh; test tests/test_notifier_order.sh (new).

Interfaces: macarchy-failed@.service lands in ~/.config/systemd/user/ before the repo loop and before any component install. macarchy-doctor.service stays where it is.

  • Step 1: Write the failing test in tests/test_notifier_order.sh (seam: grep -n over install.sh) — assert the macarchy-failed@.service install line number is below the sanity section and above the repo clone loop.
  • Step 2: Run bash tests/test_notifier_order.sh → FAIL (it currently sits at ~425).
  • Step 3: Move only the macarchy-failed@.service half of install.sh:425 up to just after the packages step, with a comment naming the three units that declare OnFailure= and why late is wrong. Leave macarchy-doctor.service in place.
  • Step 4: Re-run → PASS, and bash -n install.sh clean.
  • Step 5: Commit: fix(install): install the failure notifier before the units that name it.

Task 2: the doctor checks reachability, not just presence

Files: modify doctor.sh; test tests/test_notifier_order.sh (extend).

Interfaces: for every unit file in ~/.config/systemd/user/ declaring OnFailure=macarchy-failed@…, the named template must exist; the check names what it verified.

  • Step 1: Write the failing case (seam: doctor.sh's output lines) — a temp HOME with one unit declaring OnFailure=macarchy-failed@%n.service and no template beside it; assert MISS.
  • Step 2: Add the mirror case — same unit with the template present; assert ok, and that the line says how many declarations it verified.
  • Step 3: Add the empty case — no unit declares OnFailure= at all; assert it says so rather than passing silently.
  • Step 4: Run → FAIL (the check is still a bare [[ -e ]]).
  • Step 5: Replace doctor.sh:82-83 with the reachability check.
  • Step 6: Re-run the whole suite and bash -n → PASS.
  • Step 7: Confirm clean machine is still green (0 missing) on the PR.
  • Step 8: Commit: fix(doctor): verify the failure notifier is reachable, not just present.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: installinstall.sh and boot.sh: the one-command bootstrapbugSomething isn't workingeffort: smallOne task, one test cyclepriority: mediumThe default tier — worth doing, not urgent

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions