docs: archive M10 provenance to COMPLETED; reconcile CLAUDE.md + CONTEXT.md

M10 landed. CLAUDE.md gains provenance/provenance_shell entries, test
target, and a current-state refresh; CONTEXT.md null-test line annotated
(verification action cut, manual only).
This commit is contained in:
2026-07-26 18:16:36 -04:00
parent c81e125241
commit a75174f3d5
5 changed files with 73 additions and 50 deletions
+4 -1
View File
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Repo identity and current state ## Repo identity and current state
The CMake project and binary are now named `reaper_reasampler`. This is **ReaSampler** — a per-project audio sample-bank capture tool. The MPE modules (`mpe_model`, `mpe_view`) have been removed. M0M4 are complete: `bank_model` (Sample metadata + BankIndex with JSON round-trip), `peaks` (waveform min/max bin computation), the `capture` shell's offline-render path (DAW-verified spike: master-mix / time-selection capture to a project-relative bank at 32-bit float WAV, non-destructive), and `persist` (BankIndex ↔ project ext state: `SetProjExtState`/`GetProjExtState` under namespace `"reasampler"`, GUID-based project identity, project-relative path resolution, Save-As bank relocation with copy semantics) are all implemented and tested. The remaining REAPER-facing shells (`insert`, `bank_panel`, `actions`) and the realtime backend are being built out per CONTEXT.md / PLAN.md. The *discipline* — pure REAPER-free testable core split from REAPER-facing shells — is **preserved** throughout. The CMake project and binary are now named `reaper_reasampler`. This is **ReaSampler** — a per-project audio sample-bank capture tool. The MPE modules (`mpe_model`, `mpe_view`) have been removed. M0M8 are complete (bank_model, peaks, capture offline+realtime, persist, bank_panel, insert, capture action family, RealtimeRecordBackend, tail T1+T2+T1-followons). Phase B multi-bank (B1B5, B-cap), Phase D1/D2 Design View (D1D5, D2-W1W3-B), Phase V versioning/beta-channel (V1/V3, V4), and M10 provenance + re-capture from source have all landed. M9 slots, M11 polish, and Phase R prune remain. The *discipline* — pure REAPER-free testable core split from REAPER-facing shells — is **preserved** throughout.
CONTEXT.md is the authoritative spec and build roadmap. Read it first for any non-trivial task. Every REAPER API name cited there is correct-by-intent; verify argument order, types, and flag values against `vendor/reaper-sdk/sdk/reaper_plugin_functions.h` before use. CONTEXT.md is the authoritative spec and build roadmap. Read it first for any non-trivial task. Every REAPER API name cited there is correct-by-intent; verify argument order, types, and flag values against `vendor/reaper-sdk/sdk/reaper_plugin_functions.h` before use.
@@ -36,6 +36,7 @@ Key targets (see CMakeLists.txt for the full list):
| `wav_trim_tests` | executable | Pure unit tests for `wav_trim` — no REAPER, no DAW. | | `wav_trim_tests` | executable | Pure unit tests for `wav_trim` — no REAPER, no DAW. |
| `owned_manifest_tests` | executable | Pure unit tests for `owned_manifest` — no REAPER, no DAW. | | `owned_manifest_tests` | executable | Pure unit tests for `owned_manifest` — no REAPER, no DAW. |
| `app_version_tests` | executable | Pure unit tests for `app_version` — no REAPER, no DAW. | | `app_version_tests` | executable | Pure unit tests for `app_version` — no REAPER, no DAW. |
| `provenance_tests` | executable | Pure unit tests for `provenance` — no REAPER, no DAW. |
| `reaper_reasampler` | loadable module | The actual extension binary (`.dll` / `.dylib` / `.so`). | | `reaper_reasampler` | loadable module | The actual extension binary (`.dll` / `.dylib` / `.so`). |
### Beta channel build (Phase V, V4) ### Beta channel build (Phase V, V4)
@@ -71,6 +72,7 @@ There is no hot-reload. Copy the built binary into REAPER's `UserPlugins/` folde
- `owned_manifest` — owned-file manifest seam (Phase B B-cap): the set of project-relative files the capture path itself created, persisted under the `"owned_files"` ext-state key, so Phase R prune can distinguish the bank system's own orphans from hand-dropped files. Deliberately decoupled from `bank_book` — tracks files created, not index membership. Phase R (R1/R2) consumes it; no prune logic here. - `owned_manifest` — owned-file manifest seam (Phase B B-cap): the set of project-relative files the capture path itself created, persisted under the `"owned_files"` ext-state key, so Phase R prune can distinguish the bank system's own orphans from hand-dropped files. Deliberately decoupled from `bank_book` — tracks files created, not index membership. Phase R (R1/R2) consumes it; no prune logic here.
- `app_version` — REAPER-free version/channel identity (Phase V, V1+V4): CMake-sourced semver constant (`appVersion()`), ext-state stamp value (`stampVersion()` — numeric triple only, no channel suffix), `parseVersion`/`versionLess`/`classifyWritingVersion`, and the full set of channel-derived identity accessors (`extStateNamespace()`, `commandIdPrefix()`, `actionDisplayPrefix()`, `binaryName()`, `dockTitle()`, `dockIdent()`, `channelCommandId()`, `channelActionName()`). All channel strings derive from the one `REASAMPLER_CHANNEL_IS_BETA` bit threaded in via `configure_file``version_generated.h`; no scattered `#ifdef`s in the shells. - `app_version` — REAPER-free version/channel identity (Phase V, V1+V4): CMake-sourced semver constant (`appVersion()`), ext-state stamp value (`stampVersion()` — numeric triple only, no channel suffix), `parseVersion`/`versionLess`/`classifyWritingVersion`, and the full set of channel-derived identity accessors (`extStateNamespace()`, `commandIdPrefix()`, `actionDisplayPrefix()`, `binaryName()`, `dockTitle()`, `dockIdent()`, `channelCommandId()`, `channelActionName()`). All channel strings derive from the one `REASAMPLER_CHANNEL_IS_BETA` bit threaded in via `configure_file``version_generated.h`; no scattered `#ifdef`s in the shells.
- `wav_trim` — 32-bit-float WAV parse + header-aware truncate plan (RIFF/data size rewrite) for the realtime tail's PCM decay-scan trim (T2). Rejects WAVE_FORMAT_EXTENSIBLE with non-float SubFormat GUID. Depends on `peaks` for the `AudioSample` float alias. - `wav_trim` — 32-bit-float WAV parse + header-aware truncate plan (RIFF/data size rewrite) for the realtime tail's PCM decay-scan trim (T2). Rejects WAVE_FORMAT_EXTENSIBLE with non-float SubFormat GUID. Depends on `peaks` for the `AudioSample` float alias.
- `provenance` — capture-recipe fingerprint (M10): build/encode/compare a `rsprov1` length-prefixed fingerprint of scope, exact range, tail, rate/channels, track GUIDs, and order-sensitive FX-chain identity; parse/compare for drift detection on re-capture. A thin reproducibility fingerprint — NOT a serialized chain to restore. Drives `BankIndex::updateInPlace` / `BankBook::updateSampleInPlace` (order-preserving, id-stable) on re-capture.
**REAPER-facing shells:** **REAPER-facing shells:**
- `capture``ICaptureBackend` interface; `OfflineRenderBackend` (deterministic default) and `RealtimeRecordBackend`. Input: `CaptureRequest`. Output: finished file + populated `Sample` handed to `bank_model`. - `capture``ICaptureBackend` interface; `OfflineRenderBackend` (deterministic default) and `RealtimeRecordBackend`. Input: `CaptureRequest`. Output: finished file + populated `Sample` handed to `bank_model`.
@@ -79,6 +81,7 @@ There is no hot-reload. Copy the built binary into REAPER's `UserPlugins/` folde
- `persist` — project ext state (`SetProjExtState` / `GetProjExtState`, namespace `"reasampler"`) ↔ `BankBook` JSON (`"banks"` key) + `ViewModeModel` JSON (`"view_state"` key) + `TailSetting` JSON (`"tail_setting"` key) + `OwnedManifest` JSON (`"owned_files"` key) + writing-version stamp (`"version"` key, written via `stampVersion()` on every `saveToActiveProject()`); project-relative path resolution. A `projectconfig` hook (`BeginLoadProjectState(isUndo)`) triggers a deferred session reload on undo/redo so Ctrl-Z/redo visibly restores book/view/tail/manifest in-session. - `persist` — project ext state (`SetProjExtState` / `GetProjExtState`, namespace `"reasampler"`) ↔ `BankBook` JSON (`"banks"` key) + `ViewModeModel` JSON (`"view_state"` key) + `TailSetting` JSON (`"tail_setting"` key) + `OwnedManifest` JSON (`"owned_files"` key) + writing-version stamp (`"version"` key, written via `stampVersion()` on every `saveToActiveProject()`); project-relative path resolution. A `projectconfig` hook (`BeginLoadProjectState(isUndo)`) triggers a deferred session reload on undo/redo so Ctrl-Z/redo visibly restores book/view/tail/manifest in-session.
- `view` — Design View shell: reads the folder tree via `view_tree`, snapshots flag values before parking, drives hide + CPU-park on inactive-mode leaves (`B_SHOWINTCP`/`B_SHOWINMIXER`/`B_MAINSEND`/`I_FXEN` + per-FX offline) and derived visibility on parents; restores from snapshot. Never touches master or `B_MUTE`/`I_SOLO`. - `view` — Design View shell: reads the folder tree via `view_tree`, snapshots flag values before parking, drives hide + CPU-park on inactive-mode leaves (`B_SHOWINTCP`/`B_SHOWINMIXER`/`B_MAINSEND`/`I_FXEN` + per-FX offline) and derived visibility on parents; restores from snapshot. Never touches master or `B_MUTE`/`I_SOLO`.
- `track_guid` — shared `MediaTrack*` → canonical GUID-string formatter; single source of truth for membership keys used by both the view shell and the actions layer. - `track_guid` — shared `MediaTrack*` → canonical GUID-string formatter; single source of truth for membership keys used by both the view shell and the actions layer.
- `provenance_shell` — FX-chain identity queries via `TrackFX_*` / `TakeFX_*` APIs; collects source-item paths and parent-detection inputs to feed the pure `provenance` fingerprint builder. Stamps `Sample.provenance` on capture when every resolving source item maps by exact normalized path (case-folded on Windows) to exactly one bank sample; ambiguous/mixed cases record nothing conservatively.
- `actions` — registers the capture/placement/slot action family, the Design View action family (toggle active mode, activate Arrange/Design, tag/untag selected tracks, show-both), and the multi-bank action family (create/rename/reorder/delete bank, evacuate, activate, move/copy/remove selected samples); routes each to the modules above via the `command_id`/`gaccel`/`hookcommand` contract. Every bank index verb wraps its mutation in a batched REAPER undo point (`Undo_BeginBlock2`/`EndBlock2`, `UNDO_STATE_MISCCFG`) so one bank operation is one Ctrl-Z. - `actions` — registers the capture/placement/slot action family, the Design View action family (toggle active mode, activate Arrange/Design, tag/untag selected tracks, show-both), and the multi-bank action family (create/rename/reorder/delete bank, evacuate, activate, move/copy/remove selected samples); routes each to the modules above via the `command_id`/`gaccel`/`hookcommand` contract. Every bank index verb wraps its mutation in a batched REAPER undo point (`Undo_BeginBlock2`/`EndBlock2`, `UNDO_STATE_MISCCFG`) so one bank operation is one Ctrl-Z.
## REAPER extension contract (src/main.cpp) ## REAPER extension contract (src/main.cpp)
+61
View File
@@ -964,6 +964,67 @@ timeline item).
--- ---
## Milestone 10 — provenance (re-capture from source)
**Goal:** Populate `Sample.provenance` (parent sample id + a capture-recipe
fingerprint) on resample-from-sample, and ship a **"re-capture from source"**
action that regenerates a sample from its recorded source. Reconciled with the
dual-canvas (Phase D2) model. CONTEXT.md §Data model, §capture; product framing +
the settled reconciliation in `docs/product/provenance.md`.
**Verify (in DAW):** A sample resampled from a bank sample carries its parent id +
recipe fingerprint; "re-capture from source" regenerates the file into the bank
(never auto-inserting into the timeline — load-bearing principle); re-capture with
an unchanged source + request is byte-identical to the original (bit-identical
repeats); non-destructive to source items/tracks.
> **Reshaped from the old "provenance + null-test verify" M10.** **Cut (fixed by
> Daniel):** the null-test verification *action* and the true-pre-FX-dry *mechanism*
> the old note required — both dropped, see `docs/product/provenance.md` §What was
> cut. **Kept:** provenance + re-capture. The `Sample.provenance` struct and its JSON
> round-trip **already exist** (M1) — M10 populates and consumes the field, it does
> not add it. Fork picks settled by Daniel (2026-07-23): **P1=a thin fingerprint,
> P2=a bank-only re-capture**; P3/P4 moot under P2=a.
- [x] Populate `Sample.provenance` on resample-from-sample: `parentSampleId` (the
bank sample the capture derived from) + `fxChainSnapshot` as a **thin capture-recipe
fingerprint** (scope + source FX-chain identity/hash at capture time — a drift/repro
fingerprint, NOT a serialized pre-FX-dry chain to restore; P1=a settled).
- [x] "Re-capture from source" action (`RECAPTURE_FROM_SOURCE`, channel-composed):
regenerate a provenanced sample by re-running its recorded capture request against
the source's **current** state; update the bank file + Sample in place
(`BankIndex::updateInPlace` / `BankBook::updateSampleInPlace` — order-preserving,
id-stable; old file becomes a Phase R orphan). **Bank-only — never inserts/re-places
into the timeline** (load-bearing principle). Reports drift if the source changed
since capture.
- [x] Verify: re-capture of an unchanged source is byte-identical to the original
capture (bit-identical repeats); non-destructive (`FxBypassGuard` snapshot/restore
as M7); relative-paths-only preserved.
**Dual-canvas reconciliation (settled — `docs/product/provenance.md`):** With
bank-only re-capture (P2=a), provenance is **pure per-sample bank metadata**,
`bank_model` and `view_mode_model` **stay decoupled**, and M10 touches **no** canvas
code. Dual-canvas compliance is satisfied by staying on the right side of the
capture-never-places line — not by any new coupling. Forks P3 (canvas/lane memory in
provenance) and P4 (re-capture auto-tag interaction) were only live under
re-capture-and-replace (P2=b) and are **closed as moot**; if the user manually
re-places a regenerated sample, the existing D2 mode-aware placement rule governs.
**Notes/decisions:**
- Pure `provenance` module: `rsprov1` length-prefixed encoding; captures scope, exact
range, tail, rate/channels, track GUIDs, order-sensitive FX-chain identity;
parse/compare for drift detection. NOT a serialized chain to restore.
- `provenance_shell`: FX-chain identity queries via `TrackFX_*` / `TakeFX_*`;
source-item path collection; parent-detection inputs. Item scope fingerprints take
FX via `TakeFX_*`; track scope fingerprints track FX. Stamps `Sample.provenance`
when every resolving source item maps by exact normalized path (case-folded on
Windows) to exactly one bank sample — ambiguous/mixed cases conservatively record
nothing.
- **Cut items (correct per spec, not built):** the null-test verification action and
the pre-FX dry path. Both were explicitly removed at M10 reshaping
(`docs/product/provenance.md` §What was cut).
- New CTest target `provenance_tests`.
---
## Phase B open questions — all resolved ## Phase B open questions — all resolved
All five forks settled by Daniel (2026-07-23): persistence key = fold pool into `banks`, All five forks settled by Daniel (2026-07-23): persistence key = fold pool into `banks`,
+2 -1
View File
@@ -154,7 +154,8 @@ Persistence & paths:
- **Null test:** a dry offline capture of a range, re-inserted at its source - **Null test:** a dry offline capture of a range, re-inserted at its source
position, nulls to silence against the source. Ship this as a verification position, nulls to silence against the source. Ship this as a verification
action; it is the tool's trust anchor. action; it is the tool's trust anchor. (Verification action cut per
`docs/product/provenance.md` — manual verification only.)
- **Bit-identical repeats:** identical offline requests produce identical files. - **Bit-identical repeats:** identical offline requests produce identical files.
- **Non-destructive:** capture never mutates source items or tracks (realtime's - **Non-destructive:** capture never mutates source items or tracks (realtime's
temp track is created and removed cleanly; source routing is restored). temp track is created and removed cleanly; source routing is restored).
-42
View File
@@ -23,48 +23,6 @@ state persists via the index.
- [ ] Slot model + slot↔sample assignment. - [ ] Slot model + slot↔sample assignment.
- [ ] "Capture to slot N" / "insert slot N" actions, MIDI-bindable. - [ ] "Capture to slot N" / "insert slot N" actions, MIDI-bindable.
## Milestone 10 — provenance (re-capture from source)
**Goal:** Populate `Sample.provenance` (parent sample id + a capture-recipe
fingerprint) on resample-from-sample, and ship a **"re-capture from source"**
action that regenerates a sample from its recorded source. Reconciled with the
dual-canvas (Phase D2) model. CONTEXT.md §Data model, §capture; product framing +
the settled reconciliation in `docs/product/provenance.md`.
**Verify (in DAW):** A sample resampled from a bank sample carries its parent id +
recipe fingerprint; "re-capture from source" regenerates the file into the bank
(never auto-inserting into the timeline — load-bearing principle); re-capture with
an unchanged source + request is byte-identical to the original (bit-identical
repeats); non-destructive to source items/tracks.
> **Reshaped from the old "provenance + null-test verify" M10.** **Cut (fixed by
> Daniel):** the null-test verification *action* and the true-pre-FX-dry *mechanism*
> the old note required — both dropped, see `docs/product/provenance.md` §What was
> cut. **Kept:** provenance + re-capture. The `Sample.provenance` struct and its JSON
> round-trip **already exist** (M1) — M10 populates and consumes the field, it does
> not add it. Fork picks settled by Daniel (2026-07-23): **P1=a thin fingerprint,
> P2=a bank-only re-capture**; P3/P4 moot under P2=a. The points below are locked to
> that path.
- [ ] Populate `Sample.provenance` on resample-from-sample: `parentSampleId` (the
bank sample the capture derived from) + `fxChainSnapshot` as a **thin capture-recipe
fingerprint** (scope + source FX-chain identity/hash at capture time — a drift/repro
fingerprint, NOT a serialized pre-FX-dry chain to restore; P1=a settled).
- [ ] "Re-capture from source" action: regenerate a provenanced sample by re-running
its recorded capture request against the source's **current** state; update the
bank file + Sample in place. **Bank-only — never inserts/re-places into the
timeline** (load-bearing principle). Reports if the source drifted since capture.
- [ ] Verify: re-capture of an unchanged source is byte-identical to the original
capture (bit-identical repeats); non-destructive (`FxBypassGuard` snapshot/restore
as M7); relative-paths-only preserved.
**Dual-canvas reconciliation (settled — `docs/product/provenance.md`):** With
bank-only re-capture (P2=a), provenance is **pure per-sample bank metadata**,
`bank_model` and `view_mode_model` **stay decoupled**, and M10 touches **no** canvas
code. Dual-canvas compliance is satisfied by staying on the right side of the
capture-never-places line — not by any new coupling. Forks P3 (canvas/lane memory in
provenance) and P4 (re-capture auto-tag interaction) were only live under
re-capture-and-replace (P2=b) and are **closed as moot**; if the user manually
re-places a regenerated sample, the existing D2 mode-aware placement rule governs.
## Milestone 11 — polish ## Milestone 11 — polish
**Goal:** Batch capture (per selected item / per razor area), **Goal:** Batch capture (per selected item / per razor area),
resample-and-mute-source, conform-on-insert, native OS drag-out. CONTEXT.md resample-and-mute-source, conform-on-insert, native OS drag-out. CONTEXT.md
+6 -6
View File
@@ -6,12 +6,12 @@ authoritative technical detail is `CONTEXT.md` (§Data model, §capture) plus th
note for the reconciliation calls. This doc holds the *why* and the open forks so note for the reconciliation calls. This doc holds the *why* and the open forks so
they don't clutter the build docs. they don't clutter the build docs.
Status: **SETTLED (2026-07-23).** Reshaped from the old "provenance + null-test Status: **IMPLEMENTED (2026-07-26).** Settled 2026-07-23; landed 2026-07-26.
verify" M10. Two decisions were fixed by Daniel up front (see *What was cut* below). Reshaped from the old "provenance + null-test verify" M10. Two decisions were fixed
The four dual-canvas interaction forks are now resolved: **P1=a thin fingerprint, by Daniel up front (see *What was cut* below). The four dual-canvas interaction forks
P2=a bank-only re-capture**, which makes **P3 and P4 moot (closed)**. The fork are now resolved: **P1=a thin fingerprint, P2=a bank-only re-capture**, which makes
analysis below is retained as the rationale record — each fork is stamped with its **P3 and P4 moot (closed)**. The fork analysis below is retained as the rationale
resolution inline; nothing here is open. record — each fork is stamped with its resolution inline; nothing here is open.
--- ---