diff --git a/CONTEXT.md b/CONTEXT.md index d978f1c..85aa51c 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -184,9 +184,27 @@ are **Arrange** mode (the default). Toggling to a mode **hides and disables** th tracks that don't belong to it. Workflow value: mental separation + clutter elimination — be in Design view, resample into the bank, flip to Arrange, place it. -**This is not a separate canvas.** REAPER has exactly one arrange timeline. Design -View is the *same timeline* with a curated, filtered track set and the inactive -tracks parked — not a second surface, window, or duplicated project. +Design View is a **mode projection over REAPER's single arrange timeline** — +reaching both **tracks** (parked per mode) and **items** (lane-split per mode on +shared tracks). It approximates two canvases without a second surface: same project, +same timeline, but each stance sees its own tracks and its own items. It **never** +duplicates the project or opens a second window. + +> **Two-canvas reach — settled (2026-07-23).** The original single-canvas framing +> here was derived from a REAPER constraint, not chosen as a product stance. Daniel +> reopened it — "as close as possible to two separate design and arrange canvases, +> same project, different items and leaves" — and has now signed off on the +> mechanism and resolved all forks. The "different leaves" half is delivered by +> track-parking (D1). The "different items" half is delivered by **per-item mode +> membership via REAPER fixed lanes** (track-side `I_FREEMODE=2`, `I_NUMFIXEDLANES`, +> `C_LANEPLAYS:N`; item-side `I_FIXEDLANE`, `C_LANEPLAYS`, `B_FIXEDLANE_HIDDEN`): +> each mode owns a lane on a shared track, and toggling shows/plays only the active +> mode's lane. This is an item-visibility projection over the one timeline — the +> exact analog of today's track-visibility projection — with still **no** literal +> second surface, window, or duplicate project. It is an **additive sub-phase (Phase +> D2 / Phase E)** on top of D1, spec'd in *§Two-canvas sub-phase* below. Full framing +> and the rejected alternatives (timebase-offset, subproject) live in +> `docs/product/design-view.md` §Two-canvas direction. It is the visibility/processing analog of the capture pillar's load-bearing rule: **designing and arranging are separate stances on one timeline**, and the tool @@ -297,10 +315,21 @@ togglable per selection. ## Non-goals / guardrails -- **No second canvas.** Do not build a parallel arrange surface — reject any such - path in review. +- **No *literal* second canvas.** A literal second arrange surface, a second window, + or a duplicated project stays **rejected** — reject any such path in review. This + guardrail was **narrowed (2026-07-23), not lifted**: per-item mode separation via + REAPER fixed lanes on shared tracks (an item-visibility projection over the one + timeline) is now **allowed** and specified in *§Two-canvas sub-phase* below. Paths + that remain **rejected**: subproject / second-project-file approaches, and + overloading item `D_POSITION` with mode semantics (timebase-offset regions) — the + latter collides with the capture null test. See `docs/product/design-view.md` + §Two-canvas direction for why those were rejected. - **Never touch mute/solo.** Any code path reading/writing `B_MUTE` / `I_SOLO` is a bug. +- **Never drive a manual lane** (Phase D2). A mode toggle touches only **managed** + lanes (minted by the mode system, keyed in the lane-ownership index). Any code path + that shows, hides, silences, or re-lanes a **manual** lane — a user-created comp/take + lane outside the mode system — is a bug. The tool drives only lanes it created. - **Every leaf is managed.** The mode system owns all leaf tracks: an untagged leaf is an Arrange member, and when the active mode is not Arrange it is fully parked and snapshot-restored exactly like a tagged leaf out of its mode. **show-both** is @@ -325,6 +354,136 @@ togglable per selection. - Interaction with the user having a screenset active (Design View drives the same flags a screenset recall would; last writer wins — confirm no surprising fight). +## Two-canvas sub-phase (Phase D2 / Phase E) — additive to D1 + +> **Additive sub-phase, settled 2026-07-23.** Extends D1's track-level mode +> projection to **item level** so each stance owns its own items as well as its own +> tracks. Nothing in D1 changes; this wraps it. Runtime floor rises to **REAPER 7** +> for this sub-phase (fixed lanes shipped in v7). Product framing in +> `docs/product/design-view.md` §Two-canvas direction. + +### What it adds + +On a track present in **both** stances (a show-both track, or a folder carrying its +own media), each mode owns a **fixed lane**: the active mode's lane shows and plays; +the inactive mode's lane is hidden and silent. A Design take and an Arrange take can +then live on the *same track, same time position*, without colliding on the view. +Track-only-in-one-mode content is still handled by D1 track-parking, unchanged. + +### Settled decisions + +- **Mechanism: fixed item lanes.** Map mode → lane; toggle drives per-lane play/show + so only the active mode's lane is present. Items keep their real position and real + track — nothing is moved in time or deleted. SDK surface (**verified present in + `vendor/reaper-sdk`**): track-side `I_FREEMODE = 2`, `I_NUMFIXEDLANES`, + `C_LANEPLAYS:N`; item-side `I_FIXEDLANE`, `C_LANEPLAYS`, `B_FIXEDLANE_HIDDEN`. + **`I_FREEMODE` changes require `UpdateTimeline()`** to take visible effect. +- **Membership: auto-tag by active mode at creation.** New content — **both new + tracks and new items** — is tagged to whatever mode is active when it is created. + Pre-existing content defaults to **Arrange**. Membership is **exclusive**: + Design-created content never appears in Arrange and vice versa, except via the + existing **show-both** escape hatch. (This is the same tag-to-active-mode rule as + D1 track membership, now reaching items on shared tracks.) +- **Inactive-mode content is hidden AND silenced.** The off-mode lane is set + `C_LANEPLAYS = 0` — neither shown nor played — consistent with exclusive + membership and with D1's "flipping modes is a real change, not cosmetic." Show-both + is the deliberate opt-out for a lane that must stay audible across modes. +- **Managed vs. manual lanes — indexed and distinct.** Fixed lanes are also REAPER's + native comping surface: a user may keep **their own** manual lanes (comp takes, + alternate reads) on a track alongside the mode system's lanes. The tool maintains a + **lane-ownership index** — per (track GUID, lane): **managed** (which mode owns it) + vs **manual** (user-minted, outside the mode system). Mode operations touch **only + managed lanes**; manual lanes are never shown, hidden, silenced, or re-laned by a + toggle, and their `C_LANEPLAYS` stays exactly as the user set it. Items a user adds + to a **manual** lane are **not** auto-tagged (auto-tag governs normal timeline + content, not hand-managed lanes). The ownership index rides in `"reasampler"` + `view_state` alongside the membership index, GUID-keyed and portable. +- **Capture placement is mode-aware.** An **explicit** placement while in Design mode + — including capture-and-place — lands the item in the **Design lane**; the same + rule governs manual insertion. **The capture load-bearing principle is untouched:** + capture still writes a file + index entry and **never** auto-inserts; this governs + only *where an explicit placement lands*. +- **REAPER floor: v7.** No version-gate branch — below v7 this sub-phase is simply + unavailable. + +### Precision invariants (unaffected — called out explicitly) + +The capture precision invariants — **null test, bit-identical repeats, +non-destructive, exact bounds, relative-paths-only** — are **entirely unaffected** by +this sub-phase. No capture path changes; lanes are a placement/view concern +downstream of the written file. Lane assignment and `C_LANEPLAYS` are **reversible +flags**: the item is never relocated in time or deleted, so the sub-phase extends the +D1 non-destructive snapshot/restore contract to a new (item-lane) flag family rather +than introducing any destructive operation. + +**New invariant — mode operations touch only managed lanes.** A mode toggle drives +only lanes the mode system minted (managed lanes, keyed in the lane-ownership index). +Manual lanes — user-created comp/take lanes outside the mode system — are **never** +shown, hidden, silenced, or re-laned by a toggle; their `C_LANEPLAYS` is left exactly +as the user set it. This is the fixed-lane analog of *never touch `B_MUTE`/`I_SOLO`* +and *never touch master*: **the tool drives only what it created.** Enforceable and +testable in the pure layer — the "which lanes may this toggle touch" decision is a +pure query over the ownership index; only reading REAPER's live lane state is shell. + +### Module architecture (preserve the pure/shell split) + +- **Pure (`view_mode_model` extension).** Lane math — which lane maps to which mode, + which `C_LANEPLAYS` value per mode, the item-lane op family alongside the existing + track-flag op family — is **REAPER-free and unit-tested**, mirroring the D1 + planner. The **lane-ownership index** (per (track GUID, lane): managed-which-mode vs + manual) and the **"which lanes may this toggle touch" query** (managed only) are + pure and unit-tested — the planner emits lane ops for managed lanes only and never + for manual lanes. The **auto-tag decision** is pure too: given *a set of new + track/item GUIDs + the active mode* — and, for items, whether the item landed in a + manual lane (exempt) — produce the membership writes. +- **Shell.** Two shell responsibilities. (1) **Apply** the planner's item-lane ops + (`I_FREEMODE`/`I_FIXEDLANE`/`C_LANEPLAYS`/`B_FIXEDLANE_HIDDEN` via the media-item + info setters, `UpdateTimeline()` after `I_FREEMODE` changes) — for managed lanes + only. (2) **Detect** new content and read live lane state — see below. +- **Persistence.** The tool persists which lane maps to which mode **and the + managed/manual ownership index** (a small addition to the `"reasampler"` view + section); REAPER stores fixed lanes and lane-plays in the `.rpp` natively. + +### New-content detection (implementation design point) + +REAPER exposes **no clean "item added" / "track added" event callback.** Auto-tagging +therefore requires the shell to **diff project state on the panel's existing timer** — +the `bank_panel` already polls and fingerprints the bank; this extends that machinery +to the timeline's tracks and items. + +- Each poll, compare the live track/item GUID set against the previous poll's set; + **any GUID new since the last poll is tagged to the then-active mode.** +- Correctness the implementation must handle: the **first poll after project open must + not mass-tag** pre-existing content (pre-existing defaults to Arrange, per the + membership rule). +- **Manual-lane exemption (design point).** An item added to a **manual** lane is + **not** auto-tagged — auto-tag governs normal timeline content, not lanes the user + hand-manages. Distinguishing the two may need a heuristic at detection (e.g., an item + whose `I_FIXEDLANE` is marked manual in the ownership index is exempt; content + outside any managed lane on a mode-managed track follows the active-mode rule). The + precise rule is an **open implementation design point**; the settled boundary is that + manual-lane content is off-limits to auto-tag. +- **Lane-identity fragility (design point).** `I_FIXEDLANE` is the lane's identity and + is how the ownership index keys to a lane. Whether the index survives lane + reorder/renumber/deletion without going stale is an **implementation design point** + (same class as GUID-keyed reorder-safety for tracks) — flag, don't solve here. +- Pure/shell seam: the **detection** (diffing REAPER's live set each tick, reading live + lane ownership) is shell; the **tagging decision** and the **managed/manual lane + query** (new GUIDs + active mode + manual-lane exemption ⇒ membership + lane writes) + are pure and unit-tested. + +### REAPER API surface (verify all signatures) + +- Fixed lanes — track: `I_FREEMODE` (=2), `I_NUMFIXEDLANES`, `C_LANEPLAYS:N` via + `GetMediaTrackInfo_Value`/`SetMediaTrackInfo_Value`; item: `I_FIXEDLANE`, + `C_LANEPLAYS`, `B_FIXEDLANE_HIDDEN` via `GetMediaItemInfo_Value` / + `SetMediaItemInfo_Value`. Call `UpdateTimeline()` after `I_FREEMODE` changes. +- Detection reuses the `bank_panel` timer + GUID fingerprinting already in place; + item GUIDs via the item's `GUID` (`GetSetMediaItemInfo_String` `"GUID"`), track + GUIDs via `GetTrackGUID` as in D1. +- **Verify every name/signature against the SDK header before use** — the surface is + verified *present*, but confirm argument order, types, and flag values. + --- # Multi-bank — additive phase spec diff --git a/docs/product/design-view.md b/docs/product/design-view.md index 480c473..aae7bb5 100644 --- a/docs/product/design-view.md +++ b/docs/product/design-view.md @@ -6,8 +6,10 @@ detail in `CONTEXT.md` (§Design View). This doc holds the *why* — the workflo narrative, the N-mode reasoning, the screenset differentiation, and the design-direction recommendations — so those don't clutter the build docs. -Status: settled with Daniel (2026-07-22). Open items for Daniel are listed at the -bottom. +Status: settled with Daniel (2026-07-22). The **two-canvas direction** (item-level +mode separation via fixed lanes) is also settled with Daniel (2026-07-23) — see the +§Two-canvas direction section, which **supersedes** the "not a second canvas" +framing below. Open items for Daniel are listed above that section. --- @@ -25,12 +27,19 @@ place it. The design scaffolding never touches the arrangement while you're arranging, and the arrangement never buries the design bench while you're designing. -**It is not a second canvas.** REAPER has exactly one arrange timeline. Design -View does not create a parallel surface, a separate window, or a duplicate -project. It is the *same timeline* with a curated, filtered track set and the -inactive tracks parked. Anyone expecting a second arrange view will be -disappointed — and that expectation must be headed off in the spec, not -discovered in review. +**It is not a *literal* second canvas.** REAPER has exactly one arrange timeline. +Design View does not create a parallel surface, a separate window, or a duplicate +project — that stays true and is enforced in review. It is the *same timeline* with +a curated, filtered track set and the inactive content parked. + +> **Superseded in one respect (2026-07-23).** The original claim here was that +> Design View separates only *tracks*, not *items*. That is now extended: the +> settled §Two-canvas direction adds **item-level** mode separation on shared tracks +> via REAPER fixed lanes — so each stance can own its own items as well as its own +> tracks. It is still not a literal second surface/window/project; it is a mode +> *projection* over the one timeline that now reaches items. Read §Two-canvas +> direction for the settled shape; the sentence "It does not separate items" no +> longer holds. This is the visibility/processing analog of the capture pillar's load-bearing rule. The capture pillar says *capture and placement are separate acts*. Design @@ -345,3 +354,326 @@ tooltip on the switch. deleted or a folder is restructured while parked, the index holds a stale GUID. The pure model should tolerate unknown GUIDs (ignore-and-prune on next reconcile) — noted as a hardening item for the build, not a phase-defining decision. + +--- + +# Two-canvas direction — settled (2026-07-23) + +> **Status: settled with Daniel (2026-07-23).** This section reopens and supersedes +> the "not a second canvas" decision above. Daniel's stated intent (verbatim): *"I +> wasn't the one who specified single-canvas, that emerged from REAPER's design. I +> want to come as close as possible to supporting two separate design and arrange +> canvases, which are actually the same project but have different items and +> leaves."* The single-canvas framing above was a **derivation from a REAPER +> constraint**, not a product choice — so it was reopened, and Daniel has now signed +> off on the mechanism (fixed item lanes) and resolved all five forks. Everything +> under this heading **supersedes** the "not a second canvas" language in *What it is +> (and what it is not)*: Design View is now a mode projection that reaches **both +> tracks and items**. This is an **additive sub-phase** (Phase D2 / Phase E) on top +> of the shipped track-parking work — not a rewrite of it. + +## What actually changed in the ask + +The shipped model separates modes by **track membership** on one shared timeline: +tag a leaf into Design, and when you flip to Arrange that leaf is parked — hidden, +out of the mix, FX offline. Because items ride their tracks, a Design track's items +already vanish from the Arrange view. **The "different leaves" half of Daniel's ask +is already delivered.** Flipping modes already gives you a different *track set*. + +The genuinely new half is **"different items."** Daniel wants two canvases that +differ not only in which tracks are present but in which *items* are present — +including items that live on a track shared by both stances. Concretely: a track +that exists in both Arrange and Design (a show-both reference track, or a folder +carrying its own media) should be able to hold a design take that only appears in +Design and an arrangement take that only appears in Arrange, on the *same track*, +without the two colliding on the timeline. Track-parking can't express that, +because parking is all-or-nothing per track — it can hide a whole track, never a +subset of its items. + +So the reframe is precise: **the feature grows from track-level mode separation to +track-level *plus* item-level mode separation.** "Two canvases" = each stance owns +its own item set, layered over the shared project, with tracks it doesn't want +parked as today. + +## The hard constraint (and why it's not fatal) + +REAPER has exactly one arrange timeline and one project item graph. There is no +API to instantiate a second arrange surface, and the "no second window/no +duplicate project" observation in the shipped framing is *structurally true* — you +cannot conjure a literal second canvas. What is reversed is only the **conclusion +drawn from it**: that item separation is therefore off the table. It isn't. Items +carry per-item state (`I_FIXEDLANE`, `C_LANEPLAYS`, `D_POSITION`, track +assignment) that the tool can drive to make an item present-or-absent *per mode* +without destroying it. "Two canvases" becomes an **item-visibility projection over +one timeline**, exactly as "two track sets" is a track-visibility projection over +one timeline today. Same discipline, one level deeper. + +## Mechanism (settled) and the alternatives it beat + +**The settled mechanism is Option A — fixed lanes as per-mode item layers.** The two +alternatives (B timebase-offset, C subproject) are kept below because *why they were +rejected* is load-bearing: both collide with settled invariants, and recording that +keeps them from being re-proposed. + +### Option A — Fixed lanes as per-mode item layers (SETTLED) + +REAPER's **fixed-lane** feature lets a single track hold multiple horizontal lanes +of items sharing one timebase, with **per-lane play/visibility control**. Map each +mode to a lane: Arrange items live in the Arrange lane, Design items in the Design +lane. Toggling a mode sets `C_LANEPLAYS` so only the active mode's lane plays and +shows; the collapse/hidden flags hide the inactive lane. Items keep their real +positions and their real track — nothing is moved off the timeline, nothing is +deleted. + +**SDK surface (verified present in `vendor/reaper-sdk`).** Track-side: +`I_FREEMODE = 2` (fixed-lane mode), `I_NUMFIXEDLANES`, per-lane `C_LANEPLAYS:N`. +Item-side: `I_FIXEDLANE`, `C_LANEPLAYS`, `B_FIXEDLANE_HIDDEN`. Two operational +notes for the implementation spec: **`I_FREEMODE` changes require +`UpdateTimeline()`** to take visible effect, and fixed lanes shipped in **REAPER 7**, +which sets the runtime floor (see fork 5). + +- **Fidelity to the two-canvas feel:** high. Same track, same time position, but the + design take and the arrange take are genuinely distinct item sets that never + co-occupy the view. This is exactly "same project, different items." +- **Non-destructiveness:** strong. Lane assignment and `C_LANEPLAYS` are + reversible flags; the item is never relocated in time or deleted. Snapshot the + prior lane state, restore on toggle — a direct extension of the existing + snapshot/restore contract to a new flag family. +- **Fit with park/restore:** clean. It's the same architecture — the planner gains + an item-lane op family alongside the track-flag op family. Pure model stays pure: + lane math (which lane = which mode, which `C_LANEPLAYS` value per mode) is + REAPER-free and unit-testable, mirroring the existing flag planner. +- **Capture-pillar precision:** untouched. Capture writes files to the bank and + never inserts into the timeline; lanes are a placement/view concern downstream of + capture. The null test and bit-identical invariants are unaffected because no + capture path changes. +- **Portability/persistence:** native. Fixed lanes and lane-plays are stored in the + `.rpp` by REAPER itself; the tool only persists which lane maps to which mode + (a small addition to the `"reasampler"` view section). +- **Cost / caveats:** fixed lanes are a real REAPER mode on a track — enabling + `I_FREEMODE=2` changes how that track behaves for the user (lane buttons, comp + behavior), and users unfamiliar with fixed lanes see new UI on managed tracks. + Under the settled **auto-tag** membership rule (see *Membership — settled* below), + a track becomes lane-split when it first needs to hold content for a second mode, + not by a manual "make this a two-canvas track" opt-in. Requires **REAPER 7**, where + fixed lanes shipped — this sets the runtime floor. + +### Option B — Timebase-region offset (each mode owns a stretch of the timeline) + +Give each mode a disjoint region of the single timeline — Arrange from 0, Design +starting at some large offset (say bar 1000). Items are authored in their mode's +region; toggling a mode scrolls/zooms the arrange view to that region +(`GetSet_ArrangeView2`) and optionally sets the loop/time selection there. +Different items appear because you're *looking at a different part of the timeline*. + +- **Fidelity:** medium. It reads as two workspaces if the scroll is snappy, but + they share tracks vertically — a Design track is still a lane on the same track + strip, just at a different horizontal offset. It doesn't give per-track item + layering; a shared track shows both stances' items if you scroll between them. +- **Non-destructiveness:** high (items just have positions), but **positions become + semantically loaded** — an item's `D_POSITION` now encodes its mode. That + collides with the capture pillar's null test, which re-inserts a capture *at its + source position* to verify it nulls. If source positions live in the Design + region, the null-test placement logic has to be region-aware. Friction with a + load-bearing invariant. +- **Fit with park/restore:** awkward. Parking is per-track; this is per-region. + Two orthogonal separation axes that don't compose cleanly. +- **Portability:** fine (just positions + a stored offset), but the offset is a + magic constant that leaks into every position calculation. +- **Verdict:** clever, but it overloads timeline position with mode semantics and + rubs against the capture invariants. Not recommended. + +### Option C — Dual sub-projects / project tabs (true separation, heavy) + +REAPER supports project tabs and subprojects (a project rendered as an item in a +parent). Model Design as a genuinely separate project surface, imported/rendered +back into Arrange. This is the *only* option that yields a literally separate +canvas. + +- **Fidelity:** highest — it *is* two canvases. +- **Cost:** enormous, and it fights the whole premise. "Same project" is Daniel's + explicit constraint; a subproject is a *different* project file with its own + item graph, its own render boundary, and a copy/sync problem between the two. The + capture pillar's "one bank per project, GUID-keyed project identity, travels with + the .rpp" assumption breaks — which project owns the bank? Persistence, + reconcile, and the show-both/derivation model all have to be rethought across a + project boundary. This is a different product. +- **Verdict:** rejected. It satisfies "two canvases" literally by violating "same + project." Daniel asked for *close as possible* within one project, not a second + project. + +## The settled shape + +**Option A — fixed lanes as per-mode item layers — layered on top of the shipped +track-parking model.** The shipped model already delivers "different leaves"; this +adds "different items" using a native REAPER mechanism that (a) preserves every +precision invariant, (b) extends the existing snapshot/restore architecture rather +than replacing it, (c) keeps the pure/shell split intact (lane math is pure, lane +writes are shell), and (d) persists natively. It is the transplant-a-known-pattern +move: REAPER already solved "multiple item sets, one track, one timebase, +switchable visibility" for comping — we repurpose comping lanes as mode lanes. + +The mental model: **modes are a projection, and now the projection reaches items as +well as tracks.** A track can be Arrange-only (parked in Design as today), +Design-only (parked in Arrange as today), or **shared-and-lane-split** (present in +both, but showing each mode its own lane of items). The third case is the new +capability and the concrete meaning of "two canvases." + +Phase namespace: **Phase D2 / Phase E** (per the lettered-phase convention for +parallel features) — additive to the shipped D1 track-mode work, not a rewrite. + +## Membership — settled (auto-tag by active mode at creation) + +The earlier draft floated a manual per-track opt-in ("make this a two-canvas +track"). **That is superseded.** The settled rule, verbatim from Daniel: + +> *"Items AND tracks added to the timeline in arrange mode or design mode should be +> tagged as for that mode only. Existing tracks and items default to arrange. If an +> item is added to arrange mode, it does not appear in design mode. If an item is +> added in design mode, it is NOT part of the arrange mode."* + +Unpacked into the settled model: + +- **Auto-tag at creation, not manual opt-in.** New content — **both new tracks and + new items** — is tagged to whatever mode is **active at the moment it is created**. + There is no separate "convert this track" gesture; membership follows the active + stance automatically. +- **Pre-existing content defaults to Arrange.** Every track and item that existed + before the mode system (or before this sub-phase) is an Arrange member, exactly as + the track-level default already established. +- **Membership is exclusive.** Design-created content never appears in Arrange, and + Arrange-created content never appears in Design — the one exception is the existing + **show-both** escape hatch, which continues to pin a leaf visible across modes. +- **Track level unchanged; item level is the new reach.** At the track level this is + the same tag-to-active-mode rule already settled. What is new: when a **shared** + track (present in both stances — a show-both track, or a folder carrying its own + media) gains an item in Design mode, that item lands in the track's **Design lane** + and is invisible/silent in Arrange, and vice versa. That per-item split is the + fixed-lane mechanism doing its job. + +This resolves the old fork 2 (opt-in vs. automatic) in favor of **automatic**, and +it is the through-line that also settles fork 4 (capture placement) below. + +## Inactive-mode items — settled (hidden AND silenced) + +When you are in one mode, the other mode's items on a shared track are **both hidden +and silenced**: the off-mode lane is set `C_LANEPLAYS = 0` — neither shown nor +played. This matches the exclusive-membership rule (Design-created content is *not +part of* Arrange, so it must not sound there) and the track-level principle already +settled: **flipping modes is a real change, not a cosmetic one.** A user who wants +the design lane audible under the arrangement uses show-both, which is the deliberate +opt-out; the default is full separation. + +## Managed vs. manual lanes — settled (2026-07-23) + +Fixed lanes are not only the mechanism we borrow for mode-item layering — they are +also **REAPER's native comping surface.** A user may want *their own* multiple lanes +on a track (manual comp takes, alternate reads) that have nothing to do with the mode +system. So a fixed-lane track can host **both** kinds of lane at once, and the tool +must not confuse them. Daniel's constraint, verbatim intent: *"as long as I can still +opt in manually to put multiple lanes on a track. we must index which lanes are +managed and which lanes are manual."* + +The settled distinction: + +- **Managed lanes** — minted and owned by the mode system to represent a mode's item + set on that track. Mode toggles drive these: the active mode's managed lane shows + and plays (`C_LANEPLAYS`), inactive-mode managed lanes are hidden and silenced. + These are the lanes the two-canvas mechanism creates and controls. +- **Manual lanes** — lanes the user created outside the mode system (native REAPER + comping, alternate takes). The mode system did **not** mint these and **must never + touch them**: a mode toggle never shows, hides, silences, re-lanes, or re-plays a + manual lane. Its `C_LANEPLAYS` state is the user's, left exactly as they set it. + +This is the fixed-lane analog of the two invariants already load-bearing in D1 — +*never touch `B_MUTE`/`I_SOLO`* and *never touch the master* — extended to a third +surface: **never drive a lane the tool did not mint.** It is the same non-destructive +promise (the tool owns only what it created) reaching one level deeper, into the lane +dimension. + +### Lane-ownership index (the new data) + +The tool maintains a **lane-ownership index**: per (track GUID, lane) it records +whether the lane is **managed** (and if so, which mode owns it) or **manual**. This +rides in the `"reasampler"` `view_state` alongside the membership index, GUID-keyed +and portable — same travel-with-the-`.rpp` guarantee as everything else in the view +section. Deciding *which lanes a toggle may touch* (managed only) is a **pure, +testable** query over this index; reading REAPER's live lane state is **shell**. The +seam is the same as everywhere else in the phase. + +> **Lane-identity fragility — flag for the implementation spec, not solved here.** +> REAPER's `I_FIXEDLANE` is the lane's identity and is how the ownership index keys to +> a specific lane. Whether `I_FIXEDLANE` values survive lane reorder / renumber / +> deletion without the index going stale is a **design point the technical spec must +> resolve** (the same class of concern as GUID-keyed reorder-safety for tracks). The +> product decision is only that managed and manual lanes are indexed and distinct; how +> the index stays correct under lane reordering is an implementation call, not a +> product one. + +### What a mode toggle does to manual lanes (intended behavior) + +A mode toggle **leaves every manual lane exactly as the user set it** — its +`C_LANEPLAYS` (play/show) state is untouched across the toggle. Only managed lanes are +partitioned into active (shown/played) and inactive (hidden/silenced). Concretely: if +a shared track has an Arrange managed lane, a Design managed lane, and two manual comp +lanes the user is auditioning, flipping Arrange↔Design swaps which managed lane plays +and leaves both manual lanes precisely as they were. + +**Interaction with auto-tag.** Auto-tag applies to content the user adds as **normal +timeline content** — items dropped, recorded, or placed onto the arrange surface in +the active mode. It does **not** reach into a lane the user is hand-managing: items a +user adds to a **manual** lane are **not** auto-tagged to the active mode, because the +user has taken explicit lane control there and the tool respects that boundary — the +manual/managed distinction is exactly the signal that this content is outside the mode +system. + +> **Auto-tag/manual-lane boundary heuristic — flag for the implementation spec.** +> Distinguishing "item added as normal timeline content (auto-tag it)" from "item added +> to a manual lane the user hand-manages (leave it alone)" may need a heuristic at the +> detection layer — e.g., an item landing in a lane the ownership index marks manual is +> exempt from auto-tag; an item landing outside any managed lane on a mode-managed +> track follows the active-mode rule. The precise rule is an **open implementation +> design point**, not invented here. The product decision is the boundary itself: +> manual-lane content is off-limits to auto-tag. + +## Capture placement — settled (mode-aware) + +Daniel's rule is general over *"items added to the timeline."* So an **explicit** +placement while in Design mode — including capture-and-place — lands the item in the +**Design lane**; the same rule governs manual insertion. This is the same auto-tag +rule reaching the placement pillar, not a new special case. + +**The capture load-bearing principle is untouched.** Capture still writes a file to +the bank and an index entry and **never** auto-inserts into the timeline. This rule +governs only *where an explicit placement lands* once the user chooses to place — +it does not create any auto-insertion path. The precision invariants (null test, +bit-identical repeats, non-destructive, exact bounds, relative paths) are entirely +unaffected: no capture path changes; lanes are a placement/view concern downstream +of the file. + +## REAPER version floor — settled (v7) + +Fixed lanes shipped in **REAPER 7**, so this sub-phase sets the runtime floor at +**v7**. The full API surface (track-side `I_FREEMODE=2` / `I_NUMFIXEDLANES` / +`C_LANEPLAYS:N`, item-side `I_FIXEDLANE` / `C_LANEPLAYS` / `B_FIXEDLANE_HIDDEN`) is +**verified present in the vendored SDK header**. No version gate branch is needed — +below v7 the sub-phase is simply unavailable. + +## Technical consideration — detecting new content (for the implementation spec) + +**REAPER exposes no clean "item added" / "track added" event callback.** The auto-tag +rule therefore requires the shell to detect new track/item GUIDs by **diffing project +state on the panel's existing timer**. The `bank_panel` already polls and fingerprints +the bank; this extends that same machinery to the timeline's tracks and items. + +- **Cadence / correctness.** Each poll, the shell compares the live track/item GUID + set against the previous poll's set; **any GUID new since the last poll is tagged to + the then-active mode.** The diffing cadence and the "new-since-last-poll ⇒ tag" + correctness rule are a design point the implementation must handle (e.g., first poll + after project open must not mass-tag pre-existing content — pre-existing defaults to + Arrange, per the membership rule). +- **Pure/shell split.** The **tagging decision** — given a set of new GUIDs plus the + active mode, produce the membership writes — is **pure and unit-testable**, mirroring + the existing planner. The **detection** — diffing REAPER's live item/track set each + timer tick — is **shell**. Keep the seam here: the shell hands the pure model "these + GUIDs are new, the active mode is M," and the model returns the membership mutations.