F. First-class worker service lifecycle (systemd) #138
Labels
No labels
accessibility
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
P1
P2
P3
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Creatidy/scarcity-router#138
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Child F of #132. The Precision Codex worker was manually moved from foreground execution to systemd — make that product functionality with a first-class Linux/WSL worker service UX.
Scope (frozen)
Requirements:
--ca-certpersistence) and automatically reused — unit files never need ad-hocSSL_CERT_FILEshell hacks.loginctl lingerdeliberately and visibly; never silently overwrites an unrelated existing unit.runis framed as debugging/development.Tests
Unit generation (idempotent, no secrets — negative test scans unit content for credential material), install/restart/uninstall safety against a fake systemctl, overwrite-refusal, lock behavior (second instance fails closed), state-directory correctness, source/Ollama/CA preservation.
Security classification
Security-sensitive (service lifecycle, credential-adjacent surface): independent GLM-5.3-Flash review mandatory; Daybreak security review when available, else
SECURITY_REVIEW_UNAVAILABLEwith the gate open. UX assessment mandatory.Complexity boundary
New
worker_service.py-class module +worker_client.pysubcommand + Sources UI hook + docs (worker/deployment doc in place); ~3 test files. Budget: 120 min wall clock.Non-goals
No Windows service mechanics (M10 tray remains the Windows path); no root system units; no daemonizing logic of our own (systemd owns the lifecycle); no configuration migration.
Additive scope note (D-056, PR #147 — frozen scope text above unchanged; the scope itself is unaffected):
D-056's local-transport tiers govern CLIENT traffic to the composed HTTP listener only and deliberately do NOT relax worker transport (D-056 pt 8E; the boundary note in
docs/worker-protocol.md). For this child: generated service units and service tooling must keep requiring verified-TLSsrws://worker origins in production — worker loopback plaintext remains the bounded dev/tests-only exception, and nothing in the newly accepted local-HTTP tiers may introduce a plaintext worker origin, weakened verification or weakened credential handling here.Phase-A live acceptance record — ROG (finalized 2026-10-03)
Verdict: ACCEPTANCE_A_PASS_PHASE_B_DEFERRED. Phase B (reboot persistence) is
PHASE_B_DEFERRED_BY_OWNER; its absence is not a Phase-A failure. This record consolidates the Phase-A campaign (2026-10-01 → 2026-10-03) and the finalization-state verification at the exact final HEAD. No destructive test was repeated during finalization; the only new live execution was the non-destructive single-instance-lock refusal check.Environment under test
bfff8a392fae40e021b8d6143cd7ff08ca7f3ef9(branchtask/138-worker-service-lifecycle, basedevelop@db4e1bde28b2398e94b2911eb57bd3b752538dc5; PR open, unmerged, mergeable). Local checkout HEAD identical, worktree clean, remote branch head verified equal;origin/develop..HEAD= 6 commits, 0 merge commits.systemd --user). Boot IDdf051e5a-8897-4fc6-986b-34feac17b0dd(no reboot since 2026-09-28 — Phase B not exercised, by scope).scarcity_router.control_server), PID 3148529, worker protocol listener127.0.0.1:8790.w-e69ce40f9c7842e6, paired 2026-10-01T20:18:52Z; identity row untouched since — no re-pairing through the entire campaign. Stored originsrw://127.0.0.1:8790./home/adrian/.config/systemd/user/scarcity-router-worker.service, sha-256dac3713ba3b53de24501a70800e4caeda8f090ec0240786e8f5d056f6ac2c948, written 2026-10-01 22:20:02 CEST and never rewritten since (mtime unchanged through all tests).enabled;Linger=yes; managed-by marker present;ExecStart→ durable repo-venv executable,--state-dirpinned;ProtectSystem=strict;ProtectHome=read-only;ReadWritePaths= worker state dir only;Restart=on-failure/RestartSec=5s;TimeoutStopSec=30s;NoNewPrivileges/PrivateTmp/RestrictAddressFamiliespresent. No pairing code or credential anywhere in the unit (verified by direct read; test negative-scan also covers it).systemd-analyze verifyclean./home/adrian/.local/share/scarcity-router/worker(0700 tree;worker-state.db0600;worker.lock0600 — reserved byte 0 + holder-pid line).active (running), MainPID 4105320 since 2026-10-03 10:33:32 CEST,NRestarts=0,Result=success.127.0.0.1:34088 → 127.0.0.1:8790, client side owned by MainPID 4105320, server side by the DEV Router. Prior worker generations loggedsession accepted at protocol v4on connect (D-064 protocol).Phase-A items
active (running), stable PID, ~18 MB RSS.run --state-dir …against the active service refused fail-closed with exit 2:another worker process is already running for this worker state directory (pid 4105320); stop it first (with the service installed: systemctl --user stop scarcity-router-worker), or choose a different --state-dir. The service was untouched by the attempt (identical MainPID, connection andNRestartsre-verified immediately after);worker.lockshows the holder pid and is held for the service's lifetime. Matches the prior recorded refusal.Stopping→ worker gracefulconnection lost(deterministic stop path) →Stopped; noFailed with result, no SIGKILL escalation, no automatic restart after either stop. Contrast within the same journal: the 2026-10-01 22:20 failure pattern did logFailed with result 'exit-code'.Main process exited, code=killed, status=9/KILL+Failed with result 'signal'; 10:32:16:Scheduled restart job, restart counter is at 1→Started; the restarted worker loggedsession accepted at protocol v4(reconnected to 127.0.0.1:8790); identity unchanged — no re-pairing.service restart— PASS. Journal 2026-10-03 10:33:32 CEST:Stopping→Stopped→Startedwithin ~54 ms (systemctl --user restartdriven by the product CLI; prior recorded CLI output:worker service: restarted scarcity-router-worker.service). Current MainPID 4105320 dates from that restart and holds the live connection.service install— PASS. Prior recorded no-op re-install (identical PID / unit SHA-256 / mtime; service stayed active) corroborated at finalization: unit mtime still 2026-10-01 22:20:02, on-disk unit byte-identical to a freshrender_unitoutput at HEADbfff8a3(deterministic renderer),systemd-analyze verifyclean.Notes: journal timestamps above are local CEST; the worker's own log lines are UTC (
Z). The installed unit'sExecStartisrun --state-dir …with no adapter-selection flags — install preserved this deployment's (empty) selection; flag preservation across selections is covered by unit tests. The 2026-10-01 22:20 restart loop in the journal is the historical round-3 synthetic-namespace bug (untrusted worker path component /), fixed in rounds 3–4 before final HEAD; it has not recurred since 2026-10-01 23:14 (24 h+ stable run to the first clean stop).Credential / logging observations
No secret appears in the unit, the journal, CLI output or error messages. The pairing credential lives only in the 0700 state tree (0600 files); inspection during finalization was read-only (SQLite
mode=ro) and selected only non-secret fields (worker id, origin, label). Journal worker lines are limited to session/connection events.UX verdict:
UX_PASSThe administrator workflow pair → service install → service status → systemd lifecycle → restart/recovery → idempotent re-install was operable end-to-end: no manual editing of the unit was ever required, and no credential was ever copied into a persistent command or config (the pairing code is one-time; the identity lives in the 0700/0600 state store; the unit embeds none). Linger is handled and its outcome reported by install (
Linger=yes). Observed friction, all resolved or non-blocking: (1) the initial systemd synthetic-namespace bug was discovered live via an actionable error and fixed before final HEAD; (2) the user-manager/linger prerequisite on WSL required the documented prerequisite step; (3) refusal/error messages name the holder pid and the exact remediation command (observed live in C). Minor wording/polish goes to #140.Phase B
PHASE_B_DEFERRED_BY_OWNER— automatic service return after WSL/host restart (no interactive login, no re-pairing) is deliberately not exercised in this record; the host has not rebooted since 2026-09-28. This is not a Phase-A failure.Remaining non-blocking follow-ups