Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
"@objectstack/service-settings": patch
---

test(service-settings): resolve the remaining three workspace deps from source, emptying this package's `check-test-source-alias` registry entry (#8104)

#8063 gave this package its first `vitest.config.ts` and aliased two workspace
deps to source (`@objectstack/objectql`, `@objectstack/core`) — the two that
gate named when the package's first real-engine test landed. The other three,
`@objectstack/spec`, `@objectstack/platform-objects` and `@objectstack/types`,
stayed on their registered entry in `KNOWN_UNALIASED_TEST_IMPORTS` and kept
resolving through `exports` to **`dist/`**. They are now aliased to source and
the entry is deleted.

**How much of the suite was actually reading the artifact: 17 of 20 files.**
Measured, not inferred — with the three `dist/` trees removed from the checkout
and the pre-#8104 config in place, 17 test files fail to load at all
(`Cannot find package '@objectstack/spec/system'`) and only 58 of 413 cases run.
With the aliases below, the same tree with no `spec`, `platform-objects` or
`types` build output anywhere passes 413/413. The build artifact is off the
resolution path rather than merely shadowed by a fresh copy of it.

**The subpath entry points were the whole job, and the obvious shape does not
do it.** This package imports **no bare** `@objectstack/spec` and **no bare**
`@objectstack/platform-objects` at run time. Every specifier its tests can reach
for those two is a subpath — `spec/api`, `spec/contracts`, `spec/data`,
`spec/system`, `platform-objects/system` — joined by `spec/security`, reached
transitively through `@objectstack/types` ([ADR-0105 D1] tenancy posture) once
types itself resolves to source. So the two shapes that suggest themselves both
fail, in opposite directions:

- the **object** form matches by **prefix**, so a bare key whose replacement is
a file swallows the subpaths into `…/index.ts/system` — `ENOTDIR` at run time
in a config that reads as correct (#7778);
- the **anchored bare** form (`/^@objectstack\/spec$/`, the shape #8063 left
behind) does not swallow them but does not **cover** them either — all six
specifiers stay on `dist` and the registry entry cannot come off.

What covers them is a subpath rule. `spec` takes the one-rule-for-all-namespaces
form `/^@objectstack\/spec\/([a-z-]+)$/` with the capture group inside the path,
because its export map is uniform (`src/<ns>/index.ts` throughout) — so a new
namespace import cannot make it stale. `platform-objects` gets an **explicit**
`platform-objects/system` entry instead, because its map is *not* uniform:
`./plugin` is `src/plugin.ts`, a file, so a `([a-z-]+)` rule would send
`platform-objects/plugin` to `src/plugin/index.ts`, a path nobody wrote, failing
on whoever next adds that import. `plugin-audit` writes its
`platform-objects/audit` entry the same way for the same reason.

**The registry deletion is half the change, not its cleanup.**
`KNOWN_UNALIASED_TEST_IMPORTS` is audited for set equality in both directions,
so the two halves constrain each other and neither is green alone: with the
aliases complete and the entry still present the gate fails *"registry entry is
no longer needed … Delete the entry"*; with the entry deleted and any one alias
missing it fails *"tests import 1 workspace package(s) that resolve to `dist/`
with no source alias"*. The gate goes from 62 registered packages to 61.

No test turned red and no assertion moved: 413 passed / 20 files before and
after, and **no change under `src/`**. That is the expected reading for a
checkout whose `dist` was built from the same commit — dist and source agree
here, which is exactly the condition under which the old setup looked fine. What
changes is that the suite no longer has an opinion about build state at all.
57 changes: 51 additions & 6 deletions packages/services/service-settings/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,23 @@
// adapter), which pulls `resolveAuthzContext` from core — so core became
// newly reachable from the package's tests and the gate named it.
//
// Only those two are aliased, deliberately. The package's other workspace
// imports (`@objectstack/platform-objects`, `@objectstack/spec`,
// `@objectstack/types`) are its registered set in that gate's
// `KNOWN_UNALIASED_TEST_IMPORTS`; the registry is audited for set EQUALITY in
// both directions, so aliasing them here is a separate, deliberate shrink and
// not a rider on a P0 security fix.
// #8104 finished the job for the remaining three — `@objectstack/spec`,
// `@objectstack/platform-objects` and `@objectstack/types` — and with them this
// package's entry in `KNOWN_UNALIASED_TEST_IMPORTS` came off. That registry is
// audited for set EQUALITY in both directions, so deleting the entry is half of
// that change rather than its cleanup: the aliases below and the absence of the
// entry each fail the gate without the other.
//
// ⚠️ What the shrink actually required, measured rather than assumed: this
// package imports NO bare `@objectstack/spec` and NO bare
// `@objectstack/platform-objects` at run time. Every specifier its tests can
// reach for those two is a SUBPATH — `spec/api`, `spec/contracts`, `spec/data`,
// `spec/system`, `platform-objects/system` — joined by `spec/security`, reached
// transitively through `@objectstack/types` ([ADR-0105 D1] tenancy posture)
// once types itself resolves to source. An anchored BARE pattern
// (`/^@objectstack\/spec$/`) matches none of them, so copying #8063's
// two-entry shape would have left all of them on `dist` with the registry entry
// undeletable. The subpath rules below are the load-bearing half.
import { defineConfig } from 'vitest/config';
import path from 'path';

Expand All @@ -43,6 +54,40 @@ export default defineConfig({
find: /^@objectstack\/core$/,
replacement: path.resolve(__dirname, '../../core/src/index.ts'),
},
// `platform-objects` gets an EXPLICIT subpath entry rather than the
// one-rule-for-all-namespaces capture below, because its export map is
// not uniform: `./plugin` is `src/plugin.ts`, a FILE, while every other
// namespace is `src/<ns>/index.ts`. A `([a-z-]+)` rule would send
// `platform-objects/plugin` to `src/plugin/index.ts`, which does not
// exist — a path nobody wrote, failing on whoever adds that import.
// `plugin-audit` writes its `platform-objects/audit` entry the same way
// and for the same reason.
{
find: /^@objectstack\/platform-objects\/system$/,
replacement: path.resolve(__dirname, '../../platform-objects/src/system/index.ts'),
},
{
find: /^@objectstack\/platform-objects$/,
replacement: path.resolve(__dirname, '../../platform-objects/src/index.ts'),
},
// `spec`, by contrast, IS uniform — every namespace in its export map is
// `src/<ns>/index.ts` — so one rule covers all of them and cannot go
// stale when a new namespace import arrives. The capture group has to sit
// INSIDE the path, which is what forces the template literal here (the
// shape `service-knowledge` and `plugin-audit` already use, and the one
// the gate's canary fixture pins so a reader cannot misread it — #8020).
{
find: /^@objectstack\/spec\/([a-z-]+)$/,
replacement: `${path.resolve(__dirname, '../../spec/src')}/$1/index.ts`,
},
{
find: /^@objectstack\/spec$/,
replacement: path.resolve(__dirname, '../../spec/src/index.ts'),
},
{
find: /^@objectstack\/types$/,
replacement: path.resolve(__dirname, '../../types/src/index.ts'),
},
],
},
});
3 changes: 0 additions & 3 deletions scripts/check-test-source-alias.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -302,9 +302,6 @@ const KNOWN_UNALIASED_TEST_IMPORTS = {
'@objectstack/service-package': ['@objectstack/metadata-core'],
'@objectstack/service-queue': ['@objectstack/objectql', '@objectstack/platform-objects'],
'@objectstack/service-realtime': ['@objectstack/spec'],
'@objectstack/service-settings': [
'@objectstack/platform-objects', '@objectstack/spec', '@objectstack/types',
],
'@objectstack/service-sms': ['@objectstack/plugin-auth', '@objectstack/service-settings'],
'@objectstack/service-storage': [
'@objectstack/objectql', '@objectstack/observability', '@objectstack/platform-objects',
Expand Down
Loading