You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Compiler evidence: prove self-containment from the Rspack module graph and Artifact IR; delete the generated-JS load scanners (replaces #591/#602) #619
Replaces #591 and PR #602 (closed unmerged, owner decision). Shared-compiler-policy step of #592; #604 (Artifact IR / manifest v2) records the compile provenance this issue produces; #555 is the composite root the compiler serves.
Why (owner rationale, 2026-09-05)
The approach in #591/#602 was the wrong layer. A meta-framework must not reverse-engineer emitted JavaScript to discover what its own bundler did. Rspack already knows module identity, resolved resource, external modules, dependency type, issuer, chunk membership, and runtime requirements. A bespoke scanner over emitted output (require(…), createRequire(…), bound loaders, aliases, templates, regex literals, shadowing, minified forms) is a second JavaScript parser maintained in parallel with Rspack and Node syntax, and it is fragile by construction.
Dependency-direction lesson from #602. The scanner flagged Agent Bundle's own createRequire(…).resolve(…) in src/core/dependency-manifest.ts; the runtime was rewritten to an ancestor node_modules walk to satisfy the scanner; Yarn PnP broke (locateFrameworkCli → framework-not-installed). A validator implementation detail must never force runtime architecture. The direction is: runtime requirements → the compiler resolves them → the validator checks the compiler's evidence.
selfContained: true means any runtime dependency not explicitly permitted by the artifact contract is a compiler error. Enforcement is one loop over compiler evidence:
Deterministic, and indifferent to whether Rspack emits require(...), __rspack_createRequire_require(...), or any other shim: the external is known as an external, not inferred from its emitted spelling.
tools.rspack.externals: ['left-pad'] is rejected by the configuration layer before compilation, or the compilation result shows the external and fails. Either way, no scanner.
The AGENTS.md "Generated plugin output" rule (no autoExternal, the framework never adds externals, the author's tools hatch cannot externalize a dependency on the author's behalf) is unchanged; the compiler policy is what enforces it, at configuration time and again on the compilation result.
Evidence adapter
A tiny Rspack plugin — ArtifactDependencyAuditPlugin — taps thisCompilation, captures external modules and unresolved runtime loads, and attaches structured evidence to CompileResult. Alternatives, in preference order if the plugin cannot see something: compilation modules / external-module metadata (ExternalModule.request, externalType, issuer via module reasons), then stats module reasons.
Opaque content
Content Agent Bundle did not compile — assets/, prebuilt native executables, verbatim-copied JavaScript, external command integrations — is either fully self-contained by contract or a declared opaque dependency:
Settled (owner decision, 2026-09-05 16:20 UTC, option A): bundled ≠ used. A package.jsondependencies/optionalDependencies/peerDependencies entry counts as used only when it must exist at consumer run time: (1) a definePrebuiltruntimeDependencies declaration, (2) a shipped .d.ts reference read with TypeScript's preProcessFile, (3) the install-script grammar (package.json scripts, bin commands, files, preloads), or (4) the framework's process-dependency record — which is empty today: no runtime module bundled into a generated executable resolves or spawns a package. A package the compiler merely inlined stays AB7014; the graph evidence (ModuleIR.package) upgrades the message to name the bundle that inlined it. No regex or token scanner over packed files.
Invariant
For every compiler-owned executable, all runtime code is one of:
a bundled module,
a Node built-in,
an artifact-relative emitted module,
an explicitly declared opaque/prebuilt dependency.
Anything else is a build error, proven before artifact emission. Artifact validation is then defense in depth only: files exist, hashes match, paths are inside the root, manifests reference declared executables — no JavaScript syntax understanding at all.
AB6005 evaluates the external / module graph evidence.
Delete the generated-JS load scanners (inventory below), and rewrite the docs that describe them.
PR-sized steps: 1–3, then 4–5, then 6 (which also carries the AGENTS.md, docs/diagnostics.md, and website en+zh validation / entry-conventions updates). One minor changeset per PR.
Reordered by the owner audit of 2026-09-05 17:11 UTC (see comments): step 4 lands first as a persisted compile evidence record (agent-bundle.compile-evidence.json, #638); step 6 deletes a scanner only where compiler evidence or an explicit declaration replaces it, per the coverage matrix posted below — everything else stays, gated so it skips what the record proves.
Each of these must hold on compiler evidence, with a fixture that actually builds:
An externalized package must fail: tools.rspack.externals: ['left-pad'] (import form) and externalsType: 'node-commonjs' (the createRequire shim form) both fail AB6005 in a host pack and in a package build's dist.
A Node built-in must pass, with and without the node: prefix, imported or required.
A relative emitted module must pass: an artifact-relative .js/.mjs reached from an entry is fine; a relative target that is missing, outside the root, or not in the manifest fails.
An opaque prebuilt remains opaque: a prebuilt payload module that loads a bare package neither fails AB6005 nor loses the dependency under AB7014; the dependency is kept by the prebuilt declaration.
tools.rspack cannot escape the bundling policy: externals, externalsType, autoExternal, and alias tricks on reserved specifiers are rejected at configuration time or on the compilation result.
Framework-generated modules (entry-shell.ts bins and MCP entries, install bins, hook wrappers, the composite root's bin/ and mcp/ entries, agent-bundle/meta, agent-bundle/mcp-apps) compile with zero externals other than built-ins — the audit AB6005: also refuse bare createRequire/require/import.meta.resolve loads in compiled modules #591 asked for, now as a compile-evidence assertion instead of a scan of rendered source.
The salvaged fixtures and test files from #602 are in the branch history of feat/591-ab6005-module-loads (commit 9ab94d19d) and were extracted with a README to /tmp/602-salvage/ on the owner's machine; the useful ones are the package-build.test.ts externals fixtures (node-commonjs shim, createRequire literal/computed), the prepack.test.ts prebuilt-payload fixture, and the generated-code audit list in generated-module-loads.test.ts (the list of generators, not the scan).
Scanners to delete (inventory, current main)
Scanner
Where
Replaced by
Emitted-JS import walk for AB6005 (host packs)
src/build/validate-artifact-modules.ts — validateJavaScriptModules, resolveJavaScriptImport; called from src/build/validate-artifact.ts (validateArtifact, ~L612)
CompileResult.externals/modules checked by the external dependency policy (step 3/5); the relative-target file checks stay as the manifest/file-table check (defense in depth, no JS parsing)
Dependency usage from CompileResult.modules (which packages the graph references) plus prebuilt declarations (definePrebuilt({ runtimeDependencies })); install-script and bin command evidence stays declarative (package.json), not scanned from JS
"Generated plugin output" currently says: "Proof is bytes and processes, not config: every artifact build walks the compiled host-pack modules (AB6005 fails a bare package specifier there …)". When the scanners go (step 6), that sentence must be rewritten to "proof is compiler evidence + packed-process tests": the compilation's external/module report is the proof of self-containment, and the packed pool (pnpm test:packed, packed-deleted-source) remains the process-level proof. The rest of the section — autoExternal: false, bundle: true, splitChunks: false, no framework externals, MCP App views inlined — is unchanged and is the policy the compiler enforces.
Replaces #591 and PR #602 (closed unmerged, owner decision). Shared-compiler-policy step of #592; #604 (Artifact IR / manifest v2) records the compile provenance this issue produces; #555 is the composite root the compiler serves.
Why (owner rationale, 2026-09-05)
The approach in #591/#602 was the wrong layer. A meta-framework must not reverse-engineer emitted JavaScript to discover what its own bundler did. Rspack already knows module identity, resolved resource, external modules, dependency type, issuer, chunk membership, and runtime requirements. A bespoke scanner over emitted output (
require(…),createRequire(…), bound loaders, aliases, templates, regex literals, shadowing, minified forms) is a second JavaScript parser maintained in parallel with Rspack and Node syntax, and it is fragile by construction.Dependency-direction lesson from #602. The scanner flagged Agent Bundle's own
createRequire(…).resolve(…)insrc/core/dependency-manifest.ts; the runtime was rewritten to an ancestornode_moduleswalk to satisfy the scanner; Yarn PnP broke (locateFrameworkCli→framework-not-installed). A validator implementation detail must never force runtime architecture. The direction is: runtime requirements → the compiler resolves them → the validator checks the compiler's evidence.Correct flow
Not: generated JS → reparse → infer →
AB6005.Compiler API
selfContained: truemeans any runtime dependency not explicitly permitted by the artifact contract is a compiler error. Enforcement is one loop over compiler evidence:Deterministic, and indifferent to whether Rspack emits
require(...),__rspack_createRequire_require(...), or any other shim: the external is known as an external, not inferred from its emitted spelling.Closed-world by default
bundleDependencies: 'all',allowedExternals: ['node-builtins'].tools.rspack.externals: ['left-pad']is rejected by the configuration layer before compilation, or the compilation result shows the external and fails. Either way, no scanner.AGENTS.md"Generated plugin output" rule (noautoExternal, the framework never addsexternals, the author'stoolshatch cannot externalize a dependency on the author's behalf) is unchanged; the compiler policy is what enforces it, at configuration time and again on the compilation result.Evidence adapter
A tiny Rspack plugin —
ArtifactDependencyAuditPlugin— tapsthisCompilation, captures external modules and unresolved runtime loads, and attaches structured evidence toCompileResult. Alternatives, in preference order if the plugin cannot see something: compilation modules / external-module metadata (ExternalModule.request,externalType, issuer via module reasons), then stats module reasons.Opaque content
Content Agent Bundle did not compile —
assets/, prebuilt native executables, verbatim-copied JavaScript, external command integrations — is either fully self-contained by contract or a declared opaque dependency:Never "parse arbitrary JavaScript harder".
AB7014(unused dependency) from evidenceSettled (owner decision, 2026-09-05 16:20 UTC, option A): bundled ≠ used. A
package.jsondependencies/optionalDependencies/peerDependenciesentry counts as used only when it must exist at consumer run time: (1) adefinePrebuiltruntimeDependenciesdeclaration, (2) a shipped.d.tsreference read with TypeScript'spreProcessFile, (3) the install-script grammar (package.jsonscripts,bincommands, files, preloads), or (4) the framework's process-dependency record — which is empty today: no runtime module bundled into a generated executable resolves or spawns a package. A package the compiler merely inlined staysAB7014; the graph evidence (ModuleIR.package) upgrades the message to name the bundle that inlined it. No regex or token scanner over packed files.Invariant
For every compiler-owned executable, all runtime code is one of:
Anything else is a build error, proven before artifact emission. Artifact validation is then defense in depth only: files exist, hashes match, paths are inside the root, manifests reference declared executables — no JavaScript syntax understanding at all.
Implementation order
ArtifactDependencyAuditPlugin).AB6005evaluates the external / module graph evidence.PR-sized steps: 1–3, then 4–5, then 6 (which also carries the
AGENTS.md,docs/diagnostics.md, and website en+zh validation / entry-conventions updates). Oneminorchangeset per PR.Reordered by the owner audit of 2026-09-05 17:11 UTC (see comments): step 4 lands first as a persisted compile evidence record (
agent-bundle.compile-evidence.json, #638); step 6 deletes a scanner only where compiler evidence or an explicit declaration replaces it, per the coverage matrix posted below — everything else stays, gated so it skips what the record proves.Behavioral tests to preserve from #602
Each of these must hold on compiler evidence, with a fixture that actually builds:
tools.rspack.externals: ['left-pad'](import form) andexternalsType: 'node-commonjs'(thecreateRequireshim form) both failAB6005in a host pack and in a package build'sdist.node:prefix, imported or required..js/.mjsreached from an entry is fine; a relative target that is missing, outside the root, or not in the manifest fails.AB6005nor loses the dependency underAB7014; the dependency is kept by the prebuilt declaration.tools.rspackcannot escape the bundling policy:externals,externalsType,autoExternal, and alias tricks on reserved specifiers are rejected at configuration time or on the compilation result.entry-shell.tsbins and MCP entries, install bins, hook wrappers, the composite root'sbin/andmcp/entries,agent-bundle/meta,agent-bundle/mcp-apps) compile with zero externals other than built-ins — the audit AB6005: also refuse bare createRequire/require/import.meta.resolve loads in compiled modules #591 asked for, now as a compile-evidence assertion instead of a scan of rendered source.The salvaged fixtures and test files from #602 are in the branch history of
feat/591-ab6005-module-loads(commit9ab94d19d) and were extracted with a README to/tmp/602-salvage/on the owner's machine; the useful ones are thepackage-build.test.tsexternals fixtures (node-commonjsshim,createRequireliteral/computed), theprepack.test.tsprebuilt-payload fixture, and the generated-code audit list ingenerated-module-loads.test.ts(the list of generators, not the scan).Scanners to delete (inventory, current
main)AB6005(host packs)src/build/validate-artifact-modules.ts—validateJavaScriptModules,resolveJavaScriptImport; called fromsrc/build/validate-artifact.ts(validateArtifact, ~L612)CompileResult.externals/moduleschecked by the external dependency policy (step 3/5); the relative-target file checks stay as the manifest/file-table check (defense in depth, no JS parsing)distwalk forAB6005(package builds)src/build/package-build.ts— theselfContainmentblock inbuildPackageOutputs(~L383) callingvalidateJavaScriptModulesover the stageddistdist/bin/*, Flight workers,lib)src/build/rslib.ts—assertNoResidualReservedImports(readModuleImportsover emitted bundles)externalsevidence or not at all; the config-layer rejection (reservedExternalsViolation,guardReservedExternals) staysAB7014import/require token scanning over packed filessrc/build/pack-dependencies.ts—moduleLoads,javaScriptEvidence,fileEvidence,literalLoad,computedLoad,loaderReference,loaderBinding,factoryNames,loaderNames,codeOnly,decodeLiteral,declarationSpecifiers,importedPackageNames; consumed bysrc/build/pack-inventory.tsdependencyDiagnosticsCompileResult.modules(which packages the graph references) plus prebuilt declarations (definePrebuilt({ runtimeDependencies })); install-script andbincommand evidence stays declarative (package.json), not scanned from JSsrc/build/module-imports.ts—readModuleImports,bundleSyntaxCheckFor(es-module-lexer+acornparse)routes/syntax.ts(TypeScript AST over source, not emitted output) is unaffectedsrc/build/module-loads.ts—scanModuleLoadsAGENTS.md
"Generated plugin output" currently says: "Proof is bytes and processes, not config: every artifact build walks the compiled host-pack modules (
AB6005fails a bare package specifier there …)". When the scanners go (step 6), that sentence must be rewritten to "proof is compiler evidence + packed-process tests": the compilation's external/module report is the proof of self-containment, and the packed pool (pnpm test:packed,packed-deleted-source) remains the process-level proof. The rest of the section —autoExternal: false,bundle: true,splitChunks: false, no frameworkexternals, MCP App views inlined — is unchanged and is the policy the compiler enforces.