The site
pi reports packages/ai/src/utils/provider-env.ts:26:17 - error SC1090: library functions as values (call 'readFileSync' directly) in every round of its build (round 1 has 193 diagnostics, round 2 76, round 3 67; only the last round's list is printed). It is not a round-3 artifact.
Root cause
islandModuleFile's bare-specifier branch resolved with the runtime-JS pass only. For a workspace package whose exports map points a subpath at TypeScript source ("./utils/*": { "types": "./src/utils/*.ts", "import": "./src/utils/*.ts" }), that pass answers nothing — pi's packages/ai has no runnable JS entry. An import of an island module over such a bare subpath (cache-warmer.ts:10) therefore never bound to the island, and the island module's body was compiled natively, where readFileSync's cast-typed callee hits the library-function-as-value fence.
Relative specifiers take relativeIslandFile and work, which is why the earlier isolated probes and corpus program did not reproduce it.
Fix
lower-node-island.ts, islandModuleFile, bare branch: when the runtime-JS pass answers nothing, fall back to resolveBareModule(..., "runtime-source", ...) and accept the answer only if islandOwnerOfFile names an island, so an unrelated resolution can never become an island import. An early return when the island set owns no packages keeps programs without islands on exactly the old path. The fallback answers import edges only (7adc37cc4, from review): it resolves with Node's import conditions, and a package may map "require" to another file, so a require() keeps the answer it had before, which binds nothing.
Evidence
- New differential corpus program
tests/corpus/8998-node-island-workspace-reader/: a workspace package@probe/aimapping./utils/*to TS source, an island reader module that reads through a patchedfs.readFileSync, and a native module importing it by bare subpath. It fails to compile before the change and matches Node after (differential.test.ts -t 8998-node-island-workspace-reader→ 1 passed). node-islandsunit tests: 161 passed. Node island harness: 34 passed, 1 failed (Node ignores NODE_OPTIONS from the program's environment), which fails identically on the unmodified compiler.pnpm test:ts7 --baselines-onlycomplete;order-parity.test.ts121/121 passed.- New unit test
packages/compiler/src/frontend/lowering/lower-node-island.test.ts: a workspace package whoseexportsmap names one source file for"import"and another for"require". The import edge answers the island file; the require edge answers nothing. Without the import-only guard the require case returns the import's file (1 failed, 2 passed); with it 3 passed.node-islandsunit tests with it: 164 passed. - On 7adc37cc4 in a sandbox:
differential.test.ts -t 8998-node-island-workspace-readerpasses plain and underSCRIPTC_SAN=1;differential.test.ts -t node-islandis 78 passed, 1 failed. The failure is6863-node-island-native-arrays(V8Check failed: isolate_->IsOnCentralStack()inside the sandbox's libnode pack); it fails the same way with the guard removed, and CI passes it.pnpm lintandpnpm format:checkare clean. - Zero-cost gate (
bin/validate --skip=lanes,bench,t262,san-bootstrap --gate-corpus=all) on 7adc37cc4: PASS in 14.1 min — 5175 identical, 95 both-fail over 8 shards, no differing program, noruntime-onlyrow; bench geomean −0.04 %, fixtures geomean +0.38 %, self +1.75 % (reported inconclusive; the compiler's own build has no island set, so it never reaches the changed branch). The same gate passed on 8567c8677 (18.1 min) and d7c9d1fcf (20.4 min). - The native bootstraps were not run for this PR. An earlier version of this description said the second gate run included them; it did not (
--skip=lanesleaves them out). The change is reached only with a non-empty island set, which the compiler's own build does not have. - pi: 67 → 66 diagnostics, and
diffof the two lists is exactly theprovider-env.ts:26:17line. No other diagnostic changed.
🤖 Generated with Claude Code
The latest updates on your projects. Learn more about Vercel for GitHub.