From 6aa484572b744ab90b7f10549210d47656ca1e4b Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 9 Sep 2026 22:22:36 +0000 Subject: [PATCH] fix(skills): stop naming `app` as an expression root in two published guides `app` is not a root the runtime binds. objectui#8155 ruled that `@objectstack/formula`'s `SCOPE_ROOTS` is the contract and app-shell aligns to it; PR #8164 shipped that -- `buildExpressionScope` in `packages/app-shell/src/providers/ExpressionProvider.tsx` returns `{ current_user, user, ctx:{user}, os:{user}, data, features }` and no `app`. Two lines in the PUBLISHED skills tree still taught it, and an unresolvable visibility predicate FAILS OPEN on these surfaces, so a reader who followed them authored a gate that silently passes: guides/auth-permissions.md -- the "Expression scope: which roots resolve" table listed `app`, `features` on one row. `features` IS a root and stays, with its `${features.multiOrgEnabled}` example; `app` is dropped. rules/protocol.md -- the `visible` CEL-predicate root list beside an action param read (`features` / `current_user` / `app` / `data`). Surviving roots are spelled in the order `SCOPE_ROOTS` declares them, measured against the installed `@objectstack/formula@17.4.0` (`dist/index.d.ts:215`, the version objectui's `^17.0.0` resolves to): `data` at index 18, `features` at 23, `current_user` at 26 -- so `data` / `features` / `current_user`. The upstream twin objectstack#17203 mirrors that spelling. Both lines were tested against the card's own criterion before editing: each describes the PREDICATE SCOPE, not the React context value. The context value does still carry `app` (`ExpressionProvider` returns `{ user, app, data, features, evaluator }` -- `DashboardView` reads it as a plain value), so the surfaces that describe THAT are correct as they stand and are untouched: the `app.settings.users` nested-`bind` mentions in `rules/protocol.md:215` and `guides/schema-expressions.md:305` (data binding against `dataSource`, a different mechanism) and the `content/docs/guide/console-architecture.md:44` ASCII diagram. Claude-Session: https://claude.ai/code/session_01MoTv7pn338AZ71owsp19gQ Co-authored-by: Claude --- skills/objectui/guides/auth-permissions.md | 2 +- skills/objectui/rules/protocol.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/skills/objectui/guides/auth-permissions.md b/skills/objectui/guides/auth-permissions.md index c38c16c729..0ca663ed8f 100644 --- a/skills/objectui/guides/auth-permissions.md +++ b/skills/objectui/guides/auth-permissions.md @@ -309,7 +309,7 @@ Then in schema — note the `data.` root: |---|---|---| | `data` | the `dataSource` passed to `SchemaRendererProvider` | `${data.canDeleteContacts}` | | `user` / `current_user` | the ambient host scope (app-shell's `ExpressionProvider`) | `${user.id}` | -| `app`, `features` | the ambient host scope | `${features.multiOrgEnabled}` | +| `features` | the ambient host scope | `${features.multiOrgEnabled}` | | `page` | `PageSchema.variables`, inside a Page | `${page.selectedId}` | The ambient roots exist only while a host scope is mounted — `ExpressionProvider` diff --git a/skills/objectui/rules/protocol.md b/skills/objectui/rules/protocol.md index b2680d9f5a..9c39edab32 100644 --- a/skills/objectui/rules/protocol.md +++ b/skills/objectui/rules/protocol.md @@ -280,7 +280,7 @@ form-supported type (`select`, `lookup`, `date`, `file`, `image`, `richtext`, options, lookup config, `multiple`/`accept`/`maxSize` from the object field; inline properties override. - `required` blocks submit; `visible` is a CEL predicate - (`features` / `current_user` / `app` / `data`) that hides the param. + (`data` / `features` / `current_user`) that hides the param. **❌ DO NOT** invent param-only type spellings — use spec `FieldType` values. **❌ DO NOT** add bespoke per-type render branches to `ActionParamDialog`;