|
| 1 | +--- |
| 2 | +"@objectstack/spec": major |
| 3 | +--- |
| 4 | + |
| 5 | +refactor(spec)!: retire three orphan operator vocabularies (objectui#2945 Track A) |
| 6 | + |
| 7 | +An audit of every comparison/aggregation vocabulary the spec ships |
| 8 | +(objectstack-ai/objectui#2901) found the operator vocabularies had multiplied |
| 9 | +past what any code consults. Three had **no importer at all** — not in this |
| 10 | +repo, not in objectui, not in cloud — and each contradicted the vocabulary that |
| 11 | +is actually enforced. Removed rather than reconciled: a second name for one |
| 12 | +concept is how they drifted apart in the first place. |
| 13 | + |
| 14 | +**`AggregationFunctionEnum`** (`shared/enums.zod.ts`). Its own doc comment |
| 15 | +claimed it was *"used across query, data-engine, analytics, field"*. It was used |
| 16 | +by nothing. `AggregationFunction` (`data/query.zod.ts`) is the vocabulary the |
| 17 | +query engine, `service-analytics`' dataset compiler and the native-SQL strategy |
| 18 | +all gate on — and the two disagreed: this one carried |
| 19 | +`percentile`/`median`/`stddev`/`variance`, that one carries |
| 20 | +`array_agg`/`string_agg`. It also exported a *type* named `AggregationFunction` |
| 21 | +while `data/query.zod.ts` exports a *value* of that name, so the two occupied |
| 22 | +the same identifier in different declaration spaces with different members. |
| 23 | + |
| 24 | +**`FilterOperator`** + `EventFilterCondition` + `EventFilterSchema` |
| 25 | +(`api/websocket.zod.ts`), reached from `EventSubscriptionSchema.filters`. No |
| 26 | +runtime ever evaluated an event filter — `matchesSubscription` matches on object |
| 27 | +name and event type only (`contracts/realtime-service.ts`) — and the |
| 28 | +subscription shape the transports actually carry is the separate, deliberately |
| 29 | +unvalidated `filters: z.unknown()` on `SubscriptionEventSchema` |
| 30 | +(`api/realtime.zod.ts`). So this was a *second* modelling of event filtering |
| 31 | +that described a capability no code provided: a subscriber who set `filters` |
| 32 | +received every event regardless. |
| 33 | + |
| 34 | +The `filters` **key stays**, now typed `z.unknown()` with the same |
| 35 | +NOT-YET-ENFORCED marker as its `api/realtime.zod.ts` counterpart. Retiring an |
| 36 | +object key requires a tombstone plus a conversion (ADR-0104), which is the right |
| 37 | +rule and the wrong trade here — there is no author to migrate for a shape nothing |
| 38 | +validated, and Track A is meant to carry no migration. The two subscription |
| 39 | +surfaces now describe event filtering identically, and neither implies an |
| 40 | +enforcement that does not exist. Whichever grows real filtering should lower onto |
| 41 | +`AST_OPERATOR_MAP` rather than reintroduce a vocabulary of its own. |
| 42 | + |
| 43 | +**`ODataFilterOperatorSchema`** (`api/odata.zod.ts`). Nothing parses an OData |
| 44 | +`$filter` against it — `$filter` is carried as an opaque string on |
| 45 | +`ODataQuerySchema` and as the `odata` adapter template in |
| 46 | +`query-adapter.zod.ts` — and an enum mixing operators with `(`/`)` could not |
| 47 | +validate an expression anyway, since it describes tokens, not a grammar. A real |
| 48 | +implementation needs a parser, and that parser should lower onto |
| 49 | +`AST_OPERATOR_MAP` like every other entry point. |
| 50 | + |
| 51 | +**Breaking, in the narrowest sense.** All three were reachable as public |
| 52 | +exports (`@objectstack/spec/shared` and `@objectstack/spec/api`), so this is a |
| 53 | +`major`. No consumer exists to break: verified by grep across framework |
| 54 | +`packages/` + `apps/`, objectui, and cloud. Nothing is *narrowed* — no accepted |
| 55 | +value stops being accepted, so no already-stored metadata or in-flight payload |
| 56 | +changes meaning. That is what made this the one track of objectui#2945 that was |
| 57 | +safe to start; narrowing `VALID_AST_OPERATORS` or retiring a |
| 58 | +`VIEW_FILTER_OPERATORS` alias is not, and remains blocked on #3948. |
| 59 | + |
| 60 | +The generated artefacts move with the deletions, as the ratchets require: |
| 61 | +`json-schema.manifest.json` drops the five unpublished schemas, |
| 62 | +`authorable-surface.json` the seven keys of the two deleted objects, |
| 63 | +`api-surface.json` the eight exports, and the three reference-doc pages are |
| 64 | +regenerated. |
| 65 | + |
| 66 | +Verified: full `@objectstack/spec` suite **6917 tests across 266 files**, plus |
| 67 | +`tsc --noEmit`, `check:docs`, `check:api-surface`, `check:authorable-surface` and |
| 68 | +`check:skill-docs`, all clean. |
0 commit comments