From ee60807d87fbaf45cc72e43d5aa6f2e21e61631f Mon Sep 17 00:00:00 2001 From: Leo Li Date: Sat, 31 Oct 2026 02:23:20 +0000 Subject: [PATCH] cmux-tui-core: a new release stamp no longer recompiles cmux-tui-core release::DISTRIBUTION_VERSION read CMUX_TUI_DISTRIBUTION_VERSION with option_env!, and the Linux pool stamps it per build (0.0.0-r2.sha-, macos-cross.sh, cmux-tui-build-package.yml), so every stamp recompiled cmux-tui-core and everything above it. #21980 moved core's other stamps to the binary (install_build_stamp); release.rs came a day later with its own. Core now reads release::distribution_version(): the value the binary installs at start (install_distribution_version, next to install_build_stamp), the same filter (a placeholder stamp is not a release), and the workspace crate version until then (core's tests, which saw the same value before). The binary keeps its own DISTRIBUTION_VERSION constant and DISTRIBUTION_STAMP, the one option_env! read. Test: cargo test -p cmux-tui-core --lib only_a_release_stamp_is_reported_as_the_release Co-Authored-By: Claude Opus 5.5 Agent-Session: https://cmux.com/deeplink/agent?id=aid-2f016c499153c1bead46 --- cmux-tui/crates/cmux-tui-core/src/release.rs | 40 +++++++++++++++++-- .../src/server/agent_session_proxy.rs | 2 +- .../src/server/api_revision_wire.rs | 2 +- .../src/server/api_revision_wire_tests.rs | 2 +- .../cmux-tui-core/src/server/cmd_server.rs | 2 +- cmux-tui/crates/cmux-tui/src/main.rs | 1 + .../crates/cmux-tui/src/session/remote.rs | 3 +- .../cmux-tui/src/session/remote/connect.rs | 2 +- .../crates/cmux-tui/src/version_report.rs | 16 +++++++- 9 files changed, 58 insertions(+), 12 deletions(-) diff --git a/cmux-tui/crates/cmux-tui-core/src/release.rs b/cmux-tui/crates/cmux-tui-core/src/release.rs index c06c376746b3..2a8f837e598b 100644 --- a/cmux-tui/crates/cmux-tui-core/src/release.rs +++ b/cmux-tui/crates/cmux-tui-core/src/release.rs @@ -9,10 +9,27 @@ use std::path::{Component, Path}; /// test build, or a raw R2 tree artifact stamped `0.0.0-r2.sha-…` that the /// app bundles) reports the one cmux-next version, the workspace crate /// version, which `scripts/cmux-next/check-version-surfaces.sh` requires. -pub const DISTRIBUTION_VERSION: &str = match option_env!("CMUX_TUI_DISTRIBUTION_VERSION") { - Some(version) if is_release(version) => version, - _ => env!("CARGO_PKG_VERSION"), -}; +/// The binary stamps it (`CMUX_TUI_DISTRIBUTION_VERSION`) and installs it at +/// start ([`install_distribution_version`]), so a new stamp (every build of +/// the Linux pool) recompiles the binary and not this crate. +pub fn distribution_version() -> &'static str { + INSTALLED_DISTRIBUTION_VERSION.get().copied().unwrap_or(env!("CARGO_PKG_VERSION")) +} + +static INSTALLED_DISTRIBUTION_VERSION: std::sync::OnceLock<&'static str> = + std::sync::OnceLock::new(); + +/// Records the binary's stamped release, `None` when it has none. A placeholder +/// stamp is not a release ([`is_release`]). The first call wins. +pub fn install_distribution_version(stamped: Option<&'static str>) { + let _ = INSTALLED_DISTRIBUTION_VERSION.set(release_or_workspace(stamped)); +} + +/// A release stamp as the version to report: the workspace crate version for +/// none or a placeholder. +fn release_or_workspace(stamped: Option<&str>) -> &str { + stamped.filter(|version| is_release(version)).unwrap_or(env!("CARGO_PKG_VERSION")) +} /// A release version: not empty and not a `0.0.0-…` placeholder stamp. pub const fn is_release(version: &str) -> bool { @@ -127,3 +144,18 @@ pub fn update_hint_for(install: Option<&str>) -> String { ), } } + +#[cfg(test)] +mod distribution_tests { + /// What the binary installs is what `DISTRIBUTION_VERSION` was when this + /// crate read the stamp itself: a release as stamped, anything else the + /// workspace crate version. + #[test] + fn only_a_release_stamp_is_reported_as_the_release() { + use super::release_or_workspace; + assert_eq!(release_or_workspace(Some("0.13.4")), "0.13.4"); + assert_eq!(release_or_workspace(Some("0.0.0-r2.sha-abc")), env!("CARGO_PKG_VERSION")); + assert_eq!(release_or_workspace(Some("")), env!("CARGO_PKG_VERSION")); + assert_eq!(release_or_workspace(None), env!("CARGO_PKG_VERSION")); + } +} diff --git a/cmux-tui/crates/cmux-tui-core/src/server/agent_session_proxy.rs b/cmux-tui/crates/cmux-tui-core/src/server/agent_session_proxy.rs index 8b30c3391601..05fd5cacdd75 100644 --- a/cmux-tui/crates/cmux-tui-core/src/server/agent_session_proxy.rs +++ b/cmux-tui/crates/cmux-tui-core/src/server/agent_session_proxy.rs @@ -140,7 +140,7 @@ pub(super) fn bind( writer, id, json!({"app": "cmux-tui", "protocol": super::super::PROTOCOL_VERSION, - "version": crate::release::DISTRIBUTION_VERSION, "generation": mux.registry_identity().1, + "version": crate::release::distribution_version(), "generation": mux.registry_identity().1, "capabilities": ["agent-session-attach-v1", "agent-session-observe-v1"]}), ) } diff --git a/cmux-tui/crates/cmux-tui-core/src/server/api_revision_wire.rs b/cmux-tui/crates/cmux-tui-core/src/server/api_revision_wire.rs index b17bffb70e1b..b3f3b153d96e 100644 --- a/cmux-tui/crates/cmux-tui-core/src/server/api_revision_wire.rs +++ b/cmux-tui/crates/cmux-tui-core/src/server/api_revision_wire.rs @@ -67,7 +67,7 @@ pub(super) fn too_old_text(why: &str, version: Option<&str>, install: Option<&st let release = version.map_or_else(String::new, |version| format!(" (cmux {version})")); format!( "this client{release} is too old for this cmux-tui daemon (cmux {}): {why}. To fix it, {}", - crate::release::DISTRIBUTION_VERSION, + crate::release::distribution_version(), crate::release::update_hint_for(install) ) } diff --git a/cmux-tui/crates/cmux-tui-core/src/server/api_revision_wire_tests.rs b/cmux-tui/crates/cmux-tui-core/src/server/api_revision_wire_tests.rs index 6e7bbfb1b165..f02679699ddb 100644 --- a/cmux-tui/crates/cmux-tui-core/src/server/api_revision_wire_tests.rs +++ b/cmux-tui/crates/cmux-tui-core/src/server/api_revision_wire_tests.rs @@ -129,7 +129,7 @@ fn api_revision_too_old_refusal_names_the_clients_update_command() { ); let identity = run(json!({"cmd":"identify","revisions":true})).unwrap(); - assert_eq!(identity["version"], crate::release::DISTRIBUTION_VERSION); + assert_eq!(identity["version"], crate::release::distribution_version()); assert!(identity["install"].is_string()); mux.shutdown(); } diff --git a/cmux-tui/crates/cmux-tui-core/src/server/cmd_server.rs b/cmux-tui/crates/cmux-tui-core/src/server/cmd_server.rs index a00094146e3d..90afaf5e9951 100644 --- a/cmux-tui/crates/cmux-tui-core/src/server/cmd_server.rs +++ b/cmux-tui/crates/cmux-tui-core/src/server/cmd_server.rs @@ -44,7 +44,7 @@ pub(super) fn identify( let mut identity = json!({ "app": "cmux-tui", // The npm/PyPI release (the crate version in the app and local builds). - "version": crate::release::DISTRIBUTION_VERSION, + "version": crate::release::distribution_version(), "build_commit": stamped_build_commit(), "build_id": build_id, "cli_path": cli_path, diff --git a/cmux-tui/crates/cmux-tui/src/main.rs b/cmux-tui/crates/cmux-tui/src/main.rs index a722c4d95aa0..38b00867bd62 100644 --- a/cmux-tui/crates/cmux-tui/src/main.rs +++ b/cmux-tui/crates/cmux-tui/src/main.rs @@ -1710,6 +1710,7 @@ pub fn main() -> std::process::ExitCode { unsafe { startup_env::take_link_token_from_env() }; // Before any mode can serve `identify` or `ping`. cmux_tui_core::server::install_build_stamp(build_stamp()); + cmux_tui_core::release::install_distribution_version(version_report::DISTRIBUTION_STAMP); // `cmux` (CLI and mux) and `acpmux` (a symlink) are one binary, one version. #[cfg(unix)] if std::env::args_os() diff --git a/cmux-tui/crates/cmux-tui/src/session/remote.rs b/cmux-tui/crates/cmux-tui/src/session/remote.rs index c09c6aec74aa..2653a3b0b10d 100644 --- a/cmux-tui/crates/cmux-tui/src/session/remote.rs +++ b/cmux-tui/crates/cmux-tui/src/session/remote.rs @@ -166,7 +166,8 @@ fn validate_remote_identity(ident: &Value) -> anyhow::Result<()> { /// The refusal for a version skew, naming the exact update command of the /// side that is too old (plans/cmux-next/tui-tester-rollout.md #4). fn skew_refusal(ident: &Value, protocol: u64, client_too_old: bool) -> String { - use cmux_tui_core::release::{DISTRIBUTION_VERSION, InstallChannel, update_hint_for}; + use crate::version_report::{DISTRIBUTION_VERSION, InstallChannel}; + use cmux_tui_core::release::update_hint_for; let server = ident.get("version").and_then(Value::as_str).unwrap_or("unknown"); if client_too_old { format!( diff --git a/cmux-tui/crates/cmux-tui/src/session/remote/connect.rs b/cmux-tui/crates/cmux-tui/src/session/remote/connect.rs index 766ad2e24f81..3003401c120a 100644 --- a/cmux-tui/crates/cmux-tui/src/session/remote/connect.rs +++ b/cmux-tui/crates/cmux-tui/src/session/remote/connect.rs @@ -185,7 +185,7 @@ impl RemoteSession { // how we were installed, so it can translate for us or name our // update command when it refuses (server/api_revision_wire.rs). if ident.get("api_revision").is_some() { - use cmux_tui_core::release::{DISTRIBUTION_VERSION, InstallChannel}; + use crate::version_report::{DISTRIBUTION_VERSION, InstallChannel}; client_info.set( "api_revision", json!( diff --git a/cmux-tui/crates/cmux-tui/src/version_report.rs b/cmux-tui/crates/cmux-tui/src/version_report.rs index 94cdfdbd39e5..92d8dc9c29f0 100644 --- a/cmux-tui/crates/cmux-tui/src/version_report.rs +++ b/cmux-tui/crates/cmux-tui/src/version_report.rs @@ -8,12 +8,24 @@ use std::path::Path; +pub(crate) use cmux_tui_core::release::InstallChannel; use cmux_tui_core::release::is_release; -pub(crate) use cmux_tui_core::release::{DISTRIBUTION_VERSION, InstallChannel}; + +/// This binary's release stamp, `None` for a build that has none. Read only +/// here: cmux-tui-core gets it at start (`install_distribution_version`), so a +/// new stamp recompiles this crate and not the libraries. +pub(crate) const DISTRIBUTION_STAMP: Option<&str> = option_env!("CMUX_TUI_DISTRIBUTION_VERSION"); + +/// The npm/PyPI release that contains this binary, as +/// `cmux_tui_core::release::distribution_version` reports it once installed. +pub(crate) const DISTRIBUTION_VERSION: &str = match DISTRIBUTION_STAMP { + Some(version) if is_release(version) => version, + _ => env!("CARGO_PKG_VERSION"), +}; /// Whether this binary was stamped as an npm/PyPI release (not a `0.0.0-…` /// placeholder): crash forwarding and the update check run only then. -pub(crate) const RELEASE_STAMPED: bool = match option_env!("CMUX_TUI_DISTRIBUTION_VERSION") { +pub(crate) const RELEASE_STAMPED: bool = match DISTRIBUTION_STAMP { Some(version) => is_release(version), None => false, };