You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 9525651
Browse filesBrowse the repository at this point in the historyBrowse files
A dataset's date dimension reads the bucket key `@objectstack/core`'s `bucketDateKey` writes, with its year in four digits, and a draft preview keys a row the way the same dataset does once published.
6
+
7
+
-**Dimension labels (`queryDataset`).** A date dimension's grouped key is labelled as written. The year key `0050` was labelled `1970` (read as epoch seconds, because the year check admitted only 1000..9999), and a month or day key lost its padding (`0050-06` became `50-06`, `0050-06-15` became `50-06-15`). A raw date value is relabelled with the year in four digits too. A year from 1000 to 9999 is labelled as before.
8
+
-**Draft preview (`queryDataset` with `previewDrafts`).** Drafted seed rows are keyed by `bucketDateKey` itself, the key the published path's grouping writes. For 0050-06-15 the preview answered `50`, `50-Q2`, `50-06` and `50-06-15`; it now answers `0050`, `0050-Q2`, `0050-06` and `0050-06-15`. A `week` bucket is now the ISO week label (`2026-W25`), no longer the Monday's date (`2026-06-15`), so a weekly `compareTo` in the preview merges each comparison row onto its week, as the published path does. An epoch-milliseconds value is bucketed by its instant (it was the empty bucket), and a `Date` in 0001..0999 by its own year (a `Date` in 0050 keyed `1950`).
fix(formula,plugin-security): the refusal of a field-to-field comparison across comparison classes now leads with its remedy, so the remedy reaches REST callers (#20869)
7
+
8
+
Clause-②: no
9
+
10
+
A row-level policy that compares two fields of no shared comparison class (text against a number, or any field against a file field, a formula field, or a field that holds a list or an object) is refused with `INVALID_FILTER` / 400. The REST door keeps a 4xx message under 500 characters by cutting it to its first 499 characters plus an ellipsis. Both messages for this refusal put the remedy last, so the remedy was always cut off, and a caller read the diagnosis but never the fix:
11
+
12
+
- The record matcher's message (`@objectstack/formula`, raised by the RLS write check on an insert or update through `/data`) was 972 characters, with the remedy starting at character 825.
13
+
- The explain engine's message (`@objectstack/plugin-security`, answered by `GET` / `POST /api/v1/security/explain`) put the remedy after the policy names and the diagnostic. Those have no length limit, so the message was 601 characters with a short policy name and longer with longer names.
14
+
15
+
Both messages now start with the remedy. It is the same sentence as before and has only moved:
16
+
17
+
- The record matcher's message is 494 characters and reaches the wire whole. In order it says: the remedy; that the two columns share no class, and which classes exist; why the comparison is refused; and why the columns are not named. It still names no column, operator or policy; the server log names them.
18
+
- The explain engine's message starts with the remedy, then names the policy and both columns, then gives the reason. Whatever the names' length, the remedy sits in the first 125 characters. With long names the REST door may cut the reason at the end.
19
+
20
+
Unchanged: the error code (`INVALID_FILTER`), the status (400), which comparisons are refused, the refusal a find answers with (driver-sql's read refusal, 383 characters, which already reached the wire whole), and every other refusal.
0 commit comments