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
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"
Sub of #18151 — seam 4 of four.
Context
src/dashboard/dock/window/Participation.mjsis a 342-line engine class in which all 19 seams default tonull. 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
crossWindowSortGroupand writes zero participation code: a vessel CDP-walked across the main window's centre paintsregions=0 affordances=0at every step, withNeo.main.addon.WindowPositionverifiedarmed: true/observeMovement: truein 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/workstationis 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/workstationcarries 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.mjsseam defaults, split by whether the engine can answer from state it already owns:clearPreviewcommitLocalcommitTransfergetDocumentgetForeignDocumenthitTestpreviewForpreviewToOperationsortGroupresolveNativeWindowDragmodel/Operations,dockModel, the projected zones,interaction/Preview,interaction/DragAffordances; and for the last onetearOutPanes/tearOutAdmissions, which the engine already maintains — it admitted the vessel and armed that window's geometryvesselProxyEmbodiment, 3 vianativeVesselParkHandlersThe contract already concedes the split:
apps/workstationpasses all 7 refinement seams asisMain ? … : null, so aParticipationconstructed 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:
workspaceIdappears only as a threaded parameter (24×), with zero references to any workspace-set or state registry.The Fix
The engine constructs its own
Participationfrom 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 moreWorkspacemethods besideobserveWindowGeometry, 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 insideParticipation.mjs, the class that owns the seam, which stops being a null-shell and becomes self-sufficient.Workspacegains no net lines.The deletion this names, per
AGENTS.md §self_evolving_systemsAccretion Defense:apps/workstation/view/Workspace.mjsloses the ten engine-answerable seams from its 263-line bundle —createCrossWindowParticipationkeeps only the seven refinements, andrenderCrossWindowPreview/refreshCrossWindowParticipationreduce 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
Participation#clearPreviewcommitLocalcommitTransfergetDocumentgetForeignDocumenthitTestpreviewForpreviewToOperationsortGroupwindow/Participation.mjs:63–151(allnulltoday): nulldefaults, cited aboveParticipation#resolveNativeWindowDragwindow/Participation.mjs:123tearOutPanes/tearOutAdmissionsnullkeeps today's declineapps/workstationgates itisMain ? … : nullParticipation#{promote,restore,stage,await}DragEmbodiment,#{resume,retire,suspend}NativeWindowDragwindow/Participation.mjs:128–169null, stay host-ownedapps/workstationalready passes themnullfor non-maindock.WorkspaceDecision 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
regions=0 affordances=0.nullby default and remain host-owned; aParticipationbuilt without them degrades rather than throwing.src/dashboard/dock/Workspace.mjsgains no net lines. Measured before/after in the PR body, per the PR #18213 directive.RETIRED as mis-specified — it names the one host that structurally cannot satisfy it. The workstation's seams are closures capturingapps/workstation/view/Workspace.mjsloses 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.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.workspaceIdstays 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 publishingcrossWindowSortGroupand 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.Out of Scope
apps/workstation's.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.crossWindowSortGroupas a host config. It works today and the shipping consumer already supplies it.workspaceIdstays a threaded parameter.Avoided Traps
src/would relocate a demo's re-derivation into the engine — the exact inversion of #18151's thesis.dock.Workspacemethods, besideobserveWindowGeometry. It is the idiomatic-looking choice and it is what the PR #18213 directive forbids.regions=0as a consumer defect. It was read that way first. Three of the four participation functions have zero presence insrc/; the zero is architectural. Filing it as a consumer bug would have been the second false defect of that session.Related
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"