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
Expand Up @@ -78,12 +78,12 @@ describe('AGGREGATE_FIELD_TYPE_COMPATIBILITY — the ruled rows, resolved agains
expect(sorted(AGGREGATE_FIELD_TYPE_COMPATIBILITY.count)).toEqual(sorted(FieldType.options));
});

it('[#20808] `count_distinct`: every FieldType EXCEPT the JSON-stored ones', () => {
it('`count_distinct`: every FieldType EXCEPT the JSON-stored ones', () => {
expect(sorted(AGGREGATE_FIELD_TYPE_COMPATIBILITY.count_distinct))
.toEqual(sorted(FieldType.options.filter((t) => !JSON_STORED.includes(t))));
});

it('[#20808] the JSON-stored bucket IS the field-value structured-JSON class plus the multi-option types', () => {
it('the JSON-stored bucket IS the field-value structured-JSON class plus the multi-option types', () => {
// A type joining either class elsewhere is stored in a JSON column by every
// SQL driver, and no two backends compare such values alike — so it reds
// here until the count_distinct row records a decision.
Expand Down Expand Up @@ -147,7 +147,7 @@ describe('isAggregateCompatibleWithFieldType — the pairs the card is about', (
}
});

it('accepts `sum` / `avg` / `min` / `max` over booleans — #11152 (numbers on every backend), upheld by decision batch #80', () => {
it('accepts `sum` / `avg` / `min` / `max` over booleans — numbers on every backend, a ruling that outranks the refused-by-default rule', () => {
for (const fn of ['sum', 'avg', 'min', 'max'] as const) {
expect(isAggregateCompatibleWithFieldType(fn, 'boolean')).toBe(true);
expect(isAggregateCompatibleWithFieldType(fn, 'toggle')).toBe(true);
Expand Down Expand Up @@ -181,7 +181,7 @@ describe('isAggregateCompatibleWithFieldType — the pairs the card is about', (
}
});

it('[#20808] accepts `count_distinct` over every scalar-stored type — `formula`, `percent`, `select`, `lookup`, `file` included — and refuses the JSON-stored ones', () => {
it('accepts `count_distinct` over every scalar-stored type — `formula`, `percent`, `select`, `lookup`, `file` included — and refuses the JSON-stored ones', () => {
for (const t of FieldType.options) {
expect(isAggregateCompatibleWithFieldType('count_distinct', t), t).toBe(!JSON_STORED.includes(t));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const RETIRED_SPELLINGS = [
'',
];

describe('AnalyticsQuerySchema.timeDimensions[].dateRange — closed vocabulary (#16041)', () => {
describe('AnalyticsQuerySchema.timeDimensions[].dateRange — closed vocabulary', () => {
it('derives the string arm from date-range-presets.ts — no fourth copy of the list', () => {
// The module header records the vocabulary once existed in three drifting
// copies. The enum's options ARE the module's tuple, in its order.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const REFUSED_ARITIES: ReadonlyArray<readonly unknown[]> = [
['{7_days_ago}'], // one macro token is a bound, not a window
];

describe('AnalyticsDateRangeSchema — the array arm is exactly two string bounds (#17598 ①)', () => {
describe('AnalyticsDateRangeSchema — the array arm is exactly two string bounds', () => {
it('accepts the two-bound windows the contract has always prescribed', () => {
// The control. Without it a narrowing that refused EVERY array would pass
// every refusal assertion below.
Expand Down Expand Up @@ -127,7 +127,7 @@ describe('AnalyticsDateRangeSchema — the array arm is exactly two string bound
});
});

describe('analyticsDateRangeRefusalMessage — each ORIGIN gets a true sentence (#17598 ②)', () => {
describe('analyticsDateRangeRefusalMessage — each ORIGIN gets a true sentence', () => {
it('states the schema origin only when the schema is where it was refused', () => {
for (const input of [...REFUSED_ARITIES, 'Last 7 days', 42, null]) {
const atSchema = analyticsDateRangeRefusalMessage(input, 'schema');
Expand Down Expand Up @@ -170,7 +170,7 @@ describe('analyticsDateRangeRefusalMessage — each ORIGIN gets a true sentence
expect(analyticsDateRangeRefusalMessage({ start: '2026-01-01' }, 'schema')).toContain('received object');
});

it('⭐ names the EMPTY bound the arm cannot refuse, at the bound that is empty (#18278)', () => {
it('⭐ names the EMPTY bound the arm cannot refuse, at the bound that is empty', () => {
// The premise, asserted rather than assumed: the tuple arm judges arity and
// bound TYPE, never a bound's VALUE, so this window is ACCEPTED at the
// schema door and refused PAST it — the residue
Expand Down
4 changes: 2 additions & 2 deletions packages/spec/src/data/analytics-query-window-integer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const ACCEPTED: ReadonlyArray<[string, Record<string, unknown>]> = [
];

for (const [name, schema, base] of DOORS) {
describe(`[#21365] ${name} — the window is a non-negative integer`, () => {
describe(`${name} — the window is a non-negative integer`, () => {
for (const [label, window, key, code] of REFUSED) {
it(`refuses ${label} at \`${key}\``, () => {
const r = schema.safeParse({ ...base, ...window });
Expand All @@ -88,7 +88,7 @@ for (const [name, schema, base] of DOORS) {
});
}

describe('[#21365] the dataset selection holds the query\'s own declarations, not a copy', () => {
describe('the dataset selection holds the query\'s own declarations, not a copy', () => {
it('`limit` and `offset` on DatasetSelectionSchema are the AnalyticsQuerySchema instances', () => {
expect(DatasetSelectionSchema.shape.limit).toBe(AnalyticsQuerySchema.shape.limit);
expect(DatasetSelectionSchema.shape.offset).toBe(AnalyticsQuerySchema.shape.offset);
Expand Down
18 changes: 9 additions & 9 deletions packages/spec/src/data/analytics-strictness-batchd.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const QUERY = { cube: 'batchd_probe', measures: ['count'] } as const;
// ===========================================================================
// 1. The doors — a parse must exist, or none of the rest means anything
// ===========================================================================
describe('#4001 batch D — the doors the cube family is reachable through', () => {
describe('batch D, unknown keys refused — the doors the cube family is reachable through', () => {
it('`defineCube()` is a real parse door — it throws on a malformed config', () => {
expect(() => defineCube({ ...CUBE, notACubeKey: 1 } as never)).toThrow(/notACubeKey/);
});
Expand All @@ -90,7 +90,7 @@ describe('#4001 batch D — the doors the cube family is reachable through', ()
expect(reject(ObjectStackDefinitionSchema, stack)).toContain('publik');
});

it('[#10194] `analytics_cube` now resolves the SAME schema at the saveMetaItem door', () => {
it('`analytics_cube` now resolves the SAME schema at the saveMetaItem door', () => {
// This pin used to assert the opposite — `getMetadataTypeSchema` answering
// `undefined` — and its comment demanded that the ADR-0010 envelope
// question be re-asked before the line was "fixed". It was: commit 2306a765c bound
Expand Down Expand Up @@ -128,7 +128,7 @@ describe('#4001 batch D — the doors the cube family is reachable through', ()
// ===========================================================================
// 2. Every closed site, at its own path, through its real carrier
// ===========================================================================
describe('#4001 batch D — closed sites reject unknown keys where they live', () => {
describe('batch D — closed sites reject unknown keys where they live', () => {
it('`Cube` — the top-level cube shape', () => {
expect(reject(CubeSchema, { ...CUBE, publik: true })).toContain('publik');
});
Expand Down Expand Up @@ -245,7 +245,7 @@ describe('#4001 batch D — closed sites reject unknown keys where they live', (
// ===========================================================================
// 3. The curation — each alias anchored to the declaration that makes it true
// ===========================================================================
describe('#4001 batch D — alias claims are true of the surfaces they point at', () => {
describe('batch D, unknown keys refused — alias claims are true of the surfaces they point at', () => {
it('`title` → `label` on Metric/Dimension, and `label` → `title` on Cube: each spelling is CORRECT on the other surface', () => {
// The claims are structural: CubeSchema declares `title`, Metric/Dimension
// declare `label`. If either declaration changes, this pins the alias table
Expand All @@ -267,7 +267,7 @@ describe('#4001 batch D — alias claims are true of the surfaces they point at'
expect(reject(AnalyticsQuerySchema, { ...QUERY, orderBy: { stage: 'asc' } })).toContain('order');
});

it('`filters` gets the wrong-layer prescription (`where`), matching the dispatcher\'s #3878 bespoke hint', () => {
it('`filters` gets the wrong-layer prescription (`where`), matching the dispatcher\'s bespoke hint at the /analytics entry', () => {
const issues = reject(AnalyticsQuerySchema, { ...QUERY, filters: { is_active: true } });
expect(issues).toContain('where');
});
Expand All @@ -285,7 +285,7 @@ describe('#4001 batch D — alias claims are true of the surfaces they point at'
// ===========================================================================
// 4. The REST wrapper still composes — strictness rides `.extend()` correctly
// ===========================================================================
describe('#4001 batch D — the strict base does not break the request wrapper', () => {
describe('batch D — the strict base does not break the request wrapper', () => {
it('a valid request body still parses through `AnalyticsQueryRequestSchema`', () => {
accept(AnalyticsQueryRequestSchema, {
...QUERY,
Expand All @@ -294,7 +294,7 @@ describe('#4001 batch D — the strict base does not break the request wrapper',
});
});

it('the #3878 tombstones still fire — `query` and `format` carry their migration text', () => {
it('the retired-envelope tombstones still fire — `query` and `format` carry their migration text', () => {
expect(reject(AnalyticsQueryRequestSchema, { ...QUERY, query: { measures: ['count'] } })).toContain('was removed from AnalyticsQueryRequest');
expect(reject(AnalyticsQueryRequestSchema, { ...QUERY, format: 'csv' })).toContain('was removed from AnalyticsQueryRequest');
});
Expand All @@ -303,8 +303,8 @@ describe('#4001 batch D — the strict base does not break the request wrapper',
// ===========================================================================
// 5. The shapes this batch deliberately did NOT close, with the reason
// ===========================================================================
describe('#4001 batch D — deliberate non-closures (re-verdicts, not omissions)', () => {
it('`LocationValueSchema` / `AddressSchema` are CLOSED since #13802 — the batch-D `open` verdict was overruled', () => {
describe('batch D, unknown keys refused — deliberate non-closures (re-verdicts, not omissions)', () => {
it('`LocationValueSchema` / `AddressSchema` are CLOSED now — the batch-D `open` verdict was overruled', () => {
// Batch D pinned these two as tolerant ("a phone's geolocation payload
// carries `heading`/`speed`; a geocoder's address carries `district`") and
// said the day the line went red, the decision would have been made
Expand Down
12 changes: 6 additions & 6 deletions packages/spec/src/data/analytics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ describe('TimeUpdateInterval', () => {
expect(TimeUpdateInterval.options).toEqual(DateGranularity.options);
});

it('refuses each retired sub-day interval with the retirement prescription (#17296)', () => {
it('refuses each retired sub-day interval with the retirement prescription', () => {
// COST DIRECTION. The cheap narrowing is the enum alone: delete three
// members and let zod answer its stock "invalid option". That parses
// identically and tells an upgrading author nothing, so what is pinned
Expand Down Expand Up @@ -147,7 +147,7 @@ describe('MetricSchema', () => {
// `expect(metric.filters).toHaveLength(1)`). The pin flips: the refusal must
// carry the prescription — the fully-qualified key, the removal, and the
// migration channel — not merely throw.
it('rejects the removed `filters` key with the retirement prescription (#10414)', () => {
it('rejects the removed `filters` key with the retirement prescription', () => {
expect(() => MetricSchema.parse({
label: 'Average Order Value',
type: 'avg',
Expand All @@ -163,7 +163,7 @@ describe('MetricSchema', () => {
// refused, the key-equal one included, and the refusal carries the
// prescription. The full door-by-door pin lives in
// `cube-member-inner-name-retirement.test.ts`.
it('refuses the retired inner `name` with the prescription, whatever its value (#20300)', () => {
it('refuses the retired inner `name` with the prescription, whatever its value', () => {
for (const name of ['total_revenue', 'TotalRevenue', '']) {
expect(() => MetricSchema.parse({ name, label: 'Total Revenue', type: 'sum', sql: 'amount' }), name)
.toThrow(/`measures\.<metric>\.name` was removed in @objectstack\/spec 17\.5\.0.*the record key is the metric's name.*os migrate meta --from 17/s);
Expand Down Expand Up @@ -237,7 +237,7 @@ describe('DimensionSchema', () => {

// #20300 — the same flip as the metric's (see that block): the snake_case
// check on the inner `name` pinned a value nothing read.
it('refuses the retired inner `name` with the prescription, whatever its value (#20300)', () => {
it('refuses the retired inner `name` with the prescription, whatever its value', () => {
for (const name of ['product_category', 'ProductCategory']) {
expect(() => DimensionSchema.parse({ name, label: 'Product Category', type: 'string', sql: 'category' }), name)
.toThrow(/`dimensions\.<dimension>\.name` was removed in @objectstack\/spec 17\.5\.0.*the record key is the dimension's name.*os migrate meta --from 17/s);
Expand Down Expand Up @@ -311,7 +311,7 @@ describe('CubeJoinSchema', () => {
* shape). The conversion is `retiredFromLoadPath`, so the AUTHORING funnel still
* teaches the tombstone; the data-at-rest seams pin `includeRetired: true`.
*/
describe('a persisted cube heals at the door (#18612, ADR-0087 D2)', () => {
describe('a persisted cube heals at the door — the retired join `sql` / `relationship` are stripped (ADR-0087 D2)', () => {
/** What `CubeSchema.parse` itself emitted before this retirement. */
const persisted = () => ({
analyticsCubes: [{
Expand Down Expand Up @@ -532,7 +532,7 @@ describe('AnalyticsQuerySchema', () => {
}
});

it('should NOT default timezone -- absence means the engine resolves it (#4538)', () => {
it('should NOT default timezone -- absence means the engine resolves it', () => {
const query = AnalyticsQuerySchema.parse({
measures: ['orders.count'],
});
Expand Down
12 changes: 6 additions & 6 deletions packages/spec/src/data/api-derivation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from './api-derivation';
import { ApiMethod, API_OPERATION_ORDER, LEGACY_API_METHODS } from './object.zod';

describe('api-derivation (#3391)', () => {
describe('api-derivation — one table resolves the effective operations from six primitives', () => {
describe('three-state mode', () => {
it('undefined apiMethods → unrestricted', () => {
const eff = resolveEffectiveApiMethods({});
Expand All @@ -29,7 +29,7 @@ describe('api-derivation (#3391)', () => {
expect(isApiOperationAllowed(eff, 'bulk')).toBe(true);
});

it('empty array → deny-all (flipped semantics, #3391)', () => {
it('empty array → deny-all (flipped semantics)', () => {
const eff = resolveEffectiveApiMethods({ apiMethods: [] });
expect(eff.mode).toBe('deny-all');
for (const p of API_PRIMITIVES) expect(isApiOperationAllowed(eff, p)).toBe(false);
Expand Down Expand Up @@ -95,7 +95,7 @@ describe('api-derivation (#3391)', () => {
expect(isApiOperationAllowed(resolveEffectiveApiMethods({ apiMethods: ['get'], trackHistory: false }), 'history')).toBe(false);
});

it('restore/purge never derive (trash flag retired, #2377)', () => {
it('restore/purge never derive (trash flag retired)', () => {
const eff = resolveEffectiveApiMethods({ apiMethods: ['get', 'list', 'create', 'update', 'delete'] });
expect(isApiOperationAllowed(eff, 'restore')).toBe(false);
expect(isApiOperationAllowed(eff, 'purge')).toBe(false);
Expand Down Expand Up @@ -133,7 +133,7 @@ describe('api-derivation (#3391)', () => {
});
});

describe('legacy values are ignored — strip semantics (#3543)', () => {
describe('legacy values are ignored — strip semantics', () => {
it('a whitelist of ONLY legacy values resolves to deny-all', () => {
const eff = resolveEffectiveApiMethods({ apiMethods: ['import'] });
expect(eff.mode).toBe('deny-all');
Expand All @@ -159,7 +159,7 @@ describe('api-derivation (#3391)', () => {
});
});

describe('present-but-unreadable policy fails CLOSED (#3545)', () => {
describe('present-but-unreadable policy fails CLOSED', () => {
it('a non-array apiMethods resolves to deny-all, not unrestricted', () => {
const eff = resolveEffectiveApiMethods({ apiMethods: 'get,list' as unknown as string[] });
expect(eff.mode).toBe('deny-all');
Expand Down Expand Up @@ -283,7 +283,7 @@ describe('api-derivation (#3391)', () => {
expect(overlap).toEqual([]);
});

describe('vocabulary split (#3543)', () => {
describe('vocabulary split — authors write six primitives, the wire speaks operations', () => {
it('the authored enum is exactly the six primitives', () => {
expect(ApiMethod.options).toEqual([...API_PRIMITIVES]);
});
Expand Down
8 changes: 4 additions & 4 deletions packages/spec/src/data/api-methods-batch-conformance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ const SINGLE_RECORD_WRITE_ONLY: Record<string, string> = {
"ADR-0092 D2's identity write guard admits). No console surface multi-selects " +
'API keys — the grid renders no checkbox column because the object grants no ' +
'delete affordance — and a promoted bulk revoke would fan out per row through ' +
'the action runner rather than hitting /batch (#7802).',
'the action runner rather than hitting /batch.',
// #15873 — maintainer ruling 2026-09-07 (decision batch #64, option (a),
// verbatim 「同意」): the data door admits `update` so an administrator can set
// the four platform-owned columns (`require_mfa`, `parent_organization_id`,
Expand Down Expand Up @@ -227,12 +227,12 @@ const SINGLE_RECORD_WRITE_ONLY: Record<string, string> = {
// both stand.
sys_organization:
'Administrators set the platform-owned columns through single-record PATCH ' +
'and the derived update-mode import door (#15873 ruled `update`; both are ' +
'and the derived update-mode import door (a ruling grants `update`; both are ' +
'column-clamped per row by ADR-0092 D2). `bulk` — /batch and the *Many ' +
'routes — is not granted: no console surface multi-selects organizations ' +
'(the list view declares no bulk actions and the object grants no delete ' +
'affordance), and a promoted bulk edit would fan out per row through the ' +
'action runner rather than hitting /batch (#7802).',
'action runner rather than hitting /batch.',
};

/** Every `*.object.ts` under `packages/`, skipping build output and deps. */
Expand Down Expand Up @@ -292,7 +292,7 @@ function collectWhitelists(): Whitelist[] {

const WHITELISTS = collectWhitelists();

describe('apiMethods conformance — single-record writes imply batch (#3026)', () => {
describe('apiMethods conformance — single-record writes imply batch', () => {
it('scans a plausible number of declarations (guards a silently empty sweep)', () => {
// A scan that matches nothing passes every assertion below vacuously — the
// exact failure mode this file exists to prevent. Pin a floor instead.
Expand Down
Loading
Loading