Skip to content

An authored ActionParam.referenceTo is never read — the dev warning tells authors to use reference, which the public type didn't declare #3174

Description

@os-zhuang

Found while triaging @object-ui/types:ActionParam for the objectstack#4115 ledger burn-down (batch 2, objectui#3156). Recording only — not fixed there, because the fix changes what the resolver reads, and a behavior change should not ride on a symbol-derivation PR.

The gap

Two spellings for one concept, on two sides of resolveActionParams():

  • authoring side — resolveActionParams() (packages/app-shell/src/utils/resolveActionParams.ts) reads param.reference for an inline lookup/master_detail target, and nothing else. Its own local input interface documents this: "Spelled reference to match FieldSchema.reference / ActionParamSchema.reference."
  • resolved side — it emits @object-ui/core's ActionParamDef with referenceTo, which paramToField.ts maps to the picker's reference_to.

@object-ui/types' public ActionParam — the type a host app authors against — declared referenceTo and did not declare reference at all (until batch 2 derived the type from the spec's ActionParamSchema, which restores reference).

So an author who followed the public type and wrote:

{ name: 'account_id', type: 'lookup', referenceTo: 'account' }

got a param whose picker target was silently dropped: the picker degrades to a plain record-id text input. The dev-mode warning in paramToField.ts then says:

Declare reference: '<object>' on the param, or make it field-backed …

i.e. it names a key the public type did not have. The two halves of the contract disagreed about the spelling, and the type was the half that was wrong.

Now

After objectui#3156's derivation, ActionParam carries both: reference (inherited from the spec, and the one the resolver reads) and referenceTo (the resolved-side spelling, declared for parity with ActionParamDef and documented as such, pointing here).

The decision this needs

Pick one, and make declaration and runtime agree:

  1. reference is the authoring key (matches the spec and FieldSchema). Then referenceTo and the rest of the picker group (displayField, idField, descriptionField, titleFormat, lookupColumns, lookupFilters, lookupPageSize, dependsOn) should be removed from the authoring ActionParam — they belong to the resolved ActionParamDef only. That is a breaking change to a published type and needs a changeset.
  2. Accept both at authoring time. resolveActionParams() reads param.reference ?? param.referenceTo, and the same for the rest of the group, with a test per key.

Either way the gate should be a test that authors a param through the public type and asserts the picker gets its target — the current tests exercise the resolver's own local input interface, which is why the mismatch survived.

Activity

  1. self-assigned this
    on Aug 2, 2026
  2. os-zhuang commented on Aug 2, 2026

    @os-zhuang
    ContributorAuthor

    认领:PM 循环第 2 轮(分片:objectui 整仓)
    会话:session_01PRJtkgUAaVG11FsJQbvZWA
    分支:claude/issue-3174-action-param-reference-spelling
    Worktree:objectui-issue-3174

    分诊裁决(PM 可决;若实现中发现须改动 @objectstack/spec 的公开契约则停手升级):reference 是 spec 侧 ActionParamSchema 的正统拼法(批次 2 派生后公共类型已恢复该字段),因此以 reference 为准;referenceTo 若在公共类型上仍可写,需给出可作者化的处置——能识别就发出点名警告并按 reference 语义解析,或明确不再声明。判据是不能再出现「作者照公共类型写、picker 静默降级成记录 ID 文本框」。resolveActionParams → ActionParamDef.referenceTo → paramToField 的内部管线拼法不必强行统一,但要有测试钉住端到端行为。


    Generated by Claude Code

  3. os-zhuang commented on Aug 2, 2026

    @os-zhuang
    ContributorAuthor

    验收:ACCEPT → PR #3203(CI 全绿后进合并流程)。

    修正我先前的分诊裁决:我给的两支里有一支是错的。我写「能识别就按 reference 语义解析」——开发 agent 查出 spec 的 ActionParamSchema 是 .strict() 且别名表点名列着 referenceto → reference,即作者写 referenceTo 在服务端本来就是硬性 parse 拒绝。若按我那支做,objectui 会渲染平台自己拒收的元数据:本地 TS 里能用、一发布就失败,正是 contract-first 禁止的消费端宽容。取「不再声明」这一支是对的。

    交付内容:① 从公共 ActionParam 移除九个解析侧 picker 键;② 钉住规则「作者类型的键集 == spec 可作者化键集」,并用反向断言把唯一例外锁死为 validation(多一个键就红);③ resolveActionParams() dev 模式点名任何解析侧键并给处方,仍拒绝读取——补 tsc 管不到的 JS/JSON/运行时合成路径;④ 端到端测试改为经公共 ActionParam 类型编写并跟到 reference_to(此前所有用例都写 resolver 自己的本地类型,所以 resolver 永远只跟自己一致,错配才得以存活),并纳入 tsconfig.typetests.json 否则类型标注无人校验;⑤ changeset 两包 minor,FROM/TO 迁移写全(referenceTo: → reference:,或改 field-backed 整组继承)。

    越界发现已核实:#3201(validation 同属声明了、没人读、被 spec 拒收),作为漂移守卫的具名例外挂账。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions