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

fix(boot): align runtime profile resolution with links

imccyu 2 недель назад
Родитель
Сommit
013aead5c9

+ 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: f88b75b4c75db825797fea4f2c776372baabfaea
-2026-09-09-profile-resolution-generations.zh.md: 6c16cd022db148a86e62d41f76fdee710e33d698
+2026-09-09-profile-resolution-generations.md: 39c64bd50d5dd3856233d24cf37ca874c54d6b2c
+2026-09-09-profile-resolution-generations.zh.md: 55fb5af8c16d8c713b983991cd5d26e929730a7a

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

@@ -36,9 +36,9 @@ 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, `#imports`, parents outside the profile scope, and explicit calls outside the supported lookup. 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 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.
 
-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 final errors. A selected package's invalid export or missing target does not trigger another same-name candidate. CommonJS does not replace `_findPath` or reproduce `_resolveFilename`.
+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`.
 
 The guarantee covers Node's default `import`, `import()`, `import.meta.resolve`, `require`, and `require.resolve` after installation in that thread. It does not cover already linked modules, custom `vm` linkers, opaque non-Node importers, or third-party Workers.
 
@@ -86,7 +86,7 @@ Generation construction is startup or update work, not resolve work, and its abs
 
 One-off local measurements taken during implementation ran built JavaScript under plain Node in fresh processes and compared it with a process that installed no hook. The measurement script and results are not committed, and these figures are not a benchmark or CI budget. Seven alternating rounds covered outside, profile-local, and fallback imports through dynamic import, `import.meta.resolve`, require, and `require.resolve`. Across Node 22.19, 24.18, and 26.8, the largest positive hot-path median was 4.5%. On Node 24.18, a 256-package cold workload regressed by at most 11.2% and generation construction took 16.027 ms median; the 32-package local `require.resolve` case added 1.033 ms across the batch (+34.7%) from fixed startup cost.
 
-Behavior tests compare the runtime generation with the disk materializer over the same package trees, then exercise root order, transitive and peer dependencies, local and external precedence, exports and subpath errors, conditions, explicit CommonJS options, source and built Workers, and supported Node versions. Generation tests prove failed construction does not publish partial state and successful replacement is atomic.
+Behavior tests compare the runtime generation with the disk materializer over the same package trees, then exercise root order, transitive and peer dependencies, local and external precedence, exports and subpath errors, conditions, and explicit CommonJS options. The Node compatibility matrix runs the resolver, service, and bootstrap specifications across the supported internal-loader variants. Worker tests verify environment-data publication and bootstrap installation with mocked thread and native-loader interfaces; they do not launch a built Worker. Generation tests prove failed construction does not publish partial state and successful replacement is atomic.
 
 ## Alternatives considered
 
@@ -108,8 +108,8 @@ Behavior tests compare the runtime generation with the disk materializer over th
 - Link-only, dual, and runtime-only tests consume the same generation; runtime startup neither writes nor retires module-resolution data.
 - ESM and CommonJS adapters share one router and delegate final resolution to Node without `module.registerHooks` or `_findPath` replacement.
 - Production metadata lookup does not record Loader import results or wrap Entry, registry, tree, or HMR methods.
-- Main-thread and built owned-Worker tests cover supported Node versions.
-- Built plain-Node measurements record the hot and cold results above against no-hook Node.
+- The Node compatibility matrix runs main-thread resolver specifications across supported loader interfaces; service and bootstrap specifications cover Worker environment-data and installation interfaces without launching a built Worker.
+- One-off built plain-Node measurements produced the hot and cold observations above against no-hook Node; the script and results are not committed evidence.
 - Package READMEs, architecture references, generated catalogs, and the bilingual pair describe the shipped implementation.
 
 ## Consequences

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

@@ -36,9 +36,9 @@ 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、`#imports`、profile 作用域外 parent 和支持的查找以外的显式调用都直接委托原生实现。对于作用域内的 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` 请求会先使用 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 独立应用相同的插入规则。
 
-适配器完成路由后调用捕获的原生 resolver。exports、import/require conditions、main、subpath、扩展名、原生缓存和最终错误仍归 Node 处理。选中包的无效 export 或缺失目标不会触发另一个同名候选。CommonJS 不替换 `_findPath`,也不复制 `_resolveFilename`。
+适配器完成路由后调用捕获的原生 resolver。exports、import/require conditions、main、subpath、扩展名、原生缓存和错误码仍归 Node 处理。路由后的 ESM 失败会把 Node 诊断中的内部查找锚点替换为原始 importer。选中包的无效 export 或缺失目标不会触发另一个同名候选。CommonJS 不替换 `_findPath`,也不复制 `_resolveFilename`。
 
 保证范围是当前线程安装后发生的 Node 默认 `import`、`import()`、`import.meta.resolve`、`require` 和 `require.resolve`。已经链接的模块、自定义 `vm` linker、不透明的非 Node importer 和第三方 Worker 不在透明保证范围。
 
@@ -86,7 +86,7 @@ generation 构造发生在启动或显式更新阶段,不属于单次 resolve
 
 实现期间的一次性本地测量用 plain Node 在全新进程中执行构建后的 JavaScript,并与完全没有安装 hook 的进程比较。测量脚本和结果未提交,这些数据不是 benchmark 或 CI 预算。七轮交替顺序覆盖 outside、profile-local 和 fallback 的 dynamic import、`import.meta.resolve`、require、`require.resolve`。Node 22.19、24.18 和 26.8 的热路径中位数最大正向回退为 4.5%。Node 24.18 的 256 包 cold workload 最大回退为 11.2%,generation 构造中位数为 16.027 ms;32 包本地 `require.resolve` 因固定启动成本在整批增加 1.033 ms(+34.7%)。
 
-行为测试在同一包树上比较运行时 generation 与磁盘 materializer,再覆盖根顺序、传递依赖和 peer、本地与外层优先级、exports 与 subpath 错误、conditions、显式 CommonJS options、源码和构建 Worker及支持的 Node 版本。generation 测试证明构造失败不发布部分状态,成功换代只做原子引用替换。
+行为测试在同一包树上比较运行时 generation 与磁盘 materializer,再覆盖根顺序、传递依赖和 peer、本地与外层优先级、exports 与 subpath 错误、conditions 和显式 CommonJS options。Node 兼容矩阵会在受支持的内部 loader 变体上运行 resolver、service 和 bootstrap 规格。Worker 测试通过 mock 线程与 native loader 接口验证 environment data 发布和 bootstrap 安装,但不会启动构建后的 Worker。generation 测试证明构造失败不发布部分状态,成功换代只做原子引用替换。
 
 ## Alternatives considered
 
@@ -108,8 +108,8 @@ generation 构造发生在启动或显式更新阶段,不属于单次 resolve
 - link-only、dual 和 runtime-only 测试消费同一个 generation;runtime 启动既不写入也不退休模块解析数据。
 - ESM 与 CommonJS 适配器共享同一个路由器,并把最终解析委托给 Node,不使用 `module.registerHooks` 或替换 `_findPath`。
 - 生产 package metadata 查询不记录 Loader import 结果,也不包装 Entry、registry、tree 或 HMR 方法。
-- 主线程和构建后的自有 Worker 测试覆盖受支持的 Node 版本。
-- plain Node 构建产物测量记录上述相对无 hook Node 的热路径和 cold 结果。
+- Node 兼容矩阵会在受支持的 loader 接口上运行主线程 resolver 规格;service 和 bootstrap 规格覆盖 Worker environment data 与安装接口,但不会启动构建后的 Worker。
+- 一次性 plain Node 构建产物测量得到上述相对无 hook Node 的热路径和 cold 观察结果;脚本与结果并未提交为证据。
 - package README、架构引用、生成目录和双语文档对描述已交付实现。
 
 ## Consequences

+ 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: 197754a24dd2cf5402e0165be81fbaaf38e6862c
-README.zh.md: 05ab7b0d39a922051e44093137aa59122c2f374e
+README.md: 034cf9313e4ea864769d9a8c7e6494a161fac86f
+README.zh.md: e5414bbb7e6cd7077e073465b03c51c096eccaf2

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

@@ -105,7 +105,7 @@ This section explains how the outcomes above are realized and points at the code
 
 ### Design notes
 
-- **Process-local module resolution.** The package installs one generation on Node's internal ESM and CommonJS resolvers before profile rows mount. Node still owns exports, conditions, subpaths, module caches, and final errors. `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.
+- **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.

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

@@ -105,7 +105,7 @@ Loader 结算后,app-boot 将 optional 失败报告为警告;若已启用的
 
 ### 设计说明
 
-- **进程内模块解析。** 此包会在挂载 profile 条目前,将一份 generation 安装到 Node 的 ESM 与 CommonJS 内部 resolver。exports、conditions、subpath、模块缓存和最终错误仍由 Node 负责。`ctx.pluginPackages` 从同一 generation 提供 package metadata,不记录 Entry import;安装 generation 后,即使查询未命中也以 generation 为准,仅安装服务而未提供 generation 的底层嵌入方仍使用 Node 原生查找。
+- **进程内模块解析。** 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,修改或删除既有映射则要求重启。

+ 194 - 76
packages/boot/app-boot/src/profile-resolution/resolver.ts

@@ -6,6 +6,7 @@ import { basename, dirname, join, resolve, sep } from 'node:path'
 import { fileURLToPath, pathToFileURL } from 'node:url'
 import { getEnvironmentData, setEnvironmentData } from 'node:worker_threads'
 import type { ModuleLoaderV1, ModuleLoaderV2, ResolveResult } from '@deepseek-ai/cordis-plugin-loader'
+import { imports as resolvePackageImports, type Package as ResolvePackageManifest } from 'resolve.exports'
 import { isProfileModuleFallbackLink } from './legacy-links.ts'
 import type { ProfileResolutionEntry, ProfileResolutionGeneration } from '../profile.ts'
 
@@ -14,6 +15,7 @@ const EMPTY_ATTRIBUTES: ImportAttributes = Object.freeze({})
 
 interface CommonJsParent {
   filename?: string | null
+  parent?: CommonJsParent | null
   paths?: string[]
 }
 
@@ -33,6 +35,7 @@ interface CommonJsModule {
 interface InternalModules {
   esm: ModuleLoaderV1 | ModuleLoaderV2
   cjs: CommonJsModule
+  cjsConditions: ReadonlySet<string>
   modern: boolean
 }
 
@@ -41,7 +44,7 @@ type EsmResolve = (
 ) => ResolveResult | Promise<ResolveResult>
 
 type ResolutionRoute =
-  | { readonly kind: 'fallback'; readonly entry: ProfileResolutionEntry }
+  | { readonly kind: 'fallback'; readonly entry: ProfileResolutionEntry; readonly after: string }
   | { readonly kind: 'after-fallback'; readonly parent: string }
   | { readonly kind: 'native'; readonly packageDir?: string }
 
@@ -168,10 +171,8 @@ function localPackageCandidate(
   const stat = statSync(candidate, { throwIfNoEntry: false })
   const found = flavor === 'esm'
     ? stat?.isDirectory() === true
-    : stat?.isFile() === true
-      || existsSync(join(candidate, 'package.json'))
+    : stat !== undefined
       || ['.js', '.json', '.node'].some(extension => existsSync(candidate + extension))
-      || ['index.js', 'index.json', 'index.node'].some(entry => existsSync(join(candidate, entry)))
   return found ? { packageDir: candidate, canBeManagedLink: stat !== undefined } : undefined
 }
 
@@ -199,9 +200,55 @@ function selfReferenceName(parent: string): string | false | null {
   }
 }
 
-function localCandidateOwnsResolution(candidate: string, resolved: string): boolean {
+function packageImportsTarget(
+  parent: string, request: string, conditions: Iterable<string>,
+): string | undefined {
+  let current = dirname(parent)
+  while (true) {
+    const manifestPath = join(current, 'package.json')
+    if (existsSync(manifestPath)) {
+      let manifest: ResolvePackageManifest
+      try {
+        manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as ResolvePackageManifest
+      } catch (_error) {
+        // The native resolver retains invalid package-target and manifest diagnostics.
+        /* v8 ignore next -- native resolution cannot report MODULE_NOT_FOUND after an invalid scope manifest */
+        return undefined
+      }
+      try {
+        const target = resolvePackageImports(manifest, request, {
+          conditions: [...conditions],
+          unsafe: true,
+        })?.[0]
+        return target !== undefined && barePackageName(target) !== undefined ? target : 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 */
+        return undefined
+      }
+    }
+    const next = dirname(current)
+    /* v8 ignore next -- a MODULE_NOT_FOUND package-import target always has an owning package scope */
+    if (next === current) return undefined
+    current = next
+  }
+}
+
+function localCandidateOwnsResolution(candidate: string, resolved: string, request: string, name: string): boolean {
   if (startsWithin(resolved, prefixes(candidate))) return true
-  return ['.js', '.json', '.node'].some(extension => sameResolution(candidate + extension, resolved))
+  if (sameResolution(candidate, resolved)) return true
+  if (['.js', '.json', '.node'].some(extension => sameResolution(candidate + extension, resolved))) return true
+  if (request !== name) return false
+  try {
+    const manifest = JSON.parse(readFileSync(join(candidate, 'package.json'), 'utf8')) as Record<string, unknown>
+    if (typeof manifest.main !== 'string') return false
+    const main = createRequire(join(candidate, 'package.json')).resolve(resolve(candidate, manifest.main))
+    return sameResolution(main, resolved)
+  } catch (_error) {
+    // Native resolution already owns malformed manifests and missing legacy entries.
+    /* v8 ignore next -- this helper runs only after the same native resolution succeeded */
+    return false
+  }
 }
 
 function packageHasExports(packageDir: string): boolean {
@@ -262,6 +309,7 @@ class ResolutionRouter {
     generation: CompiledGeneration,
     flavor: 'esm' | 'cjs',
     nativeResolve?: () => string,
+    cacheable = false,
   ): ResolutionRouteState | undefined {
     const { parent, profilesDir, requests } = parentRoutes
     const name = barePackageName(request)
@@ -270,8 +318,7 @@ class ResolutionRouter {
     if (parentRoutes.selfReferenceName === undefined) {
       parentRoutes.selfReferenceName = selfReferenceName(parent)
     }
-    if (parentRoutes.selfReferenceName === name
-      || (parentRoutes.selfReferenceName === null && flavor === 'esm')) {
+    if (parentRoutes.selfReferenceName === name || parentRoutes.selfReferenceName === null) {
       const state = { route: { kind: 'native' as const } }
       requests.set(request, state)
       return state
@@ -294,12 +341,14 @@ class ResolutionRouter {
       if (flavor === 'cjs' && nativeResolve !== undefined) {
         try {
           const resolved = nativeResolve()
-          const selected = candidates.find(candidate => localCandidateOwnsResolution(candidate.packageDir, resolved))
+          const selected = candidates.find(candidate => (
+            localCandidateOwnsResolution(candidate.packageDir, resolved, request, name)
+          ))
           if (selected !== undefined) {
             const state = {
               route: { kind: 'native' as const, packageDir: selected.packageDir },
               packageDir: selected.packageDir,
-              cjs: resolved,
+              ...(cacheable ? { cjs: resolved } : {}),
             }
             requests.set(request, state)
             return state
@@ -321,9 +370,10 @@ class ResolutionRouter {
 
     const eligible = target?.scope === 'installation'
       || (target?.scope === 'profile' && parentRoutes.activeProfile)
+    const after = join(dirname(profilesDir), 'package.json')
     const route: ResolutionRoute = eligible
-      ? { kind: 'fallback', entry: target }
-      : { kind: 'after-fallback', parent: join(dirname(profilesDir), 'package.json') }
+      ? { kind: 'fallback', entry: target, after }
+      : { kind: 'after-fallback', parent: after }
     const state: ResolutionRouteState = { route }
     if (route.kind === 'fallback') requests.set(request, state)
     return state
@@ -377,7 +427,9 @@ class ResolutionRouter {
     return this.routeScoped(request, parentRoutes, generation, 'esm')
   }
 
-  routePath(request: string, parent: string, nativeResolve?: () => string): ResolutionRouteState | undefined {
+  routePath(
+    request: string, parent: string, nativeResolve?: () => string, cacheable = false,
+  ): ResolutionRouteState | undefined {
     const generation = this.current
     let parentRoutes = generation.cjsRoutes.get(parent)
     if (parentRoutes === false) return undefined
@@ -403,7 +455,7 @@ class ResolutionRouter {
       generation.cjsRoutes.set(parent, false)
       return undefined
     }
-    return this.routeScoped(request, parentRoutes, generation, 'cjs', nativeResolve)
+    return this.routeScoped(request, parentRoutes, generation, 'cjs', nativeResolve, cacheable)
   }
 
   explicitRoute(
@@ -411,7 +463,7 @@ class ResolutionRouter {
   ): { index: number; state: ResolutionRouteState } | 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))
+      const state = this.routePath(request, parent, nativeResolve(path), false)
       if (state !== undefined) return { index, state }
     }
     return undefined
@@ -442,17 +494,41 @@ function internalModules(): InternalModules {
     getOrInitializeCascadedLoader(): ModuleLoaderV1 | ModuleLoaderV2
   }
   const cjsModule = addon.requireBuiltin('internal/modules/cjs/loader') as { Module: CommonJsModule }
+  const cjsHelpers = addon.requireBuiltin('internal/modules/helpers') as {
+    getCjsConditions(): ReadonlySet<string>
+  }
   const esm = esmModule.getOrInitializeCascadedLoader()
   const modern = 'getOrCreateModuleJob' in esm
   /* v8 ignore start -- the supported Node 22/24/26 matrix validates each available Internal interface */
   if (typeof esm.resolveSync !== 'function'
     || typeof Reflect.get(esm, modern ? 'getOrCreateModuleJob' : 'getModuleJobForImport') !== 'function'
     || (!modern && typeof Reflect.get(esm, 'resolve') !== 'function')
-    || typeof cjsModule.Module._resolveFilename !== 'function') {
+    || typeof cjsModule.Module._resolveFilename !== 'function'
+    || typeof cjsHelpers.getCjsConditions !== 'function') {
     throw new Error('profile resolution: unsupported Node module loader')
   }
   /* v8 ignore stop */
-  return { esm, cjs: cjsModule.Module, modern }
+  return {
+    esm,
+    cjs: cjsModule.Module,
+    cjsConditions: cjsHelpers.getCjsConditions(),
+    modern,
+  }
+}
+
+function throwWithImporter(error: unknown, routedParent: string, parent: string): never {
+  const code = (error as NodeJS.ErrnoException).code
+  if (error instanceof Error && (code === 'ERR_MODULE_NOT_FOUND' || code === 'ERR_PACKAGE_PATH_NOT_EXPORTED')) {
+    const routedPath = fileURLToPath(routedParent)
+    const parentPath = fileURLToPath(parent)
+    const originalMessage = error.message
+    const message = originalMessage.replaceAll(routedParent, parent).replaceAll(routedPath, parentPath)
+    const stack = error.stack
+    error.message = message
+    /* v8 ignore next -- Node's resolver errors always carry a stack */
+    if (stack !== undefined) error.stack = stack.replace(originalMessage, message)
+  }
+  throw error
 }
 
 function assertEquivalent(actual: string, expected: string, request: string, parent: string): void {
@@ -473,7 +549,7 @@ export function installProfileResolution(
   behavior: ProfileResolutionBehavior = 'enforce',
 ): ProfileResolutionRegistration {
   const router = new ResolutionRouter(generation)
-  const { esm, cjs, modern } = internalModules()
+  const { esm, cjs, cjsConditions, modern } = internalModules()
   const esmScope = new Map<string, boolean>()
   const profileUrls = [
     ...prefixes(generation.profilesDir),
@@ -483,66 +559,85 @@ export function installProfileResolution(
   let recentEsmScoped = false
   let delegatedEsm: { parent: string | undefined; request: string } | undefined
 
-  const adaptEsm = (native: EsmResolve): EsmResolve => (request, parent, attributes) => {
-    const delegated = delegatedEsm
-    /* v8 ignore next -- reentry requires a separate synchronous Node hook; supported launches install none */
-    if (delegated !== undefined && delegated.parent === parent && delegated.request === request) {
-      return native(request, parent, attributes)
-    }
-    if (parent === undefined) return native(request, parent, attributes)
-    let scoped = recentEsmParent === parent ? recentEsmScoped : esmScope.get(parent)
-    if (scoped === undefined) {
-      scoped = startsWithin(parent, profileUrls)
-      esmScope.set(parent, scoped)
-    }
-    if (recentEsmParent !== parent) {
-      recentEsmParent = parent
-      recentEsmScoped = scoped
-    }
-    if (!scoped) return native(request, parent, attributes)
-    const state = router.routeUrl(request, parent)
-    if (state === undefined) return native(request, parent, attributes)
-    const cacheable = attributes === EMPTY_ATTRIBUTES || Object.keys(attributes).length === 0
-    if (cacheable && state.esm !== undefined) return state.esm
-    const route = state.route
-    if (route.kind === 'native') {
-      const result = native(request, parent, attributes)
-      if (cacheable && !(result instanceof Promise)) state.esm = result
-      return result
-    }
-    const routedParent = pathToFileURL(route.kind === 'fallback' ? route.entry.declarer : route.parent).href
-    if (behavior === 'enforce') {
+  const adaptEsm = (native: EsmResolve): EsmResolve => {
+    const adapted: EsmResolve = (request, parent, attributes) => {
+      const delegated = delegatedEsm
+      /* v8 ignore next -- reentry requires a separate synchronous Node hook; supported launches install none */
+      if (delegated !== undefined && delegated.parent === parent && delegated.request === request) {
+        return native(request, parent, attributes)
+      }
+      if (parent === undefined) return native(request, parent, attributes)
+      let scoped = recentEsmParent === parent ? recentEsmScoped : esmScope.get(parent)
+      if (scoped === undefined) {
+        scoped = startsWithin(parent, profileUrls)
+        esmScope.set(parent, scoped)
+      }
+      if (recentEsmParent !== parent) {
+        recentEsmParent = parent
+        recentEsmScoped = scoped
+      }
+      if (!scoped) return native(request, parent, attributes)
+      const state = router.routeUrl(request, parent)
+      if (state === undefined) return native(request, parent, attributes)
+      const cacheable = attributes === EMPTY_ATTRIBUTES || Object.keys(attributes).length === 0
+      if (cacheable && state.esm !== undefined) return state.esm
+      const route = state.route
+      if (route.kind === 'native') {
+        const result = native(request, parent, attributes)
+        if (cacheable && !(result instanceof Promise)) state.esm = result
+        return result
+      }
+      const routedParent = pathToFileURL(route.kind === 'fallback' ? route.entry.declarer : route.parent).href
+      if (behavior === 'enforce') {
+        const previous = delegatedEsm
+        delegatedEsm = { parent: routedParent, request }
+        const restoreImporter = (error: unknown): never => throwWithImporter(error, routedParent, parent)
+        try {
+          let result: ResolveResult | Promise<ResolveResult>
+          try {
+            result = native(request, routedParent, attributes)
+          } catch (error) {
+            return restoreImporter(error)
+          }
+          /* v8 ignore next -- Node 24+ resolves synchronously; the Node 22 matrix covers its Promise result */
+          if (result instanceof Promise) return result.catch(restoreImporter)
+          if (cacheable) state.esm = result
+          return result
+        } finally {
+          delegatedEsm = previous
+        }
+      }
+      const actual = native(request, parent, attributes)
       const previous = delegatedEsm
       delegatedEsm = { parent: routedParent, request }
+      const restoreImporter = (error: unknown): never => throwWithImporter(error, routedParent, parent)
       try {
-        const result = native(request, routedParent, attributes)
-        /* v8 ignore next -- Node 24+ resolves synchronously; the Node 22 matrix covers its Promise result */
-        if (cacheable && !(result instanceof Promise)) state.esm = result
-        return result
+        let expected: ResolveResult | Promise<ResolveResult>
+        try {
+          const result = native(request, routedParent, attributes)
+          expected = result
+          /* v8 ignore next -- Node 24+ resolves synchronously; the Node 22 matrix covers its Promise result */
+          if (result instanceof Promise) expected = result.catch(restoreImporter)
+        } catch (error) {
+          return restoreImporter(error)
+        }
+        /* 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)
+            if (cacheable) state.esm = resolved
+            return resolved
+          })
+        }
+        /* v8 ignore stop */
+        assertEquivalent(actual.url, expected.url, request, parent)
+        if (cacheable) state.esm = actual
+        return actual
       } finally {
         delegatedEsm = previous
       }
     }
-    const actual = native(request, parent, attributes)
-    const previous = delegatedEsm
-    delegatedEsm = { parent: routedParent, request }
-    try {
-      const expected = native(request, routedParent, 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)
-          if (cacheable) state.esm = resolved
-          return resolved
-        })
-      }
-      /* v8 ignore stop */
-      assertEquivalent(actual.url, expected.url, request, parent)
-      if (cacheable) state.esm = actual
-      return actual
-    } finally {
-      delegatedEsm = previous
-    }
+    return adapted
   }
 
   let restoreEsm: () => void
@@ -592,15 +687,20 @@ export function installProfileResolution(
     parent: CommonJsParent, main: boolean, options?: CommonJsOptions,
   ): string => {
     const anchor = routed.kind === 'fallback' ? routed.entry.declarer : routed.parent
-    const synthetic = new cjs(anchor, parent)
+    const synthetic = new cjs(anchor)
+    // Late parent assignment preserves Node's require stack without publishing this routing anchor in parent.children.
+    synthetic.parent = parent
     synthetic.filename = anchor
-    synthetic.paths = cjs._nodeModulePaths(dirname(anchor))
+    synthetic.paths = routed.kind === 'fallback'
+      ? [dirname(routed.entry.packageDir)]
+      : cjs._nodeModulePaths(dirname(anchor))
     return originalFilename.call(cjs, request, synthetic, main, options)
   }
   const wrappedFilename: CommonJsModule['_resolveFilename'] = (request, parent, main, options) => {
     if (delegatedCjs || !parent?.filename) {
       return originalFilename.call(cjs, request, parent, main, options)
     }
+    const cacheable = options?.paths === undefined && options?.conditions === undefined
     const explicitPaths = Array.isArray(options?.paths) ? options.paths : undefined
     const explicit = explicitPaths === undefined
       ? undefined
@@ -624,9 +724,19 @@ export function installProfileResolution(
       request,
       parent.filename,
       () => originalFilename.call(cjs, request, parent, main, options),
+      cacheable,
     )
-    if (state === undefined) return originalFilename.call(cjs, request, parent, main, options)
-    const cacheable = options?.paths === undefined && options?.conditions === undefined
+    if (state === undefined) {
+      try {
+        return originalFilename.call(cjs, request, parent, main, options)
+      } catch (error) {
+        if ((error as NodeJS.ErrnoException).code !== 'MODULE_NOT_FOUND' || request[0] !== '#') throw error
+        const conditions = options?.conditions ?? cjsConditions
+        const target = packageImportsTarget(parent.filename, request, conditions)
+        if (target === undefined) throw error
+        return wrappedFilename(target, parent, main, options)
+      }
+    }
     if (cacheable && state.cjs !== undefined) return state.cjs
     const route = state.route
     if (route.kind === 'native') {
@@ -650,7 +760,15 @@ export function installProfileResolution(
     delegatedCjs++
     try {
       const routedOptions = options?.conditions === undefined ? undefined : { conditions: options.conditions }
-      const expected = resolveRoutedCjs(request, route, parent, main, routedOptions)
+      let expected: string
+      try {
+        expected = resolveRoutedCjs(request, route, parent, main, routedOptions)
+      } catch (error) {
+        if (route.kind !== 'fallback' || (error as NodeJS.ErrnoException).code !== 'MODULE_NOT_FOUND') throw error
+        expected = resolveRoutedCjs(
+          request, { kind: 'after-fallback', parent: route.after }, parent, main, routedOptions,
+        )
+      }
       if (behavior === 'enforce') {
         if (cacheable) state.cjs = expected
         return expected

+ 294 - 11
packages/boot/app-boot/tests/profile-resolution.spec.ts

@@ -1,10 +1,19 @@
 /** Runtime profile resolution uses one eager generation for ESM and CommonJS. */
 
-import { existsSync, mkdirSync, mkdtempSync, realpathSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'
+import {
+  existsSync,
+  mkdirSync,
+  mkdtempSync,
+  realpathSync,
+  rmSync,
+  symlinkSync,
+  unlinkSync,
+  writeFileSync,
+} from 'node:fs'
 import { createRequire } from 'node:module'
 import { tmpdir } from 'node:os'
 import { dirname, join } from 'node:path'
-import { pathToFileURL } from 'node:url'
+import { fileURLToPath, pathToFileURL } from 'node:url'
 import { getEnvironmentData } from 'node:worker_threads'
 import { afterEach, describe, expect, it } from 'vitest'
 import {
@@ -100,6 +109,15 @@ function resolveFrom(
     : internal.resolveSync(parent, { specifier, attributes }).url
 }
 
+function thrownMessage(callback: () => unknown): string {
+  try {
+    callback()
+  } catch (error) {
+    return (error as Error).message
+  }
+  throw new Error('expected callback to throw')
+}
+
 function fixture(name = 'resolution-lib'): {
   root: string
   installAnchor: string
@@ -247,6 +265,8 @@ describe('profile resolution generation', { concurrent: false }, () => {
     expect(require.resolve('resolution-lib')).toBe(join(f.installed, 'index.cjs'))
     const parent = pathToFileURL(join(f.profile.dir, 'entry.mjs')).href
     expect(resolveFrom('resolution-lib', parent)).toBe(pathToFileURL(join(f.installed, 'index.js')).href)
+    expect(resolveFrom('resolution-lib', parent, { type: 'javascript' }))
+      .toBe(pathToFileURL(join(f.installed, 'index.js')).href)
     expect(resolveFrom('resolution-lib', parent)).toBe(pathToFileURL(join(f.installed, 'index.js')).href)
     expect(import.meta.resolve('resolution-lib', parent)).toBe(pathToFileURL(join(f.installed, 'index.js')).href)
     expect(await importFrom('resolution-lib', parent)).toMatchObject({ marker: 1 })
@@ -335,11 +355,12 @@ describe('profile resolution generation', { concurrent: false }, () => {
     }))
     const alias = join(f.profile.dir, 'node_modules', 'alias')
     pkg(alias, 'real-name', 6)
-    const generation = await generationOf(f)
+    const generation = await healProfilesModuleFallback({
+      installAnchor: f.installAnchor,
+      profile: f.profile,
+      home: f.root,
+    })
     expect(generation.localPackageNames).toEqual(['alias'])
-    const registration = installProfileResolution(generation)
-    registrations.push(registration)
-
     const require = createRequire(join(alias, 'inside.cjs'))
     expect(require.resolve('real-name')).toBe(join(alias, 'index.cjs'))
     expect(resolveFrom('real-name', pathToFileURL(join(alias, 'inside.mjs')).href)).toBe(
@@ -347,10 +368,71 @@ describe('profile resolution generation', { concurrent: false }, () => {
     )
     const invalidScope = join(f.profile.dir, 'node_modules', 'invalid-scope')
     file(join(invalidScope, 'package.json'), '{')
-    expect(createRequire(join(invalidScope, 'inside.cjs')).resolve('resolution-lib'))
-      .toBe(join(f.installed, 'index.cjs'))
+    expect(() => createRequire(join(invalidScope, 'inside.cjs')).resolve('resolution-lib'))
+      .toThrow(/Invalid package config/u)
     expect(() => resolveFrom('resolution-lib', pathToFileURL(join(invalidScope, 'inside.mjs')).href))
       .toThrow(/Invalid package config/u)
+    unlinkSync(join(generation.profilesDir, 'node_modules', 'resolution-lib'))
+
+    const registration = installProfileResolution(generation)
+    registrations.push(registration)
+    expect(require.resolve('real-name')).toBe(join(alias, 'index.cjs'))
+    expect(resolveFrom('real-name', pathToFileURL(join(alias, 'inside.mjs')).href)).toBe(
+      pathToFileURL(join(alias, 'index.js')).href,
+    )
+    expect(() => createRequire(join(invalidScope, 'inside.cjs')).resolve('resolution-lib'))
+      .toThrow(/Invalid package config/u)
+    expect(() => resolveFrom('resolution-lib', pathToFileURL(join(invalidScope, 'inside.mjs')).href))
+      .toThrow(/Invalid package config/u)
+  })
+
+  it('keeps package imports aliases on the generation route', 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 nested = join(f.profile.dir, 'nested')
+    const require = createRequire(join(nested, 'entry.cjs'))
+    const parent = pathToFileURL(join(nested, 'entry.mjs')).href
+    expect(require.resolve('#resolution-lib')).toBe(join(f.installed, 'index.cjs'))
+    expect(resolveFrom('#resolution-lib', parent)).toBe(pathToFileURL(join(f.installed, 'index.js')).href)
+    unlinkSync(join(generation.profilesDir, 'node_modules', 'resolution-lib'))
+
+    const registration = installProfileResolution(generation)
+    registrations.push(registration)
+    expect(require.resolve('#resolution-lib')).toBe(join(f.installed, 'index.cjs'))
+    expect(resolveFrom('#resolution-lib', parent)).toBe(pathToFileURL(join(f.installed, 'index.js')).href)
+  })
+
+  it('leaves relative package imports targets and their diagnostics to Node', async () => {
+    const f = fixture()
+    file(join(f.profile.dir, 'package.json'), JSON.stringify({
+      name: 'test-profile',
+      private: true,
+      imports: { '#missing-relative': './missing.cjs' },
+    }))
+    const generation = await healProfilesModuleFallback({
+      installAnchor: f.installAnchor,
+      profile: f.profile,
+      home: f.root,
+    })
+    const require = createRequire(join(f.profile.dir, 'entry.cjs'))
+    const parent = pathToFileURL(join(f.profile.dir, 'entry.mjs')).href
+    const cjsMessage = thrownMessage(() => require.resolve('#missing-relative'))
+    const esmMessage = thrownMessage(() => resolveFrom('#missing-relative', parent))
+    unlinkSync(join(generation.profilesDir, 'node_modules', 'resolution-lib'))
+
+    const registration = installProfileResolution(generation)
+    registrations.push(registration)
+    expect(thrownMessage(() => require.resolve('#missing-relative'))).toBe(cjsMessage)
+    expect(thrownMessage(() => resolveFrom('#missing-relative', parent))).toBe(esmMessage)
   })
 
   it('falls through a missing local CommonJS subpath to the generation', async () => {
@@ -442,6 +524,60 @@ describe('profile resolution generation', { concurrent: false }, () => {
     expect(createRequire(join(f.profile.dir, 'entry.cjs'))('resolution-lib')).toEqual({ marker: 2 })
   })
 
+  it('keeps a manifestless local CommonJS subpath ahead of the generation', async () => {
+    const f = fixture()
+    const localSubpath = join(f.profile.dir, 'node_modules', 'resolution-lib', 'sub.cjs')
+    file(localSubpath, 'module.exports = { marker: 2 }\n')
+    const require = createRequire(join(f.profile.dir, 'entry.cjs'))
+    expect(require.resolve('resolution-lib/sub.cjs')).toBe(localSubpath)
+
+    const registration = installProfileResolution(await generationOf(f))
+    registrations.push(registration)
+    expect(require.resolve('resolution-lib/sub.cjs')).toBe(localSubpath)
+  })
+
+  it('keeps a local extensionless CommonJS package ahead of the generation', async () => {
+    const f = fixture()
+    const local = join(f.profile.dir, 'node_modules', 'resolution-lib')
+    file(local, 'module.exports = { marker: 2 }\n')
+    const require = createRequire(join(f.profile.dir, 'entry.cjs'))
+    expect(require.resolve('resolution-lib')).toBe(local)
+
+    const registration = installProfileResolution(await generationOf(f))
+    registrations.push(registration)
+    expect(require.resolve('resolution-lib')).toBe(local)
+  })
+
+  it('keeps a local legacy main outside its package directory ahead of the generation', async () => {
+    const f = fixture()
+    const local = join(f.profile.dir, 'node_modules', 'resolution-lib')
+    const outside = join(f.profile.dir, 'node_modules', 'outside.cjs')
+    file(join(local, 'package.json'), JSON.stringify({ name: 'resolution-lib', main: '../outside.cjs' }))
+    file(outside, 'module.exports = { marker: 2 }\n')
+    const require = createRequire(join(f.profile.dir, 'entry.cjs'))
+    expect(require.resolve('resolution-lib')).toBe(outside)
+
+    const registration = installProfileResolution(await generationOf(f))
+    registrations.push(registration)
+    expect(require.resolve('resolution-lib')).toBe(outside)
+  })
+
+  it('falls through a missing local legacy main to the generation', async () => {
+    const f = fixture()
+    const local = join(f.profile.dir, 'node_modules', 'resolution-lib')
+    file(join(local, 'package.json'), JSON.stringify({ name: 'resolution-lib', main: './missing.cjs' }))
+    const generation = await healProfilesModuleFallback({
+      installAnchor: f.installAnchor,
+      profile: f.profile,
+      home: f.root,
+    })
+    const registration = installProfileResolution(generation)
+    registrations.push(registration)
+
+    expect(createRequire(join(f.profile.dir, 'entry.cjs')).resolve('resolution-lib'))
+      .toBe(join(f.installed, 'index.cjs'))
+  })
+
   it('keeps a profile-local CommonJS package file ahead of the generation', async () => {
     const f = fixture()
     file(join(f.profile.dir, 'node_modules', 'resolution-lib.js'), 'module.exports = { marker: 2 }\n')
@@ -510,6 +646,40 @@ describe('profile resolution generation', { concurrent: false }, () => {
       .toMatchObject({ marker: 1 })
   })
 
+  it('continues the original ancestor lookup after a generation subpath miss', async () => {
+    const f = fixture()
+    const home = join(f.root, 'home')
+    const profileDir = join(home, 'profiles', 'test')
+    const profile = {
+      ...f.profile,
+      dir: profileDir,
+      patchPath: join(profileDir, 'cordis.patch.yml'),
+    }
+    file(join(profileDir, 'package.json'), JSON.stringify({ name: 'test-profile', private: true }))
+    file(join(profileDir, 'node_modules', 'resolution-lib', 'package.json'), JSON.stringify({
+      name: 'resolution-lib', version: '2.0.0',
+    }))
+    file(join(f.installed, 'package.json'), JSON.stringify({
+      name: 'resolution-lib', version: '1.0.0', type: 'module', main: './index.cjs',
+    }))
+    const ancestorSubpath = join(home, 'node_modules', 'resolution-lib', 'sub.cjs')
+    file(ancestorSubpath, 'module.exports = { marker: 3 }\n')
+    const generation = await healProfilesModuleFallback({
+      installAnchor: f.installAnchor,
+      profile,
+      home,
+    })
+    const require = createRequire(join(profileDir, 'entry.cjs'))
+    expect(require.resolve('resolution-lib')).toBe(join(f.installed, 'index.cjs'))
+    expect(require.resolve('resolution-lib/sub.cjs')).toBe(ancestorSubpath)
+    unlinkSync(join(generation.profilesDir, 'node_modules', 'resolution-lib'))
+
+    const registration = installProfileResolution(generation)
+    registrations.push(registration)
+    expect(require.resolve('resolution-lib')).toBe(join(f.installed, 'index.cjs'))
+    expect(require.resolve('resolution-lib/sub.cjs')).toBe(ancestorSubpath)
+  })
+
   it('skips stale shared and profile-owned fallback entries when the generation misses', async () => {
     const f = fixture()
     pkg(join(f.root, 'profiles', 'node_modules', 'stale-shared'), 'stale-shared', 9)
@@ -560,12 +730,12 @@ describe('profile resolution generation', { concurrent: false }, () => {
   it('leaves conditional exports to Node', async () => {
     const f = fixture('conditional-lib')
     conditionalPkg(f.installed, 'conditional-lib', 11, 12)
+    const local = join(f.profile.dir, 'node_modules', 'conditional-lib')
+    conditionalPkg(local, 'conditional-lib', 21, 22)
     const registration = installProfileResolution(await generationOf(f))
     registrations.push(registration)
-    const require = createRequire(join(f.profile.dir, 'entry.cjs'))
-    expect(require('conditional-lib')).toEqual({ marker: 12 })
     expect(await importFrom('conditional-lib', pathToFileURL(join(f.profile.dir, 'entry.mjs')).href))
-      .toMatchObject({ marker: 11 })
+      .toMatchObject({ marker: 21 })
     const addon = createRequire(import.meta.url)('node-addon-require-builtin') as { requireBuiltin(id: string): unknown }
     const internal = addon.requireBuiltin('internal/modules/cjs/loader') as {
       Module: {
@@ -583,11 +753,103 @@ describe('profile resolution generation', { concurrent: false }, () => {
     const parent = new internal.Module(parentFile)
     parent.filename = parentFile
     parent.paths = internal.Module._nodeModulePaths(f.profile.dir)
+    expect(internal.Module._resolveFilename(
+      'conditional-lib', parent, false, { conditions: new Set(['node', 'require', 'custom']) },
+    )).toBe(join(local, 'custom.cjs'))
+    const require = createRequire(join(f.profile.dir, 'entry.cjs'))
+    expect(require('conditional-lib')).toEqual({ marker: 22 })
+    expect(require.resolve('conditional-lib')).toBe(join(local, 'require.cjs'))
+  })
+
+  it('passes explicit CommonJS conditions to the generation target', async () => {
+    const f = fixture('conditional-lib')
+    conditionalPkg(f.installed, 'conditional-lib', 11, 12)
+    const registration = installProfileResolution(await generationOf(f))
+    registrations.push(registration)
+    const addon = createRequire(import.meta.url)('node-addon-require-builtin') as { requireBuiltin(id: string): unknown }
+    const internal = addon.requireBuiltin('internal/modules/cjs/loader') as {
+      Module: {
+        new(id?: string): { filename?: string; paths?: string[] }
+        _nodeModulePaths(path: string): string[]
+        _resolveFilename(
+          request: string,
+          parent: { filename?: string; paths?: string[] },
+          isMain: boolean,
+          options: { conditions: Set<string> },
+        ): string
+      }
+    }
+    const parentFile = join(f.profile.dir, 'conditional-entry.cjs')
+    const parent = new internal.Module(parentFile)
+    parent.filename = parentFile
+    parent.paths = internal.Module._nodeModulePaths(f.profile.dir)
+
     expect(internal.Module._resolveFilename(
       'conditional-lib', parent, false, { conditions: new Set(['node', 'require', 'custom']) },
     )).toBe(join(f.installed, 'custom.cjs'))
   })
 
+  it('does not attach routed CommonJS anchors to the importing module', async () => {
+    const f = fixture()
+    const registration = installProfileResolution(await generationOf(f))
+    registrations.push(registration)
+    const addon = createRequire(import.meta.url)('node-addon-require-builtin') as { requireBuiltin(id: string): unknown }
+    const internal = addon.requireBuiltin('internal/modules/cjs/loader') as {
+      Module: {
+        new(id?: string): { children: unknown[]; filename?: string; paths?: string[] }
+        _nodeModulePaths(path: string): string[]
+        _resolveFilename(
+          request: string,
+          parent: { children: unknown[]; filename?: string; paths?: string[] },
+          isMain: boolean,
+        ): string
+      }
+    }
+    const parentFile = join(f.profile.dir, 'entry.cjs')
+    const parent = new internal.Module(parentFile)
+    parent.filename = parentFile
+    parent.paths = internal.Module._nodeModulePaths(f.profile.dir)
+    const originalChildren = [...parent.children]
+
+    expect(internal.Module._resolveFilename('resolution-lib', parent, false)).toBe(join(f.installed, 'index.cjs'))
+    expect(parent.children).toEqual(originalChildren)
+  })
+
+  it('reports routed ESM failures from the original importer', async () => {
+    const f = fixture()
+    const parent = pathToFileURL(join(f.profile.dir, 'entry.mjs')).href
+    const linkMessage = thrownMessage(() => resolveFrom('unavailable-lib', parent))
+    const generation = await healProfilesModuleFallback({
+      installAnchor: f.installAnchor,
+      profile: f.profile,
+      home: f.root,
+    })
+    unlinkSync(join(generation.profilesDir, 'node_modules', 'resolution-lib'))
+    const registration = installProfileResolution(generation)
+    registrations.push(registration)
+
+    expect(thrownMessage(() => resolveFrom('unavailable-lib', parent))).toBe(linkMessage)
+    expect(thrownMessage(() => resolveFrom('resolution-lib/private', parent)))
+      .toContain(` imported from ${fileURLToPath(parent)}`)
+  })
+
+  it('leaves an invalid generation manifest error to Node', async () => {
+    const f = fixture()
+    const generation = await healProfilesModuleFallback({
+      installAnchor: f.installAnchor,
+      profile: f.profile,
+      home: f.root,
+    })
+    file(join(f.installed, 'package.json'), '{')
+    const parent = pathToFileURL(join(f.profile.dir, 'entry.mjs')).href
+    expect(() => resolveFrom('resolution-lib', parent)).toThrow(/Invalid package config/u)
+    unlinkSync(join(generation.profilesDir, 'node_modules', 'resolution-lib'))
+    const registration = installProfileResolution(generation)
+    registrations.push(registration)
+
+    expect(() => resolveFrom('resolution-lib', parent)).toThrow(/Invalid package config/u)
+  })
+
   it('does not fall back after Node selects a broken profile-local package', async () => {
     const f = fixture('broken-lib')
     file(join(f.profile.dir, 'node_modules', 'broken-lib', 'package.json'), JSON.stringify({
@@ -627,6 +889,27 @@ describe('profile resolution generation', { concurrent: false }, () => {
     )).rejects.toThrow(/profile resolution mismatch/u)
   })
 
+  it('reports a missing dual-mode generation target from the original importer', async () => {
+    const f = fixture()
+    const disk = await healProfilesModuleFallback({
+      installAnchor: f.installAnchor,
+      profile: f.profile,
+      home: f.root,
+    })
+    const missing = join(f.root, 'missing')
+    const mismatched = {
+      ...disk,
+      entries: disk.entries.map(entry => entry.name === 'resolution-lib'
+        ? { ...entry, packageDir: missing, declarer: join(missing, 'package.json') }
+        : entry),
+    }
+    const registration = installProfileResolution(mismatched, 'verify')
+    registrations.push(registration)
+    const parent = pathToFileURL(join(f.profile.dir, 'entry.mjs')).href
+
+    expect(thrownMessage(() => resolveFrom('resolution-lib', parent))).toContain(fileURLToPath(parent))
+  })
+
   it('accepts matching disk and generation targets in dual mode', async () => {
     const f = fixture()
     const generation = await healProfilesModuleFallback({

+ 7 - 0
scripts/run-gates.ts

@@ -386,6 +386,13 @@ function nodeCompatSmokeGates(options: { cliSmoke?: boolean } = {}): Gate[] {
       'run',
       'scripts/vitest-environment.compat.spec.ts',
     ], { label: 'Vitest jsdom smoke' }),
+    pnpmExec('profile-resolution-smoke', [
+      'vitest',
+      'run',
+      'packages/boot/app-boot/tests/profile-resolution.spec.ts',
+      'packages/boot/app-boot/tests/profile-resolution-service.spec.ts',
+      'packages/boot/app-boot/tests/profile-resolution-worker-bootstrap.spec.ts',
+    ], { label: 'profile resolution smoke' }),
   ]
   if (options.cliSmoke) {
     gates.push(