Context
Follow-up leaf under #13158, the QT-parity docking polish epic. The epic names auto-hide / pin sidebars as the next visible docking affordance after the foundation. Current source and contract evidence show a policy hint exists (pinnable), but no persisted semantic state or model operation exists for an item becoming pinned vs auto-hide eligible.
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 GitHub issues immediately before creation; #13158 is the parent epic, but no equivalent pin-state leaf exists. A2A in-flight claim sweep: checked the latest 30 messages immediately before creation; no overlapping [lane-claim] / [lane-intent] on dock pin state or auto-hide model state found. Local exact sweep: rg "auto-hide|autohide|pin|pinnable|pinned|setItemPinned|pinItem|hide.*dock|dock.*hide" src/dashboard test/playwright/unit/dashboard learn/agentos/HarnessDockZoneModel.md resources/content/issues resources/content/discussions found the existing pinnable policy hint and the #13158 epic framing, but no operation/state implementation ticket. KB semantic sweep: ask_knowledge_base("dock auto-hide pin sidebars pinnable pinned DockZoneModel HarnessDockZoneModel existing ticket") confirmed pinnable is only a UI policy hint today and no explicit pinned/auto-hide state is defined.
The Problem
learn/agentos/HarnessDockZoneModel.md lists pinnable as a UI policy hint on dock items. #13158’s auto-hide/pin affordance needs a semantic state transition before a renderer can safely collapse sidebars or show a pin toggle. Without a model-owned pin state, the first UI implementation would likely store pin/auto-hide behavior in a renderer-local field or pointer/UI state, bypassing the DockZoneModel fail-closed operation boundary.
The model needs a narrow persisted state seam: a dock item can be marked pinned or unpinned through a semantic operation, while the visual sidebar affordance remains out of scope.
The Architectural Reality
src/dashboard/DockZoneModel.mjs owns pure static semantic operations over neo.harness.dockZone.v1 documents.
- The finite schema allowlist currently accepts item fields
componentRef, title, kind, blueprint, closable, pinnable, movable, and metadata.
learn/agentos/HarnessDockZoneModel.md documents pinnable as a policy hint, not persisted state.
DockZoneModel.applyOperation() is the descriptor dispatch seam used by operation producers.
DockLayoutAdapter should not own this mutation; it should eventually render committed model state.
The Fix
Add a narrow model-only operation:
- Add a persisted item field
pinned to the dock-zone item schema.
pinned: true means the item is pinned open.
pinned: false means the item is eligible for auto-hide behavior when an adapter later supports that affordance.
- Omitted
pinned preserves the current adapter-defined default.
- Add
DockZoneModel.setItemPinned(document, {itemId, pinned}).
- Reject unknown items fail-closed.
- Require
pinned to be a boolean.
- Reject attempts to pin-state-toggle an item whose
pinnable === false.
- Commit through the existing clone / normalize / validate path without mutating caller input.
- Add
operation: 'setItemPinned' dispatch in DockZoneModel.applyOperation().
- Update
learn/agentos/HarnessDockZoneModel.md to distinguish pinnable policy from pinned semantic state and list the operation.
- 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 |
Dock item field pinned |
#13158 auto-hide/pin scope; current pinnable policy hint in HarnessDockZoneModel.md; DockZoneModel finite item schema |
Persist a boolean item pin state separate from the pinnable capability hint |
Omitted field preserves current adapter-defined default; non-boolean values fail validation once operation-enforced |
Update HarnessDockZoneModel.md item-field notes |
Focused unit tests for allowed persisted pinned state and fail-closed invalid operation payloads |
DockZoneModel.setItemPinned(document, {itemId, pinned}) |
Existing DockZoneModel semantic operation pattern |
Update an existing item’s pinned value through clone + commit, without touching tree topology |
Return original document plus errors for unknown item, non-boolean pinned, or pinnable === false |
Add operation row to HarnessDockZoneModel.md |
Unit tests for success, fail-closed errors, and caller input immutability |
DockZoneModel.applyOperation(document, descriptor) dispatch |
Existing descriptor seam |
Dispatch {operation: 'setItemPinned', itemId, pinned} to setItemPinned() |
Unknown operations continue to fail closed as today |
Same docs row |
Unit test proving descriptor dispatch |
Decision Record impact
aligned-with ADR 0020 — continues the Agent Harness dashboard composition lane and preserves the dashboard-layer ownership boundary.
Acceptance Criteria
Out of Scope
- Rendering auto-hide sidebars or pin buttons.
- Pointer/hover/click behavior for collapsed sidebars.
- Layout persistence storage UI, named perspectives, grouped tab drag, tab overflow menus, or splitter handles.
- Changing
DockLayoutAdapter projection unless implementation evidence shows the model operation requires it.
Avoided Traps
- Do not let sidebar UI store pin state in renderer-only state that bypasses
DockZoneModel.
- Do not serialize hover state, screen coordinates,
windowId, popup state, or pointer lifecycle data into the dock-zone document.
- Do not treat
pinnable as state; it remains a capability/policy hint.
- Do not bundle visual auto-hide rendering with this model operation.
Related
Parent: #13158
Related: #13030
Related: #13012
Related: #13159
Related: #13153
Origin Session ID: 0ed5b1b0-739e-40e5-93e6-21a2e567ec24
Handoff Retrieval Hint: "dock auto-hide pin pinned pinnable setItemPinned DockZoneModel HarnessDockZoneModel"
Context
Follow-up leaf under #13158, the QT-parity docking polish epic. The epic names auto-hide / pin sidebars as the next visible docking affordance after the foundation. Current source and contract evidence show a policy hint exists (
pinnable), but no persisted semantic state or model operation exists for an item becoming pinned vs auto-hide eligible.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 GitHub issues immediately before creation; #13158 is the parent epic, but no equivalent pin-state leaf exists. A2A in-flight claim sweep: checked the latest 30 messages immediately before creation; no overlapping
[lane-claim]/[lane-intent]on dock pin state or auto-hide model state found. Local exact sweep:rg "auto-hide|autohide|pin|pinnable|pinned|setItemPinned|pinItem|hide.*dock|dock.*hide" src/dashboard test/playwright/unit/dashboard learn/agentos/HarnessDockZoneModel.md resources/content/issues resources/content/discussionsfound the existingpinnablepolicy hint and the #13158 epic framing, but no operation/state implementation ticket. KB semantic sweep:ask_knowledge_base("dock auto-hide pin sidebars pinnable pinned DockZoneModel HarnessDockZoneModel existing ticket")confirmedpinnableis only a UI policy hint today and no explicit pinned/auto-hide state is defined.The Problem
learn/agentos/HarnessDockZoneModel.mdlistspinnableas a UI policy hint on dock items. #13158’s auto-hide/pin affordance needs a semantic state transition before a renderer can safely collapse sidebars or show a pin toggle. Without a model-owned pin state, the first UI implementation would likely store pin/auto-hide behavior in a renderer-local field or pointer/UI state, bypassing theDockZoneModelfail-closed operation boundary.The model needs a narrow persisted state seam: a dock item can be marked pinned or unpinned through a semantic operation, while the visual sidebar affordance remains out of scope.
The Architectural Reality
src/dashboard/DockZoneModel.mjsowns pure static semantic operations overneo.harness.dockZone.v1documents.componentRef,title,kind,blueprint,closable,pinnable,movable, andmetadata.learn/agentos/HarnessDockZoneModel.mddocumentspinnableas a policy hint, not persisted state.DockZoneModel.applyOperation()is the descriptor dispatch seam used by operation producers.DockLayoutAdaptershould not own this mutation; it should eventually render committed model state.The Fix
Add a narrow model-only operation:
pinnedto the dock-zone item schema.pinned: truemeans the item is pinned open.pinned: falsemeans the item is eligible for auto-hide behavior when an adapter later supports that affordance.pinnedpreserves the current adapter-defined default.DockZoneModel.setItemPinned(document, {itemId, pinned}).pinnedto be a boolean.pinnable === false.operation: 'setItemPinned'dispatch inDockZoneModel.applyOperation().learn/agentos/HarnessDockZoneModel.mdto distinguishpinnablepolicy frompinnedsemantic state and list the operation.test/playwright/unit/dashboard/DockZoneModel.spec.mjs.Contract Ledger Matrix
pinnedpinnablepolicy hint inHarnessDockZoneModel.md;DockZoneModelfinite item schemapinnablecapability hintHarnessDockZoneModel.mditem-field notespinnedstate and fail-closed invalid operation payloadsDockZoneModel.setItemPinned(document, {itemId, pinned})DockZoneModelsemantic operation patternpinnedvalue through clone + commit, without touching tree topologypinned, orpinnable === falseHarnessDockZoneModel.mdDockZoneModel.applyOperation(document, descriptor)dispatch{operation: 'setItemPinned', itemId, pinned}tosetItemPinned()Decision Record impact
aligned-with ADR 0020 — continues the Agent Harness dashboard composition lane and preserves the dashboard-layer ownership boundary.
Acceptance Criteria
pinnedfield without saved-layout schema rejection.DockZoneModel.setItemPinned()updates an existing item’spinnedstate without mutating caller input.setItemPinned()fails closed for unknown items, non-booleanpinned, andpinnable === false.DockZoneModel.applyOperation()dispatchesoperation: 'setItemPinned'descriptors.learn/agentos/HarnessDockZoneModel.mddocumentspinnedas semantic state distinct frompinnablepolicy.Out of Scope
DockLayoutAdapterprojection unless implementation evidence shows the model operation requires it.Avoided Traps
DockZoneModel.windowId, popup state, or pointer lifecycle data into the dock-zone document.pinnableas state; it remains a capability/policy hint.Related
Parent: #13158 Related: #13030 Related: #13012 Related: #13159 Related: #13153
Origin Session ID: 0ed5b1b0-739e-40e5-93e6-21a2e567ec24
Handoff Retrieval Hint: "dock auto-hide pin pinned pinnable setItemPinned DockZoneModel HarnessDockZoneModel"