[x] 18475 Lower declarative dock layouts into the existing document model
blocking
[x] 18479 Explain declarative DockLayouts adoption in real applications, [x] 18478 Write the first declarative DockLayouts tutorial, [x] 18477 Adopt declarative configuration in the dock example
closedAt
Sep 8, 2026, 10:15 PM
Consume declarative panes and zones in DockWorkspace
This is the stage-one engine adoption contract: a basic consumer declares panes and zones and receives working dock components without implementing a constructor seed, pane resolver, cache or projection hook. The pure conversion is supplied by #18475; this leaf owns the real Workspace behavior and its normative documentation together.
The Problem
Nicer graph data does not itself instantiate a component. LayoutAdapter tries a resolver before a blueprint, while the base Workspace resolver returns a placeholder. Ordinary/lazy pane declarations therefore need an engine-owned resolution path, and initial declaration consumption must not become a second way to overwrite an active layout.
The Architectural Reality
Source baseline: Engine dev b537d0a3c8101c7d9fcb2a23317b6133d8d356ec, containing merged PRs #18470 and #18472.
Workspace.afterSetMounted already projects an absent first shell. Reuse this ownership; do not introduce another mounting loop.
Operations.addItem already creates a JSON record with optional atomic placement. addTab still requires an existing record. Reuse the accepted create/reopen vocabulary; do not weaken addTab's refusal.
ADR 0029 §2.6 governs pane identity, policy and standard lifecycle.
The Fix
Add plain initial panes and zones configs to Neo.dashboard.dock.Workspace. A pane key is the default persisted reference to its runtime declaration; header, module/ntype/className and normal component configuration use existing container idioms. Keep constructor functions and live bindings outside the dock document.
Consume the effective seed once, before the first dock projection. This leaf chooses and documents the precise framework lifecycle point, with static and computed initial values covered. A valid explicitly supplied dockModel takes precedence over zones; a supplied invalid document fails visibly rather than silently falling back to defaults.
Stage-one later-assignment contract: assigning panes or zones after seed consumption has no effect on the active document or the consumed declaration used for pane resolution. Document and test that behavior. Live declaration changes are not supported by this plain-config tier.
The consumed declaration registry remains available independently of the current dock document's catalog. Closing an item removes its catalog record; it does not erase the declaration needed to reopen that pane.
Resolve declared panes through the existing component lifecycle. Two declarations of one class remain separate instances/configurations. Existing instances are reused across ordinary moves and rail transitions. Standard declared-pane close/reopen uses the merged addItem operation when the record was deleted; creation/replacement is not performed by writing document.items outside the operation path. Document the supported public host call for reopening so consumers do not build their own seeding hook.
Amend ADR 0029 §§2.1/2.6 and the normative Decisions 1–2 of DockLayoutsAdoption.md in this same PR. The broad adoption tutorial rewrite remains a separate dependent guide leaf.
Contract Ledger Matrix
Target surface
Source of authority
Required behavior
Refusal / fallback
Docs
Evidence
panes / zones first use
D#18468 stage one; normal Base/Container initialization
Consume literal or computed seed once before first projection; use #18475 conversion
Invalid declaration reports its path; no partial shell/document
File-list absence with positive controls; report host+normalizer delta
Normative consumer authority
ADR 0029 and DockLayoutsAdoption.md
Declarations become the basic contribution; custom hooks remain explicit advanced extension points
No later-stage API advertised
Same-PR ADR/reference edits
Source-to-doc comparison at the reviewed head
Discussion Criteria Mapping
Source criteria 1–6: actual declaration consumption and timing, lazy repeated-class identity, declared-pane close/reopen, supplied-document compatibility, host/dependency delta and same-PR normative authority. The model corpus is supplied by #18475.
Acceptance Criteria
AC-1: A real minimal Workspace subclass containing only normal class config plus panes/zones renders the intended tabs/splits/edge rail. It defines no constructor, custom resolver, cache or projection hook.
AC-2: Literal and computed seeds are consumed at the documented lifecycle point exactly once. Supplied-document precedence and post-consumption assignments behave as stated, without extra projection or document writes.
AC-3: Lazy panes load through existing framework machinery when needed. Two keys using the same module keep distinct per-pane config/state, and moves/rail transitions retain the correct live instances.
AC-4: Closing and reopening a declared pane works through the documented host entry and merged addItem contract, with no consumer-side catalog mutation. Exercise a removed catalog record and duplicate/open-pane refusal. Standard declared-pane lifecycle remains covered; no separate recreation feature is introduced.
AC-5: Existing consumers that supply dockModel or override resolution continue to work. Reuse first-mount ownership, and keep declaration seeding out of projectDockZoneDocument; retain the Group-context repair from #18472.
AC-6: Measure the static closure of src/dashboard/dock/Workspace.mjs before/after this PR. Report normalizer+host bytes/modules, and assert absence of src/manager/Transaction.mjs, src/manager/transaction/History.mjs and src/dashboard/dock/persistence/TopologyLibrary.mjs with a non-vacuous file-list control. Do not freeze the previous byte total.
AC-7: ADR 0029 §§2.1/2.6, Workspace API JSDoc and the normative Decisions 1–2 of learn/guides/uibuildingblocks/DockLayoutsAdoption.md describe exactly this shipped contract in the same PR.
AC-8: Run the current file-size ratchet against the PR base. If Workspace.mjs growth requires an exception, put an exact size-guard-growth: src/dashboard/dock/Workspace.mjs — <specific reason> line in the PR body. Explain why the new seed/consumption/resolution responsibility belongs in this host; pure lowering stays in the model. The guard checks the declaration, while review judges the rationale—do not claim the script proves architectural placement or inflate the baseline to hide growth.
Validation
Load the repository unit/component testing guidance before execution. Add focused real-Workspace tests beside the existing dashboard suites, including the first-projection and import-direction controls. Run:
npx playwright test -c test/playwright/playwright.config.unit.mjs unit/dashboard --reporter=list
npx playwright test -c test/playwright/playwright.config.component.mjs dashboard
node buildScripts/util/static-closure.mjs --list src/dashboard/dock/Workspace.mjs
Record an exact-head rendered declaration receipt, the supplied-document and later-assignment controls, and the closure file-list/delta. Model-only scratch success is insufficient for ACs 1–4.
Dependencies and Decision Record
Native blocked-by dependency: #18475. Before editing the hot host, verify the implementation base contains merged PR #18470 (addItem; closes #18467) and PR #18472 (Group projection context; closes #18471). Those are completed prerequisites, not new children or ownership claims.
Decision Record: REQUIRED. Decision Record impact: amends ADR 0029 §§2.1/2.6 in this PR; neither supersedes it nor changes persisted schemas.
Out of Scope
perspectives/persistence/workspaces configuration; storage-key ownership; popup materialization; reactive panes_; authorization revocation and history invalidation; general Workstation decomposition; standalone tutorial authoring.
Avoided Traps
No second initial-mount loop; no resolver that rereads mutable post-consumption declarations; no callback serialization; no aliasing two pane keys to one instance; no eager Group import; no delayed normative-doc companion.
Related and Pickup
Related: #18474; #18467; #18471; #18456; #18475.
unowned-rationale: Available for peer self-selection after the model dependency; existing hot-file ownership must be checked at intake.
Retrieval Hint: D18468 stage-one plain panes/zones, first-mount consumption, supplied dockModel precedence, no consumer resolver, standard close/reopen, closure absence.
Latest 20 live open issues, latest 30 all-state A2A, a problem-oriented Memory Core query (placeholder/custom resolver/constructor burden), and eight own assignments checked immediately before filing. #18475 is the intended model dependency; no competing host leaf exists. Vega confirmed this packet is ours to file. Recall surfaced no actionable conflicting ruling. Existing #18303 Group/history work is separate. Engine structure-map command is unavailable; placement is the existing Workspace and its existing dashboard unit/component siblings. No new source directory is introduced.
Part of #18474. Blocked by #18475.
Context
This is the stage-one engine adoption contract: a basic consumer declares panes and zones and receives working dock components without implementing a constructor seed, pane resolver, cache or projection hook. The pure conversion is supplied by #18475; this leaf owns the real Workspace behavior and its normative documentation together.
The Problem
Nicer graph data does not itself instantiate a component. LayoutAdapter tries a resolver before a blueprint, while the base Workspace resolver returns a placeholder. Ordinary/lazy pane declarations therefore need an engine-owned resolution path, and initial declaration consumption must not become a second way to overwrite an active layout.
The Architectural Reality
Source baseline: Engine dev b537d0a3c8101c7d9fcb2a23317b6133d8d356ec, containing merged PRs #18470 and #18472.
The Fix
Add plain initial panes and zones configs to Neo.dashboard.dock.Workspace. A pane key is the default persisted reference to its runtime declaration; header, module/ntype/className and normal component configuration use existing container idioms. Keep constructor functions and live bindings outside the dock document.
Consume the effective seed once, before the first dock projection. This leaf chooses and documents the precise framework lifecycle point, with static and computed initial values covered. A valid explicitly supplied dockModel takes precedence over zones; a supplied invalid document fails visibly rather than silently falling back to defaults.
Stage-one later-assignment contract: assigning panes or zones after seed consumption has no effect on the active document or the consumed declaration used for pane resolution. Document and test that behavior. Live declaration changes are not supported by this plain-config tier.
The consumed declaration registry remains available independently of the current dock document's catalog. Closing an item removes its catalog record; it does not erase the declaration needed to reopen that pane.
Resolve declared panes through the existing component lifecycle. Two declarations of one class remain separate instances/configurations. Existing instances are reused across ordinary moves and rail transitions. Standard declared-pane close/reopen uses the merged addItem operation when the record was deleted; creation/replacement is not performed by writing document.items outside the operation path. Document the supported public host call for reopening so consumers do not build their own seeding hook.
Amend ADR 0029 §§2.1/2.6 and the normative Decisions 1–2 of DockLayoutsAdoption.md in this same PR. The broad adoption tutorial rewrite remains a separate dependent guide leaf.
Contract Ledger Matrix
Discussion Criteria Mapping
Source criteria 1–6: actual declaration consumption and timing, lazy repeated-class identity, declared-pane close/reopen, supplied-document compatibility, host/dependency delta and same-PR normative authority. The model corpus is supplied by #18475.
Acceptance Criteria
AC-1: A real minimal Workspace subclass containing only normal class config plus panes/zones renders the intended tabs/splits/edge rail. It defines no constructor, custom resolver, cache or projection hook.
AC-2: Literal and computed seeds are consumed at the documented lifecycle point exactly once. Supplied-document precedence and post-consumption assignments behave as stated, without extra projection or document writes.
AC-3: Lazy panes load through existing framework machinery when needed. Two keys using the same module keep distinct per-pane config/state, and moves/rail transitions retain the correct live instances.
AC-4: Closing and reopening a declared pane works through the documented host entry and merged addItem contract, with no consumer-side catalog mutation. Exercise a removed catalog record and duplicate/open-pane refusal. Standard declared-pane lifecycle remains covered; no separate recreation feature is introduced.
AC-5: Existing consumers that supply dockModel or override resolution continue to work. Reuse first-mount ownership, and keep declaration seeding out of projectDockZoneDocument; retain the Group-context repair from #18472.
AC-6: Measure the static closure of src/dashboard/dock/Workspace.mjs before/after this PR. Report normalizer+host bytes/modules, and assert absence of src/manager/Transaction.mjs, src/manager/transaction/History.mjs and src/dashboard/dock/persistence/TopologyLibrary.mjs with a non-vacuous file-list control. Do not freeze the previous byte total.
AC-7: ADR 0029 §§2.1/2.6, Workspace API JSDoc and the normative Decisions 1–2 of learn/guides/uibuildingblocks/DockLayoutsAdoption.md describe exactly this shipped contract in the same PR.
AC-8: Run the current file-size ratchet against the PR base. If Workspace.mjs growth requires an exception, put an exact
size-guard-growth: src/dashboard/dock/Workspace.mjs — <specific reason>line in the PR body. Explain why the new seed/consumption/resolution responsibility belongs in this host; pure lowering stays in the model. The guard checks the declaration, while review judges the rationale—do not claim the script proves architectural placement or inflate the baseline to hide growth.Validation
Load the repository unit/component testing guidance before execution. Add focused real-Workspace tests beside the existing dashboard suites, including the first-projection and import-direction controls. Run:
Record an exact-head rendered declaration receipt, the supplied-document and later-assignment controls, and the closure file-list/delta. Model-only scratch success is insufficient for ACs 1–4.
Dependencies and Decision Record
Native blocked-by dependency: #18475. Before editing the hot host, verify the implementation base contains merged PR #18470 (addItem; closes #18467) and PR #18472 (Group projection context; closes #18471). Those are completed prerequisites, not new children or ownership claims.
Decision Record: REQUIRED. Decision Record impact: amends ADR 0029 §§2.1/2.6 in this PR; neither supersedes it nor changes persisted schemas.
Out of Scope
perspectives/persistence/workspaces configuration; storage-key ownership; popup materialization; reactive panes_; authorization revocation and history invalidation; general Workstation decomposition; standalone tutorial authoring.
Avoided Traps
No second initial-mount loop; no resolver that rereads mutable post-consumption declarations; no callback serialization; no aliasing two pane keys to one instance; no eager Group import; no delayed normative-doc companion.
Related and Pickup
Related: #18474; #18467; #18471; #18456; #18475. unowned-rationale: Available for peer self-selection after the model dependency; existing hot-file ownership must be checked at intake. Retrieval Hint: D18468 stage-one plain panes/zones, first-mount consumption, supplied dockModel precedence, no consumer resolver, standard close/reopen, closure absence.
Origin Session ID: 4f9b7bbe-9dbc-4d36-a167-38fe0d288113
Creation checks
Latest 20 live open issues, latest 30 all-state A2A, a problem-oriented Memory Core query (placeholder/custom resolver/constructor burden), and eight own assignments checked immediately before filing. #18475 is the intended model dependency; no competing host leaf exists. Vega confirmed this packet is ours to file. Recall surfaced no actionable conflicting ruling. Existing #18303 Group/history work is separate. Engine structure-map command is unavailable; placement is the existing Workspace and its existing dashboard unit/component siblings. No new source directory is introduced.