Build the large compiler tables on first use

The native compiler ran four large module initializers at every startup:
the builtin call signatures (LIB_FN_SIGS), the Node 24 fetch
compatibility profile, and the builtin module function and ambient
surface tables. Together their init functions are about 1.3 MB of code,
and --version and warm cache-hit builds paged them in and built the
tables without reading them.

Each table is now built by a function on its first call and kept in a
module variable:

- libFnSignatures() replaces LIB_FN_SIGS
- node24FetchCompatProfile() and staticFetchMembers() replace
  NODE24_FETCH_COMPAT_PROFILE and the STATIC_* member sets
- builtinModuleFns() and ambientSurfaceFns() replace BUILTIN_MODULE_FNS
  and AMBIENT_SURFACE_FNS

The @scriptc/compiler entry point keeps LIB_FN_SIGS and
NODE24_FETCH_COMPAT_PROFILE as deprecated constants built from the new
functions when the entry module loads. The native compiler does not load
that module.

The surface manifest's coverage notes read the fetch target through the
profile function, so building the manifest module no longer builds the
profile. The table contents are unchanged.
This commit is contained in:
Chris Tate
2026-10-25 05:23:35 -05:00
parent c3d778b615
commit 9abf35f6a2
18 changed files with 7525 additions and 7406 deletions
File diff suppressed because it is too large Load Diff
@@ -39,14 +39,14 @@ import { InternalCompilerError } from "../errors.js";
* byte-deterministic: entries sort by id, keys are emitted in one fixed
* order, and the output carries no timestamps or absolute paths. */
import { FENCE_CODES, UNSUPPORTED, webAssemblyDiag } from "../diagnostics/diagnostic.js";
import { NODE24_FETCH_COMPAT_PROFILE } from "../compat/fetch-profile.js";
import { node24FetchCompatProfile } from "../compat/fetch-profile.js";
import { SUPPORTED_BUILTIN_MODULES, SUPPORTED_NODE_MODULES } from "../frontend/builtin-modules.js";
import {
AMBIENT_SURFACE_FNS,
ambientSurfaceFns,
ARRAY_METHODS,
BUILTIN_MODULE_CONSTS,
BUILTIN_MODULE_FENCE_HINTS,
BUILTIN_MODULE_FNS,
builtinModuleFns,
COLLECTION_ITERATOR_METHODS,
COMPOUND_ASSIGN_OPS,
STDLIB_SURFACE,
@@ -88,18 +88,21 @@ export const MANIFEST_SCHEMA_VERSION = 2;
/** The manifest's own scope statement: what the projection covers and —
* just as load-bearing — what it deliberately leaves out, so absence is
* never read as a support claim in either direction. */
const COVERAGE_NOTES: string[] = [
"Entries are projected mechanically from the compiler's own decision tables: the diagnostics registry, the unsupported-syntax dispatch tables, the stdlib and node-builtin lowering tables, and the supported-builtin-module list. Nothing is hand-maintained; the manifest regenerates byte-identically from the source tree at this version.",
"Absence from this manifest means 'not projected', never 'unsupported'. Surfaces lowered through dedicated code paths rather than tables are not yet projected: console, JSON, Promise/async and the timer surface, the net/http/tls/https/dgram/dns/assert/test/stream/readline module member surfaces, template literals, the regex slice, global functions (parseInt, parseFloat, isNaN, isFinite), and the process surface outside its ambient slice.",
"The ambient-nondeterminism and ambient-authority surfaces the library sidecar's determinism attestation scans ARE projected even where they lower through dedicated code paths — the Date compositions (stdlib.date.*), perf_hooks' performance.now, and the process global's ambient reads and authority calls (node-builtin.process.*) — so a determinism fence can name every surface the attestation demotes on.",
"stdlib and node-builtin member entries name surface whose LOWERED call forms are constrained (arity, argument shapes); declared call forms outside the lowered set are refused per site, with code SC2020 for standard-library and node-builtin surface.",
"Entries with status 'unsupported' describe where the named code is raised: forms of the construct outside the supported subset are refused with that code — not that every form of the named feature is refused. Supported forms appear as their own static entries where a table projects them.",
`The engine-free fetch projection targets Node ${NODE24_FETCH_COMPAT_PROFILE.target.node} with bundled Undici ${NODE24_FETCH_COMPAT_PROFILE.target.undici}. Each projected row names the differential evidence that guards it; changing the pinned Node or Undici version is an explicit profile update.`,
"The fetch profile also contains a runtime-reflected census of the selected fetch, abort, Headers, and readable-stream interfaces plus RequestInit/ResponseInit dictionary reads. Static and unsupported census rows are projected here; its explicitly out-of-scope metadata rows and adjacent-interface exclusions remain in the profile so absence is deliberate rather than ambiguous.",
"Process-level diagnostic codes are not surface entries: SC0001-SC0004 are preflight gates, SC1110 is a comptime evaluation failure, SC3001/SC3002 are backend/target tier refusals, SC9001/SC9002 are internal errors.",
"Entry statuses are projected for the desktop targets. The mobile targets (aarch64-apple-ios, aarch64-apple-ios-simulator, aarch64-linux-android) compile library-mode archives only: the library-admissible surface (what SC4005's async_free requirement and the library link set admit) is supported there, the executable lane refuses those triples with SC3002, and no entry outside the library-admissible surface carries a mobile support claim. iOS archives build for iOS 15.0 on darwin hosts; Android archives build against NDK API level 26.",
"No scheduling metadata is published; entry ids are the stable diff keys across releases.",
];
function coverageNotes(): string[] {
const fetchTarget = node24FetchCompatProfile().target;
return [
"Entries are projected mechanically from the compiler's own decision tables: the diagnostics registry, the unsupported-syntax dispatch tables, the stdlib and node-builtin lowering tables, and the supported-builtin-module list. Nothing is hand-maintained; the manifest regenerates byte-identically from the source tree at this version.",
"Absence from this manifest means 'not projected', never 'unsupported'. Surfaces lowered through dedicated code paths rather than tables are not yet projected: console, JSON, Promise/async and the timer surface, the net/http/tls/https/dgram/dns/assert/test/stream/readline module member surfaces, template literals, the regex slice, global functions (parseInt, parseFloat, isNaN, isFinite), and the process surface outside its ambient slice.",
"The ambient-nondeterminism and ambient-authority surfaces the library sidecar's determinism attestation scans ARE projected even where they lower through dedicated code paths — the Date compositions (stdlib.date.*), perf_hooks' performance.now, and the process global's ambient reads and authority calls (node-builtin.process.*) — so a determinism fence can name every surface the attestation demotes on.",
"stdlib and node-builtin member entries name surface whose LOWERED call forms are constrained (arity, argument shapes); declared call forms outside the lowered set are refused per site, with code SC2020 for standard-library and node-builtin surface.",
"Entries with status 'unsupported' describe where the named code is raised: forms of the construct outside the supported subset are refused with that code — not that every form of the named feature is refused. Supported forms appear as their own static entries where a table projects them.",
`The engine-free fetch projection targets Node ${fetchTarget.node} with bundled Undici ${fetchTarget.undici}. Each projected row names the differential evidence that guards it; changing the pinned Node or Undici version is an explicit profile update.`,
"The fetch profile also contains a runtime-reflected census of the selected fetch, abort, Headers, and readable-stream interfaces plus RequestInit/ResponseInit dictionary reads. Static and unsupported census rows are projected here; its explicitly out-of-scope metadata rows and adjacent-interface exclusions remain in the profile so absence is deliberate rather than ambiguous.",
"Process-level diagnostic codes are not surface entries: SC0001-SC0004 are preflight gates, SC1110 is a comptime evaluation failure, SC3001/SC3002 are backend/target tier refusals, SC9001/SC9002 are internal errors.",
"Entry statuses are projected for the desktop targets. The mobile targets (aarch64-apple-ios, aarch64-apple-ios-simulator, aarch64-linux-android) compile library-mode archives only: the library-admissible surface (what SC4005's async_free requirement and the library link set admit) is supported there, the executable lane refuses those triples with SC3002, and no entry outside the library-admissible surface carries a mobile support claim. iOS archives build for iOS 15.0 on darwin hosts; Android archives build against NDK API level 26.",
"No scheduling metadata is published; entry ids are the stable diff keys across releases.",
];
}
/** Stable kebab id segment from prose: quotes dropped, the parenthetical
* tail dropped, non-alphanumeric runs collapsed to one dash. */
@@ -410,7 +413,7 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes
: "recognized module (bare and node:-prefixed specifiers)",
});
}
for (const [mod, members] of Object.entries(BUILTIN_MODULE_FNS)) {
for (const [mod, members] of Object.entries(builtinModuleFns())) {
for (const member of Object.keys(members!)) {
add({
id: `${moduleId(mod)}.${member}`,
@@ -459,10 +462,9 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes
}
// ── fetch/Web platform: one explicit, versioned compatibility profile ─
const fetchTarget =
`Node ${NODE24_FETCH_COMPAT_PROFILE.target.node} / ` +
`Undici ${NODE24_FETCH_COMPAT_PROFILE.target.undici}`;
for (const operation of NODE24_FETCH_COMPAT_PROFILE.operations) {
const fetchProfile = node24FetchCompatProfile();
const fetchTarget = `Node ${fetchProfile.target.node} / Undici ${fetchProfile.target.undici}`;
for (const operation of fetchProfile.operations) {
const evidence = operation.evidence.map((item) =>
item.generated !== undefined ? `generated:${item.generated}` : `fixture:${item.fixture!}`,
);
@@ -478,10 +480,7 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes
`differential evidence: ${evidence.join(", ")}`,
});
}
for (const options of [
NODE24_FETCH_COMPAT_PROFILE.requestInit,
NODE24_FETCH_COMPAT_PROFILE.responseInit,
]) {
for (const options of [fetchProfile.requestInit, fetchProfile.responseInit]) {
for (const option of options) {
const evidence = option.evidence.map((item) =>
item.generated !== undefined ? `generated:${item.generated}` : `fixture:${item.fixture!}`,
@@ -497,7 +496,7 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes
});
}
}
for (const row of NODE24_FETCH_COMPAT_PROFILE.inventory.entries) {
for (const row of fetchProfile.inventory.entries) {
if (row.status !== "unsupported") continue;
if (row.code === undefined || row.reason === undefined) {
throw new InternalCompilerError(`non-static fetch inventory row '${row.id}' is incomplete`);
@@ -524,7 +523,7 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes
// Date/perf_hooks/process rows from the one ambient table — each entry
// is fenceable by construction (its row carries the reach-witnessing
// libCall spellings the fence detector uses).
for (const row of AMBIENT_SURFACE_FNS) {
for (const row of ambientSurfaceFns()) {
add({
id: row.id,
kind: row.kind,
@@ -578,7 +577,7 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes
return {
schemaVersion: MANIFEST_SCHEMA_VERSION,
compilerVersion,
coverage: COVERAGE_NOTES,
coverage: coverageNotes(),
entries,
};
}
@@ -57,7 +57,7 @@ import {
isUnitType,
typeEquals,
} from "../../ir/ir.js";
import { LIB_FN_SIGS } from "../../ir/builtin-signatures.js";
import { libFnSignatures } from "../../ir/builtin-signatures.js";
import { REGEX_INTRINSIC_SIGS, STR_INTRINSIC_SIGS } from "../../ir/intrinsic-signatures.js";
import { unionMismatchDiag, unsupportedDiag } from "../../diagnostics/diagnostic.js";
@@ -162,7 +162,7 @@ function enforceExprBoundary(lowerer: Lowerer, node: IrExpr): void {
const kind = node.kind;
if (kind === "libCall") {
const e = node;
const sig = LIB_FN_SIGS[e.fn];
const sig = libFnSignatures()[e.fn];
if (!sig) return;
e.args.forEach((a, i) => {
const want = sig.argTypes[i];
@@ -16,7 +16,7 @@ import { strLit, varRef } from "../../ir/build.js";
import type { Lowerer } from "./lowerer.js";
import {
BUILTIN_MODULE_CONSTS,
BUILTIN_MODULE_FNS,
builtinModuleFns,
OBJECT_CALLABLE_VALUES,
builtinConstLit,
builtinModuleConstOf,
@@ -430,7 +430,7 @@ export function pathModuleValue(lowerer: Lowerer, module: string, loc: SrcLoc):
const add = (member: string, value: IrExpr): void => {
fields.push({ key: strLit(member, loc), value: box(value) });
};
for (const member of Object.keys(BUILTIN_MODULE_FNS[module] ?? {})) {
for (const member of Object.keys(builtinModuleFns()[module] ?? {})) {
const value = lowerer.lowerBuiltinCallableValue({ module, member }, loc);
if (value) add(member, value);
}
@@ -512,7 +512,7 @@ function moduleValue(lowerer: Lowerer, module: string, loc: SrcLoc): IrExpr {
loc,
});
};
for (const member of Object.keys(BUILTIN_MODULE_FNS[module] ?? {})) {
for (const member of Object.keys(builtinModuleFns()[module] ?? {})) {
const callable = lowerer.lowerBuiltinCallableValue({ module, member }, loc);
if (callable) add(member, callable);
}
@@ -35,14 +35,7 @@ import { esmNamedImportLinkCrash, isCjsJsFile, locOf, npmPackageNameOf } from ".
import { foldedStringKeyOf, lowerDynObjectLiteral } from "./expressions/object-literals.js";
import { noteEventListeners } from "./lower-event-target.js";
import { PoisonError, newFnCtx, own } from "./lowerer.js";
import {
NODE24_FETCH_COMPAT_PROFILE,
STATIC_HEADERS_CALLS,
STATIC_READABLE_STREAM_CALLS,
STATIC_READABLE_STREAM_READS,
STATIC_RESPONSE_CALLS,
STATIC_RESPONSE_READS,
} from "../../compat/fetch-profile.js";
import { node24FetchCompatProfile, staticFetchMembers } from "../../compat/fetch-profile.js";
import { classGeneratorIterable } from "./class-iterables.js";
import { generatorDrain } from "./iterator-adapters.js";
@@ -434,7 +427,7 @@ function fenceRequestInitObject(
: contextual
? [contextual]
: [];
const rows = NODE24_FETCH_COMPAT_PROFILE.inventory.entries.filter(
const rows = node24FetchCompatProfile().inventory.entries.filter(
(entry) => entry.owner === "RequestInit" && entry.placement === "dictionary",
);
const shadowed = new Set<string>();
@@ -837,7 +830,7 @@ function fetchInventoryStatus(
placement: "static" | "prototype" | "prototype-symbol",
): "static" | "unsupported" | "out-of-scope" | null {
return (
NODE24_FETCH_COMPAT_PROFILE.inventory.entries.find(
node24FetchCompatProfile().inventory.entries.find(
(entry) => entry.owner === owner && entry.member === member && entry.placement === placement,
)?.status ?? null
);
@@ -848,7 +841,7 @@ function fetchInventoryReason(
member: string,
placement: "static" | "prototype" | "prototype-symbol",
): string | undefined {
return NODE24_FETCH_COMPAT_PROFILE.inventory.entries.find(
return node24FetchCompatProfile().inventory.entries.find(
(entry) => entry.owner === owner && entry.member === member && entry.placement === placement,
)?.reason;
}
@@ -951,8 +944,9 @@ export function fenceStaticResponseMember(
member.startsWith("[Symbol.") ? "prototype-symbol" : "prototype",
);
const projected = staticFetchMembers();
const supported = (member: string) =>
use === "call" ? STATIC_RESPONSE_CALLS.has(member) : STATIC_RESPONSE_READS.has(member);
use === "call" ? projected.responseCalls.has(member) : projected.responseReads.has(member);
if (members.every(supported)) return null;
const member = members.find((candidate) => !supported(candidate))!;
if (status(member) === "unsupported") {
@@ -993,12 +987,9 @@ export function fenceStaticHeadersMember(
member.startsWith("[Symbol.") ? "prototype-symbol" : "prototype",
);
if (use === "call" && members.every((member) => STATIC_HEADERS_CALLS.has(member))) {
return null;
}
const member = members.find(
(candidate) => use !== "call" || !STATIC_HEADERS_CALLS.has(candidate),
)!;
const headersCalls = staticFetchMembers().headersCalls;
if (use === "call" && members.every((member) => headersCalls.has(member))) return null;
const member = members.find((candidate) => use !== "call" || !headersCalls.has(candidate))!;
if (status(member) === "unsupported") {
lowerer.noLowering(
`Headers.${member}`,
@@ -1108,7 +1099,7 @@ function fetchInterfaceInventoryOwner(
const symbol = [type.getSymbol(), type.getAliasSymbol()].find(
(candidate) =>
candidate !== undefined &&
NODE24_FETCH_COMPAT_PROFILE.inventory.interfaces.includes(ts.symbolName(candidate)) &&
node24FetchCompatProfile().inventory.interfaces.includes(ts.symbolName(candidate)) &&
lowerer.isStdlibSymbol(candidate),
);
return symbol ? { owner: ts.symbolName(symbol), symbol } : null;
@@ -1123,7 +1114,7 @@ function fenceFetchObjectMembers(
if (!resolved) return;
const { owner, symbol } = resolved;
for (const { member, node } of members) {
const row = NODE24_FETCH_COMPAT_PROFILE.inventory.entries.find(
const row = node24FetchCompatProfile().inventory.entries.find(
(entry) =>
entry.owner === owner &&
entry.member === member &&
@@ -1136,7 +1127,7 @@ function fenceFetchObjectMembers(
// Static data properties retain the ordinary checked-dynamic keyed-read
// lowering. Only a method extraction loses the receiver that its direct
// call bridge would preserve; non-static rows keep their inventory fence.
const operation = NODE24_FETCH_COMPAT_PROFILE.operations.find(
const operation = node24FetchCompatProfile().operations.find(
(candidate) => candidate.id === row.id,
);
if (row.status === "static" && operation?.kind === "property") {
@@ -1235,7 +1226,7 @@ export function lowerFetchElementMethodCall(
return null;
}
const rows = members.map((member) =>
NODE24_FETCH_COMPAT_PROFILE.inventory.entries.find(
node24FetchCompatProfile().inventory.entries.find(
(entry) =>
entry.owner === resolved.owner &&
entry.member === member &&
@@ -1397,10 +1388,11 @@ export function fenceStaticReadableStreamMember(
member.startsWith("[Symbol.") ? "prototype-symbol" : "prototype",
);
const projected = staticFetchMembers();
const supported = (member: string) =>
use === "call"
? STATIC_READABLE_STREAM_CALLS.has(member)
: STATIC_READABLE_STREAM_READS.has(member);
? projected.readableStreamCalls.has(member)
: projected.readableStreamReads.has(member);
if (members.every(supported)) return null;
const member = members.find((candidate) => !supported(candidate))!;
if (status(member) === "unsupported") {
File diff suppressed because it is too large Load Diff
+10 -2
View File
@@ -46,6 +46,8 @@ export type {
AnalyzeResult,
} from "./compile-types.js";
import { compilePackedLibrary } from "./backend/library-pack.js";
import { node24FetchCompatProfile } from "./compat/fetch-profile.js";
import { libFnSignatures } from "./ir/builtin-signatures.js";
import { InternalCompilerError } from "./errors.js";
import { frontendProcessExecArgv } from "./frontend-process-args.js";
import { type ChildProcess, spawn } from "node:child_process";
@@ -249,7 +251,7 @@ export {
type SurfaceManifestEntry,
} from "./coverage/surface-manifest.js";
export {
NODE24_FETCH_COMPAT_PROFILE,
node24FetchCompatProfile,
type FetchCompatEvidence,
type FetchCompatFacet,
type FetchCompatInventory,
@@ -261,7 +263,13 @@ export {
type FetchCompatOption,
type FetchCompatProfile,
} from "./compat/fetch-profile.js";
export { LIB_FN_SIGS } from "./ir/builtin-signatures.js";
export { libFnSignatures } from "./ir/builtin-signatures.js";
/** @deprecated Use `libFnSignatures()`. Built when this module loads; the
* native compiler does not load this module. */
export const LIB_FN_SIGS = libFnSignatures();
/** @deprecated Use `node24FetchCompatProfile()`. Built when this module
* loads; the native compiler does not load this module. */
export const NODE24_FETCH_COMPAT_PROFILE = node24FetchCompatProfile();
export { validateModule } from "./ir/validate.js";
export {
assignLegacyTiers,
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -3940,7 +3940,7 @@ export type IrExpr =
}
/** Standard-library call (`process` members, node:fs functions). `fn` is a
* closed union; arg/result types are fixed per member (validated against
* LIB_FN_SIGS). Property READS (`process.argv`, `process.platform`) are
* libFnSignatures()). Property READS (`process.argv`, `process.platform`) are
* zero-arg libCalls. Args are BORROWED by the operation (frame temps
* release at statement end); refcounted results come back owned (+1) —
* `process.argv` returns +1 on ONE interned array (JS identity:
+2 -2
View File
@@ -66,7 +66,7 @@ import {
import { unionWideningTags } from "./analysis.js";
import { alwaysReturns } from "./control-flow.js";
import { dynamicOperationOf, functionTier } from "./tiers.js";
import { LIB_FN_SIGS, pipelinePumpedRuns } from "./builtin-signatures.js";
import { libFnSignatures, pipelinePumpedRuns } from "./builtin-signatures.js";
import { ALWAYS_THROW_LIB_FNS } from "./builtin-effects.js";
/** The promisified crypto calls' value kinds besides checked-dynamic. */
@@ -4104,7 +4104,7 @@ function validateFunction(
}
if (e.fn === "worker.new" && !workers)
errors.push({ message: "Worker construction requires worker execution mode", loc: e.loc });
const sig = LIB_FN_SIGS[e.fn];
const sig = libFnSignatures()[e.fn];
if (!sig) {
err(`libCall of unknown library function "${e.fn as string}"`, e.loc);
return;
+6 -6
View File
@@ -56,9 +56,9 @@ import {
} from "../coverage/surface-manifest.js";
import { libFenceDiag, type ScrDiagnostic } from "../diagnostics/diagnostic.js";
import {
AMBIENT_SURFACE_FNS,
ambientSurfaceFns,
BUILTIN_MODULE_CONSTS,
BUILTIN_MODULE_FNS,
builtinModuleFns,
BUILTIN_MODULE_FN_ALIASES,
STATIC_MATH_FNS,
STATIC_MATH_PROPS,
@@ -125,7 +125,7 @@ interface FenceTaxonomy {
/** node-builtin constant ids: reads fold to literals at compile time. */
foldedIds: Set<string>;
/** Ambient dedicated-path surfaces (Date/perf_hooks/process): manifest
* id → the libCall spellings witnessing reach (AMBIENT_SURFACE_FNS —
* id → the libCall spellings witnessing reach (ambientSurfaceFns() —
* the same rows the manifest projects the entries from). */
ambientFns: Map<string, readonly string[]>;
}
@@ -148,7 +148,7 @@ function fenceTaxonomy(): FenceTaxonomy {
const builtinFns = new Map<string, readonly string[]>();
const builtinRoots = new Map<string, readonly string[]>();
const foldedIds = new Set<string>();
for (const [mod, members] of Object.entries(BUILTIN_MODULE_FNS)) {
for (const [mod, members] of Object.entries(builtinModuleFns())) {
const root = new Set<string>();
for (const [member, entry] of Object.entries(members!)) {
if (entry === undefined) continue;
@@ -156,7 +156,7 @@ function fenceTaxonomy(): FenceTaxonomy {
// The bare-path and url tables rebind per TARGET platform
// (builtinModuleFnsOf): a fence on the bare id covers both flavors.
if (mod === "path") {
const w = BUILTIN_MODULE_FNS["path/win32"]?.[member];
const w = builtinModuleFns()["path/win32"]?.[member];
if (w !== undefined) fns.add(w.fn);
}
if (mod === "url" && member === "pathToFileURL") fns.add("url.pathToFileURLWin32");
@@ -173,7 +173,7 @@ function fenceTaxonomy(): FenceTaxonomy {
}
for (const member of Object.keys(STATIC_MATH_PROPS)) foldedIds.add(`stdlib.math.${member}`);
const ambientFns = new Map(
AMBIENT_SURFACE_FNS.map((row) => [row.id, row.fns as readonly string[]]),
ambientSurfaceFns().map((row) => [row.id, row.fns as readonly string[]]),
);
taxonomy = {
byId,
@@ -0,0 +1,12 @@
import { expect, test } from "vitest";
import {
LIB_FN_SIGS,
libFnSignatures,
NODE24_FETCH_COMPAT_PROFILE,
node24FetchCompatProfile,
} from "../src/index.js";
test("the table constants name the tables their functions build", () => {
expect(LIB_FN_SIGS).toBe(libFnSignatures());
expect(NODE24_FETCH_COMPAT_PROFILE).toBe(node24FetchCompatProfile());
});
+2 -2
View File
@@ -5,7 +5,7 @@
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { expect, test } from "vitest";
import { NODE24_FETCH_COMPAT_PROFILE } from "../src/compat/fetch-profile.js";
import { node24FetchCompatProfile } from "../src/compat/fetch-profile.js";
import { NODE_COMPAT_VERSION } from "../src/frontend/lowering/builtins/process.js";
import { CRYPTO_CONSTANTS } from "../src/frontend/lowering/crypto-tables.js";
import { ZLIB_CONSTANTS } from "../src/frontend/lowering/zlib-constants.js";
@@ -23,7 +23,7 @@ test("the Node pins agree", () => {
expect(compat.tag).toBe(`v${pinned}`);
expect(read("Dockerfile.sandbox")).toMatch(new RegExp(`^ARG NODE_VERSION=${pinned}$`, "m"));
expect(NODE_COMPAT_VERSION).toBe(pinned);
expect(NODE24_FETCH_COMPAT_PROFILE.target.node).toBe(pinned);
expect(node24FetchCompatProfile().target.node).toBe(pinned);
expect(read("packages/runtime/src/scr_lib.c")).toContain(
`#define SCR_NODE_COMPAT_VERSION "${pinned}"`,
);
+1 -1
View File
@@ -52,7 +52,7 @@ that may be newer than the installed declarations). Every item is classified:
The selected adjacent interface families excluded from the census carry
reasons too. A Node upgrade that adds/removes a public member or dictionary key
fails the focused suite until that member is classified. The static and unsupported rows project into the shipped surface manifest;
filter `NODE24_FETCH_COMPAT_PROFILE.inventory.entries` by `status`/`owner` for
filter `node24FetchCompatProfile().inventory.entries` by `status`/`owner` for
the next cohesive implementation queue.
When Node changes, update `.node-version` and the profile's Node/Undici tuple
+1 -1
View File
@@ -93,7 +93,7 @@ test("IR imports and the explicit parser islands remain usable", () => {
source(
work,
"packages/compiler/src/frontend/lowering/probe.ts",
'export { LIB_FN_SIGS } from "../../ir/builtin-signatures.js";\nexport { STR_INTRINSIC_SIGS } from "../../ir/intrinsic-signatures.js";\n',
'export { libFnSignatures } from "../../ir/builtin-signatures.js";\nexport { STR_INTRINSIC_SIGS } from "../../ir/intrinsic-signatures.js";\n',
);
source(
work,
+1 -1
View File
@@ -429,7 +429,7 @@ export function generateFetchConformanceProgram(
const traceCount = options.traceCount ?? 12;
const scenarios = generatedScenarioIds(profile);
const sections: string[] = [
`// Generated from NODE24_FETCH_COMPAT_PROFILE. Seed: 0x${seed.toString(16)}.`,
`// Generated from node24FetchCompatProfile(). Seed: 0x${seed.toString(16)}.`,
];
for (const scenario of scenarios) {
if (!Object.hasOwn(SCENARIO_GENERATORS, scenario)) {
+2 -2
View File
@@ -17,7 +17,7 @@ import { promisify } from "node:util";
import { beforeAll, describe, expect, test } from "vitest";
import {
compile,
NODE24_FETCH_COMPAT_PROFILE,
node24FetchCompatProfile,
renderDiagnostics,
type FetchCompatEvidence,
} from "@scriptc/compiler";
@@ -32,7 +32,7 @@ const execFileAsync = promisify(execFile);
const repoRoot = join(import.meta.dirname, "../..");
const fixturesRoot = join(repoRoot, "tests/fixtures/fetch");
const sanitize = process.env["SCRIPTC_SAN"] === "1";
const profile = NODE24_FETCH_COMPAT_PROFILE;
const profile = node24FetchCompatProfile();
function configuredInteger(name: string, fallback: number, maximum: number): number {
const raw = process.env[name];
if (raw === undefined || raw === "") return fallback;
+3 -3
View File
@@ -6,7 +6,7 @@ import {
analyze,
generateSurfaceManifest,
ir,
LIB_FN_SIGS,
libFnSignatures,
renderSurfaceManifest,
resolveLibraryFences,
type SurfaceManifest,
@@ -563,7 +563,7 @@ describe("determinism attestation ↔ fence parity", () => {
// initializer is the Date expression the fences witness.
"date.fromTime",
]);
const missing = Object.keys(LIB_FN_SIGS).filter(
const missing = Object.keys(libFnSignatures()).filter(
(fn) =>
ir.LIB_NONDETERMINISTIC_PREFIXES.some(([prefix]) => fn.startsWith(prefix)) &&
!covered.has(fn) &&
@@ -571,7 +571,7 @@ describe("determinism attestation ↔ fence parity", () => {
);
expect(
missing,
"attestation-demoting spellings no declarable fence can deny — add a manifest projection (AMBIENT_SURFACE_FNS) or a member alias (BUILTIN_MODULE_FN_ALIASES)",
"attestation-demoting spellings no declarable fence can deny — add a manifest projection (ambientSurfaceFns()) or a member alias (BUILTIN_MODULE_FN_ALIASES)",
).toEqual([]);
// The excuse list stays honest in the other direction too: an excused
// spelling that gains detector coverage must leave the list.