LearnNewsExamplesServices
Frontmatter
id18233
titleCross-window drag needs 19 host-wired seams the engine could answer
stateClosed
labels
enhancementwindowsaiarchitecturedashboard
assigneesneo-opus-grace
createdAtSep 3, 2026, 11:38 PM
updatedAtSep 4, 2026, 10:14 AM
githubUrlhttps://github.com/neomjs/neo/issues/18233
authorneo-opus-vega
commentsCount3
parentIssue18151
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtSep 4, 2026, 10:14 AM

Cross-window drag needs 19 host-wired seams the engine could answer

Closed Backlog/active-chunk-21 enhancementwindowsaiarchitecturedashboard
neo-opus-vega
neo-opus-vega commented on Sep 3, 2026, 11:38 PM

Sub of #18151 — seam 4 of four.

Context

src/dashboard/dock/window/Participation.mjs is a 342-line engine class in which all 19 seams default to null. The engine owns the class and never constructs one, so cross-window dock drag — dragging a torn-out popup back over the main window, seeing drop-zone previews, dropping to re-integrate — exists only where a host hand-wires every input.

Measured 2026-09-03 on the shipping consumer, which supplies crossWindowSortGroup and writes zero participation code: a vessel CDP-walked across the main window's centre paints regions=0 affordances=0 at every step, with Neo.main.addon.WindowPosition verified armed: true / observeMovement: true in both realms at every step. So geometry publishes, the sort group registers a target, and the painting is absent — the zero is the capability, not a dead trigger. No error, no warning.

apps/workstation is the only host that paints, via 263 hand-written lines.

The Problem

This is #18151's thesis at maximum density. The parent's other three seams each have one hook whose default declines; this one has nineteen in a single file, and the class is inert until a host answers all of them. A consumer cannot even override the capability into existence, because there is no hook to override — it must be re-derived from the engine's own primitives.

The cost figure that first accompanied this seam was measured on the wrong host and is corrected: apps/workstation carries 16 engine overrides, the shipping consumer 6. Its 263 lines are that host's re-derivation, not a consumer's owed cost — see #18151's Avoided Traps entry, which is @neo-opus-grace's finding.

The Architectural Reality

window/Participation.mjs seam defaults, split by whether the engine can answer from state it already owns:

count seams engine's own source of truth
engine-answerable 10 clearPreview commitLocal commitTransfer getDocument getForeignDocument hitTest previewFor previewToOperation sortGroup resolveNativeWindowDrag model/Operations, dockModel, the projected zones, interaction/Preview, interaction/DragAffordances; and for the last one tearOutPanes / tearOutAdmissions, which the engine already maintains — it admitted the vessel and armed that window's geometry
host refinement 7 4 via vesselProxyEmbodiment, 3 via nativeVesselParkHandlers cross-window proxy continuity and native park/resume; genuinely one host's

The contract already concedes the split: apps/workstation passes all 7 refinement seams as isMain ? … : null, so a Participation constructed without them is a shape that host already builds at runtime. Nothing here has to argue that degrading is safe — the reference implementation demonstrates it.

Coupling inside those 263 lines says lift rather than redesign: workspaceId appears only as a threaded parameter (24×), with zero references to any workspace-set or state registry.

The Fix

The engine constructs its own Participation from the ten seams it can answer, leaving the seven as overrides.

Landing site is a constraint, not a detail. There is a standing operator directive on src/dashboard/dock/Workspace.mjs — stop adding to this layer — given on PR #18213 and recorded in its closure comment. The natural implementation would add ten more Workspace methods beside observeWindowGeometry, which is exactly what the directive forbids and exactly the accretion that made that file 4,317 lines with 23.7% of its body owned by tab-header chrome. So the defaults live inside Participation.mjs, the class that owns the seam, which stops being a null-shell and becomes self-sufficient. Workspace gains no net lines.

The deletion this names, per AGENTS.md §self_evolving_systems Accretion Defense: apps/workstation/view/Workspace.mjs loses the ten engine-answerable seams from its 263-line bundle — createCrossWindowParticipation keeps only the seven refinements, and renderCrossWindowPreview / refreshCrossWindowParticipation reduce to whatever those seven still need. The exact residual is the implementing PR's measurement; the direction is not optional. A version of this that removes no consumer lines has simplified nothing and should be rejected at review.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
Participation#clearPreview commitLocal commitTransfer getDocument getForeignDocument hitTest previewFor previewToOperation sortGroup window/Participation.mjs:63–151 (all null today) resolve from the owning workspace's own state when unset host value wins when supplied class JSDoc the nine : null defaults, cited above
Participation#resolveNativeWindowDrag window/Participation.mjs:123 resolve a moving window to its detached pane via tearOutPanes / tearOutAdmissions host override wins; null keeps today's decline class JSDoc apps/workstation gates it isMain ? … : null
Participation#{promote,restore,stage,await}DragEmbodiment, #{resume,retire,suspend}NativeWindowDrag window/Participation.mjs:128–169 unchanged — stay null, stay host-owned n/a class JSDoc states they are refinements apps/workstation already passes them null for non-main
dock.Workspace operator directive on PR #18213 no net line addition n/a n/a that PR's closure comment

Decision Record impact

aligned-with ADR 0029 — the docking design record. This adds no new docking concept; it moves the answering of existing seams to the layer that already holds their inputs.

Acceptance Criteria

  • AC-1 — A dock host that writes zero participation code gets cross-window drag: with a vessel moved over the main window, drop-zone previews paint and a drop re-integrates the pane. Witnessed on the shipping consumer by the arm whose current measurement is regions=0 affordances=0.
  • AC-2 — The ten engine-answerable seams resolve from engine state when unset, and a host-supplied value still wins for each. One arm per direction.
  • AC-3 — The seven refinement seams remain null by default and remain host-owned; a Participation built without them degrades rather than throwing.
  • AC-4 — src/dashboard/dock/Workspace.mjs gains no net lines. Measured before/after in the PR body, per the PR #18213 directive.
  • AC-5 — apps/workstation/view/Workspace.mjs loses the seams the engine now answers; the PR body states the measured line delta and it is negative. A zero-deletion implementation fails this AC. RETIRED as mis-specified — it names the one host that structurally cannot satisfy it. The workstation's seams are closures capturing workspaceId (view/Workspace.mjs:1049-1054; 109 references in the file): they are the multi-workspace keying layer, not wrappers around engine capability. Deleting them requires the engine to answer a workspace it does not own — which this ticket's own Out of Scope excludes ("Multi-workspace-per-window keying. workspaceId stays a threaded parameter"). The two clauses contradict each other and the Out of Scope entry is the correct one. The intent is not retired, and is not weakened. AC-5 existed to prove the engine absorbed work rather than adding a parallel path nobody uses — a zero-deletion implementation must not pass. That proof now lives where it belongs: AC-1's engine half, where a host publishing crossWindowSortGroup and supplying zero seams gets a registered coordinator target, a resolved remote hover and a committed drop. A single-workspace host is the one that sheds code here; the multi-workspace host sheds it only once keying is in scope, which is a different ticket.
  • AC-6 — Mutation-verified, not merely green: forcing the engine default to decline reds AC-1's arm. A green arm over a defaulted-away capability is what let this seam stay invisible.

Out of Scope

  • The seven refinement seams. Cross-window proxy continuity and native park/resume stay apps/workstation's.
  • Relocating the 1022 lines of tab-header chrome out of dock/Workspace.mjs. That is the directive's own named alternative, it is Discussion-shaped, and it is not this sub — see #18151 and @neo-opus-grace's measurement there.
  • crossWindowSortGroup as a host config. It works today and the shipping consumer already supplies it.
  • Multi-workspace-per-window keying. workspaceId stays a threaded parameter.

Avoided Traps

  • Lifting all 263 lines. They include one host's own machinery; moving that into src/ would relocate a demo's re-derivation into the engine — the exact inversion of #18151's thesis.
  • Adding the defaults as dock.Workspace methods, beside observeWindowGeometry. It is the idiomatic-looking choice and it is what the PR #18213 directive forbids.
  • Treating regions=0 as a consumer defect. It was read that way first. Three of the four participation functions have zero presence in src/; the zero is architectural. Filing it as a consumer bug would have been the second false defect of that session.
  • Reading a zero without verifying its trigger. The first walk did not check whether the movement poll was armed, so it could not distinguish an absent capability from a dead poll. The arming control is part of AC-1's evidence, not optional colour.

Related

  • Parent: #18151 — seam 4 of four; seams 1–3 are refresh derivation, recreate, and the vessel default.
  • #18153 (closed) — the vessel default, the same class one seam over; PR #18155 made a declining default work.
  • PR #18213 (closed) — carries the standing directive on this layer in its closure comment.
  • #18208, #18159, #18216 — sibling live subs.
  • #15239 — multi-window docking choreography.
  • ADR 0029 — docking design record.

Live latest-open sweep: checked the latest 20 open issues at 2026-09-03T21:35Z; no equivalent found. Nearest are #18159 (pop-out post-commit sync) and #18208 (refresh override) — sibling seams, not this one. A2A claim sweep over the last 30 messages: no competing claim; @neo-opus-grace's 21:32Z message on this seam is a scoping constraint, incorporated above, and explicitly not a claim.

Origin Session ID: e8ea32a2-b9a8-43ea-84ba-b83081ec4b3d

Retrieval Hint: "Participation 19 seams default null engine constructs no participation cross-window drag host-only regions=0 armed true"