scripts/check-side-effects-array.mjs derives its enumeration by walking ONE
graph: evaluatePackage calls walkEntryGraph(sourceBarrelAbs), where
sourceBarrelAbs is the single src/index.* that deriveSpellingMap finds.
But manifestEntryForms collects EVERY entry form the manifest publishes, and
every one of them is a module a consumer's bundler can resolve the package to.
A package with more than one entry therefore gets its array compared against an
enumeration derived from only one of them. A module that registers at load time
and is reachable only from a secondary entry is invisible to the walk: it is
never proposed as MISSING, and if the array does name it, it reads as STALE.
That is the same silent-drop failure class the gate exists to prevent — the
enumeration is quietly smaller than the promise the array makes.
Measured
@object-ui/types publishes a ./zod entry whose source barrel is
packages/types/src/zod/index.zod.ts. That file is NOT reachable from
packages/types/src/index.ts:
$ grep -n "zod" packages/types/src/index.ts
75:// they live on the main entry rather than under `/zod` (they carry no zod).
120:// envelope `{ dialect?, source }`. Its zod twin is `ExpressionWireSchema` on
121:// the `./zod` entry.
1170:// *types* only. The companion zod validators (`…Schema`) are deliberately NOT
...only comments. The walk from src/index.ts reaches 47 modules and none of
them is index.zod.ts, which is where the package's one load-time effect lives
(AnyComponentSchema = defineNodeComponentUnion(...), writing the node
recursion point's option slot).
⚠️ This matters for reading objectui#8578's headline number. That card
attributed the @object-ui/types reading of "0 module(s) with a top-level
registration, 47 walked" to the classifier's blindness to a const
initializer. The classifier blindness was real and is fixed on that card, but
it was not the only cause: even with the classifier fixed, the walk never
reaches the module the effect is in. Verified after the objectui#8578 fix —
pointing scanModule straight at the file reports the registration, and the
package-level walk still does not include the file.
⚠️ @object-ui/types declares sideEffects: false today, so it is not in this
gate's population at all (readArrayPackages takes ARRAY declarations only).
This card is about the gate, not about that manifest — the defect applies to any
multi-entry package that declares an array, and @object-ui/app-shell already
publishes many entry forms.
What a fix has to answer
- Which entry forms should anchor a walk? Every form
manifestEntryForms
returns is a resolution target, but the gate only knows the SOURCE spelling
for the one barrel deriveSpellingMap round-trips on. Mapping a published
secondary form back to its source file is the inverse of toPublished and
needs to fail loudly when it cannot.
- What is the union's cost?
@object-ui/app-shell publishes 31 entries; a walk
per entry has to stay a single de-duplicated module set or the walk time
multiplies.
- Reachability (
checkReachability) currently walks back to ONE barrel. With
several entries a registrar is retained if ANY covered entry reaches it, so
that check widens with the walk.
Related
objectui#8578 (the classifier fix, where this was measured) · objectui#6683 (the
gate's ruling and its enumeration rule) · objectui#8344 / objectui#8577.
Measured by the domain:devx developer seat working objectui#8578, session
session_01FhBNJcLRZLe8M87VcUgpKr. Generated with Claude Code.
scripts/check-side-effects-array.mjsderives its enumeration by walking ONEgraph:
evaluatePackagecallswalkEntryGraph(sourceBarrelAbs), wheresourceBarrelAbsis the singlesrc/index.*thatderiveSpellingMapfinds.But
manifestEntryFormscollects EVERY entry form the manifest publishes, andevery one of them is a module a consumer's bundler can resolve the package to.
A package with more than one entry therefore gets its array compared against an
enumeration derived from only one of them. A module that registers at load time
and is reachable only from a secondary entry is invisible to the walk: it is
never proposed as MISSING, and if the array does name it, it reads as STALE.
That is the same silent-drop failure class the gate exists to prevent — the
enumeration is quietly smaller than the promise the array makes.
Measured
@object-ui/typespublishes a./zodentry whose source barrel ispackages/types/src/zod/index.zod.ts. That file is NOT reachable frompackages/types/src/index.ts:...only comments. The walk from
src/index.tsreaches 47 modules and none ofthem is
index.zod.ts, which is where the package's one load-time effect lives(
AnyComponentSchema = defineNodeComponentUnion(...), writing the noderecursion point's option slot).
attributed the
@object-ui/typesreading of "0 module(s) with a top-levelregistration, 47 walked" to the classifier's blindness to a
constinitializer. The classifier blindness was real and is fixed on that card, but
it was not the only cause: even with the classifier fixed, the walk never
reaches the module the effect is in. Verified after the objectui#8578 fix —
pointing
scanModulestraight at the file reports the registration, and thepackage-level walk still does not include the file.
@object-ui/typesdeclaressideEffects: falsetoday, so it is not in thisgate's population at all (
readArrayPackagestakes ARRAY declarations only).This card is about the gate, not about that manifest — the defect applies to any
multi-entry package that declares an array, and
@object-ui/app-shellalreadypublishes many entry forms.
What a fix has to answer
manifestEntryFormsreturns is a resolution target, but the gate only knows the SOURCE spelling
for the one barrel
deriveSpellingMapround-trips on. Mapping a publishedsecondary form back to its source file is the inverse of
toPublishedandneeds to fail loudly when it cannot.
@object-ui/app-shellpublishes 31 entries; a walkper entry has to stay a single de-duplicated module set or the walk time
multiplies.
checkReachability) currently walks back to ONE barrel. Withseveral entries a registrar is retained if ANY covered entry reaches it, so
that check widens with the walk.
Related
objectui#8578 (the classifier fix, where this was measured) · objectui#6683 (the
gate's ruling and its enumeration rule) · objectui#8344 / objectui#8577.
Measured by the
domain:devxdeveloper seat working objectui#8578, sessionsession_01FhBNJcLRZLe8M87VcUgpKr. Generated with Claude Code.