Skip to content

fix(daemon): version+identity-keyed endpoint + version arbitration (#1009) - #1020

Merged
zackees merged 1 commit into
mainfrom
fix/1009-daemon-endpoint-identity
Jul 9, 2026
Merged

fix(daemon): version+identity-keyed endpoint + version arbitration (#1009)#1020
zackees merged 1 commit into
mainfrom
fix/1009-daemon-endpoint-identity

Conversation

@zackees

@zackees zackees commented Jul 9, 2026

Copy link
Copy Markdown
Member

Fixes #1009. Follow-up to #940/#1006 (which only warned on daemon identity mismatch). Two fixes so a wrong-version daemon can no longer silently serve another checkout's builds:

1. Endpoint keyed by version + cache-identity

get_daemon_port()'s default was a fixed per-user port (8765/8865) shared by every checkout. Now the endpoint is derived from daemon_endpoint_key() = FNV-1a of CARGO_PKG_VERSION | DaemonCacheIdentity.label_value(): default_daemon_port() maps it into the IANA dynamic range (49152–65535), and the port file is daemon-<key>.port. Since fbuild-paths is workspace-versioned, the CLI and daemon derive the same key with no handshake — daemons of different versions land on distinct ports/files and can't serve each other; same-version+cache checkouts still (correctly) share. Dropped the old cross-mode port fallback (an anti-isolation bridge). FBUILD_DAEMON_PORT still overrides.

2. Version arbitration, not mtime

ensure_direct_daemon_running used cli_binary_mtime > daemon_source_mtime to decide restarts, so a freshly-built older binary (newer mtime) could evict a newer daemon. New pure should_restart_daemon(cli_ver, daemon_ver, cli_mtime, daemon_mtime): restart iff the CLI is a newer semver (upgrade) or the same version was rebuilt (mtime); never evict a newer daemon. HealthResponse.version was already on the wire.

Acceptance criteria

  • Two versions bind distinct endpoints (distinct port + port file) → don't serve each other.
  • A newer-version daemon is never evicted by an older-version CLI regardless of mtime.
  • Regression tests: endpoint-key/port derivation + arbitration matrix.

Verified — local + Linux Docker

cargo check --workspace green; fbuild-paths 30 + fbuild-cli daemon_client 11 tests pass (Linux Docker, 28.5s). clippy -D warnings + fmt clean. CLAUDE.md port docs updated.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added isolated daemon endpoints for different backend versions and cache contexts.
    • Added support for overriding the daemon port with FBUILD_DAEMON_PORT.
    • Daemon ports now use deterministic values within the dynamic port range.
  • Bug Fixes

    • Improved daemon restart handling based on CLI and daemon versions.
    • Prevented older CLI versions from replacing newer running daemons.
    • Added safer fallback behavior when version information cannot be parsed.

…1009)

Follow-up to #940/#1006 (which only *warned* on daemon identity mismatch). Two
fixes so a wrong-version daemon can no longer silently serve another checkout's
builds:

1. **Endpoint keyed by version + cache-identity.** `get_daemon_port()`'s default
   was a fixed per-user port (8765/8865) shared by every checkout. Now the
   endpoint is derived from `daemon_endpoint_key()` = FNV-1a of
   `CARGO_PKG_VERSION | DaemonCacheIdentity.label_value()`: `default_daemon_port()`
   maps it into the IANA dynamic range (49152–65535), and the port file is named
   `daemon-<key>.port`. Since fbuild-paths is workspace-versioned, the CLI and
   daemon derive the same key with no handshake — daemons of different versions
   land on distinct ports/files and can't serve each other; same-version+cache
   checkouts still (correctly) share. Dropped the old cross-mode port fallback
   (an anti-isolation bridge). `FBUILD_DAEMON_PORT` still overrides.

2. **Version arbitration, not mtime.** `ensure_direct_daemon_running` used
   `cli_binary_mtime > daemon_source_mtime` to decide restarts, so a freshly-built
   *older* binary (newer mtime) could evict a *newer* daemon. New pure
   `should_restart_daemon(cli_ver, daemon_ver, cli_mtime, daemon_mtime)`: restart
   iff the CLI is a newer semver (upgrade) or the same version was rebuilt
   (mtime); **never** evict a newer daemon. `HealthResponse.version` was already
   on the wire.

Tests: fbuild-paths endpoint-key/port derivation (deterministic, ranged, version
-distinct, keyed port file); fbuild-cli arbitration matrix (older-never-evicts,
newer-upgrades, same-version-mtime, unparseable-fallback). CLAUDE.md port docs
updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@zackees
zackees merged commit 0bb7252 into main Jul 9, 2026
88 of 93 checks passed
@zackees
zackees deleted the fix/1009-daemon-endpoint-identity branch July 9, 2026 23:37
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6a7c2b61-0965-442d-bfb3-0e151bb7392c

📥 Commits

Reviewing files that changed from the base of the PR and between 5e82048 and 676084c.

📒 Files selected for processing (5)
  • CLAUDE.md
  • crates/CLAUDE.md
  • crates/fbuild-cli/src/daemon_client.rs
  • crates/fbuild-cli/src/daemon_client/tests.rs
  • crates/fbuild-paths/src/lib.rs

📝 Walkthrough

Walkthrough

The change isolates daemon endpoints by version and cache identity using deterministic dynamic-range ports, and adds semver-aware restart arbitration so direct-daemon acquisition handles upgrades, downgrades, equal versions, and unparsable versions consistently.

Changes

Daemon isolation and lifecycle

Layer / File(s) Summary
Endpoint-keyed daemon ports
crates/fbuild-paths/src/lib.rs, CLAUDE.md, crates/CLAUDE.md
Daemon endpoint keys now determine port files and default ports within 49152–65535, while FBUILD_DAEMON_PORT remains the highest-priority override. Documentation reflects the new isolation rules.
Version-aware daemon restart
crates/fbuild-cli/src/daemon_client.rs, crates/fbuild-cli/src/daemon_client/tests.rs
Direct-daemon acquisition now uses semver and mtime arbitration, shuts down restartable daemons, waits for termination, and spawns a replacement. Tests cover upgrade, downgrade, equal-version, and parsing-fallback cases.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/1009-daemon-endpoint-identity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

daemon: endpoint isolation follow-up to #940 — key the default endpoint by cache-identity/checkout + deterministic version arbitration

1 participant