You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(spec,objectql,metadata-protocol): a user field carries its target in the TYPE — bare {type:'user'} is not targetless (#4438)
* fix(spec,objectql,metadata-protocol): a `user` field carries its target in the TYPE — bare `{type:'user'}` is not targetless
`field.zod` defines `user` as "a lookup specialized to the `sys_user` system
object … target fixed to the `sys_user` system object", and `Field.user()` —
unlike `Field.lookup(reference, …)` / `Field.masterDetail(reference, …)` —
takes NO target argument and writes `reference: 'sys_user'` itself. The target
is a CONSTANT OF THE TYPE. `reference` on a `user` field materializes that
constant; it does not supply it.
Two callers read `field.reference` raw and so disagreed with that definition:
the protocol's expand gate refused `?expand=<a bare user field>` with
`400 INVALID_FIELD … declares no target object`, and objectql's expand loop
skipped it. Metadata authored without the redundant `reference` — hand-written
JSON, an AI author, a Studio form — was therefore read as under-specified when
it was complete.
Live capture (cloud#983): an AI-built equipment app modelled 负责人 as
`{ type: 'user' }`; objectui's default list expanded that column (its
`EXPANDABLE_FIELD_TYPES` keys on the TYPE, deliberately ignoring the target);
the very first screen of the brand-new app rendered "该视图的查询被拒绝" over
that 400.
`referenceTargetOf` in `@objectstack/spec/data` is now the single arbiter of
"what does this reference field point at", next to `REFERENCE_VALUE_TYPES` —
the set the same two callers already share for "is this a reference at all".
Both halves of the expand path read it, which is what stops the gate from
refusing a field the engine would have expanded, or blessing one it skips.
Fixing only the gate would be worse than not fixing it: the request would be
admitted and the engine would still skip the field, answering 200 with a raw
user id in the cell — the "client renders raw ids where names belong" failure
the expand axis exists to close. The conformance test pins BOTH halves (each
was verified to fail alone).
Deliberately unchanged: `seed-loader`'s reference resolution still requires an
explicit `reference`. An unresolvable seed reference is a HARD failure there,
so folding implicit targets in would turn seeds that today write a raw string
into failed loads — a different subsystem's contract question, not this one.
* chore: changeset + regenerate spec api-surface snapshot for referenceTargetOf
---------
Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
0 commit comments