Skip to content

daemon stability wave 2: health you can see, someone else's Mac - #130

Merged
m4ttheweric merged 154 commits into
mainfrom
job/integration-2
Aug 29, 2026
Merged

daemon stability wave 2: health you can see, someone else's Mac#130
m4ttheweric merged 154 commits into
mainfrom
job/integration-2

Conversation

@m4ttheweric

Copy link
Copy Markdown
Collaborator

Daemon stability wave 2: health you can see, someone else's Mac

Stacked on #127. Executes phases 2 and 6 of docs/daemon-stability-audit-2026-08.md: each phase ran as a design lane (brainstorm, spec, plan, subagent-driven TDD) with an independent Opus review of both the spec and the plan before execution.

What changed

Phase 2, health you can see (RT-79; spec docs/superpowers/specs/2026-08-28-p2-health-design.md)

  • Server-computed health verdict (ok / degraded / unhealthy, naming the failing subsystem) plus memory, uptime, watcher and client metrics on status, tray:status, and ping (R011, R012)
  • 250ms unref'd event-loop monitor with a decaying-window lag signal, and a db-free atomic-rename heartbeat file so a stalled daemon reads as "stalled Ns ago" instead of "not running" (R003)
  • rt.logLevel setting plus a live rt daemon log-level verb; log size cap, per-(cmd,error) suppression, pino stream error listener, stderr demotion, deduped resolver warn sink (R004, S031, S032, S033, R005)
  • Request id plus caller tag on every command, echoed in error envelopes; unknown-command replies carry a code and the daemon version (R008, R021)

Phase 6, someone else's Mac (RT-83; spec docs/superpowers/specs/2026-08-28-p6-portability-design.md)

  • PATH resolution rebuilt: async, login non-interactive -lc base plus a bounded best-effort -ilc overlay in a killable process group, rt.daemonPath override, missing-tool warning; the sync-exec gate loses its user-path.ts allowlist entry (S013, S014, S062)
  • Stable machine key pinned at rt home init via hardware UUID, data-preserving for existing machines (S071)
  • Dev-wrapper marker detection reads a bounded prefix, never the whole binary (S020, S067)
  • Unsupported-arch warning at setup, honest "not provisioned" and git-identity diagnostics, sops spawn timeout (R051, S090, R043, S070)
  • branch_cache keyed identity:branch with every consumer repo-scoped and bare-branch lookups preserved (S069)

Follow-up

  • Swift tray reads for the new health level are documented, not implemented (Swift-owning change)
  • summaryCache eviction and the two-layer restart wait in daemon-client.ts remain parked minors from wave 1

Checklist

  • Anything that should be behind a feature flag is behind a feature flag
    • N/A. New settings (rt.logLevel, rt.daemonPath) default to prior behavior.
  • Appropriate tests have been created or updated
    • Unit 4783 pass / 0 fail; e2e 114 pass / 0 fail; tsc 0; picker, docs, purity gates green; rt-client dist fresh.

🤖 Generated with Claude Code

m4tthewericand others added 30 commits August 28, 2026 09:29
… and report truncation at 100 files (S053, S086)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…/gitq/deck) on a same-named PATH collision (S066)
… a configured root that is an ancestor of the repo (S079)
… (S054)
api-server captured the token once at boot while the secrets handler
called loadOrCreateApiToken() fresh on every request; an external
rotation or an unwritable token dir left the two permanently
disagreeing about the current token. getApiToken/reloadApiToken share
one in-memory cache between both consumers, and a persist failure now
logs a warning instead of failing silently.
…pid after binds
Boot failures on the prod path used to leave a live-pid zombie: a stale
rt.pid could get written before the socket/API binds even attempted, so a
failed boot exited without ever removing it. runDaemon() now wraps its body
in try/catch (log.fatal + flush + exit 1 on any failure), and rt.pid is only
written once both servers.socket and servers.api are assigned.
installCrashHandlers gains an opts.booting predicate: unhandledRejection is
fatal + exit 1 while true (boot phase, nothing worth staying up for), and
logs only (today's behavior) once bootPhase flips to "ready" right before
"daemon ready".
…rly instead of racing a retry into a second pane (S087)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review fix (round 1): runDaemon() now catches and exit(1)s internally on
boot failure, so startDaemon()'s outer try/catch never runs, and its JSDoc
claiming otherwise was misleading. Replaced with a one-line comment stating
the real constraint.
…per-chunk, so a split multibyte char survives (S095)
…scope side effect
Hoists redirectNativeStderr() to the first executable statement and
installCrashHandlers() to right after the logger resolves, both before
createEventsBus, cron, sweep timers, and home-snapshot construction.
A pre-startDaemon throw (e.g. a corrupt events.db) now lands in
daemon-stderr.log instead of vanishing down a discarded fd 2.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…linked or case-variant root matches lsof (S097)
m4tthewericand others added 23 commits August 28, 2026 17:54
…0/R043)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…h/metrics/eventLoop in status/tray:status/ping
status-identity.test.ts's fakeCtx() gained getHealth/heartbeatSeq stubs to match the widened HandlerContext.
…es (R043)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…069 part 1)
Also updates the two other BranchCacheStore implementers (lib/daemon.ts's
delegating facade, fake-cache-store.ts's test double) and one exact-key-set
test assertion so tsc stays clean; store PK/upsert/delete/gc behavior is
unchanged.
…fence (S069 part 1)
get/getByBranch on the BranchCacheStore interface forced an edit to
lib/daemon.ts's cache facade, which is under a write fence owned by the
p2-health lane. Drop get entirely (Task 10 consumers will use
entries[composeKey(identity, branch)] directly); reshape getByBranch into a
free function over an entries map instead of a store method, so the
interface -- and daemon.ts's facade -- do not change. Reverts the daemon.ts
and fake-cache-store.ts edits from the prior commit.
…-now items
Applies the final whole-branch review's approved fix wave for the rt
daemon health feature: maxLagMs now decays as a windowed max instead
of a lifetime high-water mark (and currentlyStalled drops its
redundant maxLagMs OR-leg), the health degraded threshold for
event-loop lag is named instead of hardcoded, one branch-introduced
em dash is fixed, a process-citation is dropped from a comment, the
daemon log-level resolver validates against pino's level set, and the
heartbeat reader now shape-guards against a partial-but-valid JSON
object.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…consumers (S069)
Consumers updated: store put (keys off entry.repoName), enrich (cold-start sets
identity from remoteUrl), notifier (composite fired-state), worktree-reconciler
(branchOf/mrKey), freshness (composeKey lookups), handlers/cache (bare-branch
read contract + optional repoIdentity), handlers/system-processes and
handlers/worktree (repo-scoped lookups), status/data (branchOf display).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…or/identity check
Two earlier-committed behavior changes broke four consumer test fixtures:
the dev-mode wrapper detector now requires a real marker (# mattstack-dev-mode
or RT_LAUNCH_CWD) instead of treating any file's presence as dev mode, and
commitInitialUserRepo now checks git identity before committing. Production
code is unchanged; fixtures now plant a recognized wrapper and answer the
git config user.name/email probes, matching the pattern already used in
home-snapshot.test.ts's defaultResponders.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… review #1/#2)
enrichBranches's daemon-first path now passes repoIdentity on cache:read,
so a branch name shared across two tracked repos (main/master) no longer
risks a suffix-match cross-repo hit. SecretsTimeoutError now sets its
name, mirroring AgeKeyTimeoutError.
@coderabbitai

coderabbitaiBot commented Aug 29, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 21 minutes.

View limit details

Limit details: You’ve used the included review currently available. Your 72 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c27992c2-55d6-4846-8b6e-ec6088b5b884

📥 Commits

Reviewing files that changed from the base of the PR and between c6afe65 and bb73645.

📒 Files selected for processing (93)
  • commands/__tests__/home.test.ts
  • commands/__tests__/log-level.test.ts
  • commands/__tests__/status-lines.test.ts
  • commands/daemon.ts
  • commands/home.ts
  • commands/settings.ts
  • commands/status/__tests__/status-fallback.test.ts
  • commands/status/data.ts
  • docs/superpowers/plans/2026-08-28-p2-health.md
  • docs/superpowers/plans/2026-08-28-p6-portability.md
  • docs/superpowers/specs/2026-08-28-p2-health-design.md
  • docs/superpowers/specs/2026-08-28-p6-portability-design.md
  • e2e/tests/daemon.test.ts
  • lib/__tests__/daemon-config.test.ts
  • lib/__tests__/daemon-logger-level.test.ts
  • lib/__tests__/daemon-logger-resilience.test.ts
  • lib/__tests__/daemon-status.test.ts
  • lib/__tests__/dev-mode.test.ts
  • lib/__tests__/enrich-cache-identity.test.ts
  • lib/__tests__/intended-mode.test.ts
  • lib/__tests__/log-janitor.test.ts
  • lib/__tests__/notifier-fired-hygiene.test.ts
  • lib/command-tree-def.ts
  • lib/daemon-client.ts
  • lib/daemon-logger.ts
  • lib/daemon-status.ts
  • lib/daemon.ts
  • lib/daemon/__tests__/cache-read-bare-branch.test.ts
  • lib/daemon/__tests__/cache-refresh-gc.test.ts
  • lib/daemon/__tests__/caller-tag.test.ts
  • lib/daemon/__tests__/command-attribution.test.ts
  • lib/daemon/__tests__/discussions-semantics.test.ts
  • lib/daemon/__tests__/fake-cache-store.ts
  • lib/daemon/__tests__/freshness-mapping.test.ts
  • lib/daemon/__tests__/freshness-provider-rotation.test.ts
  • lib/daemon/__tests__/health-sampler.test.ts
  • lib/daemon/__tests__/health.test.ts
  • lib/daemon/__tests__/heartbeat-file.test.ts
  • lib/daemon/__tests__/home-snapshot.test.ts
  • lib/daemon/__tests__/loop-monitor.test.ts
  • lib/daemon/__tests__/refresh-status-ref.test.ts
  • lib/daemon/__tests__/status-identity.test.ts
  • lib/daemon/__tests__/system-processes-handlers.test.ts
  • lib/daemon/__tests__/unknown-command.test.ts
  • lib/daemon/__tests__/user-path.test.ts
  • lib/daemon/__tests__/worktree-reconciler.test.ts
  • lib/daemon/api-server.ts
  • lib/daemon/cache-refresh.ts
  • lib/daemon/command-attribution.ts
  • lib/daemon/freshness.ts
  • lib/daemon/handlers/cache.ts
  • lib/daemon/handlers/status.ts
  • lib/daemon/handlers/system-processes.ts
  • lib/daemon/handlers/types.ts
  • lib/daemon/handlers/worktree.ts
  • lib/daemon/health-sampler.ts
  • lib/daemon/health.ts
  • lib/daemon/heartbeat-file.ts
  • lib/daemon/home-snapshot.ts
  • lib/daemon/loop-monitor.ts
  • lib/daemon/socket-server.ts
  • lib/daemon/unknown-command.ts
  • lib/daemon/user-path.ts
  • lib/daemon/worktree-reconciler.ts
  • lib/deps/__tests__/links.test.ts
  • lib/deps/links.ts
  • lib/dev-mode.ts
  • lib/enrich.ts
  • lib/home/__tests__/init-exec.test.ts
  • lib/home/__tests__/machine-id.test.ts
  • lib/home/init-exec.ts
  • lib/home/machine-id.ts
  • lib/log-janitor.ts
  • lib/notifier.ts
  • lib/secrets/__tests__/store.test.ts
  • lib/secrets/store.ts
  • lib/setup/__tests__/fakes.ts
  • lib/setup/__tests__/steps-a.test.ts
  • lib/setup/__tests__/validators-mac.test.ts
  • lib/setup/__tests__/validators-rt-health.test.ts
  • lib/setup/probes.ts
  • lib/setup/validators/mac.ts
  • lib/state/__tests__/branch-cache.test.ts
  • lib/state/branch-cache.ts
  • lib/worktree/__tests__/dispose.test.ts
  • packages/rt-client/src/index.ts
  • packages/rt-client/src/settings/__tests__/registry.test.ts
  • packages/rt-client/src/settings/registry-defs.ts
  • packages/rt-client/src/settings/resolve.ts
  • packages/rt-client/src/transport.ts
  • packages/rt-client/test/settings-warn-sink.test.ts
  • website/docs/reference/daemon/index.mdx
  • website/docs/reference/daemon/log-level.mdx

Comment @coderabbitai help to get the list of available commands.

@m4ttheweric
m4ttheweric changed the base branch from job/integration to mainAugust 29, 2026 04:50
@m4ttheweric
m4ttheweric merged commit a39fbea into mainAug 29, 2026
4 checks passed
Sign up for freeto 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

@m4ttheweric