From 5dfa35e129430088be603ce0b100e435248757a5 Mon Sep 17 00:00:00 2001 From: Aaron Trowbridge Date: Fri, 25 Sep 2026 08:28:42 -0400 Subject: [PATCH] =?UTF-8?q?chore(ops):=20the=20erlich=20fleet-cadence=20un?= =?UTF-8?q?its=20=E2=80=94=20status=20collection=20+=20projection=20refres?= =?UTF-8?q?h=20(#1560)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Fleet (live) block's two artifacts had no cadence on the canonical server: fleet-status.json was last collected by hand and the projection cache was a one-shot. Versioned systemd pair (5-min, launchd parity) runs fleet-status.sh then 'amico fleet status --projection' — exit 75 (the honest unenrolled-host bootstrap exception) is SuccessExitStatus, never a failed cadence. PATH rides in the unit (#1558's lesson: systemd's default PATH resolves /usr/bin/node v12 on erlich, which SyntaxErrors the dist). README + install.sh rows. --- ops/README.md | 2 +- ops/install.sh | 2 +- ops/systemd/co.harmoniqs.fleet-status.service | 21 +++++++++++++++++++ ops/systemd/co.harmoniqs.fleet-status.timer | 10 +++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 ops/systemd/co.harmoniqs.fleet-status.service create mode 100644 ops/systemd/co.harmoniqs.fleet-status.timer diff --git a/ops/README.md b/ops/README.md index 1d04bde7..8aace464 100644 --- a/ops/README.md +++ b/ops/README.md @@ -23,7 +23,7 @@ rename(2) over the running executable — atomic, no stop, ever. | script | cadence (launchd) | reads | writes / posts | |---|---|---|---| -| `fleet-status.sh` | every 5 min (`co.harmoniqs.fleet-status`) | ssh probes (mini/macbook/erlich), canonical chat DB, server lsof, `~/.amico/sync.log`, local repo scan | `~/.amico/ops/fleet-status.json` (the dashboard widget's input); macOS notification on server-guard state change | +| `fleet-status.sh` | every 5 min (mini/macbook: launchd `co.harmoniqs.fleet-status`; **erlich**: systemd pair `co.harmoniqs.fleet-status.{service,timer}` under `ops/systemd/` — the unit ALSO runs the projection refresh `amico fleet status --projection` (#1560), the Fleet (live) block's role line (#1106 P3b-2); exit 75 is the honest unenrolled-host bootstrap exception, never a failed cadence) | ssh probes (mini/macbook/erlich), canonical chat DB, server lsof, `~/.amico/sync.log`, local repo scan | `~/.amico/ops/fleet-status.json` (the dashboard widget's input); on erlich also `~/.amico/ops/fleet/projection.json` (the projection cache the system-prompt block and every #1106 consumer reads); macOS notification on server-guard state change | | `fleet-alert.sh` | every 15 min (`co.harmoniqs.fleet-alert`) | `fleet-status.json`, state file | **Slack `#fleet`** — device transitions only (noise-gated; always-on hosts `mini erlich` notify, laptops never do); down->24h re-reminds once daily | | `papers-digest/daily.sh` | daily ~09:00 (`co.harmoniqs.amicode-papers-digest`) | the frozen bundle | **Slack `#papers`** — top-5 quant-ph digest; appends to `papers-digest/log.txt` | | `skill-freshness/run-skill-freshness.sh` | daily ~04:30 (`co.harmoniqs.skill-freshness`) | the three skill surfaces (repo public library, armonissima vault library, server staging tree), Julia package checkouts, the `#586` lint CLI | receipt line appended to `~/.amico/server/upgrade-receipts/upgrade-receipts.jsonl`; on drift, the tracking issue "Skill freshness report (nightly)" in `harmoniqs/armonissima` (created once, then commented); reports under `skill-freshness/reports/` | diff --git a/ops/install.sh b/ops/install.sh index aa1faa5c..b34a444f 100755 --- a/ops/install.sh +++ b/ops/install.sh @@ -11,7 +11,7 @@ set -euo pipefail DEST="$HOME/.amico/ops" SRC="$(cd "$(dirname "$0")" && pwd)" -mkdir -p "$DEST/papers-digest" "$DEST/skill-freshness" "$DEST/role-parity" "$DEST/session-archive" "$DEST/shard-watch" +mkdir -p "$DEST/papers-digest" "$DEST/skill-freshness" "$DEST/role-parity" "$DEST/session-archive" "$DEST/shard-watch" "$DEST/fleet-status" install -m 0755 "$SRC/fleet-status.sh" "$DEST/fleet-status.sh" install -m 0755 "$SRC/fleet-alert.sh" "$DEST/fleet-alert.sh" diff --git a/ops/systemd/co.harmoniqs.fleet-status.service b/ops/systemd/co.harmoniqs.fleet-status.service new file mode 100644 index 00000000..bf2985a8 --- /dev/null +++ b/ops/systemd/co.harmoniqs.fleet-status.service @@ -0,0 +1,21 @@ +[Unit] +Description=Amicode fleet status collection + projection refresh, every 5 min (the Fleet (live) block's freshness backbone, amicode#1560) +Documentation=https://github.com/harmoniqs/amicode/blob/main/ops/README.md +After=network-online.target +Wants=network-online.target + +[Service] +Type=oneshot +# #1558's deployment finding, carried in the versioned unit (one place, all hosts): +# systemd's default PATH resolves /usr/bin/node v12 on erlich, which SyntaxErrors +# the amico dist — the fleet host's node must come first. +Environment=PATH=%h/.local/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin +ExecStart=/bin/bash %h/.amico/ops/fleet-status.sh +# The projection refresh (#1106 P3b-2): amicissimo parses and publishes, the +# consumers read the one cache (~/.amico/ops/fleet/projection.json). Exit 75 is +# the verb's HONEST bootstrap exception (unenrolled host) — never a failed +# cadence, same posture as fleet-status's own unreachable-warnings. +ExecStart=%h/.local/bin/amico fleet status --projection +SuccessExitStatus=75 +StandardOutput=append:%h/.amico/ops/fleet-status/systemd.out +StandardError=append:%h/.amico/ops/fleet-status/systemd.err diff --git a/ops/systemd/co.harmoniqs.fleet-status.timer b/ops/systemd/co.harmoniqs.fleet-status.timer new file mode 100644 index 00000000..0569e842 --- /dev/null +++ b/ops/systemd/co.harmoniqs.fleet-status.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Amicode fleet status + projection refresh every 5 minutes (launchd co.harmoniqs.fleet-status parity) + +[Timer] +OnCalendar=*:0/5 +Persistent=true +Unit=co.harmoniqs.fleet-status.service + +[Install] +WantedBy=timers.target