Context
Follow-up leaf under #13158, the QT-parity docking polish epic. The foundation already models split sizes and projects them as flex values through DockLayoutAdapter, but there is no semantic operation for resizing an existing split.
Release classification: post-release / Agent Harness Project 13 M3 candidate — additive docking polish, not a v13 release blocker.
Live latest-open sweep: checked the latest 25 open issues immediately before creation; no equivalent splitter-resize semantic-operation ticket found. A2A in-flight claim sweep: checked latest 30 messages; no overlapping [lane-claim] / [lane-intent] on split resizing found. Local exact sweep: rg "resizeSplit|resize split|split resize|splitter resize|interactive splitter|split sizes" resources/content/issues resources/content/discussions learn/agentos/HarnessDockZoneModel.md src/dashboard test/playwright/unit/dashboard found only the existing contract references to split sizes and the future splitter affordance. KB semantic sweep: ask_knowledge_base("Is there an existing ticket or implementation for harness dock split resize semantic operation resizeSplit split sizes DockZoneModel?") found split.sizes and splitNode, but no existing resizeSplit operation or ticket.
The Problem
learn/agentos/HarnessDockZoneModel.md already says resizable splitters should write back semantic size changes through an operation, not mutate persisted sizes directly from pointer handlers. The model has the persisted field (split.sizes) and the adapter consumes it, but the operation seam is missing.
Without this operation, the first visual splitter UI leaf would either mutate model data directly from pointer logic or invent its own persistence path. That would bypass the existing fail-closed DockZoneModel operation boundary and recreate the exact runtime-vs-persisted-state drift the dock-zone contract rejects.
The Architectural Reality
src/dashboard/DockZoneModel.mjs owns pure semantic operations over neo.harness.dockZone.v1 documents.
DockZoneModel.validate() already enforces split-size invariants: size count matches child count and normalized sizes sum to 1.
DockZoneModel.applyOperation() is the descriptor dispatch seam used by runtime preview/operation producers.
src/dashboard/DockLayoutAdapter.mjs already projects valid split sizes into child flex values. It does not need to own mutation.
learn/agentos/HarnessDockZoneModel.md documents the future resizable splitter boundary: splitter affordances sit between projected children and write back semantic size changes through an operation.
The Fix
Add a narrow model-only operation:
DockZoneModel.resizeSplit(document, {splitNodeId, sizes})
- rejects unknown nodes and non-
split nodes fail-closed;
- requires one finite positive size per child;
- normalizes positive ratios to sum to
1, allowing callers to pass pixel-derived or ratio-derived values;
- returns
{document, errors} via the existing commit() path without mutating the caller input.
- Add
operation: 'resizeSplit' dispatch to DockZoneModel.applyOperation().
- Update
learn/agentos/HarnessDockZoneModel.md to list resizeSplit as the semantic write-back seam for future splitter affordances.
- Add focused unit coverage in
test/playwright/unit/dashboard/DockZoneModel.spec.mjs.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback / Edge Case |
Docs |
Evidence |
DockZoneModel.resizeSplit(document, {splitNodeId, sizes}) |
#13158 Stage 3 matrix; HarnessDockZoneModel.md Split Projection note; current DockZoneModel.validate() split-size invariants |
Update an existing split node's sizes with normalized positive ratios, preserving child order and all other model fields |
Return the original document plus errors for unknown node, non-split node, wrong size count, non-finite values, zero/negative values, or empty/zero-sum input |
Add the operation to HarnessDockZoneModel.md operation table |
Focused unit tests for success, normalization, fail-closed bad inputs, and caller-input immutability |
DockZoneModel.applyOperation(document, descriptor) descriptor dispatch |
Existing operation descriptor seam in DockZoneModel.applyOperation() |
Dispatch {operation: 'resizeSplit', splitNodeId, sizes} to resizeSplit() |
Unknown operations continue to fail closed as today |
Same doc row |
Unit test proving descriptor dispatch |
Decision Record impact
aligned-with ADR 0020 — continues the Agent Harness concept's dashboard composition lane by adding a semantic model operation without changing ownership boundaries.
Acceptance Criteria
Out of Scope
- Rendering splitter handles between projected children.
- Pointer/drag event handling for splitter UI.
- Named perspectives, saved-layout storage, auto-hide/pin, grouped tab drag, or overflow menus.
- Changing
DockLayoutAdapter projection unless implementation evidence shows the model operation requires it.
Avoided Traps
- Do not let visual pointer handlers mutate persisted
sizes directly.
- Do not serialize runtime pixels, DOMRects, pointer coordinates, or
windowId into the dock-zone document.
- Do not bundle visual splitter UI with the semantic operation; the operation is the narrow prerequisite seam.
- Do not lift this into a core
src/layout/Dock primitive; the current ownership boundary remains src/dashboard/.
Related
Parent: #13158
Related: #13030
Related: #13012
Related: #13147
Related: #13153
Origin Session ID: Codex Desktop thread 019ec1bf-997c-7113-a082-d36c84ec5439
Handoff Retrieval Hint: "dock splitter resize resizeSplit DockZoneModel split.sizes semantic operation HarnessDockZoneModel"
Context
Follow-up leaf under #13158, the QT-parity docking polish epic. The foundation already models split
sizesand projects them as flex values throughDockLayoutAdapter, but there is no semantic operation for resizing an existing split.Release classification: post-release / Agent Harness Project 13 M3 candidate — additive docking polish, not a v13 release blocker.
Live latest-open sweep: checked the latest 25 open issues immediately before creation; no equivalent splitter-resize semantic-operation ticket found. A2A in-flight claim sweep: checked latest 30 messages; no overlapping
[lane-claim]/[lane-intent]on split resizing found. Local exact sweep:rg "resizeSplit|resize split|split resize|splitter resize|interactive splitter|split sizes" resources/content/issues resources/content/discussions learn/agentos/HarnessDockZoneModel.md src/dashboard test/playwright/unit/dashboardfound only the existing contract references to splitsizesand the future splitter affordance. KB semantic sweep:ask_knowledge_base("Is there an existing ticket or implementation for harness dock split resize semantic operation resizeSplit split sizes DockZoneModel?")foundsplit.sizesandsplitNode, but no existingresizeSplitoperation or ticket.The Problem
learn/agentos/HarnessDockZoneModel.mdalready says resizable splitters should write back semantic size changes through an operation, not mutate persistedsizesdirectly from pointer handlers. The model has the persisted field (split.sizes) and the adapter consumes it, but the operation seam is missing.Without this operation, the first visual splitter UI leaf would either mutate model data directly from pointer logic or invent its own persistence path. That would bypass the existing fail-closed
DockZoneModeloperation boundary and recreate the exact runtime-vs-persisted-state drift the dock-zone contract rejects.The Architectural Reality
src/dashboard/DockZoneModel.mjsowns pure semantic operations overneo.harness.dockZone.v1documents.DockZoneModel.validate()already enforces split-size invariants: size count matches child count and normalized sizes sum to1.DockZoneModel.applyOperation()is the descriptor dispatch seam used by runtime preview/operation producers.src/dashboard/DockLayoutAdapter.mjsalready projects valid split sizes into childflexvalues. It does not need to own mutation.learn/agentos/HarnessDockZoneModel.mddocuments the future resizable splitter boundary: splitter affordances sit between projected children and write back semantic size changes through an operation.The Fix
Add a narrow model-only operation:
DockZoneModel.resizeSplit(document, {splitNodeId, sizes})splitnodes fail-closed;1, allowing callers to pass pixel-derived or ratio-derived values;{document, errors}via the existingcommit()path without mutating the caller input.operation: 'resizeSplit'dispatch toDockZoneModel.applyOperation().learn/agentos/HarnessDockZoneModel.mdto listresizeSplitas the semantic write-back seam for future splitter affordances.test/playwright/unit/dashboard/DockZoneModel.spec.mjs.Contract Ledger Matrix
DockZoneModel.resizeSplit(document, {splitNodeId, sizes})HarnessDockZoneModel.mdSplit Projection note; currentDockZoneModel.validate()split-size invariantssizeswith normalized positive ratios, preserving child order and all other model fieldsHarnessDockZoneModel.mdoperation tableDockZoneModel.applyOperation(document, descriptor)descriptor dispatchDockZoneModel.applyOperation(){operation: 'resizeSplit', splitNodeId, sizes}toresizeSplit()Decision Record impact
aligned-with ADR 0020 — continues the Agent Harness concept's dashboard composition lane by adding a semantic model operation without changing ownership boundaries.
Acceptance Criteria
DockZoneModel.resizeSplit()updates a split node's sizes and normalizes finite positive ratios to sum to1.resizeSplit()fails closed without mutating caller input for unknown nodes, non-split nodes, wrong-size arrays, non-finite values, and zero/negative values.DockZoneModel.applyOperation()dispatchesoperation: 'resizeSplit'descriptors.learn/agentos/HarnessDockZoneModel.mddocuments the new operation as the semantic write-back seam for later splitter UI.Out of Scope
DockLayoutAdapterprojection unless implementation evidence shows the model operation requires it.Avoided Traps
sizesdirectly.windowIdinto the dock-zone document.src/layout/Dockprimitive; the current ownership boundary remainssrc/dashboard/.Related
Parent: #13158 Related: #13030 Related: #13012 Related: #13147 Related: #13153
Origin Session ID: Codex Desktop thread
019ec1bf-997c-7113-a082-d36c84ec5439Handoff Retrieval Hint: "dock splitter resize resizeSplit DockZoneModel split.sizes semantic operation HarnessDockZoneModel"