docs(plan): settle Phase V forks V1-V4
V1 semver via project(VERSION), ext-state version stamp first-wave. V2 plain -beta suffix. V3 console line + panel readout. V4 reverses prior rec: beta ships as a separate coexisting binary with isolated ext-state namespace + command-id prefix.
This commit is contained in:
@@ -12,8 +12,21 @@ This doc holds the *why*, the forks, and a recommendation. When Daniel picks, th
|
||||
tickable points land in `PLAN.md` and the deploy/build wiring hands off to dev-ops.
|
||||
This is a framing note; it changes no source or CMake.
|
||||
|
||||
Status: framed by product-designer (2026-07-26). **Forks V1–V4 open — awaiting
|
||||
Daniel.** Nothing here is settled.
|
||||
Status: framed by product-designer (2026-07-26); **all four forks settled by Daniel
|
||||
(2026-07-26).** V1 approved as recommended (ext-state version stamp prioritized to
|
||||
the first wave); V2 plain `-beta` suffix (`git describe` decoration rejected); V3
|
||||
recommendation accepted (console line + panel readout, about-box deferred); **V4
|
||||
reversed the recommendation** — Daniel chose **beta-in-isolation / full coexistence**
|
||||
(separate binary, isolated ext-state namespace, isolated command-id prefix) rather
|
||||
than the branch-discipline/one-at-a-time path the note originally recommended. The
|
||||
"Recommendation" and "Open decisions" sections below have been superseded to reflect
|
||||
the settled state; each records what was chosen and why. Deploy/build wiring hands off
|
||||
to dev-ops.
|
||||
|
||||
> **Note on V4 phrasing (provisional).** The-boss's read of "beta-in-isolation" as
|
||||
> the separate-binary + isolated-namespace + isolated-command-id-prefix coexistence
|
||||
> path is provisional pending a final confirm from Daniel. Written that way here; a
|
||||
> minor correction is a cheap edit.
|
||||
|
||||
---
|
||||
|
||||
@@ -66,7 +79,15 @@ allowed to touch.
|
||||
- The natural user-visible readout already exists: the docked LICE bank panel, and
|
||||
the console (`ShowConsoleMsg`). A version has cheap homes; none is wired.
|
||||
|
||||
## The number itself (V1) — recommendation: **semver, sourced from CMake**
|
||||
## The number itself (V1) — SETTLED (2026-07-26): **semver, sourced from CMake; ext-state stamp lands ASAP / first wave**
|
||||
|
||||
> **Decision (V1).** Approved as recommended. Semver, single source of truth in CMake
|
||||
> `project(reaper_reasampler VERSION x.y.z)`, threaded into the binary. **The
|
||||
> `"reasampler"` ext-state writing-version stamp is prioritized to the first wave, not
|
||||
> deferred** — Daniel emphasized ASAP because *every project saved without the stamp
|
||||
> is harder to migrate later*, so the migration seam must exist before more real
|
||||
> projects accrue un-stamped state. Treat the stamp as an early, high-priority
|
||||
> deliverable that ships with (or ahead of) the first versioned build.
|
||||
|
||||
Recommend **semantic versioning** (`MAJOR.MINOR.PATCH`) with the number's single
|
||||
source of truth in `CMakeLists.txt` via `project(reaper_reasampler VERSION x.y.z)`,
|
||||
@@ -99,9 +120,10 @@ about-string in lockstep from one edit.
|
||||
build literally cannot disagree with the tag; encodes commits-since-tag + dirty
|
||||
state, which is *excellent for a beta* ("1.4.0-beta.3+7.gab12cd"). Con: needs git
|
||||
present at build and a tag discipline; a source tarball without `.git` builds
|
||||
"unknown." **Recommendation: use it for the beta channel's suffix, not as the base
|
||||
number.** Best of both: `project(VERSION)` owns the release triple; `git describe`
|
||||
decorates beta builds. (See V2.)
|
||||
"unknown." **This was originally recommended for the beta suffix — Daniel rejected
|
||||
it** (V2 settled below: a plain `-beta` suffix is more legible than a decorated
|
||||
`git describe` string). `project(VERSION)` still owns the release triple; the beta
|
||||
simply carries `-beta`. (See V2.)
|
||||
- **A hand-maintained `version.h`.** Rejected — a second source of truth that drifts
|
||||
from the tag. The whole point of one source is that release can't ship a binary
|
||||
that lies about its number.
|
||||
@@ -110,7 +132,13 @@ about-string in lockstep from one edit.
|
||||
about migration compatibility, which is the load-bearing use here. Semver earns
|
||||
its place; CalVer doesn't.
|
||||
|
||||
## Where the user sees it (V3) — recommendation: **panel readout + startup log, defer an about box**
|
||||
## Where the user sees it (V3) — SETTLED (2026-07-26): **panel readout + startup log; about box deferred**
|
||||
|
||||
> **Decision (V3).** Recommendation accepted (Daniel deferred to product-designer
|
||||
> judgment — "whatever"). Startup console line (`"ReaSampler x.y.z loaded"`) + a
|
||||
> bank-panel version/channel readout ship; the about-box stays deferred. Panel
|
||||
> placement (header corner / footer / folded into existing chrome) remains a small
|
||||
> residual polish call, same class as the settled active-bank-indicator placement.
|
||||
|
||||
Three candidate homes, cheap to expensive:
|
||||
|
||||
@@ -232,62 +260,95 @@ wants. It's the knob; A and B are policies for the knob.
|
||||
The flag is worth having either way because it makes "what makes a beta a beta" a
|
||||
**single, auditable definition** instead of scattered `#ifdef`s.
|
||||
|
||||
## Recommendation: **B now, built on C, with A as the deliberate upgrade later**
|
||||
## Decision (V4) — SETTLED (2026-07-26): **Option A — beta-in-isolation / full coexistence**
|
||||
|
||||
Start with **Option B (branch discipline, one at a time) implemented through a
|
||||
compile-time channel flag (Option C)**:
|
||||
> **This reverses the note's original recommendation.** The note originally
|
||||
> recommended Option B (branch discipline, one installed at a time) built on the
|
||||
> Option C channel flag, with Option A (true simultaneous coexistence) *seam-designed
|
||||
> but deferred*. **Daniel chose the coexistence path instead.** The superseded
|
||||
> recommendation prose is retained below the decision (struck through in intent, kept
|
||||
> for the reasoning trail) so a future reader sees what was weighed; the decision here
|
||||
> governs.
|
||||
|
||||
- Ship the release from `main` as `reaper_reasampler` with a clean semver
|
||||
(`x.y.z`).
|
||||
- Build beta from `dev` through `-DREASAMPLER_CHANNEL=beta`, which stamps a
|
||||
`-beta`/`-dev.<git-describe>` **version suffix** and a **panel channel indicator**
|
||||
(so a beta is unmistakable at a glance — the version readout from Part 1 doubles as
|
||||
the channel badge). This is where `git describe` earns its keep (V2): the beta
|
||||
suffix carries commits-since-tag so two betas are distinguishable.
|
||||
- **Do not fork the command-id prefix or the ext-state namespace yet** — because
|
||||
under B only one binary loads, so there is nothing to collide with, and forking
|
||||
them prematurely commits you to a second forever-stable id family and splits your
|
||||
own test data for no gain.
|
||||
**Settled shape: beta ships as a separate, fully isolated binary that coexists with
|
||||
stable in one REAPER.** Concretely, all three global identities fork (this *is*
|
||||
Option A, built through the Option C compile-time channel flag as the mechanism):
|
||||
|
||||
Then treat **Option A (true coexistence) as a later, deliberate upgrade** if and
|
||||
only if "swap-and-restart" proves too slow — i.e. you find you genuinely need stable
|
||||
and beta live in one REAPER to compare them. The upgrade is *clean* precisely
|
||||
because you built B on the channel flag: flipping A "on" means extending the same
|
||||
flag to also fork the output name, the command-id prefix (`_BETA_`), and the
|
||||
ext-state namespace (`"reasampler_beta"`). The seam is designed now; the feature is
|
||||
deferred (the same *defer-the-feature-design-the-seam* discipline the project
|
||||
already applies to the owned-file manifest and Phase D adaptability).
|
||||
- **Separate binary** — `reaper_reasampler_beta` alongside `reaper_reasampler`, so
|
||||
REAPER's startup dlopen loads both and the user runs stable and beta side-by-side.
|
||||
- **Isolated ext-state namespace** — the beta writes under its own namespace (e.g.
|
||||
`"reasampler_beta"`), distinct from stable's `"reasampler"`, so **a beta can never
|
||||
read or rewrite a stable project's saved bank/view/tail state.** The price is
|
||||
accepted: a beta does not see a stable project's bank (it looks empty until
|
||||
re-captured under the beta namespace). That is the correct price — isolation over
|
||||
convenience.
|
||||
- **Isolated forever-stable command-id prefix** — the beta mints its own prefix (e.g.
|
||||
`CEREBELLUM_REASAMPLER_BETA_`), so beta and stable actions never collide in
|
||||
REAPER's one Actions list and their keybindings stay independent.
|
||||
|
||||
Why not A first: A's power is real but it forces you to mint a **second permanent
|
||||
command-id namespace** and a **second ext-state namespace** on day one — both
|
||||
irreversible-ish commitments (the ids are forever-stable; the namespace split means
|
||||
beta and stable never share a project's bank). That is a large, permanent price for
|
||||
a convenience (simultaneous compare) you may not need. B pays nothing permanent and
|
||||
keeps A one flag away.
|
||||
The compile-time channel flag (`-DREASAMPLER_CHANNEL=beta`, Option C) remains the
|
||||
implementation mechanism: one flip coordinates output name + command-id prefix +
|
||||
ext-state namespace + `-beta` version suffix + panel channel badge as a single
|
||||
auditable definition, so the three-way divergence can't drift by hand.
|
||||
|
||||
Why not B without the flag: hand-managing the suffix and channel badge across two
|
||||
branches drifts. The flag makes "beta vs. release" one definition and is the exact
|
||||
thing you'd extend for A — so building B *through* C costs little now and saves the
|
||||
A upgrade later.
|
||||
### The two permanent commitments this locks in (recorded honestly)
|
||||
|
||||
### The sharp edge that survives every option: ext-state across a channel swap
|
||||
Choosing coexistence over the deferred-seam path accepts two commitments that are
|
||||
**permanent once the first beta ships** — exactly the prices the original
|
||||
recommendation flagged as reasons to defer:
|
||||
|
||||
Whichever way this goes, call out loudly (and this is a genuine **Daniel decision**,
|
||||
V4): **can a beta build write experimental `"reasampler"` ext-state schema that a
|
||||
stable build might later read?**
|
||||
1. **A second forever-stable command-id prefix.** The beta's ids are their own
|
||||
forever-family (`STABLE_FOREVER_STRING` contract applies to them too the moment a
|
||||
beta ships). Beta keybindings do not carry to stable and vice versa. Irreversible.
|
||||
2. **A second ext-state namespace.** `"reasampler_beta"` is permanent — and its
|
||||
isolation means beta and stable never share a project's bank. This is the safety
|
||||
property, but it is also a fork of your own test data that you own from day one.
|
||||
|
||||
- Under **A** with a forked namespace: no — isolated, safe, at the cost of beta not
|
||||
seeing stable's bank.
|
||||
- Under **B**: yes, sequentially — the project file is shared across a swap. Needs a
|
||||
policy: beta stays schema-compatible, **or** the version-stamp-in-blob (V1) lets
|
||||
stable detect-and-refuse, **or** "don't open beta-touched real projects in stable"
|
||||
is an accepted discipline.
|
||||
Both are deliberate and accepted; recorded here so no future reader treats them as
|
||||
oversights.
|
||||
|
||||
The cheapest robust mitigation across both is **V1's version stamp in the ext-state
|
||||
blob** — it turns a silent mis-read into a detectable "this project was written by a
|
||||
newer/other build." Recommend adopting it as part of the first release wave
|
||||
regardless of the A/B choice, because it's the seam that makes every later channel
|
||||
and migration decision safe.
|
||||
### Deploy / CD implication (dev-ops hand-off)
|
||||
|
||||
The build now **produces two named artifacts per platform** — `reaper_reasampler`
|
||||
(stable) and `reaper_reasampler_beta` (beta) — selected by `REASAMPLER_CHANNEL`.
|
||||
That is a dev-ops handoff: the pipeline builds, names, and publishes both channels
|
||||
(three platform artifacts each). See Part 3.
|
||||
|
||||
### The ext-state safety property, now settled by isolation
|
||||
|
||||
The sharp edge the original note flagged as the genuine V4 sub-decision — *can a beta
|
||||
write experimental ext-state that a stable build later reads?* — is **resolved by the
|
||||
isolated namespace: no.** Beta writes only under `"reasampler_beta"`; stable reads
|
||||
only `"reasampler"`. There is no shared-project corruption path across the channels,
|
||||
neither simultaneous nor sequential. V1's writing-version stamp still lands first-wave
|
||||
(it guards *within-channel* forward migration — stable-1.4 reading stable-1.6 state —
|
||||
which isolation does not address), but it is no longer load-bearing for cross-channel
|
||||
safety.
|
||||
|
||||
---
|
||||
|
||||
### Superseded recommendation (retained for the reasoning trail)
|
||||
|
||||
> The following was the note's original V4 recommendation. **It is superseded by the
|
||||
> settled decision above** (Daniel chose coexistence). Kept because the trade-off
|
||||
> reasoning — the permanent-price argument in particular — is what the decision was
|
||||
> weighed against.
|
||||
|
||||
~~Start with **Option B (branch discipline, one at a time) implemented through a
|
||||
compile-time channel flag (Option C)**~~: ship stable as `reaper_reasampler` from
|
||||
`main`; build beta from `dev` via the channel flag with only a `-beta` suffix + panel
|
||||
badge; **do not fork the command-id prefix or ext-state namespace**, since under B
|
||||
only one binary loads and forking prematurely commits a second forever-stable id
|
||||
family for no gain. Then treat **Option A (true coexistence) as a later, deliberate
|
||||
upgrade** if swap-and-restart proved too slow — the upgrade being clean precisely
|
||||
because B was built on the channel flag (flip A on = extend the flag to fork name +
|
||||
`_BETA_` prefix + `"reasampler_beta"` namespace). The stated reason to defer A: it
|
||||
forces minting a **second permanent command-id namespace** and a **second ext-state
|
||||
namespace** on day one — a large, permanent price for a convenience (simultaneous
|
||||
compare) that might not be needed. **Daniel weighed that price and chose to pay it:
|
||||
the value of running stable and beta side-by-side, with hard isolation guaranteeing a
|
||||
beta can never corrupt stable state, outweighed avoiding the two permanent
|
||||
commitments.**
|
||||
|
||||
---
|
||||
|
||||
@@ -314,21 +375,24 @@ implies these touchpoints:
|
||||
|
||||
---
|
||||
|
||||
# Open decisions for Daniel
|
||||
# Settled decisions (all four — Daniel, 2026-07-26)
|
||||
|
||||
- **V1 — version scheme.** Recommend semver via `project(VERSION)` as single source
|
||||
of truth, **plus a writing-version stamp in the `"reasampler"` ext-state blob** for
|
||||
forward migration/detection. Approve scheme + whether the ext-state stamp lands in
|
||||
the first release wave.
|
||||
- **V2 — beta suffix source.** Recommend `git describe` decorating beta builds
|
||||
(`x.y.z-beta.N+g<hash>`) while `project(VERSION)` owns the release triple. Approve
|
||||
or simplify to a plain `-beta` suffix.
|
||||
- **V3 — user-visible home + placement.** Recommend startup console line + a
|
||||
bank-panel version/channel readout now; about-box deferred. Panel placement
|
||||
(header corner / footer / folded into existing chrome) is the residual call.
|
||||
- **V4 — beta channel shape (the big one).** Recommend **Option B (branch
|
||||
discipline, one at a time) built on an Option C compile-time channel flag**, with
|
||||
**Option A (true simultaneous coexistence) designed-as-a-seam but deferred**. The
|
||||
sub-decision that must be made explicitly either way: **the ext-state-across-a-
|
||||
channel-swap policy** — isolate (A), stay schema-compatible / stamp-and-detect (B),
|
||||
or accept the discipline. This is genuinely Daniel's call, not one to default.
|
||||
- **V1 — version scheme: APPROVED as recommended.** Semver, single source of truth in
|
||||
CMake `project(reaper_reasampler VERSION x.y.z)`, threaded into the binary. **The
|
||||
`"reasampler"` ext-state writing-version stamp is prioritized to the first wave** —
|
||||
every project saved without it is harder to migrate later, so the migration seam
|
||||
lands early, not deferred.
|
||||
- **V2 — beta suffix: plain `-beta`.** `project(VERSION)` owns the release triple;
|
||||
beta builds carry a `-beta` suffix. The `git describe` decoration was considered and
|
||||
**rejected** for legibility ("-beta is better than a random string").
|
||||
- **V3 — user-visible home: recommendation accepted.** Startup console line
|
||||
(`"ReaSampler x.y.z loaded"`) + a bank-panel version/channel readout; about-box
|
||||
deferred. Panel placement remains a small residual polish call.
|
||||
- **V4 — beta channel shape: BETA-IN-ISOLATION (full coexistence).** *Reverses the
|
||||
original recommendation.* Beta ships as a **separate binary**
|
||||
(`reaper_reasampler_beta`) with an **isolated ext-state namespace** and an
|
||||
**isolated forever-stable command-id prefix**, so stable and beta install and run
|
||||
side-by-side with no shared-state corruption path. Locks in two permanent
|
||||
commitments — a second forever-stable command-id prefix and a second ext-state
|
||||
namespace — both accepted. Dev-ops implication: the build now produces two named
|
||||
artifacts (stable + beta) per platform.
|
||||
|
||||
Reference in New Issue
Block a user