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
2 changes: 1 addition & 1 deletion packages/spec/src/api/ai-agents-envelope.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ describe('GET /ai/agents — the shapes a producer must NOT drift back into', ()
expect(servesTheDeclaredShape(body)).toBe(false);
});

it('the pre-#4053 bare body — no flag for `unwrapResponse` to key on', () => {
it('the bare body from before the envelope relocation — no flag for `unwrapResponse` to key on', () => {
const body = { agents: [ASK] };
expect(servesTheDeclaredShape(body)).toBe(false);
expect(envelopeViolations(body)).toContain('success is missing, must be a boolean');
Expand Down
6 changes: 3 additions & 3 deletions packages/spec/src/api/analytics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe('AnalyticsEndpoint', () => {
});
});

describe('AnalyticsQueryRequestSchema — the BARE AnalyticsQuery shape (#3878)', () => {
describe('AnalyticsQueryRequestSchema — the BARE AnalyticsQuery shape', () => {
it('should accept a minimal bare query', () => {
const req = AnalyticsQueryRequestSchema.parse({
cube: 'orders',
Expand Down Expand Up @@ -104,7 +104,7 @@ describe('AnalyticsQueryRequestSchema — the BARE AnalyticsQuery shape (#3878)'
).toThrow();
});

it('should reject the retired {cube, query: {...}} envelope (#3891 shim dialect)', () => {
it('should reject the retired {cube, query: {...}} envelope (the degraded shim dialect)', () => {
expect(() =>
AnalyticsQueryRequestSchema.parse({
cube: 'orders',
Expand Down Expand Up @@ -384,7 +384,7 @@ describe('GetAnalyticsMetaRequestSchema', () => {
* replaced by the assertion that carries the actual load of this change: the
* previously-declared shape is now rejected.
*/
describe('AnalyticsMetadataResponseSchema — the CubeMeta[] projection (#6442)', () => {
describe('AnalyticsMetadataResponseSchema — the CubeMeta[] projection', () => {
/**
* A real `GET /analytics/meta` body: what `AnalyticsService.getMeta` builds —
* measure/dimension names CUBE-QUALIFIED, `title` projected from the
Expand Down
2 changes: 1 addition & 1 deletion packages/spec/src/api/api-entry-graph.pin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ function valueGraph(entry: string): Set<string> {
return new Set([...seen].map((f) => relative(SRC, f).split('\\').join('/')));
}

describe('`@objectstack/spec/api` stays off the assembled package body (#18576 ruling, letter B)', () => {
describe('`@objectstack/spec/api` stays off the assembled package body (ruled: split the entry rather than watch its weight)', () => {
const api = valueGraph('api/index.ts');
const assembled = valueGraph('api-assembled/index.ts');

Expand Down
2 changes: 1 addition & 1 deletion packages/spec/src/api/api-error-code-type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ function refusalAt(result: z.ZodSafeParseResult<unknown>): Array<{ code: string;
return (result.error?.issues ?? []).map((issue) => ({ code: issue.code, path: issue.path }));
}

describe('[#19920] ApiError.code is typed as the vocabulary its schema parses against', () => {
describe('ApiError.code is typed as the vocabulary its schema parses against', () => {
it('every body the type refuses is refused by the schema at `code`', () => {
expect(refusalAt(ApiErrorSchema.safeParse({ code: 42, message: 'x' }))).toEqual([
{ code: 'invalid_value', path: ['code'] },
Expand Down
24 changes: 12 additions & 12 deletions packages/spec/src/api/apis-publish-gates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ function accept(stack: Record<string, unknown>) {
return result.success ? result.data.apis : undefined;
}

describe('[#5111] the flip — a well-formed `apis:` publishes', () => {
describe('the flip — a well-formed `apis:` publishes', () => {
it('accepts an object_operation endpoint under the stack\'s own namespace', () => {
const apis = accept({ manifest, apis: [validObjectEndpoint] });
expect(apis).toHaveLength(1);
Expand Down Expand Up @@ -149,7 +149,7 @@ describe('[#5111] the flip — a well-formed `apis:` publishes', () => {
});
});

it('still accepts an EMPTY and an ABSENT `apis:` — the #4936 regression pin', () => {
it('still accepts an EMPTY and an ABSENT `apis:` — never refused, even while a non-empty one was', () => {
expect(ObjectStackDefinitionSchema.safeParse({ manifest, apis: [] }).success).toBe(true);
expect(ObjectStackDefinitionSchema.safeParse({ manifest }).success).toBe(true);
expect(() => defineStack({ manifest, apis: [] })).not.toThrow();
Expand All @@ -162,7 +162,7 @@ describe('[#5111] the flip — a well-formed `apis:` publishes', () => {
});
});

describe('[#5111] gate (c) — namespace carve-out (ADR-0121 D1/D2)', () => {
describe('gate (c) — namespace carve-out (ADR-0121 D1/D2)', () => {
it('rejects a path outside the `apps/<namespace>/` mount, naming the endpoint and the shape', () => {
const message = reject({
manifest,
Expand Down Expand Up @@ -214,7 +214,7 @@ describe('[#5111] gate (c) — namespace carve-out (ADR-0121 D1/D2)', () => {
});
});

describe('[#5310] the `path` vocabulary text is itself publishable', () => {
describe('the `path` vocabulary text is itself publishable', () => {
/**
* `ApiEndpointSchema.path`'s `.describe()` is not a code comment. Since `api`
* became a registered metadata kind (#5271) it is the field help the
Expand Down Expand Up @@ -273,7 +273,7 @@ describe('[#5310] the `path` vocabulary text is itself publishable', () => {
});
});

describe('[#5111] gate (a) — the supported subset (mirrors `planEndpointTarget`)', () => {
describe('gate (a) — the supported subset (mirrors `planEndpointTarget`)', () => {
it("rejects `type: 'script'` with the flow prescription", () => {
const message = reject({
manifest,
Expand Down Expand Up @@ -324,7 +324,7 @@ describe('[#5111] gate (a) — the supported subset (mirrors `planEndpointTarget
});
});

describe('[#5111] gate (b) — mapping declarations (mirrors `mappingDeclarationRejection`)', () => {
describe('gate (b) — mapping declarations (mirrors `mappingDeclarationRejection`)', () => {
const bodyEndpoint = {
...validObjectEndpoint,
name: 'showcase_task_create',
Expand Down Expand Up @@ -399,7 +399,7 @@ describe('[#5111] gate (b) — mapping declarations (mirrors `mappingDeclaration
});
});

describe('[#5111] gate (e) — policy keys (ADR-0121 D6 + the E4 refusals)', () => {
describe('gate (e) — policy keys (ADR-0121 D6 + the E4 refusals)', () => {
it('rejects `authRequired: false` with NO rateLimit', () => {
const message = reject({ manifest, apis: [{ ...validFlowEndpoint, authRequired: false }] });
expect(message).toMatch(/ADR-0121 D6|armed rate limit/i);
Expand Down Expand Up @@ -464,7 +464,7 @@ describe('[#5111] gate (e) — policy keys (ADR-0121 D6 + the E4 refusals)', ()
});
});

describe('[#5111] gate (d) — one claim per METHOD + path inside a stack', () => {
describe('gate (d) — one claim per METHOD + path inside a stack', () => {
it('rejects two endpoints claiming the same method and path, naming BOTH', () => {
const message = reject({
manifest,
Expand Down Expand Up @@ -508,7 +508,7 @@ describe('[#5111] gate (d) — one claim per METHOD + path inside a stack', () =
});
});

describe('[#5111] every rejection is actionable, and reaches every publish seam', () => {
describe('every rejection is actionable, and reaches every publish seam', () => {
it('reports one issue per offending endpoint — three bad endpoints, three rejections', () => {
const result = ObjectStackDefinitionSchema.safeParse({
manifest,
Expand Down Expand Up @@ -538,7 +538,7 @@ describe('[#5111] every rejection is actionable, and reaches every publish seam'
});
});

describe('[#5111] the `ApiEndpoint` vocabulary itself is untouched', () => {
describe('the `ApiEndpoint` vocabulary itself is untouched', () => {
// Anti-vacuity for the whole file: the flip is validation logic on the
// EXISTING keys. If a key had been added, removed or renamed, every
// assertion above could still pass while the frozen-vocabulary constraint
Expand All @@ -565,7 +565,7 @@ describe('[#5111] the `ApiEndpoint` vocabulary itself is untouched', () => {
expect(parsed.authRequired).toBe(true);
});

it('keeps endpoint-level `rateLimit` in the vocabulary (#4910-Q2 routed it here)', () => {
it('keeps endpoint-level `rateLimit` in the vocabulary (ruled: left to the endpoint executor, not the server-level seam)', () => {
const parsed = ApiEndpointSchema.parse({
name: 'x_endpoint',
path: '/api/v1/apps/showcase/x',
Expand Down Expand Up @@ -594,7 +594,7 @@ describe('identityFreeEndpointGateFailure — the same judge, minus stack identi
expect(identityFreeEndpointGateFailure(ApiEndpointSchema.parse(validObjectEndpoint))).toBeUndefined();
});

it('still refuses D6 — the gate with no runtime counterpart, and the reason #5189 exists', () => {
it('still refuses D6 — the gate with no runtime counterpart, so the per-item publish path runs it too', () => {
const failure = identityFreeEndpointGateFailure(
ApiEndpointSchema.parse({ ...validObjectEndpoint, cacheTtlSeconds: undefined, authRequired: false }),
);
Expand Down
4 changes: 2 additions & 2 deletions packages/spec/src/api/auth-endpoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ describe('AuthEndpointSchema', () => {
// leave nothing to grep (#3733, ADR-0104) — the tombstone is what makes the
// withdrawal audible, so it is pinned on both legs: the prescription a writer
// hits, and the absence a reader gets.
describe('AuthFeaturesConfig retired flags (#7481)', () => {
describe('AuthFeaturesConfig retired flags (ruled: stop advertising them)', () => {
const valid = { twoFactor: false, organization: true };

it('rejects `passkeys` with its own prescription, naming the missing consumer', () => {
Expand Down Expand Up @@ -181,7 +181,7 @@ describe('getAuthEndpointUrl', () => {
// than a bare unrecognized-key error, and the value survives at the same
// magnitude. Asserting the message, not just `.toThrow()`: a bare throw stays
// green when the schema throws for some unrelated reason.
describe('DeviceRequestResponse.interval \u2192 intervalSeconds (#15677)', () => {
describe('DeviceRequestResponse.interval \u2192 intervalSeconds', () => {
const base = {
code: 'ABCD-1234',
verificationUrl: 'https://example.com/device',
Expand Down
4 changes: 2 additions & 2 deletions packages/spec/src/api/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ describe('SessionUserSchema', () => {
});
});

describe('SessionUser.language retirement (#14788, ADR-0049 — maintainer ruling D, 2026-09-03)', () => {
describe('SessionUser.language retirement (ADR-0049 — ruled: gone, with no replacement field)', () => {
const base = { id: 'usr_1', email: 'a@b.com', name: 'A' };

it('REJECTS a `language` value, with the prescription in the message', () => {
Expand Down Expand Up @@ -152,7 +152,7 @@ describe('SessionUser.language retirement (#14788, ADR-0049 — maintainer rulin
// and the excluded ledger really is where the key's record lives.
expect(fs.existsSync(tombstone)).toBe(true);
expect(fs.existsSync(path.join(ledger, 'entries', 'retired-keys', '18.api__SessionUser__language.ts'))).toBe(true);
expect(readers, 'a reader of SessionUser.language reappeared — the key is retired (#14788)').toEqual([]);
expect(readers, 'a reader of SessionUser.language reappeared — the key is retired').toEqual([]);
});
});

Expand Down
8 changes: 4 additions & 4 deletions packages/spec/src/api/automation-api.zod.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ describe('AutomationRunPathParamsSchema', () => {
// List Flows — RETIRED (#19543, door ④)
// ==========================================

describe('the GET /api/v1/automation flow-list door is retired (#19543)', () => {
describe('the GET /api/v1/automation flow-list door is retired', () => {
// Flows are metadata (ADR-0106); the list is `GET /api/v1/meta/flow`. The
// three schemas left with the route and are registered as whole-def removals
// (`RETIRED_DEFS_BY_MAJOR[18]`), so an export that came back would be a
Expand Down Expand Up @@ -324,7 +324,7 @@ describe('TriggerFlowResponseSchema', () => {
// undeclared keys (BaseResponseSchema.extend + plain z.object), so before
// the widening the paused-run triple below "passed" while the parse silently
// dropped `status`, the `runId` a caller resumes with and the whole screen.
it('should preserve the paused-run triple — status, runId and the screen (#9378/#9510 third state)', () => {
it('should preserve the paused-run triple — status, runId and the screen (a pause is the third state, not a failure)', () => {
const result = TriggerFlowResponseSchema.parse({
success: true,
data: {
Expand Down Expand Up @@ -596,7 +596,7 @@ describe('ListRunsRequestSchema', () => {
})).toThrow();
});

it('declares exactly the canonical ExecutionStatus set (#7359)', () => {
it('declares exactly the canonical ExecutionStatus set', () => {
// The wire's filter and the runtime boundary that now enforces it must
// accept ONE set. The boundary reads `ExecutionStatus.options`; this pins
// that the schema does too, so a member added to the enum cannot end up
Expand Down Expand Up @@ -754,7 +754,7 @@ describe('AutomationApiContracts', () => {
expect(Object.keys(AutomationApiContracts)).toHaveLength(8);
});

it('declares no flow-list entry and no GET at the bare /api/v1/automation path (#19543)', () => {
it('declares no flow-list entry and no GET at the bare /api/v1/automation path', () => {
expect(Object.keys(AutomationApiContracts)).not.toContain('listFlows');
const routes = Object.values(AutomationApiContracts).map((c) => `${c.method} ${c.path}`);
expect(routes).not.toContain('GET /api/v1/automation');
Expand Down
4 changes: 2 additions & 2 deletions packages/spec/src/api/batch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ describe('BatchOptionsSchema', () => {
expect(options.continueOnError).toBe(true);
});

it('rejects the retired `validateOnly` key with its prescription (#3963 follow-up)', () => {
it('rejects the retired `validateOnly` key with its prescription', () => {
// Never implemented — a "dry-run" that silently persisted. Tombstoned so
// writing it is audible rather than silently stripped (ADR-0104 / PD #10).
const result = BatchOptionsSchema.safeParse({ validateOnly: true });
Expand Down Expand Up @@ -197,7 +197,7 @@ describe('UpdateManyRequestSchema', () => {
// had already drifted: batch.zod's accepted `{}` rows, protocol.zod's required
// id+data, and only the latter was ever enforced. Pin the relationship so a
// future edit to one cannot silently fork them again.
describe('protocol request schemas derive from the wire-body schemas (#3939)', () => {
describe('protocol request schemas derive from the wire-body schemas', () => {
it('updateMany: same record shape, plus object', async () => {
const { UpdateManyDataRequestSchema } = await import('./protocol.zod');
const records = [{ id: '1', data: { name: 'x' } }];
Expand Down
6 changes: 3 additions & 3 deletions packages/spec/src/api/contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,7 @@ describe('QueryOptimizationConfigSchema', () => {
* unregistered code must still fail, and `ApiErrorSchema` must not have been
* widened by the factory's existence.
*/
describe('makeApiErrorSchema (federated ledger, #4805)', () => {
describe('makeApiErrorSchema (federated ledger)', () => {
const DOWNSTREAM_CODES = ['CONTACT_SALES_PLAN', 'PRODUCTION_ENV_LIMIT'] as const;
const DownstreamApiError = makeApiErrorSchema(DOWNSTREAM_CODES);

Expand Down Expand Up @@ -778,7 +778,7 @@ describe('makeApiErrorSchema (federated ledger, #4805)', () => {
// than a bare unrecognized-key error, and the value survives at the same
// magnitude. Asserting the message, not just `.toThrow()`: a bare throw stays
// green when the schema throws for some unrelated reason.
describe('DataLoaderConfig.cacheTtl \u2192 cacheTtlSeconds (#15677)', () => {
describe('DataLoaderConfig.cacheTtl \u2192 cacheTtlSeconds', () => {
it('REFUSES the retired `cacheTtl` spelling with the rename in the message', () => {
const result = DataLoaderConfigSchema.safeParse({ cacheTtl: 60 });
expect(result.success).toBe(false);
Expand Down Expand Up @@ -810,7 +810,7 @@ describe('DataLoaderConfig.cacheTtl \u2192 cacheTtlSeconds (#15677)', () => {
// contradict, the declaration is taken from the sibling channel that does speak:
// every key in this spec that spells the unit for a processing time spells
// milliseconds (`tracing.durationMs`, `worker.durationMs`, `worker.avgExecutionMs`).
describe('BaseResponse.meta.duration declares milliseconds (#18124)', () => {
describe('BaseResponse.meta.duration declares milliseconds', () => {
it('refuses a fractional millisecond count', () => {
const result = BaseResponseSchema.safeParse({
success: true,
Expand Down
10 changes: 5 additions & 5 deletions packages/spec/src/api/dataset-selection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ const SHARED_WITH_ANALYTICS_QUERY = [

const DATASET_ONLY = ['runtimeFilter', 'dateGranularity', 'compareTo', 'totals'] as const;

describe('#17551 §1 — a transcription of published text, not a new contract', () => {
describe('§1 — a transcription of published text, not a new contract', () => {
it('the seven shared members ARE `AnalyticsQuery`’s declarations, by identity', () => {
const selection = DatasetSelectionSchema.shape as Record<string, unknown>;
const query = AnalyticsQuerySchema.shape as Record<string, unknown>;
Expand Down Expand Up @@ -126,7 +126,7 @@ describe('#17551 §1 — a transcription of published text, not a new contract',
// §2 — ⭐ #17550's case: an unrecognised `compareTo.kind`
// ─────────────────────────────────────────────────────────────────────────────

describe('#17550 §2 — `compareTo: { kind: … }` outside the closed pair is refused, with a remedy', () => {
describe('§2 — `compareTo: { kind: … }` outside the closed pair is refused, with a remedy', () => {
it('the card’s own specimen is refused', () => {
const text = refusalText({ measures: ['revenue'], compareTo: { kind: 'nonsense' } });
// ① what arrived — so the caller can find it in the body they sent.
Expand Down Expand Up @@ -191,7 +191,7 @@ describe('#17550 §2 — `compareTo: { kind: … }` outside the closed pair is r
// §3 — the other three undoored members, both directions each
// ─────────────────────────────────────────────────────────────────────────────

describe('#17551 §3 — `runtimeFilter` / `dateGranularity` / `totals`', () => {
describe('§3 — `runtimeFilter` / `dateGranularity` / `totals`', () => {
it('`dateGranularity` outside the closed vocabulary is refused; every member of it passes', () => {
expect(refusalText({ measures: ['revenue'], dateGranularity: 'fortnight' }))
.toMatch(/fortnight|Invalid option/);
Expand Down Expand Up @@ -240,7 +240,7 @@ describe('#17551 §3 — `runtimeFilter` / `dateGranularity` / `totals`', () =>
// §4 — an unknown key is named, echoed and pointed somewhere
// ─────────────────────────────────────────────────────────────────────────────

describe('#17551 §4 — the selection is `.strict()`, like every other analytics door', () => {
describe('§4 — the selection is `.strict()`, like every other analytics door', () => {
it('names the surface, echoes the key, and carries the history', () => {
const text = refusalText({ measures: ['revenue'], totaIs: { groupings: [[]] } });
expect(text).toContain('Unrecognized key(s) on this dataset selection');
Expand All @@ -264,7 +264,7 @@ describe('#17551 §4 — the selection is `.strict()`, like every other analytic
// §5 — ⭐ the negative side: the whole shape still passes, unchanged
// ─────────────────────────────────────────────────────────────────────────────

describe('#17551 §5 — a valid selection still passes, and the parse adds nothing', () => {
describe('§5 — a valid selection still passes, and the parse adds nothing', () => {
it('the fully-loaded eleven-member selection parses', () => {
const parsed = DatasetSelectionSchema.safeParse(FULLY_LOADED);
expect(parsed.success, parsed.success ? '' : JSON.stringify(parsed.error.issues)).toBe(true);
Expand Down
Loading
Loading