From b388156593cdfecddead67818ec0f5574bbd9fc4 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Thu, 22 Oct 2026 19:08:34 -0700 Subject: [PATCH] Make packages islands only for fences that surely fire; keep jose and run-node native without pins A gap fence inside a function body may never run, so it no longer makes its package a Node island under --node-islands=auto: only fences in top-level module code and fences that need the JavaScript runtime do. The package's island class still decides after a failed build. Typed packages like jose stay native (DECISIONS.md, 2026-10-21), so the corpus pins of jose and run-node are gone. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/src/executable/prepare.ts | 16 ++++++++++++---- tests/corpus/6331-jose-root-entry/package.json | 1 - .../6610-npm-execa-child-mixin/package.json | 1 - 3 files changed, 12 insertions(+), 6 deletions(-) delete mode 100644 tests/corpus/6331-jose-root-entry/package.json delete mode 100644 tests/corpus/6610-npm-execa-child-mixin/package.json diff --git a/packages/compiler/src/executable/prepare.ts b/packages/compiler/src/executable/prepare.ts index 90504d0ef..5f3e45c9a 100644 --- a/packages/compiler/src/executable/prepare.ts +++ b/packages/compiler/src/executable/prepare.ts @@ -461,10 +461,13 @@ function preflightIslands( /** Packages compiled natively with runtime fences (refusals deferred to the * operation that reaches them) that should run in islands instead: those - * whose island class is runtime (R1) or object-model (R2), by NI-2's report - * over the pre-scan markers and the fences, or with a fence that itself - * needs the runtime. Gap-only packages keep their fences until decision 8 - * (D6) retires them. `--node-islands=auto` only; null for none. */ + * with a fence that surely fires (one in top-level module code, which runs + * when the module evaluates) or that itself needs the runtime (R1). Other + * fences stay deferred refusals until decision 8 (D6) retires them, so + * typed packages like jose stay native. With `requireFence` false (after a + * failed build) the package's island class by NI-2's report decides + * instead: runtime (R1) or object-model (R2). `--node-islands=auto` only; + * null for none. */ function fenceIslands( entryPath: string, opts: CompileRequestOptions, @@ -515,6 +518,11 @@ function fenceIslands( if (runtimeFence === undefined || island.path === null) continue; if (!compiled.has(island.package) || known.has(island.package)) continue; if (policy.forcedNative.has(island.package) || policy.unloaded.has(island.package)) continue; + // With fences (requireFence), only fences that surely fire count: a + // gap fence inside a function body may never run (jose's typed paths + // stay native, DECISIONS.md 2026-10-21). After a failed build + // (!requireFence), the package's report class decides. + if (requireFence && !runtimeFence) continue; if (!runtimeFence && island.class !== "runtime" && island.class !== "object-model") continue; grown.set(island.package, { name: island.package, diff --git a/tests/corpus/6331-jose-root-entry/package.json b/tests/corpus/6331-jose-root-entry/package.json deleted file mode 100644 index 30d3e0af0..000000000 --- a/tests/corpus/6331-jose-root-entry/package.json +++ /dev/null @@ -1 +0,0 @@ -{ "type": "module", "scriptc": { "packages": { "jose": "native" } } } diff --git a/tests/corpus/6610-npm-execa-child-mixin/package.json b/tests/corpus/6610-npm-execa-child-mixin/package.json deleted file mode 100644 index 5a418a30c..000000000 --- a/tests/corpus/6610-npm-execa-child-mixin/package.json +++ /dev/null @@ -1 +0,0 @@ -{ "type": "module", "scriptc": { "packages": { "run-node": "native" } } }