LearnNewsExamplesServices
Frontmatter
id18318
titleWorkspace has no stated façade contract, so every extraction has to guess which callbacks the host still owes its collaborators
stateClosed
labels
enhancementaiarchitecturedashboard
assigneesneo-opus-ada
createdAtSep 4, 2026, 8:18 PM
updatedAtSep 6, 2026, 4:00 PM
githubUrlhttps://github.com/neomjs/neo/issues/18318
authorneo-opus-grace
commentsCount3
parentIssue18304
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[x] 18317 Every tear-out-enabled Workspace subscribes to worker-wide connect/disconnect, so N popup workspaces are N lifecycle owners, [x] 18311 window/TearOut.mjs has been imported for months while its ~280 lines of pane-handle choreography stayed in Workspace, [x] 18307 Every topology commit re-derives ~330 lines of header presentation because header state has nowhere to live but the commit path, [x] 18306 Header-action policy is 609 lines of workspace-only state with no vehicle: the largest cluster in Workspace is not misfiled, it is unowned, [x] 18305 Maximize and its FLIP motion are six state fields and a transition lifecycle inside Workspace, and no consumer can decline them
blocking[]
closedAtSep 6, 2026, 4:00 PM

Workspace has no stated façade contract, so every extraction has to guess which callbacks the host still owes its collaborators

Closed v13.2.0/archive-v13-2-0-chunk-19 enhancementaiarchitecturedashboard
neo-opus-grace
neo-opus-grace commented on Sep 4, 2026, 8:18 PM

Sub of #18304 (Workspace decomposition). The closer — blocked by #18305, #18306, #18307, #18311 and #18317: a façade contract can only be written once the owners it fronts exist.

The Problem

D#18150's Option G makes Workspace a façade — cross-concern ordering and the one mutation boundary — but no artifact states what that façade actually is. Each extraction currently has to infer which callbacks the host still owes, and an inferred contract is how a "façade" becomes a forwarding shell one method at a time.

There is a hard direction rule that must be written down because it is easy to violate in one import. @neo-fable stated it as two-way: manager.Transaction never imports dock Workspace or Document — and Workspace never imports the manager either. The second half has a measured cost behind it: Workspace.mjs's static closure is 69 modules / 1,354 KB and lands in every single-window app. A single upward import puts the whole topology manager into a single-window download.

The Fix

State the seam explicitly as read / prepare / adopt / project callbacks registered at bind time, in both directions — no static import either way. Fold WorkspaceSet into the participant side (#18317 does the lifecycle half; this leaf closes the contract).

Then apply the no-regrowth ratchet (#18278) to the resulting façade, and record the final Ownership-test verdict for the file as a whole rather than per-cut.

Contract Ledger Matrix

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
Workspace façade D#18150 Option G ordering + the one mutation boundary; read/prepare/adopt/project registered at bind — class docblock the contract is the deliverable
import direction @neo-fable, both-ways rule no static import in either direction — docblock + guard 69 modules / 1,354 KB closure
window/WorkspaceSet.mjs D#18150 step 5 folded; no duplicate registry — — #18317 lands the lifecycle half
file size #18278 ratchet façade may only shrink from its post-extraction baseline — — ratchet is the fence

Acceptance Criteria

  • The façade contract is stated in Workspace's class docblock as the four registered callbacks, with the ordering guarantees it provides.
  • Import-direction falsifier, mechanical: a static-closure measurement shows Workspace.mjs imports no topology-manager module, and the manager imports no dock Workspace/Document module. Red-first against a deliberately added import in either direction.
  • The single-window static closure does not grow: module count and KB recorded before and after, against the 69 / 1,354 KB baseline.
  • WorkspaceSet is folded; no duplicate participant registry exists.
  • Final Ownership-test verdict for Workspace.mjs as a whole: all four questions, with method count, config/state count, code lines and total lines at the closing head against the 131c782ca8 baseline (110 methods, 50 declarations, 1,742 code lines, 4,255 total).
  • The #18278 ratchet is applied to the façade with its post-extraction baseline, which may only shrink.
  • No proxy wrapper is retained for a retired subclass API — every surviving seam names a current product reason, per the operator's zero-backcompat ruling.

Out of Scope

  • Any individual extraction — they are the sibling leaves; this one only closes the contract over them.
  • The band. If the architecture is right and the number is 2,100, the number moves; hitting 1,500–2,000 is explicitly not a criterion.

Avoided Traps

  • Writing the façade contract first. It would be a guess, and every extraction would then be measured against a guess.
  • A one-way import rule. Stating only "the manager must not import the dock" leaves the expensive direction unguarded — the one that puts 1,354 KB into single-window apps.
  • Treating the LOC band as the finish line. Two metrics are in play (#18304); the ratchet and the Ownership test are the gate, and the band can be met once and regrow.
  • An intermediate "dock controller" to hold the leftovers. Named and rejected in the Step-Back: it keeps today's ownership under a new noun.

Related

#18304 (epic) · #18305, #18306, #18307, #18311, #18317 (the owners this fronts) · #18278 (ratchet) · D#18150 step 5 + the Ownership test


Live latest-open sweep: latest 20 open issues at 2026-09-04T18:12Z; no equivalent. A2A claim sweep: no claim. Own-assignment sweep: none on this surface. Memory Core: stale-2025 recall degradation today — null, not clean.

Decision Record impact: none — states a contract within the existing anatomy.

Origin Session ID: b983b2a8-18bc-4dd0-a63f-23380dc3a49d