Skip to content

Commit a1402a3

Browse files
committed
fix(spec): cut three over-claims from the filter-is-empty migration guidance and one from its changeset
The at-tier review's wording flags, folded in as cuts: - acceptanceCriteria: "it now also selects the rows holding the empty string or the empty list" read as if is_not_empty gained those rows; it loses them. - acceptanceCriteria: "fails with INVALID_FILTER" — the analytics read scope fails with a different code. - reason: "while the three builders already showed them as empty" is cut. - changeset: "and the prescription `$null`" — the read-scope envelope's message does not spell it; the FROM → TO lines carry the remedy. registry.ts regenerated by gen:migration-registry. Claude-Session: https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1 Co-authored-by: Claude <noreply@anthropic.com>
1 parent 395c531 commit a1402a3

3 files changed

Lines changed: 13 additions & 13 deletions

File tree

‎.changeset/20446-empty-joins-filter-operators.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ A stored 「is empty」 / 「is not empty」 — `['field', 'is_empty', …]`, `
1212

1313
- **A `{ $empty: … }` object written as a field value** (a `where` pasted into an insert or update payload) is refused with `VALIDATION_FAILED` (`invalid_type`, "$empty is a filter operator, not a value"). Before, a text-like field stored it as data.
1414
FROM `update('task', { title: { $empty: true } })` → TO write the value itself (`{ title: '' }`, `{ title: null }`); a filter belongs in `where`.
15-
- **`is_empty` / `is_not_empty` where no face holds the column's declared type** is refused with `INVALID_FILTER` / 400 (`READ_SCOPE_COMPILE_FAILED` / 500 on an analytics read scope) and the prescription `$null`. The `$null` lowering answered these. The compositions:
15+
- **`is_empty` / `is_not_empty` where no face holds the column's declared type** is refused with `INVALID_FILTER` / 400 (`READ_SCOPE_COMPILE_FAILED` / 500 on an analytics read scope). The `$null` lowering answered these. The compositions:
1616
- the built-in `id`, which no object declares. FROM `['id', 'is_empty', true]` → TO `['id', 'is_null', true]` / `is_not_null`;
1717
- a federated (external) object on a driver that does not implement `registerExternalObject` (driver-memory, driver-mongodb). The boot already reports such an object as NOT bound to its remote table, naming it, and its reads answered from a table named after the object. FROM `is_empty` on such an object → TO bind it on a driver that implements federation (driver-sql and its heirs, driver-turso);
1818
- an `AnalyticsService` constructed without `sourceFieldMeta`. FROM such a host → TO pass `sourceFieldMeta` (the package README shows it), or filter with `is_null` / `is_not_null`;

‎packages/spec/src/migrations/entries/semantic/18.filter-is-empty-lowers-to-empty-operator.ts‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ export const entry: SemanticMigration = {
3636
+ 'of FILTER_OPERATORS until every face answered it, then added in the same change that flipped '
3737
+ 'the lowering, after measuring that no face drops it. Two consequences reach stored metadata. '
3838
+ 'A stored 「is empty」 on a text or multi-value field finds more rows: the ones holding the '
39-
+ 'empty string or the empty list, which the $null lowering missed while the three builders '
40-
+ 'already showed them as empty. And the rule is refused, loudly and with the $null '
39+
+ 'empty string or the empty list, which the $null lowering missed. '
40+
+ 'And the rule is refused, loudly and with the $null '
4141
+ 'prescription, where the face that answers it holds no declaration for the column — the four '
4242
+ 'compositions the replacement names — where the $null lowering compiled IS NULL. The same '
4343
+ 'change made the write door refuse a $empty object as a field value, because that door '
@@ -47,10 +47,10 @@ export const entry: SemanticMigration = {
4747
+ 'ADR-0087 / ADR-0112.',
4848
acceptanceCriteria:
4949
'Grep your stored views, sharing rules and filter arrays for is_empty / is_not_empty. On a text '
50-
+ 'or multi-value field, re-check what the view or rule is supposed to select: it now also '
51-
+ 'selects the rows holding the empty string or the empty list. On the built-in id, rewrite it '
50+
+ 'or multi-value field, re-check what the view or rule is supposed to select. '
51+
+ 'On the built-in id, rewrite it '
5252
+ 'to is_null / is_not_null. If a federated object on driver-memory or driver-mongodb, or an '
53-
+ 'AnalyticsService host without sourceFieldMeta, carries such a rule, the query now fails with '
54-
+ 'INVALID_FILTER instead of answering — bind the object on a federation-capable driver, or pass '
53+
+ 'AnalyticsService host without sourceFieldMeta, carries such a rule, the query now fails '
54+
+ 'instead of answering — bind the object on a federation-capable driver, or pass '
5555
+ 'sourceFieldMeta. No insert or update payload carries a $empty object as a field value.',
5656
};

‎packages/spec/src/migrations/registry.ts‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10882,8 +10882,8 @@ const step18: MigrationStep = {
1088210882
+ 'of FILTER_OPERATORS until every face answered it, then added in the same change that flipped '
1088310883
+ 'the lowering, after measuring that no face drops it. Two consequences reach stored metadata. '
1088410884
+ 'A stored 「is empty」 on a text or multi-value field finds more rows: the ones holding the '
10885-
+ 'empty string or the empty list, which the $null lowering missed while the three builders '
10886-
+ 'already showed them as empty. And the rule is refused, loudly and with the $null '
10885+
+ 'empty string or the empty list, which the $null lowering missed. '
10886+
+ 'And the rule is refused, loudly and with the $null '
1088710887
+ 'prescription, where the face that answers it holds no declaration for the column — the four '
1088810888
+ 'compositions the replacement names — where the $null lowering compiled IS NULL. The same '
1088910889
+ 'change made the write door refuse a $empty object as a field value, because that door '
@@ -10893,11 +10893,11 @@ const step18: MigrationStep = {
1089310893
+ 'ADR-0087 / ADR-0112.',
1089410894
acceptanceCriteria:
1089510895
'Grep your stored views, sharing rules and filter arrays for is_empty / is_not_empty. On a text '
10896-
+ 'or multi-value field, re-check what the view or rule is supposed to select: it now also '
10897-
+ 'selects the rows holding the empty string or the empty list. On the built-in id, rewrite it '
10896+
+ 'or multi-value field, re-check what the view or rule is supposed to select. '
10897+
+ 'On the built-in id, rewrite it '
1089810898
+ 'to is_null / is_not_null. If a federated object on driver-memory or driver-mongodb, or an '
10899-
+ 'AnalyticsService host without sourceFieldMeta, carries such a rule, the query now fails with '
10900-
+ 'INVALID_FILTER instead of answering — bind the object on a federation-capable driver, or pass '
10899+
+ 'AnalyticsService host without sourceFieldMeta, carries such a rule, the query now fails '
10900+
+ 'instead of answering — bind the object on a federation-capable driver, or pass '
1090110901
+ 'sourceFieldMeta. No insert or update payload carries a $empty object as a field value.',
1090210902
},
1090310903
// Ruling A on #19886, item 1: the $ne slot's half of the question

0 commit comments

Comments
 (0)