Skip to content

SOW-0001 Chunk 19: systemd user units + install script#23

Merged
ktsaou merged 2 commits into
masterfrom
sow-0001-chunk-19-systemd
May 29, 2026
Merged

SOW-0001 Chunk 19: systemd user units + install script#23
ktsaou merged 2 commits into
masterfrom
sow-0001-chunk-19-systemd

Conversation

@ktsaou
Copy link
Copy Markdown
Member

@ktsaou ktsaou commented May 29, 2026

Summary

Run ai-viewer persistently on a workstation via systemd USER units (localhost, run-on-login, auto-restart) — no privilege, no remote scope.

  • deploy/systemd/ai-viewer-{ingest,serve}.service — USER unit templates (%h paths, Restart=on-failure/RestartSec=3s, serve After=ingest). The serve unit documents the intentional start-order race: it may start before the ingester migrates the schema → CheckSchema exits → Restart retries until the DB exists.
  • scripts/install-systemd-user.sh (install/uninstall/status) — install always rebuilds from source, copies binaries to ~/.local/bin + units to the user systemd dir, daemon-reloads, then prints the enable --now command for the operator to run (never enables/starts services itself). Idempotent uninstall keeps binaries + data. No sudo, no home-path literals.
  • scripts/test/systemd-units-test.sh — directive lint + systemd-analyze verify (offline); asserts exact ExecStart, Restart, RestartSec, and the serve After= ordering.

Quality gates (local, master-run)

  • shellcheck both scripts clean; bash -n clean
  • systemd-analyze verify + directive lint PASS (a typo'd binary name and a removed RestartSec both fail it)
  • install --help mutates nothing; systemctl --user is-enabled confirms nothing was installed/started on the build machine
  • scripts/build.sh still green

External review: codex + glm + minimax, 3 iterations to convergence (codex found the stale-binary install path + the lint-masking hole + the uninstall failure-swallow; all fixed).

Test plan

  • CI gates job runs the unit lint (systemd-units-test.sh) green
  • CI lint / test / frontend / embed-smoke stay green (no Go/app/CI-runtime change)

ktsaou added 2 commits May 29, 2026 06:27
Run ai-viewer persistently on a workstation via systemd USER units
(localhost, run-on-login, auto-restart) — no privilege, no remote scope.

- deploy/systemd/ai-viewer-{ingest,serve}.service: USER unit templates
  (%h paths, Restart=on-failure/RestartSec=3s, serve After=ingest). The
  serve unit documents the intentional start-order behaviour: it may
  start before the ingester migrates the schema, CheckSchema exits, and
  Restart retries until the DB exists.
- scripts/install-systemd-user.sh (install/uninstall/status): install
  always rebuilds from source, copies binaries to ~/.local/bin and units
  to the user systemd dir, daemon-reloads, then PRINTS the enable command
  for the operator to run — it never enables/starts services itself.
  Idempotent uninstall keeps binaries + data. No sudo, no home-path
  literals (XDG/$HOME/%h).
- scripts/test/systemd-units-test.sh: directive lint + systemd-analyze
  verify (offline), asserting exact ExecStart, Restart, RestartSec, and
  the serve After= ordering.

deployment.md updated (install/uninstall/status, update path via the
install script, start-order note). shellcheck + systemd-analyze verify
clean; nothing is installed or started by the build/test.
Wire scripts/test/systemd-units-test.sh into the gates job (guarded on
the test existing) so unit-template regressions — a wrong ExecStart, a
dropped Restart/RestartSec, a broken After= ordering — are caught in CI,
not only on a developer's machine. GitHub ubuntu runners provide
systemd-analyze; the test skips the verify step gracefully if absent.
@ktsaou ktsaou merged commit f641797 into master May 29, 2026
6 checks passed
@ktsaou ktsaou deleted the sow-0001-chunk-19-systemd branch May 29, 2026 03:34
ktsaou added a commit that referenced this pull request May 30, 2026
…, EndTs

Round-3 fixes completing the partially-fixed exec/patch enrichment and
web_search pairing plus two correctness gaps, all verified against the
real ~/.codex wire shapes.

- exec_command_end exit_code is now authoritative for op status in BOTH
  orders: exec-first applies at finalize; output-first emits a correcting
  OpFinalized(failed,command_failed) via the finalizedOps lookup (a
  non-zero exit no longer leaves a failed command marked completed).
- patch_apply_end is now order-independent (finalizedOps path) and merges
  patch_success/patch_status into op Extras; success=false -> failed.
- exec_duration_ms is now emitted (real duration is {secs,nanos} ->
  secs*1000 + nanos/1e6).
- web_search pairing uses a per-turn FIFO queue of open searches (oldest
  pairs with each web_search_end) so interleaved searches don't mis-pair;
  the end event's action object is now decoded and emitted alongside query.
- NativeID is taken from the authoritative session_meta.payload.id (the
  UUID parent_thread_id/forked_from_id reference); the filename UUID is
  only a fallback.
- old-format turn_context-only sessions now finalize their EOF turn at the
  turn's last-activity timestamp (deterministic), not the file mtime, so
  the golden is stable across runs; the new-format stale crash finalize
  still uses the stale mtime.

New fixtures l_exec_failed / n_patch_apply / m_multi_web_search /
o_payload_id_filename + regenerated f_exec_truncated / b_old_turncontext /
k_web_search, each line-checked against the spec and byte-identical across
repeated -update-golden runs. Spec pinned the order-independence + the
{secs,nanos} and {patch_success,patch_status} shapes (rules #14/#16/#23).
Gates green: golangci(0)/gosec(0)/vet; race 13/13; codex coverage 92.6%;
FuzzParseLine 0 crashes; secret + AI-attribution scans clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant