Context
Surfaced as a non-blocking Depth-Floor note in @neo-fable's terminal review of PR #16403 (pullrequestreview-4839791143): the two tour-reset call sites of Workspace.refreshDockWorkspace declare geometryOnly: true over what can be a topology change. Harmless at PR head — her walk verified the landed-in-place guards keep it so — but the flag's name now promises more than those callers deliver, and the promise became load-bearing the moment a consumer started trusting it.
The Problem
apps/workstation/view/Workspace.mjs:2286 (runTourSpec) and :2433 (tour start) both reset me.dockModel = DockZoneModel.clone(initialDocument) and immediately call refreshDockWorkspace({geometryOnly: true}). A reset to the initial document is only geometry-only if the current layout still shares the initial topology. After structural divergence — tear-outs, splits, converts during a session — the reset is a topology change wearing a stable-topology declaration.
Until PR #16403 the flag was an internal projection hint. Since that PR, geometryOnly is passed straight into DockFlip.play({geometryOnly}) and gates the landed-in-place bypass: the consumer's declaration is taken as certain knowledge that no node replacement can be pending. The current guards (hasLandedInPlace requires an exact, lineage-unchanged marker set) absorb a false declaration by accident of their own strictness, not by contract — the next consumer of the flag may not be so conservative.
The Architectural Reality
Workspace.refreshDockWorkspace({geometryOnly=false, ...}) (apps/workstation/view/Workspace.mjs:2065): geometryOnly = geometryOnly || operation === 'resizeSplit' — the resizeSplit derivation is certain (the semantic op cannot replace nodes); the two tour-reset literals are asserted.
DockFlip.play({geometryOnly}) JSDoc (post-#16403) states the contract plainly: "consumer-declared geometry-only projection: no topology swap can be pending." The tour-reset callers do not check that premise before declaring it.
- The safe-degradation shape today: a false declaration only activates the discriminator when the marker set is exact, lineage-unchanged, and geometry-moved — a state in which skipping stage A is correct anyway. The exposure is forward-looking: any future branch keyed on the flag (or a relaxed discriminator) inherits the unverified premise.
The Fix
Reconcile the declaration with reality — implementation chooses, with the trade named:
- Compute, don't assert (preferred if cheap): inside the tour-reset paths, derive the flag from a topology compare of
me.dockModel vs initialDocument before refresh (the dockZone.v1 diff vocabulary from #14650 already names the six mutation categories; a moves/adds/removes/tabReorders-empty diff IS topology-stable). The declaration becomes proof.
- Rename to the real contract: if (1) is not cheap, rename the flag to what callers actually assert — e.g.
stableTopology with JSDoc stating the caller's obligation — so geometryOnly ceases to over-promise at both layers (refreshDockWorkspace and DockFlip.play).
Either way, the two tour-reset sites end up honest: verified or renamed.
Contract Ledger
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
Workspace.refreshDockWorkspace options.geometryOnly |
apps/workstation/view/Workspace.mjs:2065 |
Callers either compute the declaration from a document topology diff or pass a renamed flag carrying the caller-obligation contract |
operation === 'resizeSplit' derivation stays certain and untouched |
JSDoc at the option |
runTourSpec + tour-start diff receipts |
DockFlip.play options.geometryOnly |
src/main/addon/DockFlip.mjs play() JSDoc |
Same rename (if chosen) propagates; the "no topology swap can be pending" contract is either guaranteed upstream or spelled as caller obligation |
Current geometry guards (hasLandedInPlace) stay as the second line regardless |
play() JSDoc |
unit/dashboard/DockFlip.spec.mjs pin set stays green |
Decision Record impact
none
Acceptance Criteria
Out of Scope
- Re-opening the #16391 landed-in-place discriminator itself (merged shape stands)
- The tab-drag header-over-content defect (#16406 — separate surface, separate lane)
- Tour script content or timing
Related
- #16391 + PR #16403 (the landed-in-place consumer that made the flag load-bearing) · #14650 (the
dockZone.v1 diff vocabulary option 1 reuses) · #16406 (sibling DockFlip-family defect)
Live latest-open sweep: checked latest 20 open issues at 2026-08-02T21:58Z; no equivalent found. A2A in-flight sweep: no claim on this scope in the last 60 min. KB semantic sweep: no equivalent.
Origin Session ID: 0b6854a1-2b0f-457a-8a16-2e8f9d0983c8
Retrieval Hint: "geometryOnly stable topology declaration tour reset DockFlip landed-in-place flag contract"
Context
Surfaced as a non-blocking Depth-Floor note in @neo-fable's terminal review of PR #16403 (pullrequestreview-4839791143): the two tour-reset call sites of
Workspace.refreshDockWorkspacedeclaregeometryOnly: trueover what can be a topology change. Harmless at PR head — her walk verified the landed-in-place guards keep it so — but the flag's name now promises more than those callers deliver, and the promise became load-bearing the moment a consumer started trusting it.The Problem
apps/workstation/view/Workspace.mjs:2286(runTourSpec) and:2433(tour start) both resetme.dockModel = DockZoneModel.clone(initialDocument)and immediately callrefreshDockWorkspace({geometryOnly: true}). A reset to the initial document is only geometry-only if the current layout still shares the initial topology. After structural divergence — tear-outs, splits, converts during a session — the reset is a topology change wearing a stable-topology declaration.Until PR #16403 the flag was an internal projection hint. Since that PR,
geometryOnlyis passed straight intoDockFlip.play({geometryOnly})and gates the landed-in-place bypass: the consumer's declaration is taken as certain knowledge that no node replacement can be pending. The current guards (hasLandedInPlacerequires an exact, lineage-unchanged marker set) absorb a false declaration by accident of their own strictness, not by contract — the next consumer of the flag may not be so conservative.The Architectural Reality
Workspace.refreshDockWorkspace({geometryOnly=false, ...})(apps/workstation/view/Workspace.mjs:2065):geometryOnly = geometryOnly || operation === 'resizeSplit'— theresizeSplitderivation is certain (the semantic op cannot replace nodes); the two tour-reset literals are asserted.DockFlip.play({geometryOnly})JSDoc (post-#16403) states the contract plainly: "consumer-declared geometry-only projection: no topology swap can be pending." The tour-reset callers do not check that premise before declaring it.The Fix
Reconcile the declaration with reality — implementation chooses, with the trade named:
me.dockModelvsinitialDocumentbefore refresh (thedockZone.v1diff vocabulary from #14650 already names the six mutation categories; amoves/adds/removes/tabReorders-empty diff IS topology-stable). The declaration becomes proof.stableTopologywith JSDoc stating the caller's obligation — sogeometryOnlyceases to over-promise at both layers (refreshDockWorkspaceandDockFlip.play).Either way, the two tour-reset sites end up honest: verified or renamed.
Contract Ledger
Workspace.refreshDockWorkspaceoptions.geometryOnlyapps/workstation/view/Workspace.mjs:2065operation === 'resizeSplit'derivation stays certain and untouchedrunTourSpec+ tour-start diff receiptsDockFlip.playoptions.geometryOnlysrc/main/addon/DockFlip.mjsplay()JSDochasLandedInPlace) stay as the second line regardlessunit/dashboard/DockFlip.spec.mjspin set stays greenDecision Record impact
none
Acceptance Criteria
geometryOnly: true— the flag is computed from a topology compare, or the renamed flag + caller-obligation JSDoc is in place at both layersresizeSplitderivation path is bit-identical in behavior (theWorkstationDockFlipResizeNLwitness stays green, ≤34ms assertion intact)unit/dashboard/DockFlip.spec.mjspin set green (the truth-table pins from #16391 survive whichever option lands)Out of Scope
Related
dockZone.v1diff vocabulary option 1 reuses) · #16406 (sibling DockFlip-family defect)Live latest-open sweep: checked latest 20 open issues at 2026-08-02T21:58Z; no equivalent found. A2A in-flight sweep: no claim on this scope in the last 60 min. KB semantic sweep: no equivalent.
Origin Session ID: 0b6854a1-2b0f-457a-8a16-2e8f9d0983c8
Retrieval Hint: "geometryOnly stable topology declaration tour reset DockFlip landed-in-place flag contract"