docs: fix audit citations — bad line ranges, misattributed evidence, overclaimed severity

Corrects a false unguarded-include claim, re-scopes hot-path evidence to what's actually linked, replaces a nonexistent Fork-A collision scenario, fixes several miscounted TUs/libraries, re-grades two Fork-B items from Blocker to Major/non-blocker, and adds missing owners/done-conditions.
This commit is contained in:
2026-08-02 06:39:31 -04:00
parent 5455b1047b
commit f57bf4fb6d
@@ -13,12 +13,14 @@ and nowhere else.
**Verification posture.** I am on Windows and cannot build or run anything on Linux. Every **Verification posture.** I am on Windows and cannot build or run anything on Linux. Every
claim below is grounded in a file I opened in this worktree — the tree's own CMake, or a claim below is grounded in a file I opened in this worktree — the tree's own CMake, or a
vendored header/source under `vendor/`and every line number was re-read immediately before vendored header/source under `vendor/`not asserted from memory of similar SDKs. Where a
being written down. Where a claim depends on runtime behaviour I cannot observe (does REAPER's claim depends on runtime behaviour I cannot observe (does REAPER's Linux build call
Linux build call `SWELL_dllMain`? does GCC accept this TU?), it is marked `[verify — Linux]` `SWELL_dllMain`? does GCC accept this TU?), it is marked `[verify — Linux]` with the exact
with the exact check, and it is **not** stated as fact. To get the vendored citations I ran check, and it is **not** stated as fact. A subsequent citation pass caught several
`git submodule update --init` for all three submodules inside this worktree; nothing in the line-number and attribution errors in this draft (corrected in place, disclosed at the point
tracked tree was modified. each occurs) — grounded-in-a-file is a floor, not a guarantee against a mis-copied line range.
To get the vendored citations I ran `git submodule update --init` for all three submodules
inside this worktree; nothing in the tracked tree was modified.
Severity vocabulary, per the dispatch: **Blocker** = the Linux build cannot produce a loadable Severity vocabulary, per the dispatch: **Blocker** = the Linux build cannot produce a loadable
artifact; **Major** = it builds but is degraded or unshippable; **Minor** = ergonomics, artifact; **Major** = it builds but is degraded or unshippable; **Minor** = ergonomics,
@@ -30,8 +32,13 @@ names the reason for the band rather than asserting a number.
## 1. Baseline — what the build does today, per platform ## 1. Baseline — what the build does today, per platform
**Two loadable modules, 84 pure libraries declared under `src/core/`, 91 CTest targets, **Two loadable modules, 84 pure libraries declared under `src/core/`, 91 CTest targets,
three vendored submodules.** (84 = the `reasampler_pure_library` + bare `add_library` count three vendored submodules.** (84 = the `reasampler_pure_library` + bare `add_library` count,
across the 19 `src/core/**` CMake files; 46 of them are on the extension's link line.) grep-verified library-by-library across the 18 `src/core/**` CMake files that declare any —
`src/core/CMakeLists.txt` and `src/core/instrument/CMakeLists.txt` declare none, only
`add_subdirectory` calls (plus one test in the latter); there are 20 CMake files under
`src/core/**` total, matching the 19 figure in §1d below, which counts *test* declarations
across the whole tree, not `src/core/**` alone. 46 of the 84 are on the extension's link
line.)
- Root `CMakeLists.txt` is 95 lines and declares **no targets at all**: it owns the version - Root `CMakeLists.txt` is 95 lines and declares **no targets at all**: it owns the version
string (`:24`), the channel fork (`:4054`), the `configure_file` for string (`:24`), the channel fork (`:4054`), the `configure_file` for
@@ -55,8 +62,8 @@ across the 19 `src/core/**` CMake files; 46 of them are on the extension's link
### 1a. The REAPER extension (`reaper_reasampler`) ### 1a. The REAPER extension (`reaper_reasampler`)
Declared as a `MODULE` library over 39 shell TUs plus `${LICE_SRC}` Declared as a `MODULE` library over 39 listed TUs (38 shell TUs + `app/main.cpp` itself)
(`src/app/CMakeLists.txt:851`), linking 46 pure static libraries (`:52`) with plus `${LICE_SRC}` (`src/app/CMakeLists.txt:851`), linking 46 pure static libraries (`:52`) with
`${SDK_INC} ${WDL_INC}` on the include path (`:56`). Output naming is `${SDK_INC} ${WDL_INC}` on the include path (`:56`). Output naming is
`PREFIX ""` + channel-derived `OUTPUT_NAME`, pinned to the top of the build tree by `PREFIX ""` + channel-derived `OUTPUT_NAME`, pinned to the top of the build tree by
`LIBRARY_OUTPUT_DIRECTORY`/`ARCHIVE_OUTPUT_DIRECTORY` (`:6569`). `LIBRARY_OUTPUT_DIRECTORY`/`ARCHIVE_OUTPUT_DIRECTORY` (`:6569`).
@@ -73,6 +80,13 @@ So on Linux the build system today produces `reaper_reasampler.so` with the SWEL
compiled in and **no dialog resource of any kind**. `README.md:6768` states this is compiled in and **no dialog resource of any kind**. `README.md:6768` states this is
"expected, not a bug" — the tree is honest about it. "expected, not a bug" — the tree is honest about it.
**Open question, macOS-only, unresolved by this doc.** The APPLE branch adds
`${SWELL}/swell-modstub.mm` (`:79`), an Objective-C++ TU, but `CMakeLists.txt:26` is
`project(reaper_reasampler VERSION 1.4.0 LANGUAGES CXX)` — OBJCXX is never enabled anywhere
in the tree. Whether CMake resolves a `.mm` source against a plain CXX-only project (some
Apple-toolchain configurations infer Objective-C++ from the extension regardless; others do
not) is unverified from this tree and untestable without a macOS box. `[verify — macOS]`.
Three build-input facts I verified in `vendor/` and that hold in the extension's favour: Three build-input facts I verified in `vendor/` and that hold in the extension's favour:
- `vendor/WDL/WDL/swell/swell-modstub-generic.cpp` is entirely inside - `vendor/WDL/WDL/swell/swell-modstub-generic.cpp` is entirely inside
@@ -91,9 +105,16 @@ Three build-input facts I verified in `vendor/` and that hold in the extension's
`SWELL_PushClipRegion`/`SWELL_SetClipRegion` (`:10271028`) and `SWELL_PopClipRegion` `SWELL_PushClipRegion`/`SWELL_SetClipRegion` (`:10271028`) and `SWELL_PopClipRegion`
(`:1048`). All six are entries in SWELL's API table (`:1048`). All six are entries in SWELL's API table
(`vendor/WDL/WDL/swell/swell-functions.h:857`, `:863`, `:877`, `:885887`), so the (`vendor/WDL/WDL/swell/swell-functions.h:857`, `:863`, `:877`, `:885887`), so the
modstub resolves them from the host. No fifth LICE TU is implied: the `_LICE_RGB2HSV` modstub resolves them from the host. No fifth LICE TU is implied: the `_LICE_RGB2HSV_invtab`
table lives inside `lice.cpp` itself (`:3040`), and the one non-Win32-only helper table lives inside `lice.cpp` itself (`:3040`), and the one non-Win32-only helper
`utf8makechar` is a file-static defined at `lice_textnew.cpp:26` and used at `:241242`. `utf8makechar` is a file-static defined at `lice_textnew.cpp:26` and used at `:241242`.
This is a link-success inference, not a from-first-principles proof — the actual proof is
V1, a successful build. One loose end: SWELL's own `Makefile:106107` lists
`lice_colorspace.o` among the LICE objects *its* build needs — a fifth TU we don't compile.
It stays unreconciled but harmless: `lice_colorspace.cpp` defines the real `LICE_RGB2HSV`
function (declared `lice.h:577`, distinct from the `_invtab` table above), and grepping our
four LICE_SRC TUs and all of `src/` for a call to it returns nothing — SWELL needs the TU
for its own generic-GDK backend, which our four-TU slice never invokes into.
- `CMAKE_POSITION_INDEPENDENT_CODE ON` (`CMakeLists.txt:30`) is already set. This is the - `CMAKE_POSITION_INDEPENDENT_CODE ON` (`CMakeLists.txt:30`) is already set. This is the
single most commonly missed setting for a `MODULE` target fed by `STATIC` libraries on single most commonly missed setting for a `MODULE` target fed by `STATIC` libraries on
Linux, and it is correct today. Linux, and it is correct today.
@@ -109,7 +130,8 @@ non-goal: `src/core/instrument/CLAUDE.md` (Non-goals/guardrails) and
`src/shell/instrument/CLAUDE.md` (same). `src/shell/panel/CLAUDE.md` carries a third `src/shell/instrument/CLAUDE.md` (same). `src/shell/panel/CLAUDE.md` carries a third
instance ("Windows-only (D5) — font/GDI/HFONT choices assume Windows"). instance ("Windows-only (D5) — font/GDI/HFONT choices assume Windows").
Inside the gate: a 19-source `vst3_sdk` static library (`:1539`) pinned to SDK tag Inside the gate: a 20-source `vst3_sdk` static library (`:1638`, grep-counted; lines 28/29/37
are comments) pinned to SDK tag
`v3.7.9_build_61` (confirmed by `git describe --tags` in `vendor/vst3sdk`), and the `v3.7.9_build_61` (confirmed by `git describe --tags` in `vendor/vst3sdk`), and the
`reasampler_vst` MODULE (`:4481`) which additionally compiles `dllmain.cpp` and `reasampler_vst` MODULE (`:4481`) which additionally compiles `dllmain.cpp` and
`moduleinit.cpp` directly (`:7879`, with the linker-stripping rationale at `:7577`) plus `moduleinit.cpp` directly (`:7879`, with the linker-stripping rationale at `:7577`) plus
@@ -152,8 +174,11 @@ surface**; see §3 for the one generator-shape caveat.
- `:364366` — "Install is copy-in + restart… there is no server-side rollout." - `:364366` — "Install is copy-in + restart… there is no server-side rollout."
What that document does **not** contain: any mention of code signing, macOS notarization, a What that document does **not** contain: any mention of code signing, macOS notarization, a
CI runner, or a Linux install path. I grepped it for `sign|notariz|CI|platform|linux`the CI runner, or a Linux install path. I grepped it for `sign|notariz|CI|platform|linux`one
only hits are the lines above. There is no CI configuration anywhere in the repo (`ls -a` on hit is not cited above (`:393`, "artifacts (stable + beta) per platform", the same dev-ops
handoff as `:307310`); the rest are the lines above. The substantive conclusion — no
signing/notarization/CI/Linux-install-path mention anywhere — holds regardless. There is no
CI configuration anywhere in the repo (`ls -a` on
the root shows `.git`, `.gitignore`, `.gitmodules`, `CLAUDE.md`, `CMakeLists.txt`, `LICENSE`, the root shows `.git`, `.gitignore`, `.gitmodules`, `CLAUDE.md`, `CMakeLists.txt`, `LICENSE`,
`README.md`, `cmake`, `docs`, `src`, `tests`, `vendor` — no `.github`, no `.gitlab-ci.yml`), `README.md`, `cmake`, `docs`, `src`, `tests`, `vendor` — no `.github`, no `.gitlab-ci.yml`),
and no `install()` rule in any of the 23 CMake files. So "the pipeline" is entirely notional and no `install()` rule in any of the 23 CMake files. So "the pipeline" is entirely notional
@@ -211,7 +236,15 @@ Blocker only because the binary loads and the actions work.
**The route worth considering first.** `swell-functions.h:606608` documents an escape **The route worth considering first.** `swell-functions.h:606608` documents an escape
hatch: *"If you are using CreateDialog() and creating a child window, you can use a resource hatch: *"If you are using CreateDialog() and creating a child window, you can use a resource
ID of 0, which creates an opaque child window. Instead of passing a DLGPROC, you should pass ID of 0, which creates an opaque child window. Instead of passing a DLGPROC, you should pass
a (WNDPROC) routine that returns LRESULT (and cast it to DLGPROC)."* `src/resource.rc:1822` a (WNDPROC) routine that returns LRESULT (and cast it to DLGPROC)."* The header comment is
not just documentation — the implementation confirms both halves of it:
`swell-dlg-generic.cpp:291292` is `SWELL_DialogResourceIndex *p=resById(reshead,resid); if
(!p&&resid) return 0;`, and `resById` (`:3443`) walks from a (here, null) `reshead` and
returns 0 on a miss. That confirms the graceful-failure claim behind "Major rather than
Blocker" above (a null `reshead` plus a non-zero `resid` returns 0, not a crash — matching
`panel_window.cpp:137`'s `if (!g_panel.hwnd) return;`), **and** that `resid == 0` skips the
lookup entirely (`&&resid` short-circuits), which is the escape hatch this paragraph is about.
`src/resource.rc:1822`
shows `IDD_BANK_PANEL` is precisely that: a `WS_CHILD` dialog with an empty body and zero shows `IDD_BANK_PANEL` is precisely that: a `WS_CHILD` dialog with an empty body and zero
controls, whose comment at `:810` says "the bank_panel shell owns every pixel and draws the controls, whose comment at `:810` says "the bank_panel shell owns every pixel and draws the
sample grid with LICE in `WM_PAINT`". If the panel is created with resource id 0 on sample grid with LICE in `WM_PAINT`". If the panel is created with resource id 0 on
@@ -243,14 +276,26 @@ optimize-and-ship incantation, and `README.md:130131` tells the user to copy
is accepted and ignored. Because no `CMAKE_BUILD_TYPE` default is set, the resulting build is accepted and ignored. Because no `CMAKE_BUILD_TYPE` default is set, the resulting build
passes **no `-O` flag at all** to GCC/Clang — not `-O0` explicitly, just the compiler's passes **no `-O` flag at all** to GCC/Clang — not `-O0` explicitly, just the compiler's
unoptimized default. The failure is silent in both directions: the command succeeds, and the unoptimized default. The failure is silent in both directions: the command succeeds, and the
artifact lands at `build/reaper_reasampler.so` rather than the documented `build/Release/` artifact lands at `build/reaper_reasampler.so` — a path the docs never state for a
path (see Λ-08). single-config generator (a gap, not an error; see Λ-08).
This matters more here than the usual "forgot to set the build type", because `CLAUDE.md`'s This matters more here than the usual "forgot to set the build type" — but only for `peaks`.
own performance guardrails section states that the header-inline hot paths (`peaks` `CLAUDE.md`'s §"Build and test" (not §"Performance guardrails") states, at `CLAUDE.md:54`,
envelope compute, `Voice::advanceFrame`, the three envelope evaluators) "presume an that the header-inline hot paths "presume an **optimizing** build", with no LTO configured to
**optimizing** build", and there is no LTO configured to recover any of it. A Linux user recover it if they don't. `peaks`' `computeEnvelope`/`lastFrameAboveThreshold` is one of
following the README would ship a binary whose hottest loops did not inline. those paths and IS linked into the extension (`src/app/CMakeLists.txt:52`), so the finding
holds for Fork A as stated. It does **not** extend to `Voice::advanceFrame` or the three
`envelopes.h` evaluators (named at `src/core/instrument/CLAUDE.md:342`, not in root
`CLAUDE.md`) — those belong to `sampler_core`, which `src/app/CMakeLists.txt:5355` states is
deliberately NOT linked into the extension and which only enters a build at all inside the
Windows-gated `reasampler_vst` target (§1b). On Fork A that code never compiles into
`reaper_reasampler` in the first place; the unoptimized-build risk to it is a Fork B concern,
not this extension-only one. A Linux user following the README's `--config Release` would
ship an extension binary whose `peaks` hot path did not inline.
**Done when:** `cmake --build build` on Linux (Ninja/Make, no `--config`) produces a build
whose compile commands (`compile_commands.json` or verbose build log) show an explicit `-O`
flag, and the README/CLAUDE.md ship instruction names the single-config-generator path.
**Sequencing note.** This is not strictly Linux-specific — Ninja on Windows has the same **Sequencing note.** This is not strictly Linux-specific — Ninja on Windows has the same
shape — but it becomes load-bearing the moment Linux is a shipped platform, because Makefiles shape — but it becomes load-bearing the moment Linux is a shipped platform, because Makefiles
@@ -272,11 +317,19 @@ modules — the rationale for the duplication is at `CMakeLists.txt:7577`);
`-fvisibility=default` and every non-static symbol in both modules — all of LICE, all the `-fvisibility=default` and every non-static symbol in both modules — all of LICE, all the
WDL helpers, every pure library's exported functions, and the whole C++ standard-library WDL helpers, every pure library's exported functions, and the whole C++ standard-library
instantiation set — lands in the module's dynamic symbol table. On Windows this is a instantiation set — lands in the module's dynamic symbol table. On Windows this is a
non-issue: each DLL has its own symbol table and per-module resolution. On Linux ELF, symbols non-issue: each DLL has its own symbol table and per-module resolution. `[verify — Linux]`
from `dlopen`'d objects can participate in global interposition, so `reaper_reasampler.so`'s on ELF, symbols from `dlopen`'d objects CAN participate in global interposition — but whether
`LICE_FillRect` and a hypothetical `reasampler_9000.so`'s `LICE_FillRect` are candidates to they actually do here depends on REAPER's own `dlopen` flags (`RTLD_GLOBAL` vs `RTLD_LOCAL`)
bind to the same definition. That is a class of bug that presents as "the VST editor draws and whether REAPER's executable is linked `--export-dynamic`, neither of which this tree can
with the extension's LICE build" and is invisible on Windows. answer. The scenario this doc originally named — a hypothetical `reasampler_9000.so` — does
not exist on Fork A: per Λ-10 and `src/shell/instrument/CMakeLists.txt:9`, the VST3 target is
gated `WIN32 AND EXISTS ...` and is never built on Linux unless D1 selects Fork B. The
Fork-A-real risk is different: any **second REAPER extension** loaded in the same REAPER
process (a third-party `.so` in `UserPlugins/`) that links its own copy of LICE/WDL and also
defaults to `-fvisibility=default` is a candidate to interpose with `reaper_reasampler.so`'s
`LICE_FillRect` and the rest of the exported LICE/WDL symbol set. That is a class of bug that
presents as "one extension's LICE draws with another extension's LICE build" and is invisible
on Windows, where each DLL keeps its own symbol table.
**Why hiding is safe here.** The two symbols that genuinely must be exported already say so **Why hiding is safe here.** The two symbols that genuinely must be exported already say so
explicitly: `reaper_plugin.h:52` defines explicitly: `reaper_plugin.h:52` defines
@@ -288,6 +341,11 @@ thing to confirm on a Linux box is that `swell-modstub-generic.cpp:135`'s `SWELL
survives — it carries its own `__attribute__ ((visibility ("default")))` at that line, so it survives — it carries its own `__attribute__ ((visibility ("default")))` at that line, so it
should, but the modstub is compiled by *our* build, not SWELL's. should, but the modstub is compiled by *our* build, not SWELL's.
*Shared macOS/Linux — the visibility default and the LICE-TU duplication (`CMakeLists.txt:7577`)
apply the same way under the APPLE branch's Mach-O two-level namespace, though the concrete
Fork-A-real interposition mechanism above is ELF-specific; macOS's own dynamic-linker symbol
resolution is a separate `[verify]` this doc does not attempt.*
--- ---
### Λ-04 — nothing links a thread library, and `<pthread.h>` is in the extension's include graph ### Λ-04 — nothing links a thread library, and `<pthread.h>` is in the extension's include graph
@@ -300,10 +358,14 @@ should, but the modstub is compiled by *our* build, not SWELL's.
**What breaks.** No CMake file in the tree calls `find_package(Threads)` or links **What breaks.** No CMake file in the tree calls `find_package(Threads)` or links
`Threads::Threads`/`-lpthread`/`-ldl` (grep-verified across all 23). Two separate exposures: `Threads::Threads`/`-lpthread`/`-ldl` (grep-verified across all 23). Two separate exposures:
- **Extension.** `panel_state.h:23` includes `<pthread.h>` on non-Win32. I did not find a - **Extension.** `panel_state.h:23` includes `<pthread.h>` on non-Win32 — and it is not the
pthread *call* in the panel's own code, so this may be an include-only dependency that only entry point: `vendor/reaper-sdk/sdk/reaper_plugin.h:50` includes `<pthread.h>`
needs no link flag on a modern glibc (where the pthread symbols are in libc proper). That unconditionally in its non-Windows branch, so it is in **every** shell TU's include graph
makes it Minor, and `[verify — Linux]`. (every `.cpp` that includes `reaper_plugin.h`/`reaper_plugin_functions.h`), not just the
one panel file. This strengthens rather than changes the finding: I still did not find a
pthread *call* in `src/shell/`'s own code, so this may be an include-only dependency that
needs no link flag on a modern glibc (where the pthread symbols are in libc proper). Stays
Minor, and `[verify — Linux]`.
- **VST3 target.** `flock.cpp` is unambiguous: on non-Windows it calls - **VST3 target.** `flock.cpp` is unambiguous: on non-Windows it calls
`pthread_mutexattr_init`/`_settype`/`_destroy` (`:7176`), `pthread_mutex_init` (`:74`), `pthread_mutexattr_init`/`_settype`/`_destroy` (`:7176`), `pthread_mutex_init` (`:74`),
`pthread_mutex_destroy` (`:89`), `_lock` (`:105`), `_unlock` (`:121`) and `_trylock` `pthread_mutex_destroy` (`:89`), `_lock` (`:105`), `_unlock` (`:121`) and `_trylock`
@@ -314,6 +376,13 @@ should, but the modstub is compiled by *our* build, not SWELL's.
Adding `find_package(Threads REQUIRED)` + `target_link_libraries(... Threads::Threads)` is Adding `find_package(Threads REQUIRED)` + `target_link_libraries(... Threads::Threads)` is
correct on all three platforms and costs nothing on Windows. correct on all three platforms and costs nothing on Windows.
**Done when:** the extension links with `Threads::Threads` removed (proving the include-only
half needs no flag, or naming the symbol that forces it — see V5), and, if Fork B is taken,
`reasampler_vst` links clean with `Threads::Threads` present.
*Shared macOS/Linux — `reaper_plugin.h:50`'s non-Windows `<pthread.h>` include and
`flock.cpp`'s non-Windows pthread calls apply identically to the APPLE branch.*
--- ---
### Λ-05 — `reaper_plugin.h`'s SWELL include resolves only by coincidence of the `-I` line ### Λ-05 — `reaper_plugin.h`'s SWELL include resolves only by coincidence of the `-I` line
@@ -345,7 +414,7 @@ fail only on Linux/macOS. Worth pinning before more targets are added.
**Citations.** `src/app/CMakeLists.txt:851` and `:7198`; **Citations.** `src/app/CMakeLists.txt:851` and `:7198`;
`src/shell/actions/drag_out_win.cpp:8`, `:249`, `:282`. `src/shell/actions/drag_out_win.cpp:8`, `:249`, `:282`.
**Mechanism.** All 39 shell TUs are listed unconditionally (`:851`); the platform block at **Mechanism.** All 38 shell TUs (plus `app/main.cpp`, 39 listed TUs total) are listed unconditionally (`:851`); the platform block at
`:7198` only *adds* sources, never removes or substitutes any. Every TU therefore enters a `:7198` only *adds* sources, never removes or substitutes any. Every TU therefore enters a
Linux compile, and the only thing standing between the build and a compile error is each Linux compile, and the only thing standing between the build and a compile error is each
file's own `#ifdef` discipline. Today that discipline is uneven in a way worth recording: file's own `#ifdef` discipline. Today that discipline is uneven in a way worth recording:
@@ -374,28 +443,40 @@ extension's. GCC 8 requires an explicit `-lstdc++fs` for `std::filesystem`; GCC
libstdc++ ≥ 9 do not. `README.md:51` states only "A C++17 compiler" as the prerequisite, and libstdc++ ≥ 9 do not. `README.md:51` states only "A C++17 compiler" as the prerequisite, and
`cmake_minimum_required(VERSION 3.19)` (`CMakeLists.txt:1`) says nothing about the compiler. `cmake_minimum_required(VERSION 3.19)` (`CMakeLists.txt:1`) says nothing about the compiler.
On any current distro toolchain this is a non-issue; it becomes one on an older CI image. On any current distro toolchain this is a non-issue; it becomes one on an older CI image.
Twelve other files in `src/shell/` also use `<filesystem>` (grep), but they are all in the Twelve other files in `src/shell/` also use `<filesystem>` (grep-verified), but one —
extension target, which shares the same fix. `src/shell/instrument/instrument_bake.cpp` — is in the `reasampler_vst` target, not the
extension: eleven in `reaper_reasampler`, sharing the fix below; the twelfth shares it only
if/when Fork B builds that target on Linux.
**Done when:** `capture_paths_tests` links on the oldest toolchain the phase targets without
`-lstdc++fs` added explicitly, or that flag is added and documented as the floor.
*Shared macOS/Linux — `capture_paths` and the eleven extension-side `<filesystem>` users
compile identically under the APPLE branch; whether Apple's libc++ needs the same kind of
minimum-toolchain floor as libstdc++ does is a separate `[verify]` this doc has not checked,
but the coverage-hole shape (undocumented compiler floor) is identical either way.*
--- ---
### Λ-08 — the artifact path and the install instruction are both wrong for a single-config generator ### Λ-08 — the install instruction is silent about single-config generators, and no path is documented for Linux at all
**Severity: Minor. Effort: S — a doc fix, or an `install()` rule if packaging is ever automated.** **Severity: Minor. Effort: S — a doc fix, or an `install()` rule if packaging is ever automated.**
**Citations.** `src/app/CMakeLists.txt:68` (`LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}"`); **Citations.** `src/app/CMakeLists.txt:68` (`LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}"`);
`README.md:130133`; `CLAUDE.md` §"Install / reload"; `README.md:130131`; `CLAUDE.md` §"Install / reload";
`docs/product/versioning-and-release.md:364366`. `docs/product/versioning-and-release.md:364366`.
**What breaks.** On a multi-config generator CMake appends the config directory, giving the **What breaks — a gap, not an error.** `README.md:130131` and `CLAUDE.md` §"Install /
documented `build/Release/`. On Ninja/Make the module lands directly at reload" both already carry the multi-config qualifier verbatim ("`build/Release/` on a
`build/reaper_reasampler.so`, so the README's "copy from `build/Release/`" instruction has no multi-config generator — not the default `Debug/` output") — so the instruction is not
matching directory on Linux. Compounding it, there is no `install()` rule anywhere in the 23 wrong, it is simply silent about the other case. On a multi-config generator CMake appends
CMake files, and no target directory is documented for Linux at all — `CLAUDE.md` and the config directory, giving the documented `build/Release/`. On Ninja/Make the module lands
`README.md:132` say "REAPER's `UserPlugins/` folder (Options → Show REAPER resource path)", directly at `build/reaper_reasampler.so`, and neither doc names that path. Compounding it,
which is a correct user-facing instruction but not a path a pipeline can use. I could not there is no `install()` rule anywhere in the 23 CMake files, and no target directory is
confirm REAPER's Linux resource-path root from the SDK: grepping documented for Linux at all — `CLAUDE.md` and `README.md:132` say "REAPER's `UserPlugins/`
`vendor/reaper-sdk/sdk/` for `UserPlugins` and `reaper_*.so` returns nothing — the folder (Options → Show REAPER resource path)", which is a correct user-facing instruction but
`reaper_*.dll|dylib|so` filename convention stated in `CLAUDE.md` is not documented in the not a path a pipeline can use. I could not confirm REAPER's Linux resource-path root from the
SDK: grepping `vendor/reaper-sdk/sdk/` for `UserPlugins` and `reaper_*.so` returns nothing —
the `reaper_*.dll|dylib|so` filename convention stated in `CLAUDE.md` is not documented in the
vendored headers. `[verify — Linux]`. vendored headers. `[verify — Linux]`.
--- ---
@@ -420,6 +501,28 @@ GCC/Clang compile as `-std=gnu++17` rather than `-std=c++17`. Not a bug; a hygie
worth flipping while the flags are being set, since it is the difference between "portable worth flipping while the flags are being set, since it is the difference between "portable
C++17" and "whatever GNU extensions happened to be used". C++17" and "whatever GNU extensions happened to be used".
**Coverage hole: the link-succeeds-but-load-fails asymmetry is never stated.** GNU `ld` does
not error on undefined symbols in a shared object by default — MSVC's linker does. For a
`MODULE` REAPER `dlopen()`s, that means a Linux build can link `reaper_reasampler.so` clean
and only discover a missing symbol when REAPER tries to load it (`dlopen` failing, or a
partially-resolved symbol table if a satisfying-by-coincidence symbol exists elsewhere in the
process — a real risk given Λ-03's global-interposition finding above). Neither `Threads`
(Λ-04) nor visibility (Λ-03) named this asymmetry, and it undercuts §5's framing of V1
(`cmake --build build`) as "the single highest-information action available" — a clean build
on Linux does not carry the same guarantee a clean Windows build does. `-Wl,--no-undefined`
(GNU ld) would restore the MSVC-equivalent fail-at-link-time behavior; whether it is needed
here specifically depends on whether `SWELL_PROVIDED_BY_APP`'s function-pointer design (§1a)
already accounts for every symbol the modstub doesn't itself define — that is `[verify —
Linux]`, since it requires an actual GCC/Clang link to observe.
**Done when:** the Linux build either adds `-Wl,--no-undefined` (or the equivalent) so an
undefined-symbol build failure surfaces at link time, or a stated reason is recorded for why
`SWELL_PROVIDED_BY_APP` makes the gap moot.
*Shared macOS/Linux — `-Wall -Wextra`, `CMAKE_CXX_EXTENSIONS OFF`, and the GNU-ld-vs-MSVC-ld
asymmetry (macOS's linker also does not default to erroring on undefined symbols) apply
identically to the APPLE branch.*
--- ---
### Λ-10 — the submodule story costs a Linux developer a large download for a target that is gated off ### Λ-10 — the submodule story costs a Linux developer a large download for a target that is gated off
@@ -470,8 +573,10 @@ pass.
build` works bare on Linux; the `-C Debug` in the README's example is harmless there. build` works bare on Linux; the `-C Debug` in the README's example is harmless there.
- **SWELL API coverage for the LICE slice** — all six SWELL GDI entry points LICE needs are - **SWELL API coverage for the LICE slice** — all six SWELL GDI entry points LICE needs are
in the modstub-resolved table (`swell-functions.h:857`, `:863`, `:877`, `:885887`). in the modstub-resolved table (`swell-functions.h:857`, `:863`, `:877`, `:885887`).
- **The LICE slice needs no fifth TU on Linux** (`lice.cpp:3040` colorspace table, - **The LICE slice needs no fifth TU on Linux** (`lice.cpp:3040` `_LICE_RGB2HSV_invtab`
`lice_textnew.cpp:26` file-static `utf8makechar`). table, `lice_textnew.cpp:26` file-static `utf8makechar`) — an inference from V1's link
success plus these two spot checks, not exhaustive; see §1a's fuller caveat, including the
unreconciled `lice_colorspace.o` in SWELL's own `Makefile:106107`.
- **`swell-modstub-generic.cpp` compiles against its own includes** — it uses `printf` - **`swell-modstub-generic.cpp` compiles against its own includes** — it uses `printf`
(`:61`), which arrives via `swell.h``swell-types.h:29` (`#include <stdio.h>`). The (`:61`), which arrives via `swell.h``swell-types.h:29` (`#include <stdio.h>`). The
`dlopen`/`readlink` block (`:69131`) is behind `SWELL_LOAD_SWELL_DYLIB`, which this build `dlopen`/`readlink` block (`:69131`) is behind `SWELL_LOAD_SWELL_DYLIB`, which this build
@@ -506,13 +611,16 @@ one-line-ish but load-bearing (Λ-02 optimization, Λ-03 visibility), one Major/
change to any product decision on record. change to any product decision on record.
**The unknown that dominates the band:** none of the extension's source portability is **The unknown that dominates the band:** none of the extension's source portability is
audited here. The build-system work is small; whether the 39 shell TUs *compile and behave* audited here. The build-system work is small; whether the 38 shell TUs *compile and behave*
against SWELL's Win32 subset is T2's answer, and it, not this list, sets the phase's size. against SWELL's Win32 subset is T2's answer, and it, not this list, sets the phase's size.
### Fork B — extension + ReaSampler 9000 on Linux ### Fork B — extension + ReaSampler 9000 on Linux
Everything in Fork A, plus the following. Each item is a Blocker for the VST3 artifact — Everything in Fork A, plus the following. Three of five are Blockers under the severity
without it there is no loadable `.vst3`. vocabulary defined above ("the Linux build cannot produce a loadable artifact"): B1, B2, B3.
B4 downgrades to Major — the module still loads; only the editor fails to attach without it.
B5 is not a technical blocker at all — it is a documentation act, though one that must
precede the others in sequence (see §6 Stage 5).
- **B1 — the entry point is the wrong one, and the right one is already vendored.** - **B1 — the entry point is the wrong one, and the right one is already vendored.**
`src/shell/instrument/CMakeLists.txt:78` compiles `src/shell/instrument/CMakeLists.txt:78` compiles
@@ -522,11 +630,14 @@ without it there is no loadable `.vst3`.
`#if defined(_MSC_VER) && defined(DEVELOPMENT)` (`:43`, `:96`) and `#ifdef __cplusplus` `#if defined(_MSC_VER) && defined(DEVELOPMENT)` (`:43`, `:96`) and `#ifdef __cplusplus`
(`:58`, `:87`). Linux needs (`:58`, `:87`). Linux needs
`public.sdk/source/main/linuxmain.cpp`, which is present in the slice and exports `public.sdk/source/main/linuxmain.cpp`, which is present in the slice and exports
`ModuleEntry`/`ModuleExit` (`linuxmain.cpp:4752`, `:5982`). Both are **mandatory** — the `ModuleEntry`/`ModuleExit` (`extern "C"` declarations `linuxmain.cpp:4752`; definitions
`:5967` and `:7282` respectively). Both are **mandatory** — the
SDK's own loader refuses the module without either SDK's own loader refuses the module without either
(`public.sdk/source/vst/hosting/module_linux.cpp:189204`, error strings "The shared (`public.sdk/source/vst/hosting/module_linux.cpp:189204`, error strings "The shared
library does not export the required 'ModuleEntry' function" and the same for `ModuleExit`). library does not export the required 'ModuleEntry' function" and the same for `ModuleExit`).
`GetPluginFactory` is checked at `:205`. **Effort S.** `GetPluginFactory` is checked at `:205`. **Effort S** — a `CMakeLists.txt` source swap
(`dllmain.cpp``linuxmain.cpp`) plus the platform `if()`; both files are already vendored,
nothing to write from scratch.
- **B2 — the artifact is a directory bundle, not a file.** Today the target sets - **B2 — the artifact is a directory bundle, not a file.** Today the target sets
`SUFFIX ".vst3"` on a MODULE (`src/shell/instrument/CMakeLists.txt:106111`), producing a `SUFFIX ".vst3"` on a MODULE (`src/shell/instrument/CMakeLists.txt:106111`), producing a
@@ -551,12 +662,13 @@ without it there is no loadable `.vst3`.
reads `/proc/self/exe`, strips to the directory, and `dlopen`s `libSwell.so` beside the reads `/proc/self/exe`, strips to the directory, and `dlopen`s `libSwell.so` beside the
host binary (`:8198`), then calls `SWELL_set_app_main(SWELLAppMain)` (`:112114`). That host binary (`:8198`), then calls `SWELL_set_app_main(SWELLAppMain)` (`:112114`). That
reference makes `SWELLAppMain` a **required definition in the plugin** — it is declared at reference makes `SWELLAppMain` a **required definition in the plugin** — it is declared at
`swell-types.h:137` as "to be implemented by app". Whether REAPER's Linux install ships a `swell-types.h:137` as "to be implemented by app (if using swellappmain.mm)". Whether
REAPER's Linux install ships a
`libSwell.so` beside its executable is `[verify — Linux]`, and this route makes the VST3 `libSwell.so` beside its executable is `[verify — Linux]`, and this route makes the VST3
load-bearing on being hosted by REAPER specifically, which is consistent with D5's load-bearing on being hosted by REAPER specifically, which is consistent with D5's
REAPER-only stance but is a new runtime coupling to state explicitly. REAPER-only stance but is a new runtime coupling to state explicitly.
- **Route B3b — build SWELL into the module.** `vendor/WDL/WDL/swell/Makefile:100104` - **Route B3b — build SWELL into the module.** `vendor/WDL/WDL/swell/Makefile:100104`
enumerates the 13 SWELL TUs (`swell.o swell-ini.o swell-miscdlg-generic.o enumerates the 14 SWELL TUs (`swell.o swell-ini.o swell-miscdlg-generic.o
swell-wnd-generic.o swell-menu-generic.o swell-kb-generic.o swell-dlg-generic.o swell-wnd-generic.o swell-menu-generic.o swell-kb-generic.o swell-dlg-generic.o
swell-gdi-generic.o swell-misc-generic.o swell-gdi-lice.o swell-generic-headless.o swell-gdi-generic.o swell-misc-generic.o swell-gdi-lice.o swell-generic-headless.o
swell-generic-gdk.o swell-appstub-generic.o swell-modstub-generic.o`) and `:106107` the 8 swell-generic-gdk.o swell-appstub-generic.o swell-modstub-generic.o`) and `:106107` the 8
@@ -577,7 +689,11 @@ without it there is no loadable `.vst3`.
defined as on other platforms." The whole `namespace Linux` block is `#if SMTG_OS_LINUX` defined as on other platforms." The whole `namespace Linux` block is `#if SMTG_OS_LINUX`
(`:209`, closed `:284`), so it compiles in automatically. The **build-side** cost is nil (`:209`, closed `:284`), so it compiles in automatically. The **build-side** cost is nil
(the IIDs are already vendored — see §3); the **source-side** cost is `editor_platform.cpp` (the IIDs are already vendored — see §3); the **source-side** cost is `editor_platform.cpp`
and every timer in the editor, which is T2's surface. **Effort: build S, source L.** and every timer in the editor, which is T2's surface. **Effort: build S, source L** — build
is S because no new CMake source is needed (the SDK block compiles in automatically); source
is L because it is a genuine window/run-loop rewrite (an X11 embed contract with no Win32
analogue, not a mechanical port) and outside this doc's own portability scope to size
further.
- **B5 — a settled product decision has to be reversed, in writing.** D5 ("Windows-only, - **B5 — a settled product decision has to be reversed, in writing.** D5 ("Windows-only,
VST3-only, REAPER-only") is recorded as a locked decision with "a mac/Linux build" named VST3-only, REAPER-only") is recorded as a locked decision with "a mac/Linux build" named
@@ -585,7 +701,9 @@ without it there is no loadable `.vst3`.
and again under Non-goals/guardrails) and `src/shell/instrument/CLAUDE.md` and again under Non-goals/guardrails) and `src/shell/instrument/CLAUDE.md`
(Non-goals/guardrails). `src/shell/panel/CLAUDE.md` carries a third dependent statement. (Non-goals/guardrails). `src/shell/panel/CLAUDE.md` carries a third dependent statement.
Fork B is not just more work — it invalidates three recorded invariants and needs Daniel's Fork B is not just more work — it invalidates three recorded invariants and needs Daniel's
explicit reversal before any code moves. explicit reversal before any code moves. **Effort S** — no code or CMake change of its own,
a rewrite of the three `CLAUDE.md` passages naming D5 plus Daniel's sign-off; the L-sized
cost sits in B3/B4, not here.
**The asymmetry worth naming.** Fork A's build work is small and its unknown is source **The asymmetry worth naming.** Fork A's build work is small and its unknown is source
portability. Fork B's build work is genuinely large (B2, B3) *and* carries an unbounded portability. Fork B's build work is genuinely large (B2, B3) *and* carries an unbounded
@@ -601,7 +719,7 @@ are different-shaped commitments.
| # | Question | Exact check | | # | Question | Exact check |
|---|---|---| |---|---|---|
| V1 | Does the extension compile at all under GCC/Clang? | `cmake -B build -S . -G Ninja && cmake --build build 2>&1 \| tee build.log` this is the single highest-information action available and gates most of T2's list too. | | V1 | Does the extension compile at all under GCC/Clang? | `cmake -B build -S . -G Ninja && cmake --build build 2>&1 \| tee build.log` — the single highest-information action available and gates most of T2's list too, with one caveat (Λ-09): a clean link is not the same guarantee here as on MSVC, since GNU `ld` does not error on undefined symbols in a `MODULE` by default — V1 answers "does it compile and link", not "does it load". |
| V2 | Does `ctest` pass all 91 targets? | `cmake -B build -S . -G Ninja && cmake --build build && ctest --test-dir build --output-on-failure` (no `-C` needed on Ninja). | | V2 | Does `ctest` pass all 91 targets? | `cmake -B build -S . -G Ninja && cmake --build build && ctest --test-dir build --output-on-failure` (no `-C` needed on Ninja). |
| V3 | Does REAPER's Linux build call `SWELL_dllMain` in a `reaper_*.so`, populating the API table? | Drop the built `.so` in `~/.config/REAPER/UserPlugins/`, restart, and check the extension's actions appear. A null table shows as immediate crash or dead actions. | | V3 | Does REAPER's Linux build call `SWELL_dllMain` in a `reaper_*.so`, populating the API table? | Drop the built `.so` in `~/.config/REAPER/UserPlugins/`, restart, and check the extension's actions appear. A null table shows as immediate crash or dead actions. |
| V4 | Where exactly is `UserPlugins/` on Linux, and is `reaper_*.so` the right filename glob? | Options → Show REAPER resource path in a Linux REAPER. The SDK headers do not document either — grep of `vendor/reaper-sdk/sdk/` for `UserPlugins` and `reaper_*.so` returns nothing. | | V4 | Where exactly is `UserPlugins/` on Linux, and is `reaper_*.so` the right filename glob? | Options → Show REAPER resource path in a Linux REAPER. The SDK headers do not document either — grep of `vendor/reaper-sdk/sdk/` for `UserPlugins` and `reaper_*.so` returns nothing. |
@@ -610,7 +728,7 @@ are different-shaped commitments.
| V7 | With Λ-01 fixed by the resource-id-0 route, does `SWELL_CreateDialog` return a usable child HWND for the docker? | Panel toggle action in a Linux REAPER. | | V7 | With Λ-01 fixed by the resource-id-0 route, does `SWELL_CreateDialog` return a usable child HWND for the docker? | Panel toggle action in a Linux REAPER. |
| V8 | Does `std::filesystem` need `-lstdc++fs` on the chosen toolchain? | Build `capture_paths_tests` alone; the link error names it. | | V8 | Does `std::filesystem` need `-lstdc++fs` on the chosen toolchain? | Build `capture_paths_tests` alone; the link error names it. |
| V9 | Does REAPER's Linux install ship a `libSwell.so` beside its executable (Fork B, route B3a)? | `ls $(dirname $(readlink -f $(which reaper)))/libSwell.so`. | | V9 | Does REAPER's Linux install ship a `libSwell.so` beside its executable (Fork B, route B3a)? | `ls $(dirname $(readlink -f $(which reaper)))/libSwell.so`. |
| V10 | Which `uname -m` values must the VST3 bundle carry (Fork B, B2)? | `uname -m` on each target — REAPER ships x86_64, aarch64 and armv7l Linux builds, and `module_linux.cpp:158163` keys the bundle directory off exactly this string. | | V10 | Which `uname -m` values must the VST3 bundle carry (Fork B, B2)? | `uname -m` on each target. `module_linux.cpp:158163` keys the bundle directory off exactly this string (tree-grounded and verified); which architectures REAPER itself ships for Linux (x86_64, aarch64, armv7l is the claim) is an external fact with no source in this tree — `[verify]` against REAPER's own download page before relying on it. |
### `[Daniel]` — genuine product/scope calls ### `[Daniel]` — genuine product/scope calls
@@ -618,9 +736,10 @@ are different-shaped commitments.
|---|---|---| |---|---|---|
| D1 | **Fork A or Fork B?** Extension only, or extension + ReaSampler 9000 on Linux? | §4 states both costs. The choice is scope, and D5 makes it a reversal of a recorded decision, not a technical lookup. | | D1 | **Fork A or Fork B?** Extension only, or extension + ReaSampler 9000 on Linux? | §4 states both costs. The choice is scope, and D5 makes it a reversal of a recorded decision, not a technical lookup. |
| D2 | If Fork B: **route B3a (dlopen the host's `libSwell.so`, requires defining `SWELLAppMain`) or B3b (vendor and build full SWELL, adds GDK/GTK3 + FreeType + Fontconfig + OpenGL)?** | B3b is a dependency-surface expansion; the dispatch requires that be flagged rather than chosen. B3a is cheaper but couples the plugin's UI to being hosted by REAPER specifically. | | D2 | If Fork B: **route B3a (dlopen the host's `libSwell.so`, requires defining `SWELLAppMain`) or B3b (vendor and build full SWELL, adds GDK/GTK3 + FreeType + Fontconfig + OpenGL)?** | B3b is a dependency-surface expansion; the dispatch requires that be flagged rather than chosen. B3a is cheaper but couples the plugin's UI to being hosted by REAPER specifically. |
| D3 | Is **macOS in or out** of the same phase? | Λ-01 is a *shared* macOS/Linux fix (both branches carry the identical broken comment block, `src/app/CMakeLists.txt:8386` vs `:9497`), and `swell_resgen.php` output is shared per `README.md:120`. Doing both at once is cheaper than doing them serially — but that is a scope call, and macOS additionally implies signing/notarization, which `versioning-and-release.md` does not mention anywhere. | | D3 | Is **macOS in or out** of the same phase? | Λ-01, Λ-03, Λ-04, Λ-07 and Λ-09 are all marked *shared macOS/Linux* at their own sections above (Λ-01: identical broken comment block, `src/app/CMakeLists.txt:8386` vs `:9497`, and shared `swell_resgen.php` output per `README.md:120`; Λ-03/04/07/09: same mechanism under the APPLE branch, detailed at each). Doing both at once is cheaper than doing them serially — but that is a scope call, and macOS additionally implies signing/notarization (not mentioned anywhere in `versioning-and-release.md`) plus its own open question this doc does not resolve: whether `swell-modstub.mm` (`src/app/CMakeLists.txt:79`) even compiles under a CXX-only `project()` (`CMakeLists.txt:26`, no `OBJCXX`) — see §1a. |
| D4 | Does **CI get built in this phase**, and on what runner? | `versioning-and-release.md:307311` and `:361363` hand "the pipeline" to dev-ops and commit to three platform artifacts per channel, but no CI exists in the repo on any platform. Adding it is infrastructure and needs an explicit ask. | | D4 | Does **CI get built in this phase**, and on what runner? | `versioning-and-release.md:307311` and `:361363` hand "the pipeline" to dev-ops and commit to three platform artifacts per channel, but no CI exists in the repo on any platform. Adding it is infrastructure and needs an explicit ask. |
| D5 | Is the Linux artifact **shipped or developer-only** for 1.x? | Determines whether Λ-02 (Release build) and Λ-08 (install path) are must-fix or nice-to-have, and whether a Linux `install()` rule is worth authoring. | | D6 | Is the Linux artifact **shipped or developer-only** for 1.x? | Determines whether Λ-02 (Release build) and Λ-08 (install path) are must-fix or nice-to-have, and whether a Linux `install()` rule is worth authoring. (Numbered D6, not D5, to avoid colliding with the settled product decision D5 — "Windows-only, VST3-only, REAPER-only" — cited above at §1b and B5.) |
| D7 | Λ-01's fork: **resource-id-0 escape hatch, or the resgen route?** §6 Stage 2 gates on T2's read of `panel_window.cpp`, and V7 presupposes the route is already picked. | It is a source-code + build-pipeline tradeoff (a `panel_window.cpp` DLGPROC→WNDPROC change vs. a PHP build step + generated-file handling) with no code-only right answer — needs Daniel's call once T2 reports, same as D1/D2. |
Deliberately **not** listed as `[Daniel]`, because reading more would settle them: whether Deliberately **not** listed as `[Daniel]`, because reading more would settle them: whether
`arrange_drop_win.cpp`/`instrument_drop_win.cpp` need platform gating (read the files — T2); `arrange_drop_win.cpp`/`instrument_drop_win.cpp` need platform gating (read the files — T2);
@@ -655,7 +774,7 @@ non-Windows sibling, the source list in `src/app/CMakeLists.txt:851` gains it
partition. Strictly after T2 and after Stage 2 (the resgen/shim TU, if that route is taken, partition. Strictly after T2 and after Stage 2 (the resgen/shim TU, if that route is taken,
is one of the entries). is one of the entries).
**Stage 4 — packaging.** Λ-08, plus whatever D5 decides. Depends on Stage 1 (there is no **Stage 4 — packaging.** Λ-08, plus whatever D6 decides. Depends on Stage 1 (there is no
point documenting an install path for an unoptimized artifact) and on V4. point documenting an install path for an unoptimized artifact) and on V4.
**Stage 5 — Fork B, only if D1 says so.** Internally ordered: B1 (entry point swap, S) → **Stage 5 — Fork B, only if D1 says so.** Internally ordered: B1 (entry point swap, S) →
@@ -692,5 +811,3 @@ parallel track owns each of these and I have deliberately not investigated furth
7. `src/core/capture/capture_paths.cpp``normalizeSlashes` lowercases on `_WIN32` only, and 7. `src/core/capture/capture_paths.cpp``normalizeSlashes` lowercases on `_WIN32` only, and
`tests/test_capture_paths.cpp:1946` already encodes the case-sensitive POSIX contract. `tests/test_capture_paths.cpp:1946` already encodes the case-sensitive POSIX contract.
The test is written; the behaviour under a case-sensitive filesystem is unverified. The test is written; the behaviour under a case-sensitive filesystem is unverified.
8. `src/shell/instrument/reasampler_editor.h:30` — unguarded `#include <windows.h>`. Only
matters under Fork B.