Skip to content

fix(module): retain origin for detached import.meta.resolve - #116

Merged
steipete merged 8 commits into
mainfrom
claude/fix-detached-import-meta-resolve
Oct 5, 2026
Merged

steipete merged 8 commits into
mainfrom
claude/fix-detached-import-meta-resolve

Conversation

@steipete

@steipete steipete commented Oct 5, 2026 •

Copy link
Copy Markdown

Detached import.meta.resolve must keep the originating module's resolution base. Bind the resolver on first access, preserve its writable data-property behavior, and keep explicit parent arguments working. A foreign receiver cannot change its origin. The resolve-once loader from oven-sh#44473 remains unchanged.

Coverage includes detached calls, descriptors, replacement, freeze, seal, preventExtensions and foreign receivers. The generic WebKit integrity path materializes the custom value before applying integrity attributes; native controls confirm that freezing or sealing cannot be undone by first access. The canonical before/after resolver control improves from 49 pass / 5 fail to 54 pass / 0 fail.

Reviewed head 957df2767fbe0836645ab48ad2fa8c0040a048f6 includes current main 2518a31b3b995e3af82832add3e503a2e69c0e73. This refresh preserves the implementation and regression blobs and appends the owned changelog entry after the exact main prefix. The original implementation and authorship are Peter Steinberger's.

The exact macOS arm64 release binary, with the pinned f1e engine, passes its 4 own rows and all 57 surrounding module/resolver/plugin rows. P2 autoreview, formatting, source lints and JavaScript lint pass.

The frozen broader Mac selection completes 46/47 rows. Its sole failing file retains the two reconnect assertions with additional ECONNRESET events. A verified binary whose tree equals current main reproduces the same two assertions using identical test and harness sources (135 pass / 12 existing skips / 2 fail). The HTTP row and the newly merged VM guard pass in the refreshed aggregate. This is baseline comparison evidence, not a 47/47 success claim. No assertions, skips or deadlines changed.

An earlier preparation (ab20de1c) also failed the HTTP TCP body-to-come assertion at node-http.test.ts:3866, expecting closed: true and receiving false after 10.038 seconds. The matching base-tree binary independently reproduced it after 10.043 seconds; unchanged candidate isolation passed. The original 45/47 aggregate and both controls remain retained as historical evidence.

Final exact-head CI qualification:

  • Fork CI passes Linux x64 17/17 and Darwin arm64 13/13 on the first attempt. Its merge tree 30667d3634078d349c4c98587b70d0ec59a32941 equals the reviewed head tree.
  • Windows qualification passes both builds, unsigned packaging and both native smoke tests. ARM64 passes 31/31 rows. The frozen test-only workflow builds this PR's exact source SHA; architecture, executable identity and all 30 selected test/harness hashes are verified for each architecture. Executable SHA-256: x64 4b5cb9136129038795fbaa433d0a4d5439d705ca01b70bc450472d7bbefedfae; ARM64 a3120166380d70c46af82da4b5d4339806e40156a28a3cd059fd7219a3aeda7b. Signing and publication are disabled.
  • Windows x64 reports 30/31 rows. Its sole failed result row is test/js/node/module/node-module-module.test.js; the resolver's own files and every other selected row pass. Manifest assembly is skipped because that compatibility job reports failure.

Named Windows intermittent: run 37386790583, x64 job 112026689208, node-module-module > compile cache wakes an idle loop for deferred modules. The unchanged test must complete within 30,000 ms; it timed out at 30,001.35 ms, followed by cleanup of one dangling child. The file reports 204 pass, 4 existing skips, 1 todo and 1 fail. The full log also retains the preliminary parallel batch's natural-exit cache timeout at 31,476.47 ms and its delayed cleanup assertion (expected flushed, received an empty string); the runner's standard serial fallback produced the final idle-test failure above.

This post-#130 recurrence is recorded under the known-intermittent landing policy. The policy does not waive any of #116's own rows. No rerun is used as qualification, and no assertion, skip or deadline changed. The earlier exact-source preparation passed both Windows architectures: ab20de1c to this head changes only #131's VM test, CI notes and changelog, with no production changes and identical selected Windows test/harness hashes. Recurrence diagnosis remains a separate follow-up; a passing rerun would not establish its cause.

Historical Darwin watch failure, retained explicitly: run 37356789711, original Darwin job at head 4a9a85a8b0367cc4e747daa796003acc905eccfd passed the resolver's own rows and all other selected rows, but failed test/js/node/watch/fs.watch.rewrite.test.ts:94. The assertion expect(seen.some(p => p.startsWith("a/"))).toBe(false) expected false and received true; the runner also reported ENOTEMPTY during temporary-directory cleanup. The same unchanged row independently failed on #131, while #120 had passed it. The known-failure policy permits this single row only when all own and other selected CI rows pass. No assertion, skip, or deadline was changed. The passing unchanged-head retry is retained as an observation and is not the qualification basis.

The separate watcher comparison reproduces the same failure class on official upstream Bun 1.4.3 (13a98b0dbd136bcc5c98a8adfb53c909aa3183cc): 3/80 upstream trials and 4/80 fork trials, versus 0/80 Node 24 trials on the same Mac. Every failure contains a late a/seed.txt and the correct b/inside.txt, with no a/inside.txt. The FSEvents source and maintained test are byte-identical; directory callback code is identical. These are independent reproduced traces, not invented traces of the original CI process. This establishes upstream-equivalent behavior, not a deterministic fix or Node immunity. The watcher implementation and test remain unchanged.

Original implementation and historical Windows/OpenClaw consumer evidence

Copying import.meta.resolve into a local variable currently throws because the resolver reads its call receiver's path. Give each import-meta object a lazy resolver bound to its originating module, matching Node's detached-call behavior and function metadata. Preserve explicit-parent resolution and writable/configurable resolver properties.

The regression covers detached calls, call/apply/bind, foreign receivers, visible-path mutation, function name/length, property descriptors, independent module origins, explicit parents, and resolve hooks. Node 24 controls pass; unmodified Bun reproduces the binding failures. P2 review is scoped-clean and scoped formatting passes.

Native Windows Server 2022 x64 proof used matched source and verified binaries: the resolver runner improved from 37/42 test files passing on fork main d2d2a26ef973cdd97b37953f5dba58052acad74f to 42/42 passing, with both dependency-install steps also successful. The passing executable was built from local integration 03aa23b6adea8e12235339d8650cae41fa1ea80d (tree 1c5084c96b361801cd9f595795774ec41e81e250), combining four independent fixes. This branch's production and test files are byte-identical in that integration. Executable SHA-256: cbd65560d2f8651dc82722d1d957803651e2803f0a1a66ae039b946d3b53b156.

Node24 portable and freeze/seal/preventExtensions/foreign-receiver controls pass. Upstream searches found no matching detached-binding fix.

Exact-head fork CI passes both required lanes: Linux x64 (15/15 selected and compatibility test files) and macOS arm64 (11/11); both dependency-install steps also pass in each lane. Native Windows proof is recorded above because this PR workflow has no Windows test lane.

Final native Windows proof uses local integration 9a2e4b08f3b3f2e17e05a23c35aeade9c6da06f3, executable SHA-256 19453c39dbb599eff57c1544a1c117dbc7bde7947ba2d41c9829cee9f20b10e0. The maintained module selection passes 2/2 files, the resolver selection 42/42, and broad compatibility 29/29; each run also passes both install steps. Source and executable guards pass before and after. Both Node 24 and the fork pass the complete 12-step installed OpenClaw path, including real update, foreground Gateway, plugins, a verified mock-provider turn, sustained readiness and Doctor. Foreground cleanup uses taskkill. No Windows build is published or signed.

The full 186-file/32-envelope comparison on identical OpenClaw deb44a7f20b774769104ab4262c8ada438d4fc8e reports all 3,184 assertions on each runtime: Node 2,896 pass / 13 fail / 275 skip (30 successful envelope exits), fork 2,891 pass / 16 fail / 277 skip (29 successful exits), with no missing reports, unhandled errors or suite failures. The three extra fork failures are shared Windows path limits reproduced with equal-length Node/fork/stock controls; the raw totals are preserved. All three shared timing failures pass isolated on Node and fork under unchanged deadlines (92 pass / 5 skip each). Runtime-specific conditional skips remain explicit. The original d2d2 runtime also passes the six-file/two-envelope OpenClaw consumer control (220 pass / 3 skip); these selected consumers provide non-regression evidence. The installed-update proof separately exercises the native-addon failure.

The three affected OpenClaw fixture files are fully revalidated on Node 24 and the fork: frozen before deb44a7f20b774769104ab4262c8ada438d4fc8e gives 40 pass / 13 fail / 3 skip on each; the corrected private fixture commit 96222ca4829457295a7fa3b00324b9d96b989291 and exact public head 343017e1202b579274fe87d51f6491ba8eeeeee4 each give 53 pass / 3 existing skips on both runtimes. All 56 cases are accounted for, every one of the 13 before-failures now explicitly passes, and the skip set is unchanged. This is complete three-file before/after and public-head proof, not a rerun of the full 32-envelope matrices. The verified public proof archive SHA-256 is 504d7ef2308d3c0a48d4b26135c233cdc720e8dc10c6e6061ddbe4d79e0c9f7a. The fixture correction openclaw/openclaw#165577 was merged from that exact tested public head as 8bc338dbed0ddf5c35b2178eb624ffc88ccef7e7. Its inherited-CI exception is recorded on the OpenClaw PR; no CI rerun or tested-head change was used for this proof.

@steipete
steipete merged commit 8ae8f41 into main Oct 5, 2026
7 checks passed
@steipete
steipete deleted the claude/fix-detached-import-meta-resolve branch October 5, 2026 23:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant