Skip to content

Keep Range endpoints owned by the creating document during Monaco layout #863

Description

@wieslawsoltes

Parent: #227
Release owner: SceneTech/AppScene#130
Related acceptance: #259

Reproduction

The exact packaged Code OSS release built from AppScene 15e30dedcaa7c6a0242c1929a8c8d6e47a1cc600, WebScene 5b97aac934dee450ec2b01291a004b246dc08364, and unchanged Code OSS 645f29cc3176500b4b5762ba887cf2a7f0ffdf2c reaches the workbench, renders a real editor edit, and completes an editor-worker request/reply. During Monaco layout it repeatedly reports:

WrongDocumentError: The selected node belongs to another document
  at _detachRange
  at _readClientRects
  at readHorizontalRanges
  at getVisibleRangesForRange

The failure is distinct from the browser extension-host MessagePort blocker in #81. It happens while Monaco reuses a DOM Range to measure visible text after document/realm activity.

Investigation

WebScene has focused Range boundary contracts, but current acceptance does not cover moving or reusing a Range when its endpoints come from different documents or after a document replacement. The exception proves that a Range object and at least one selected node have diverged in document ownership. The implementation must preserve browser-compatible ownership and atomic failure semantics without retaining replaced documents.

Proposed fix

  • Reduce the packaged trace to a native test using two documents/realms and Monaco's detach/select/measure sequence.
  • Keep each Range bound to its creating document; validate both endpoint nodes before mutating either endpoint.
  • Define browser-matched behavior for adopted/imported nodes and document replacement.
  • Ensure detach/reuse and getClientRects() cannot observe partially updated endpoints.
  • Release Range roots when documents, iframes, workers, or the engine tear down.

Gates

  • WPT/browser oracle for cross-document setStart, setEnd, selectNode, selectNodeContents, detach/reuse, adoption, and document replacement.
  • Native regression matching Monaco's _detachRange / _readClientRects sequence.
  • 10,000 measurement cycles with bounded live Range/root counts, no retained replaced document, and no new style/layout/scene publication beyond the requested measurement.
  • Exact packaged Code OSS run with zero WrongDocumentError, stable editor geometry, and Chromium/AppScene visual comparison.

Acceptance

  • Monaco layout no longer emits WrongDocumentError in the unchanged package.
  • Cross-document failures match browser exception names and leave prior endpoints unchanged.
  • Same-document range reuse remains allocation-bounded and does not add idle frames or retained documents.

Activity

  1. added
    bugSomething isn't working
    vscode-oss/plannedPlanned for the AppScene/WebScene VS Code OSS integration
    on Sep 20, 2026
  2. wieslawsoltes commented on Sep 20, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Exact-package follow-up (2026-09-20)

    The first fix in #866 correctly binds Document.createRange() to the receiver document and its focused cross-realm test passes. The exact Release package built from AppScene 52c3f302e3eb7cf3863da6f4d6b5338e5fd76853, WebScene e9e53c4edbcbab8c4d81f0c85491aa519ce7f077, and unchanged Code OSS 645f29cc3176500b4b5762ba887cf2a7f0ffdf2c still reports WrongDocumentError from Monaco _detachRange() / selectNodeContents().

    The package trace narrows the remaining case: WebScene tests Range membership by walking parent links to the document root. Monaco measures a node after detaching it, so connectivity is not document ownership. A detached node retains its ownerDocument in browsers and must remain selectable by a Range from that document.

    Follow-up implementation:

    • retain document identity for nodes independently of current tree connectivity;
    • bind nodes created by top-level, iframe, and detached Document receivers to the receiver document;
    • preserve identity while removing/reinserting a subtree and update it only for explicit adoption/import behavior;
    • use document identity for Range validation while continuing to reject nodes owned by a different document;
    • cover Monaco's connected → detached → selectNodeContents() → reinsert sequence and detached iframe/document cases.

    Exact evidence retained at artifacts/smoke-52c3f30-e9e53c4/native-smoke.json in the integration checkout. The same run proves extension iframe bootstrap, MessagePort transfer, Ready, and Initialized now succeed.

  3. wieslawsoltes commented on Sep 20, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Exact-package confirmation — 20 September 2026

    Release package inputs: AppScene 52c3f302e3eb7cf3863da6f4d6b5338e5fd76853, WebScene c356c5a3eda915cd114d444ca3dccaaa02c65816, unchanged Code OSS 645f29cc3176500b4b5762ba887cf2a7f0ffdf2c.

    The unchanged Monaco edit/render/Worker/undo path now completes with zero WrongDocumentError diagnostics. The same run proves editor Worker construction/request/reply and extension iframe/MessagePort Ready/Initialized. This confirms merged #869 fixes the never-connected document.createElement('div') Range endpoint used by Monaco while retaining cross-document rejection.

    Retained local evidence: artifacts/smoke-52c3f30-c356c5a/native-smoke.json and native-stderr.log.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingvscode-oss/plannedPlanned for the AppScene/WebScene VS Code OSS integration

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions