Skip to content

feat(lint): page-component field bindings + non-dashboard chart bindings (#3583) - #3684

Merged
os-zhuang merged 1 commit into
mainfrom
claude/app-metadata-validation-assessment-xskbcg
Jul 27, 2026
Merged

feat(lint): page-component field bindings + non-dashboard chart bindings (#3583)#3684
os-zhuang merged 1 commit into
mainfrom
claude/app-metadata-validation-assessment-xskbcg

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

#3583 方案的 Phase 2:剩下的两类引用(页面字段绑定、仪表盘之外的图表轴),同 PR 接入 validate/lint/compile

先说一个必须修的缺陷

上个 PR(#3657)里的 quick-actions 检查走的是 page.components —— PageSchema 根本没有这个键。组件实际挂在 regions[].components[]slots 下,子树嵌在无类型的 properties 包里(children / items[].children / body / footer),而不是组件上的 children(PageComponentSchema.strict(),不允许该键)。

也就是说那段检查在解析后的 stack 上一个组件都没访问到,而它的测试恰好也是照着这个臆想的形状写的,所以全绿。现在遍历抽成一个共享且有测试的模块;在 showcase 上它访问到 194 个组件,旧形状只有 46 个。

validate-page-field-bindings

PageComponent.properties 是无类型包,所以 highlights 条、KPI 卡、details 分区都能写一个对象上不存在的字段,组件静默跳过、页面少渲染一项。

  • 对象绑定按 dataSource.objectproperties.objectpage.object,多对象页面逐元素判定,而不是拿一个页面级猜测硬套。
  • record:related_listcolumns/sort/filter 解析到关联对象(objectName),add-picker 解析到 picker 自己的对象。
  • 严重级 warning,与 FORM_FIELD_UNKNOWN 一致 —— 页面消费方是降级而非崩溃。

描述表是手写的,这是刻意的:Zod schema 说不出哪个 z.string() 是字段名(statusFieldagentId 一样都是字符串),而且 PageComponent.type 接受任意字符串,所以未知类型一律静默跳过。表里还覆盖了 props schema 没描述、但真实页面确实这么写的形状(record:detailssections[].fieldshideFields、picker 的 labelField)—— 只按 schema 形状写规则,在真实语料上会一条都查不出来。

validate-chart-bindings

把 ADR-0021 的轴校验从仪表盘扩到:报表图表(report.chart + blocks[].chart)、列表视图图表(三条容器路径)、以及数据集绑定的页面图表组件。

  • 轴指向原始字段而非已声明 measure → error(cutover 之后结果行按 measure 名索引,所以序列返回空)。
  • 轴指向已声明但本图表未 values 选中的 measure → warning(查询根本不返回它)。
  • 报表需要单独处理:ReportChartSchemaxAxis/yAxis 收窄成裸字符串,仪表盘规则的 Array.isArray(yAxis) 守卫会静默跳过它 —— 直接把老规则指向报表会一条都查不出来。

故意不做:react <ObjectChart> 是对象绑定而非数据集绑定,而仓库里没有任何地方定义它的 aggregate 把结果列叫什么,所以「轴该解析成什么」没有可辩护的答案。猜一个就是在制造误报。留作后续(ADR-0078:先验证再强制)。

验证

  • 误报地板:三个真实应用零 finding。
  • 并且先确认了这不是空转:探针显示遍历确实访问到 194 个组件、11 个有对象绑定、1 个报表图表、2 个列表图表 —— 遍历若静默为空,零误报就是假通过(这正是上面那个缺陷的教训)。
  • 测试:lint 435 / cli 637 全过;eslint、nul-bytes、api-surface 干净。

关联:#3583 · #3640(方案)· #3657(Phase 1)· ADR-0021 / ADR-0072 / ADR-0078


Generated by Claude Code

…ngs (#3583)

Phase 2 of the #3583 assessment: the two remaining reference classes the
HotCRM audit found, both wired into validate/lint/compile together.

validate-page-field-bindings — `PageComponent.properties` is an untyped
bag, so a highlights strip, KPI card, or details section can name a field
the bound object lacks and the component silently skips it. Object
binding follows dataSource.object -> properties.object -> page.object, so
a multi-object page is judged per element instead of against one page-wide
guess; `record:related_list` resolves columns/sort/filter against the
RELATED object and its add-picker against the picker's own. Advisory,
matching FORM_FIELD_UNKNOWN. The descriptor table is hand-written on
purpose: a Zod schema cannot say which `z.string()` prop is a field name,
and `PageComponent.type` accepts arbitrary strings, so unknown types are
skipped silently. It also covers shapes the props schemas do not describe
but real pages author anyway (record:details `sections[].fields` and
`hideFields`, the picker's `labelField`) — linting the schema shape alone
would find nothing on the actual corpus.

validate-chart-bindings — extends ADR-0021 axis checking past dashboards
to report charts (report.chart + blocks[].chart), list-view charts (three
container paths), and dataset-bound page chart components. An axis naming
a raw field instead of a declared measure is an error (post-cutover rows
are keyed by measure NAME, so the series returns empty); a declared but
unselected measure is a warning. Reports needed their own handling:
ReportChartSchema narrows xAxis/yAxis to bare STRINGS, which the dashboard
rule's Array.isArray guard skips silently. The react <ObjectChart> block
is object-bound rather than dataset-bound and nothing in the repo defines
what its aggregate names the result column, so it is left out rather than
guessed at (ADR-0078: verify, then enforce).

Fixes a defect in the rule shipped by #3657: its page walk read a
top-level `page.components` array that PageSchema does not have —
components live under regions[].components[] and slots, and sub-trees
nest inside the untyped properties bag (children, items[].children, body,
footer), not a `children` key on the component (PageComponentSchema is
strict). The quick-actions check was visiting nothing on a parsed stack,
and its tests encoded the invented shape so they passed. Traversal is now
one shared, tested module; on the showcase app it reaches 194 components
where the old shape found 46. Source-authored pages (html/react/jsx) are
skipped — their regions hold a derived cache the source wins over.

Verified zero false positives on app-crm, app-showcase and app-todo with
the fuller traversal, after confirming the walk actually visits their 194
components, 1 report chart and 2 list charts (a silently-empty walk would
pass vacuously). Suites: lint 435, cli 637 passing; eslint, nul-bytes and
api-surface clean.

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

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 27, 2026 2:26pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/xl labels Jul 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

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

  • content/docs/ai/skills-reference.mdx (via packages/cli)
  • content/docs/api/client-sdk.mdx (via @objectstack/cli)
  • content/docs/api/data-flow.mdx (via @objectstack/cli)
  • content/docs/api/environment-routing.mdx (via @objectstack/cli)
  • content/docs/api/error-catalog.mdx (via @objectstack/cli)
  • content/docs/automation/hook-bodies.mdx (via packages/cli)
  • content/docs/deployment/backup-restore.mdx (via @objectstack/cli)
  • content/docs/deployment/cli.mdx (via @objectstack/cli)
  • content/docs/deployment/self-hosting.mdx (via @objectstack/cli)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/cli)
  • content/docs/kernel/runtime-services/data-service.mdx (via packages/cli)
  • content/docs/kernel/runtime-services/index.mdx (via packages/cli)
  • content/docs/permissions/authentication.mdx (via @objectstack/cli)
  • content/docs/permissions/authorization.mdx (via @objectstack/lint)
  • content/docs/plugins/packages.mdx (via @objectstack/cli)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/cli)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/cli)
  • content/docs/releases/implementation-status.mdx (via @objectstack/cli)
  • content/docs/releases/v16.mdx (via @objectstack/cli)

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.

@os-zhuang
os-zhuang marked this pull request as ready for review July 27, 2026 14:41
@os-zhuang
os-zhuang merged commit 17749fc into main Jul 27, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/app-metadata-validation-assessment-xskbcg branch July 27, 2026 14:42
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 size/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants