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
feat(platform): sandbox tx boundary, gantt tree schema, formula date math, RLS §7.3.1
Four platform enhancements surfaced by a real eHR/MES dogfood:
- runtime/objectql/spec: ctx.api.transaction() — transaction boundary for
sandboxed hook/action bodies (explicit handle threading across the
deferred-promise pump; rollback on throw or timeout). New api.transaction
capability.
- spec: extend GanttConfigSchema with the 11 fields the renderer already
supports (parentField tree, baselines, resourceView, quickFilters, …) so
the metadata pipeline stops stripping them at the spec boundary.
- formula: addDays/addMonths CEL stdlib functions (UTC, dyn-typed, addMonths
clamps to month end).
- spec/plugin-security: converge the RLS contract to the four expression
forms the compiler implements (drop the over-promised subquery/LIKE/regex/
ANY/ALL surface) and wire §7.3.1 dynamic membership via a pre-resolved
ExecutionContext.rlsMembership bag; recognize "1 = 1" as always-true so
RLS.allowAllPolicy grants instead of failing closed.
Add `addDays(date, n)` and `addMonths(date, n)` to the CEL standard library — shift an arbitrary date by a (possibly negative) number of days or months. Unlike `daysFromNow`, these operate on a *given* date (the "next service date = last service + cycle" shape). `addMonths` clamps to the target month's last day (`addMonths(date('2026-01-31'), 1)` → Feb 28, never overflowing into March). Both coerce their inputs (Date | ISO string | epoch) and type `n` as `dyn` so a record number field arriving as a `double` doesn't fault `no such overload` (#1928).
Extend `GanttConfigSchema` (ListView `gantt` config) to expose the full set of fields the Gantt renderer already supports, so the metadata pipeline preserves them end-to-end instead of stripping them at the spec boundary.
6
+
7
+
New optional fields: `colorField`, `parentField` (multi-level row tree — 项目 → 产品 → 排产计划 → 派工单), `typeField` (task / summary-folder / milestone row shape), `tooltipFields`, `baselineStartField` / `baselineEndField` (planned-vs-actual), `groupByField`, `resourceView` + `assigneeField` / `effortField` / `capacity` (resource-workload histogram), `quickFilters`, and `autoZoomToFilter`. The original five fields are unchanged; all additions are optional so existing Gantt views validate as before.
Converge the RLS contract with the reference compiler, and wire §7.3.1 dynamic membership.
7
+
8
+
-**spec (docs)**: narrow `rls.zod.ts` to the four expression forms the compiler actually implements — `field = current_user.<prop>`, `field = 'literal'`, `field IN (current_user.<array>)`, and `1 = 1`. Removed the over-promised surface (subqueries, `AND`/`OR`/`NOT`, `LIKE`/`ILIKE`, regex, `ANY`/`ALL`, `NOT IN`, `IS NULL`, `NOW()`/`CURRENT_DATE`) from the operator list, context-variable list, and `@example` policies, and documented the fail-closed behaviour explicitly.
9
+
-**spec (schema)**: `ExecutionContext` gains `rlsMembership?: Record<string, string[]>` — a bag of pre-resolved dynamic-membership id arrays (team members, territory accounts, shared records) that the runtime stages so RLS can scope via `field IN (current_user.<key>)` without subquery support. Generalizes the previously hard-coded `org_user_ids`.
10
+
-**plugin-security**: `RLSCompiler.compileFilter` merges `rlsMembership` keys into the user context (arrays only, never clobbering the named `id`/`organization_id`/`roles`/`org_user_ids` fields), so §7.3.1 hierarchy- and sharing-based policies compile. `compileExpression` now recognizes `1 = 1` as always-true (empty filter), making `RLS.allowAllPolicy` grant access instead of silently failing closed. Missing/empty membership sets still fail closed.
Add a transaction boundary to sandboxed hook/action bodies: `ctx.api.transaction(async () => { … })`. Every `ctx.api` read/write inside the callback runs in one driver transaction — committed when the callback returns, rolled back if it throws (or if the body leaves the transaction open at timeout). Guarded by the new `api.transaction` capability.
8
+
9
+
-**spec**: new `api.transaction` capability token on `HookBodyCapability`.
10
+
-**objectql**: `ScopedContext` gains discrete `beginTransaction()` / `commitTransaction(handle)` / `rollbackTransaction(handle)` primitives. The handle is threaded **explicitly** through a child context (`resolveTx` honors it ahead of the ambient `txStore`), because the sandbox drives the body across many host event-loop turns where AsyncLocalStorage context does not survive. Degrades to non-transactional execution when the driver has no transaction support.
11
+
-**runtime**: the QuickJS runner wires `ctx.api.transaction` over three deferred-promise host leaves (begin/commit/rollback), routes in-transaction ops through the tx-scoped context, and rolls back a transaction the body left open before disposing the VM.
0 commit comments