From 3552dcbf3ecfbbf4b51b18ef55194f8e9be0b7d6 Mon Sep 17 00:00:00 2001 From: zackees Date: Sun, 23 Aug 2026 08:54:23 -0700 Subject: [PATCH 1/2] test(daemon): pin the dev daemon-namespace contract, and correct its docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FastLED/fbuild#1285's remaining work item was recorded as "repin zccache to a release honoring `ZCCACHE_DAEMON_NAMESPACE`", on the stated grounds that fbuild's exported stamp is inert until then. Both #1285's tracking comment and `fbuild_paths::dev_daemon_namespace`'s own module doc said so. That is not true, and has not been since the stamp landed in #1343. The pinned zccache (1.13.1, `8cf6dd0`) already folds the namespace into `zccache_ipc::default_endpoint()`. Measured: bare \.\pipe\zccache--0d204d7e-v1.13.1 stamp \.\pipe\zccache--0d204d7e-2.5.20-bbbbbbbbbbbbbbbb-v1.13.1 Two stamps, two pipes. The `displace-stale` war from zackees/soldr#2352 cannot happen between co-located dev checkouts today, which is what #1285's fbuild-specific ask was for. ## Why the claim went unnoticed Nothing could catch it. `fbuild-paths` produces the stamp and does not depend on zccache; zccache consumes it and is a pinned external dependency. The contract between them lived only in prose — so when the prose was wrong, every test still passed. `fbuild-build-engine/tests/dev_daemon_namespace_isolation.rs` is the place that can tell, because that crate depends on both sides. It asserts two stamps give two endpoints, a stamp differs from bare, clearing it restores the original endpoint exactly (release builds must keep single-daemon-on-upgrade semantics), and the stamp stays legible in the endpoint so an operator can see which checkout owns a daemon. A future repin that dropped endpoint namespacing would otherwise pass the whole suite while quietly restoring the bug. ## What actually remains zccache-side zccache#1362 adds zccache *deriving its own* stamp when nothing exported one. fbuild does not need it — fbuild exports one. That work is still unreleased (latest tag 1.13.5; the commit sits untagged on main), and is no longer a blocker for anything on this side. Co-Authored-By: Claude Opus 5 (1M context) --- crates/fbuild-build-engine/tests/README.md | 12 ++++ .../tests/dev_daemon_namespace_isolation.rs | 68 +++++++++++++++++++ .../fbuild-paths/src/dev_daemon_namespace.rs | 16 +++-- 3 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 crates/fbuild-build-engine/tests/README.md create mode 100644 crates/fbuild-build-engine/tests/dev_daemon_namespace_isolation.rs diff --git a/crates/fbuild-build-engine/tests/README.md b/crates/fbuild-build-engine/tests/README.md new file mode 100644 index 00000000..59510eeb --- /dev/null +++ b/crates/fbuild-build-engine/tests/README.md @@ -0,0 +1,12 @@ +# `fbuild-build-engine` integration tests + +Tests that need a separate final executable, or that exercise a contract +spanning this crate and one of its external dependencies. + +- **`dev_daemon_namespace_isolation.rs`** — proves the dev daemon-identity + stamp `fbuild-paths` exports actually changes the zccache IPC endpoint + (FastLED/fbuild#1285). It lives here because this is the crate that depends + on both sides: `fbuild-paths` produces the stamp but cannot see zccache, and + zccache consumes it but is a pinned external dependency. A repin that + dropped endpoint namespacing would otherwise pass every other test in the + tree while quietly restoring the `displace-stale` daemon war. diff --git a/crates/fbuild-build-engine/tests/dev_daemon_namespace_isolation.rs b/crates/fbuild-build-engine/tests/dev_daemon_namespace_isolation.rs new file mode 100644 index 00000000..449d573b --- /dev/null +++ b/crates/fbuild-build-engine/tests/dev_daemon_namespace_isolation.rs @@ -0,0 +1,68 @@ +//! The dev daemon-identity stamp actually isolates the compile daemon +//! (FastLED/fbuild#1285). +//! +//! `fbuild-paths` derives a per-checkout stamp and exports it as +//! `ZCCACHE_DAEMON_NAMESPACE`; zccache folds that value into the IPC endpoint +//! its daemons rendezvous on. Neither half can prove the other works — the +//! producer lives in a crate that does not depend on zccache, and the +//! consumer is a pinned external dependency — so the contract *between* them +//! was asserted only in prose, and the prose was wrong: both #1285's tracking +//! comment and `fbuild_paths::dev_daemon_namespace`'s module doc claimed the +//! export was inert until fbuild repinned zccache. It is not; it has been +//! live since the stamp landed. +//! +//! This test is the place that can tell. It lives in `fbuild-build-engine` +//! because that is the crate depending on both sides. A zccache repin that +//! silently dropped endpoint namespacing would take the `displace-stale` war +//! from zackees/soldr#2352 with it, and nothing else in the tree would +//! notice. + +use fbuild_paths::dev_daemon_namespace::ZCCACHE_DAEMON_NAMESPACE_ENV; + +/// One test, not three: the variable is process-global, so parallel cases +/// would race each other's `set_var`. +#[test] +fn the_exported_stamp_changes_the_zccache_daemon_endpoint() { + // SAFETY: this test binary contains one test, so no peer thread can + // observe the process-wide environment change. + unsafe { std::env::remove_var(ZCCACHE_DAEMON_NAMESPACE_ENV) }; + let bare = zccache::ipc::default_endpoint(); + + unsafe { std::env::set_var(ZCCACHE_DAEMON_NAMESPACE_ENV, "2.5.0-aaaaaaaaaaaaaaaa") }; + let first = zccache::ipc::default_endpoint(); + + unsafe { std::env::set_var(ZCCACHE_DAEMON_NAMESPACE_ENV, "2.5.0-bbbbbbbbbbbbbbbb") }; + let second = zccache::ipc::default_endpoint(); + + unsafe { std::env::remove_var(ZCCACHE_DAEMON_NAMESPACE_ENV) }; + let bare_again = zccache::ipc::default_endpoint(); + + // The property that matters: two checkouts with different stamps do not + // meet on one pipe. Without this, each displaces the other as + // "stale-version" on every invocation and the compile daemon wedges. + assert_ne!( + first, second, + "two stamps must rendezvous on two different endpoints" + ); + assert_ne!( + first, bare, + "a stamped endpoint must differ from the unstamped one" + ); + + // An unset stamp must keep the historical endpoint, or release builds + // would silently move off the daemon they share on upgrade — the + // single-daemon-on-upgrade semantics #1285 deliberately preserves for + // non-dev invocations. + assert_eq!( + bare, bare_again, + "clearing the stamp must restore the original endpoint exactly" + ); + + // The stamp is expected to appear in the endpoint rather than merely + // perturb a hash of it: an operator reading `\\.\pipe\...` or a socket + // path should be able to see which checkout owns the daemon. + assert!( + second.contains("bbbbbbbbbbbbbbbb"), + "the stamp should be legible in the endpoint, got {second}" + ); +} diff --git a/crates/fbuild-paths/src/dev_daemon_namespace.rs b/crates/fbuild-paths/src/dev_daemon_namespace.rs index 4fc60e01..932c7f73 100644 --- a/crates/fbuild-paths/src/dev_daemon_namespace.rs +++ b/crates/fbuild-paths/src/dev_daemon_namespace.rs @@ -8,10 +8,18 @@ //! invocation (the `displace-stale` war, root-caused in zackees/soldr#2352). //! //! The fix is a per-checkout namespace stamp exported as -//! `ZCCACHE_DAEMON_NAMESPACE` (the variable zccache honors once its own -//! adoption lands — zccache#1362; an inherited value always wins there, so -//! this export is inert, and harmless, until fbuild repins a zccache -//! release containing it): +//! `ZCCACHE_DAEMON_NAMESPACE`, which the pinned zccache folds into the IPC +//! endpoint its daemons rendezvous on — so two stamps mean two pipes, and +//! neither checkout can see the other as stale. +//! +//! This module previously claimed the export was "inert until fbuild repins +//! a zccache release containing it". That was wrong: endpoint namespacing is +//! already present at the pinned rev, and the isolation has worked since the +//! stamp landed. `crates/fbuild-build-engine/tests/ +//! dev_daemon_namespace_isolation.rs` pins the contract so a future repin +//! cannot drop it silently. What remains zccache-side (zccache#1362) is +//! zccache *deriving its own* stamp when nothing exported one — which fbuild +//! does not need, because fbuild exports one: //! //! ```text //! stamp = "-" From 512b9f50879e6fe866cc2e8862e4b7e32a4362ef Mon Sep 17 00:00:00 2001 From: zackees Date: Sun, 23 Aug 2026 09:06:50 -0700 Subject: [PATCH 2/2] chore(ci): refresh the platform-boundary inventory for the shifted doc The corrected module doc is eight lines longer, so the ledger's file/line record for `dev_daemon_namespace.rs`'s `std::env::current_exe` moved from 83 to 91. One line, no occurrence added, removed, or reclassified. Refs FastLED/fbuild#1285 Co-Authored-By: Claude Opus 5 (1M context) --- ci/platform_boundary_research.tsv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/platform_boundary_research.tsv b/ci/platform_boundary_research.tsv index 37b4383e..bf666dc4 100644 --- a/ci/platform_boundary_research.tsv +++ b/ci/platform_boundary_research.tsv @@ -67,7 +67,7 @@ crates/fbuild-core/src/platform/windows/usb_pnp.rs 40 native_path windows_sys:: crates/fbuild-daemon/src/handlers/emulator/tests_npm_cache.rs 146 attr_cfg #[cfg(windows)] host_executable host_artifact_policy crates/fbuild-daemon/src/handlers/emulator/tests_process.rs 9 attr_cfg #[cfg(windows)] host_executable host_artifact_policy crates/fbuild-daemon/src/handlers/emulator/tests_process.rs 21 attr_cfg #[cfg(not(windows))] host_executable host_artifact_policy -crates/fbuild-paths/src/dev_daemon_namespace.rs 83 native_path std::env::current_exe host_executable host_mechanic +crates/fbuild-paths/src/dev_daemon_namespace.rs 91 native_path std::env::current_exe host_executable host_mechanic crates/fbuild-toolchain/src/toolchain/esp_qemu.rs 528 attr_cfg #[cfg(windows)] host_executable host_mechanic crates/fbuild-toolchain/src/toolchain/esp_qemu.rs 534 attr_cfg #[cfg(windows)] host_executable host_mechanic crates/fbuild-toolchain/src/toolchain/esp_qemu.rs 565 attr_cfg #[cfg(not(windows))] host_executable host_mechanic