diff --git a/crates/aura-cli/src/main.rs b/crates/aura-cli/src/main.rs index 9c39769..2ea536b 100644 --- a/crates/aura-cli/src/main.rs +++ b/crates/aura-cli/src/main.rs @@ -125,7 +125,7 @@ fn sim_optimal_manifest( // Typed params pass straight through: the manifest carries self-describing // Scalars, so a length stays `i64` and a scale `f64` in the record. RunManifest { - commit: option_env!("AURA_COMMIT").unwrap_or("unknown").to_string(), + commit: ENGINE_COMMIT.to_string(), params, defaults: Vec::new(), window, @@ -2640,10 +2640,36 @@ fn parse_scalar_csv(csv: &str) -> Option> { // the campaign path. Usage errors (clap parse + argv-applicability guards) exit 2; // runtime failures exit 1. -/// The `aura` root parser. `#[command(version)]` reads `CARGO_PKG_VERSION` -/// (the workspace `0.1.0`), so `aura --version` prints `aura 0.1.0`. +/// The single build-time commit provenance (`option_env!("AURA_COMMIT")`, +/// falling back to `"unknown"`): both `--version` (via `version_string`) and +/// `sim_optimal_manifest`'s `RunManifest.commit` read this one const, so a +/// stale binary is distinguishable from a fresh one at the CLI surface, +/// before any run, without a second commit-sourcing mechanism (#266). +const ENGINE_COMMIT: &str = match option_env!("AURA_COMMIT") { + Some(c) => c, + None => "unknown", +}; + +/// `aura 0.1.0 ()` as a process-lifetime `&'static str` — computed once +/// (clap's `version` builder method wants `Into`, and `clap::builder::Str` +/// (clap 4.6) only implements `From<&'static str>`, not `From`, so the +/// one owned `String` this formats is leaked for the process's lifetime, same +/// as any other CLI one-shot startup string). +fn version_string() -> &'static str { + static VERSION: std::sync::OnceLock = std::sync::OnceLock::new(); + VERSION.get_or_init(|| format!("{} ({ENGINE_COMMIT})", env!("CARGO_PKG_VERSION"))) +} + +/// The `aura` root parser. `version` is built from `CARGO_PKG_VERSION` (the +/// workspace `0.1.0`) plus the parenthesized `ENGINE_COMMIT`, so +/// `aura --version` prints `aura 0.1.0 ()`. #[derive(Parser)] -#[command(name = "aura", version, about = "Author, backtest, and validate trading strategies — research CLI", infer_long_args = true)] +#[command( + name = "aura", + version = version_string(), + about = "Author, backtest, and validate trading strategies — research CLI", + infer_long_args = true +)] struct Cli { #[command(subcommand)] command: Command,