Skip to content

A package with unit tests and no vitest.config.ts lets a stale @objectstack/core dist decide its verdicts — #7668 fixed one, nothing stops the next #7849

Description

@huangyiirene

Filing unassigned; domain:* routing is the triage seat's. Carried forward from PR #7778's out-of-scope report, where the dev explicitly declined to widen the fix into a repo-wide sweep and asked for it to be its own card.

The hazard, as proven on one package

packages/services/service-storage had no vitest.config.ts, so @objectstack/core resolved through the workspace link to packages/core/dist/index.jsa build artifact. Every unit pin in that package therefore returned a verdict about build state, not about the source in the checkout.

#7668 is what that cost: all 17 cases of attachment-access-hooks.test.ts — the only executable guard on the #4757 predicate-less unscoped-multi-delete refusal, which cannot be expressed over REST — errored with TypeError: withoutOperationPrivateKeys is not a function against a tree whose prebuilt core predated that export, while packages/core/src/security/operation-private-keys.ts was correct the whole time.

The loud error is the mild half. A core dist merely behind rather than missing the symbol lets a pin run green against core's old behaviour — a passing test that is not testing the code in the checkout, with nothing in the output saying so.

Ordering does not reach it: turbo.json already declares test dependsOn ^build, and turbo run test was never the failing path. What broke are the paths turbo does not mediate — pnpm test inside the package, vitest run <file>, an editor runner, or an agent working in a tree built at an older commit. Those are exactly the paths a pin is re-run on while someone is changing core, i.e. when it most needs to be telling the truth.

Why this card exists

PR #7778 added the missing vitest.config.ts to service-storage — one package, the one the issue named. It did not sweep, and said so: "the same hazard shape exists wherever a package with unit tests imports @objectstack/core and ships no vitest config… a repo-wide sweep (or a lint gate asserting the invariant) is a separate change and should be its own issue rather than a rider here."

Ten packages already alias core to source (service-knowledge, plugin-audit, runtime, metadata, driver-memory, driver-sql, knowledge-memory, knowledge-ragflow, plugin-dev, plugin-hono-server), which is what makes the omission a drift rather than a design: the convention exists and is unevenly applied, with nothing enforcing it.

The ask (unmeasured — step 1 is the census)

  1. Count first. How many packages have unit tests, import @objectstack/core (or another workspace package whose dist can go stale), and ship no vitest alias? Nobody has that number; it decides whether this is a five-line sweep or a staged one.
  2. Then either add the configs, or — better, since a new package will re-introduce it — assert the invariant mechanically, so "package has tests + imports a workspace package + has no alias" fails a gate rather than waiting to produce a wrong verdict.

Note the failure mode being defended against is silent: the observable symptom is a test that passes for the wrong reason. That argues for the gate over the sweep, since a sweep leaves the next package unguarded.

One thing to get right, from #7778's own notes

Alias with the anchored regex / array form, not the object form: the object form matches by prefix, so a bare @objectstack/core entry also swallows @objectstack/core/logger and resolves it to core/src/index.ts/logger (ENOTDIR). And aliasing is graph-wide, which is a feature here — the deps still loaded from dist resolve to the same single core instance rather than a second copy.

Provenance

PR #7778 (test(service-storage): resolve @objectstack/core from source so a stale dist can't decide a pin), out-of-scope findings section. Filed by the devx PM seat (#6023).

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