|
89 | 89 | * them at all, so a predicate using one silently stops being portable. |
90 | 90 | * - **A relation field is its FOREIGN KEY**, on every surface and on the |
91 | 91 | * server: `record.f_lookup == "<id>"`, never `record.f_lookup.id`. |
92 | | - * - **The RECORD HEADER does not speak CEL** (objectui#3521). It evaluates |
93 | | - * header-action predicates on objectui's legacy JS evaluator, so `.size()`, |
94 | | - * `.contains()`, `.matches()`, the `in` operator and stdlib calls like |
95 | | - * `today()` all THROW there and fail-closed hide the action, while the same |
96 | | - * predicate is correct in the row kebab and the selection bar. Every gate |
97 | | - * below that uses one of those is therefore absent from the `⋯` menu today |
98 | | - * and present in the list — see `ZooDialectSplitAction` for the one-screen |
99 | | - * comparison. Predicates built only from `==` / `!=` / `<` / `&&` / `||` / |
100 | | - * `!` agree on both. |
| 92 | + * - **The RECORD HEADER speaks CEL, like every other record surface.** |
| 93 | + * Measured in a browser at the pinned objectui (`.objectui-sha` |
| 94 | + * `82a94170c405`), on both specimens: `.contains()`, `.size()`, |
| 95 | + * `.matches()`, the `in` operator, `has()` and stdlib calls like `today()` |
| 96 | + * all evaluate on the record header and in its `⋯` overflow. Where the same |
| 97 | + * action is also declared elsewhere it agrees: the row `⋮` menu matches the |
| 98 | + * header on both specimens, and so does the selection bar for the six |
| 99 | + * specimens the view names in `bulkActions`. `record_header` / `record_more` |
| 100 | + * hand the predicate to `evalRowPredicate` WHOLE, so the |
| 101 | + * `{ dialect: 'cel' }` envelope `defineAction` normalizes to is routed to |
| 102 | + * the canonical engine rather than flattened onto a dialect guess. |
| 103 | + * |
| 104 | + * ⚠️ This bullet used to say the opposite — that the header ran objectui's |
| 105 | + * legacy JS evaluator and fail-closed hid every CEL-only gate (objectui#3521, |
| 106 | + * pre-#3314 behaviour). That was stale, and it is recorded rather than |
| 107 | + * deleted because of what it would have cost: after #8990 every gate in this |
| 108 | + * file opens with `has(...)`, which the legacy evaluator answers with |
| 109 | + * `"has" is not a function`, so had the claim still been true, all 51 |
| 110 | + * header-located gates would have been silently absent from the `⋯` menu. |
| 111 | + * Measured instead: the menu offers them, and hides exactly the ones whose |
| 112 | + * predicate is false on that record. ⛔ Do not restore the claim from a |
| 113 | + * source read — it is falsifiable in a browser in one click, which is the |
| 114 | + * only way it was ever settled (objectstack#9281). |
101 | 115 | * |
102 | 116 | * ## `visible` has three authoring forms, one meaning |
103 | 117 | * |
@@ -227,26 +241,49 @@ export const ZooUserIdentityGateAction = defineAction({ |
227 | 241 | }); |
228 | 242 |
|
229 | 243 | /** |
230 | | - * **The dialect split.** One action, one predicate, two surfaces — and, as of |
231 | | - * this writing, two different answers. |
| 244 | + * **The dialect PIN.** One action, one CEL-only predicate, declared on all |
| 245 | + * three `RECORD_SURFACES` — and, measured, one answer on each of them. |
| 246 | + * |
| 247 | + * `.contains()` is ordinary CEL, and this action is where "the record header |
| 248 | + * runs the same engine as the row kebab" is falsifiable in one click. Measured |
| 249 | + * in a browser at pinned objectui `82a94170c405`, signed in as the seeded |
| 250 | + * admin (objectstack#9281): |
| 251 | + * |
| 252 | + * | surface | Specimen — Full | Specimen — Minimal | |
| 253 | + * |---|---|---| |
| 254 | + * | record header `⋯` (`record_more`) | OFFERED | absent | |
| 255 | + * | row `⋮` menu (`list_item`) | OFFERED | absent | |
| 256 | + * |
| 257 | + * ⚠️ The selection bar is deliberately NOT a row of that table: this action is |
| 258 | + * not named in either view's `bulkActions` (`field-zoo.view.ts`), so it never |
| 259 | + * reaches that surface at all — an absence of DECLARATION, which would read as |
| 260 | + * an absence of dialect support if tabulated beside the other two. The |
| 261 | + * three-surface agreement is pinned instead by the neighbours that ARE declared |
| 262 | + * on all three: `ZooVisibleStringAction` and its two twins, and |
| 263 | + * `ZooRelationGateAction` — whose `.size()` call is CEL-only and which likewise |
| 264 | + * appears on all three for Full and on none for Minimal. |
232 | 265 | * |
233 | | - * `.contains()` is ordinary CEL and evaluates correctly wherever the canonical |
234 | | - * engine runs: the row `⋮` menu, the selection bar, conditional formatting. The |
235 | | - * RECORD HEADER does not run that engine — it evaluates header-action |
236 | | - * predicates on objectui's legacy JS evaluator — so the same predicate throws |
237 | | - * there (`.contains` is not a JS string method) and the action is fail-closed |
238 | | - * hidden. Measured, not assumed: the browser console carries |
239 | | - * `[page:header] action "…" hidden: its predicate threw`. |
| 266 | + * Both columns are load-bearing. `f_textarea` is `'Line one\nLine two'` on Full |
| 267 | + * and `null` on Minimal, so the RIGHT column is what proves the header is |
| 268 | + * evaluating rather than offering everything: the same action on the same |
| 269 | + * surface flips with the record. The browser console carries no |
| 270 | + * `page:header action "…" visible` fail-closed warning on either record — the |
| 271 | + * predicate is answering, not faulting. |
240 | 272 | * |
241 | | - * The same split hides every CEL-only construct on that one surface — |
242 | | - * `.size()`, `.matches()`, the `in` operator, and stdlib calls like `today()` |
243 | | - * (`"today" is not a function`). Filed as objectui#3521; kept here as a LIVE |
244 | | - * fixture rather than papered over, because "works in the list, silently gone |
245 | | - * on the detail page" is invisible to any test that exercises one surface. |
| 273 | + * ⚠️ This action used to be framed as **the dialect SPLIT** — the live |
| 274 | + * demonstration that the header ran objectui's legacy JS evaluator and threw on |
| 275 | + * `.contains()` (objectui#3521), with "when #3521 lands, this action should |
| 276 | + * appear in the header too — that is the test." That test has since passed: |
| 277 | + * objectui#3314 stopped the header hand-unwrapping the envelope, and |
| 278 | + * `evalRowPredicate` routes `{ dialect: 'cel' }` to `@objectstack/formula`. The |
| 279 | + * fixture keeps its name and its value — inverted. It no longer demonstrates a |
| 280 | + * split; it is the sentinel that FAILS if a surface ever demotes to the legacy |
| 281 | + * dialect again, which is why it keeps all three `locations` rather than being |
| 282 | + * deleted along with the claim. |
246 | 283 | * |
247 | 284 | * Compare it against `ZooVisibleStringAction` above, whose predicate uses only |
248 | | - * operators BOTH dialects share and therefore agrees on every surface. When |
249 | | - * #3521 lands, this action should appear in the header too — that is the test. |
| 285 | + * operators both dialects share: that one agreed across surfaces even while the |
| 286 | + * split was real, so it cannot detect a demotion. This one can. |
250 | 287 | */ |
251 | 288 | export const ZooDialectSplitAction = defineAction({ |
252 | 289 | name: 'showcase_zoo_dialect_split', |
|
0 commit comments