Context
The neo.harness.dockZone.v1 contract (learn/agentos/HarnessDockZoneModel.md §Operations) defines the semantic operations that mutate a dock-zone workspace tree, but no code implements them yet. The docking line now has the two surrounding leaves: #13104 (AgentOS.view.DockPreview, PR #13109) produces operation descriptors via previewToOperation(), and #13105 (Neo.dashboard.DockLayoutAdapter, src/dashboard/) renders committed model nodes. The executor that applies an operation to mutate the persisted tree is the missing middle.
The Problem
Without a DockZoneModel executor, a dropped preview cannot commit into the persisted tree, and the adapter has no canonical producer of the committed nodes it renders. The contract's operations (moveItem / splitNode / addTab / detachItem / closeItem / normalizeTree) and invariants (referenced item ids exist; every item appears at most once; split sizes match child count and normalize to 1; tabs.activeItemId is null or a member of tabs.items; empty structural nodes collapse before serialization) are documentation-only.
The Architectural Reality
- Source of authority:
learn/agentos/HarnessDockZoneModel.md §Data Model (schema neo.harness.dockZone.v1: items catalog + nodes of type edge-zone / split / tabs) + §Operations.
- Placement:
apps/agentos/dock/ — harness-app-first per the contract's Ownership Boundary ("place in harness app layer" until a second independent in-repo consumer justifies a lift to dashboard/container substrate). NOT apps/agentos/model/ (that is Neo.data.Model records; this is a tree + pure-operations domain module).
- The #13105
DockLayoutAdapter (src/dashboard/) consumes committed model nodes (JSON) — there is no code import from the adapter to this model, so the placements are independent.
- This executor's input is the operation descriptor shape #13104
previewToOperation() emits ({operation: 'addTab'|'splitNode'|..., itemId, ...}).
The Fix
Add apps/agentos/dock/DockZoneModel.mjs — a class wrapping a dockZone.v1 document and exposing the contract's semantic operations plus normalizeTree() / validate(). Pure JSON manipulation, fail-closed on invalid references, mutation only through the named operations (never raw tree surgery). Unit spec under test/playwright/unit/apps/agentos/dock/.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Evidence |
moveItem / addTab |
HarnessDockZoneModel.md §Operations |
Reorder / insert an item within a tabs node at an index; set activeItemId |
Invalid itemId / nodeId → no-op + validation error, no partial mutation |
Unit coverage per operation + invariant |
splitNode |
§Operations |
Replace a node with a split of the old + new node; normalize sizes to 1 |
Invalid target / orientation → reject, tree unchanged |
Unit coverage |
detachItem / closeItem |
§Operations |
Remove from tree (detach preserves the item record; close removes from catalog) |
Missing item → no-op |
Unit coverage |
normalizeTree / validate |
§Operations invariants |
Collapse empty tabs/splits, re-validate refs + size sums + activeItemId |
Returns structured errors; never corrupts the tree |
Unit coverage of each invariant |
Decision Record impact
aligned-with ADR 0020 and the merged HarnessDockZoneModel.md dock-zone contract. No ADR amendment.
Acceptance Criteria
Out of Scope
- Rendering the committed tree — that is #13105 (
DockLayoutAdapter).
- Producing previews / the drag lifecycle — that is #13104.
- Layout persistence I/O, drag/pointer events, OS-window geometry.
- A generic core
src/layout/Dock primitive (the contract rejects it for this stage).
Avoided Traps
- External docking-library object model — rejected; Neo keeps worker-owned JSON.
- Pixel-absolute persistence — rejected; the model persists semantic splits/tabs/order, never runtime pixels.
- Tree surgery in UI handlers — rejected; mutation flows only through the named semantic operations.
Related
- Parent: #13030 (QT-grade docking). Refs #13012, #13104, #13105.
- Source of authority:
learn/agentos/HarnessDockZoneModel.md.
Release classification: harness line (Project 13); post-v13 product line, not release-blocking.
Origin Session ID: 4c598c8f-d8a7-4288-9420-e825a45d310e
Retrieval Hint: "dock-zone model operations executor moveItem splitNode addTab normalizeTree dockZone.v1 DockZoneModel apps/agentos/dock"
Context
The
neo.harness.dockZone.v1contract (learn/agentos/HarnessDockZoneModel.md§Operations) defines the semantic operations that mutate a dock-zone workspace tree, but no code implements them yet. The docking line now has the two surrounding leaves: #13104 (AgentOS.view.DockPreview, PR #13109) produces operation descriptors viapreviewToOperation(), and #13105 (Neo.dashboard.DockLayoutAdapter,src/dashboard/) renders committed model nodes. The executor that applies an operation to mutate the persisted tree is the missing middle.The Problem
Without a
DockZoneModelexecutor, a dropped preview cannot commit into the persisted tree, and the adapter has no canonical producer of the committed nodes it renders. The contract's operations (moveItem/splitNode/addTab/detachItem/closeItem/normalizeTree) and invariants (referenced item ids exist; every item appears at most once; split sizes match child count and normalize to1;tabs.activeItemIdis null or a member oftabs.items; empty structural nodes collapse before serialization) are documentation-only.The Architectural Reality
learn/agentos/HarnessDockZoneModel.md§Data Model (schemaneo.harness.dockZone.v1:itemscatalog +nodesof typeedge-zone/split/tabs) + §Operations.apps/agentos/dock/— harness-app-first per the contract's Ownership Boundary ("place in harness app layer" until a second independent in-repo consumer justifies a lift to dashboard/container substrate). NOTapps/agentos/model/(that isNeo.data.Modelrecords; this is a tree + pure-operations domain module).DockLayoutAdapter(src/dashboard/) consumes committed model nodes (JSON) — there is no code import from the adapter to this model, so the placements are independent.previewToOperation()emits ({operation: 'addTab'|'splitNode'|..., itemId, ...}).The Fix
Add
apps/agentos/dock/DockZoneModel.mjs— a class wrapping adockZone.v1document and exposing the contract's semantic operations plusnormalizeTree()/validate(). Pure JSON manipulation, fail-closed on invalid references, mutation only through the named operations (never raw tree surgery). Unit spec undertest/playwright/unit/apps/agentos/dock/.Contract Ledger Matrix
moveItem/addTabHarnessDockZoneModel.md§OperationsactiveItemIditemId/nodeId→ no-op + validation error, no partial mutationsplitNodesplitof the old + new node; normalize sizes to 1detachItem/closeItemnormalizeTree/validateDecision Record impact
aligned-with ADR 0020 and the merged
HarnessDockZoneModel.mddock-zone contract. No ADR amendment.Acceptance Criteria
apps/agentos/dock/DockZoneModel.mjsimplementsmoveItem,splitNode,addTab,detachItem,closeItem,normalizeTree,validateper the contract §Operations.tabs.activeItemIdnull-or-member; empty structural nodes collapse on normalize.AgentOS.view.DockPreview.previewToOperation()emits (#13104) applies through the matching operation.structural-pre-flightrecorded for the newapps/agentos/dock/placement.Out of Scope
DockLayoutAdapter).src/layout/Dockprimitive (the contract rejects it for this stage).Avoided Traps
Related
learn/agentos/HarnessDockZoneModel.md.Release classification: harness line (Project 13); post-v13 product line, not release-blocking.
Origin Session ID: 4c598c8f-d8a7-4288-9420-e825a45d310e Retrieval Hint: "dock-zone model operations executor moveItem splitNode addTab normalizeTree dockZone.v1 DockZoneModel apps/agentos/dock"