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
check-node-esm-load.mjs's readTsconfig() destroys any tsconfig whose JSON strings contain /*, so effectiveNoEmit() silently answers from its catch block for packages/auth and packages/fields #5367
Found while clearing the six small packages of #5214, by running the gate's own exported helpers directly. Not fixed there — it is gate machinery, not the defect that card is about, and the direction of the failure is currently safe.
What was measured, 2026-08-20
import{readTsconfig,effectiveNoEmit}from'./scripts/check-node-esm-load.mjs';readTsconfig('packages/auth/tsconfig.json')// SyntaxError: Expected ':' after property name in JSON at position 182readTsconfig('packages/fields/tsconfig.json')// SyntaxError: Expected ',' or '}' after property value in JSON at position 87
readTsconfig strips comments with two regexes over the raw text:
The /* inside "@/*" opens a "block comment" that runs to the */ inside "**/*.test.ts" at the bottom of the file, eating paths, include and most of exclude. What survives the strip is:
"paths": {
"@*.test.ts", "**/*.test.tsx"]
}
packages/fields/tsconfig.json loses everything after "outDir": "dist" the same way, via the packages/*/src written inside one of its // comments.
Why nothing is red today
effectiveNoEmit catches the parse failure deliberately:
}catch{// An unreadable config is graded as emitting, so a parse failure widens the// scan rather than silently dropping a package out of it.returnfalse;}
So both packages are graded "emitting", buildPreservesSpecifiers returns true, and they land inside the ratchet's scope — which is where they belong. The gate's verdict is right; it just is not being reached by the code that is supposed to decide it.
Why it is still worth fixing
The conservative catch is the documented fallback for an unreadable config. It is silently absorbing a readable one, so the safety margin the comment describes is already spent, and nobody can see it.
packages/fields is the case where the answer actually matters and is actually wrong: its tsc step inherits the root's noEmit: true (it only type-checks; dist comes from vite). Correctly parsed, effectiveNoEmit returns true and fields would drop out of the specifier leg. Measured alongside Seven published packages still emit extensionless relative specifiers, so plain Node ESM cannot load them #5214: fields' dist carries 0 extensionless relative specifiers even before that card's fix — its published entry failed via @object-ui/providers, never on its own file. So the gate is currently ratcheting fields' sources on the strength of a verdict it never computed. (Whether it should keep ratcheting them is a real question and probably yes — but it should be a decision, not an accident.)
Any future package whose tsconfig genuinely should be excluded will be included instead, with no signal.
Suggested shape
Parse with a real JSONC reader rather than regexes — TypeScript itself ships ts.parseConfigFileTextToJson, and the repo already depends on typescript. If a dependency-free strip is preferred, it has to be string-aware: track " and skip comment openers inside strings.
Whatever the fix, it should come with the assertion this class of bug needs: that readTsconfig round-trips every tsconfig in the repository without throwing. That is the check that would have caught it, and it is cheap.
Found while clearing the six small packages of #5214, by running the gate's own exported helpers directly. Not fixed there — it is gate machinery, not the defect that card is about, and the direction of the failure is currently safe.
What was measured, 2026-08-20
readTsconfigstrips comments with two regexes over the raw text:Neither knows what a JSON string is.
packages/auth/tsconfig.jsoncontainsThe
/*inside"@/*"opens a "block comment" that runs to the*/inside"**/*.test.ts"at the bottom of the file, eatingpaths,includeand most ofexclude. What survives the strip is:packages/fields/tsconfig.jsonloses everything after"outDir": "dist"the same way, via thepackages/*/srcwritten inside one of its//comments.Why nothing is red today
effectiveNoEmitcatches the parse failure deliberately:So both packages are graded "emitting",
buildPreservesSpecifiersreturns true, and they land inside the ratchet's scope — which is where they belong. The gate's verdict is right; it just is not being reached by the code that is supposed to decide it.Why it is still worth fixing
packages/fieldsis the case where the answer actually matters and is actually wrong: itstscstep inherits the root'snoEmit: true(it only type-checks;distcomes from vite). Correctly parsed,effectiveNoEmitreturns true andfieldswould drop out of the specifier leg. Measured alongside Seven published packages still emit extensionless relative specifiers, so plain Node ESM cannot load them #5214:fields'distcarries 0 extensionless relative specifiers even before that card's fix — its published entry failed via@object-ui/providers, never on its own file. So the gate is currently ratchetingfields' sources on the strength of a verdict it never computed. (Whether it should keep ratcheting them is a real question and probably yes — but it should be a decision, not an accident.)Suggested shape
Parse with a real JSONC reader rather than regexes — TypeScript itself ships
ts.parseConfigFileTextToJson, and the repo already depends ontypescript. If a dependency-free strip is preferred, it has to be string-aware: track"and skip comment openers inside strings.Whatever the fix, it should come with the assertion this class of bug needs: that
readTsconfiground-trips every tsconfig in the repository without throwing. That is the check that would have caught it, and it is cheap.Found via #5214.