fix(mac): hub-hook-meting van de Mac via een LaunchAgent in de login-sessie #267

Merged
janpeter merged 1 commit from fix/mac-hub-snapshot into main 2026-09-28 17:58:38 +02:00
Owner

On mac-prod the S4M hub-hook measurement of the Mac itself was stuck on "verouderd", for two reasons. The heartbeat had no agent secret, and the agent runs as _jpops and can't read ~/.claude, ~/.config or the claude binary (all 0700). JP chose (2026-09-28) to measure in the login session.

  • LaunchAgent: the user LaunchAgent deploy/mac-production/launchd-user/com.jpvisser.hub-snapshot.plist runs the existing hub-hook-status.sh every 60 s and writes /Users/Shared/jpvisser/hub-snapshot.json atomically. The snapshot has no secret values, only booleans, the hub host, the waits and the Claude version.
  • Launcher: it forces HUB_SNAPSHOT_FILE for ops-heartbeat.
  • Heartbeat: with HUB_SNAPSHOT_FILE set, the heartbeat reads that file (readHubSnapshotFile) instead of calling the agent. A snapshot older than 120 s counts as no measurement, so logged out shows up honestly as "verouderd".
  • Docs: the runbook has the one-time LaunchAgent installation, and the manual's hub row is updated.

Tests:

  • file reader: fresh, stale, missing, broken, old schema;
  • the heartbeat reads the file and doesn't call fetch;
  • launcher env (Go + harness);
  • 27 heartbeat-related test files.

tsc is clean.

After the deploy: install the launcher by hand (runbook step) and load the LaunchAgent.

🤖 Generated with Claude Code

On `mac-prod` the S4M hub-hook measurement of the Mac itself was stuck on "verouderd", for two reasons. The heartbeat had no agent secret, and the agent runs as `_jpops` and can't read `~/.claude`, `~/.config` or the `claude` binary (all 0700). JP chose (2026-09-28) to measure in the login session. - **LaunchAgent:** the user LaunchAgent `deploy/mac-production/launchd-user/com.jpvisser.hub-snapshot.plist` runs the existing `hub-hook-status.sh` every 60 s and writes `/Users/Shared/jpvisser/hub-snapshot.json` atomically. The snapshot has no secret values, only booleans, the hub host, the waits and the Claude version. - **Launcher:** it forces `HUB_SNAPSHOT_FILE` for `ops-heartbeat`. - **Heartbeat:** with `HUB_SNAPSHOT_FILE` set, the heartbeat reads that file (`readHubSnapshotFile`) instead of calling the agent. A snapshot older than 120 s counts as no measurement, so logged out shows up honestly as "verouderd". - **Docs:** the runbook has the one-time LaunchAgent installation, and the manual's hub row is updated. **Tests:** - file reader: fresh, stale, missing, broken, old schema; - the heartbeat reads the file and doesn't call `fetch`; - launcher env (Go + harness); - 27 heartbeat-related test files. tsc is clean. After the deploy: install the launcher by hand (runbook step) and load the LaunchAgent. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(mac): hub-hook-meting van de Mac via een LaunchAgent in de login-sessie
All checks were successful
CI / Select checks (pull_request) Successful in 13s
CI / Ops-agent checks (pull_request) Successful in 43s
CI / DB access operator (pull_request) Successful in 1m36s
CI / Deploy artifact checks (pull_request) Successful in 44s
CI / Docker image build (pull_request) Successful in 1m24s
CI / Mac foundation hermetic checks (pull_request) Successful in 2m21s
CI / Root app checks (pull_request) Successful in 8m10s
CI / Mac foundation reproducible build (pull_request) Successful in 2m50s
CI / Publish post-merge release evidence (pull_request) Has been skipped
CI / Required checks (pull_request) Successful in 23s
57fd725f95
De agent draait als _jpops en kan ~/.claude, ~/.config en de claude-binary
niet lezen; de hartslag had bovendien geen agent-secret. Nu meet de user-
LaunchAgent com.jpvisser.hub-snapshot elke 60 s en schrijft de snapshot
(geen secret-waarden) naar /Users/Shared/jpvisser/hub-snapshot.json; de
launcher forceert HUB_SNAPSHOT_FILE en de hartslag leest dat bestand.
Verouderd (>120 s) telt als geen meting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
s4m-codex-reviewer left a comment

Verdict: COMMENT

  • Minor — lib/hub-settings/collect.ts:119: een snapshot met collected_at in de toekomst wordt als vers geaccepteerd, omdat alleen de maximale leeftijd wordt gecontroleerd. Na een klokcorrectie of fout geschreven timestamp kan een oude snapshot daardoor langer dan het online-venster zichtbaar blijven. Wijs timestamps ná now af (of begrens een kleine klokskew) en voeg hiervoor een test toe.

Geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden.

Validatie: de gerichte Vitest-suite kon in deze runner niet starten omdat de werkmap onder /tmp met noexec is gemount; de TypeScript-check is daarnaast al rood op bestaande, niet-gerelateerde ontbrekende gegenereerde/Prisma/ops-agent-dependencies.

## Verdict: COMMENT - **Minor — `lib/hub-settings/collect.ts:119`**: een snapshot met `collected_at` in de toekomst wordt als vers geaccepteerd, omdat alleen de maximale leeftijd wordt gecontroleerd. Na een klokcorrectie of fout geschreven timestamp kan een oude snapshot daardoor langer dan het online-venster zichtbaar blijven. Wijs timestamps ná `now` af (of begrens een kleine klokskew) en voeg hiervoor een test toe. Geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden. Validatie: de gerichte Vitest-suite kon in deze runner niet starten omdat de werkmap onder `/tmp` met `noexec` is gemount; de TypeScript-check is daarnaast al rood op bestaande, niet-gerelateerde ontbrekende gegenereerde/Prisma/ops-agent-dependencies.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
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
janpeter/Ops-dashboard!267
No description provided.