LearnNewsExamplesServices
Frontmatter
id13169
titleAdd dock named-layout collection helpers
stateClosed
labels
enhancementaiarchitecture
assigneesneo-gpt
createdAtJun 14, 2026, 3:35 AM
updatedAtJun 14, 2026, 8:39 AM
githubUrlhttps://github.com/neomjs/neo/issues/13169
authorneo-gpt
commentsCount0
parentIssue13158
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 14, 2026, 8:39 AM

Add dock named-layout collection helpers

Closed v13.1.0/archive-v13-1-0-chunk-2 enhancementaiarchitecture
neo-gpt
neo-gpt commented on Jun 14, 2026, 3:35 AM

Context

#13158 names named perspectives as one of the remaining QT-parity docking polish leaves. The saved-layout foundation is now in place: #13147 defined fail-closed saved layout helpers, and #13153 hardened saved-layout metadata framing. What is still missing is the smallest model-level collection layer that can hold multiple named neo.harness.dockLayout.v1 wrappers and switch the active one without choosing a storage backend or UI.

This ticket deliberately stays below the visual switcher and persistence backend. It gives later Agent Harness / Portal workspace UI slices a pure, unit-testable substrate for named layout perspectives.

The Problem

Neo.dashboard.DockZoneModel can create and restore a single saved-layout wrapper, but callers still have to invent their own collection shape for multiple named perspectives. If every consumer picks its own {layouts, activeLayoutId} convention, the switcher, import/export, and storage leaves will drift before the UI even lands.

Named perspectives should be a JSON-first model concern first: a validated collection of saved-layout wrappers, one active id, and pure semantic operations to upsert, remove, and select layouts. Storage and UI can then consume the same contract instead of encoding persistence-specific assumptions.

The Architectural Reality

  • src/dashboard/DockZoneModel.mjs owns the neo.harness.dockZone.v1 model helpers and the neo.harness.dockLayout.v1 saved-layout wrapper helpers.
  • learn/agentos/HarnessDockZoneModel.md already documents layoutId, title, revision, JSON-only saved layouts, and named-perspective demand under #13158.
  • The correct layer is still src/dashboard/: the helpers are pure model operations over dock layout JSON, not harness-app pane registry code and not a core src/layout/Dock lift.
  • The storage backend is intentionally undecided. This ticket must not touch localStorage, Memory Core, app preferences, or a rendered switcher.

The Fix

Add pure DockZoneModel helpers for a versioned named-layout collection around existing saved-layout wrappers:

  • create/validate a neo.harness.dockLayoutCollection.v1 collection;
  • upsert a saved layout by its layoutId;
  • select an active layout id;
  • remove a layout and fail closed when the active layout would become invalid;
  • restore the active saved layout through the existing restoreSavedLayout() path.

Update HarnessDockZoneModel.md with the collection shape and named-perspective boundary. Add focused unit coverage beside the existing saved-layout tests.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
DockZoneModel.LAYOUT_COLLECTION_SCHEMA src/dashboard/DockZoneModel.mjs saved-layout schema pattern New schema string neo.harness.dockLayoutCollection.v1 wraps multiple saved-layout wrappers Unknown schema rejected by validation/restore helpers HarnessDockZoneModel.md named perspectives section unit: rejects wrong collection schema
Named layout collection shape neo.harness.dockLayout.v1 wrapper and #13158 named-perspectives leaf JSON object with {schema, activeLayoutId, layouts, metadata, revision}; layouts is id-keyed by layoutId Invalid/missing layout ids produce errors, not implicit repair docs include JSON shape and field rules unit: creates collection from valid saved layouts
Upsert operation Existing pure model operation style in DockZoneModel Valid saved layout replaces/adds layouts[layoutId]; optional activation selects it Invalid saved layout returns errors and preserves prior collection docs operations table unit: upsert clone, replacement, activation
Select operation #13158 named perspectives, active-layout switcher consumer selectSavedLayout(collection, layoutId) changes active id only when the id exists Missing id fails closed with unchanged collection docs operations table unit: missing id rejected
Remove operation Fail-closed restore boundary from #13147/#13153 Removing a non-active layout succeeds; removing active layout requires explicit replacement or returns an error Active-layout removal without replacement denied docs operations table unit: active removal fail-closed
Active restore Existing restoreSavedLayout() helper restoreActiveSavedLayout(collection) restores the selected saved-layout wrapper through the existing validator Missing/invalid active layout returns errors and no document docs named-perspective boundary unit: restores selected layout and rejects invalid active id
Storage/UI boundary #13158 out-of-scope and HarnessDockZoneModel.md ownership boundary No browser storage, no UI switcher, no app-specific pane registry Later leaves choose storage/rendering against this pure contract out-of-scope section source diff: only model/docs/unit helpers

Acceptance Criteria

  • DockZoneModel exposes pure named-layout collection helpers without choosing a storage backend.
  • Collection helpers preserve JSON-only saved-layout guarantees by reusing existing saved-layout validation/restore paths.
  • Active-layout selection fails closed when the requested layout id is missing or invalid.
  • Removing the active layout fails closed unless a valid replacement active id is explicitly provided.
  • HarnessDockZoneModel.md documents the named-perspective collection shape and storage/UI boundary.
  • Focused unit tests cover create, upsert, select, remove, active restore, wrong schema, and invalid saved-layout rejection.

Out of Scope

  • Rendering a layout switcher UI.
  • Browser/app storage, Memory Core persistence, or user preferences.
  • Auto-hide/pin sidebars, grouped tab drag, or tab overflow menus.
  • Any core src/layout/Dock primitive.
  • Cross-window choreography.

Avoided Traps

  • Do not encode layout collections in apps/agentos first; that would force Portal or future consumers to reverse-engineer a harness-app-private shape.
  • Do not persist runtime preview geometry, windowId, live components, callbacks, or credentials in the collection metadata.
  • Do not silently pick a different active layout when the selected one is removed; that creates hidden user-workspace loss. Require an explicit replacement.

Related

Parent: #13158 Related: #13147 Related: #13153 Related: #13030 Related: #13012

Decision Record impact: aligned-with ADR 0020.

Release classification: post-release Agent Harness / M3 docking polish; not v13 release-blocking.

Live latest-open sweep: checked latest 20 open issues at 2026-06-14T01:31Z; no equivalent named-layout collection helper ticket found. Closest live/open item is parent epic #13158; closest closed foundations are #13147 and #13153.

A2A in-flight sweep: checked recent 40 A2A messages at 2026-06-14T01:31Z; no [lane-claim] / [lane-intent] overlaps named-layout collection helpers. #13167 Bridge-auth split is owned by Grace and is unrelated to this saved-layout helper lane.

Origin Session ID: 0ed5b1b0-739e-40e5-93e6-21a2e567ec24

Retrieval Hint: "DockZoneModel named layout collection helpers activeLayoutId saved-layout perspectives #13158"