LearnNewsExamplesServices
Frontmatter
id13213
titleWire Harness dock splitter drag into resizeSplit
stateClosed
labels
enhancementaiarchitecture
assigneesneo-gpt
createdAtJun 14, 2026, 11:52 AM
updatedAtJun 14, 2026, 3:35 PM
githubUrlhttps://github.com/neomjs/neo/issues/13213
authorneo-gpt
commentsCount3
parentIssue13158
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtJun 14, 2026, 3:35 PM

Wire Harness dock splitter drag into resizeSplit

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

Context

PR #13209 renders stable dock splitter affordances and exposes DockLayoutAdapter.createResizeSplitOperation() so a later drag handler can emit the existing semantic resizeSplit operation. Ada approved that PR with no required changes, but named one durable follow-up: the Harness view still needs live pointer/drag wiring so the affordance becomes interactive instead of only projected metadata.

Release classification: post-release (Approve+Follow-Up from PR #13209; non-blocking for the #13206 merge gate).

Live duplicate sweep: checked the latest 30 open issues at 2026-06-14T09:50:50Z; exact live search for splitter drag resizeSplit Harness view returned no duplicate; labels enhancement, ai, and architecture exist. A2A latest-30 all-status sweep at the same boundary found no overlapping splitter-drag lane claim. Local and archived search found only the new #13206 adapter seam, the existing Neo.component.Splitter, and unrelated historical dashboard/splitter work.

The Problem

The dock-zone split model now has three separate pieces:

  • persisted semantic state owned by DockZoneModel
  • projected splitter affordances emitted by DockLayoutAdapter
  • future pointer/drag input that calculates a new child-size vector

The missing piece is the live Harness-view handler that turns a user drag into a committed resizeSplit operation. Leaving that work only as a PR post-merge checkbox makes it easy to lose after PR #13209 is merged, even though the user-facing resize affordance depends on it.

The Architectural Reality

learn/agentos/HarnessDockZoneModel.md defines resizeSplit as the semantic operation that updates a split node's normalized child sizes. The same contract says the dock model does not own pointer events, preview-only state must stay runtime-only, and the adapter must not read DOM rectangles, pointer coordinates, or drag-zone internals while projecting committed layout.

src/dashboard/DockZoneModel.mjs is the persisted-operation authority. Its class summary states operations are pure static functions over a dockZone.v1 document, return {document, errors}, fail closed, and keep runtime pixels, DOMRects, and preview state out of the persisted model.

src/dashboard/DockLayoutAdapter.mjs now projects splitter metadata and exposes createResizeSplitOperation(splitter, sizes). That helper intentionally accepts resolved positive sizes, clones size arrays, and emits {operation: 'resizeSplit', splitNodeId, sizes} without doing pointer math itself.

src/component/Splitter.mjs is not the correct authority for this model. It uses drag:start / drag:end and mutates sibling inline style.width / style.height after resolving DOM geometry. That existing component can inform UI affordance behavior, but the Harness dock path must commit through DockZoneModel.applyOperation() rather than letting a splitter component mutate persisted split sizes or sibling styles as the source of truth.

The Fix

Wire the Harness/dashboard view layer that owns rendered dock splitter components so pointer or drag completion:

  • reads the projected splitter metadata from the affordance rendered by DockLayoutAdapter
  • resolves the affected split children into a positive size vector in model child order
  • calls DockLayoutAdapter.createResizeSplitOperation(splitter, sizes)
  • commits that descriptor through DockZoneModel.applyOperation() or the owning Harness state reducer
  • re-renders from the committed dock-zone document

The implementation may wrap or adapt Neo.component.Splitter only if it prevents direct sibling style mutation from becoming the persistence authority. A Harness-specific handler is acceptable when it stays inside the existing drag lifecycle boundary and does not create a parallel docking pointer system.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback / Edge Case Docs Evidence
Harness dock splitter drag completion handler This issue plus learn/agentos/HarnessDockZoneModel.md drag integration boundary On drag completion, compute positive split sizes in child order and emit the semantic resizeSplit descriptor. Invalid metadata, non-finite sizes, missing split node, or rejected model operation leaves the previous dock-zone document unchanged and surfaces recoverable UI state. JSDoc on the handler or controller method. Focused unit or whitebox coverage proving handler-to-model commit and reject path.
DockLayoutAdapter.createResizeSplitOperation(splitter, sizes) PR #13209 / issue #13206 adapter seam Convert projected splitter metadata and resolved sizes into {operation: 'resizeSplit', splitNodeId, sizes} without pointer math or model mutation. Missing metadata still returns the descriptor shape; downstream model application rejects invalid split ids. Existing JSDoc is sufficient unless the handler adds stricter input rules. Unit coverage that the handler calls this helper and the descriptor commits through DockZoneModel.applyOperation().
DockZoneModel.applyOperation({operation: 'resizeSplit', ...}) learn/agentos/HarnessDockZoneModel.md operations contract and src/dashboard/DockZoneModel.mjs Apply valid split-size changes to a cloned document and return {document, errors}. Invalid references or invalid sizes fail closed with original document plus errors. No new docs unless behavior changes. Existing model tests plus handler-level commit/rejection tests.

Decision Record impact

aligned-with ADR 0020. The ticket implements a leaf under the Harness docking contract pointer in learn/agentos/decisions/0020-agent-harness-concept.md; it does not amend the ADR. It also aligns with learn/agentos/HarnessDockZoneModel.md, especially the operation table, drag integration boundary, and split projection rule that resizable splitters write back through resizeSplit rather than mutating persisted sizes directly.

Acceptance Criteria

  • A rendered dock splitter can be dragged in the Harness/dashboard view and commits a resizeSplit operation against the owning dock-zone document.
  • The implementation uses projected splitter metadata (splitNodeId, orientation, boundary index) rather than DOM position as persistent identity.
  • Positive child-size vectors are produced in model child order and passed through DockLayoutAdapter.createResizeSplitOperation().
  • Invalid metadata, missing split nodes, non-finite sizes, or model rejection leave the previous document unchanged.
  • Tests cover the successful drag-to-commit path and at least one rejection path.
  • No preview-only fields, DOM rectangles, pointer coordinates, window ids, or live component references are serialized into the dock-zone model.

Out of Scope

  • Generic drag-to-dock preview/drop wiring for tab, split, or edge targets.
  • Auto-hide, pin/unpin, perspective storage, grouped drag, or detached-window restore.
  • Replacing Neo.component.Splitter globally.
  • Changing the persisted dock-zone schema or adding another resize operation.

Avoided Traps

  • Do not make Neo.component.Splitter the persistence authority. Its current behavior mutates sibling inline styles, while dock layout persistence is model-owned.
  • Do not put pointer math into DockLayoutAdapter.project(). Projection consumes committed model state only.
  • Do not persist hover rectangles, DOMRects, window ids, pointer coordinates, or drag preview payloads.
  • Do not add a docking-specific pointer manager that bypasses the existing drag lifecycle unless a separate architectural decision explicitly changes the drag integration boundary.

Related

Parent: #13158

Related: #13206, #13209, #13012, #13030

Origin Session ID: 019ec50d-5a01-7b11-9490-50f3241e8cfc

Handoff Retrieval Hints: Harness dock splitter drag resizeSplit DockLayoutAdapter createResizeSplitOperation DockZoneModel applyOperation PR 13209