Просмотр исходного кода

fix(app-boot): align remaining runtime resolution edges

imccyu 1 месяц назад
Родитель
Сommit
0d4b097375

+ 2 - 2
.agents/notes/implemented/architecture/2026-09-09-profile-resolution-generations.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-09-09-profile-resolution-generations.md
-2026-09-09-profile-resolution-generations.md: 39c64bd50d5dd3856233d24cf37ca874c54d6b2c
-2026-09-09-profile-resolution-generations.zh.md: 55fb5af8c16d8c713b983991cd5d26e929730a7a
+2026-09-09-profile-resolution-generations.md: b840f5dbd32dfe026580201d11a5e9e7013c1a23
+2026-09-09-profile-resolution-generations.zh.md: 1f4ba585efe99673a520fe2d74e23027ca921f46

+ 1 - 1
.agents/notes/implemented/architecture/2026-09-09-profile-resolution-generations.md

@@ -36,7 +36,7 @@ The launcher constructs one startup generation. The service accepts an additive
 
 The resolver uses `node-addon-require-builtin` to read `internal/modules/esm/loader` and `internal/modules/cjs/loader`. The ESM adapter wraps the per-thread singleton `CascadedLoader` resolve methods. The CommonJS adapter wraps the internal builtin's `Module._resolveFilename`; that `Module` is the same object exported by `node:module`.
 
-Both adapters call one routing function. It ignores builtins, relative or absolute paths, URLs, parents outside the profile scope, and explicit calls outside the supported lookup. A `#imports` request first uses Node's mapping and, when its external bare target is absent from disk, routes that target through the generation with the same conditions. For a scoped bare request, a package self-reference keeps the original parent even when an npm alias gives its installed directory another name. A profile-local or plugin-private package also keeps the original parent when Node resolves the requested entry before the virtual shared-fallback position; a CommonJS package directory without `exports` does not suppress the fallback when only its requested subpath is absent. Otherwise the router uses a generation hit through that entry's declaring anchor or continues native lookup after the virtual fallback. Explicit CommonJS path lists apply the same insertion rule independently to each path in caller order.
+Both adapters call one routing function. It ignores builtins, relative or absolute paths, URLs, parents outside the profile scope, and explicit calls outside the supported lookup. A `#imports` request uses Node's mapping from its owning manifest; an external bare target follows the same local, generation, and after-fallback package order with the request's conditions, while Node retains exact target resolution. For a scoped bare request, a package self-reference keeps the original parent even when an npm alias gives its installed directory another name. A profile-local or plugin-private package also keeps the original parent when Node resolves the requested entry before the virtual shared-fallback position; a CommonJS package directory without `exports` does not suppress the fallback when only its requested subpath is absent. Otherwise the router uses a generation hit through that entry's declaring anchor or continues native lookup after the virtual fallback. Explicit CommonJS path lists apply the same insertion rule independently to each path in caller order.
 
 The adapters call the captured native resolver after routing. Node remains responsible for exports, import and require conditions, main files, subpaths, extensions, native caches, and error codes. Routed ESM failures replace the internal lookup anchor in Node's diagnostic with the original importer. A selected package's invalid export or missing target does not trigger another same-name candidate. CommonJS does not replace `_findPath` or reproduce `_resolveFilename`.
 

+ 1 - 1
.agents/notes/implemented/architecture/2026-09-09-profile-resolution-generations.zh.md

@@ -36,7 +36,7 @@ launcher 只构造启动 generation。服务接受新增型后继 generation,
 
 resolver 使用 `node-addon-require-builtin` 读取 `internal/modules/esm/loader` 和 `internal/modules/cjs/loader`。ESM 适配器包装每线程单例 `CascadedLoader` 的 resolve 方法。CommonJS 适配器包装内部 builtin 导出的 `Module._resolveFilename`;该 `Module` 与 `node:module` 导出的对象相同。
 
-两个适配器调用同一个路由函数。builtin、相对或绝对路径、URL、profile 作用域外 parent 和支持的查找以外的显式调用都直接委托原生实现。`#imports` 请求会先使用 Node 的映射;当映射到的外部 bare target 不在磁盘上时,解析器使用相同 conditions 让该 target 经过 generation。对于作用域内的 bare request,package self-reference 保留原 parent,即使 npm alias 使安装目录使用另一个名称。Node 能在虚拟共享 fallback 之前从 profile 本地包或插件私有包解析到所请求入口时,也保留原 parent;没有 `exports` 的 CommonJS 包目录仅缺少所请求 subpath 时,不会压过 fallback。其他请求在 generation 命中时通过该条目的声明锚点解析,未命中时从虚拟 fallback 之后继续原生查找。显式 CommonJS path 列表按调用方顺序,对每个 path 独立应用相同的插入规则。
+两个适配器调用同一个路由函数。builtin、相对或绝对路径、URL、profile 作用域外 parent 和支持的查找以外的显式调用都直接委托原生实现。`#imports` 请求使用所属 manifest 中的 Node 映射;外部 bare target 按相同 conditions 遵循本地包、generation 和 after-fallback 的选包顺序,精确 target 解析仍由 Node 负责。对于作用域内的 bare request,package self-reference 保留原 parent,即使 npm alias 使安装目录使用另一个名称。Node 能在虚拟共享 fallback 之前从 profile 本地包或插件私有包解析到所请求入口时,也保留原 parent;没有 `exports` 的 CommonJS 包目录仅缺少所请求 subpath 时,不会压过 fallback。其他请求在 generation 命中时通过该条目的声明锚点解析,未命中时从虚拟 fallback 之后继续原生查找。显式 CommonJS path 列表按调用方顺序,对每个 path 独立应用相同的插入规则。
 
 适配器完成路由后调用捕获的原生 resolver。exports、import/require conditions、main、subpath、扩展名、原生缓存和错误码仍归 Node 处理。路由后的 ESM 失败会把 Node 诊断中的内部查找锚点替换为原始 importer。选中包的无效 export 或缺失目标不会触发另一个同名候选。CommonJS 不替换 `_findPath`,也不复制 `_resolveFilename`。
 

+ 2 - 2
packages/boot/app-boot/README.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write packages/boot/app-boot/README.md
-README.md: 034cf9313e4ea864769d9a8c7e6494a161fac86f
-README.zh.md: e5414bbb7e6cd7077e073465b03c51c096eccaf2
+README.md: 0ac38122886945cc87268350ee8459b509a73ed6
+README.zh.md: bc96350f8f2cf0eb1f41beb878220b24dbaa4392

+ 1 - 1
packages/boot/app-boot/README.md

@@ -108,7 +108,7 @@ This section explains how the outcomes above are realized and points at the code
 - **Process-local module resolution.** Runtime and dual modes install one generation on Node's internal ESM and CommonJS resolvers before profile rows mount; link mode leaves both resolvers unchanged. Node still owns exports, conditions, subpaths, module caches, and error codes; routed ESM failures report the original importer instead of the internal lookup anchor. `ctx.pluginPackages` exposes package metadata from the same generation without recording Entry imports; an installed generation is authoritative even for a miss, while low-level embedders that install the service without one retain native lookup.
 - **Two Loader builtins.** `mountRootInclude` registers `cordis:include` and `cordis:group` as Loader builtins: a group row gives one `isolate` realm to a provider and its consumers together, and an agent preset outside this workspace cannot resolve `@deepseek-ai/cordis-plugin-group` by name. Both load through the ambient module pipeline rather than the included tree's own specifier resolution.
 - **Consumer-owned strictness.** Ordinary Loader groups keep successful siblings. App-boot applies the global required-entry policy after initial settlement; agent presets and dynamic multi-entry compositions own and dispose their separate generation when they require all-or-nothing setup. App-boot reads failed fibers to report their recorded errors and coalesces duplicate Loader rejection notifications through one process checkpoint.
-- **One fallback generation.** The installation-first and ordered-bundle breadth-first traversal produces both the runtime table and the retained disk materializer. Runtime mode creates no resolution links and ignores stale projections at their former lookup positions. Link mode materializes the same table; dual mode also compares Node's disk result with the table. A complete successor may add package names atomically, while changing or removing an existing mapping requires restart.
+- **One fallback generation.** The installation-first and ordered-bundle breadth-first traversal produces both the runtime table and the retained disk materializer. Runtime mode creates no resolution links and ignores stale projections at their former lookup positions. External bare targets selected by package `imports` use the same package order, while Node retains mapping, conditions, and exact target resolution. Link mode materializes the same table; dual mode also compares Node's disk result with the table. A complete successor may add package names atomically, while changing or removing an existing mapping requires restart.
 - **Owned Workers.** Worker build banners import `@deepseek-ai/dsh-app-boot/worker/profile-resolution-bootstrap` before bundled business code. Each Worker installs the structured-cloned generation in its own isolate. The bootstrap bundle has no static package imports; on Windows it temporarily supplies the native loader with a service-private cache directory and restores the Worker environment before business code starts. Disposal restores resolver state before asynchronously removing that directory; a lock that survives bounded retries leaves an inert private temporary directory and emits a warning. Source Worker entries retain their self-contained dependency closure, and third-party Workers receive no injection.
 - **Update completion.** App boot observes restart failures through the `internal/update` waterfall. Live patch reloads wait for the tree's fibers before auditing activation; `Fiber.update()` and `Entry.update()` alone do not establish restart success.
 - **One rejection checkpoint.** `assertEntriesActivated` keeps the exact reasons it folds into the boot diagnostic visible through the next process rejection checkpoint, so `installFailLoud` coalesces Loader's duplicate notification while unrelated unhandled rejections remain fatal.

+ 1 - 1
packages/boot/app-boot/README.zh.md

@@ -108,7 +108,7 @@ Loader 结算后,app-boot 将 optional 失败报告为警告;若已启用的
 - **进程内模块解析。** runtime 和 dual 模式会在挂载 profile 条目前,将一份 generation 安装到 Node 的 ESM 与 CommonJS 内部 resolver;link 模式不修改这两个 resolver。exports、conditions、subpath、模块缓存和错误码仍由 Node 负责;路由后的 ESM 失败会报告原始 importer,而不是内部查找锚点。`ctx.pluginPackages` 从同一 generation 提供 package metadata,不记录 Entry import;安装 generation 后,即使查询未命中也以 generation 为准,仅安装服务而未提供 generation 的底层嵌入方仍使用 Node 原生查找。
 - **两个 Loader builtin。** `mountRootInclude` 把 `cordis:include` 与 `cordis:group` 注册为 Loader builtin:group 行能把一个提供方与它的消费方放进同一个 `isolate` realm,而位于本工作区之外的 agent preset 无法按名称解析 `@deepseek-ai/cordis-plugin-group`。两者都通过宿主的模块管线加载,而非被包含树自身的说明符解析。
 - **由 consumer 持有严格语义。** 普通 Loader group 保留成功 sibling。App-boot 在首次结算后应用全局 required-entry policy;agent preset 与动态多 entry 组合在需要 all-or-nothing setup 时,持有并拆卸各自的独立 generation。App-boot 读取 failed fiber 来报告已记录的错误,并在一个进程检查点内合并 Loader 重复的 rejection 通知。
-- **唯一 fallback generation。** 安装优先、有序 bundle 逐根 breadth-first 遍历同时生成运行时表和保留的磁盘 materializer。runtime 模式不创建解析链接,并在旧链接原来的查找位置忽略陈旧投影。link 模式物化同一张表;dual 模式还会比较 Node 的磁盘结果与表。完整后继 generation 可以原子增加 package name,修改或删除既有映射则要求重启。
+- **唯一 fallback generation。** 安装优先、有序 bundle 逐根 breadth-first 遍历同时生成运行时表和保留的磁盘 materializer。runtime 模式不创建解析链接,并在旧链接原来的查找位置忽略陈旧投影。package `imports` 选中的外部 bare target 使用相同的选包顺序,映射、conditions 和精确 target 解析仍由 Node 负责。link 模式物化同一张表;dual 模式还会比较 Node 的磁盘结果与表。完整后继 generation 可以原子增加 package name,修改或删除既有映射则要求重启。
 - **自有 Worker。** Worker 构建 banner 会在业务 bundle 前导入 `@deepseek-ai/dsh-app-boot/worker/profile-resolution-bootstrap`。每个 Worker 在自己的 isolate 中安装结构化克隆的 generation。bootstrap bundle 不静态导入任何包;在 Windows 上,它会临时向 native loader 提供服务私有缓存目录,并在业务代码启动前恢复 Worker 环境。释放时会先恢复 resolver 状态,再异步删除该目录;若有锁经过有界重试仍未释放,则留下无害的私有临时目录并输出警告。源码 Worker 入口保留自包含依赖,第三方 Worker 不接受注入。
 - **更新完成。** App boot 通过 `internal/update` waterfall 观察重启失败。实时 patch 重载在检查激活状态前等待配置树中的 fiber;单独调用 `Fiber.update()` 或 `Entry.update()` 不能确定重启成功。
 - **单一 rejection 检查点。** `assertEntriesActivated` 把折入启动诊断的确切原因保持到下一个进程级 rejection 检查点可见,使 `installFailLoud` 能合并 Loader 的重复通知,而所有无关的未处理 rejection 仍然致命。

+ 100 - 55
packages/boot/app-boot/src/profile-resolution/resolver.ts

@@ -34,6 +34,10 @@ interface CommonJsModule {
 
 interface InternalModules {
   esm: ModuleLoaderV1 | ModuleLoaderV2
+  esmDefaultResolve: (
+    specifier: string,
+    context: { parentURL?: string; conditions?: readonly string[] },
+  ) => ResolveResult
   esmConditions: readonly string[]
   cjs: CommonJsModule
   cjsConditions: ReadonlySet<string>
@@ -203,7 +207,7 @@ function selfReferenceName(parent: string): string | false | null {
 
 function packageImportsTarget(
   parent: string, request: string, conditions: Iterable<string>,
-): string | undefined {
+): { specifier: string; parentURL: string } | undefined {
   let current = dirname(parent)
   while (true) {
     const manifestPath = join(current, 'package.json')
@@ -221,7 +225,9 @@ function packageImportsTarget(
           conditions: [...conditions],
           unsafe: true,
         })?.[0]
-        return target !== undefined && barePackageName(target) !== undefined ? target : undefined
+        return target !== undefined && barePackageName(target) !== undefined
+          ? { specifier: target, parentURL: pathToFileURL(manifestPath).href }
+          : undefined
       } catch (_error) {
         // The native resolver retains missing mappings and unmatched-condition diagnostics.
         /* v8 ignore next -- native resolution cannot report MODULE_NOT_FOUND before selecting a valid mapping */
@@ -252,9 +258,11 @@ function localCandidateOwnsResolution(candidate: string, resolved: string, reque
   if (startsWithin(resolved, prefixes(candidate))) return true
   if (sameResolution(candidate, resolved)) return true
   if (['.js', '.json', '.node'].some(extension => sameResolution(candidate + extension, resolved))) return true
+  /* v8 ignore next -- a bounded native lookup can escape a candidate only through its root legacy main */
   if (request !== name) return false
   try {
     const manifest = JSON.parse(readFileSync(join(candidate, 'package.json'), 'utf8')) as Record<string, unknown>
+    /* v8 ignore next -- a bounded native lookup outside the package directory requires a legacy main */
     if (typeof manifest.main !== 'string') return false
     const main = createRequire(join(candidate, 'package.json')).resolve(resolve(candidate, manifest.main))
     return sameResolution(main, resolved)
@@ -320,7 +328,7 @@ class ResolutionRouter {
     parentRoutes: ParentRoutes,
     generation: CompiledGeneration,
     flavor: 'esm' | 'cjs',
-    nativeResolve?: () => string,
+    nativeResolve?: (searchPaths: readonly string[]) => string,
     cacheable = false,
   ): ResolutionRouteState | undefined {
     const { parent, profilesDir, requests } = parentRoutes
@@ -338,8 +346,10 @@ class ResolutionRouter {
 
     const target = generation.entries.get(name)
     const candidates: Array<{ packageDir: string; canBeManagedLink: boolean }> = []
+    const localSearchPaths: string[] = []
     for (const searchPath of createRequire(parent).resolve.paths(name) as string[]) {
       if (generation.shared.has(resolve(searchPath))) break
+      localSearchPaths.push(searchPath)
       const candidate = localPackageCandidate(searchPath, name, flavor)
       if (candidate !== undefined) {
         const legacy = candidate.canBeManagedLink && generation.profile.some(prefix => (
@@ -352,7 +362,7 @@ class ResolutionRouter {
     if (candidates.length > 0) {
       if (flavor === 'cjs' && nativeResolve !== undefined) {
         try {
-          const resolved = nativeResolve()
+          const resolved = nativeResolve(localSearchPaths)
           const selected = candidates.find(candidate => (
             localCandidateOwnsResolution(candidate.packageDir, resolved, request, name)
           ))
@@ -439,7 +449,7 @@ class ResolutionRouter {
   }
 
   routePath(
-    request: string, parent: string, nativeResolve?: () => string, cacheable = false,
+    request: string, parent: string, nativeResolve?: (searchPaths: readonly string[]) => string, cacheable = false,
   ): ResolutionRouteState | undefined {
     const generation = this.current
     let parentRoutes = generation.cjsRoutes.get(parent)
@@ -470,16 +480,25 @@ class ResolutionRouter {
   }
 
   explicitRoute(
-    request: string, paths: readonly string[], nativeResolve: (path: string) => () => string,
-  ): { index: number; state: ResolutionRouteState } | undefined {
+    request: string, paths: readonly string[],
+  ): { index: number; parent: string } | undefined {
+    if (barePackageName(request) === undefined) return undefined
     for (const [index, path] of paths.entries()) {
       const parent = join(resolve(path), '.dsh-profile-resolution.cjs')
-      const state = this.routePath(request, parent, nativeResolve(path), false)
-      if (state !== undefined) return { index, state }
+      if (startsWithin(parent, this.current.profilePaths) || startsWithin(parent, this.current.profile)) {
+        return { index, parent }
+      }
     }
     return undefined
   }
 
+  nativeSelfReference(request: string, parent: string): boolean {
+    const name = barePackageName(request)
+    if (name === undefined) return false
+    const self = selfReferenceName(parent)
+    return self === name || self === null
+  }
+
   packageDir(specifier: string, parentURL: string): string | undefined {
     const name = barePackageName(specifier)
     if (name === undefined) return undefined
@@ -511,6 +530,12 @@ function internalModules(): InternalModules {
   const esmUtils = addon.requireBuiltin('internal/modules/esm/utils') as {
     getDefaultConditions(): readonly string[]
   }
+  const esmResolve = addon.requireBuiltin('internal/modules/esm/resolve') as {
+    defaultResolve(
+      specifier: string,
+      context: { parentURL?: string; conditions?: readonly string[] },
+    ): ResolveResult
+  }
   const esm = esmModule.getOrInitializeCascadedLoader()
   const modern = 'getOrCreateModuleJob' in esm
   /* v8 ignore start -- the supported Node 22/24/26 matrix validates each available Internal interface */
@@ -519,12 +544,14 @@ function internalModules(): InternalModules {
     || (!modern && typeof Reflect.get(esm, 'resolve') !== 'function')
     || typeof cjsModule.Module._resolveFilename !== 'function'
     || typeof cjsHelpers.getCjsConditions !== 'function'
-    || typeof esmUtils.getDefaultConditions !== 'function') {
+    || typeof esmUtils.getDefaultConditions !== 'function'
+    || typeof esmResolve.defaultResolve !== 'function') {
     throw new Error('profile resolution: unsupported Node module loader')
   }
   /* v8 ignore stop */
   return {
     esm,
+    esmDefaultResolve: esmResolve.defaultResolve,
     esmConditions: esmUtils.getDefaultConditions(),
     cjs: cjsModule.Module,
     cjsConditions: cjsHelpers.getCjsConditions(),
@@ -598,7 +625,7 @@ export function installProfileResolution(
   behavior: ProfileResolutionBehavior = 'enforce',
 ): ProfileResolutionRegistration {
   const router = new ResolutionRouter(generation)
-  const { esm, esmConditions, cjs, cjsConditions, modern } = internalModules()
+  const { esm, esmDefaultResolve, esmConditions, cjs, cjsConditions, modern } = internalModules()
   const esmScope = new Map<string, boolean>()
   const profilePaths = [
     ...prefixes(generation.profilesDir),
@@ -632,33 +659,28 @@ export function installProfileResolution(
         const target = request[0] === '#'
           ? packageImportsTarget(fileURLToPath(parent), request, esmConditions)
           : undefined
-        const recoverPackageImport = (error: unknown): ResolveResult | Promise<ResolveResult> => {
-          if ((error as NodeJS.ErrnoException).code !== 'ERR_MODULE_NOT_FOUND' || target === undefined) throw error
-          return adapted(target, parent, attributes)
-        }
-        const verifyPackageImport = (resolved: ResolveResult): ResolveResult | Promise<ResolveResult> => {
-          if (behavior !== 'verify' || target === undefined) return resolved
-          const expected = adapted(target, parent, attributes)
-          /* v8 ignore start -- Node 22 is the asynchronous adapter and is covered by the external version matrix */
-          if (expected instanceof Promise) {
-            return expected.then((wanted) => {
-              assertEquivalent(resolved.url, wanted.url, request, parent)
-              return resolved
-            })
-          }
-          /* v8 ignore stop */
-          assertEquivalent(resolved.url, expected.url, request, parent)
-          return resolved
-        }
+        if (target === undefined) return native(request, parent, attributes)
+        const restoreImporter = (error: unknown): never => throwWithImporter(error, target.parentURL, parent)
+        let expected: ResolveResult | Promise<ResolveResult>
         try {
-          const result = native(request, parent, attributes)
-          /* v8 ignore next -- Node 22 is the asynchronous adapter and is covered by the external version matrix */
-          return result instanceof Promise
-            ? result.then(verifyPackageImport, recoverPackageImport)
-            : verifyPackageImport(result)
+          expected = adapted(target.specifier, target.parentURL, attributes)
+          /* v8 ignore next -- Node 24+ resolves synchronously; the Node 22 matrix covers its Promise result */
+          if (expected instanceof Promise) expected = expected.catch(restoreImporter)
         } catch (error) {
-          return recoverPackageImport(error)
+          return restoreImporter(error)
+        }
+        if (behavior === 'enforce') return expected
+        const actual = native(request, parent, attributes)
+        /* v8 ignore start -- Node 22 is the asynchronous adapter and is covered by the external version matrix */
+        if (expected instanceof Promise || actual instanceof Promise) {
+          return Promise.all([actual, expected]).then(([resolved, wanted]) => {
+            assertEquivalent(resolved.url, wanted.url, request, parent)
+            return resolved
+          })
         }
+        /* v8 ignore stop */
+        assertEquivalent(actual.url, expected.url, request, parent)
+        return actual
       }
       const cacheable = attributes === EMPTY_ATTRIBUTES || Object.keys(attributes).length === 0
       if (cacheable && state.esm !== undefined) return state.esm
@@ -781,17 +803,44 @@ export function installProfileResolution(
       return throwWithoutCjsAnchor(error, anchor)
     }
   }
+  const resolveNativeCjs = (
+    request: string, searchPaths: readonly string[], parent: CommonJsParent,
+    parentFilename: string, main: boolean, conditions: ReadonlySet<string> | undefined,
+  ): string => {
+    const synthetic = new cjs(parentFilename)
+    synthetic.parent = parent
+    synthetic.filename = parentFilename
+    synthetic.paths = [...searchPaths]
+    const options = conditions === undefined ? undefined : { conditions }
+    return originalFilename.call(cjs, request, synthetic, main, options)
+  }
+  const resolvePackageImportCjs = (
+    target: { specifier: string; parentURL: string }, conditions: Iterable<string>,
+  ): string => {
+    const state = router.routeUrl(target.specifier, target.parentURL)
+    const resolveFrom = (parentURL: string): string => fileURLToPath(esmDefaultResolve(
+      target.specifier, { parentURL, conditions: [...conditions] },
+    ).url)
+    /* v8 ignore next -- the target manifest was found inside the established profile scope */
+    if (state === undefined) return resolveFrom(target.parentURL)
+    if (state.route.kind === 'native') return resolveFrom(target.parentURL)
+    const route = state.route
+    if (route.kind === 'after-fallback') return resolveFrom(pathToFileURL(route.parent).href)
+    return resolveFrom(pathToFileURL(route.entry.declarer).href)
+  }
   const wrappedFilename: CommonJsModule['_resolveFilename'] = (request, parent, main, options) => {
     if (delegatedCjs || !parent?.filename) {
       return originalFilename.call(cjs, request, parent, main, options)
     }
+    const parentFilename = parent.filename
     const cacheable = options?.paths === undefined && options?.conditions === undefined
     const explicitPaths = Array.isArray(options?.paths) ? options.paths : undefined
+    if (explicitPaths !== undefined && router.nativeSelfReference(request, parentFilename)) {
+      return originalFilename.call(cjs, request, parent, main, options)
+    }
     const explicit = explicitPaths === undefined
       ? undefined
-      : router.explicitRoute(request, explicitPaths, path => () => originalFilename.call(
-        cjs, request, parent, main, { ...options, paths: [path] },
-      ))
+      : router.explicitRoute(request, explicitPaths)
     if (options?.paths !== undefined && explicit === undefined) {
       return originalFilename.call(cjs, request, parent, main, options)
     }
@@ -805,28 +854,24 @@ export function installProfileResolution(
         if (!isUnselectedPackageMiss(error)) throw error
       }
     }
-    const state = explicit?.state ?? router.routePath(
+    const state = router.routePath(
       request,
-      parent.filename,
-      () => originalFilename.call(cjs, request, parent, main, options),
-      cacheable,
+      explicit?.parent ?? parentFilename,
+      searchPaths => resolveNativeCjs(request, searchPaths, parent, parentFilename, main, options?.conditions),
+      explicit === undefined && cacheable,
     )
     if (state === undefined) {
-      const scoped = startsWithin(parent.filename, profilePaths)
+      const scoped = startsWithin(parentFilename, profilePaths)
       const conditions = options?.conditions ?? cjsConditions
       const target = request[0] === '#' && scoped
-        ? packageImportsTarget(parent.filename, request, conditions)
+        ? packageImportsTarget(parentFilename, request, conditions)
         : undefined
-      try {
-        const result = originalFilename.call(cjs, request, parent, main, options)
-        if (behavior === 'verify' && target !== undefined) {
-          assertEquivalent(result, wrappedFilename(target, parent, main, options), request, parent.filename)
-        }
-        return result
-      } catch (error) {
-        if ((error as NodeJS.ErrnoException).code !== 'MODULE_NOT_FOUND' || target === undefined) throw error
-        return wrappedFilename(target, parent, main, options)
-      }
+      if (target === undefined) return originalFilename.call(cjs, request, parent, main, options)
+      const expected = resolvePackageImportCjs(target, conditions)
+      if (behavior === 'enforce') return expected
+      const actual = originalFilename.call(cjs, request, parent, main, options)
+      assertEquivalent(actual, expected, request, parentFilename)
+      return actual
     }
     if (cacheable && state.cjs !== undefined) return state.cjs
     const route = state.route
@@ -880,7 +925,7 @@ export function installProfileResolution(
         return expected
       }
       const actual = originalFilename.call(cjs, request, parent, main, options)
-      assertEquivalent(actual, expected, request, parent.filename)
+      assertEquivalent(actual, expected, request, parentFilename)
       if (cacheable) state.cjs = actual
       return actual
     } finally {

+ 124 - 0
packages/boot/app-boot/tests/profile-resolution.spec.ts

@@ -361,12 +361,39 @@ describe('profile resolution generation', { concurrent: false }, () => {
     expect(require.resolve('resolution-lib', { paths: [f.profile.dir] })).toBe(join(f.installed, 'index.cjs'))
     expect(require.resolve('resolution-lib', { paths: [join(f.root, 'missing'), f.profile.dir] }))
       .toBe(join(f.installed, 'index.cjs'))
+    const relative = join(f.profile.dir, 'relative.cjs')
+    file(relative, '')
+    expect(require.resolve('./relative.cjs', { paths: [f.profile.dir] })).toBe(relative)
     const invalid = join(f.root, 'invalid')
     file(join(invalid, 'node_modules', 'resolution-lib', 'package.json'), '{')
     expect(() => { require.resolve('resolution-lib', { paths: [invalid, f.profile.dir] }) })
       .toThrow(/Invalid package config/u)
   })
 
+  it('keeps earlier explicit CommonJS paths ahead of a managed local failure', async () => {
+    const f = fixture()
+    const generation = await healProfilesModuleFallback({
+      installAnchor: f.installAnchor,
+      profile: f.profile,
+      home: f.root,
+    })
+    const local = join(f.profile.dir, 'node_modules', 'resolution-lib')
+    file(join(local, 'package.json'), JSON.stringify({
+      name: 'resolution-lib', version: '2.0.0', exports: './missing.cjs',
+    }))
+    const alternative = join(f.root, 'alternative')
+    const selected = join(alternative, 'node_modules', 'resolution-lib', 'index.cjs')
+    pkg(dirname(selected), 'resolution-lib', 3)
+    const require = createRequire(join(f.profile.dir, 'entry.cjs'))
+    const paths = [alternative, f.profile.dir]
+    expect(require.resolve('resolution-lib', { paths })).toBe(selected)
+    unlinkSync(join(generation.profilesDir, 'node_modules', 'resolution-lib'))
+
+    const registration = installProfileResolution(generation)
+    registrations.push(registration)
+    expect(require.resolve('resolution-lib', { paths })).toBe(selected)
+  })
+
   it('keeps a missing legacy main before a managed explicit CommonJS path', async () => {
     const f = fixture()
     const invalid = join(f.root, 'invalid')
@@ -464,6 +491,15 @@ describe('profile resolution generation', { concurrent: false }, () => {
 
   it('preserves an npm alias package self-reference', async () => {
     const f = fixture()
+    file(f.installAnchor, JSON.stringify({
+      name: 'test-app',
+      version: '0.0.0',
+      type: 'module',
+      exports: { import: './index.js', require: './index.cjs' },
+      dependencies: { 'resolution-lib': '*', 'real-name': '*' },
+    }))
+    const installedRealName = join(dirname(f.installAnchor), 'node_modules', 'real-name')
+    pkg(installedRealName, 'real-name', 7)
     file(join(f.profile.dir, 'package.json'), JSON.stringify({
       name: 'test-profile',
       private: true,
@@ -479,6 +515,7 @@ describe('profile resolution generation', { concurrent: false }, () => {
     expect(generation.localPackageNames).toEqual(['alias'])
     const require = createRequire(join(alias, 'inside.cjs'))
     expect(require.resolve('real-name')).toBe(join(alias, 'index.cjs'))
+    expect(require.resolve('real-name', { paths: [f.profile.dir] })).toBe(join(alias, 'index.cjs'))
     expect(resolveFrom('real-name', pathToFileURL(join(alias, 'inside-link.mjs')).href)).toBe(
       pathToFileURL(join(alias, 'index.js')).href,
     )
@@ -489,10 +526,12 @@ describe('profile resolution generation', { concurrent: false }, () => {
     expect(() => resolveFrom('resolution-lib', pathToFileURL(join(invalidScope, 'inside.mjs')).href))
       .toThrow(/Invalid package config/u)
     unlinkSync(join(generation.profilesDir, 'node_modules', 'resolution-lib'))
+    unlinkSync(join(generation.profilesDir, 'node_modules', 'real-name'))
 
     const registration = installProfileResolution(generation)
     registrations.push(registration)
     expect(require.resolve('real-name')).toBe(join(alias, 'index.cjs'))
+    expect(require.resolve('real-name', { paths: [f.profile.dir] })).toBe(join(alias, 'index.cjs'))
     expect(resolveFrom('real-name', pathToFileURL(join(alias, 'inside-runtime.mjs')).href)).toBe(
       pathToFileURL(join(alias, 'index.js')).href,
     )
@@ -550,6 +589,41 @@ describe('profile resolution generation', { concurrent: false }, () => {
     )).toBe(pathToFileURL(realpathSync(join(f.installed, 'index.js'))).href)
   })
 
+  it('ignores a stale package imports projection and detects it in dual mode', async () => {
+    const f = fixture()
+    file(join(f.profile.dir, 'package.json'), JSON.stringify({
+      name: 'test-profile',
+      private: true,
+      imports: { '#resolution-lib': 'resolution-lib' },
+    }))
+    const generation = await healProfilesModuleFallback({
+      installAnchor: f.installAnchor,
+      profile: f.profile,
+      home: f.root,
+    })
+    const projection = join(generation.profilesDir, 'node_modules', 'resolution-lib')
+    unlinkSync(projection)
+    const stale = join(f.root, 'stale', 'resolution-lib')
+    pkg(stale, 'resolution-lib', 9)
+    symlinkSync(stale, projection, process.platform === 'win32' ? 'junction' : 'dir')
+    const require = createRequire(join(f.profile.dir, 'entry.cjs'))
+
+    const runtime = installProfileResolution(generation)
+    expect(require.resolve('#resolution-lib')).toBe(join(f.installed, 'index.cjs'))
+    expect(require.resolve('resolution-lib')).toBe(join(f.installed, 'index.cjs'))
+    expect(resolveFrom(
+      '#resolution-lib', pathToFileURL(join(f.profile.dir, 'runtime.mjs')).href,
+    )).toBe(pathToFileURL(join(f.installed, 'index.js')).href)
+    runtime.dispose()
+
+    const dual = installProfileResolution(generation, 'verify')
+    registrations.push(dual)
+    expect(() => require.resolve('#resolution-lib')).toThrow(/profile resolution mismatch/u)
+    expect(() => resolveFrom(
+      '#resolution-lib', pathToFileURL(join(f.profile.dir, 'dual-stale.mjs')).href,
+    )).toThrow(/profile resolution mismatch/u)
+  })
+
   it('leaves relative package imports targets and their diagnostics to Node', async () => {
     const f = fixture()
     file(join(f.profile.dir, 'package.json'), JSON.stringify({
@@ -574,6 +648,27 @@ describe('profile resolution generation', { concurrent: false }, () => {
     expect(thrownMessage(() => resolveFrom('#missing-relative', parent))).toBe(esmMessage)
   })
 
+  it('keeps local and after-fallback package imports targets in native order', async () => {
+    const f = fixture()
+    file(join(f.profile.dir, 'package.json'), JSON.stringify({
+      name: 'test-profile',
+      private: true,
+      imports: { '#local': 'local-import', '#ancestor': 'ancestor-import' },
+    }))
+    const local = join(f.profile.dir, 'node_modules', 'local-import')
+    const ancestor = join(f.root, 'node_modules', 'ancestor-import')
+    pkg(local, 'local-import', 4)
+    pkg(ancestor, 'ancestor-import', 5)
+    const require = createRequire(join(f.profile.dir, 'entry.cjs'))
+    expect(require.resolve('#local')).toBe(join(local, 'index.cjs'))
+    expect(require.resolve('#ancestor')).toBe(join(ancestor, 'index.cjs'))
+
+    const registration = installProfileResolution(await generationOf(f))
+    registrations.push(registration)
+    expect(require.resolve('#local')).toBe(join(local, 'index.cjs'))
+    expect(require.resolve('#ancestor')).toBe(join(ancestor, 'index.cjs'))
+  })
+
   it('leaves package imports outside the profile scope to Node', async () => {
     const f = fixture()
     const outside = join(f.root, 'outside')
@@ -632,6 +727,35 @@ describe('profile resolution generation', { concurrent: false }, () => {
       .toBe(join(f.installed, 'legacy-install.cjs'))
   })
 
+  it('stops a local CommonJS probe before the generation fallback position', async () => {
+    const f = fixture()
+    file(join(f.installed, 'package.json'), JSON.stringify({
+      name: 'resolution-lib', version: '1.0.0', type: 'module', main: './index.cjs',
+    }))
+    const installedSubpath = join(f.installed, 'only-install.cjs')
+    file(installedSubpath, 'module.exports = { marker: 8 }\n')
+    const generation = await healProfilesModuleFallback({
+      installAnchor: f.installAnchor,
+      profile: f.profile,
+      home: f.root,
+    })
+    file(join(f.profile.dir, 'node_modules', 'resolution-lib', 'package.json'), JSON.stringify({
+      name: 'resolution-lib', version: '2.0.0', main: './index.cjs',
+    }))
+    file(join(f.profile.dir, 'node_modules', 'resolution-lib', 'index.cjs'), 'module.exports = {}\n')
+    file(join(f.root, 'node_modules', 'resolution-lib', 'package.json'), JSON.stringify({
+      name: 'resolution-lib', version: '3.0.0', exports: './index.cjs',
+    }))
+    file(join(f.root, 'node_modules', 'resolution-lib', 'index.cjs'), 'module.exports = {}\n')
+    const require = createRequire(join(f.profile.dir, 'entry.cjs'))
+    expect(require.resolve('resolution-lib/only-install.cjs')).toBe(installedSubpath)
+    unlinkSync(join(generation.profilesDir, 'node_modules', 'resolution-lib'))
+
+    const registration = installProfileResolution(generation)
+    registrations.push(registration)
+    expect(require.resolve('resolution-lib/only-install.cjs')).toBe(installedSubpath)
+  })
+
   it('observes a profile-local package installed after an earlier miss', async () => {
     const f = fixture()
     const registration = installProfileResolution(await generationOf(f))