Skip to content

fix(plugin): refresh newly created files during delegated resolution - #88

Merged
steipete merged 4 commits into
mainfrom
fix/plugin-delegated-dircache
Oct 3, 2026
Merged

steipete merged 4 commits into
mainfrom
fix/plugin-delegated-dircache

Conversation

@steipete

@steipete steipete commented Oct 3, 2026 •

Copy link
Copy Markdown

A runtime Bun.plugin callback can create a package file and return undefined, yet delegated resolution still reports MODULE_NOT_FOUND because the directory was cached before that file existed. This fixes first-use package-import captures, including computed require/import, static dependencies, newly created directories, directory indexes, and extension candidates.

Plugin registration records a per-resolver capability. The existing NotFound arm retries nonfatal misses once using the filesystem refresh policy already used by module.registerHooks(). A scoped guard restores that policy, and recovered results go through normal finalization. Directory entry and descriptor lookups use the same locked snapshot and release the lock before refreshing. The compatibility note and append-only changelog describe the behavior.

Validation uses matched release/LTO builds of base 45ad44f68a and this change on one AWS c7a.24xlarge host (Ubuntu 26.04.1), with Node 24.21.0 as the filesystem oracle. All consumer runs isolate HOME, state, and temporary directories.

  • All 12 new regression cases fail on base and pass with this change; the full plugin test file passes 62/62.
  • The resolver folder has identical results on both binaries: 549 passed, 5 inherited failures, 4 skips, 3 todos. Failures cover a builtin package-import alias, three legacy CJS/ESM expectations, and a release-only internal-module import.
  • rust:check-all: 2 configured targets pass, 10 skip for missing installed target libraries. Required independent Codex branch review is scoped-clean through P2.
  • The raw filesystem controls are main 4/10, patched 8/10, Node 10/10. Every hook-enabled control passes patched; the two no-hook late-file cases retain existing behavior.

OpenClaw consumer proof uses the capture-adapter candidate on a45979ee0f763, including all original 44 conditions plus retained-target and first-use wildcard cases:

Runtime Conditions Interop Lazy alias
Patched Bun 48/48 56/56 24/24
Fork main 47/48 56/56 24/24
Node 24.21 46/48 56/56 24/24

Node's two failures are confined to the added consumer first-use fixtures; the original 44 and retention controls pass, and its standalone filesystem oracle passes 10/10.

Thirty interleaved rounds per runtime/mode, cold processes, isolated state, warm OS cache; each sample loads all 88 entries with 88 native hits and zero forced/fallback transforms. Extra-hook Bun samples each execute 126,175 delegating callbacks. Baseline and patched exports match. loadMs is the primary metric; intervals use 10,000 paired bootstrap samples (seed 73).

Cold-load mode Main median (ms) Patched median (ms) Median change Main p95 (ms) Patched p95 (ms) Paired 95% change interval Observed noise
Normal application registration 3341.852486 3342.081085 +0.006840% 3366.287978 3353.513436 [-0.295263%, +0.245032%] 0.445500%
Extra delegating Bun.plugin 3398.284136 3396.846019 -0.042319% 3418.232931 3420.489032 [-0.214147%, +0.165836%] 0.515518%

The separately measured no-hooks control makes zero calls to Bun.plugin or registerHooks. Thirty paired processes each resolve 10,000 existing paths and 1,000 missing paths:

No-hook control Main median (ms) Patched median (ms) Median change Main p95 (ms) Patched p95 (ms) Paired 95% change interval Observed noise
10,000 hits 15.722415 15.600769 -0.773711% 16.033189 15.750746 [-1.619336%, -0.579998%] 1.194098%
1,000 misses 3.639758 3.647788 +0.220619% 3.692779 3.757620 [-0.647839%, +0.975107%] 1.308081%

The accepted cold median ceiling is +0.5%; the no-hooks criterion remains no measurable slowdown within the paired interval. Both pass, and both cold modes also pass the earlier conservative all-metric checker. Noise is min(5%,2*MAD(main)/median(main)). Node cold medians are 5092.905132ms (normal) and 5077.791885ms (extra-hook control).

Performance and consumer measurements use the matched 45ad44f68a base and 04f6fde48c candidate. The final rebase onto stack-formatting fix #92 leaves both resolver source files and this regression test file byte-identical; final-head review and CI validate the rebased integration.

Final head 93f9f76261de8f6a74772a2cca07e804e13864c8 has a scoped-clean P2 branch review. Native CI run 37119871754 passed both Linux x64 and Darwin arm64 on this exact head.

Upstream oven-sh/bun#40279 remains open and tracks negative filesystem facts across runtime/build/watch resolution, including directory and package-metadata changes. This patch reuses the fork's existing mutable-directory policy only after a runtime plugin resolution miss. No duplicate upstream PR is needed.

@steipete
steipete force-pushed the fix/plugin-delegated-dircache branch 3 times, most recently from 2672f99 to 04f6fde Compare October 3, 2026 11:10
Enable the existing runtime mutable-directory policy when runtime plugin hooks are registered, matching registerHooks missing-file recovery. Cover delegated require/import and onLoad-only registration with late-created package-import targets.
Retry unresolved plugin lookups once with the existing mutable-directory policy and restore it afterward. Refresh newly created directory indexes under the entries lock. Cover cached directory indexes, static dependencies in missing directories, and genuine unresolved targets.
Keep entry and directory descriptor lookups together across refreshes. Cover TypeScript targets selected by package imports and package main, plus wildcard extension inference.
@steipete
steipete force-pushed the fix/plugin-delegated-dircache branch from 04f6fde to 93f9f76 Compare October 3, 2026 11:30
@steipete
steipete marked this pull request as ready for review October 3, 2026 11:48
@steipete
steipete merged commit ec4debf into main Oct 3, 2026
11 checks passed
@steipete
steipete deleted the fix/plugin-delegated-dircache branch October 3, 2026 11:48
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