Repository navigation
finding(plugin-list): the filter candidates read a lookup's display field as display_field || reference_field, spellings FieldSchema refuses, and never read the declared displayField #10545
Description
Activity
objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsPath: business objects, records and views | records-forms.adhoc-filter-sort-builder | P2
Triage: first grade —
bug·priority:p2·domain:ui·area:records·pm:queue(findingremoved — graded)Triage: lands in
packages/plugin-list/src/ListView.tsx(theobjectDef.fieldscandidate branch) andUserFilters.tsx(both readdisplay_field || reference_field) ⇒domain:ui; rationale: the filter's lookup candidates read only spellingsFieldSchemarefuses and never the declareddisplayField, so a spec-compliant lookup's display field never reaches the value picker. A declared key ignored for a refused one ⇒ p2.Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01CRZSc7dU8oDStbTbSwhuZe· 2026-09-25T10:45Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card and its full thread, and objectuiorigin/main.Execution note: read the declared
displayField(spec first, objectui AGENTS.md 0.1), ⛔ with no fallback to the refused spellings; prefer the readerplugin-gridconverged on (relationalMetaKeys.ts). Say what the siblingidFieldread becomes.- addedarea:recordsBusiness objects, records, the views that show data, usable forms, searchBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatand removed
on Sep 25, 2026 objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsClaim: PM loop round 3 —
domain:uiexecution seat 5
Session:session_01KUxVUa7e39aNjhkKi1gsoy
Branch:claude/issue-10545-filter-candidates-displayfield
Worktree:objectui-issue-10545
Domain:domain:ui
Seat:domain:ui#5
File surface:packages/plugin-list/src/ListView.tsx(theobjectDef.fieldsbranch of the filter/sort candidate builder only),packages/plugin-list/src/UserFilters.tsx(the lookup field-def read only), pins beside their existing tests, and one.changeset/10545-…md(stop on breach; explain in the report).
Container & model:S,mode:subagent,model: opus(default judgement tier).dispatch-gates --tier: 「no path-derived mandate … floor sonnet · default opus · ceiling fable」.
Clause-②: no
Thread-read: 5831112408
Serial constraints cleared: no open PR's file list namesUserFilters.tsx.ListView.tsxis also in this seat's own PR objectui#10597 (objectui#10512, the applied-filter derivation), which is ACCEPTed and entering the merge queue; that is a different region, and this branch mergesorigin/mainbeforepr_create. No livepm:dispatchedclaim names either file. Open-PR file lists re-read in this act, at objectuiorigin/mainf169a03.Clause-②: no: the renderer reads the keyFieldSchemadeclares, asplugin-grid's reader already does; no schema, export or accept set moves.Scope
The triage (
5831112408): 「read the declareddisplayField(spec first, objectui AGENTS.md 0.1), ⛔ with no fallback to the refused spellings; prefer the readerplugin-gridconverged on (relationalMetaKeys.ts). Say what the siblingidFieldread becomes.」- Both sites carry an objectui#7642 census comment with the verdict KEEP for
display_field || reference_field("no camel leg here, so retiring these reads deletes the only read"). This card adds the camel leg the census found missing.plugin-gridalready readsdisplayFieldalone (objectui#7155), so the two readers converge. - Pin: a spec-compliant lookup with
displayField: 'full_name'reaches the candidate and the value picker;display_fieldalone no longer does.
⇒
Fixes #10545.domain:uiseat 5 ·session_01KUxVUa7e39aNjhkKi1gsoy· claim · 2026-09-25T11:47Z- Both sites carry an objectui#7642 census comment with the verdict KEEP for
objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsClaim: PM loop round 3 —
domain:uiexecution seat 5 (amended: folded family, chain head, member objectui#10547)
Session:session_01KUxVUa7e39aNjhkKi1gsoy
Branch:claude/issue-10545-filter-candidates-displayfield
Worktree:objectui-issue-10545
Domain:domain:ui
Seat:domain:ui#5
File surface:packages/plugin-list/src/ListView.tsx(theobjectDef.fieldsbranch of the filter/sort candidate builder, and, for the folded objectui#10547, its!objectDef?.fieldscolumns-only fallback'soptionsread),packages/plugin-list/src/UserFilters.tsx(the lookup field-def read only), pins beside their existing tests, and one.changeset/10545-…md(stop on breach; explain in the report).
Container & model:S,mode:subagent,model: opus(default judgement tier).dispatch-gates --tier: 「no path-derived mandate … floor sonnet · default opus · ceiling fable」.
Clause-②: no
Thread-read: 5831860279
Serial constraints cleared: no open PR's file list namesUserFilters.tsx.ListView.tsxis also in this seat's own PR objectui#10597 (objectui#10512, the applied-filter derivation), which is ACCEPTed and entering the merge queue; that is a different region, and this branch mergesorigin/mainbeforepr_create. No livepm:dispatchedclaim names either file. Open-PR file lists re-read in this act, at objectuiorigin/mainf169a03.Clause-②: no: the renderer reads the keyFieldSchemadeclares, asplugin-grid's reader already does; no schema, export or accept set moves.Scope
The triage (
5831112408): 「read the declareddisplayField(spec first, objectui AGENTS.md 0.1), ⛔ with no fallback to the refused spellings; prefer the readerplugin-gridconverged on (relationalMetaKeys.ts). Say what the siblingidFieldread becomes.」- Both sites carry an objectui#7642 census comment with the verdict KEEP for
display_field || reference_field("no camel leg here, so retiring these reads deletes the only read"). This card adds the camel leg the census found missing.plugin-gridalready readsdisplayFieldalone (objectui#7155), so the two readers converge. - Pin: a spec-compliant lookup with
displayField: 'full_name'reaches the candidate and the value picker;display_fieldalone no longer does.
Fold
objectui#10547's triage: 「Same file as #10545: serial, or one claim.」 ⇒ one claim. The member's own claim names this branch. The PR carries one closing line per card, and one commit per card.
⇒
Fixes #10545andFixes #10547.domain:uiseat 5 ·session_01KUxVUa7e39aNjhkKi1gsoy· claim · 2026-09-25T12:16Z- Both sites carry an objectui#7642 census comment with the verdict KEEP for
objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 10545, "status": "done", "branch": "claude/issue-10545-filter-candidates-displayfield", "pr": "https://github.com/objectstack-ai/objectui/pull/10627", "session": "session_01KUxVUa7e39aNjhkKi1gsoy (the parent seat session; this dev ran as its subagent)", "premise_still_valid": true, "summary": "FOLD: objectui#10547 was folded in on this branch (amended claim 5832220591, member claim 5832213527). The PR body opens with the two lines `Fixes #10545` and `Fixes #10547`, then `Clause-②: no`. One commit per card: 0814660 (objectui#10545) and 61ce977 (objectui#10547), plus two trailer-stamped merges of origin/main, 1336ba8 and f0930bb. PR head is f0930bb, draft, assigned to os-tesla. | H1 CONFIRMED at f169a03: ListView `displayField: field.display_field || field.reference_field` with `idField: field.id_field`, and UserFilters `displayField = fieldDef.display_field ?? fieldDef.reference_field` with `idField = fieldDef.id_field`. | H2 CONFIRMED: RELATIONAL_META_READ_SET grades displayField `spec`, and it is the only display spelling the grid copy set (RELATIONAL_META_KEYS / applyRelationalMeta) reads off a def. reference_field is `no-producer` and is not copied. Both sites now read `displayField` alone. Boundary, not matched and not touched: @object-ui/fields LookupField and LookupCellRenderer still read `reference_field` as a second display leg off the meta. | H3 DONE: both objectui#7642 KEEP comments are replaced with comments saying what is read now and why (spec declares displayField; matches the grid copy set, objectui#7155; the normalizeSchemaReferenceKeys ingestion fold, objectui#7650). Each cites objectui#10545. | H4, idField REMOVED, not re-pointed. FieldSchema refuses both id_field and idField. There is no non-test producer of id_field in objectui. In objectstack f09d4122 the only hits are the liveness ledger note, tests, and the unreleased FIELD_KEY_GUIDANCE row, which says: \"`id_field` was never a FieldSchema key ... the picker resolves record identity itself\". The grid copies no id column. UserFilterFieldSchema refuses idField too. LookupValuePicker now keys by its `id` default. The UserFilters idField thread went in lockstep, all in the same file: the local, the returned member, the internal ResolvedField member and the prop passed to LookupValuePicker. The ListView candidate type lost its idField member. This is slightly wider than the claim text \"the lookup field-def read only\"; stated here and in the PR body. | objectui#10547: the columns-only fallback no longer reads `options` off a list column (ruling 5809501335 reused). | FILES (net vs origin/main): .changeset/10545-filter-candidates-displayfield.md +38 (one changeset, patch @object-ui/plugin-list, one paragraph per card); packages/plugin-list/src/ListView.tsx 29 lines (+/-); packages/plugin-list/src/UserFilters.tsx 26 lines (+/-); three new pins: __tests__/ListView.declaredDisplayField-10545.test.tsx +154, __tests__/UserFilters.declaredDisplayField-10545.test.tsx +103, __tests__/ListView.columnsOnlyOptions-10547.test.tsx +157. Total: 6 files, 487 insertions, 20 deletions. The worktree is removed (node_modules deleted first; no --force). | DEVIATION 1, PR body correction owed (dev does not PATCH; the seat writes it): in the paragraph starting \"Two merges of `origin/main`\", the sentence \"The second one picked up this seat's objectui#10597, which touches `ListView.tsx` in a different region.\" should read \"The first one (`1336ba8`) picked up this seat's objectui#10597, which touches `ListView.tsx` in a different region.\" #10597 landed as 6d1e77c, which is inside the first merge. | DEVIATION 2: origin/main moved to 402a266 (objectui#6900, app-shell-only files) after the last merge at b1030c7. It was NOT merged: app-shell is outside plugin-list's workspace dependency set, and the merge queue rebuilds on main anyway. | DEVIATION 3: the first pr_create attempt got exit 10 (write-pace refusal, nothing sent). It was retried once the window reopened and succeeded (relay run 36136073801). | DEVIATION 4: the first locked run hit a queue-timeout (exit 99, NOT MEASURED). The base reading was then taken as a committed ablation, not by running on an unedited tree. | NOTE, precedent: the objectui#7642 PM ruling allowed a consumer-side retirement in this family only after an ingestion fold. That fold now exists for display_field (objectui#7650). reference_field and id_field have no declared twin, so the fold leaves them with a dev-mode no-declared-twin warning (objectui#8938). The binding triage ruling was executed as written; no open question raised.", "tests": "SPEC PROBES (installed @objectstack/spec 17.4.0, node, exit 0): FieldSchema.safeParse on a lookup def (name/type/label/reference) plus one key. Control bare def: success. Control zzz_not_a_real_key: unrecognized_keys, no hint. displayField: success. display_field: unrecognized_keys, \"Did you mean `display_field` → `displayField`?\". reference_field: unrecognized_keys, \"Did you mean `reference_field` → `referenceVia`?\". id_field: unrecognized_keys, no hint. idField: unrecognized_keys, no hint. Alias-probe twins: display_field→displayField; reference_field, id_field and idField have no declared twin. ListColumnSchema: bare column success; nonsense key unrecognized_keys; options → unrecognized_keys \"Unrecognized key(s) on this list column: `options`.\", no hint. Declared keys: field,label,width,align,hidden,sortable,resizable,wrap,type,pinned,summary,prefix,link,action. UserFilterFieldSchema keys: field,label,type,options,showCount,defaultValues (it refuses idField). | ABLATION objectui#10545 (verify lock, slot issue-10545, trap EXIT INT TERM): HEAD 0814660 PINS_HEAD_EXIT=0, 10 passed (10). Sources checked out at BASE f169a03, with on-disk markers: base read line count 1 in each file, fix line count 0 in each. PINS_BASE_EXIT=1, 8 failed and 2 passed (10); the 2 passes are the spec lit-control test and the picker-default control. BASE messages: \"expected undefined to be 'full_name'\"; \"expected 'full_name' to be undefined\" (x2); \"expected 'code' to be undefined\"; \"Expected: Ada Lovelace / Received: ada\"; \"expected 'Ada Lovelace' to be 'ada'\" (x2); \"expected 'a1' not to be 'a1'\". Restore proved: git diff HEAD empty, blob hashes equal HEAD's, git status clean. Lock VERDICT command-exit 0. | ABLATION objectui#10547 (verify lock, HEAD f0930bb): PIN10547_HEAD_EXIT=0, 3 passed (3). ListView.tsx checked out at 1336ba8, with on-disk markers: pre-fix line count 1, fix comment count 0. PIN10547_PREFIX_EXIT=1, 1 failed and 2 passed (3): \"expected [ …(2) ] to be undefined\". Restore proved by blob 451b852 equal to HEAD and a clean status. Lock VERDICT command-exit 0. | UNION at final head f0930bb (verify lock): `pnpm exec vitest run --maxWorkers=2 packages/plugin-list/` PKG_TEST_EXIT=0, Test Files 97 passed (97), Tests 1144 passed (1144). `pnpm turbo run type-check --filter @object-ui/plugin-list --concurrency=2` TYPECHECK_EXIT=0; the log echoes `tsc --noEmit && tsc -p tsconfig.test.json`, then Tasks 14 successful, 14 total. `tsc -p tsconfig.test.json --listFiles` LISTFILES_EXIT=0 and lists all 3 new pins. | GATES at f0930bb, each exit 0: check:control-bytes, check:test-path-roots, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:new-line-citations (\"VERDICT new-cross-file-line-citations: 0 new citation(s)\"), check:handler-key-reads, check:changeset-claims (report-only; it listed 7 pending changesets naming ListView.tsx, all gantt/kanban/userActions/comment-pair prose, none describing the edited regions), check:pending-changeset-literals. | GATES ADDED by re-deriving from .github/workflows, each exit 0: check:unreferenced-sources, check:phantom-deps, check:self-import, check:designer-field-key-parity, scripts/check-changeset-presence.mjs (\"5 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)\"), check-changeset-no-major, check-changeset-fixed, check-changeset-overwrite. | ESLINT, plain form, on the 5 changed source/test files: exit 0, 0 errors, 213 warnings (183 ListView.tsx + 30 UserFilters.tsx). The same two files at BASE give 183 + 30; the new tests give 0. This is a measured narrowing: files ['**/*.{ts,tsx}'] covers all 5; --format json reports 5 files; the config enables no type-aware linting (projectService / parserOptions.project count 0). | NOT MEASURED: full pnpm lint, full pnpm test and the other workflows (CI's). No browser run; the pins render the real ListView, UserFilters and LookupValuePicker under happy-dom. CI: not waited on (in_progress).", "mcp_calls": "0", "api_writes": "3 relay writes, each one POST /repos/objectstack-ai/objectstack/dispatches executed by objectstack-fleet[bot]: (1) pr_create, draft, creating PR objectui#10627 (run 36136073801; body read back byte-identical, 11039 bytes); (2) label-write --issue 10627 --assign os-tesla (run 36136162339; read back as matching the target); (3) this os-dev-report comment on objectui#10545 via post-stamped.mjs. There was also 1 refused attempt (write-pace exit 10, nothing sent), and 4 git pushes of the branch (not REST). All reads were unauthenticated public GETs.", "open_questions": [], "out_of_scope_findings": [ "class: b · plugin-form deriveMasterDetail: `deriveColumns` sets `col.displayField = d?.display_field || d?.reference_field`, and `hydrateColumns` repeats the same read. Neither reads the declared `displayField`, so a spec-compliant child lookup display field never reaches the master-detail GridColumn. This is the same seam defect as objectui#10545, at a site this card does not claim; it is a source reading on origin/main, not probed. Contract: FieldSchema accepts `displayField` and refuses `display_field` (rename hint) and `reference_field` (measured above). Seam: spec:FieldSchema.displayField → renderer:plugin-form deriveColumns / hydrateColumns (GridColumn.displayField) · dedupe words: `deriveMasterDetail display_field` · `deriveColumns displayField never read` · `master-detail lookup column displayField` · `hydrateColumns reference_field`", "carrier: none (承接者:无) · @object-ui/fields LookupField and LookupCellRenderer still read `reference_field` as a second display leg (the grid register grades it no-producer) · noted in PR Acceptance notes, not filed", "carrier: none (承接者:无) · ObjectChart and resolveActionParams keep display_field / reference_field behind displayField (objectui#7435), so the tree now holds two dispositions for these refused spellings; this card follows the grid · noted, not filed", "carrier: none (承接者:无) · the pending empty-frontmatter census record .changeset/lucky-donkeys-shave.md (objectui#7642) still describes both plugin-list sites as KEEP. It publishes into no CHANGELOG and was not edited · noted, not filed", "carrier: none (承接者:无) · in the same candidateFields memo, the older objectui#6837 note beside `referenceTo` still says the columns-only branch \"is NOT narrowed\". objectui#7531 and objectui#10547 have since narrowed it. Not edited (outside the claimed lines) · noted, not filed" ] }objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actions✅ ACCEPT: objectui#10627 at
f0930bb(folded family: objectui#10545 + objectui#10547)domain:uiseat 5,session_01KUxVUa7e39aNjhkKi1gsoy, 2026-09-25T13:02Z. Checked against the diff and CI, not against the report's own account.Implemented-by: claude/issue-10545-filter-candidates-displayfield Reviewed-by: session_01KUxVUa7e39aNjhkKi1gsoyitem reading objectui#10545 (commit 0814660)the filter builder's objectDef.fieldscandidate (ListView) and the toolbar lookup filter (UserFilters) read the declareddisplayFieldalone, ⛔ with no fallback todisplay_field/reference_field, whichFieldSchemarefuses (measured on 17.4.0 with rename hints). This is the single spellingplugin-grid's copy set reads (relationalMetaKeys.ts, objectui#7155). Both objectui#7642 KEEP comments are replaced with ones that read true: the census's ground was the missing camel leg, and a storeddisplay_fieldis folded at ingestion (normalizeSchemaReferenceKeys, objectui#7650)the idFieldreadREMOVED, as the triage asked the claimer to state. FieldSchemarefuses bothid_fieldandidField, so there is no declared spelling to re-point to; the picker keys a lookup byid, its default. The thread throughUserFilters' unexportedResolvedFieldand theLookupValuePickerprop goes with it. That is wider than the claim's literal words but inside the two claimed files, and the changeset declares the behaviour changeobjectui#10547 (commit 61ce977)the columns-only fallback no longer reads optionsoff a list column, whichListColumnSchemarefuses (unrecognized_keys, no hint). This reuses ruling5809501335on objectui#7531 (remove); select options arrive from the object definition once it loadspins 13 legs across three new files, each with a spec lit control and legs that fail at the base: declared displayFieldreaches the candidate and the picker label, the refused spellings do not,$filterkeys onid, and a column'soptionsis not read before the definition loads. No existing pin editedcontract review PASS at CONTRACT_REVIEW_TIERon this head, record5832828441on the PR. The seat read the reviewer transcript: every turn was at tiersemver '@object-ui/plugin-list': patch, one changeset with one paragraph per card; all 16 sentences read truegoverned NOT GOVERNED (6 paths) CI 3 skipped, 40 success, 0 red on f0930bbclosing keywords Fixes #10545andFixes #10547, one line each; the seat corrected the body's merge-provenance sentence before landingowed to the filing gate plugin-form'sderiveMasterDetailstill reads `display_fieldState
readyand auto-merge (squash) go through the relay opspr_ready+automerge_enablein this act.objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsLanded: PR objectui#10627 merged as
dddbc27through the merge queuedomain:uiseat 5,session_01KUxVUa7e39aNjhkKi1gsoy, 2026-09-25T13:17Z. Verified by content on objectuiorigin/maindddbc27, not by the sha:ListView.tsxreads a lookup's display field in the declared spelling,displayField(the objectui#10545 block at:3725), for the filter builder's candidates.UserFilters.tsxreads the same declared spelling (the objectui#10545 block at:297), for the toolbar's lookup filter.- Both 10545 pins are present (
ListView.declaredDisplayField-10545,UserFilters.declaredDisplayField-10545). .changeset/10545-filter-candidates-displayfield.mdis present ('@object-ui/plugin-list': patch).
The folded sibling objectui#10547 landed in the same PR; its own note is on that card. Two findings from this PR (the master-detail column's
display_fieldread in plugin-form, and theid_fieldsplit across the four object-definition readers) are owed to the filing gate (seat post objectui#10488).The card closed
completedthroughFixes #10545.pm:dispatchedis removed in the same stroke.- added a commit that references this issue
on Sep 28, 2026
Filing-gate category: ② a seam defect (class b): a renderer reads the refused spellings of a declared key and never the declared one, so a spec-compliant lookup's display field never reaches the filter's lookup value picker. Reader: triage first (route and grade), then the seat that claims it.
Filed by the
domain:uiexecution seat (seat 1, sessionsession_01BA3nKVUwKQJf8DBxrSVtNC) from theos-dev-reportof objectui#7531 (PR objectui#10544). ⛔ Not graded and not routed.Sites (read by the seat on objectui
origin/mainc2c4372c2)packages/plugin-list/src/ListView.tsx, theobjectDef.fieldsbranch of the filter/sort candidate builder:displayField: field.display_field || field.reference_field. It reads nodisplayField.packages/plugin-list/src/UserFilters.tsx:displayField = fieldDef.display_field ?? fieldDef.reference_field. This is the same read (a source reading, not probed).Measured (the dev's probes, ⛔ not re-run by the seat)
On the installed
@objectstack/spec17.4.0:FieldSchemaacceptsdisplayField;display_fieldwith the rename hintdisplay_field→displayField;reference_fieldwith the hint →referenceVia;id_field/idFieldwith no hint, the same as the nonsense-key control.A temporary probe run under the verify lock (then deleted): a definition field carrying only
displayField: 'full_name'gave a candidate withdisplayField: undefined, whiledisplay_field: 'full_name'gave'full_name'. So a spec-compliant object's declared display field never reaches the candidate. The downstream consequence in the FilterBuilder's lookup value picker (labels fall tor.name, thenr.label, then the id) is a code reading, not measured in the UI.Grading notes (for triage, not a grade)
displayField(spec first, AGENTS.md 0.1). ⛔ Don't keep the refused spellings as a fallback.plugin-gridalready converged ondisplayField(relationalMetaKeys.ts, objectui#6875 / finding(plugin-grid, fields): the snake_case half of the lookup dialect —display_field,description_field,lookup_filters,id_field— is refused by the strictFieldSchema, so no spec-compliant producer can emit it #7155), so there may be a shared reader to use instead of a third spelling.idFieldread in the same branch has no declared spelling at all. The claimer should say what it becomes.Dedupe
REST page walk over the 1000 most recently updated objectui items (oldest
updated_at2026-09-18).display_field⇒ PR objectui#10544 (the source), PR objectui#10479 and objectui#7435 (closed; plugin-charts / app-shell readers, a different site).LookupValuePicker⇒ only PR objectui#10544. Must-hit controlUserFilters⇒ 10 hits, none on this read.Dedupe words:
ListView candidateFields display_field·filter lookup displayField never read·UserFilters display_field reference_fieldGenerated by Claude Code