Context
The remaining extension question on #18304 names WorkspaceSet as a bounded candidate. Its parent record already rejects a registered wrapper that copies factory descriptors after class setup: registration succeeds while the copied method shadows the configured override.
The Problem
At dev@5c75b2d666, src/dashboard/dock/window/WorkspaceSet.mjs still exports createDockWorkspaceSet, returning an object whose methods close over manager and Group resolvers. A direct probe against the identical source blob 47880b2eb98ae24eaeaefc63ce44ed1c917041a9 produced:
factory namespace: null; configured has override: not reached
registered Base control namespace: present; configured has override: reached
Workstation and Demo-B each construct this adapter. Popups borrow the root's adapter. A class conversion introduces a real instance lifetime: neither creating consumer currently destroys this plain object.
The Architectural Reality
Neo.setupClass applies overwrites to the prototype; core.Base.destroy unregisters the instance and clears its own fields. window/VesselPark.mjs is the neighbouring registered-owner precedent. Group participant membership belongs to manager.Transaction, not to this adapter. Registration callbacks may outlive the adapter that created them.
The Fix
Convert the existing module to Neo.dashboard.dock.window.WorkspaceSet extends Neo.core.Base, default-exported through Neo.setupClass. Put the actual operations on the prototype. Replace the factory imports and calls in both production constructors and existing tests. The creating consumers destroy their adapter; borrowed popup references do not.
Keep Group participant callbacks bound to their registration context so clearing adapter fields cannot break retained capture, preparation, adoption, compensation or projection. Preserve current membership, validation, queue-head reduction and write receipts.
Contract Ledger Matrix
| Target surface |
Source of authority |
Proposed behavior |
Fallback |
Docs |
Evidence |
| Module construction |
WorkspaceSet.mjs#createDockWorkspaceSet; Neo.setupClass |
Default registered class, created through Neo with manager/getGroupId/documentModel |
No compatibility factory |
Class/config JSDoc |
Namespace plus effective overwrite/subclass dispatch |
| Existing methods and size |
Current WorkspaceSet implementation |
Same arguments/results; real prototype dispatch |
Existing unbound/refusal behavior |
Method JSDoc |
Existing membership, compensation and transaction suites |
| Adapter destruction |
core.Base.destroy; creator teardown in Workstation/Demo-B |
Release adapter instance only; creator owns teardown |
No implicit participant retirement |
Lifetime JSDoc |
Instance released; retained participants remain usable |
| Registered participant callbacks |
WorkspaceSet.register; Group participant lifetime |
Retain their registration dependencies independently of adapter fields |
Existing validation/refusal behavior |
Registration JSDoc |
Queued and later writes after adapter destruction, including projection |
Decision Record impact
Aligned with ADR 0029 §2.1: windows remain render targets, membership remains worker-owned. No schema, Group or transaction protocol amendment. This is a leaf of the already-graduated ownership direction on #18304.
Acceptance Criteria
Out of Scope
TearOut conversion, additional consumer decomposition, #18448's multi-step pin repair, changed transaction semantics, new persisted state, and guide authoring.
Avoided Traps
- A namespace-only wrapper is a false green; the prototype must own the executed methods.
- Destroying the adapter must not retire the Group or borrowed participants.
- Do not bind retained callbacks to fields that Base destruction clears.
- Do not preserve an unused factory for compatibility or introduce another manager.
Related
Parent: #18304. Registered-owner precedent: #18399. Adjacent active repair: #18448.
Live latest-open and all-state A2A sweeps ran immediately before creation; no equivalent or overlapping current claim. Own-assignment bodies #16498 and #17540 cover film acceptance and deferred guides, not this adapter. The final MC sweep recovered memory fdabb0ab-56ea-468c-94c4-66d037c4d94c: the same factory/overwrite counterexample, the descriptor-copy false green and the new Base lifetime obligation were already recorded on the parent. Earlier broader queries returned irrelevant initialization records. KB returned older docking vocabulary and was not treated as current implementation authority. Structure-map command is unavailable in this Engine checkout (silent exit 1); placement stays in the existing module.
Origin Session ID: 153d2e0a-ebae-4087-bcd5-3c92d213132c
Retrieval Hint: WorkspaceSet prototype override dispatch retained Group participant callbacks adapter destruction
Context
The remaining extension question on #18304 names
WorkspaceSetas a bounded candidate. Its parent record already rejects a registered wrapper that copies factory descriptors after class setup: registration succeeds while the copied method shadows the configured override.The Problem
At
dev@5c75b2d666,src/dashboard/dock/window/WorkspaceSet.mjsstill exportscreateDockWorkspaceSet, returning an object whose methods close over manager and Group resolvers. A direct probe against the identical source blob47880b2eb98ae24eaeaefc63ce44ed1c917041a9produced:Workstation and Demo-B each construct this adapter. Popups borrow the root's adapter. A class conversion introduces a real instance lifetime: neither creating consumer currently destroys this plain object.
The Architectural Reality
Neo.setupClassapplies overwrites to the prototype;core.Base.destroyunregisters the instance and clears its own fields.window/VesselPark.mjsis the neighbouring registered-owner precedent. Group participant membership belongs tomanager.Transaction, not to this adapter. Registration callbacks may outlive the adapter that created them.The Fix
Convert the existing module to
Neo.dashboard.dock.window.WorkspaceSet extends Neo.core.Base, default-exported throughNeo.setupClass. Put the actual operations on the prototype. Replace the factory imports and calls in both production constructors and existing tests. The creating consumers destroy their adapter; borrowed popup references do not.Keep Group participant callbacks bound to their registration context so clearing adapter fields cannot break retained capture, preparation, adoption, compensation or projection. Preserve current membership, validation, queue-head reduction and write receipts.
Contract Ledger Matrix
WorkspaceSet.mjs#createDockWorkspaceSet;Neo.setupClasscore.Base.destroy; creator teardown in Workstation/Demo-BWorkspaceSet.register; Group participant lifetimeDecision Record impact
Aligned with ADR 0029 §2.1: windows remain render targets, membership remains worker-owned. No schema, Group or transaction protocol amendment. This is a leaf of the already-graduated ownership direction on #18304.
Acceptance Criteria
Out of Scope
TearOut conversion, additional consumer decomposition,
#18448's multi-step pin repair, changed transaction semantics, new persisted state, and guide authoring.Avoided Traps
Related
Parent: #18304. Registered-owner precedent: #18399. Adjacent active repair: #18448.
Live latest-open and all-state A2A sweeps ran immediately before creation; no equivalent or overlapping current claim. Own-assignment bodies
#16498and#17540cover film acceptance and deferred guides, not this adapter. The final MC sweep recovered memory fdabb0ab-56ea-468c-94c4-66d037c4d94c: the same factory/overwrite counterexample, the descriptor-copy false green and the new Base lifetime obligation were already recorded on the parent. Earlier broader queries returned irrelevant initialization records. KB returned older docking vocabulary and was not treated as current implementation authority. Structure-map command is unavailable in this Engine checkout (silent exit 1); placement stays in the existing module.Origin Session ID: 153d2e0a-ebae-4087-bcd5-3c92d213132c
Retrieval Hint:
WorkspaceSet prototype override dispatch retained Group participant callbacks adapter destruction