| 1 | <!-- English translation of adr/0017-multi-window-workspace-and-agent-surfaces.md. Canonical Russian: ../../adr/0017-multi-window-workspace-and-agent-surfaces.md --> |
| 2 | |
| 3 | # ADR 0017: Multiple Application Windows (Multi-Window), Screen Zones, and Agent Surfaces |
| 4 | |
| 5 | **Status:** Accepted · Implemented |
| 6 | **Date:** 2026-04-05 |
| 7 | **Updated:** 2026-04-18 — canon for `TopLevel` count and `display.screens` / topology; details — [§ History](#adr0017-history). |
| 8 | |
| 9 | ## Related ADRs |
| 10 | |
| 11 | | ADR | Role | |
| 12 | |-----|------| |
| 13 | | [0010](0010-ui-modes-toml-configuration.md) | UI modes and TOML over window frame; **zone presentation topology** — separate subsection in 0010, not mixed with `attention_zone_panels` | |
| 14 | | [0012](0012-floating-workspace-chrome.md) | Floating chrome; separate windows as one mechanic | |
| 15 | | [0021](0021-pfd-mfd-cockpit-attention-model.md) | PFD / forward / MFD zone semantics — **not** synonymous with window count | |
| 16 | | [0025](0025-sdk-attention-zones-and-capabilities.md) | Zones in SDK | |
| 17 | | [0016](0016-agent-client-protocol-external-agent.md) | External agent via ACP — orthogonal to *how many windows* show built-in UI | |
| 18 | | [0030](0030-command-ids-hotkeys-and-ui-registry-layers.md) | Command ids, **`Hotkeys/hotkeys.toml`** + user overlay, palette | |
| 19 | | [0031](0031-agent-chat-clarification-batches-and-threading.md) | Chat clarification batches — not PFD confirmations | |
| 20 | | [0002](0002-debug-human-agent-parity.md) | MCP parity | |
| 21 | | [0008](0008-mcp-contracts-and-testable-infrastructure.md) | MCP contracts | |
| 22 | | [0063](0063-instrument-deck-named-composition-one-anchor.md) | **Instrument deck** axis and *presentation* vs CDS — see § there; **topology keys** — below in this ADR | |
| 23 | | [0120](0120-primary-work-surface-intercom-or-editor.md) | `primary_work_surface` — Intercom or Editor in Forward (orthogonal to `presentation`) | |
| 24 | |
| 25 | ### Outside ADR |
| 26 | |
| 27 | | Document | Role | |
| 28 | |----------|------| |
| 29 | | [`attention-zone-panel-playbook-v1.md`](../../design/attention-zone-panel-playbook-v1.md) | Zone ↔ panel ↔ topology; in code — `AttentionLayoutSurfaceKind` | |
| 30 | | [`concept-pfd-mfd-cascade-v1.md`](../ui-ux/concept-pfd-mfd-cascade-v1.md) | PFD/MFD UX concept (superseded by [0021](0021-pfd-mfd-cockpit-attention-model.md)) | |
| 31 | | [`concept-to-implementation-map-v1.md`](../ui-ux/concept-to-implementation-map-v1.md) | Concept → code map | |
| 32 | | [skia-surfaces-vs-overlays-v1.md](../../design/skia-surfaces-vs-overlays-v1.md) | Skia surfaces vs overlays | |
| 33 | |
| 34 | ## Summary |
| 35 | |
| 36 | - **Multiple `TopLevel`** — product model for spreading zones across monitors; zone semantics ([0021](0021-pfd-mfd-cockpit-attention-model.md)) **≠** window count. |
| 37 | - Layout source of truth — **`presentation`** / **`zone_screen_layout`** string in **`settings.toml`** ([0028](0028-user-settings-toml-localappdata-and-secrets.md)), parser + `[presentation_grammar]`. |
| 38 | - **`(P+F)(M)`** → two windows; **`(P)(F)(M)`** → three; group order in the string = left to right on screens. |
| 39 | - **`MfdHostWindow` / `PfdHostWindow`** — full zone shell; placement only via `PresentationHostWindowPlacement`. |
| 40 | - MCP **`ide_get_ui_layout`** already returns all windows; roadmap — EICAS on second screen, fallbacks, agent confirmations ([“Open questions”](#adr0017-open-questions)). |
| 41 | |
| 42 | <a id="adr0017-implementation-status"></a> |
| 43 | |
| 44 | ## Implementation status (current in repository) |
| 45 | |
| 46 | Below — **what exists in code** so product backlog from [“Open questions”](#adr0017-open-questions) is not confused with shipped behavior. |
| 47 | |
| 48 | ### Already implemented |
| 49 | |
| 50 | | Area | Where in code / what it does | |
| 51 | |--------|------------------------------| |
| 52 | | `presentation` string parsing | `Services/Presentation/PresentationParser.cs`, **`PresentationInnerEtoGrammar`** (Eto.Parse), `PresentationGrammarTokens`, `PresentationLayoutAnalyzer`, `PresentationAnchorKind`, **`PresentationAnchorSlot`** (weights); tests `CascadeIDE.Tests/PresentationParserTests.cs`. **Zone weights** within a group — [§](#adr0017-zone-weights). **Main window columns:** `PresentationMainGridColumnDefinitions.Get` → **`MainGridColumnDefinitions`** on `MainWindowViewModel`, applied in **`MainWindow.PresentationLayout.axaml.cs`** (`ColumnDefinitions.Parse` — Avalonia does not bind a string to `ColumnDefinitions` from VM); MFD tail on two-anchor preset — `340` or `0` when column hidden for host ([implementation](../../Services/Presentation/PresentationMainGridColumnDefinitions.cs)). | |
| 53 | | Topology ↔ displays | `PresentationMonitorTopology.OrderScreensForPresentation` — sort `Screen` left-to-right, then top-to-bottom (shared coordinate grid; not OS primary as anchor). | |
| 54 | | Host window placement (`MfdHostWindow`, `PfdHostWindow`) | `Services/PresentationHostWindowPlacement` — target screen by index from preset; else first “non-main” screen; with saved bounds — restore clamped to `WorkingArea`. On dedicated monitor default **`WindowState.Maximized`**; disable — `[display]` **`maximize_presentation_host_windows_on_dedicated_screens`** (`DisplaySettings.MaximizePresentationHostWindowsOnDedicatedScreens`). | |
| 55 | | Placement invariant | Positioning/restoring `PfdHostWindow` / `MfdHostWindow` geometry — **only** via `PresentationHostWindowPlacement` (and shared lifecycle in `MainWindow.PresentationHostWindows.axaml.cs`); do not duplicate screen/`WorkingArea` logic in other Views without extending this service. | |
| 56 | | Host geometry persistence | `CascadeIdeSettings` / `[display]`: MFD — `MfdHostWindowPixelX` / `PixelY` / `Width` / `Height`; PFD — `PfdHostWindowPixelX` / `PixelY` / `Width` / `Height`; written on `Closing` of the window (`Views/MainWindow.PresentationHostWindows.axaml.cs`). | |
| 57 | | MFD host window | `Views/MfdHostWindow.axaml` — full `MfdShellView` ([§8](#adr0017-p8-mfd-host-wide)), same `DataContext` as `MainWindow`; MCP highlight layer like main window. Column under Mfd anchor in `MainWindow` — **one** `MfdShellView` (pages: chat, terminal, solution explorer, etc.), no baked-in “tree + shell” split; second `TopLevel` repeats **same** secondary contour ([skia-surfaces-vs-overlays-v1.md](../../design/skia-surfaces-vs-overlays-v1.md)), not necessarily pixel-matched width. | |
| 58 | | Lifecycle | No separate menu “second window” — source of truth is `presentation` / `zone_screen_layout`; auto-start on `Loaded` (`MainWindow.PresentationHostWindows.axaml.cs`): when topology fits && `OpenPfdHostWindowOnStartup` / `OpenMfdHostWindowOnStartup` && enough monitors — open `PfdHostWindow` and/or `MfdHostWindow`; optional MCP `toggle_mfd_host_window` under same topology (`CanExecute`). When host open, matching column in `MainWindow` hidden (`SetPfdHostWindowShellOpen` / `SetMfdHostWindowShellOpen`). | |
| 59 | | Attention topology | `AttentionLayoutSurfaceKind`: with hosts — `MainWindowPlusMfdHostTopLevel`, `MainWindowPlusPfdHostTopLevel`, `MainWindowPlusPfdMfdHostTopLevel` (`MainWindowViewModel.Presentation.cs`). | |
| 60 | | MCP / snapshots | `UiLayoutSnapshot`, roles `mfd_host` / `pfd_host` for respective windows; `ide_get_ui_layout` across all top-levels. | |
| 61 | |
| 62 | ### Partial or outside current code (roadmap remains) |
| 63 | |
| 64 | - **Preset with three groups `(…) (…) (…)`** (any anchor order, e.g. `(P) (F) (M)`): **canon** — **three** `TopLevel`, one zone per window; **spatially** left-to-right = group order in string (see “Spatial canon”). **In code:** `PresentationLayoutAnalyzer.IsTripleOneAnchorPerZonePreset`, host screen indices — `TryGetPfdHostPresentationScreenIndex` / `TryGetMfdHostPresentationScreenIndex`; windows **`PfdHostWindow`** and **`MfdHostWindow`**, main — Forward; placement/persist — `PresentationHostWindowPlacement` / `[display]`. Roadmap: product UX polish, monitor-change fallback, MCP beyond base `ide_get_ui_layout`. |
| 65 | - **Fallback** when monitor disappears / large OS layout change: clamp to work areas exists; dedicated “monitor unavailable” UX not mandatory here. |
| 66 | - **Closing main window:** on `MainWindow` `DataContext` reset, host close (`CloseMfdHostWindowIfOpen`); explicit `MainWindow.Closing` cascade — depends on app lifecycle. |
| 67 | - **EICAS / IDE Health on second screen**, chat/terminal density — product open items ([“Open questions”](#adr0017-open-questions)). |
| 68 | - **Agent confirmations** with two `TopLevel` — direction in [§6](#adr0017-p6); implementation details open. |
| 69 | |
| 70 | --- |
| 71 | |
| 72 | ## Context |
| 73 | |
| 74 | Today **one main window** (`MainWindow`) defines the whole visible cockpit: editor, tree, chat, Mfd column, etc. Mode configuration ([0010](0010-ui-modes-toml-configuration.md)) describes **visibility and metrics on a fixed frame**; an alternative “whole window schema” in data is explicitly deferred. |
| 75 | |
| 76 | Need: **spread roles across the screen** without cramming everything into one column — including: |
| 77 | |
| 78 | - **Multiple physical monitors** — ideally **`(PFD) (Forward) (MFD)`** (three displays); see “Multiple monitors” and layout table **`(PFD+Forward+MFD)`** with default **`Z`** or **`(PFD|Forward|MFD)`** with **`zone_separator = "|"`** / **`(PFD+Forward) (MFD)`**. |
| 79 | - **Move an attention zone to another display** — especially **MFD** (chat, terminal, trace, heavy agent panels); optionally **PFD** or a compact confirmations/status strip. Product wording — **zone ↔ second or third monitor**, not abstract “second window”. Code type `MfdHostWindow`, MCP snapshot `role` = `mfd_host` for that second `TopLevel`. |
| 80 | - **Layout experiments** isolated from stable presets — **Flight** as sandbox; multi-window fits there first (see `concept-pfd-mfd-cascade-v1.md` §5). |
| 81 | |
| 82 | [0012](0012-floating-workspace-chrome.md) already allows **separate windows** for part of chrome (telemetry, strips). **Basic MCP for multi-window exists:** `ide_get_ui_layout` returns JSON with `windows` (one tree per open `Window`, roles `main` / `mfd_host` / `other`); control lookup for inspect/act — main window first then others (`Cockpit/Surface/UiLayoutSnapshot`, `UiControlAppearance`). This ADR **extends** from technical “several roots in snapshot” to **product model** (which surfaces, lifecycle, state, modes and agent); **contract additions** when new window types or region semantics appear ([§7](#adr0017-p7)). |
| 83 | |
| 84 | ### One monitor and three semantic zones ([0021](0021-pfd-mfd-cockpit-attention-model.md)) |
| 85 | |
| 86 | Three spatial attention anchors (PFD, forward, MFD) **do not require** three separate windows. Current implementation — **one** main window, `MainGrid` columns, topology `AttentionLayoutSurfaceKind.MainWindowDockedGrid` (see playbook). |
| 87 | |
| 88 | **Optional:** spread same semantics across **several `TopLevel` on one physical monitor** (e.g. very wide display) — one process, same panel→zone map ([`AttentionZonePanelRuntime`](../../design/attention-zone-panel-playbook-v1.md)), different **presentation geometry** only. **Not the default goal:** **main window + zone on another monitor** and/or **preset inside one `TopLevel`** ([0021](0021-pfd-mfd-cockpit-attention-model.md), FancyZones motive). **Three linked `TopLevel` on one monitor** — only with explicit feedback or ultrawide scenarios; otherwise risk/complexity outweighs two windows or in-window grid. |
| 89 | |
| 90 | **Not** an argument for multi-window: “block OS-level window move”. Snapping, grid, predictable layout — within **one** `TopLevel` (splitters, presets) or programmatic positioning without promising OS forbid; see [0022](0022-mfd-visual-design-surface-axaml-blazor.md). |
| 91 | |
| 92 | <a id="adr0017-several-monitors"></a> |
| 93 | |
| 94 | ### Multiple monitors |
| 95 | |
| 96 | **Notation (do not mix “zones on one screen” and “number of displays”):** |
| 97 | |
| 98 | - **`( … )`** — **one physical display** (one area in OS monitor configuration). |
| 99 | - **Separator between anchors inside one parenthesis pair** — **exactly** literal **`Z`** from **`zone_separator`** (default **`+`**). Multiple semantic anchors (**PFD**, **Forward**, **MFD**) on **that** display (as columns in one `MainWindow`) are written **`anchor` `Z` `anchor` `Z` `anchor`**. In prose **`+`** and **`|`** illustrate one meaning; **in `presentation` string** with **`Z = "+"`** only **`+`** is allowed, with **`Z = "|"`** only **`|`** (parser does not substitute a “synonym”). |
| 100 | - **Short form** — same keys **`pfd_zone_identifier`** / **`forward_zone_identifier`** / **`mfd_zone_identifier`**, e.g. **`"P"`**, **`"F"`**, **`"M"`**; only the chosen literal is valid in `presentation`. |
| 101 | - **Several `(…) (…) (…)` in a row** — **different** displays; left-to-right in text is a convenient orientation; actual order comes from geometry and preset. **Three displays for three anchors** — only **three parenthesis groups**, e.g. **`(PFD) (Forward) (MFD)`**. **Bracket-less** `PFD | Forward | MFD` is **ambiguous** — do not use in config/docs; symbol between anchors **inside** brackets is **`Z`**, not a display separator. |
| 102 | |
| 103 | <a id="adr0017-display-screens-topology-naming"></a> |
| 104 | |
| 105 | ### Notation capacity and config naming direction (`display.screens` / `topology`) |
| 106 | |
| 107 | **Intentional density:** the same topology string (**`presentation`** in `settings.toml` root, future **`topology`** inside the table below) **mixes in one layer** (a) **how many** display groups in the preset (several `(…) (…) (…)` — see [§ “Multiple monitors”](#adr0017-several-monitors)) and (b) **how groups relate** to each other and anchors (spatial order in text, semantics inside a group). Splitting “display count” and “topology description” into **separate** keys could be clearer but **costs** verbosity. Current notation trades that for brevity; meanings (a) and (b) are **not separated** without grammar context and examples ([§ grammar](#adr0017-presentation-grammar), [EBNF](#adr0017-presentation-ebnf)). |
| 108 | |
| 109 | **TOML rename direction (reduce *presentation* confusion with UI “presentation” and other layers — [0063 § CDS](0063-instrument-deck-named-composition-one-anchor.md#adr0063-cds-not-presentation)):** canon — nest topology under semantic **`[display]`** ([0050](0050-declarative-instrument-zone-placement-toml.md), `Display` in model): |
| 110 | |
| 111 | - Table-level “whole topology in one place” (today root **`presentation`** / **`zone_screen_layout`** and related fields — see code) → **`[display.screens]`**. |
| 112 | - EBNF / anchor placement string — key **`topology`**. |
| 113 | - Grammar: section **`[presentation_grammar]`** → **`[display.screens.grammar]`** (or consistent nesting; code today — `CascadeIdeSettings.PresentationGrammar`). |
| 114 | |
| 115 | **What *screen* means in `display.screens`:** colloquial *screen* often means “OS monitor”. Here **screen** matches **`screen_markers`** in [token table](#adr0017-presentation-grammar): a **group** in the string, boundary of one preset presentation surface, PFD/MFD cockpit metaphor. “One `( … )` ↔ one physical OS display” is fixed [above](#adr0017-several-monitors); future table name **does not** change bracket semantics without explicit migration. |
| 116 | |
| 117 | **Why not `display.layout`:** **layout** is overloaded — **CockpitPresentationLayout**, [0046](0046-presentation-layout-authority-and-cockpit-invariants.md), plus layout **inside** an anchor (**instrument deck**, [0063](0063-instrument-deck-named-composition-one-anchor.md)). **`[display.layout]`** with **`topology`** could read clearer without “screens” but risks mixing with *in-region* layout more than **`display.screens`** after the paragraph above. If product picks **`layout`**, document: *multi-window / multi-anchor topology preset only, not deck or inner region grid*. |
| 118 | |
| 119 | **Migration:** read old keys as **legacy** N releases; on conflict new canon wins when present; update `settings.toml` examples when implemented. Immediate key rename in code **not required** by this section — direction only; timeline in TOML loader tasks. |
| 120 | |
| 121 | <a id="adr0017-presentation-grammar"></a> |
| 122 | |
| 123 | **Where to store and why not only `workspace.toml`:** layout across **physical displays** is **personal** (team members have different hardware). Repo **`.cascade/workspace.toml`** ([0021](0021-pfd-mfd-cockpit-attention-model.md) §2.1, [0028](0028-user-settings-toml-localappdata-and-secrets.md)) — **team convention** for panels/zones in shared attention model, **not** mandatory “three monitors for everyone”. In **`settings.toml`** root: **`presentation`** and/or **`zone_screen_layout`**; **optional** grammar tokens in **`[presentation_grammar]`** — personal monitor topology, **primarily** **`settings.toml`** (`%LocalAppData%\CascadeIDE\`, [0028](0028-user-settings-toml-localappdata-and-secrets.md)); on merge with `UiModes/` bundle and repo overlay **user** keys for these **override** bundle/repo if they ever appear (product default, not “team monitor decision”). |
| 124 | |
| 125 | **`presentation` string grammar (configurable in TOML):** optional keys in **`[presentation_grammar]`** — **which symbols** are screen markers, screen separator, zone separator, and **three zone literals** (long or short — one key per zone). Values are **user choice**; below — **defaults** used in examples in this ADR: |
| 126 | |
| 127 | | TOML key (inside `[presentation_grammar]`) | Default | Meaning | |
| 128 | |-------------|--------|--------| |
| 129 | | **`screen_markers`** | **`"()"`** | two-character string: open/close **one display** boundary | |
| 130 | | **`screen_separator`** | **`" "`** | separator **between** groups (displays), usually space between `)` and next `(` | |
| 131 | | **`zone_separator`** | **`"+"`** | separator **between anchors** inside one marker pair; **only this literal** allowed between anchors in `presentation` | |
| 132 | | **`pfd_zone_identifier`** | **`"PFD"`** | PFD anchor literal in `presentation` | |
| 133 | | **`forward_zone_identifier`** | **`"Forward"`** | forward anchor literal | |
| 134 | | **`mfd_zone_identifier`** | **`"MFD"`** | MFD anchor literal | |
| 135 | |
| 136 | Three literals must be **pairwise distinct** (case-insensitive compare). On collision implementation **resets** all three identifiers to table defaults. |
| 137 | |
| 138 | <a id="adr0017-anchor-aliases"></a> |
| 139 | |
| 140 | **Anchor identifiers.** User may set e.g. **`forward_zone_identifier = "Lob"`** and write **`(PFD+Lob+MFD)`**. Short letters **P** / **F** / **M** — same keys: **`pfd_zone_identifier = "P"`**, etc.; then only **`(P+F+M)`** in the string. |
| 141 | |
| 142 | Examples with **default** identifiers (**`PFD`**, **`Forward`**, **`MFD`**): full literals in string, e.g. **`(PFD+Forward+MFD)`**, **`(PFD) (Forward) (MFD)`**. Single-letter examples — after explicit **`[presentation_grammar]`** with short identifiers. |
| 143 | |
| 144 | <a id="adr0017-presentation-ebnf"></a> |
| 145 | |
| 146 | **Grammar (EBNF).** Unambiguous description below; anchor literals from TOML keys (see table). No whitespace **inside** `screen_markers` between anchors (only `zone_sep`). |
| 147 | |
| 148 | ```ebnf |
| 149 | (*--- Parameters from TOML: O, C, Z, S; anchor ids PfdId, ForwardId, MfdId (defaults — see table) ---*) |
| 150 | |
| 151 | presentation ::= [ SP ] screen { SP screen } [ SP ] |
| 152 | screen ::= "(" anchor { zone_sep anchor } ")" |
| 153 | zone_sep ::= Z |
| 154 | anchor ::= pfd_zone_identifier | forward_zone_identifier | mfd_zone_identifier |
| 155 | |
| 156 | pfd_zone_identifier ::= (* literal from pfd_zone_identifier key *) |
| 157 | forward_zone_identifier ::= (* literal from forward_zone_identifier key *) |
| 158 | mfd_zone_identifier ::= (* literal from mfd_zone_identifier key *) |
| 159 | |
| 160 | (* after parse: semantics PFD / forward / MFD — [0021](0021-pfd-mfd-cockpit-attention-model.md) *) |
| 161 | |
| 162 | (* lexer: three anchor strings; match longest literal first; length-1 literals — case insensitive *) |
| 163 | |
| 164 | SP ::= U+0020 { U+0020 } (* one or more spaces — display separator with default *) |
| 165 | ``` |
| 166 | |
| 167 | **Parameterization from TOML:** let **`O`** and **`C`** be first/second char of **`screen_markers`**, **`Z`** — **`zone_separator`**, **`S`** — **`screen_separator`**, anchor literals — values of **`pfd_zone_identifier`**, **`forward_zone_identifier`**, **`mfd_zone_identifier`**. Then: |
| 168 | |
| 169 | ```ebnf |
| 170 | presentation ::= [ S ] screen { S screen } [ S ] |
| 171 | screen ::= O anchor { Z anchor } C |
| 172 | (* anchor — as above; anchor tokens from TOML *) |
| 173 | ``` |
| 174 | |
| 175 | Between anchors in one screen only literal **`Z`** from TOML (default **`+`**). Parser **does not** substitute **`|`** or **`+`** for chosen **`Z`**. `presentation` must use **same** literals as configured tokens. Parser reads grammar from **`[presentation_grammar]`** (or defaults), then applies production. In code — **`CascadeIdeSettings.PresentationGrammar`**; merge with bundle — in implementation ([0010](0010-ui-modes-toml-configuration.md), [0028](0028-user-settings-toml-localappdata-and-secrets.md)). |
| 176 | |
| 177 | **In config:** same compact value may have **`# …`** comment explaining anchors and display count; ADR references in user file **not required**. |
| 178 | |
| 179 | **Product layer (outside this ADR):** where/how to give users expanded explanations (external docs, in-IDE help) — **product decision**, not ADR; see [architecture-policy.md](../../architecture-policy.md). |
| 180 | |
| 181 | **Three typical layouts by display:** |
| 182 | |
| 183 | | Layout | Meaning | |
| 184 | |--------|--------| |
| 185 | | **`(PFD+Forward+MFD)`** … (default **`Z`**); **`(PFD\|Forward\|MFD)`** with **`zone_separator = "\|"`**; **`(P+F+M)`** with short identifiers in **`[presentation_grammar]`** | One display: three anchors in **one** `TopLevel` (`MainGrid`). | |
| 186 | | **`(PFD+Forward) (MFD)`** …; **`(P+F) (M)`** with short ids | **Two `TopLevel`:** main — **PFD and forward together**; second window — **MFD** zone (`MfdHostWindow`). Typical two-monitor compromise. | |
| 187 | | **`(PFD) (Forward) (MFD)`** …; **`(P) (F) (M)`** with short ids | **Three `TopLevel`:** **one zone per window** (PFD; forward; MFD). Ideal with three monitors ([0021](0021-pfd-mfd-cockpit-attention-model.md)); vs v1 code — [“Implementation status”](#adr0017-implementation-status). | |
| 188 | |
| 189 | **Canon for window count:** **`(P+F)(M)`** ⇔ **two** top-level windows (main holds P+F, M out); **`(P)(F)(M)`** ⇔ **three** top-level windows (P, F, M separate). This is **`presentation` string semantics**, not “one window on three OS screens” and not three windows on one monitor as default goal. |
| 190 | |
| 191 | **Spatial canon (three displays, typical row):** **left to right** on screens (per `PresentationMonitorTopology.OrderScreensForPresentation`: left-right, then top-bottom) follows **`(…) (…) (…)`** **write order**. First group — left screen in that order, second — middle, third — right. Examples: **`(P) (F) (M)`** — PFD left, Forward center, MFD right; **`(M) (F) (P)`** — MFD left, Forward center, PFD right. No fixed “P always left” — only bracket order. If physical monitors are not one row, user maps **i-th** group to **i-th** screen in chosen order (or adjusts OS layout). |
| 192 | |
| 193 | <a id="adr0017-zone-weights"></a> |
| 194 | |
| 195 | ### Zone shares on one display (optional anchor weights) |
| 196 | |
| 197 | **Accepted:** inside **one** **`screen_markers`** pair, with **more than one** anchor, optional **positive coefficients** — **real literals immediately before** anchor id (canonical **no** space between number and id: **`0.25P`**). Before parse, parser **strips all Unicode whitespace** inside the screen pair, so **`(0.25P + 0.75F)(M)`** equals **`(0.25P+0.75F)(M)`**. Meaning: **share** of main column strip width (typical — three columns in `MainGrid`); coefficients in a group **sum to 1**. Example **`(0.25P+0.75F)(M)`** — first screen P and F split 1∶3; second screen single **M** on full display, **no separate weights** (between groups **`(…) (…)`** there are no weights: monitor boundary is desk/OS geometry, not a share in the string). |
| 198 | |
| 199 | **Invariant:** coefficients change only **shares within one group** (one screen). **Topology** — how many `(…)` groups, which anchors on which screen, how many physical displays, product effects like maximizing main on start — from **bracket composition**, not from picking **`0.25` vs `0.5`**. |
| 200 | |
| 201 | **When weights omitted** — current behavior: equal shares between anchors in group or existing grid default. |
| 202 | |
| 203 | **Within one group** with **two or more** anchors: either **every** anchor has a coefficient and **sum = 1**, or **none** (equal shares). Mixed like **`(0.25P+F+M)`** — **parse error** (ambiguous). |
| 204 | |
| 205 | **Single anchor in brackets** — anchor literal only, no coefficient (or equivalently one anchor fills the screen). |
| 206 | |
| 207 | **Number format:** decimal point **`.`** (TOML/JSON style); comma locale **not** supported in `presentation` string. |
| 208 | |
| 209 | **Parser link:** `PresentationParser` parses optional weight prefixes; inside one `screen_markers` pair anchor list structure from **Eto.Parse** (`PresentationInnerEtoGrammar`, NuGet **Eto.Parse**). Result — `PresentationParseResult.Screens` as lists of **`PresentationAnchorSlot`** (`Kind` + `Weight?`). Strings **without** coefficients remain canonical (`Weight == null` on all anchors in group). |
| 210 | |
| 211 | Extended **EBNF** relative to [base production](#adr0017-presentation-ebnf); may merge into one block in docs. |
| 212 | |
| 213 | ```ebnf |
| 214 | (*--- Extension: weights only inside screen with two+ anchors; sum weight = 1 ---*) |
| 215 | |
| 216 | weight ::= (* positive literal: integer or decimal, decimal point U+002E *) |
| 217 | weighted_anchor ::= weight anchor | anchor |
| 218 | screen ::= O weighted_anchor { Z weighted_anchor } C |
| 219 | (* semantics: in one screen either every weighted_anchor is "weight anchor" or each is "anchor"; mixing forbidden; with weights sum=1 *) |
| 220 | |
| 221 | (* Base form without weights — as now: anchor only *) |
| 222 | ``` |
| 223 | |
| 224 | **Examples** (short ids **`P`**, **`F`**, **`M`** in **`[presentation_grammar]`**): **`(0.25P+0.75F)(M)`**; **`(0.2P+0.3F+0.5M)`**; **`(P+F+M)`** — no weights, three equal shares. |
| 225 | |
| 226 | <a id="adr0017-nested-vh-notation"></a> |
| 227 | |
| 228 | ### Nested **v** and **h** axes (T-layout; note for agents and overview docs) |
| 229 | |
| 230 | Sometimes layout on **one** physical display is described with **explicit axes**, e.g.: |
| 231 | |
| 232 | **`0.3vPFD + 0.7v(0.8hForward + 0.2hMFD)`** |
| 233 | |
| 234 | **Reading:** |
| 235 | |
| 236 | 1. Split screen **vertically** (**`v`**): **30%** width left — **PFD** (workspace context, link tree, primary indicators in cockpit model). |
| 237 | 2. Remaining **70%** right — vertical band; split **horizontally** (**`h`**): **top 80%** — **Forward** (windshield: editor, work object), **bottom 20%** — **MFD** (telemetry, secondary contour, settings “at hand”). |
| 238 | |
| 239 | Classic cockpit **T-layout**: main work (code and “flight status”) center field of view, auxiliary below. Without **`v`** / **`h`** and nesting order, analyzer or agent **cannot unambiguously** map shares to Avalonia **`RowDefinitions` / `ColumnDefinitions`**: need **which split is first** (here vertical 0.3/0.7), then how **right part** splits by **rows** (0.8/0.2). |
| 240 | |
| 241 | **Link to current `presentation` string (v1 implementation):** parser and weights in [§ “Zone shares”](#adr0017-zone-weights) currently set **one axis** — typically **three `MainGrid` columns** (**PFD | Forward | MFD**) with width shares. **Nested** **`v` / `h`** notation in this ADR is **target semantics** for future grammar and/or composition layer ([0036](0036-cds-channel-compositor-surface-pipeline.md)); until nested-group parser exists, **do not** treat as equivalent to flat **`(0.3P+0.7F+…)`** without separate spec. |
| 242 | |
| 243 | <a id="adr0017-weight-fuse-policy"></a> |
| 244 | |
| 245 | **Fuse policy (geometry stability):** when weights and axes are **explicit in config**, product **must not** **dynamically recalculate** proportions at runtime “for convenience” (window resize must not replace configured shares). |
| 246 | |
| 247 | - **Analyzer** (parse/validate): at **each nesting level** coefficient sum on that axis **= 1** (as for flat screen with anchor weights). |
| 248 | - **Surface compositor** ([0036](0036-cds-channel-compositor-surface-pipeline.md)): at session start **fix** computed **normalized** shares (and pixel bounds after measure if needed), **no** floating recalc of shares on ordinary resize; exceptions — separate explicit product rule, not silent coefficient change. |
| 249 | |
| 250 | **Ideal (three physical displays):** **`(PFD) (Forward) (MFD)`** — target cockpit layout with enough hardware: workspace context / explorer and primary indicators on first screen, work object (editor) on second, secondary heavy panels (chat, terminal, trace…) on third. **Canon:** preset with **three `(…) (…) (…)` groups** means **three separate `TopLevel`** (see table above), not one window stretched across three monitors without zone split. |
| 251 | |
| 252 | **Attention metaphor (cockpit):** besides **forward** field of view there are **side zones** — reachable with **one glance** (peripheral attention) without long break from “forward” work. **PFD** and **MFD** are **side** relative to **forward (Forward)**, not “secondary screens” only; multi-window and direction-from-forward anchor align with this model. |
| 253 | |
| 254 | **Typical compromise (two displays):** **`(PFD+Forward) (MFD)`** with default **`Z`**, or **`(PFD|Forward) (MFD)`** with **`zone_separator = "|"`** — first monitor: PFD and forward together (as in one `MainGrid` today); second — **MFD** zone. Common; differs from three-screen ideal by merging PFD and forward on one display. |
| 255 | |
| 256 | ### `SkiaHost` instance matrix (fixed for v1) |
| 257 | |
| 258 | `SkiaHost` is **per slot**, not “one per window”. Typical topologies — three work surfaces (PFD / Forward / MFD), distribution changes by `TopLevel` only. |
| 259 | |
| 260 | | Topology (`presentation` formula) | `MainWindow` | `MfdHostWindow` | Total | |
| 261 | |--------|--------|--------|--------| |
| 262 | | **`(PFD+Forward+MFD)`** | `SkiaHost(PFD)`, `SkiaHost(Forward)`, `SkiaHost(MFD)` | — | **3** slots / **1** `TopLevel` | |
| 263 | | **`(PFD+Forward) (MFD)`** / **`(P+F) (M)`** | `SkiaHost(PFD)`, `SkiaHost(Forward)` | `SkiaHost(MFD)` | **3** slots / **2** `TopLevel` (canon) | |
| 264 | | **`(PFD) (Forward) (MFD)`** / **`(P) (F) (M)`** | per canon — one anchor per window (separate PFD/Forward hosts — roadmap) | `SkiaHost(MFD)` | **3** slots / **3** `TopLevel` (canon); **v1:** as row above since P+F in `MainWindow` | |
| 265 | |
| 266 | **Consequence:** no extra “aggregating” `SkiaHost` for whole `MainWindow`; base geometry from `presentation`/`MainGridColumnDefinitions`, surfaces stay slot-oriented. |
| 267 | |
| 268 | **Fourth and further** display — optional (e.g. fullscreen telemetry, second Mfd contour, external doc browser — per preset and product policy). |
| 269 | |
| 270 | Not the only possible scheme; presets map display↔zone. **`presentation` TopLevel canon** — table and `SkiaHost` matrix above; triple-group code fact — [“Implementation status”](#adr0017-implementation-status). MCP snapshot for several windows already supported ([§7](#adr0017-p7)); new scenarios — field/role tweaks in same delivery. |
| 271 | |
| 272 | ## Decision (principles; detail per discussion outcomes) |
| 273 | |
| 274 | <a id="adr0017-p1"></a> |
| 275 | 1. **One process, several `TopLevel`.** Windows belong to one IDE instance; solution, agent, settings state — **unified** VM/service graph behind a facade, not a second “independent” app instance. *Exceptions* (if ever needed) — separate decision and ADR. |
| 276 | |
| 277 | <a id="adr0017-p2"></a> |
| 278 | 2. **Main frame.** Keep **main window** (editor, solution, default navigation). Additional `TopLevel` are primarily **carriers of detached zones** (see context: MFD/PFD on **second or third monitor**); they **need not** duplicate the full cockpit. Composition and display binding — mode preset and/or explicit user action (e.g. “detach MFD” / “detach chat page” as part of Mfd secondary contour). MCP role `mfd_host` is the Mfd zone host window, not “chat only”. Closing main window — **app exit policy** (close all children or confirm) — fixed in implementation, not implicit. |
| 279 | |
| 280 | <a id="adr0017-p3"></a> |
| 281 | 3. **What may live in second and further windows (candidates, not all in v1):** primarily **Mfd zone region** on a **separate physical display** — in [0021](0021-pfd-mfd-cockpit-attention-model.md) secondary attention semantics; in code same **`MfdShellView`** host switching **`SecondaryShellPage`** pages (chat, terminal, build, …) — **page is not “the zone”**, zone is **Mfd** attention anchor; optionally **PFD** or compact confirmations/critical indicators on another monitor; detachable chrome per [0012](0012-floating-workspace-chrome.md). **Editor documents as floating MDI** — **out of this ADR** until separate decision (as [0012](0012-floating-workspace-chrome.md)). |
| 282 | |
| 283 | <a id="adr0017-p4"></a> |
| 284 | 4. **Link to UI modes ([0010](0010-ui-modes-toml-configuration.md)).** Presets set **visibility and slots** over available surfaces: one or several windows. **Zone presentation topology** (`AttentionLayoutSurfaceKind`: one window / several `TopLevel`, etc.) aligns with merge layers in [0010](0010-ui-modes-toml-configuration.md) and separation from panel→zone map — see “Zone presentation topology” in [0010](0010-ui-modes-toml-configuration.md). **Display layout string** — **`presentation`** or **`zone_screen_layout`**; **one** of two, not both. Value — literal from “Multiple monitors” (e.g. `(PFD+Forward) (MFD)`); optionally grammar tokens from [table](#adr0017-presentation-grammar) ([EBNF](#adr0017-presentation-ebnf)). **Storage:** primarily user **`settings.toml`** ([§ above](#adr0017-presentation-grammar), [0028](0028-user-settings-toml-localappdata-and-secrets.md)) so **personal** monitor layout is not mixed with **team** repo `workspace.toml`. Extension: keys for “which panels in detached zone by default” — **mode TOML** / Flight if needed. Validation and enum — in implementation. |
| 285 | |
| 286 | <a id="adr0017-p5"></a> |
| 287 | 5. **Geometry persistence.** Positions/sizes of **detached zone** windows (incl. 2nd/3rd monitor) — **not** written back to shipped `UiModes/*.toml` ([0010](0010-ui-modes-toml-configuration.md) rule). **In v1 code:** **`MfdHostWindow`** geometry persists in user **`settings.toml`** (`MfdHostWindowPixelX` / `PixelY` / `Width` / `Height` — [“Implementation status”](#adr0017-implementation-status)); other windows / full workspace snapshot — when separately agreed. |
| 288 | |
| 289 | **Presets and display choice for detached zone (accepted direction):** besides raw OS display id and saved rectangles, allow **user-natural semantics** — neighbor direction relative to the screen where **forward** anchor is shown in current layout ([0021](0021-pfd-mfd-cockpit-attention-model.md)), not OS **primary** by default. **Cross-platform:** target stack **.NET + Avalonia**; enumerate displays and **bounds in shared coordinate grid** (neighbor as `left | right | up | down`) via graphics API on **Windows, Linux, macOS**; not single-OS. OS differences (names, hotplug, Wayland vs X11, etc.) — **implementation and tests**, not forward-anchor product model. Key names/schema — same delivery as multi-window / [0010](0010-ui-modes-toml-configuration.md). **Tie-break:** if **several** neighbors in chosen direction, **do not** auto-pick “best” — **user choice** (explicit screen in UI, preset tweak, or raw id/saved rectangle). **Forward spanning several physical displays** — rare; **v1** — **one forward anchor screen** enough; generalize on explicit need. On monitor config change — **fallback** (saved geometry, return to main window, etc.) — implementation topic. |
| 290 | |
| 291 | <a id="adr0017-p5-primary-vs-forward"></a> |
| 292 | **OS primary display and Forward anchor (accepted):** system **primary** monitor (Windows “Make this my main display”) **is not identified** with **forward (Forward)** cockpit semantics. Primary serves OS/drivers (taskbar, scaling, etc.); typical **conflict** — touch monitor that **must** be primary for calibration though **forward** in user layout is **another** display. Defaulting Forward to primary **breaks** such setups. **Aligning** physical monitor arrangement, OS order, and **`presentation`** string — **user responsibility**; product does not replace desk layout or derive anchor semantics from primary alone. Implementation maps `(…) (…) …` groups to displays per accepted scheme (work area geometry and string order — see code), without “first in `presentation` = OS primary”. |
| 293 | |
| 294 | <a id="adr0017-p6"></a> |
| 295 | 6. **Agent (ACP, [0016](0016-agent-client-protocol-external-agent.md)).** Transport to external agent **does not depend** on window count: one stdio/session channel. This ADR decides only **where built-in** response/confirmation UI mounts (main vs additional). Short confirmations and critical signals should remain in **PFD attention** zone (concept §3); with second window — duplicate compact strip or explicit rule “focus main for confirmation”. |
| 296 | |
| 297 | <a id="adr0017-p6-confirmations"></a> |
| 298 | **Confirmations with several `TopLevel` (accepted direction):** do not rely only on system modal over the “wrong” window. Show request in **PFD attention stream** (banner/strip; presentation may avoid classic full-screen modal). Optional **secondary attention channel** (sound, OS notification area flash) if focus is on MFD/second window. **User answer** — same semantics as buttons: **command palette** and **gestures from [0030](0030-command-ids-hotkeys-and-ui-registry-layers.md)** — shipped [`Hotkeys/hotkeys.toml`](../../Hotkeys/hotkeys.toml) and user overlay `%LocalAppData%\CascadeIDE\hotkeys.toml` ([0028](0028-user-settings-toml-localappdata-and-secrets.md)). Until separate protocol decision: one `request_confirmation` (and analogs) still ends **ok/cancel** after answer; “non-blocking” refers to **presentation UX**, not mandatory MCP model change. |
| 299 | |
| 300 | <a id="adr0017-p7"></a> |
| 301 | 7. **MCP and parity ([0002](0002-debug-human-agent-parity.md), [0008](0008-mcp-contracts-and-testable-infrastructure.md), [0012](0012-floating-workspace-chrome.md)).** **Already implemented:** UI snapshot for agent/tests not limited to `MainWindow` — `ide_get_ui_layout` builds **`windows[]`** for all open process `Window`s; control-by-name actions consider non-main windows (see context). **When new product windows or semantics appear** (e.g. dedicated second `TopLevel` for MFD with separate zone taxonomy) **extend contract in same delivery**: new `role` values, region/surface id fields, parity tests — per [0012](0012-floating-workspace-chrome.md). Multi-window surfaces must not stay “human only” without conscious exception. |
| 302 | |
| 303 | <a id="adr0017-p8-mfd-host-wide"></a> |
| 304 | 8. **`MfdHostWindow` — full secondary contour only.** For layouts like **`(PFD+Forward) (MFD)`** / **`(PFD|Forward) (MFD)`** the second display semantically carries **whole Mfd zone**: one **`MfdHostWindow`** with **full** **`MfdShellView`** — same **page** host (`SecondaryShellPage`: chat, terminal, build, solution explorer, …) and same `DataContext` (`MainWindowViewModel`) as **secondary contour** in main window. **Parity** here — **secondary contour semantics** (page set inside `MfdShellView`), **not** mandatory pixel copy of **entire** visual column under Mfd anchor in `MainWindow`: under Mfd anchor in main — **one** `MfdShellView`; secondary tools (including solution explorer) switch by **pages**, not baked “tree + shell” split ([0021](0021-pfd-mfd-cockpit-attention-model.md): **zone** ≠ **page**). Separate `TopLevel` **need not** duplicate other main-window panels outside secondary contour. **Do not** ship “second window with one page only” (narrow host); “chat only” alternative **rejected** as target. Placement, initial geometry save, screen index from `presentation` — [“Implementation status”](#adr0017-implementation-status); open: monitor-change fallback polish, product UX ([§5](#adr0017-p5)). |
| 305 | |
| 306 | ## Consequences |
| 307 | |
| 308 | - **VM ownership design:** shared services; child windows as views or light VMs subscribed to shared session layer. |
| 309 | - UI tests/scenarios that assumed **only** `MainWindow` tree without `windows[]` in MCP need updates or explicit dual mode (one vs several windows); MCP snapshot for several `TopLevel` already supported. |
| 310 | - User docs (later): how to detach panel, return, where geometry is saved. |
| 311 | |
| 312 | ## Rejected alternatives (as target state) |
| 313 | |
| 314 | - **Rely only on external Cursor/IDE on second monitor** without built-in multi-window — rejected: does not close “one Cascade + screen zones” and in-product PFD/MFD (concept §8 — external tools **complement**, do not replace meaningful Cascade layout). |
| 315 | - **Full document MDI immediately** — out of scope; see [0012](0012-floating-workspace-chrome.md). |
| 316 | - **Several windows on one monitor to “forbid OS drag”** — rejected as motivation: weak; covered by layout **inside one window** (see “One monitor and three semantic zones” above). |
| 317 | |
| 318 | <a id="adr0017-modes-scope"></a> |
| 319 | |
| 320 | ## Clarification: UI modes (Power, Flight, etc.) |
| 321 | |
| 322 | **Accepted:** rework of **Power**, **Balanced**, and other presets/families per [0010](0010-ui-modes-toml-configuration.md) is a **separate** line; in **first delivery** of second `TopLevel` those modes **are not changed**; later preset/family rework — **separate** line. Multi-window v1 **not blocked** and **not mixed** with agreeing “how Power will look”. Question “only **Flight** / **Power** with flag” for multi-window **closed** until separate modes roadmap. **Flight** remains a useful experiment sandbox (see context), without obligating product to only that mode. |
| 323 | |
| 324 | <a id="adr0017-open-questions"></a> |
| 325 | |
| 326 | ## Open questions (for discussion before/during further code) |
| 327 | |
| 328 | - **Three `TopLevel` on one physical monitor** (three PFD/forward/MFD anchors as three OS frames): **not a default goal** — enough with “main window + detached **zone** on another monitor” (2nd/3rd display), multi-monitor per [0021 §13](0021-pfd-mfd-cockpit-attention-model.md) and **one window + preset/FancyZones** in [0021](0021-pfd-mfd-cockpit-attention-model.md). Revisit “three on one” only with explicit feedback (e.g. single ultrawide). |
| 329 | - Second `TopLevel` for Mfd on separate monitor — see [§8](#adr0017-p8-mfd-host-wide) and [“Implementation status”](#adr0017-implementation-status): **full** `MfdShellView` in **`MfdHostWindow`**; zone/page semantics — [0021](0021-pfd-mfd-cockpit-attention-model.md). **Basic** placement, bounds save, autostart — in code. **Open:** EICAS/IDE Health when detached, **chat/terminal UX** (density, keyboard), full monitor-change fallback; UI mode rework — [“Clarification: UI modes”](#adr0017-modes-scope). |
| 330 | - **Agent confirmations (product details):** timeouts, destructive ops, separate process modal layer — when implementing on top of accepted direction ([§6](#adr0017-p6) above). |
| 331 | - **Presets and monitors (implementation details):** accepted guide — [§5](#adr0017-p5) ( **forward** anchor, neighbor `left | right | up | down`). **Tie-break** with several neighbors one direction — **user side** ([§5](#adr0017-p5)), not mandatory product heuristic. **Display layout keys** — **`presentation`** / **`zone_screen_layout`** and grammar tokens — **personal**, see [§4](#adr0017-p4) and [§ storage](#adr0017-presentation-grammar); **open implementation detail:** fallback completeness when OS layout mismatches. |
| 332 | |
| 333 | ## Acceptance |
| 334 | |
| 335 | **2026-04-11** — status **Accepted**; link from [architecture-policy.md](../../architecture-policy.md). [concept-to-implementation-map-v1.md](../ui-ux/concept-to-implementation-map-v1.md) §6 — multi-window and `MfdHostWindow` (current file binding). **2026-04-11** — section [“Implementation status”](#adr0017-implementation-status): ADR synced with code (topology, placement, bounds persistence). |
| 336 | |
| 337 | --- |
| 338 | |
| 339 | ## Change history |
| 340 | |
| 341 | <a id="adr0017-history"></a> |
| 342 | |
| 343 | | Date | Change | |
| 344 | |------|--------| |
| 345 | | 2026-04-08 | [0021](0021-pfd-mfd-cockpit-attention-model.md), [0010](0010-ui-modes-toml-configuration.md); rejected motivation “forbid OS drag”. | |
| 346 | | 2026-04-11 | **[Zone shares on one display](#adr0017-zone-weights)** (optional anchor coefficients; no weights between `(…) (…)` groups). | |
| 347 | | 2026-04-11 | **[§5 addendum primary vs Forward](#adr0017-p5-primary-vs-forward)**. | |
| 348 | | 2026-04-11 | **[§8](#adr0017-p8-mfd-host-wide):** `MfdHostWindow` — full `MfdShellView` (all pages); narrow single-page host **not** shipped. | |
| 349 | | 2026-04-11 | **`(PFD+Forward) (MFD)` and analogs:** second screen = full MFD. | |
| 350 | | 2026-04-11 | **`presentation`** / **`zone_screen_layout`:** primarily **`settings.toml`** ([0028](0028-user-settings-toml-localappdata-and-secrets.md)), not team repo — see [§ storage](#adr0017-presentation-grammar), [§4](#adr0017-p4), [0010](0010-ui-modes-toml-configuration.md). | |
| 351 | | 2026-04-11 | **`zone_separator` strict:** parser does not substitute **`|`** for **`+`** or vice versa — see “Multiple monitors”, [EBNF](#adr0017-presentation-ebnf). | |
| 352 | | 2026-04-11 | **no separate `*_zone_alias`:** one literal per zone — only **`pfd_zone_identifier`** / **`forward_zone_identifier`** / **`mfd_zone_identifier`**; short names via same keys (e.g. **`pfd_zone_identifier = "P"`**). | |
| 353 | | 2026-04-11 | **`presentation` grammar:** EBNF in [§](#adr0017-presentation-ebnf); TOML keys — [§](#adr0017-presentation-grammar). | |
| 354 | | 2026-04-11 | **Ideal multi-monitor layout:** **`(PFD) (Forward) (MFD)`** (three displays); **side zone** cockpit metaphor; two-monitor compromise; Mfd zone host (`MfdHostWindow`), MCP `mfd_host`; three `TopLevel` on one monitor — not default goal; **v1 / `MfdShellView`** clarified in code; MCP `windows[]` ([§7](#adr0017-p7)); agent confirmations ([0030](0030-command-ids-hotkeys-and-ui-registry-layers.md)); presets and second display: direction anchor — **forward screen**, not OS primary; neighbor `left \| right \| up \| down`; displays — cross-platform; forward on several displays — out of v1; **tie-break** — user discretion; | |
| 355 | | 2026-04-11 | **Anchor literals in TOML** — [§ table](#adr0017-presentation-grammar), [EBNF](#adr0017-presentation-ebnf). | |
| 356 | | 2026-04-11 | **Display notation:** intra-bracket separator — **`zone_separator`** (**`Z`**, default **`+`**); prose **`+`** and **`|`** illustrate one meaning, `presentation` uses only chosen **`Z`**; several `(…) (…) (…)` — several displays; TOML `#` comments without mandatory ADR refs; product docs — [architecture-policy.md](../../architecture-policy.md). | |
| 357 | | 2026-04-11 | **UI modes (Power, etc.):** not in scope of first second-`TopLevel` delivery; mode rework separate; Flight vs Power for multi-window closed until modes line. | |
| 358 | | 2026-04-11 | **Status:** split “already implemented” / “roadmap” (parser and TOML not backlog). | |
| 359 | | 2026-04-11 | **Terminology:** attention zone **Mfd** vs **`SecondaryShellPage`** pages in `MfdShellView` (chat is a page, not a zone). | |
| 360 | | 2026-04-11 | **Grammar tokens** in **`settings.toml`** — **`[presentation_grammar]`** (`CascadeIdeSettings.PresentationGrammar`). | |
| 361 | | 2026-04-11 | status **Accepted**; navigator [architecture-policy.md](../../architecture-policy.md). | |
| 362 | | 2026-04-16 | [skia-surfaces-vs-overlays-v1.md](../../design/skia-surfaces-vs-overlays-v1.md); [§8](#adr0017-p8-mfd-host-wide): solution explorer — secondary contour page, not separate split in Mfd column `MainWindow`. | |
| 363 | | 2026-04-17 | **`TopLevel` count canon:** `(P+F)(M)` ⇒ two windows; `(P)(F)(M)` ⇒ three; left-to-right = group order in string; host placement only `PresentationHostWindowPlacement`. | |
| 364 | | 2026-04-18 | [§ `display.screens` / topology](#adr0017-display-screens-topology-naming); alignment with [0063](0063-instrument-deck-named-composition-one-anchor.md). | |
| 365 | |