Skip to content

feat(cli): validate action visible/disabled predicates at build time - #2185

Merged
xuyushun441-sys merged 1 commit into
mainfrom
feat/validate-action-predicates
Jun 22, 2026
Merged

feat(cli): validate action visible/disabled predicates at build time#2185
xuyushun441-sys merged 1 commit into
mainfrom
feat/validate-action-predicates

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

The build-time guard that would have caught the #2183 bug at os build instead of at click-time. Closes the post-mortem follow-up from the Mark Done / action-UX work.

Why

A record-header / row action's visible is evaluated by ActionEngine.getActionsForLocation against { record, recordId, objectName, user, … } with fail-closed semantics (evaluateCondition(expr, { throwOnError: true })catch → hide). So a bare field reference — !done instead of !record.done — is an undefined top-level identifier, throws, and the action is silently hidden on every record. That's exactly the trap that sent the #2183 debugging down a long path: the predicate looked fine and the failure was invisible (no error, just a missing button).

The ADR-0032 build validator already detects "bare reference in a record-scoped formula" — but its v1 scope was flows + validation-rule / field-formula predicates only. Action predicates weren't covered, so a bare-field visible shipped clean.

What

  • @objectstack/clivalidateStackExpressions now also checks action visible / disabled predicates (stack-level and object-attached), record-scoped, with the same corrective record.<field> message. disabled: <boolean> is skipped; disabled: <predicate> is checked. Actions merged onto objects and kept top-level are de-duped.
  • @objectstack/formula — adds ctx and features to the record-scope namespace roots, so the ambient globals real action predicates legitimately use (record.id == ctx.user.id, features.multiOrgEnabled) are not false-positives. (Consistent with the file's stated "declare more roots — a missing root is a build-breaking false positive" philosophy.)

Effect

// Before: builds clean, button silently hidden on every record at runtime.// After: os build → error: bare reference `done` — did you mean `record.done`?defineAction({name: 'mark_done',objectName: 'showcase_task',visible: '!done'})

Verification

  • Full monorepo build (turbo build, 76 tasks): every example + platform bundle still compiles clean — no false positives (incl. platform-objects' ctx.user / features predicates and the showcase's !record.done).
  • Tests: @objectstack/formula 201 pass; @objectstack/cli 496 pass, incl. 5 new cases (bare-field action visible flagged; record.-qualified accepted; ctx/features/user accepted; bare disabled flagged but boolean disabled ignored; object-attached action validated).

🤖 Generated with Claude Code

…(ADR-0032)
Extends the build-time expression check to UI action `visible`/`disabled`
predicates (stack-level + object-attached), record-scoped like validation rules.
A record-header/row action's `visible` is evaluated by ActionEngine against
`{ record, recordId, objectName, user, … }` with fail-closed semantics, so a
bare field ref (`!done` instead of `!record.done`) throws at runtime and the
action is silently hidden on every record — the trap behind the #2183
"Mark Done never hides" hunt. `os build` now flags it as an error with the
corrective `record.<field>` message instead of shipping a dead control.
@objectstack/formula: add `ctx` and `features` to the record-scope namespace
roots so ambient globals real action predicates use (`record.id == ctx.user.id`,
`features.multiOrgEnabled`) aren't false-positives. Verified against the full
monorepo build (76 tasks) — every example + platform bundle still compiles
clean; formula (201) + cli (496, incl. 5 new) tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercelBot commented Jun 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJun 22, 2026 7:23am

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling labels Jun 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/cli, @objectstack/formula.

18 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/cloud-artifact-api.mdx(via packages/cli)
  • content/docs/concepts/implementation-status.mdx(via @objectstack/cli)
  • content/docs/concepts/packages.mdx(via @objectstack/cli, @objectstack/formula)
  • content/docs/getting-started/cli.mdx(via @objectstack/cli)
  • content/docs/getting-started/quick-start.mdx(via @objectstack/cli)
  • content/docs/guides/authentication.mdx(via @objectstack/cli)
  • content/docs/guides/client-sdk.mdx(via @objectstack/cli)
  • content/docs/guides/formula.mdx(via @objectstack/formula)
  • content/docs/guides/hook-bodies.mdx(via packages/cli)
  • content/docs/guides/metadata/validation.mdx(via @objectstack/formula)
  • content/docs/guides/packages.mdx(via @objectstack/cli, @objectstack/formula)
  • content/docs/guides/project-scoping.mdx(via @objectstack/cli)
  • content/docs/guides/runtime-services/data-service.mdx(via packages/cli)
  • content/docs/guides/runtime-services/index.mdx(via packages/cli)
  • content/docs/guides/skills.mdx(via packages/cli)
  • content/docs/protocol/objectos/plugin-spec.mdx(via @objectstack/cli)
  • content/docs/protocol/objectos/realtime-protocol.mdx(via @objectstack/cli)
  • content/docs/protocol/objectui/record-alert.mdx(via @objectstack/formula)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@xuyushun441-sys
xuyushun441-sys merged commit 48a307a into mainJun 22, 2026
16 checks passed
@xuyushun441-sys
xuyushun441-sys deleted the feat/validate-action-predicates branch June 22, 2026 07:31
xuyushun441-sys added a commit that referenced this pull request Jun 22, 2026
…kills/examples/docs to it (#2201)
* feat(cli,create-objectstack): make `os validate` the author-time gate; steer scaffolds/skills/examples/docs to it
ObjectStack metadata mistakes fail silently at runtime (bare-field predicates,
dangling widget bindings). `os build` caught them; `os validate` did not — yet
the scaffold's Next steps steered users to `validate`. Close the gap.
- cli: `os validate` now runs the ADR-0032 CEL/predicate gate (CEL syntax +
`record.<field>` existence) in addition to the protocol schema and widget
bindings — a read-only superset of `os build`'s checks, no artifact emitted.
Catches bare-field predicates (#2183/#2185).
- create-objectstack: emit `AGENTS.md` + `.github/copilot-instructions.md` into
every generated project telling coding agents to run `npm run validate` after
editing metadata; align the blank template `dev`/`start` scripts with the
example apps; sharpen the post-create "Next steps". Removes the previously
dead copilot-instructions template (superseded by the emitted guide).
- skills: add a "Verify your work" section to all 9 objectstack-* skills —
authoritative in objectstack-platform, predicate/binding-focused in
data/ui/automation/formula, tight pointers in api/query/i18n/ai.
- examples: add a `validate` script to each app (folded into app-showcase's
`verify`) + a single examples/AGENTS.md.
- docs: new guide content/docs/guides/validating-metadata.mdx; correct the
`os validate` reference in getting-started/cli.mdx.
Verified: cli builds clean (tsc); `os validate` passes app-todo and fails a
bare `visible: '!is_completed'` with a corrective message; scaffolder smoke test
emits AGENTS.md with placeholders substituted.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(create-objectstack): atomic exclusive-create for emitted guides (CodeQL js/file-system-race)
CodeQL flagged the existsSync()+writeFileSync() check-then-write in
writeAgentGuides as a TOCTOU file-system race (2 high alerts). Replace with an
atomic `wx` (exclusive-create) write via a writeIfAbsent() helper that swallows
EEXIST, and read the bundled template with try/catch ENOENT instead of a
separate existence check. Same "don't clobber a template's own guide" semantics,
no check-then-act gap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jul 3, 2026
fix(grid): 批量编辑弹窗补齐多选/日期控件 + 确认展示与必填校验 (#2185) (#2186)
objectui@2cfa36e963cb9d7d886dd68b3f503524bab0bf89
baozhoutao added a commit that referenced this pull request Jul 3, 2026
* demo(app-showcase): bulk multi-select edit on the Project grid (#2185)
Exercises the objectui BulkActionDialog multi-select fix
(objectstack-ai/objectui#2186) end-to-end in a real running app:
- project.object.ts: add `labels` (multiselect, fixed options) and
`team_members` (multi-user) — the two shapes the bulk dialog could not
set before #2185 (its picker collapsed to a single value / overwrote
the array).
- project.view.ts: add the two columns and three `bulkActionDefs`:
• set_labels → multi-select on a `select` param (array patch)
• assign_team → multi-select on a `lookup` param (sys_user)
• reschedule → the new `date` control + a single-select
Verified in objectstack dev: select rows → each action writes an array
(or date) patch to all selected records; labels/team_members/end_date
persist server-side.
* demo(app-showcase): add single-lookup bulk action (reassign_account)
Exercises the searchable single-lookup picker (objectui#2186): a
`lookup` param with no `multiple` now renders a searchable reference
combobox over showcase_account, not a bare dropdown. Verified in
objectstack dev — select rows → Reassign Account → search/pick one →
every selected project's `account` is set to the single chosen id.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@xuyushun441-sys@os-zhuang