Repository navigation
finding(fields): the record picker's display column still renders titleFormat above nameField, so after objectui#10479 the lookup dropdown and the picker label the same record differently #10486
Description
Filing-gate category: ① a product defect with a named site and a reproduction. Reader: triage first (route and grade), then the domain:ui execution seat that claims it. The site is packages/fields/src/widgets/lookupColumnDisplay.tsx (renderLookupColumnValue, the display-column step).
Filed by the domain:ui seat #2 (session_014mXUNuFomfj24w7s1pZzhN) at the ACCEPT of objectui#10343 (PR objectui#10479). It comes from the dev's out_of_scope_findings (class b) and the at-tier contract review of that PR, which both measured it. ⛔ Filed bare, not graded here.
The defect
objectui#10479 moved the lookup dropdown option label onto @object-ui/core's getRecordDisplayName. The order is now the field's own displayField, then the object's nameField, then the deprecated titleFormat: the lookup branch of objectui#9436 ruling C1. The browse-all record picker's display column was outside that claim and still does it the old way. renderLookupColumnValue renders titleFormat first, through its own private single-brace renderer.
⇒ On an object that declares both nameField and titleFormat, the same record reads differently:
| surface | label |
|---|---|
| lookup dropdown option (after PR objectui#10479) | the nameField value, e.g. HT-001 |
| record picker, display column | the rendered template, e.g. Globex / HT-001 |
Before PR objectui#10479 both surfaces read the template, so this PR creates the disagreement. A double-brace template also still keeps its outer braces in the picker column ({Globex} / {HT-001}). Spec 17.4.0's titleFormat describe says the two placeholder spellings are equivalent: the title renderers normalize the double-brace form to the single-brace one before substituting.
Contract
@objectstack/spec17.4.0,titleFormatdescribe: "[DEPRECATED → nameField (ADR-0079)] … an explicit nameField now takes precedence".- objectui#9436 ruling C1 (maintainer 「同意」): the declared pointer outranks
titleFormat. The record page (ba0b61a) and the lookup dropdown (PR objectui#10479) now follow it.
Reproduction
The dev ran a throwaway probe at PR head 600c330, not committed. The object has nameField: 'contract_no' and titleFormat: '{party} / {contract_no}'. The dropdown reads ['HT-001'], and the picker's name column reads Globex / HT-001. The existing pin in LookupField.candidateExpand-10223 (C-0 - samepick_task_0 in the name column) shows template-over-column too. lookupColumnDisplay.tsx:190-208 at head); the seat did not re-run them.
Fix direction (for triage, not a ruling)
Route the display column through the same getRecordDisplayName call the dropdown and the read cell use, rather than a third copy of the ladder. That way the three lookup surfaces cannot drift again.
Dedupe
REST page walk over the 1000 most recently updated objectui issues and PRs (the search API answers 403 here), oldest updated 2026-09-18T06:33Z. Pattern lookupColumnDisplay|renderLookupColumnValue|picker … (display|name) column … titleFormat ⇒ 3 hits: PR objectui#10479 (the origin), PR objectui#10459 and PR objectui#10341. The last two are unrelated PRs that mention the file. No issue. Lit control recordToOption ⇒ 4 hits, so the instrument is lit. ⇒ No duplicate.
Dedupe words: renderLookupColumnValue titleFormat · picker display column nameField · RecordPickerDialog title column template · lookup picker double brace placeholder
Generated by Claude Code
Activity
objectstack-fleet commentedon Sep 25, 2026
Path: business objects, records and views | records-forms.lookup-picker-create-new | P2
Triage: first grade —
bug·priority:p3·domain:ui·area:records·pm:queue(findingremoved — graded)Triage: lands in
packages/fields/src/widgets/lookupColumnDisplay.tsx(renderLookupColumnValue,titleFormatfirst on objectuiorigin/maind999617) ⇒domain:ui; rationale: the record picker's display column still renderstitleFormatabovenameField, so after PR #10479 the dropdown and the picker label the same record differently; ruling C1 on objectui#9436 already sets the order ⇒ p3.Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01CRZSc7dU8oDStbTbSwhuZe· 2026-09-25T07:01Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card and its full thread, and objectuiorigin/maind999617. Dedupe by this seat over 739 objectui cards (open, plus closed since 2026-09-18):renderLookupColumnValue→ 1 hit (this card).Execution note: route the column through the same
getRecordDisplayNamecall as the dropdown and the read cell; ⛔ not a third copy of the ladder.objectstack-fleet commentedon Sep 25, 2026
Claim: PM loop round 3 —
domain:uiexecution seat 5Session:
session_01KUxVUa7e39aNjhkKi1gsoyBranch:
claude/issue-10486-picker-column-display-nameWorktree:
objectui-issue-10486Domain:
domain:uiSeat:
domain:ui#5File surface:
packages/fields/src/widgets/lookupColumnDisplay.tsx(renderLookupColumnValue, the display-column step only), a pin beside the existing record-picker tests, and one.changeset/10486-…md(stop on breach; explain in the report). ⛔ NotLookupField.tsx(seat 1's live claim on objectui#10487) and ⛔ notpackages/core/src/utils/record-title.ts(seat 2's open PR objectui#10555): the column callsgetRecordDisplayNameas it stands.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: 5828316879
Serial constraints cleared: no open PR's file list names
lookupColumnDisplay.tsxorRecordPickerDialog.tsx, and no live claim does. PR objectui#10555 editsrecord-title.ts, which this card consumes and does not edit; seat 1's objectui#10487 claim holdsLookupField.tsx's hydration region, a different file. Open-PR file lists re-read in this act, at objectuiorigin/mainfee1da5.Clause-②: no: the picker column adopts the order ruling C1 on objectui#9436 already sets for the dropdown; no schema, export or accept set moves.Scope
The triage (
5828316879): 「route the column through the samegetRecordDisplayNamecall as the dropdown and the read cell; ⛔ not a third copy of the ladder.」nameField: 'contract_no'andtitleFormat: '{account} / {contract_no}'. The dropdown option readsHT-001and the picker's display column readsGlobex / HT-001.getRecordDisplayName's answer; the private single-brace renderer goes if nothing else reads it (count its callers and report them).titleFormatalone still renders its template.⇒
Fixes #10486.domain:uiseat 5 ·session_01KUxVUa7e39aNjhkKi1gsoy· claim · 2026-09-25T08:48Zobjectstack-fleet commentedon Sep 25, 2026
os-dev-report
{
"issue": 10486,
"status": "blocked",
"branch": "claude/issue-10486-picker-column-display-name",
"pr": null,
"session": "session_01KUxVUa7e39aNjhkKi1gsoy (parent PM session; this run is its subagent)",
"premise_still_valid": true,
"summary": "Blocked before the first edit. The branch is pushed empty at 4a7ef0d (BASE = origin/main 4a7ef0d). git diff fee1da5 4a7ef0d over packages/fields and core record-title.ts is empty, so the dispatch readings still apply. Premise reproduced at base (P1, P2 in tests). H1 confirmed at source: step 1 of renderLookupColumnValue is a private single-brace template renderer, gated on ctx.titleFormat and col.field === displayField. H2 FALSIFIED: RecordPickerDialog holds no object schema. Its only inputs are three props from LookupField: titleFormat (the refTitleFormat memo, a string cut out of refObjectSchema), fieldsMeta (refObjectSchema.fields) and displayField (declaredDisplayField, else the 'name' default). nameField reaches the dialog through no prop, and the dialog cannot tell a declared displayField from the 'name' default. The dropdown's call is getRecordDisplayName(objectDef, shown, { titleField: declaredDisplayField }), so making the column's call the same one needs two inputs that only LookupField.tsx holds. The order fences that file (seat 1, objectui#10487): 'stop and report blocked'. Neither input can be faked inside the dialog (measured): P5 shows that the dialog's displayField used as titleField ranks the 'name' guess (Acme) above both titleFormat and nameField, and P4 shows that the declared displayField rung disagrees today as well. Scope is wider than the card title. With no titleFormat at all the column still never reads nameField: P6 and P7 in tests. H3 confirmed at source: the row step 1 reads is withoutDeniedFields(toPredicateRecord(record, fieldsMeta), perms, objectName, idField). Its pins are LookupField.candidateExpand-10223 'picker: same title cells, same task cells, same records handed to onSelectRecords' and RecordPickerDialog.displayFls-10373 'a
titleFormatnaming a denied field does not render it in the display column'. Both pass titleFormat and displayField='name' straight into RecordPickerDialog, and both fixtures' rows carry a name value. H4: git grep EMPTY_SLOT = 5 hits in lookupColumnDisplay.tsx (1 declaration, 4 uses), all inside step 1. The template renderer is inline in step 1, not a separate function. git grep 'titleFormat=' over non-test tsx = 1 hit (LookupField's RecordPickerDialog JSX). Seat 1's branch claude/issue-10487-lookup-hydrated-label-follows-schema (head 0116766, read into a private ref that is now deleted) edits recordToOption, the component's early state block and the hydration/findOption region of LookupField.tsx. The edits option A needs are the refTitleFormat memo and the RecordPickerDialog JSX props, and they sit outside every one of its hunks. Files changed: 0. Two throwaway probe test files were created and deleted uncommitted; git status is empty and HEAD = BASE.","tests": "No gates run: the diff is empty. NOT MEASURED: every dispatch gate family (vitest packages/fields, type-check, eslint, check:* list, changeset gates), reason: blocked before the first edit, no code change. The agreement pin's before/after pair is NOT MEASURED because there is no fix. P1 is the base-side reading of that pin's shape. Probes: throwaway vitest files under packages/fields/src/widgets, run from the worktree root as pnpm exec vitest run --maxWorkers=2 FILE with NODE_OPTIONS=--max-old-space-size=4096 through os-verify-lock slot dev-10486-objectui. Results went to a scratch file, the files were never committed, and they were deleted (git status empty afterwards). Run 1: VERDICT command-exit 0, Tests 5 passed, no readings (the test setup silences console). Run 2: VERDICT command-exit 0, Tests 5 passed = P1..P5. Run 3: VERDICT queue-timeout (exit 99), never acquired, NOT MEASURED, retaken with the same slot. Run 4: VERDICT command-exit 0, Tests 2 passed = P6, P7. Probe fixture: object contract, fields contract_no / name / account / short_code (all text); rows c1 = HT-001 / Acme / Globex / AC and c2 = HT-002 / Initech / Umbrella / IN; template T = '{account} / {contract_no}'. Dropdown = each option's title attribute; picker = textContent of the display column's data-lookup-cell cells, opened through LookupField's browse-all-records button. Readings at 4a7ef0d: P1 nameField contract_no + T: dropdown [HT-001, HT-002], picker [Globex / HT-001, Umbrella / HT-002]. P2 the double-brace spelling of T, no nameField: dropdown [Globex / HT-001, Umbrella / HT-002], picker [{Globex} / {HT-001}, {Umbrella} / {HT-002}]. P3 T alone (lit control): dropdown and picker both [Globex / HT-001, Umbrella / HT-002]. P4 field displayField short_code + nameField + T: dropdown [AC, IN], picker short_code column [Globex / HT-001, Umbrella / HT-002]. P5 getRecordDisplayName on row c1: T-only object with titleField 'name' = Acme, with titleField undefined = Globex / HT-001; nameField+T object with titleField 'name' = Acme, with titleField undefined = HT-001. P6 nameField only, rows carry name: dropdown [HT-001, HT-002], picker [Acme, Initech]. P7 nameField only, no name field or value: dropdown [HT-001, HT-002], picker ['', ''] (columns name, contract_no, account).",
"mcp_calls": "0",
"api_writes": "1: POST /repos//issues/10486/comments (this report, scripts/pm/post-stamped.mjs through the fleet-write relay). Also one git push of the empty branch, which is not a REST write. Zero PR writes, zero label writes. Reads: REST GET issues 10486, 9436 and 10487 plus their comment threads; one git fetch of seat 1's branch into a private ref, now deleted.",
"open_questions": [
{
"question": "The column's call needs two inputs only LookupField.tsx holds: the referenced object's schema (for nameField) and whether the lookup declared its displayField. How should the claim be re-scoped? Axes: business need / long-term soundness / AI-error resistance / startup focus.",
"options": [
"A: widen the surface by one file region, LookupField.tsx's refTitleFormat memo plus its RecordPickerDialog JSX (hunk-disjoint from seat 1's objectui#10487 branch, measured). RecordPickerDialog's titleFormat prop is REPLACED by objectSchema (the referenced object's schema). LookupField passes objectSchema=refObjectSchema and displayField=declaredDisplayField, and the dialog keys its display column on displayField ?? 'name' while handing the raw declared value to the resolver as titleField. LookupColumnRenderContext carries objectSchema and titleField in place of titleFormat. Step 1 renders getRecordDisplayName(objectSchema, row, { titleField }) whenever a schema is given, not only when a titleFormat is declared, on the same denied-stripped, relation-collapsed row (H3). It uses recordToOption's floor exclusion, falling through to the cell renderer on 'Untitled' or 'Record #id'. The private renderer and EMPTY_SLOT go (0 readers outside step 1). The two H3 pins migrate titleFormat= to objectSchema= and drop their explicit displayField='name', with unchanged assertions. One changeset for @object-ui/fields, minor with a behaviour-change banner, because a published prop is retired and the column moves for nameField-only objects too (P6, P7). Clause-2 becomes yes. Business: measured, since LookupField is the only non-test producer of titleFormat= and P1, P2, P4, P6 and P7 reproduce the user-visible split. Long-term: one resolver call on all three lookup surfaces, schema in rather than a pre-cut template, no third ladder. AI-error: no caller can hand the dialog a template without the pointer that outranks it. Startup: the prop retires at once, with no dual spelling.",
"B: as A, but KEEP the titleFormat prop beside objectSchema. The dialog builds objectSchema ?? { titleFormat, fields: fieldsMeta }. That is additive (no break), but still Clause-2 yes. Business: no named external user of the prop was found. Long-term: two sources for one fact. AI-error: a consumer-side ?? fallback, the tolerance contract-first rules out, and it keeps a declared prop that its only producer stops using. Startup: a staged transition without named external-user evidence.",
"C: stay inside the fence. The dialog fetches the schema itself (dataSource.getObjectSchema(objectName)) and passes no titleField. That needs no LookupField edit and makes P1, P2 and P3 go green. Business: leaves the ruled first rung unhonoured, because a declared displayField column still disagrees with the dropdown (P4). Long-term: a second schema fetch per picker, and the dialog widened beyond the pre-authorized renderCellContent callback. AI-error: passing the dialog's own displayField as titleField instead is measured wrong (P5: the 'name' guess outranks titleFormat and nameField). Startup: ships a partial that needs a follow-up card.",
"D: park this card until objectui#10487 lands, then re-dispatch with A's surface. Business: the split stays live meanwhile. Long-term: same end state as A. AI-error: same as A. Startup: no parallel edit of one file."
],
"recommendation": "A, landed hunk-coordinated with seat 1's objectui#10487 (whichever lands second merges main), or D if the seat will not share LookupField.tsx. Business need: A is the only option that closes every measured split (P1, P2, P4, P6, P7). Long-term soundness: it puts the column on the exact call the dropdown and the read cell make. AI-error resistance: it removes the only prop through which a bare template can outrank a declared pointer. Startup focus: it retires that prop with no grace window, and its only producer migrates in the same PR."
}
],
"out_of_scope_findings": []
}
objectstack-fleet commentedon Sep 25, 2026
Claim: PM loop round 3 —
domain:uiexecution seat 5 (amended: surface and Clause-② re-scoped)Session:
session_01KUxVUa7e39aNjhkKi1gsoyBranch:
claude/issue-10486-picker-column-display-nameWorktree:
objectui-issue-10486Domain:
domain:uiSeat:
domain:ui#5File surface:
packages/fields/src/widgets/lookupColumnDisplay.tsx(step 1 ofrenderLookupColumnValueandLookupColumnRenderContext);packages/fields/src/widgets/RecordPickerDialog.tsx(itstitleFormatprop, replaced byobjectSchema, andrenderCellContent);packages/fields/src/widgets/LookupField.tsx(therefTitleFormatmemo and theRecordPickerDialogJSX props only); the two pins that passtitleFormat=today (LookupField.candidateExpand-10223,RecordPickerDialog.displayFls-10373), migrated with unchanged assertions; new pins beside them; one.changeset/10486-…md(stop on breach; explain in the report). ⛔ Notpackages/core/src/utils/record-title.ts.Container & model:
M,mode:subagent,model: opus(default judgement tier).dispatch-gates --tier: 「no path-derived mandate … floor sonnet · default opus · ceiling fable」.Clause-②: yes
Thread-read: 5830011189
Serial constraints cleared: objectui#10487 (seat 1, the
LookupField.tsxhydration region) landed asfde4cafvia PR objectui#10557, and its card is closed. No open PR's file list namesLookupField.tsx,RecordPickerDialog.tsxorlookupColumnDisplay.tsx, and no livepm:dispatchedclaim does. Open-PR file lists re-read in this act, at objectuiorigin/mainfde4cafor later.Clause-②: yes:RecordPickerDialogis published (packages/fields/src/index.tsxre-exports./widgets/RecordPickerDialog.js). ItstitleFormatprop retires in favour ofobjectSchema, the referenced object's schema, so the published surface moves. The at-tier contract review is owed before the seat enqueues.Why the surface moved
The dev's measured report
5830011189:RecordPickerDialogholds no object schema. Its display column gets a template string cut out of the schema (titleFormat),fieldsMeta, and adisplayFieldthat cannot tell a declared value from the'name'default. The dropdown's call isgetRecordDisplayName(objectDef, shown, { titleField: declaredDisplayField }), and both inputs live only inLookupField.tsx. Probes P1, P2, P4, P6 and P7 reproduce the split, including objects withnameFieldand notitleFormatat all.Ruled shape (the seat's choice among the report's options, on the four axes)
Option A. The column renders
getRecordDisplayName(objectSchema, row, { titleField })with the same inputs the dropdown uses, on the same denied-stripped, relation-collapsed row (objectui#10223 / objectui#10373). The private template renderer goes. ThetitleFormatprop retires at once: ⛔ no dual spelling, ⛔ noobjectSchema ?? { titleFormat }fallback (option B). The four-axis framework's startup rule says a retired spelling goes immediately unless a named external user needs a staged path; the dev's census found no producer butLookupField. Option C (a second schema fetch inside the dialog) leaves the declareddisplayFieldrung wrong (P4) and is not taken. The changeset isminorfor@object-ui/fields, and its prose states the breaking change: objectui's version policy marks its own breaking changesminorand nevermajor.⇒
Fixes #10486.domain:uiseat 5 ·session_01KUxVUa7e39aNjhkKi1gsoy· claim · 2026-09-25T09:38Zobjectstack-fleet commentedon Sep 25, 2026
os-dev-report
{
"issue": 10486,
"status": "done",
"branch": "claude/issue-10486-picker-column-display-name",
"pr": "#10590",
"session": "session_01KUxVUa7e39aNjhkKi1gsoy (parent PM session; this run is its subagent)",
"premise_still_valid": true,
"summary": "Option A implemented under amended claim 5830222755, the newest Claim on the card (it names this branch). Draft PR objectui#10590 is open at head 3e3ad60. Its body opens with this card's closing-keyword line, then the Clause-② yes line, and reads back byte-identical (9081 = 9081). Worktree recreated from pushed 4a7ef0d, then merged origin/main 8740e86 (a fast-forward; it contains fde4caf). New BASE = 8740e86. Commits: 20b031b (implementation + pins + changeset) and 3e3ad60 (changeset prose). Files: lookupColumnDisplay.tsx +37/-40 (248 to 245 lines); RecordPickerDialog.tsx +41/-21 (1389 to 1409); LookupField.tsx +5/-12 (1752 to 1745); LookupField.candidateExpand-10223.test.tsx +1/-2; RecordPickerDialog.displayFls-10373.test.tsx +1/-2; new LookupField.pickerColumnOrder-10486.test.tsx +202; new .changeset/10486-picker-column-display-name.md +44 ('@object-ui/fields': minor). What changed: RecordPickerDialog's titleFormat prop is REMOVED, with no fallback, and objectSchema is added. displayField now means the declared value, and the column is keyed on displayField ?? 'name'. LookupColumnRenderContext carries objectSchema + titleField in place of titleFormat. Step 1 renders getRecordDisplayName(objectSchema, row, { titleField }) whenever a schema is given, with recordToOption's floor exclusion, on the same toPredicateRecord + withoutDeniedFields row. The private renderer and EMPTY_SLOT are deleted. LookupField.tsx edits are limited to deleting the refTitleFormat memo and the RecordPickerDialog JSX props: displayField={declaredDisplayField}, objectSchema={refObjectSchema}, plus one comment. Reader recount at the new base: EMPTY_SLOT 5 hits, all in step 1, before; 0 after. git grep EMPTY_SLOT|refTitleFormat under packages/ exits 1, and the control git grep -c renderLookupColumnValue hits. Callers re-checked: the only non-test titleFormat= was LookupField's. AccessExplainPanel (2 dialogs), AssignedUsersSection and RelatedList pass neither titleFormat nor objectSchema. PeoplePicker imports only lookupFiltersToRecord, and LocationField names the dialog only in a comment. No caller migration was needed. PR assignee os-tesla set and read back. Labels are the labeler's own (tests, package: fields); I wrote none. Deviations: (1) both migrated pins also drop their explicit displayField='name'. Their rows carry a name value, so a declared name would outrank the template; assertions are unchanged. (2) The reverse verification swapped whole files to their BASE blobs with git checkout, proved by blob hashes, rather than using ablation-replace.mjs anchors. (3) No re-merge after 8740e86: main moved 6 commits, and git diff --stat 8740e86 origin/main over packages/fields and the two named changesets is empty. (4) No docs edit: content/docs and packages/fields/README.md do not document this prop, and docs are outside the claimed surface. Write-pace refusals (exit 10, nothing written) were waited out in the foreground: one before pr_create, one before the assign.",
"tests": "All at head 3e3ad60 unless noted. Heavy runs went through os-verify-lock slot dev-10486-objectui with NODE_OPTIONS=--max-old-space-size=4096. (1) pnpm exec vitest run --maxWorkers=2 packages/fields/: Test Files 201 passed | 1 skipped (202), Tests 3315 passed | 7 skipped (3322), FIELDS SUITE EXIT=0, lock VERDICT command-exit 0. (2) pnpm turbo run type-check --filter @object-ui/fields --concurrency=2: Tasks 12 successful, 12 total; '@object-ui/fields:type-check: cache miss, executing'; lock VERDICT command-exit 0. tsc -p tsconfig.test.json --listFiles contains the three touched test files. (3) Targeted run before commit: 5 files (10486, 10223, 10373, 10343 labelOrder, pickerAgreement), 39 passed, VERDICT command-exit 0. (4) Reverse verification at 20b031b..3e3ad60, fix committed first, trap restore. The three implementation files were swapped to their 8740e86 blobs (disk blob == base blob each: d05ac7e7, 0cf98a87, 30540879). Markers: getRecordDisplayName 0 and EMPTY_SLOT 5 in lookupColumnDisplay.tsx. Ran 10486 + 10223 + 10373: ABLATED RUN EXIT=1, 8 failed | 23 passed (31). The agreement pin is red there (dispatch pin-shape exit pair: base 1, fixed 0). Red set: agreement, double-brace, declared displayField, nameField-only x2, the unit control 'a record with a title renders it in the display column only', 10223 'picker: same title cells, same task cells, same records handed to onSelectRecords', and 10373 'control: with no policy loaded, the same
titleFormatrenders every field it names'. Predicted 9 before the run; observed 8. The 10373 case 'atitleFormatnaming a denied field does not render it in the display column' stayed green because its expected cells equal the no-template output. Restore proven: disk blob == HEAD blob for all three (78718f9e, bdbe7c1a, a1cbd3b4), git diff HEAD empty, status 0 lines. (5) eslint, plain form, on the 6 changed .ts/.tsx files: exit 0, 0 errors, 119 warnings. Population: ESLint.isPathIgnored false for 6 of 6. Count: --format json gives 6 results. Invariance: eslint.config.js has 0 parserOptions (no type-aware linting), and no eslint-rules/*.js outside tests reads files (grep exit 1). (6) Exit 0 for each of: pnpm check:control-bytes (8661 files), 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:changeset-claims (report-only; it flags lookup-dropdown-cell-renderer-5492, whose paragraph I read and which still holds), check:pending-changeset-literals, check:phantom-deps, node scripts/check-changeset-presence.mjs ('6 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'), check-changeset-no-major, check-changeset-fixed and check-changeset-overwrite. Control-byte self-scan of changed files: 0 hits. (7) Probe P8, a throwaway file deleted uncommitted (VERDICT command-exit 0): a declared displayField naming a relation, against a backend that does not honour $expand, reads dropdown [org1, org2] and picker [org1, org2] at both head and base, so no change was measured. The expanding-backend case is NOT MEASURED. (8) NOT MEASURED locally: downstream consumer type-check ('...@object-ui/fields', i.e. plugin-detail, app-shell and others), declared to CI. None of them passes titleFormat or objectSchema (git grep). CI on 3e3ad60 at report time: 42 check runs, 31 success, 3 skipped, 8 in_progress, 0 failed. Convergence is the PM's.","mcp_calls": "0",
"api_writes": "4 across both rounds, all REST through the fleet-write relay as objectstack-fleet[bot]: (1) round 1 POST /repos//issues/10486/comments (blocked report 5830011189); (2) POST /repos/objectstack-ai/objectui/pulls (draft pr_create, objectui#10590, run 36123796050); (3) POST /repos//issues/10590/assignees os-tesla (label-write.mjs --assign, run 36124633943, read back); (4) POST /repos//issues/10486/comments (this report, post-stamped.mjs). Refused attempts wrote nothing: two write-pace exit-10 refusals, one per round. git pushes (not REST): the empty branch, 20b031b and 3e3ad60. Zero label writes.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: domain:ui seat 5 · two pending changesets describe the pre-change tree: the last paragraph of .changeset/10343-lookup-option-label-order.md (the picker column 'still shows the template') and the titleFormat={refTitleFormat} sentence of .changeset/6874-retire-titleformat.md. This PR's changeset names both. The named fix is a prose-only correction of those two paragraphs, outside the claimed surface · noted, not filed",
"carrier: 承接者:无 · the withoutDeniedFields doc comment in LookupField.tsx still says the picker applies the rule to its display column's titleFormat; it now applies to the display column's title. That comment sits outside the two fenced spots · noted in Acceptance notes, not filed",
"carrier: 承接者:无 · the objectui#10373 pin 'a
titleFormatnaming a denied field does not render it in the display column' passes with or without the template, because its expected cells equal the no-template output; its lit twin carries the bite · noted in Acceptance notes, not filed"]
}
objectstack-fleet commentedon Sep 25, 2026
✅ ACCEPT: objectui#10590 at
f75aa9a(Clause-②: yes)domain:uiseat 5,session_01KUxVUa7e39aNjhkKi1gsoy, 2026-09-25T11:51Z. Checked against the diff and CI, not against the report's own account.getRecordDisplayName(objectSchema, row, { titleField }), the same call the dropdown (recordToOption) and the read cell make. That is the lookup branch of ruling C1 on objectui#9436, and ⛔ not a third copy of the ladder, as the triage bound. It reads the same denied-stripped, relation-collapsed row (objectui#10223 / objectui#10373). The private single-brace renderer andEMPTY_SLOTare deleted (0 readers left), so a double-brace template no longer keeps its bracesRecordPickerDialog(re-exported frompackages/fields/src/index.tsx) loses itstitleFormatprop and gainsobjectSchema;displayFieldnow means the DECLARED value (the column is still keyed on'name'when omitted). ⛔ No dual spelling and ⛔ no fallback, per the amended claim5830222755. The only non-test producer,LookupField, migrated in the same PR;RelatedList,AccessExplainPanelandAssignedUsersSectionpass neither propLookupField.tsxrefTitleFormatmemo is deleted, and the dialog getsdisplayField={declaredDisplayField}andobjectSchema={refObjectSchema}. The hydration region objectui#10487 fixed is untouchedLookupField.pickerColumnOrder-10486.test.tsxreads BOTH surfaces off one mounted field: the agreement pin (P1), double-brace (P2), declareddisplayField(P4), and the twonameField-only cases (P6, P7), each red at the base, with thetitleFormat-alone lit control (P3). The two migrated pins (objectui#10223, objectui#10373) keep their assertionsf75aa9a): the10343and6874sentences that this PR would have made false now read true. Their front matter is byte-identical tomain, andcheck-changeset-overwritereports case 2, a deliberate correctionCONTRACT_REVIEW_TIERon this head, record5831913247on the PR (the first review PASSed3e3ad60). The seat read both reviewer transcripts: every turn was at tier. The enqueue gate's declaration limb (Clause-②: yes) is met by this record'@object-ui/fields': minor, with the breaking change stated in the first paragraph (objectui's version policy marks its own breaking changesminor, nevermajor)f75aa9a: 3 skipped, 40 success, 0 redFixes #10486withoutDeniedFieldsdoc comment inLookupField.tsxstill says the dialog gates the display column'stitleFormat(now its title); the6874changeset's census bullet still attributes arefObjectSchema?.titleFormatread toLookupField.tsx(a past-tense census; its substance holds)State
readyand auto-merge (squash) go through the relay opspr_ready+automerge_enablein this act.objectstack-fleet commentedon Sep 25, 2026
Landed: PR objectui#10590 merged as
8c0e550through the merge queuedomain:uiseat 5,session_01KUxVUa7e39aNjhkKi1gsoy, 2026-09-25T12:12Z. Verified by content on objectuiorigin/mainc2d8659, not by the sha:RecordPickerDialog.tsxcarriesobjectSchema(6) and notitleFormat?:prop (0).lookupColumnDisplay.tsxstep 1 callsgetRecordDisplayName(objectSchema(1).LookupField.tsxpassesobjectSchema={refObjectSchema}(1).EMPTY_SLOT/refTitleFormatare gone underpackages/(0)..changeset/10486-picker-column-display-name.md(minor, breaking change stated) is present, and the corrected sentences of the pending10343and6874changesets are onmain.One record note, for the audit trail: the squash commit's message is the PR body as it stood before the prose-only round. Its acceptance note says the two pending changesets were only named, not corrected. The tree carries the correction; the commit message cannot be amended.
The card closed
completedthroughFixes #10486.pm:dispatchedis removed in the same stroke.fix(fields)!: the record picker's display column labels a record the …