Skip to content

[finding] the @objectstack/metadata/errors leaf loads 2.4 MB / 83 modules standalone - the manager half of its leanness promise holds, the general one does not #15346

Description

@claude

Found while measuring #14680 (PR #15343). Recording only, unassigned.

The promise

packages/metadata/src/errors.ts is the leaf subpath @objectstack/metadata/errors, and its header states why it exists:

@objectstack/metadata's root entry pulls the manager, every loader and the YAML/filesystem machinery behind them. A consumer that wants a 40-line predicate should not have to load any of that.

That promise is the precedent #14680 was decided on, so it is worth knowing whether it still holds. Measured, it half holds.

The measurement

Method: build the workspace, load one entry in a fresh Node process, and record every module file Node actually evaluates through a module.registerHooks load hook unioned with require.cache, byte sizes from statSync. Measured at origin/main 6e67b86c0 plus the #15343 branch (the leaf under test is unchanged by that branch).

entry loaded standalone modules bytes
packages/metadata/dist/errors.js 83 2,487,842
its breakdown packages/spec 1,883,493 · zod 567,918 · @objectstack/types 36,288 · @objectstack/metadata 143

So the manager, the loaders, chokidar, glob, js-yaml and readdirp are all correctly absent — that half of the promise holds and is worth keeping. But an out-of-repo consumer that imports the subpath for a 40-line predicate loads 2.4 MB across 83 modules, because since the maintainer's 2026-08-30 ruling the file re-exports from @objectstack/types, @objectstack/types declares @objectstack/spec as its one dependency, and packages/types/src/env.ts imports @objectstack/spec/security at module top.

Why this is a finding and not a bug

  • Nothing enforced is crossed. No gate measures any entry point's module-init closure (which is the subject of a sibling finding filed from the same measurement).
  • In-repo it costs nothing measurable: every current consumer of the subpath already loads @objectstack/spec, so its marginal contribution to, for example, @objectstack/objectql/core is 143 bytes.
  • The header's own wording is about the manager and the YAML machinery specifically, and that part is accurate. What has drifted is the general claim a reader takes from it.

What could be done, none of it prescribed

  1. Nothing — record the measurement in the header so the next author is not surprised, and keep the narrow claim.
  2. Make the type-level seam leaner at the source: if the predicate's home in @objectstack/types could reach it without @objectstack/spec/security at module top (a lazy or type-only edge), the whole chain would collapse for every consumer of @objectstack/types, not just this one.
  3. Nothing at all, deliberately, if 2.4 MB for an in-process node consumer is judged uninteresting.

Option 2 touches packages/types and packages/spec and is the domain:spec seat's call, not the engine lane's.

Re-check

node -e "import('@objectstack/metadata/errors')"   # from a package that depends on it

with the closure harness quoted in #15343's report.


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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions