Skip to content

Commit a308aaa

Browse files
committed
test(runtime): the org-scope harness adds zero errors to the TEST_DEBT ledger (#7018)
`check:type-check-debt` went red on the merged base: `@objectstack/runtime`'s TEST_DEBT is a shrink-only ratchet (#5278) recording 227 raw errors, and the new file pushed the measured count to 240. The package's own `tsc --noEmit` never saw them — `tsconfig.json` excludes `*.test.ts`, which is the hidden layer that ledger exists to measure. Fixed rather than ledgered, since none of the 15 were irreducible: - `HttpDispatcherResult.response` is optional (a declining route answers `{ handled: false }`), so every `res.response.status` was a TS18048. One `responseOf()` helper says once, loudly, that these routes must answer, and hands back a narrowed response — instead of a narrowing dance at each of the 13 call sites. - the muting `console.warn` spy was bound to an unread variable (TS6133); only the `console.error` spy is read back, so only that one is bound now. - the `error.mock.calls` reducers carried implicit `any` parameters (TS7006). Measured with the ledger's own method — a sibling tsconfig that drops the test exclusion — over this file: 15 errors before, 0 after. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PiRUoQkTSBBmpyXBY3cVn2
1 parent f42f205 commit a308aaa

1 file changed

Lines changed: 36 additions & 23 deletions

File tree

packages/runtime/src/meta-write-org-scope.test.ts

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ import { assertEngineDeleteDispatch, assertEngineUpdateDispatch } from '@objects
6565
import { ObjectStackProtocolImplementation } from '@objectstack/metadata-protocol';
6666
import { DEFAULT_METADATA_TYPE_REGISTRY } from '@objectstack/spec/kernel';
6767
import { HttpDispatcher } from './http-dispatcher.js';
68+
import type { HttpDispatcherResult } from './http-dispatcher.js';
6869
import { declaresOrgOverride, organizationIdForMetaWrite } from './meta-write-org-scope.js';
6970

7071
const ACTIVE_ORG = 'org_alpha';
@@ -279,16 +280,28 @@ const VIEW = {
279280
/** `allowOrgOverride: false` — the ADR-0045 publish-visibility specimen. */
280281
const APP = { name: 'crm', label: 'CRM' };
281282

283+
/**
284+
* The dispatcher's `response` is optional on `HttpDispatcherResult` — a route
285+
* that declines answers `{ handled: false }`. Every case here drives a route
286+
* that MUST answer, so an absent response is a failure of the harness rather
287+
* than a value to narrow around at each call site: this says so once, loudly,
288+
* and hands back a response the assertions can read.
289+
*/
290+
function responseOf(result: HttpDispatcherResult): NonNullable<HttpDispatcherResult['response']> {
291+
const response = result.response;
292+
if (!response) throw new Error('the dispatcher handled the route but returned no response');
293+
return response;
294+
}
295+
282296
describe('#7018 — the registry decides whether a metadata write carries the session org', () => {
283-
let warn: ReturnType<typeof vi.spyOn>;
284297
let error: ReturnType<typeof vi.spyOn>;
285298

286299
beforeEach(() => {
287300
// The protocol logs degradation lines on these paths; they are not the
288301
// subject and must not drown the run. `error` is spied rather than
289302
// silenced-and-forgotten — the ADR-0045 flip reports its own failure
290303
// there (#4754), and the last case reads it back.
291-
warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
304+
vi.spyOn(console, 'warn').mockImplementation(() => {});
292305
error = vi.spyOn(console, 'error').mockImplementation(() => {});
293306
});
294307

@@ -317,9 +330,9 @@ describe('#7018 — the registry decides whether a metadata write carries the se
317330
it('a NON-overridable type lands env-wide even though the session has an active org', async () => {
318331
const { engine, dispatcher } = makeStack(ACTIVE_ORG);
319332

320-
const res = await dispatcher.handleMetadata(`/flow/${FLOW.name}`, ctx(), 'PUT', FLOW);
333+
const res = responseOf(await dispatcher.handleMetadata(`/flow/${FLOW.name}`, ctx(), 'PUT', FLOW));
321334

322-
expect(res.response.status).toBe(200);
335+
expect(res.status).toBe(200);
323336
const row = metaRow(engine, 'flow', FLOW.name);
324337
expect(row).toBeDefined();
325338
// THE assertion. Before #7018 this was `'org_alpha'` — a row
@@ -337,9 +350,9 @@ describe('#7018 — the registry decides whether a metadata write carries the se
337350
fields: { subject: { type: 'text', label: 'Subject' } },
338351
};
339352

340-
const res = await dispatcher.handleMetadata(`/object/${OBJECT.name}`, ctx(), 'PUT', OBJECT);
353+
const res = responseOf(await dispatcher.handleMetadata(`/object/${OBJECT.name}`, ctx(), 'PUT', OBJECT));
341354

342-
expect(res.response.status).toBe(200);
355+
expect(res.status).toBe(200);
343356
expect(metaRow(engine, 'object', OBJECT.name)!.organization_id).toBeNull();
344357
});
345358

@@ -352,20 +365,20 @@ describe('#7018 — the registry decides whether a metadata write carries the se
352365
const withOrg = makeStack(ACTIVE_ORG);
353366
const withoutOrg = makeStack(undefined);
354367

355-
const a = await withOrg.dispatcher.handleMetadata(`/flow/${FLOW.name}`, ctx(), 'PUT', FLOW);
356-
const b = await withoutOrg.dispatcher.handleMetadata(`/flow/${FLOW.name}`, ctx(), 'PUT', FLOW);
368+
const a = responseOf(await withOrg.dispatcher.handleMetadata(`/flow/${FLOW.name}`, ctx(), 'PUT', FLOW));
369+
const b = responseOf(await withoutOrg.dispatcher.handleMetadata(`/flow/${FLOW.name}`, ctx(), 'PUT', FLOW));
357370

358-
expect(a.response.status).toBe(200);
359-
expect(a.response.body.data).toEqual(b.response.body.data);
360-
expect(a.response.body.data).toMatchObject({ success: true, state: 'active' });
371+
expect(a.status).toBe(200);
372+
expect(a.body.data).toEqual(b.body.data);
373+
expect(a.body.data).toMatchObject({ success: true, state: 'active' });
361374
});
362375

363376
it('CONTROL — an `allowOrgOverride: true` type keeps its org scoping exactly as before', async () => {
364377
const { engine, dispatcher } = makeStack(ACTIVE_ORG);
365378

366-
const res = await dispatcher.handleMetadata(`/view/${VIEW.name}`, ctx(), 'PUT', VIEW);
379+
const res = responseOf(await dispatcher.handleMetadata(`/view/${VIEW.name}`, ctx(), 'PUT', VIEW));
367380

368-
expect(res.response.status).toBe(200);
381+
expect(res.status).toBe(200);
369382
// ADR-0005's per-org overlay is the point of the flag and must survive
370383
// this change untouched — `getMetaItem`/`getMetaItems` load it on demand.
371384
expect(metaRow(engine, 'view', VIEW.name)!.organization_id).toBe(ACTIVE_ORG);
@@ -374,9 +387,9 @@ describe('#7018 — the registry decides whether a metadata write carries the se
374387
it('CONTROL — the plural URL spelling of an overridable type is scoped the same way', async () => {
375388
const { engine, dispatcher } = makeStack(ACTIVE_ORG);
376389

377-
const res = await dispatcher.handleMetadata(`/views/${VIEW.name}`, ctx(), 'PUT', VIEW);
390+
const res = responseOf(await dispatcher.handleMetadata(`/views/${VIEW.name}`, ctx(), 'PUT', VIEW));
378391

379-
expect(res.response.status).toBe(200);
392+
expect(res.status).toBe(200);
380393
expect(metaRow(engine, 'view', VIEW.name)!.organization_id).toBe(ACTIVE_ORG);
381394
});
382395

@@ -403,11 +416,11 @@ describe('#7018 — the registry decides whether a metadata write carries the se
403416
success: true, publishedCount: 0, failedCount: 0, published: [], failed: [],
404417
});
405418

406-
const res = await dispatcher.handlePackages('/crm_pkg/publish-drafts', 'POST', {}, {}, ctx());
419+
const res = responseOf(await dispatcher.handlePackages('/crm_pkg/publish-drafts', 'POST', {}, {}, ctx()));
407420

408-
expect(res.response.status).toBe(200);
409-
expect(res.response.body.data.unhiddenApps).toEqual([APP.name]);
410-
expect(res.response.body.data.unhideError).toBeUndefined();
421+
expect(res.status).toBe(200);
422+
expect(res.body.data.unhiddenApps).toEqual([APP.name]);
423+
expect(res.body.data.unhideError).toBeUndefined();
411424

412425
// One row, still env-wide — not a second, org-scoped row shadowing it.
413426
const appRows = engine.metaRows().filter((r: any) => r.type === 'app' && r.state === 'active');
@@ -438,12 +451,12 @@ describe('#7018 — the registry decides whether a metadata write carries the se
438451
});
439452
error.mockClear();
440453

441-
const res = await dispatcher.handlePackages('/crm_pkg/publish-drafts', 'POST', {}, {}, ctx());
454+
const res = responseOf(await dispatcher.handlePackages('/crm_pkg/publish-drafts', 'POST', {}, {}, ctx()));
442455

443-
expect(res.response.body.data.unhiddenApps).toEqual([APP.name]);
444-
const flipComplaints = error.mock.calls
456+
expect(res.body.data.unhiddenApps).toEqual([APP.name]);
457+
const flipComplaints = (error.mock.calls as unknown[][])
445458
.map((c) => String(c[0]))
446-
.filter((line) => line.includes('visibility flip'));
459+
.filter((line: string) => line.includes('visibility flip'));
447460
expect(flipComplaints).toEqual([]);
448461
});
449462
});

0 commit comments

Comments
 (0)