Correct the lock-watcher claims: session restart was the trigger; suspend was covered by noctalia #49

Merged
dank merged 1 commits from fix/47-attribution-and-inhibitor-correction into main 2026-10-20 17:55:08 -07:00
Owner

Two claims about the dead lock watcher, corrected by measurement

#48 landed the fix — Restart=always, StartLimitIntervalSec=0, PartOf=graphical-session.target —
and the live proof passed (NRestarts=1, new MainPID, active). While attributing the failure I
found one claim in it that was right for the wrong reason and one that was simply wrong. Docs only;
the unit file is untouched. Refs #47.

Attributed, to eight seconds

ps -o lstart= -p <niri> <noctalia>  →  Mon Oct 12 16:22:31 2026
systemctl --user show swayidle-lock.service  →  inactive (dead) since Mon 2026-10-12 16:22:23

The compositor session restarted and the watcher went with it, because it was wanted by
default.target instead of tied to the session target. PartOf=graphical-session.target is now
justified by the event rather than by reasoning about it. The user journal has no entries in that
window, so the evidence is process ages — diagnose a lapse inside the retention you actually have.

Wrong: the lid did not suspend the machine unlocked

I wrote that suspend lost its lock hook when the watcher died. systemd-inhibit --list contradicts
it:

noctalia   1000 blank 838715 noctalia   sleep   Lock before sleep   delay

noctalia-shell holds its own sleep inhibitor and locks on suspend independently of swayidle, so
suspend was covered for the whole eight days. What was actually dead is the idle lock — five
minutes of inactivity locked nothing — and after-resume.

The method error is the part worth keeping: pgrep -c -u blankpad 'swayidle|swaylock|hyprlock|gtklock'
returned 0 and I read that as "no lock path exists". A locker can be a hook inside a running shell,
invisible to the process list. Read systemd-inhibit --list before pgrep.

Added: why an agent session suppresses your idle lock

Not enabling timeouts: idle inhibitor found
omp   1000 blank 304194 omp   idle   omp agent session   block

While an omp session runs, swayidle arms no idle timeout at all — by harness design — while
before-sleep and after-resume keep working. Anyone auditing "why did the screen never lock"
should look at the inhibitor table before suspecting the unit.

Verification

kb-lint.sh omp-docs 0 violations, kb-coverage.py 0 issues, bats tests/ 71/71. Live watcher
active, NRestarts=1 after the deliberate SIGTERM.


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

# Two claims about the dead lock watcher, corrected by measurement #48 landed the fix — `Restart=always`, `StartLimitIntervalSec=0`, `PartOf=graphical-session.target` — and the live proof passed (`NRestarts=1`, new `MainPID`, `active`). While attributing the failure I found one claim in it that was right for the wrong reason and one that was simply wrong. Docs only; the unit file is untouched. Refs #47. ## Attributed, to eight seconds ps -o lstart= -p <niri> <noctalia> → Mon Oct 12 16:22:31 2026 systemctl --user show swayidle-lock.service → inactive (dead) since Mon 2026-10-12 16:22:23 The compositor session restarted and the watcher went with it, because it was wanted by `default.target` instead of tied to the session target. `PartOf=graphical-session.target` is now justified by the event rather than by reasoning about it. The user journal has no entries in that window, so the evidence is process ages — diagnose a lapse inside the retention you actually have. ## Wrong: the lid did not suspend the machine unlocked I wrote that suspend lost its lock hook when the watcher died. `systemd-inhibit --list` contradicts it: noctalia 1000 blank 838715 noctalia sleep Lock before sleep delay noctalia-shell holds **its own** sleep inhibitor and locks on suspend independently of swayidle, so suspend was covered for the whole eight days. What was actually dead is the **idle** lock — five minutes of inactivity locked nothing — and `after-resume`. The method error is the part worth keeping: `pgrep -c -u blankpad 'swayidle|swaylock|hyprlock|gtklock'` returned 0 and I read that as "no lock path exists". A locker can be a hook inside a running shell, invisible to the process list. **Read `systemd-inhibit --list` before `pgrep`.** ## Added: why an agent session suppresses your idle lock Not enabling timeouts: idle inhibitor found omp 1000 blank 304194 omp idle omp agent session block While an `omp` session runs, swayidle arms no idle timeout at all — by harness design — while `before-sleep` and `after-resume` keep working. Anyone auditing "why did the screen never lock" should look at the inhibitor table before suspecting the unit. ## Verification `kb-lint.sh omp-docs` 0 violations, `kb-coverage.py` 0 issues, `bats tests/` **71/71**. Live watcher `active`, `NRestarts=1` after the deliberate `SIGTERM`. --- cwd: /home/blank/.omp/wt/wt-20261019-125509-7c8a99d · session: 01a155bb-6474-7366-be9d-629f74af0e05 Build worktree: `~/.omp/wt/wt-lock-correct` off `origin/main`. Refs #47
dank added 1 commit 2026-10-20 17:53:01 -07:00
Two statements in the law added by #48 need measurement rather than inference, and one of them was
wrong.

**Attributed.** `niri` and `noctalia` both started `Mon Oct 12 16:22:31 2026` (`ps -o lstart=`);
swayidle's last state change was `16:22:23`. The compositor session restarted and the watcher died
with it — eight seconds of agreement, which is what `PartOf=graphical-session.target` is for. The
fix that #48 justified by reasoning is now justified by the event itself. The user journal holds no
entries for that window, so the evidence is process ages, not logs.

**Corrected.** #48 said closing the lid suspended blankpad unlocked, because `before-sleep` lived in
the dead unit. `systemd-inhibit --list` says otherwise: `noctalia … sleep "Lock before sleep" delay`
— the shell holds its own sleep inhibitor and locks on suspend independently of swayidle, so the
suspend path held all along. What was dead for eight days is the **idle** lock and `after-resume`.
The method error is worth keeping: `pgrep` for lockers came back empty and I read that as "no lock
path", when a locker can be a hook inside a running shell. The inhibitor table is the instrument.

Added with them, because it answers a question people will ask: while an `omp` session runs, swayidle
logs `Not enabling timeouts: idle inhibitor found` and arms no idle timeout (`omp … idle "omp agent
session" block`). A box with an agent working does not lock on inactivity, by harness design.

Docs only; the unit file from #48 is unchanged and the live watcher is `active` with `NRestarts=1`
after the SIGTERM proof. `kb-lint.sh omp-docs` 0 violations, `kb-coverage.py` 0 issues, `bats tests/`
71/71. Refs #47.
dank merged commit 5ab0a49ea4 into main 2026-10-20 17:55:08 -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#49