# src/core/view — pure Design View mode model ## Scope Pure, REAPER-free Design View model: mode/track membership, folder-derived visibility, snapshot-based park/restore planning, new-content (GUID) detection, and the managed/manual lane-identity convention that underlies per-item mode separation (fixed lanes). Does **not** include: the actual DAW-side flag application (hide, CPU-park, per-FX offline, restore via `B_SHOWINTCP` / `B_SHOWINMIXER` / `B_MAINSEND` / `I_FXEN`) or the never-touch-master/mute/solo enforcement — those live in `shell/view`. ## Invariants Design View — additive phase spec (settled decisions; Two-canvas sub-phase, settled 2026-07-23): - **Membership.** Default = Arrange; every untagged leaf belongs to it. Leaves opt in to Design (or any mode). No track appears in two modes at once except via an explicit show-both toggle or parent/folder derivation. - **Parents are derived, never tagged.** A parent/folder track is visible in mode M if either any descendant leaf is visible in M, or the parent belongs to M by its own membership; an untagged parent is an Arrange member by default. A parent is never parked in any mode it is visible in. Master track is always visible and never touched. - **N-mode model, two-mode UI.** The data model carries arbitrarily many modes; the UI ships Arrange + Design. A mode is (stable id, display name, ordinal). - **Persistence.** Membership index + last-active mode + per-track flag snapshots ride in the existing `"reasampler"` project ext-state namespace and travel with the `.rpp`. - **Non-destructive restore (enforced in the pure layer).** For every flag the tool drives, snapshot the prior value before parking; on toggle-back, restore from the snapshot, never to a hardcoded default. Round-trip (snapshot → park → restore) returns every driven flag to its captured value — this is the phase's trust anchor, the analog of the capture null test. - **GUID-keyed, reorder-safe.** Membership keys on track GUID (`GetTrackGUID`), never track index; tolerates unknown/stale GUIDs (pruned on reconcile via `ViewModeModel::reconcile(liveGuids)`). - **Relative/portable state only** in the persisted view section (GUID strings, mode ids — no absolute paths, no index positions). - **Show-both semantics.** A per-track "pin visible across modes" flag that re-enables processing whenever shown. A show-both leaf appears in every mode's visible set and is never parked — its driven flags stay at snapshot/restored values. Stored on the membership record; persists; togglable per selection. - **Non-goals / guardrails:** No literal second canvas — a second window or duplicated project stays rejected; subproject/second-project-file approaches and overloading item `D_POSITION` with mode semantics (timebase-offset regions) are rejected paths (the latter collides with the capture null test). Every leaf is managed: an untagged leaf is an Arrange member and, when the active mode is not Arrange, is fully parked and snapshot-restored exactly like a tagged leaf; show-both is the only way to opt a leaf out of parking. Restore from snapshot, never to a default: no hardcoded "on" restores. **Two-canvas sub-phase (Phase D2/E) — settled and landed parts only:** - **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. - **Membership: adoption rule for new items; active mode for new tracks.** New tracks are tagged to the active mode at creation. New items follow an adoption rule: if the item's track has pre-existing managed-eligible content spanning exactly one mode, the item adopts that mode; the active-mode fallback applies only when the track is empty or already spans multiple modes. Items in manual lanes are excluded from the prior-mode computation and are not auto-tagged at all. Membership is exclusive per item except via show-both. - **Managed vs. manual lanes — indexed and distinct.** 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. The ownership index rides in `"reasampler"` `view_state` alongside the membership index, GUID-keyed and portable. **New invariant — mode operations touch only managed lanes:** "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." - **REAPER floor: v7** for this sub-phase (fixed lanes shipped in v7); no version-gate branch — below v7 the sub-phase is simply unavailable. - 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; lane assignment and `C_LANEPLAYS` are reversible flags, never a destructive operation. ## Modules - `view_mode_model` — Design View mode system: mode registry, GUID-keyed membership, folder-tree-aware visibility derivation, snapshot-based park/restore planner, JSON round-trip. - `view_tree` — pure `I_FOLDERDEPTH`→FolderTree helper for the Design View shell. - `mode_switch` — REAPER-free segment layout + hit-test for the bank_panel's Design View mode switch. - `guid_diff` — the pure, REAPER-free core of the D2 Wave-2 new-content detection: `newGuids(previous, current)` computes the GUIDs present in `current` but absent from `previous` (empty GUIDs ignored); `GuidBaseline` tracks the live GUID set across polls for one project, implementing the first-poll-after-open guard (the first `observe()` after construction/`reset()` records a baseline and reports nothing new, so pre-existing content is never mass-tagged) and re-arms via `reset()` on a detected project switch so detection never diffs across two unrelated projects. - `lane_keys` — the pure, REAPER-free convention mapping a fixed lane's durable REAPER name (`P_LANENAME:n`) to the opaque lane-key `view_mode_model` keys by, plus the managed/manual heuristic both the toggle-apply path and the new-content/auto-tag exemption path share: `kManagedLanePrefix` ("reasampler:") stamps every lane the tool mints; `isManagedLaneName`/`managedLaneKey`/`laneNameForMode`/`modeIdFromLaneName` round-trip a lane name ↔ its owning mode id; `isOnManualLane` is the single predicate governing which lanes a toggle may drive and which items are exempt from auto-tag. ## Gotchas - REAPER exposes no durable per-lane GUID — the only lane identity is the ordinal `I_FIXEDLANE`, which REAPER renumbers on reorder/delete. Lane identity must ride on the durable `P_LANENAME` (`lane_keys`), never the raw ordinal, or a reorder will silently corrupt managed/manual ownership. - `kManagedLanePrefix` ("reasampler:") is stable-forever like an action-id string — changing it strands the ownership of every already-minted lane in every already-saved project. - `guid_diff::GuidBaseline` must have `reset()` called on every detected project switch, or the next `observe()` will diff across two unrelated projects and mass-tag (or miss) content.