LearnNewsExamplesServices
Frontmatter
id13147
titlePersist harness dock layouts with fail-closed restore
stateClosed
labels
enhancementaiarchitecture
assigneesneo-gpt
createdAtJun 14, 2026, 1:05 AM
updatedAtJun 14, 2026, 2:35 AM
githubUrlhttps://github.com/neomjs/neo/issues/13147
authorneo-gpt
commentsCount0
parentIssue13030
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[x] 13153 Enforce no-secret metadata for dock saved layouts
closedAtJun 14, 2026, 2:35 AM

Persist harness dock layouts with fail-closed restore

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

Context

The QT-grade docking line under #13030 has now moved through the narrow contract and rendering leaves:

  • #13061 / PR #13062 closed the dock-zone model contract.
  • #13086 / PR #13087 closed the drag-to-dock preview-state contract.
  • #13089 / PR #13090 closed the split/tab adapter boundary.
  • #13104 / PR #13109 closed the visual preview renderer.
  • #13105 / PR #13107 closed split/tab layout rendering.
  • #13115 / PR #13116 closed semantic dock-zone operations.
  • #13120 / PR #13142 relocated the reusable dock-zone subsystem under src/.
  • #13127 / PR #13128 closed the saved-layout persistence boundary, but explicitly kept save/restore code out of scope.

#13030 still carries the scoping-level AC that layouts are serializable/restorable and blueprint-compatible. The remaining gap is not another contract note; it is a tiny runtime helper surface that turns the existing normalized neo.harness.dockZone.v1 document into a saved layout wrapper and restores it fail-closed.

Release classification: post-release harness Project 13 work; not a v13 release blocker.

The Problem

learn/agentos/HarnessDockZoneModel.md now defines a Layout Persistence Boundary, including a versioned saved-layout wrapper and forbidden runtime fields. apps/agentos/dock/DockZoneModel.mjs already validates and mutates committed dock-zone documents, while src/dashboard/DockLayoutAdapter.mjs renders committed documents and rejects preview-only fields.

Without a runtime save/restore helper, the next UI/storage leaf has to re-derive the same wrapper validation, schema checks, forbidden-field exclusions, and fail-closed restore semantics. That would duplicate policy that already belongs beside the dock-zone semantic executor.

The Architectural Reality

  • apps/agentos/dock/DockZoneModel.mjs owns pure static operations over neo.harness.dockZone.v1 documents. It already has SCHEMA, clone(), validate(), normalizeTree(), and fail-closed operation commits.
  • learn/agentos/HarnessDockZoneModel.md lines 289-325 define the saved-layout wrapper boundary and runtime-field exclusions.
  • src/dashboard/DockLayoutAdapter.mjs consumes committed dock-zone state, not saved-layout wrappers or runtime preview state.
  • The first implementation can stay harness-local because storage backend and pane registry wiring are app-specific. Reusable import/export/storage projection can move later only with second-consumer evidence.

Structural pre-flight: no new .mjs file is required. The implementation should modify the existing apps/agentos/dock/DockZoneModel.mjs sibling surface and its existing unit spec at test/playwright/unit/apps/agentos/dock/DockZoneModel.spec.mjs.

The Fix

Add two small pure static helpers to DockZoneModel:

  • createSavedLayout(document, metadata) returns a versioned JSON-only wrapper around a normalized and validated dock-zone document.
  • restoreSavedLayout(savedLayout) validates the wrapper schema, validates the inner dock-zone document, rejects runtime/preview/window/component credential fields, and returns {document, errors} without replacing caller state on failure.

The helpers should not choose a storage backend, preference key, UI, pane registry, or persistence service. They only establish the runtime wrapper/restore boundary that the later storage/UI leaf can consume.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback / Edge Docs Evidence
DockZoneModel.createSavedLayout(document, metadata) #13127 + HarnessDockZoneModel.md Layout Persistence Boundary Return a versioned saved-layout wrapper containing JSON metadata plus normalized committed dock-zone state Invalid dock-zone document returns errors or throws consistently with existing fail-closed helper style; no runtime fields are serialized learn/agentos/HarnessDockZoneModel.md Unit tests against valid and invalid documents
DockZoneModel.restoreSavedLayout(savedLayout) #13127 + stale componentRef policy in the contract Validate wrapper schema, inner schema, and dock-zone invariants; return the restored document only when valid Unsupported wrapper schema, invalid inner model, missing document, or runtime-only fields fail closed with original caller state untouched same Unit tests for invalid schema/model/forbidden fields
Runtime-field exclusion Existing DockLayoutAdapter.forbiddenPreviewKeys + HarnessDockZoneModel.md Reject or strip preview/window/live component/credential material from saved layouts; do not persist dockPreview, DOM/window geometry, live instances, functions, listeners, PATs, or credentials Future detached-window restore hints must be separate semantic metadata, not runtime state same Unit tests prove forbidden payloads do not restore
Storage boundary ADR 0020 + #13030/#13127 No storage backend, UI, or user preference API in this ticket Later app-local storage leaf consumes these helpers same Diff contains only executor/spec/doc touchpoints

Decision Record impact

aligned-with ADR 0020. No ADR amendment expected; this is a runtime helper leaf under the accepted Agent Harness docking decomposition.

Acceptance Criteria

  • DockZoneModel exposes a saved-layout wrapper schema separate from neo.harness.dockZone.v1.
  • createSavedLayout() normalizes and validates the committed dock-zone document before wrapping it.
  • restoreSavedLayout() fails closed for unsupported wrapper schema, invalid inner dock-zone schema, invalid references, malformed payloads, and forbidden runtime/preview/window/credential fields.
  • The helper surface is pure: no storage backend, no browser storage, no preferences API, no UI, no live component registry, and no drag behavior.
  • Existing semantic operation behavior remains unchanged.
  • Focused unit tests cover valid save/restore, invalid wrapper schema, invalid dock-zone document, forbidden runtime fields, and immutability/no mutation of caller input.

Out of Scope

  • Persisting to localStorage, IndexedDB, files, config, Memory Core, or a user preference service.
  • Named-layout management UI.
  • Pane registry or live component resolution.
  • Drag/drop behavior changes.
  • New src/layout/Dock or generic docking engine promotion.
  • Cross-window detached-window placement restoration.

Avoided Traps

  • Bundling storage backend with validation — rejected; the first runtime helper should be reusable by any later storage owner.
  • Serializing runtime state — rejected; the model persists semantic layout only.
  • Silent restore repair — rejected; invalid saved state must fail closed and preserve last-good caller state.
  • Generic core lift — rejected; #13120 relocated reusable dock-zone model pieces, but first save/restore ownership remains harness-local until another consumer proves generic need.

Related

Parent: #13030 Parent epic: #13012 Refs #13127 Refs #13120 Refs #13115 Refs #13105

Live latest-open sweep: checked latest 20 open issues at 2026-06-14T00:00+02:00; no equivalent runtime dock layout persistence ticket found. Closest live issue is #13030, the scoping anchor. A2A in-flight sweep: checked latest 30 messages across all read states at 2026-06-14T00:00+02:00; no active lane-claim or lane-intent overlaps runtime dock layout persistence. KB/local sweep: ask_knowledge_base(type='ticket') for dock layout persistence implementation returned no Agent Harness persistence ticket; exact rg over issues/discussions/docs/source/tests found no createSavedLayout, restoreSavedLayout, or equivalent saved-layout implementation.

Origin Session ID: 0ed5b1b0-739e-40e5-93e6-21a2e567ec24 Retrieval Hint: "dock layout persistence runtime saved layout wrapper DockZoneModel createSavedLayout restoreSavedLayout #13030"