Commit f6cd635
* fix(formula): converge the CEL pushdown parser onto the canonical front end, with an rc grace window (#6132)
`packages/formula/src/cel-to-filter.ts` — the one canonical CEL →
FilterCondition pushdown compiler (ADR-0058 D1/D2/D6) — kept a private,
limitless `new Environment({ unlistedVariablesAreDyn: true, enableOptionalTypes:
true })` with no `limits`, no stdlib and no `rewriteNullableTernary`, and read
`.ast` off it. That made the RLS / sharing pushdown path the one place on the
platform answering a different question from `celEngine.compile()` about what
parses: an 80-term conjunction, a 40-level nest and a 200-element `$in` all
reached REAL pushdown SQL while the interpreter refused each outright, and
`isSupportedRlsExpression` was a thin wrapper over the same env rather than an
independent gate.
It now parses through `parseCelToAstWithReason`, the canonical entry (#4812),
carrying DEFAULT_LIMITS.
Within the limits this is behaviour-preserving, measured rather than asserted:
across the 710 sources of the pushdown corpus both front ends accept, the only
AST difference is `rewriteNullableTernary`'s `dyn(...)` wrap on the null-guard
ternaries, and a ternary faults on its own `?:` node before the lowerer descends
into a branch — so reason AND detail are byte-identical. Pinned in
cel-to-filter-parse-convergence.test.ts, which rebuilds the old env to compare.
Over the limits, the maintainer's A' ruling (2026-08-08, on the issue) is
implemented as a single dated switch, `CEL_PUSHDOWN_LIMITS_MODE` in the new
`cel-pushdown-limits.ts`:
- `rc-grace` (shipping default, 17.0.0-rc.x): an over-limit predicate still
compiles, off the unbounded AST the canonical entry hands back for exactly
this purpose, and WARNs once per predicate naming the exceeded bound, the
platform's value for it, the predicate's own measure, and the GA
consequence.
- `fail-closed` (v17 GA, one line): the predicate is refused as
`{ reason: 'parse-error', detail: 'Exceeded maxAstNodes (256)' }`, which the
RLS path already routes to RLS_DENY_FILTER.
Both positions run in CI today — in `@objectstack/formula` and in
`@objectstack/plugin-security`, which owns the deny sentinel — so the GA half is
proven before it ships. Two assertions go red on the flip so it cannot be
silent.
Sister entrance: `parseCelToAstWithReason` separates "not valid CEL" from "valid
CEL, over budget" and names WHICH bound was blown, its platform value, and what
the source measures (cel-js's own accounting — the smallest bound it parses
under, found by probing the parser, because `maxDepth` counts parenthesised
recursion that leaves no AST node behind). Graded by the same by-class/by-code
classifier `compile`/`evaluate` use (#6223), never by error prose; the parity is
pinned. `parseCelToAst` is unchanged and still collapses every refusal to
`null`.
`@objectstack/lint` needs no change at either position: its two enforceability
gates read `isSupportedRlsExpression` / `compileCelToFilter` and both suites pin
"the lint verdict IS the consumer's verdict" in both directions, so authoring
reporting flips with the runtime by construction.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bx3H8DJhBsmgDoMp8Tz87T
* fix(formula): spy the WARN sink through globalThis, and correct the flip docblock (#6132)
Two follow-ups from running the gate list:
- `check:type-check-debt` went red: `@objectstack/formula`'s TEST_DEBT ledger
records 17 raw tsc errors and the new suite made it 18. The added error was
`TS2584: Cannot find name 'console'` — this package compiles with neither the
DOM lib nor `@types/node`, which is why the compiler itself reaches the sink
through `globalThis`. The test now spies on the same object the compiler
writes to, rather than a differently-obtained one, which is also the only
version of this spy that cannot go green over a silent sink. Back to 17.
- The switch docblock named three test files that do not exist (the suites were
consolidated into one). It now names the real file and states the flip's
measured blast radius: 10 tests, all in that file, and nothing else.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bx3H8DJhBsmgDoMp8Tz87T
* refactor(formula): name the measurement cap once (#6132)
The grace WARN's "measurement capped" branch spelled the cap factor as a literal
`64` while `measureOverrun` read it from `MEASURE_CAP_FACTOR` — two copies of one
number, in two files, where a drift would make the WARN quote a bound the
measurement never used. The constant is now exported from `cel-engine.ts` (not
from the package index: it is an implementation detail of the diagnostic, not
public surface) and read in both places.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bx3H8DJhBsmgDoMp8Tz87T
* fix(formula): report an unnameable bound as `limit: null`, not as a guessed key (#6132)
`parseCelToAstWithReason`'s "cel-js raised a limit fault whose key this package
cannot read" branch filled the overrun with `maxAstNodes` while its own comment
said a guessed name is the thing to avoid. It is unreachable on cel-js 8.0.0 —
`Parser#limitExceeded` always phrases it `Exceeded <key> (<n>)` — but a guessed
key is worse than none: the author goes and shortens the wrong axis. The branch
now reports `{ limit: null, limitValue: null }`, which the types carry, and
hands back no unbounded AST, so the pushdown path fails closed on it in either
position of the switch rather than compiling something it cannot describe.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bx3H8DJhBsmgDoMp8Tz87T
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent e1e7629 commit f6cd635
9 files changed
Lines changed: 1259 additions & 26 deletions
File tree
- .changeset
- packages
- formula/src
- plugins/plugin-security/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
271 | 271 | | |
272 | 272 | | |
273 | 273 | | |
274 | | - | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
| 453 | + | |
| 454 | + | |
| 455 | + | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
275 | 470 | | |
276 | 471 | | |
277 | 472 | | |
278 | 473 | | |
279 | | - | |
280 | | - | |
281 | | - | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
282 | 511 | | |
283 | 512 | | |
284 | 513 | | |
| |||
0 commit comments