Lock M10 provenance spec to Daniel's fork picks (P1=a, P2=a)

Settle the reshaped Milestone 10: thin capture-recipe fingerprint and
bank-only re-capture; P3/P4 closed as moot. Remove the pending-picks
banner in PLAN.md and stamp the provenance product note as settled.
This commit is contained in:
2026-07-23 20:10:54 -04:00
parent 1743df135b
commit 92827c59be
2 changed files with 66 additions and 57 deletions
+20 -20
View File
@@ -28,26 +28,26 @@ state persists via the index.
fingerprint) on resample-from-sample, and ship a **"re-capture from source"** fingerprint) on resample-from-sample, and ship a **"re-capture from source"**
action that regenerates a sample from its recorded source. Reconciled with the action that regenerates a sample from its recorded source. Reconciled with the
dual-canvas (Phase D2) model. CONTEXT.md §Data model, §capture; product framing + dual-canvas (Phase D2) model. CONTEXT.md §Data model, §capture; product framing +
the reconciliation forks in `docs/product/provenance.md`. the settled reconciliation in `docs/product/provenance.md`.
**Verify (in DAW):** A sample resampled from a bank sample carries its parent id + **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 recipe fingerprint; "re-capture from source" regenerates the file into the bank
(never auto-inserting into the timeline — load-bearing principle); re-capture with (never auto-inserting into the timeline — load-bearing principle); re-capture with
an unchanged source + request is byte-identical to the original (bit-identical an unchanged source + request is byte-identical to the original (bit-identical
repeats); non-destructive to source items/tracks. repeats); non-destructive to source items/tracks.
> **PROPOSAL — pending Daniel's fork picks (2026-07-23).** Reshaped from the old > **Reshaped from the old "provenance + null-test verify" M10.** **Cut (fixed by
> "provenance + null-test verify" M10. **Cut (fixed by Daniel):** the null-test > Daniel):** the null-test verification *action* and the true-pre-FX-dry *mechanism*
> verification *action* and the true-pre-FX-dry *mechanism* the old note required — > the old note required — both dropped, see `docs/product/provenance.md` §What was
> both dropped, see `docs/product/provenance.md` §What was cut. **Kept:** provenance > cut. **Kept:** provenance + re-capture. The `Sample.provenance` struct and its JSON
> + re-capture. The `Sample.provenance` struct and its JSON round-trip **already > round-trip **already exist** (M1) — M10 populates and consumes the field, it does
> exist** (M1) — M10 populates and consumes the field, it does not add it. The points > not add it. Fork picks settled by Daniel (2026-07-23): **P1=a thin fingerprint,
> below reflect the **leaned path** (bank-only re-capture, thin fingerprint); the > P2=a bank-only re-capture**; P3/P4 moot under P2=a. The points below are locked to
> re-place variant is deferred behind forks P2P4. Lock the points once Daniel picks. > that path.
- [ ] Populate `Sample.provenance` on resample-from-sample: `parentSampleId` (the - [ ] Populate `Sample.provenance` on resample-from-sample: `parentSampleId` (the
bank sample the capture derived from) + `fxChainSnapshot` as a **capture-recipe bank sample the capture derived from) + `fxChainSnapshot` as a **thin capture-recipe
fingerprint** (scope + source FX-chain identity at capture time — a drift/repro fingerprint** (scope + source FX-chain identity/hash at capture time — a drift/repro
fingerprint, NOT a pre-FX-dry chain; see product note fork P1). 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 - [ ] "Re-capture from source" action: regenerate a provenanced sample by re-running
its recorded capture request against the source's **current** state; update the 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 bank file + Sample in place. **Bank-only — never inserts/re-places into the
@@ -56,14 +56,14 @@ repeats); non-destructive to source items/tracks.
capture (bit-identical repeats); non-destructive (`FxBypassGuard` snapshot/restore capture (bit-identical repeats); non-destructive (`FxBypassGuard` snapshot/restore
as M7); relative-paths-only preserved. as M7); relative-paths-only preserved.
**Dual-canvas reconciliation (forks for Daniel — `docs/product/provenance.md`):** **Dual-canvas reconciliation (settled — `docs/product/provenance.md`):** With
Under the leaned path (bank-only re-capture) provenance is **pure per-sample bank bank-only re-capture (P2=a), provenance is **pure per-sample bank metadata**,
metadata**, `bank_model` and `view_mode_model` **stay decoupled**, and M10 touches `bank_model` and `view_mode_model` **stay decoupled**, and M10 touches **no** canvas
no canvas code — compliance is satisfied by staying on the right side of the code. Dual-canvas compliance is satisfied by staying on the right side of the
capture-never-places line. Forks P3 (canvas/lane memory in provenance) and P4 capture-never-places line — not by any new coupling. Forks P3 (canvas/lane memory in
(re-capture auto-tag interaction) only wake up if Daniel wants **P2 = provenance) and P4 (re-capture auto-tag interaction) were only live under
re-capture-and-replace-on-timeline**, which would make re-place a mode-aware re-capture-and-replace (P2=b) and are **closed as moot**; if the user manually
placement. Awaiting picks on P1 (fingerprint shape) and P2 (re-capture scope). 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),
+46 -37
View File
@@ -6,11 +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: **PROPOSAL, pending Daniel's sign-off (2026-07-23).** Reshaped from the Status: **SETTLED (2026-07-23).** Reshaped from the old "provenance + null-test
old "provenance + null-test verify" M10. Two decisions are fixed by Daniel and are verify" M10. Two decisions were fixed by Daniel up front (see *What was cut* below).
**not** reopened here (see *What was cut* below). The remaining content is the The four dual-canvas interaction forks are now resolved: **P1=a thin fingerprint,
provenance-only shape plus the dual-canvas interaction forks Daniel needs to P2=a bank-only re-capture**, which makes **P3 and P4 moot (closed)**. The fork
settle. analysis below is retained as the rationale record — each fork is stamped with its
resolution inline; nothing here is open.
--- ---
@@ -72,7 +73,8 @@ bit — enough of the **source FX-chain identity at capture time** that "re-capt
from source" can tell whether the source still matches what was captured. This is a from source" can tell whether the source still matches what was captured. This is a
*fingerprint for reproducibility*, not a mechanism for a different render mode. *fingerprint for reproducibility*, not a mechanism for a different render mode.
> **Fork P1 — how much chain state does `fxChainSnapshot` carry?** Two shapes: > **Fork P1 — how much chain state does `fxChainSnapshot` carry? — CHOSEN: (a)
> thin fingerprint (Daniel, 2026-07-23).** Two shapes:
> **(a) thin fingerprint** — a hash/summary of the source scope + FX-chain identity > **(a) thin fingerprint** — a hash/summary of the source scope + FX-chain identity
> at capture time, used only to detect drift ("source has changed since capture") > at capture time, used only to detect drift ("source has changed since capture")
> and to re-run the *same* capture request; or **(b) fat snapshot** — a full > and to re-run the *same* capture request; or **(b) fat snapshot** — a full
@@ -85,7 +87,8 @@ from source" can tell whether the source still matches what was captured. This i
> most naturally means "run the capture again against the source's *current* state" > most naturally means "run the capture again against the source's *current* state"
> — that's the useful workflow (I changed the source, give me the updated sample). > — that's the useful workflow (I changed the source, give me the updated sample).
> The fingerprint's job is to *tell* the user the source drifted, not to freeze it. > The fingerprint's job is to *tell* the user the source drifted, not to freeze it.
> Confirm this is the intent before scoping. > **Resolved 2026-07-23: (a). `fxChainSnapshot` is a capture-recipe fingerprint for
> drift detection and re-run — not a serialized chain to restore.**
--- ---
@@ -119,7 +122,7 @@ onto the timeline (replacing the old placed item). That is a *placement*, and
placement is mode-aware under D2. placement is mode-aware under D2.
> **Fork P2 — does "re-capture from source" re-place, or only refresh the bank > **Fork P2 — does "re-capture from source" re-place, or only refresh the bank
> entry?** Two shapes: > entry? — CHOSEN: (a) bank-only re-capture (Daniel, 2026-07-23).** Two shapes:
> **(a) bank-only re-capture** — regenerate the file + update the bank Sample > **(a) bank-only re-capture** — regenerate the file + update the bank Sample
> in place; the user re-places manually if they want the new version on the > in place; the user re-places manually if they want the new version on the
> timeline. Fully honors the load-bearing principle with zero canvas coupling; > timeline. Fully honors the load-bearing principle with zero canvas coupling;
@@ -132,6 +135,9 @@ placement is mode-aware under D2.
> pillar's clean "capture never places" line and defers all the canvas-placement > pillar's clean "capture never places" line and defers all the canvas-placement
> complexity. (b) can be a later opt-in ("re-capture and replace in place") once (a) > complexity. (b) can be a later opt-in ("re-capture and replace in place") once (a)
> proves the provenance thread. If Daniel wants (b), P3 and P4 below become live. > proves the provenance thread. If Daniel wants (b), P3 and P4 below become live.
> **Resolved 2026-07-23: (a). Re-capture regenerates the file into the bank and
> updates the Sample in place; it never places/replaces on the timeline. P3 and P4
> are therefore moot — closed (b) can still be revisited as a later opt-in.**
### Does provenance need to record canvas/mode membership? ### Does provenance need to record canvas/mode membership?
@@ -146,7 +152,8 @@ it needs no canvas memory; the bank stays mode-agnostic and the two pure modules
stay decoupled. Under P2 = (b) re-place, the answer becomes **yes, partially**. stay decoupled. Under P2 = (b) re-place, the answer becomes **yes, partially**.
> **Fork P3 — (only live if P2 = re-place) does provenance store canvas/lane > **Fork P3 — (only live if P2 = re-place) does provenance store canvas/lane
> membership?** If re-capture re-places, where does it land? > membership? — CLOSED/moot under P2=a (2026-07-23).** If re-capture re-places, where
> does it land?
> **(a) active-mode rule** — re-placement follows the *same* D2 auto-tag/placement > **(a) active-mode rule** — re-placement follows the *same* D2 auto-tag/placement
> rule as any explicit placement: it lands in whatever mode is active *now*. > rule as any explicit placement: it lands in whatever mode is active *now*.
> Provenance stores **nothing** about canvas; the view model's existing rule > Provenance stores **nothing** about canvas; the view model's existing rule
@@ -159,6 +166,9 @@ stay decoupled. Under P2 = (b) re-place, the answer becomes **yes, partially**.
> avoids. **Lean: (a) active-mode rule**, kept in the view model; provenance stays > avoids. **Lean: (a) active-mode rule**, kept in the view model; provenance stays
> pure bank metadata with no view-model ids. Only reach for (b) if "re-capture > pure bank metadata with no view-model ids. Only reach for (b) if "re-capture
> restores the exact original lane" is a stated requirement. > restores the exact original lane" is a stated requirement.
> **Closed 2026-07-23: moot under P2=a. Re-capture never places, so it stores no
> canvas memory; provenance stays pure bank metadata and the two modules stay
> decoupled. Revisit only if re-capture-and-replace (P2=b) is later adopted.**
### Re-capture and auto-tagging ### Re-capture and auto-tagging
@@ -171,29 +181,31 @@ must tag the new item explicitly and **suppress** the auto-tag for that GUID (or
two fight). two fight).
> **Fork P4 — (only live if P2 = re-place AND P3 = origin-lane) does re-capture > **Fork P4 — (only live if P2 = re-place AND P3 = origin-lane) does re-capture
> preserve or re-run auto-tagging?** If provenance restores the origin lane, the > preserve or re-run auto-tagging? — CLOSED/moot under P2=a (2026-07-23).** If
> provenance restores the origin lane, the
> re-placed item must be tagged to the *origin* mode, not the active mode — so > re-placed item must be tagged to the *origin* mode, not the active mode — so
> re-capture has to write the membership itself and exempt that GUID from the > re-capture has to write the membership itself and exempt that GUID from the
> timer's auto-tag (same class as the manual-lane exemption already in > timer's auto-tag (same class as the manual-lane exemption already in
> `autoTagNewContent`). **This fork only exists under P2=(b) + P3=(b).** Under the > `autoTagNewContent`). **This fork only exists under P2=(b) + P3=(b).** Under the
> leaned defaults (P2=a, or P2=b + P3=a) it does not arise: bank-only re-capture > leaned defaults (P2=a, or P2=b + P3=a) it does not arise: bank-only re-capture
> places nothing, and active-mode re-placement rides the existing auto-tag path > places nothing, and active-mode re-placement rides the existing auto-tag path
> unchanged. > unchanged. **Closed 2026-07-23: moot under P2=a — bank-only re-capture places
> nothing, so no auto-tag interaction arises.**
### Summary of the leaned path ### Summary of the settled path
If Daniel takes the leans (**P1=a thin fingerprint, P2=a bank-only re-capture**), Daniel took the leans (**P1=a thin fingerprint, P2=a bank-only re-capture**,
the reconciliation collapses to almost nothing: provenance is **pure per-sample 2026-07-23), so the reconciliation collapses to almost nothing: provenance is
bank metadata**, `bank_model` and `view_mode_model` **stay decoupled**, and M10 **pure per-sample bank metadata**, `bank_model` and `view_mode_model` **stay
touches **no** canvas code. The dual-canvas compliance is satisfied by *staying on decoupled**, and M10 touches **no** canvas code. The dual-canvas compliance is
the right side of the load-bearing line* (capture/re-capture never places), not by satisfied by *staying on the right side of the load-bearing line* (capture/re-capture
new coupling. P3 and P4 only wake up if Daniel wants re-capture to also re-place never places), not by new coupling. P3 and P4 are moot (closed) — they were only
onto the timeline. live if re-capture also re-placed onto the timeline.
This is the recommendation: **keep provenance in the bank, keep re-capture a The settled shape: **keep provenance in the bank, keep re-capture a bank-only
bank-only regenerate, and let the existing D2 placement rule handle the timeline if regenerate, and let the existing D2 placement rule handle the timeline if and when
and when the user manually re-places.** It is the smallest thing that delivers the the user manually re-places.** It is the smallest thing that delivers the useful
useful workflow and the cleanest against the architecture. workflow and the cleanest against the architecture.
--- ---
@@ -225,19 +237,16 @@ useful workflow and the cleanest against the architecture.
--- ---
## Open forks for Daniel (the decision list) ## Decision list (settled 2026-07-23)
1. **P1 — `fxChainSnapshot` shape:** thin reproducibility fingerprint *(lean)* vs. 1. **P1 — `fxChainSnapshot` shape: CHOSEN (a) thin reproducibility fingerprint.**
fat serialized FX-chain chunk. (Rejected: (b) fat serialized FX-chain chunk.)
2. **P2 — re-capture scope:** bank-only regenerate *(lean)* vs. 2. **P2 — re-capture scope: CHOSEN (a) bank-only regenerate.** (Rejected for now:
re-capture-and-replace-on-timeline. (b) re-capture-and-replace-on-timeline; may return as a later opt-in.)
3. **P3 — (only if P2=replace) canvas memory:** re-place follows the active-mode 3. **P3 — canvas memory: CLOSED/moot under P2=a.** Was only live under P2=b; lean
rule, provenance stores no view ids *(lean)* vs. provenance records origin was (a) active-mode rule, provenance stores no view ids.
mode/lane and restores it. 4. **P4 — auto-tag interaction: CLOSED/moot under P2=a.** Was only live under P2=b +
4. **P4 — (only if P2=replace AND P3=origin-lane) auto-tag interaction:** re-capture P3=b.
writes origin-mode membership and exempts the GUID from the timer auto-tag. Only
live under the two non-leaned choices above.
The leaned path (1a, 2a) makes 3 and 4 moot and keeps M10 a small, decoupled, Picks 1a + 2a make P3 and P4 moot and keep M10 a small, decoupled, capture-pillar
capture-pillar milestone. Awaiting Daniel's picks before the PLAN M10 points are milestone. The PLAN M10 points are locked to this path.
locked.