feat(version): V4 beta-in-isolation channel via -DREASAMPLER_CHANNEL

Compile-time channel flag forks a fully isolated reaper_reasampler_beta
(namespace, command-id prefix, action names, dock ident, -beta render) from
one auditable app_version definition. Stable identity byte-unchanged.
This commit is contained in:
2026-07-26 16:06:24 -04:00
parent 0a9d8200c7
commit 5c0e3a8ccf
13 changed files with 648 additions and 224 deletions
+84 -9
View File
@@ -1,24 +1,99 @@
// app_version.cpp — implementation of the pure version-identity core (Phase V, V1).
// See app_version.h for the contract. The version STRING itself comes from
// version_generated.h (produced by CMake configure_file from the one REASAMPLER_VERSION
// variable) — this TU just re-exports it and owns the pure parse/compare/classify logic.
// app_version.cpp — implementation of the pure version-identity core (Phase V, V1 + V4).
// See app_version.h for the contract. The version STRING and the channel bit both come
// from version_generated.h (produced by CMake configure_file from the one
// REASAMPLER_VERSION variable + the REASAMPLER_CHANNEL flag) — this TU re-exports them and
// owns every pure derivation: the channel-qualified identity strings (V4) and the
// parse/compare/classify logic (V1). No #ifdef forks leak beyond this file; the shells
// consume the accessors below, so channel identity is one auditable definition.
#include "app_version.h"
#include <string>
#include "version_generated.h" // REASAMPLER_VERSION_STRING — configure_file'd from CMake
#include "version_generated.h" // REASAMPLER_VERSION_STRING + REASAMPLER_CHANNEL_IS_BETA
namespace reasampler {
namespace {
// The one channel predicate every derivation below branches on — the single point the
// configure_file'd bit enters the pure module. constexpr so the branches fold at compile
// time; the accessors still return by const ref for a stable shared instance.
constexpr bool kIsBeta = (REASAMPLER_CHANNEL_IS_BETA != 0);
} // namespace
Channel channel() { return kIsBeta ? Channel::Beta : Channel::Stable; }
bool isBeta() { return kIsBeta; }
const std::string& appVersion() {
// Function-local static: initialized once from the compile-time string, returned by
// const ref so callers share the one authoritative instance. The macro is the exact
// CMake value, leading zero and all.
static const std::string kVersion = REASAMPLER_VERSION_STRING;
// The user-visible render. Stable: EXACTLY the CMake string (leading zero and all).
// Beta: the same numeric string plus a plain "-beta" suffix (V2). Function-local
// static so callers share one authoritative instance.
static const std::string kVersion =
kIsBeta ? std::string(REASAMPLER_VERSION_STRING) + "-beta"
: std::string(REASAMPLER_VERSION_STRING);
return kVersion;
}
const std::string& stampVersion() {
// The ext-state stamp value — the NUMERIC TRIPLE ONLY, IDENTICAL on both channels.
// No "-beta" suffix: it must parse as Stamped on read-back (a suffixed stamp classifies
// as Unknown), and stable's stamp stays byte-identical regardless of the channel build.
// The channel is carried by extStateNamespace(), never baked into the stamp.
static const std::string kStamp = REASAMPLER_VERSION_STRING;
return kStamp;
}
const std::string& extStateNamespace() {
// Stable "reasampler" is byte-identical to the pre-V4 build; beta is isolated.
// FOREVER-STABLE per channel.
static const std::string kNs = kIsBeta ? "reasampler_beta" : "reasampler";
return kNs;
}
const std::string& commandIdPrefix() {
// Stable prefix is byte-identical to every shipped command id; beta is a distinct
// forever-family. FOREVER-STABLE per channel.
static const std::string kPrefix =
kIsBeta ? "CEREBELLUM_REASAMPLER_BETA_" : "CEREBELLUM_REASAMPLER_";
return kPrefix;
}
const std::string& actionDisplayPrefix() {
// Actions-list legibility: two channels must be distinguishable by name. Trailing
// space so callers append the action phrase directly.
static const std::string kDisp = kIsBeta ? "ReaSampler beta: " : "ReaSampler: ";
return kDisp;
}
const std::string& binaryName() {
static const std::string kName =
kIsBeta ? "reaper_reasampler_beta" : "reaper_reasampler";
return kName;
}
const std::string& dockTitle() {
static const std::string kTitle =
kIsBeta ? "ReaSampler Bank beta" : "ReaSampler Bank";
return kTitle;
}
const std::string& dockIdent() {
// Persisted dock-position ident — FOREVER-STABLE per channel (changing it strands the
// saved dock slot). Beta qualified so the two panels do not fight over one slot.
static const std::string kIdent =
kIsBeta ? "reasampler_bank_panel_beta" : "reasampler_bank_panel";
return kIdent;
}
std::string channelCommandId(const std::string& suffix) {
return commandIdPrefix() + suffix;
}
std::string channelActionName(const std::string& phrase) {
return actionDisplayPrefix() + phrase;
}
std::optional<Version> parseVersion(const std::string& s) {
// Split on '.' into exactly three non-empty all-digit components. No sign, no
// whitespace, no trailing garbage. Leading zeros are allowed (0.9.01 parses to