deploy.sh is unsafe beside a live session: it starts a screen lock and imports another box settings #45

Merged
dank merged 1 commits from fix/44-deploy-live-safe into main 2026-10-20 17:16:48 -07:00
Owner

deploy.sh is unsafe to run beside a live session — this makes it safe

I preflighted the real deploy authorised after #43 and stopped: what I told you the run
touches — "only symlink owners, no file contents" — was wrong. sync also loads dconf and
enable --nows units. Two of those actions were harmful on this box, and a third thing the
preflight caught was a wrong-box value already living in your settings. Refs #44. The
deploy has not been run.

what sync would have done measured state now
enable --now swayidle-lock.service enabled / inactive, no swayidle process, not in autostart.kdl started only if systemd reports nothing-yet — screens stay unlocked
enable --now live-sync.service linked, timer-driven enabled, not started; the heartbeat keeps its own schedule
dconf load / 6 of 24 keys carry /home/dank paths those 6 keys deleted; picture-options='zoom' (a real preference) kept

1. The unit rule, and why the exit status is a trap

swayidle-lock.service is installed and deliberately not running. --now would have armed
a lock timer mid-conversation. A unit is now started only when its state is empty or
disabled — a fresh box, which still gets everything up. Reading "already installed" from
$? is wrong: is-enabled exits 1 for linked, the same code it gives disabled, so my
first version treated the timer-driven live-sync.service as uninstalled and started it. The
rule reads the printed state.

2. A sentence I committed in #43 that measurement contradicts

--check prints RELINK for every path the zz tier carries, even when the live link
already points at the override — rules.kdl, keybinds.kdl, misc.kdl, autostart.kdl and
.zshrc all did here, with the links already correct, because the walk visits base first and
reports the intermediate owner change. So my "RELINK noise is the sound of a stale override
waiting" is too strong; it is corrected to: the link target and actions=0 decide, the line
alone proves nothing. The layout.kdl hazard #43 deleted was real — the signal for it is
readlink, not the line.

3. Six keys from another box, five of them invisible to a diff

[org/gnome/portal/filechooser/firefox] last-folder-path  repo '/home/dank/Downloads'  live '/home/blank/Downloads'
[org/gnome/nautilus/window-state]      initial-size, initial-size-file-chooser, maximized
[org/gnome/desktop/background]         picture-uri, picture-uri-dark = file:///home/dank/.config/background

The last five showed no conflict, because blankpad's live tree already held the same
/home/dank values — an earlier deploy had written them here. A foreign value that agrees
with live is invisible to any diff and still wrong; this is why the acceptance check compares
keys rather than diffing text (dconf load writes only keys present, so a diff misleads in
both directions). The dump is now 18 keys, 0 conflicts against live, no /home/ values
at all
. As part of landing this I also clear the two live wallpaper URIs on blankpad
(gsettings … picture-uri '' and -dark) — niri draws the wallpaper, noctalia owns it, and
nothing reads a dead path.

Tests

tests/deploy.bats +4 over a stub systemctl, because the real one on this box is
precisely what must not run from a test. Red before: an enabled unit and a linked unit
both get --now. Green after, including both directions that keep the fix honest — a
disabled unit is still enable --now'd so a fresh box comes up, and a unit whose ExecStart
is absent here is never touched.

Verification and what follows

bats tests/ 70/70, kb-lint.sh omp-docs 0, kb-coverage.py 0, bash -n clean.

Once merged: I fast-forward ~/.omp, run the real deploy.sh, and the acceptance is
actions=0, no ENABLE … started for swayidle-lock.service, and the live dconf keys
cleared. If you would rather not have the deploy run at all, say so and this lands as
code-and-docs only.


cwd: /home/blank/.omp/wt/wt-20261019-125509-7c8a99d · session: 01a155bb-6474-7366-be9d-629f74af0e05
Build worktree: ~/.omp/wt/wt-deploy-live-safe off origin/main. Refs #44

# `deploy.sh` is unsafe to run beside a live session — this makes it safe I preflighted the real deploy authorised after #43 and stopped: what I told you the run touches — "only symlink owners, no file contents" — was wrong. `sync` also loads dconf and `enable --now`s units. Two of those actions were harmful on this box, and a third thing the preflight caught was a wrong-box value already living in your settings. Refs #44. **The deploy has not been run.** |what `sync` would have done|measured state|now| |---|---|---| |`enable --now swayidle-lock.service`|`enabled` / `inactive`, no swayidle process, not in `autostart.kdl`|started only if systemd reports nothing-yet — screens stay unlocked| |`enable --now live-sync.service`|`linked`, timer-driven|`enable`d, not started; the heartbeat keeps its own schedule| |`dconf load /`|6 of 24 keys carry `/home/dank` paths|those 6 keys deleted; `picture-options='zoom'` (a real preference) kept| ## 1. The unit rule, and why the exit status is a trap `swayidle-lock.service` is installed and deliberately not running. `--now` would have armed a lock timer mid-conversation. A unit is now started only when its state is empty or `disabled` — a fresh box, which still gets everything up. Reading "already installed" from `$?` is wrong: `is-enabled` exits **1** for `linked`, the same code it gives `disabled`, so my first version treated the timer-driven `live-sync.service` as uninstalled and started it. The rule reads the printed state. ## 2. A sentence I committed in #43 that measurement contradicts `--check` prints `RELINK` for **every** path the `zz` tier carries, even when the live link already points at the override — `rules.kdl`, `keybinds.kdl`, `misc.kdl`, `autostart.kdl` and `.zshrc` all did here, with the links already correct, because the walk visits base first and reports the intermediate owner change. So my "RELINK noise is the sound of a stale override waiting" is too strong; it is corrected to: the link target and `actions=0` decide, the line alone proves nothing. The `layout.kdl` hazard #43 deleted was real — the signal for it is `readlink`, not the line. ## 3. Six keys from another box, five of them invisible to a diff [org/gnome/portal/filechooser/firefox] last-folder-path repo '/home/dank/Downloads' live '/home/blank/Downloads' [org/gnome/nautilus/window-state] initial-size, initial-size-file-chooser, maximized [org/gnome/desktop/background] picture-uri, picture-uri-dark = file:///home/dank/.config/background The last five showed **no** conflict, because blankpad's live tree already held the same `/home/dank` values — an earlier deploy had written them here. A foreign value that agrees with live is invisible to any diff and still wrong; this is why the acceptance check compares keys rather than diffing text (`dconf load` writes only keys present, so a diff misleads in both directions). The dump is now 18 keys, **0 conflicts** against live, **no `/home/` values at all**. As part of landing this I also clear the two live wallpaper URIs on blankpad (`gsettings … picture-uri ''` and `-dark`) — niri draws the wallpaper, noctalia owns it, and nothing reads a dead path. ## Tests `tests/deploy.bats` +4 over a **stub `systemctl`**, because the real one on this box is precisely what must not run from a test. Red before: an `enabled` unit and a `linked` unit both get `--now`. Green after, including both directions that keep the fix honest — a `disabled` unit is still `enable --now`'d so a fresh box comes up, and a unit whose `ExecStart` is absent here is never touched. ## Verification and what follows `bats tests/` **70/70**, `kb-lint.sh omp-docs` 0, `kb-coverage.py` 0, `bash -n` clean. Once merged: I fast-forward `~/.omp`, run the real `deploy.sh`, and the acceptance is `actions=0`, no `ENABLE … started` for `swayidle-lock.service`, and the live dconf keys cleared. If you would rather not have the deploy run at all, say so and this lands as code-and-docs only. --- cwd: /home/blank/.omp/wt/wt-20261019-125509-7c8a99d · session: 01a155bb-6474-7366-be9d-629f74af0e05 Build worktree: `~/.omp/wt/wt-deploy-live-safe` off `origin/main`. Refs #44
dank added 1 commit 2026-10-20 17:13:56 -07:00
`sync` on a box with a live session on it was unsafe in two independent ways, found by
preflighting the run rather than performing it. Refs #44.

**`enable --now` would have armed a screen lock mid-session.** The unit loop started every
`systemd-user/` unit whose `ExecStart` resolves. `swayidle-lock.service` on blankpad is
`enabled`/`inactive` — nothing started it, no swayidle process exists, `autostart.kdl` does
not launch one — so one `deploy.sh` would have begun blanking and locking the monitors while
the operator was mid-sentence. `live-sync.service` is `linked`, driven by its timer, and
`--now` forces a heartbeat commit at an arbitrary moment. A unit is now started only when
systemd reports it as nothing-yet (`""`/`disabled`), which is precisely a fresh box; anything
already installed is merely `enable`d. The state has to come from the **printed state**:
`is-enabled` exits 1 for `linked` exactly as for `disabled`, so exit status cannot
distinguish "installed, timer-driven" from "never installed" — the first version of this fix
got that wrong and the test caught it.

**`--check` output was being read as more than it can mean.** It prints `RELINK` for every
path the `zz` tier carries, even when the live link already points at the override
(`rules.kdl`, `keybinds.kdl`, `misc.kdl`, `autostart.kdl`, `.zshrc` all did on blankpad),
because the walk visits the base package first and reports the intermediate owner change.
The sentence committed in #43 — RELINK noise is "the sound of a stale override waiting" — is
too strong and is corrected: the line proves a pending change only when `readlink` shows the
live target is not already the `zz-$HOST` file, and `actions=0` is the honest summary. The
stale-override hazard #43 removed was and is real; the signal for it is the target, not the line.

**The dconf dump carried six of its 24 keys from another box**, none of them preferences:
a Firefox file-chooser `last-folder-path` of `/home/dank/Downloads`, a nautilus
`window-state` section, and `picture-uri`/`picture-uri-dark` pointing at
`file:///home/dank/.config/background`. The last five showed no conflict because blankpad's
live tree *already* held those `/home/dank` values — an earlier deploy wrote them here — and
a foreign value that agrees with live is invisible to any diff while still being wrong. They
are dropped; `picture-options='zoom'` stays, because it is a preference. The live wallpaper
URIs are cleared on the box as part of landing this (niri draws the wallpaper, noctalia owns
it, nothing reads a dead path).

`tests/deploy.bats` grows by four, over a stub `systemctl` — the real one on this box is
exactly what must not be invoked from a test. Red before: an already-`enabled` unit and a
`linked` unit both get `--now`. Green after, including the two directions that keep the
change honest: a `disabled` unit is still `enable --now`'d so a fresh box comes up, and a
unit whose `ExecStart` is absent here is never touched at all.

Verification: `bats tests/` 70/70, `kb-lint.sh omp-docs` 0, `kb-coverage.py` 0. The dump now
reconciles against live state with **0 conflicts and no `/home/` values in 18 keys**, proven
by key-by-key comparison rather than `diff` — `dconf load` writes only the keys present, so a
diff overstates the damage one way and hides it the other.
dank merged commit c05f5ad451 into main 2026-10-20 17:16:48 -07:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dank/command-center#45