v0.5.1 (SESSION-ENV): the unit waits for the login's session environment — an ExecStartPre gate instead of a start before the import #11

Merged
claude merged 3 commits from oss-oo/session-env-gate into main 2026-10-28 11:57:44 +00:00
Member

Why

At the 2026-10-28 reboot oo-appserver.service (WantedBy=default.target) started at 11:53:05.3; default.target was reached at 11:53:06.5, and the X login's dbus-update-activation-environment --systemd (/etc/X11/Xsession.d/95dbus_update-activation-env) imported DISPLAY/XAUTHORITY/SSH_AUTH_SOCK/… into the user manager only after that. The shared server therefore ran without the session block until the launcher's one restart; oo-appserver doctor said WARN the service lacks session keys this shell has: ['DISPLAY', 'XAUTHORITY'] — started before the login import. Cinnamon never activates graphical-session.target (inactive on the station), so no ordering target can fix it. The owner asked for a clean autostart with the system.

What

  • systemd/oo-appserver.service: a second ExecStartPre, libexec/appserver_session_env.py — polls systemctl --user show-environment until DISPLAY or WAYLAND_DISPLAY is present (bounded 30 s; OO_APPSERVER_SESSION_ENV_TIMEOUT_S via a drop-in), writes one line to $RUNTIME_DIRECTORY/session-env, never fails the unit (a console or SSH login passes after the bound: not imported within 30s).
  • oo-appserver status: new session line (the record / no record — the running unit predates the v0.5.1 gate / unit not running); doctor names the gate record inside the session-keys warning.
  • libexec/appserver_station.py: session_env_record(); install.sh installs the gate; CI runs tests/test_session_env.py (8 legs: already imported, import during the wait, timeout, systemctl unavailable, wayland alone, custom keys + result path, no runtime dir, env seam + bad arguments); README Parts row, "The regular flow" step 1 with the measured times, Knobs; VERSION 0.5.1.

Evidence (stage: code, tests green locally; live after install)

  • Hermetic experiment on the station (systemd 255): a transient unit whose ExecStartPre waits for a PRIVATE key (OO_ENVWAIT_TEST) in the manager environment; the key was imported 2 s after the start while the unit was activating start-pre; ExecStart printed the imported value → systemd builds every Exec*'s environment at its own spawn, so a gate in the same unit suffices (no second unit). Two earlier runs were invalid (systemd-run without --no-block returns only after ExecStartPre), noted as a lesson. Cleanup verified (key unset, unit collected).
  • Local: test_session_env 8/8, test_read 23/23, test_bridge 14/14, test_send 111/111; systemd-analyze --user verify of the four units rc 0; install.sh --check lists the gate; oo-appserver status from the worktree shows session : no record — the running unit predates the v0.5.1 gate.

Validation after merge

Install from the tag, oo-appserver restart while no client, no loaded thread and the app not attached → status shows session : already imported · keys DISPLAY,XAUTHORITY,… and doctor has no session-keys WARN; the next reboot shows the gate's line in the journal before Started oo-appserver.service, without any restart.

Review: independent read-only review before the merge (fleet law); findings are fixed here first.

🤖 Generated with Claude Code

## Why At the 2026-10-28 reboot `oo-appserver.service` (`WantedBy=default.target`) started at 11:53:05.3; `default.target` was reached at 11:53:06.5, and the X login's `dbus-update-activation-environment --systemd` (`/etc/X11/Xsession.d/95dbus_update-activation-env`) imported `DISPLAY`/`XAUTHORITY`/`SSH_AUTH_SOCK`/… into the user manager only after that. The shared server therefore ran without the session block until the launcher's one restart; `oo-appserver doctor` said `WARN the service lacks session keys this shell has: ['DISPLAY', 'XAUTHORITY'] — started before the login import`. Cinnamon never activates `graphical-session.target` (inactive on the station), so no ordering target can fix it. The owner asked for a clean autostart with the system. ## What - `systemd/oo-appserver.service`: a second `ExecStartPre`, `libexec/appserver_session_env.py` — polls `systemctl --user show-environment` until `DISPLAY` or `WAYLAND_DISPLAY` is present (bounded 30 s; `OO_APPSERVER_SESSION_ENV_TIMEOUT_S` via a drop-in), writes one line to `$RUNTIME_DIRECTORY/session-env`, never fails the unit (a console or SSH login passes after the bound: `not imported within 30s`). - `oo-appserver status`: new `session` line (the record / `no record — the running unit predates the v0.5.1 gate` / `unit not running`); `doctor` names the gate record inside the session-keys warning. - `libexec/appserver_station.py`: `session_env_record()`; `install.sh` installs the gate; CI runs `tests/test_session_env.py` (8 legs: already imported, import during the wait, timeout, systemctl unavailable, wayland alone, custom keys + result path, no runtime dir, env seam + bad arguments); README Parts row, "The regular flow" step 1 with the measured times, Knobs; VERSION 0.5.1. ## Evidence (stage: code, tests green locally; live after install) - Hermetic experiment on the station (systemd 255): a transient unit whose `ExecStartPre` waits for a PRIVATE key (`OO_ENVWAIT_TEST`) in the manager environment; the key was imported 2 s after the start while the unit was `activating start-pre`; `ExecStart` printed the imported value → systemd builds every Exec*'s environment at its own spawn, so a gate in the same unit suffices (no second unit). Two earlier runs were invalid (`systemd-run` without `--no-block` returns only after `ExecStartPre`), noted as a lesson. Cleanup verified (key unset, unit collected). - Local: test_session_env 8/8, test_read 23/23, test_bridge 14/14, test_send 111/111; `systemd-analyze --user verify` of the four units rc 0; `install.sh --check` lists the gate; `oo-appserver status` from the worktree shows `session : no record — the running unit predates the v0.5.1 gate`. ## Validation after merge Install from the tag, `oo-appserver restart` while no client, no loaded thread and the app not attached → `status` shows `session : already imported · keys DISPLAY,XAUTHORITY,…` and `doctor` has no session-keys WARN; the next reboot shows the gate's line in the journal before `Started oo-appserver.service`, without any restart. Review: independent read-only review before the merge (fleet law); findings are fixed here first. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
claude agent added 1 commit 2026-10-28 11:29:17 +00:00
At the 2026-10-28 reboot the user service (WantedBy=default.target) started at 11:53:05.3; the X login imported DISPLAY/XAUTHORITY/SSH_AUTH_SOCK into the user manager only after default.target (11:53:06.5), so the shared server ran without the session block until the launcher's restart (`oo-appserver doctor`: "lacks session keys … started before the login import"). Cinnamon never activates graphical-session.target, so ordering cannot fix it.

- systemd/oo-appserver.service: second ExecStartPre `libexec/appserver_session_env.py` — polls `systemctl --user show-environment` until DISPLAY or WAYLAND_DISPLAY is present (bounded 30 s, env OO_APPSERVER_SESSION_ENV_TIMEOUT_S), records one line in $RUNTIME_DIRECTORY/session-env, never fails the unit (a console login passes after the bound). Verified hermetically on systemd 255 with a private key: ExecStart inherits what was imported while ExecStartPre waited.
- oo-appserver status: new `session` line (record / no record yet / unit not running); doctor names the gate record in the session-keys warning.
- libexec/appserver_station.py: session_env_record(); install.sh installs the gate; CI runs tests/test_session_env.py (8 legs: already imported, import during the wait, timeout, systemctl unavailable, wayland alone, custom keys + result path, no runtime dir, env seam + bad arguments).
- README: Parts row, "The regular flow" step 1 with the measured times, Knobs; VERSION 0.5.1.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent added 1 commit 2026-10-28 11:49:36 +00:00
Co-review findings on 047e933 folded:
- (1 must) `ExecStartPre=-…`: a missing gate file, a broken interpreter or an exception can no longer fail the server unit — the door opens whatever the gate does.
- (2 should) the bound is finite and capped: default 15 s (under the 20 s the launcher wrapper and the sender wait for an activating unit), ceiling 60 s below TimeoutStartSec 90 s; inf/nan/negative/garbage fall back to the default, both noted on stderr (journal); the per-poll systemctl timeout is clipped to the remaining bound (6).
- (3 should) `oo-appserver status` names `activating` (the gate may still be waiting) instead of "unit not running", and shows the state in the last branch.
- (4 nit) unit comment, docstring, station comment and README say what was measured: the X login imports DISPLAY, XAUTHORITY and DBUS_SESSION_BUS_ADDRESS (20dbus_xdg-runtime, then 95dbus_update-activation-env), SSH_AUTH_SOCK is there from the start.
- (7, 8 nits) --help exits 0; a missing systemctl binary returns `systemctl unavailable` at once instead of polling the whole bound.
- (9, 10 nits) the timeout leg uses a 1 s bound (no timing flake); new legs for finite/capped bounds, the missing binary, --help; README status example carries the stamp, Knobs name the ceiling and the callers' budgets.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent added 1 commit 2026-10-28 11:54:20 +00:00
Re-check finding 5: the clip gave the first poll a window equal to the bound (0.1 s in the env-seam test), so a slow fake on a loaded runner could turn `not imported within 0.1s` into `systemctl unavailable`. The window is now max(1 s, min(10 s, remaining)); worst-case wall time is the bound plus 1 s (15+1 under the callers' 20 s, 60+1 under TimeoutStartSec 90 s), documented in the docstring and Knobs. Knobs also name non-numeric values among the fallbacks; the clamp note prints whole seconds.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent merged commit 488bcaa163 into main 2026-10-28 11:57:44 +00:00
claude agent deleted branch oss-oo/session-env-gate 2026-10-28 11:57:44 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
OSS-OO/oo-appserver!11
No description provided.