diff --git a/CONTEXT.md b/CONTEXT.md index 900a191..73c8960 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -400,12 +400,19 @@ Track-only-in-one-mode content is still handled by D1 track-parking, unchanged. `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.) +- **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 track stays + single-mode, no lane split, nothing stranded. The active-mode fallback applies + only when the track is empty (no prior content) or already spans multiple modes. + Items in **manual lanes** are excluded from the prior-mode computation and are + not auto-tagged at all (manual/managed boundary unchanged). Deliberate multi-mode + splits occur only via the explicit tag/move-item actions, never via auto-tag. + Pre-existing content defaults to **Arrange**. Membership is **exclusive per + item**: an item lives in exactly one mode, except via the existing **show-both** + escape hatch. (New-track tagging follows the same active-mode rule as D1 track + membership; the adoption rule is a refinement for 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 @@ -456,8 +463,11 @@ pure query over the ownership index; only reading REAPER's live lane state is sh 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. + track GUIDs + active mode* (active-mode rule) and *a set of new items, each + carrying the set of modes already present on its track* (`NewItem::trackModes`) + — plus the manual-lane exemption flag — `autoTagNewContent` produces the + membership writes. The adoption guard runs inside the pure layer: single prior + mode → adopt it; empty / multi-mode track, or new track → fall back to active mode. - **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 @@ -473,8 +483,11 @@ therefore requires the shell to **diff project state on the panel's existing tim 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.** +- Each poll, compare the live track/item GUID set against the previous poll's set. + New **track** GUIDs are tagged to the then-active mode. New **item** GUIDs are + passed to `autoTagNewContent` with the pre-existing mode-span of their track + (`NewItem::trackModes`): single-mode track → adopt that mode; empty / multi-mode + track → fall back to the then-active mode. Manual-lane items are excluded. - 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). @@ -482,7 +495,7 @@ to the timeline's tracks and items. **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 + outside any managed lane on a mode-managed track is subject to the adoption 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 @@ -490,9 +503,10 @@ to the timeline's tracks and items. 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. + lane ownership and per-item `trackModes`) is shell; the **tagging decision** and the + **managed/manual lane query** (new track GUIDs + active mode; new item GUIDs + + `trackModes` + active mode + manual-lane exemption ⇒ membership + lane writes) are + pure and unit-tested. ### REAPER API surface (verify all signatures)