Skip to content

Commit fcb6cfa

Browse files
os-zhuangclaude
andauthored
test(runtime): the dispatcher envelope check uses the shared predicate (#4090 follow-up) (#4105)
* test(runtime): the dispatcher envelope check uses the shared predicate (#4090 follow-up) `domain-handler-registry.test.ts` hand-rolled "no key beside the envelope's own may hold the payload" for #4038. #4090 extracted that rule into `envelopeViolations` so it stops having two definitions; this is the caller that motivated the extraction, now using it. Leaving the local copy would have recreated the exact failure this line has been closing — one rule, two places, and only one of them updated next time. It also was not the same rule: the local set allowed any body whose top-level keys were success/data/meta, so it passed a success body with NO `data` at all, and one carrying an `error` alongside `success: true`. The shared predicate rejects both. Verified the swap is a strict improvement rather than a refactor, by breaking the producer two ways and checking the suite catches each: { success: true, data: link, link } → caught (the old check caught this too) { success: true } → caught (the old check PASSED this) runtime 914 passed. All ten gates in the TypeScript Type Check job pass, plus the six `check:*` guards. Note for the next person touching spec: after restarting a branch onto a newer main, `check:api-surface` and `check:i18n-coverage` both fail against a stale `packages/spec/dist` — the first reports other people's exports as added/removed, the second rejects an example config for a chart type the fresh spec allows. Neither is a real failure; rebuilding spec clears both. They read as "my change broke something" and are not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CYbS3kS8xzsHNXFTzp4e2z * chore: add the empty changeset this PR needs Check Changeset requires one on every PR; an empty-frontmatter changeset is the sanctioned form for a change that releases nothing, and the gate's own error message says so. Second time this session — #4009 was a comment-only PR that failed the same way. I fixed that one and did not draw the rule, which is that "this releases nothing" is a reason to write an EMPTY changeset, not a reason to skip the file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CYbS3kS8xzsHNXFTzp4e2z --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 85761cf commit fcb6cfa

2 files changed

Lines changed: 28 additions & 6 deletions

File tree

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
---
3+
4+
`domain-handler-registry.test.ts` now uses `envelopeViolations` instead of its own
5+
copy of the rule. Deliberately empty frontmatter: test-only, this releases nothing.
6+
7+
That test hand-rolled "no key beside the envelope's own may hold the payload" for
8+
#4038. #4090 promoted the rule into the spec so it would stop having two
9+
definitions; leaving the local copy would have recreated the exact failure this
10+
line has been closing — one rule, two places, only one updated next time.
11+
12+
The two were also not equivalent. The local set allowed any body whose top-level
13+
keys were `success` / `data` / `meta`, so it passed a success body with no `data`
14+
at all and one carrying an `error` beside `success: true`. The shared predicate
15+
rejects both, which makes this a strict tightening rather than a refactor:
16+
injecting `{ success: true }` into the producer now fails the suite, and used to
17+
pass it.

packages/runtime/src/domain-handler-registry.test.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515

1616
import { describe, it, expect, vi } from 'vitest';
17+
import { envelopeViolations } from '@objectstack/spec/api';
1718
import { HttpDispatcher } from './http-dispatcher.js';
1819
import { DomainHandlerRegistry } from './domain-handler-registry.js';
1920
import type { DomainHandler } from './domain-handler-registry.js';
@@ -391,9 +392,15 @@ describe('HttpDispatcher extracted domains (PR-4: share-links)', () => {
391392
});
392393

393394
it('every success body carries its payload under `data` and nowhere else', async () => {
394-
// The general form of the two assertions above, over all four success
395-
// routes: no key beside the envelope's own may hold the payload.
396-
const ENVELOPE_KEYS = new Set(['success', 'data', 'meta']);
395+
// The general form of the two assertions above, over all the success
396+
// routes — and `envelopeViolations` (#4090) is now where that general form
397+
// lives. This test hand-rolled it first, for #4038; extracting it into the
398+
// spec meant the same rule stopped having two definitions that could drift
399+
// apart, which is the failure this whole line has been closing.
400+
//
401+
// The shared one is also stricter than what stood here: the local set
402+
// allowed any body whose keys were `success`/`data`/`meta`, so it passed a
403+
// success body with no `data` at all and one carrying an `error`.
397404
const shareLinks = {
398405
createLink: vi.fn().mockResolvedValue(LINK),
399406
listLinks: vi.fn().mockResolvedValue([LINK]),
@@ -407,9 +414,7 @@ describe('HttpDispatcher extracted domains (PR-4: share-links)', () => {
407414
];
408415
for (const body of bodies) {
409416
expect(body?.success).toBe(true);
410-
for (const key of Object.keys(body ?? {})) {
411-
expect(ENVELOPE_KEYS.has(key), `body carries a non-envelope top-level key: ${key}`).toBe(true);
412-
}
417+
expect(envelopeViolations(body), `not the declared envelope: ${JSON.stringify(body)}`).toEqual([]);
413418
}
414419
});
415420

0 commit comments

Comments
 (0)