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
{{ message }}
Repository navigation
Commit 3644fad
Browse filesBrowse the repository at this point in the historyBrowse files
fix(rest): resolve the public-form lookup picker target from reference only (#17449)
* fix(rest): resolve the public-form lookup picker target from `reference` only
The lookup-picker route read a four-spelling tolerant chain
(`reference ?? referenceTo ?? target ?? options.objectName`). Retire the
tolerant tail: the spec spelling is the contract, and a stored row spelling
the target the old way is a producer defect, not a dialect this route
accommodates.
The three cases that pinned "a legacy spelling still resolves" now pin the
refusal in both halves -- `500 LOOKUP_TARGET_MISSING` and the data engine
never called -- and the file's two "open production census" notes are
replaced with the ruling that closed it.
Claude-Session: https://claude.ai/code/session_01DapQyvYrFb1MxSYe7BL2nt
Co-authored-by: Claude <noreply@anthropic.com>
* docs(forms): the public picker resolves its target from `reference` only
The `publicPicker.object` row described the tolerant chain this branch just
retired, so it now states the opposite of what the route does. Say what the
route does, and name the status an alias-spelled stored row now gets.
Claude-Session: https://claude.ai/code/session_01DapQyvYrFb1MxSYe7BL2nt
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
**BREAKING (runtime behaviour on a published route).** The public-form lookup-picker route
6
+
`GET /forms/:slug/lookup/:field` resolves its target object from the canonical field key
7
+
`reference` alone. The three tolerant fallback arms it used to read after it — the
8
+
`referenceTo`, `target` and `options.objectName` spellings — are deleted.
9
+
10
+
Effect on the wire: a stored object-metadata row whose lookup field carries one of those
11
+
three spellings and no `reference` used to answer `200` with rows from the aliased object; it
12
+
now answers `500 LOOKUP_TARGET_MISSING`, and the data engine is never called. A field
13
+
carrying `reference` is unaffected, including a partially-migrated row carrying a legacy
14
+
spelling beside it. `publicPicker.object` on the form is still the explicit override and is
15
+
still read first.
16
+
17
+
No migration is prescribed, and none is owed. `FieldSchema` is a `strictObject` that refuses
18
+
`relatedTo`, `referenceTo`, `target`, `targetObject` and `lookupObject` by name, answering
19
+
with a rename hint naming the canonical key, so no authoring path can produce such a row; a
20
+
census across both trees found no producer and no relation field carrying any of them, with
21
+
positive controls; and the maintainer ruled on 2026-09-09 that no deployment holds rows to
22
+
preserve. The spec spelling is the contract, and a stored row spelling the target the old way
23
+
is a producer defect rather than a dialect this route accommodates.
24
+
25
+
<!-- adr-0087: not-required (no-migration-prescription) This narrows a REST route's runtime read, not a metadata surface: no Zod schema, spec declaration or stored representation changes here, and `objectstack migrate meta` has nothing to rewrite for it. The one at-rest spelling with a measured population is `reference_to`, already carried by the pre-existing ADR-0087 entry `field-reference-to-alias`, which is untouched by this change and disjoint from the three spellings it removes; those three have no at-rest population and are refused by name at the write door, so a new ledger entry would be scope invented at conversion time. -->
Copy file name to clipboardExpand all lines: content/docs/ui/forms.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -257,7 +257,7 @@ sections: [{
257
257
|`displayFields`| Fields projected into each result row (plus `id`); the visitor's `q` is `contains`-matched against the **first** entry. At most 5; omitted → `['name']`. |
258
258
|`maxResults`| Rows per request, integer 1–50 (default 20). 50 is a hard server ceiling; there is **no pagination** on this surface (`offset` is pinned to 0), so a leaked endpoint cannot enumerate the table. |
259
259
|`filter`| Static pre-filter rows (same `{ field, operator, value }` dialect as list-view filters), ANDed ahead of the visitor's search. |
260
-
|`object`| The object to search. Optional — omit it and the server resolves the target from the field's own definition on the parent object (its `reference`, or a legacy `referenceTo` / `target` / `options.objectName`on a pre-fold stored row). Declare it only to search something other than what the field points at. |
260
+
|`object`| The object to search. Optional — omit it and the server resolves the target from the field's own definition on the parent object: its `reference` key, and only that key. A stored row spelling the target `referenceTo` / `target` / `options.objectName`is **not** resolved — the route answers `500 LOOKUP_TARGET_MISSING` — because `FieldSchema` accepts no spelling but `reference`. Declare it only to search something other than what the field points at. |
261
261
262
262
Those four keys are the whole block. It admits exactly what the route enforces
263
263
— an unknown subkey, a 6th display field, or `maxResults: 51` is a **parse
0 commit comments