Context
The QT-grade docking line under #13030 has progressed from pure model contracts into actual consuming surfaces: the dock-zone model contract, preview-state contract, split/tab adapter boundary, preview renderer, and split/tab rendering adapter are now separated into narrow leaves. #13115 owns semantic tree operations, and #13120 owns the later relocation of the reusable dock-zone subsystem into src/ after the open functional PRs merge.
The remaining parent AC that is safe to advance without stacking on #13115/#13116 is layout persistence: a docs-contract leaf that defines what a saved dock layout is, what restore is allowed to do, and which runtime fields remain forbidden before a persistence implementation starts.
Release classification: Project 13 harness line; not a v13 release blocker.
The Problem
learn/agentos/HarnessDockZoneModel.md repeatedly names layout persistence as a future consumer, and it already protects adjacent seams such as stale componentRef restore and runtime-only dockPreview state. It does not yet define the persistence envelope itself.
If the first persistence implementation starts from code, it will have to invent several policy decisions at once:
- whether the persisted object is just the dock-zone tree or a named layout wrapper around it;
- where schema/version metadata lives;
- what restore should do on unsupported schema, invalid references, or partial item recovery;
- whether save/restore may serialize runtime-only drag/window/preview data;
- what storage owner is allowed for the first harness-specific implementation versus later reusable
src/ ownership.
Those are contract choices, not UI details. They should be settled in the model contract first so a later code PR can stay mechanical.
The Architectural Reality
learn/agentos/HarnessDockZoneModel.md is the current contract authority for the docking line. It already separates serializable dock-zone state from runtime drag/preview/window state.
- The stale
componentRef follow-up (#13063) is closed and intentionally requires non-silent restore failure rather than silent item drops.
src/dashboard/DockLayoutAdapter.mjs consumes committed dock-zone state and explicitly rejects preview-only fields; it does not own persistence.
apps/agentos/view/DockPreview.mjs renders runtime-only preview affordances and has no write path to persisted dock-zone state.
- #13115/#13116 cover semantic operations, and #13120 covers the later source relocation. This ticket should not depend on either open PR because it is a contract clarification, not a code implementation.
The Fix
Update learn/agentos/HarnessDockZoneModel.md with a Layout Persistence Boundary section that defines the saved-layout contract.
The expected shape is documentation only:
- define a small versioned layout wrapper around the normalized
neo.harness.dockZone.v1 model;
- name required metadata such as stable layout id/title and schema/version fields;
- state that persistence consumes only committed, normalized dock-zone state after semantic operations have run;
- require fail-closed restore behavior for unsupported schema or invalid saved state;
- cross-reference stale
componentRef behavior instead of inventing a second restore policy;
- keep
dockPreview, DOM/window geometry, live component instances, functions, listeners, PATs, and harness credentials out of persisted state;
- clarify first implementation ownership: harness app storage/pane wiring may stay harness-local, while reusable projection/storage logic needs the later
src/ relocation path and second-consumer evidence.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback / Edge |
Docs |
Evidence |
| Saved dock layout wrapper |
#13030 + HarnessDockZoneModel.md |
Versioned JSON wrapper containing a normalized dock-zone model plus JSON-only layout metadata |
Unsupported schema or invalid model fails closed without replacing the active layout |
learn/agentos/HarnessDockZoneModel.md |
Static contract review |
| Restore policy |
#13063 stale componentRef policy + existing adapter boundary |
Validate schema/model first, then hand component recovery to the adapter's resolver/placeholder path |
Preserve last-good layout; expose validation/recovery instead of silent drops or tree corruption |
same |
Static cross-reference review |
| Runtime exclusion boundary |
Existing serializable-vs-runtime section |
Persist only semantic layout state; exclude previews, DOM/window geometry, live instances, functions, listeners, PATs, and credentials |
Future detached-window restoration must use a separate semantic placement hint, not runtime state |
same |
Static forbidden-field review |
| Ownership boundary |
#13120 placement decision + current harness proof surface |
First harness-specific persistence may live in the harness app layer; reusable logic follows the src/ relocation/second-consumer path |
Do not lift to generic core layout solely from this contract PR |
same |
Review against #13120 sequencing |
Decision Record impact
aligned-with ADR 0020. No ADR amendment expected; this is a contract clarification under the existing Agent Harness docking line.
Acceptance Criteria
Out of Scope
- Implementing save/restore code.
- Choosing a storage backend or user-preference API.
- Adding named-layout UI.
- Changing
DockLayoutAdapter or DockPreview behavior.
- Implementing #13115 semantic operations or #13120 relocation.
- Introducing a generic
src/layout/Dock primitive.
Avoided Traps
- Persisting runtime drag/window fields — rejected; persistence must store semantic layout state, not derived hover geometry or live window/session state.
- Silent repair of corrupt layouts — rejected; restore should fail closed or expose recovery rather than rewrite saved trees invisibly.
- Bundling code with contract policy — rejected; this leaf should make the later implementation smaller, not become the implementation.
- Premature core lift — rejected; reusable ownership is already tracked by #13120 and still needs the second-consumer path.
Related
Parent epic: #13012
Refs #13030
Refs #13063
Refs #13115
Refs #13120
Live latest-open sweep: checked latest 25 open issues at 2026-06-13T19:47Z; no equivalent layout-persistence boundary ticket found. Closest surfaces were #13030 as the parent scoping anchor, #13063 as the closed stale-restore policy, #13115 as the semantic-operations executor, and #13120 as the parked relocation ticket.
A2A in-flight sweep: checked latest 30 messages across all read states at 2026-06-13T19:47Z; recent overlapping claims were #13115 semantic operations and #13120 relocation, not layout persistence.
KB/local sweep: ask_knowledge_base(type='ticket') for harness docking layout persistence returned only unrelated archive hits; query_raw_memories returned no matching in-flight persistence claim.
Retrieval Hint: "dock layout persistence boundary saved dock layout wrapper neo.harness.dockZone.v1 #13030"
Context
The QT-grade docking line under #13030 has progressed from pure model contracts into actual consuming surfaces: the dock-zone model contract, preview-state contract, split/tab adapter boundary, preview renderer, and split/tab rendering adapter are now separated into narrow leaves. #13115 owns semantic tree operations, and #13120 owns the later relocation of the reusable dock-zone subsystem into
src/after the open functional PRs merge.The remaining parent AC that is safe to advance without stacking on #13115/#13116 is layout persistence: a docs-contract leaf that defines what a saved dock layout is, what restore is allowed to do, and which runtime fields remain forbidden before a persistence implementation starts.
Release classification: Project 13 harness line; not a v13 release blocker.
The Problem
learn/agentos/HarnessDockZoneModel.mdrepeatedly names layout persistence as a future consumer, and it already protects adjacent seams such as stalecomponentRefrestore and runtime-onlydockPreviewstate. It does not yet define the persistence envelope itself.If the first persistence implementation starts from code, it will have to invent several policy decisions at once:
src/ownership.Those are contract choices, not UI details. They should be settled in the model contract first so a later code PR can stay mechanical.
The Architectural Reality
learn/agentos/HarnessDockZoneModel.mdis the current contract authority for the docking line. It already separates serializable dock-zone state from runtime drag/preview/window state.componentReffollow-up (#13063) is closed and intentionally requires non-silent restore failure rather than silent item drops.src/dashboard/DockLayoutAdapter.mjsconsumes committed dock-zone state and explicitly rejects preview-only fields; it does not own persistence.apps/agentos/view/DockPreview.mjsrenders runtime-only preview affordances and has no write path to persisted dock-zone state.The Fix
Update
learn/agentos/HarnessDockZoneModel.mdwith aLayout Persistence Boundarysection that defines the saved-layout contract.The expected shape is documentation only:
neo.harness.dockZone.v1model;componentRefbehavior instead of inventing a second restore policy;dockPreview, DOM/window geometry, live component instances, functions, listeners, PATs, and harness credentials out of persisted state;src/relocation path and second-consumer evidence.Contract Ledger Matrix
HarnessDockZoneModel.mdlearn/agentos/HarnessDockZoneModel.mdcomponentRefpolicy + existing adapter boundarysrc/relocation/second-consumer pathDecision Record impact
aligned-with ADR 0020. No ADR amendment expected; this is a contract clarification under the existing Agent Harness docking line.
Acceptance Criteria
learn/agentos/HarnessDockZoneModel.mddefines aLayout Persistence Boundaryfor saved dock layouts.neo.harness.dockZone.v1model and names schema/version metadata.componentRefrecovery instead of duplicating policy.src/relocation path.Out of Scope
DockLayoutAdapterorDockPreviewbehavior.src/layout/Dockprimitive.Avoided Traps
Related
Parent epic: #13012 Refs #13030 Refs #13063 Refs #13115 Refs #13120
Live latest-open sweep: checked latest 25 open issues at 2026-06-13T19:47Z; no equivalent layout-persistence boundary ticket found. Closest surfaces were #13030 as the parent scoping anchor, #13063 as the closed stale-restore policy, #13115 as the semantic-operations executor, and #13120 as the parked relocation ticket. A2A in-flight sweep: checked latest 30 messages across all read states at 2026-06-13T19:47Z; recent overlapping claims were #13115 semantic operations and #13120 relocation, not layout persistence. KB/local sweep:
ask_knowledge_base(type='ticket')for harness docking layout persistence returned only unrelated archive hits;query_raw_memoriesreturned no matching in-flight persistence claim.Retrieval Hint: "dock layout persistence boundary saved dock layout wrapper neo.harness.dockZone.v1 #13030"