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
Nothing in the test suite reads an import specifier. Every import ... from '<specifier>' in src/ and scripts/ is a plain string that
has to name something real in another place — a file on disk, a Node builtin,
or a package declared in package.json — and no gate checks that it does.
Scanned at 00b44df, node v26.8.2, 2026-09-19: 22 files (11 src/**/*.js,
11 scripts/**/*.mjs) carrying 26 distinct specifiers across four
resolution kinds:
kind
example
count
relative
../hooks/useFocusTrap, ./lib/validate-utils.mjs
15
@site/ alias
@site/data/members.json
9
node: builtin
node:fs, node:child_process
22
bare package
react, yaml, @docusaurus/Link
30
All of them resolve today. Nothing pins that, and each kind fails in its own
silent way:
A renamed or deleted module breaks npm run build. No workflow and no
test runs a build against src/, so the first signal is a red deploy.
Extensionless relative imports are a live trap in scripts/. Plain Node
ESM performs no extension guessing: ./lib/github throws ERR_MODULE_NOT_FOUND even though webpack accepts it. These files run as node scripts/..., so the exact filename is the contract — but the two
existing intra-script imports (./lib/validate-utils.mjs, ./lib/github.mjs)
are correct only by convention, and a contributor copying the src/ style
would produce a script that fails only when actually invoked.
An undeclared bare specifier survives locally and dies on npm ci.
A package hoisted as a transitive dependency resolves fine in a working
tree and disappears from a clean install.
Why existing gates miss it
docusaurus build would catch the src/ half, but no test or workflow step
builds; onBrokenLinks: 'throw' governs page routes, not module graphs.
Open PR test: cover the package.json script and CI command wiring contract #278 (tests/workflow-scripts.test.mjs) checks the wiring
contract — npm run targets, node scripts/... paths named in package.json, and linter config files. It never opens a source file or
reads an import statement. Disjoint.
Add tests/module-imports.test.mjs, asserting specifier resolution only
(not which named exports a module provides, and not component behaviour — that
keeps it disjoint from #229):
every node: specifier names a real builtin (module.isBuiltin)
every relative import in src/ resolves, applying webpack's optional
extension and /index rules
every relative import in scripts/ resolves exactly, extension
included, matching plain Node ESM
every @site/ alias resolves from the repository root
every bare import's package name is declared in dependencies or devDependencies, treating @docusaurus/* subpath aliases as satisfied
by @docusaurus/core
a non-vacuity guard, so a regex regression cannot silently empty the
five assertions above
No new dependencies and no production change: the contract holds on main
today, so the test lands green and stays green.
Evidence
Revision 00b44df, node v26.8.2, run locally 2026-09-19 on a fresh clone.
Unit coverage:node --test --experimental-test-coverage → 55 tests
pass, all files 73.51% line / 47.12% branch. The report lists only scripts/lib/*.mjs, scripts/validate-*.mjs and tests/helpers.mjs — no src/ file appears at all, confirming no test loads any src/ module, and
no test reads an import specifier from any file.
End-to-end coverage:unobtainable rather than absent. The repository has
no e2e or browser suite (no playwright/cypress/puppeteer in package.json) and no workflow runs one, so there is no artifact to read.
Missing e2e coverage is therefore not claimed here; see [quality] CI publishes no coverage evidence, so coverage findings cannot be verified #186 for the
missing coverage-evidence pipeline.
Priority
Impact: medium — three silent break classes, one of which (npm ci) only
appears on a machine other than the author's
Effort: low — one test-only file, no new dependencies, green on main
Finding
Nothing in the test suite reads an
importspecifier. Everyimport ... from '<specifier>'insrc/andscripts/is a plain string thathas to name something real in another place — a file on disk, a Node builtin,
or a package declared in
package.json— and no gate checks that it does.Scanned at
00b44df, node v26.8.2, 2026-09-19: 22 files (11src/**/*.js,11
scripts/**/*.mjs) carrying 26 distinct specifiers across fourresolution kinds:
../hooks/useFocusTrap,./lib/validate-utils.mjs@site/alias@site/data/members.jsonnode:builtinnode:fs,node:child_processreact,yaml,@docusaurus/LinkAll of them resolve today. Nothing pins that, and each kind fails in its own
silent way:
npm run build. No workflow and notest runs a build against
src/, so the first signal is a red deploy.scripts/. Plain NodeESM performs no extension guessing:
./lib/githubthrowsERR_MODULE_NOT_FOUNDeven though webpack accepts it. These files run asnode scripts/..., so the exact filename is the contract — but the twoexisting intra-script imports (
./lib/validate-utils.mjs,./lib/github.mjs)are correct only by convention, and a contributor copying the
src/stylewould produce a script that fails only when actually invoked.
npm ci.A package hoisted as a transitive dependency resolves fine in a working
tree and disappears from a clean install.
Why existing gates miss it
docusaurus buildwould catch thesrc/half, but no test or workflow stepbuilds;
onBrokenLinks: 'throw'governs page routes, not module graphs.tests/workflow-scripts.test.mjs) checks the wiringcontract —
npm runtargets,node scripts/...paths named inpackage.json, and linter config files. It never opens a source file orreads an
importstatement. Disjoint.importstatements written insidedocs/andblog/MDX. This issue scopes itself explicitly to
src/**/*.jsandscripts/**/*.mjsand does not read MDX. Disjoint.filterArchitecturesbehaviour and adds a JSX loader;[quality] CSS Module class-name contract is untested; src/theme/Footer references an undeclared .iconLink and ships an orphan .orgText #319 covers CSS Module class names; test: verify local /img static asset references resolve under static/ (tests/static-assets.test.mjs) #289 covers
/imgstatic assetpaths. None of them resolves a module specifier. Disjoint.
Recommendation
Add
tests/module-imports.test.mjs, asserting specifier resolution only(not which named exports a module provides, and not component behaviour — that
keeps it disjoint from #229):
node:specifier names a real builtin (module.isBuiltin)src/resolves, applying webpack's optionalextension and
/indexrulesscripts/resolves exactly, extensionincluded, matching plain Node ESM
@site/alias resolves from the repository rootdependenciesordevDependencies, treating@docusaurus/*subpath aliases as satisfiedby
@docusaurus/corefive assertions above
No new dependencies and no production change: the contract holds on
maintoday, so the test lands green and stays green.
Evidence
00b44df, node v26.8.2, run locally 2026-09-19 on a fresh clone.node --test --experimental-test-coverage→ 55 testspass, all files 73.51% line / 47.12% branch. The report lists only
scripts/lib/*.mjs,scripts/validate-*.mjsandtests/helpers.mjs— nosrc/file appears at all, confirming no test loads anysrc/module, andno test reads an import specifier from any file.
no e2e or browser suite (no
playwright/cypress/puppeteerinpackage.json) and no workflow runs one, so there is no artifact to read.Missing e2e coverage is therefore not claimed here; see [quality] CI publishes no coverage evidence, so coverage findings cannot be verified #186 for the
missing coverage-evidence pipeline.
Priority
npm ci) onlyappears on a machine other than the author's
mainFiled by quality agent (hold-gated mode)
— hive: agent=quality backend=copilot model=claude-opus-5