Skip to content

feat(spec): conditional tabs — page:tabs items accept a visibleWhen CEL predicate (#2606) - #2967

Merged
os-zhuang merged 2 commits into
mainfrom
claude/page-tabs-visibility-cel-0cazrj
Jul 15, 2026
Merged

feat(spec): conditional tabs — page:tabs items accept a visibleWhen CEL predicate (#2606)#2967
os-zhuang merged 2 commits into
mainfrom
claude/page-tabs-visibility-cel-0cazrj

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

背景:基于 ADR-0089 对 #2606 的重新评估

#2606(2026-07-05)提出给 page:tabs 的 item 加 visibility(CEL)。该提案早于 ADR-0089(2026-07-14 接受),重新评估结论:

  • 提案本身依然成立:Tier 2(page 层)能力、复用 ExpressionInputSchema(CEL)、不进对象层、加性可选字段 → minor。这些设计边界与 ADR-0085 / 详情页相关子表:降低对自定义 page 的依赖(relatedList 三态 + 列派生 + 确定性排序) #2579 一致,不受 ADR-0089 影响。
  • 唯一需要修正的是字段名:ADR-0089 D1 已把条件显隐谓词统一为规范名 visibleWhen,visibility / visibleOn 降级为 @deprecated alias(仅为存量元数据保留)。因此本字段从第一天起就叫 visibleWhen
  • 新表面不接受 alias:ADR-0089 D2 的 alias 机制服务于已有键的存量元数据;tab item 此前没有任何 visibility 键,不存在需要兼容的存量 → 只声明规范键,不加 visibility/visibleOn alias(Prime Directive Add comprehensive test suite for Zod schema validation #12:一个严格契约优于 N 种方言)。测试中显式固化了这一点。

改动

PageTabsProps.items[] 新增可选 visibleWhen: ExpressionInputSchema:

  • 语义:谓词求值为 FALSE → 整条 tab(头 + 面板)从 tab 条移除;区别于子组件自身的 visibleWhen(只隐藏面板内容、留下空 tab 头)。
  • 求值环境:与页面组件级 visibleWhen 一致 —— record + current_user,外加 page.<var>(page 变量变化时响应式重算)。
  • 加性、向后兼容:不带 visibleWhen 的 item 行为完全不变。

测试

  • 裸 CEL 字符串 → 规范化为 { dialect: 'cel', source } 信封;信封形式直接接受。
  • 不带谓词的 item 不受影响。
  • visibility alias 在 tab item 上被折叠(新表面只认规范键)。
  • spec 全量:251 files / 6790 tests 通过;@objectstack/spec build(含 DTS)通过。

配套

渲染器落地在 objectui 同名分支 PR(item 过滤 + 激活 tab 被隐藏时回落到第一个可见 tab)。

Closes #2606. Refs #2579, ADR-0089.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FmuuXkuW3JH9LYXHHRnoQV


Generated by Claude Code

…EL predicate (#2606)

Re-evaluated #2606 under ADR-0089: the proposal predates the ADR, which made
visibleWhen the single canonical conditional-visibility key and demoted
visibility/visibleOn to deprecated aliases. The new item-level key therefore
ships as visibleWhen from day one; the aliases are NOT accepted on this new
surface (no legacy metadata to alias for — Prime Directive #12, one strict
contract over N dialects).

Semantics: when the predicate evaluates FALSE the whole tab (header + panel)
is omitted, unlike a child component's own visibleWhen which hides only the
panel content and leaves an empty tab header. Binds the same environment as
page-component visibleWhen: record + current_user + page.<var>.

Additive, back-compatible (optional field) → minor. Renderer lands in
objectui (item filtering + active-tab fallback to the first visible tab).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FmuuXkuW3JH9LYXHHRnoQV
@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 15, 2026 3:49pm

Request Review

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/dogfood, @objectstack/spec.

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

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via packages/dogfood, @objectstack/spec)
  • content/docs/permissions/delegated-administration.mdx (via packages/dogfood)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)

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.

…surface ledger (#2606)

The ADR-0058 D7 / ADR-0060 conformance ratchet re-discovers every
ExpressionInputSchema field in packages/spec/src and fails the build if any is
unclassified. The new tab-item visibleWhen surface (ui/component.zod.ts) needs
a ledger row: it belongs to cel-ui (interpret, fail-soft-log) alongside the
page/view visibility predicates — evaluated by the objectui page:tabs renderer.

Fixes the Test Core / Dogfood Regression Gate failures on this branch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FmuuXkuW3JH9LYXHHRnoQV
@os-zhuang
os-zhuang marked this pull request as ready for review July 15, 2026 14:56
@os-zhuang
os-zhuang merged commit c64ee8c into main Jul 15, 2026
16 of 17 checks passed
@os-zhuang
os-zhuang deleted the claude/page-tabs-visibility-cel-0cazrj branch July 15, 2026 14:56
os-zhuang added a commit that referenced this pull request Jul 16, 2026
…estore PageTabsProps (#2978) (#3012)

* fix(spec): stop gen:schema silently unpublishing transform-bearing schemas (#2978)

PageTabsProps vanished from json-schema/ when #2967 added an
ExpressionInputSchema (.transform) field — zod's toJSONSchema cannot
represent transforms in the default output mode, and build-schemas.ts
silently skipped it, so the next gen:docs run would have deleted the
published PageTabsProps reference section.

Two-part fix:

1. io:'input' fallback — when output-mode conversion fails on a
   transform, retry with io:'input'. These JSON Schemas describe what
   authors WRITE, and the input side of a transform pipe is plain data,
   so it is representable (for PageTabsProps.visibleWhen it emits the
   correct `anyOf: [string, expression envelope]` authoring shape).
   Rescued schemas are marked `x-io: "input"`. This restores
   PageTabsProps and 149 other transform-blocked public contracts
   (ObjectSchema, FieldSchema, FlowSchema, PageSchema, ActionSchema, …);
   only 18 truly unrepresentable schemas (function/Date/BigInt/custom)
   remain skipped.

2. Disappearance ratchet — json-schema/ is gitignored, so the committed
   json-schema.manifest.json records every schema key ever emitted.
   A key present in the manifest but absent from a build now fails
   gen:schema loudly with remediation steps; deliberate retirements must
   remove the key in the same PR. Silent skip remains only for types
   that have never been representable.

Also escape literal `|` in the description cell of generated property
tables (build-docs.ts) — rescued schemas surfaced descriptions with
pipes that split GFM table rows.

Closes #2978

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fn6qMKtJeVbs2KzouWDHhB

* docs(references): regen from restored JSON Schemas (#2978)

gen:docs over the post-fix json-schema/ output. PageTabsProps keeps its
section (now including the visibleWhen items shape from #2967), and the
149 schemas rescued by the io:'input' fallback gain reference sections —
previously delivered-but-undeclared contracts (Prime Directive #10).
Existing table rows with literal pipes in descriptions are re-emitted
with GFM escaping.

Verified: `pnpm docs:build` compiles all regenerated MDX.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fn6qMKtJeVbs2KzouWDHhB

* fix(spec): address CodeQL alerts in gen:schema/gen:docs scripts (#3012)

- build-schemas.ts: read the ratchet manifest directly and treat ENOENT
  as first-run bootstrap instead of existsSync-then-read (TOCTOU).
- build-docs.ts: escape backslashes before pipes in table-cell
  descriptions — an existing `\|` would otherwise decay into an escaped
  backslash followed by a live pipe, splitting the GFM cell.

No output changes: regenerated json-schema/ and references/ are
byte-identical.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fn6qMKtJeVbs2KzouWDHhB

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:ui size/s tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

条件 tab:给 page:tabs 的 item 加 visibility(CEL)—— #2579 follow-up

2 participants