Skip to content

Commit 3c3a05c

Browse files
build(typecheck): graduate cloud-connection, observability and hono from the DEBT ledger (#20800) (#21038)
Fixes #20800 Clause-②: no The last three packages of the #4311 type-check ledger, `@objectstack/cloud-connection`, `@objectstack/observability` and `@objectstack/hono`, now type-check their own test layer. Each gets a sibling `tsconfig.test.json` named by a new `typecheck` script, every code-tier error is repaired at its cause inside the test layer, and the three `DEBT` entries are deleted rather than lowered. `DEBT` in `scripts/check-type-check-coverage.mjs` now holds `@objectstack/spec-monorepo` alone; `@objectstack/console` stays `EXEMPT`, as the card says. ## What changed | Path | Change | |---|---| | `packages/{cloud-connection,observability,adapters/hono}/tsconfig.test.json` | new: extends the package's build config, `noEmit`, `module: esnext` / `moduleResolution: bundler`, `lib` ES2022 (hono keeps its `DOM` libs). Strictness, `paths`, `rootDir` and `types` are inherited and not re-declared. Each header carries its own measured readings. | | `packages/{cloud-connection,observability,adapters/hono}/package.json` | `typecheck` = `tsc --noEmit && tsc --noEmit -p tsconfig.test.json`, the zero-residue shape `metadata-fs` and `trigger-record-change` use: no per-package ledger, no new dependency, no lockfile change. | | test files (listed below) | the code-tier repairs. No cast, no `@ts-expect-error`, no `src` signature widened. | | `scripts/check-type-check-coverage.mjs` | the three `DEBT` entries deleted, plus one graduation paragraph in the same style as the ones above it. No gate logic moved. | ## Both readings, before any fix Taken at `f8178ffece` (origin/main) with the workspace closure built first, once per config: `tsc --noEmit --pretty false --listFiles -p tsconfig.json` (the build config) and the same with the new `tsconfig.test.json`. | package | files in the test program (own tests) | build config | test config | config tier | code tier | |---|---:|---|---|---:|---:| | `@objectstack/cloud-connection` | 923 (30) | 13 = TS2493 x11 + TS2550 x2 | 11 = TS2493 x11 | 2 | 11 | | `@objectstack/observability` | 401 (7) | 11 = TS2554 x10 + TS2552 x1 | 11 = same | 0 | 11 | | `@objectstack/hono` | 858 (5) | 3 = TS2769 x2 + TS18046 x1 | 3 = same | 0 | 3, and 4 more once those cleared (below) | The build-config column reproduces the ledger exactly (13 / 11 / 3). All three build configs already included the tests and never excluded them, so the program that reads them always existed; no script ever ran it. That is the `service-automation` shape, not an exclude-and-compensate one. After: every config of every package reads 0, and `typecheck` exits 0 for all three. ## Each error repaired at its cause | Package / file | Errors | Cause | Repair | |---|---|---|---| | cloud-connection: `cloud-connection-plugin.test.ts` x3, `connection-credential-store.test.ts` x4 (7 declarations) | TS2493 x11 | `vi.fn(async () => new Response(...))` declared with no parameters, so vitest types `mock.calls` as empty tuples, and the test indexes `calls[0][0]` / `[1]` | the mock is typed to the call it stubs: `vi.fn(async (_url: string, _init?: RequestInit) => ...)`, the shape `fetch(url, init)` is always called with in the plugin | | cloud-connection: `marketplace-install-local-bundle.test.ts` x2 | TS2550 x2 (config tier) | `Array#at` under the build config's `lib` ES2020 | rewritten to vitest's `mock.lastCall`, not a widening of the shared build config (the `service-storage` call recorded in the ledger prose). The test config also carries ES2022, but the first leg of `typecheck` reads these files under ES2020 too, so the file itself had to compile under both | | observability: `error-exporters.test.ts`, `loggers.test.ts`, `metrics-exporters.test.ts` | TS2554 x10 | the Noop classes declare zero-parameter methods (legal narrowing), so calls on the concrete class type have arity 0 while the contract consumers call through has the real one | the instance is declared as the contract it is used through (`ErrorReporter`, `Logger`, `MetricsRegistry`). The source signatures were not widened | | observability: `otlp-http.test.ts` | TS2552 | fake `fetch` parameter named `RequestInfo`, a DOM-lib name this program does not have | typed as the union of string, URL and Request, the call site it stubs | | hono: `hono.test.ts` | TS2769 x2, TS18046 | a bare `new Hono()` declares no `Variables`, so `c.get('objectStack')` takes `never` and returns `unknown` | the two tests that read the variable back build their app with a `KernelEnv` type argument declaring `objectStack` (the middleware does `c.set('objectStack', kernel)`) | | hono: `src/__mocks__/runtime.ts` | TS2883 x4, latent | see the next section | the four `vi.fn()` fields are annotated `Mock` | ## A finding for the reviewer: hono's "3" was not its whole pile With the three semantic errors repaired, the hono test config reported four more: TS2883 on the four `vi.fn()` class fields of `src/__mocks__/runtime.ts` (the inferred type cannot be named without a reference to `Procedure` inside the pnpm store). tsc withholds declaration-emit diagnostics while any semantic error stands, so the first reading could not show them, and the build config never shows them at all (it exits 0 on that file; only the `bundler` resolution reports it). Observed in two states: state A (original files) reads 3 errors and no TS2883; state B (`hono.test.ts` repaired, mock not yet) reads exactly 4 TS2883 and nothing else. The repair is a test-support annotation; the file is a vitest alias target (`vitest.config.ts`), never built or published. Nothing was hiding behind the other two: for cloud-connection and observability both configs read 0 once the listed errors were repaired. ## Acceptance, measured All at head `5f4aa15801` unless stated (the branch is two commits plus a merge of `origin/main` at `9b0de7de73`, taken so the derived gate list was not read from a stale tree; closure rebuilt after the merge). - `pnpm --filter PKG run typecheck` exits **0** for all three; each run echoes the `typecheck` script name. - `pnpm check:type-check-coverage`: OK, "79/80 workspace packages type-checked (plus the root), 1 in the DEBT ledger (26 frozen raw errors), 1 exempt". `pnpm check:type-check-debt`: OK, "1 ledger entr(ies) re-measured ... none above its recorded number", surplus none. - The three suites do not regress: cloud-connection 30 files / 397 tests, observability 7 / 85, hono 5 / 122, all passing; the diff touches no `it(`, `test(` or `describe(` line. - **The new scripts can fail.** Planted through `scripts/ablation-replace.mjs` (anchor must hit once, blob change proven, restore proven) in one test file per package that this PR does not otherwise edit: the copyright line of `marketplace-public-url.test.ts`, `perf-timing.test.ts` and `hono-wildcard-fallthrough.test.ts` replaced by a line assigning a string to a `number`. Each `typecheck` exited **2**, naming that file (TS2322 and TS6133), and each restore left the blob equal to HEAD with `git diff HEAD` empty. Direction observed: turns red, as expected. - `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived 82 families; all 82 were run one by one with the exit code captured before any pipe, and `--ran` reconciles "82 derived, 82 run, 0 NOT-MEASURED, 0 UNRUN". `check:pm-dispatch-gates` needed the detached form its own header prescribes (about 17 minutes on this shared box; its first two foreground attempts were cut by my own timeout and are not counted). - `pnpm lint` exits **0** over the whole repo at `5f4aa15801`. ## Changeset None written. The diff changes no file the three packages ship: `files[]` is `dist`, `README.md` and `CHANGELOG.md`; the `dist` build is from `src/index.ts` and reaches no test file or `__mocks__`; and after building the three packages, a grep of their `dist` for every symbol this PR introduced (`KernelEnv`, `lastCall`, the `_init` parameter, `type Mock`) found nothing, while a positive control (`CloudConnectionPlugin`, `InMemoryErrorReporter`, `createHonoApp`) hit in each. The only shipped-manifest change is the `scripts` block of each `package.json`. The seat applies `skip-changeset`. ## Acceptance notes - `@objectstack/spec-monorepo` (root entry, 26) is untouched, as the card says. Its `compositionAt` staleness notice is the same one `main` prints. - Not run locally: the repository-wide CI jobs (`pnpm test` for the whole repo, the full dogfood set); they are CI's. --- _Generated by [Claude Code](https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent a11faee commit 3c3a05c

16 files changed

Lines changed: 273 additions & 36 deletions

‎packages/adapters/hono/package.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"scripts": {
1515
"build": "tsup --config ../../../tsup.config.ts && node ../../../scripts/check-dts-emitted.mjs",
1616
"test": "vitest run",
17-
"test:watch": "vitest"
17+
"test:watch": "vitest",
18+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json"
1819
},
1920
"dependencies": {
2021
"@objectstack/plugin-hono-server": "workspace:*",

‎packages/adapters/hono/src/__mocks__/runtime.ts‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
// in `packages/**`. Declaring MORE than this adapter calls is fine (it calls
1010
// only `getDiscoveryInfo`, `handleAuth` and `dispatch`); declaring something the
1111
// dispatcher does not implement is not.
12-
import { vi } from 'vitest';
12+
import { vi, type Mock } from 'vitest';
1313

1414
export class HttpDispatcher {
15-
getDiscoveryInfo = vi.fn().mockReturnValue({ version: '1.0', routes: {} });
16-
handleAuth = vi.fn().mockResolvedValue({ handled: true, response: { status: 200, body: { ok: true } } });
17-
handleMetadata = vi.fn().mockResolvedValue({ handled: true, response: { status: 200, body: { objects: [] } } });
18-
handleData = vi.fn().mockResolvedValue({ handled: true, response: { status: 200, body: { records: [] } } });
15+
getDiscoveryInfo: Mock = vi.fn().mockReturnValue({ version: '1.0', routes: {} });
16+
handleAuth: Mock = vi.fn().mockResolvedValue({ handled: true, response: { status: 200, body: { ok: true } } });
17+
handleMetadata: Mock = vi.fn().mockResolvedValue({ handled: true, response: { status: 200, body: { objects: [] } } });
18+
handleData: Mock = vi.fn().mockResolvedValue({ handled: true, response: { status: 200, body: { records: [] } } });
1919

2020
constructor(_kernel: any) {}
2121
}

‎packages/adapters/hono/src/hono.test.ts‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,18 @@ import { objectStackMiddleware, createHonoApp } from './index';
2222

2323
const mockKernel = { name: 'test-kernel' } as any;
2424

25+
// What `objectStackMiddleware` puts on the context (`c.set('objectStack', kernel)`).
26+
// An app a test reads it back from must declare that variable: a bare `new Hono()`
27+
// has no `Variables`, so Hono types `c.get` as taking `never`.
28+
type KernelEnv = { Variables: { objectStack: { name: string } } };
29+
2530
describe('objectStackMiddleware', () => {
2631
beforeEach(() => {
2732
vi.clearAllMocks();
2833
});
2934

3035
it('sets kernel on context via c.set', async () => {
31-
const app = new Hono();
36+
const app = new Hono<KernelEnv>();
3237
const middleware = objectStackMiddleware(mockKernel);
3338

3439
app.use('*', middleware);
@@ -61,7 +66,7 @@ describe('objectStackMiddleware', () => {
6166
});
6267

6368
it('provides the correct kernel instance', async () => {
64-
const app = new Hono();
69+
const app = new Hono<KernelEnv>();
6570
const middleware = objectStackMiddleware(mockKernel);
6671

6772
app.use('*', middleware);
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// The TEST-layer type-check program (#20800 -- the last three packages of the
2+
// #4311 ledger, graduated by the #15048 / #15050 road: a sibling program named
3+
// by the `typecheck` script). `tsconfig.json` beside this one stays exactly as
4+
// it is: it is the BUILD config. `package.json`'s `typecheck` script NAMES this
5+
// sibling (`tsc --noEmit -p tsconfig.test.json`), because a config no script
6+
// invokes reads as coverage and delivers none.
7+
//
8+
// WHAT THE BUILD CONFIG ALREADY DID. `tsconfig.json` includes `src/**/*` with no
9+
// test exclusion, so the program that reads these tests always existed; the
10+
// package simply declared no `typecheck` script, so nothing ever ran it. That
11+
// is the `service-automation` / `service-cluster` shape, not the
12+
// exclude-and-compensate one, and AGENTS.md forbids ADDING such an exclusion.
13+
//
14+
// What differs from the build config, and what deliberately does NOT:
15+
// - MODULE SEMANTICS and `lib`, nothing else. vitest runs these files as ESM
16+
// through esbuild on a Node that has the ES2022 builtins. `lib` keeps the
17+
// build config's `DOM` / `DOM.Iterable` (a child's `lib` REPLACES the
18+
// parent's, it does not merge) and adds ES2022 for the Node the suite runs
19+
// on. The build leg of the script (`tsc --noEmit`) keeps the NodeNext
20+
// reading of the same files.
21+
// - STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, `noUnusedParameters`,
22+
// `noImplicitReturns`, `noFallthroughCasesInSwitch`, `rootDir`, `paths` and
23+
// `types` are all INHERITED and none is re-declared. ⚠️ A child that declared
24+
// its own `paths` would REPLACE the parent map, so this file declares none.
25+
// Nothing here may loosen a type rule; if a test does not compile, that is
26+
// the finding.
27+
//
28+
// MEASURED at f8178ffece (origin/main), the workspace closure built first
29+
// (`turbo run build --filter='@objectstack/hono^...'`), BEFORE any fix, once per
30+
// config (`tsc --noEmit --pretty false [--listFiles] -p <config>`):
31+
//
32+
// program under this config 858 files (7 of them this package's `src`),
33+
// all 5 of its `src/**/*.test.ts` in it
34+
// BUILD config (tsconfig.json) 3 = TS2769 x2 + TS18046 x1
35+
// THIS config 3 = TS2769 x2 + TS18046 x1
36+
//
37+
// The two readings AGREE, so no config-tier pile; the 3 were code tier. All in
38+
// `hono.test.ts` (36, 69, 70): a bare `new Hono()` has Hono's default `Env`, which
39+
// declares no `Variables`, so `c.get('objectStack')` is typed as taking `never`
40+
// (TS2769 x2) and the `kernel` it returns is `unknown` (TS18046). The middleware
41+
// under test does `c.set('objectStack', kernel)`, so the two tests that read the
42+
// variable back now build their app as `new Hono<KernelEnv>()` with the variable
43+
// declared (`{ objectStack: { name: string } }`, the one field the test reads).
44+
// `objectStackMiddleware`'s `(c: any, next: any)` source signature was NOT touched.
45+
//
46+
// THESE 3 WERE NOT THE WHOLE PILE. With them fixed, THIS config reported 4 more:
47+
// TS2883 ("The inferred type of 'getDiscoveryInfo' cannot be named without a
48+
// reference to 'Procedure' from '.pnpm/@vitest+spy@4.1.11/...'") on the four
49+
// `vi.fn()` class fields of `src/__mocks__/runtime.ts`. tsc withholds
50+
// declaration-emit diagnostics while any semantic error stands, so the first
51+
// reading could not show them, and the BUILD config never shows them at all
52+
// (observed: exit 0 on the same file under NodeNext resolution; only this
53+
// config's `bundler` resolution reports it). The `DEBT` ledger's "3" was a count
54+
// of what the first config could see, not of what this layer holds. Repaired
55+
// at the cause, the same way as the others: the four fields are annotated
56+
// `Mock` (vitest's own mock type) instead of leaving the inferred type to name an
57+
// unexported pnpm-store path. No cast, no `@ts-expect-error`, no `src` change:
58+
// `src/__mocks__/runtime.ts` is a vitest alias target (`vitest.config.ts`), never
59+
// built or published (`tsup` enters `src/index.ts` alone).
60+
//
61+
// AFTER: 0 and 0. There is NO `test-typecheck-debt.json` beside this config, and
62+
// its ABSENCE is the zero: any error in any file here is red immediately, with no
63+
// ledger to be added to -- the same call `metadata-fs` and
64+
// `trigger-record-change` recorded.
65+
{
66+
"extends": "./tsconfig.json",
67+
"compilerOptions": {
68+
"noEmit": true,
69+
"module": "esnext",
70+
"moduleResolution": "bundler",
71+
"lib": ["ES2022", "DOM", "DOM.Iterable"]
72+
},
73+
"include": ["src/**/*"],
74+
"exclude": ["node_modules", "dist"]
75+
}

‎packages/cloud-connection/package.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
},
2121
"scripts": {
2222
"build": "tsup --config ../../tsup.config.ts && node ../../scripts/check-dts-emitted.mjs",
23-
"test": "vitest run"
23+
"test": "vitest run",
24+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json"
2425
},
2526
"dependencies": {
2627
"@objectstack/core": "workspace:*",

‎packages/cloud-connection/src/cloud-connection-plugin.test.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ describe('multi-tenant mode (env-registry + per-env kernel auth)', () => {
151151
it('install forwards to the control plane install action for an authenticated session', async () => {
152152
const rawApp = makeRawApp();
153153
const { ctx, fireKernelReady } = makeCtx({ rawApp, services: mtServices('user-1') });
154-
const fetchSpy = vi.fn(async () => new Response(JSON.stringify({ success: true, data: { installed: true } }), { status: 200 }));
154+
const fetchSpy = vi.fn(async (_url: string, _init?: RequestInit) => new Response(JSON.stringify({ success: true, data: { installed: true } }), { status: 200 }));
155155
vi.stubGlobal('fetch', fetchSpy);
156156
await new CloudConnectionPlugin({ controlPlaneUrl: 'http://cloud.test', controlPlaneApiKey: 'svc-key' }).start(ctx as any);
157157
await fireKernelReady();
@@ -180,7 +180,7 @@ describe('multi-tenant mode (env-registry + per-env kernel auth)', () => {
180180
const rawApp = makeRawApp();
181181
const { ctx, fireKernelReady } = makeCtx({ rawApp, services: mtServices('user-1') });
182182
const items = [{ id: 'pkg_a', manifest_id: 'com.acme.crm' }];
183-
const fetchSpy = vi.fn(async () => new Response(JSON.stringify({ success: true, data: { items } }), { status: 200 }));
183+
const fetchSpy = vi.fn(async (_url: string, _init?: RequestInit) => new Response(JSON.stringify({ success: true, data: { items } }), { status: 200 }));
184184
vi.stubGlobal('fetch', fetchSpy);
185185
await new CloudConnectionPlugin({ controlPlaneUrl: 'http://cloud.test', controlPlaneApiKey: 'svc-key' }).start(ctx as any);
186186
await fireKernelReady();
@@ -206,7 +206,7 @@ describe('single-environment mode (host auth, fixed env id)', () => {
206206
it('uses the configured environment id + the host kernel auth session', async () => {
207207
const rawApp = makeRawApp();
208208
const { ctx, fireKernelReady } = makeCtx({ rawApp, services: { auth: sessionAuth('admin-1') } });
209-
const fetchSpy = vi.fn(async () => new Response(JSON.stringify({ success: true, data: { packages: [{ id: 'p1' }] } }), { status: 200 }));
209+
const fetchSpy = vi.fn(async (_url: string, _init?: RequestInit) => new Response(JSON.stringify({ success: true, data: { packages: [{ id: 'p1' }] } }), { status: 200 }));
210210
vi.stubGlobal('fetch', fetchSpy);
211211
await new CloudConnectionPlugin({
212212
singleEnvironment: true,

‎packages/cloud-connection/src/connection-credential-store.test.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ describe('CloudConnectionPlugin credential behavior', () => {
112112
new ConnectionCredentialStore(credPath).write({ runtimeToken: 'oscc_stored', environmentId: 'env_1' });
113113
const rawApp = makeRawApp();
114114
const { ctx, fire } = makeCtx(rawApp, { auth: sessionAuth('admin'), manifest: { register: vi.fn() } });
115-
const fetchSpy = vi.fn(async () => new Response(JSON.stringify({ success: true, data: { items: [] } }), { status: 200 }));
115+
const fetchSpy = vi.fn(async (_url: string, _init?: RequestInit) => new Response(JSON.stringify({ success: true, data: { items: [] } }), { status: 200 }));
116116
vi.stubGlobal('fetch', fetchSpy);
117117
await new CloudConnectionPlugin({
118118
singleEnvironment: true, controlPlaneUrl: 'http://cloud.test', controlPlaneApiKey: '', credentialPath: credPath,
@@ -134,7 +134,7 @@ describe('CloudConnectionPlugin credential behavior', () => {
134134
store.write({ runtimeToken: 'oscc_stored', environmentId: 'env_1' });
135135
const rawApp = makeRawApp();
136136
const { ctx, fire } = makeCtx(rawApp, { auth: sessionAuth('admin'), manifest: { register: vi.fn() } });
137-
const fetchSpy = vi.fn(async () => new Response(JSON.stringify({ success: true }), { status: 200 }));
137+
const fetchSpy = vi.fn(async (_url: string, _init?: RequestInit) => new Response(JSON.stringify({ success: true }), { status: 200 }));
138138
vi.stubGlobal('fetch', fetchSpy);
139139
await new CloudConnectionPlugin({
140140
singleEnvironment: true, controlPlaneUrl: 'http://cloud.test', controlPlaneApiKey: '', credentialPath: credPath,
@@ -221,7 +221,7 @@ describe('CloudConnectionPlugin credential behavior', () => {
221221
store.write({ runtimeToken: 'oscc_stored', runtimeId: 'rt-1' });
222222
const rawApp = makeRawApp();
223223
const { ctx, fire } = makeCtx(rawApp, { auth: sessionAuth('admin'), manifest: { register: vi.fn() } });
224-
const fetchSpy = vi.fn(async () => new Response(JSON.stringify({ success: true }), { status: 200 }));
224+
const fetchSpy = vi.fn(async (_url: string, _init?: RequestInit) => new Response(JSON.stringify({ success: true }), { status: 200 }));
225225
vi.stubGlobal('fetch', fetchSpy);
226226
await new CloudConnectionPlugin({
227227
singleEnvironment: true, controlPlaneUrl: 'http://cloud.test', controlPlaneApiKey: '', credentialPath: credPath,
@@ -267,7 +267,7 @@ describe('CloudConnectionPlugin credential behavior', () => {
267267
new ConnectionCredentialStore(credPath).write({ runtimeToken: 'oscc_stored', runtimeId: 'rt-1' });
268268
const rawApp = makeRawApp();
269269
const { ctx, fire } = makeCtx(rawApp, { auth: sessionAuth('admin'), manifest: { register: vi.fn() } });
270-
const fetchSpy = vi.fn(async () => new Response(JSON.stringify({ success: true, data: { items: [{ id: 'p1' }] } }), { status: 200 }));
270+
const fetchSpy = vi.fn(async (_url: string, _init?: RequestInit) => new Response(JSON.stringify({ success: true, data: { items: [{ id: 'p1' }] } }), { status: 200 }));
271271
vi.stubGlobal('fetch', fetchSpy);
272272
await new CloudConnectionPlugin({
273273
singleEnvironment: true, controlPlaneUrl: 'http://cloud.test', controlPlaneApiKey: '', credentialPath: credPath,

‎packages/cloud-connection/src/marketplace-install-local-bundle.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ describe('install-local compiled-bundle normalization', () => {
7878

7979
// The UI bundle registers at kernel:ready; the LAST register call is
8080
// the installed package — flattened: top-level id + sections.
81-
const installed = register.mock.calls.at(-1)![0];
81+
const installed = register.mock.lastCall![0];
8282
expect(installed.id).toBe('app.acme.crm');
8383
expect(installed.namespace).toBe('crm');
8484
expect(installed.version).toBe('2.0.0');
@@ -103,6 +103,6 @@ describe('install-local compiled-bundle normalization', () => {
103103
makeC({ manifest: flat }),
104104
);
105105
expect(res.payload?.success).toBe(true);
106-
expect(register.mock.calls.at(-1)![0].id).toBe('com.acme.flat');
106+
expect(register.mock.lastCall![0].id).toBe('com.acme.flat');
107107
});
108108
});
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// The TEST-layer type-check program (#20800 -- the last three packages of the
2+
// #4311 ledger, graduated by the #15048 / #15050 road: a sibling program named
3+
// by the `typecheck` script). `tsconfig.json` beside this one stays exactly as
4+
// it is: it is the BUILD config. `package.json`'s `typecheck` script NAMES this
5+
// sibling (`tsc --noEmit -p tsconfig.test.json`), because a config no script
6+
// invokes reads as coverage and delivers none.
7+
//
8+
// WHAT THE BUILD CONFIG ALREADY DID. `tsconfig.json` includes `src` with no
9+
// test exclusion, so the program that reads these tests always existed; the
10+
// package simply declared no `typecheck` script, so nothing ever ran it. That
11+
// is the `service-automation` / `service-cluster` shape, not the
12+
// exclude-and-compensate one, and AGENTS.md forbids ADDING such an exclusion.
13+
//
14+
// What differs from the build config, and what deliberately does NOT:
15+
// - MODULE SEMANTICS and `lib`, nothing else. vitest runs these files as ESM
16+
// through esbuild on a Node that has the ES2022 builtins, and the root
17+
// config's `lib` is ES2020. `module: esnext` / `moduleResolution: bundler`
18+
// is the reading vitest really performs; the build leg of the script
19+
// (`tsc --noEmit`) keeps the stricter NodeNext reading of the same files,
20+
// so the two programs complement each other rather than overlap.
21+
// - STRICTNESS IS UNTOUCHED. `strict`, `noUnusedLocals`, `noUnusedParameters`,
22+
// `noImplicitReturns`, `noFallthroughCasesInSwitch`, `rootDir`, `paths` and
23+
// `types` are all INHERITED and none is re-declared. ⚠️ A child that declared
24+
// its own `paths` would REPLACE the parent map, so this file declares none.
25+
// Nothing here may loosen a type rule; if a test does not compile, that is
26+
// the finding.
27+
//
28+
// MEASURED at f8178ffece (origin/main), the workspace closure built first
29+
// (`turbo run build --filter='@objectstack/cloud-connection^...'`), BEFORE any
30+
// fix, once per config (`tsc --noEmit --pretty false [--listFiles] -p <config>`):
31+
//
32+
// program under this config 923 files (44 of them this package's `src`),
33+
// all 30 of its `src/**/*.test.ts` in it
34+
// BUILD config (tsconfig.json) 13 = TS2493 x11 + TS2550 x2
35+
// THIS config 11 = TS2493 x11
36+
//
37+
// The two readings DISAGREE by exactly two, and those two are the config tier:
38+
// TS2550 ("Property 'at' does not exist ... change your target library"), both
39+
// `Array#at` in `marketplace-install-local-bundle.test.ts` (81, 106) -- the CHECK
40+
// reading ES2020 where the runtime is Node >= 22, which is what `lib` below
41+
// reconciles. The other 11 are code tier and agree under both configs: TS2493
42+
// ("Tuple type '[]' of length '0' has no element at index N"), every one an
43+
// index into `fetchSpy.mock.calls[0]` where `fetchSpy = vi.fn(async () => ...)`
44+
// was declared with NO parameters, so vitest types `.mock.calls` as an array of
45+
// EMPTY tuples. The call site it stubs is `fetch(url, init)`, which the plugin
46+
// always calls with a string URL and an init object; the fix types each of the 7
47+
// declarations (`cloud-connection-plugin.test.ts` x3,
48+
// `connection-credential-store.test.ts` x4) to that call --
49+
// `vi.fn(async (_url: string, _init?: RequestInit) => ...)`. No cast was added,
50+
// no `@ts-expect-error`, no `src` signature touched.
51+
//
52+
// The build leg reads these tests under ES2020 too, so the two `Array#at` reads
53+
// were not left to this file's `lib`: they now use vitest's own
54+
// `mock.lastCall` (the LAST register call, which is what both comments say),
55+
// which compiles under both programs. Without that the first leg of `typecheck`
56+
// would stay red on files this leg accepts.
57+
//
58+
// AFTER: 0 and 0. There is NO `test-typecheck-debt.json` beside this config, and
59+
// its ABSENCE is the zero: any error in any file here is red immediately, with no
60+
// ledger to be added to -- the same call `metadata-fs` and
61+
// `trigger-record-change` recorded.
62+
{
63+
"extends": "./tsconfig.json",
64+
"compilerOptions": {
65+
"noEmit": true,
66+
"module": "esnext",
67+
"moduleResolution": "bundler",
68+
"lib": ["ES2022"]
69+
},
70+
"include": ["src/**/*"],
71+
"exclude": ["node_modules", "dist"]
72+
}

‎packages/observability/package.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
},
2121
"scripts": {
2222
"build": "tsup --config ../../tsup.config.ts && node ../../scripts/check-dts-emitted.mjs",
23-
"test": "vitest run"
23+
"test": "vitest run",
24+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json"
2425
},
2526
"dependencies": {
2627
"@objectstack/spec": "workspace:*"

0 commit comments

Comments
 (0)