Skip to content

check-side-effects-array cannot see a load-time effect written inside a const initializer, and scores @object-ui/types zero #8578

Description

@claude

scripts/check-side-effects-array.mjs reports @object-ui/types as having 0 modules with a
top-level registration
(its own --list output: "0 module(s) with a top-level registration, 47
walked"), while a bundler demonstrably drops a real load-time effect from that package.

Why the two disagree

The classifier sorts a module's top-level effects and counts a CALL STATEMENT. The effect it
misses is performed inside a const INITIALIZER:

export const AnyComponentSchema = defineNodeComponentUnion(z.discriminatedUnion('type', [ ... ]));

defineNodeComponentUnion writes the node recursion point's option slot as a side effect of
evaluating that initializer. To the classifier the module declares constants and does nothing; to
a bundler honouring "sideEffects": false the const is droppable when its binding goes unread,
and the write goes with it.

Measured

On this repo's own Vite/rollup lib build, an entry importing only CardSchema from
@object-ui/types/zod produces a 370,652-byte bundle with the fill ABSENT, and a nested off-spec
node is ACCEPTED — the pre-objectui#8344 accept set, silently. The same entry that also imports
AnyComponentSchema keeps the fill and REFUSES the node. So the effect is real, it is
load-time, and the gate that exists to enumerate exactly those effects scores the package zero.

Why this matters beyond one package

The gate's own file header states the design intent: an UNKNOWN effect must be an ERROR rather
than a quiet "not a registration", because "I did not recognise that" and "that is not a
registration" must not be the same answer. An effect inside an initializer currently takes the
second answer silently. Any package can acquire one the same way — a registry write, a cache
prime, a slot fill — and the gate will keep reporting zero.

⚠️ ⛔ This card does NOT ask for the @object-ui/types manifest to change; that decision is objectui#8577, and this classifier is wrong whichever way that decision
goes.

Sketch of what a fix has to answer

  1. Does a CALL inside a top-level const initializer count as a registration? A bundler treats
    it as droppable-with-the-binding rather than pure, so "it depends on whether the binding is
    read" is a real answer the gate would have to model.
  2. If it counts, @object-ui/types acquires a registering module and its manifest options change
    with it — which is exactly the other card's decision, so the two want sequencing.
  3. If it does not count, the gate should say so explicitly rather than by silence, so the next
    author does not read a zero as "this package has no load-time effects".

Related

objectui#8344 / objectui#8501 (where the blindness surfaced) · objectui#6683 (the gate's ruling
and its enumeration rule) · objectui#3943 (the wider consistency pin) · objectui#8577 (the manifest decision).

Measured by the domain:spec developer seat working objectui#8344, session
session_01CZY49skxUBYyJcdnTcYPrE. Generated with Claude Code.


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions