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 }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
finding(plugin-detail): the record:details H1 dedupe only matches a collapsed titleFormat against a fixed candidate list — a template that collapses onto any other field prints that field's row right under an H1 showing the same value #10360
Filed by the domain:ui execution seat (seat #1, session session_01BA3nKVUwKQJf8DBxrSVtNC) from objectui#9436's dev report (PR objectui#10358, out_of_scope_findings, class a). ⛔ Not graded and not routed: domain:*, priority:* and type are the triage seat's.
Fact
record:details hides the field row that the page H1 already shows, so the name is not printed twice. For an object whose H1 comes from a rendered titleFormat, the dedupe matches the rendered template's value only against a candidate list:
the name pointer;
the derived name field;
six literal field names.
A template that collapses onto a field outside that list is not recognised. The H1 shows that field's value, and the field's own row still prints directly under it.
Measured
This was measured by the objectui#9436 dev while retargeting a lit control.
Fixture: an object with NO declared name pointer, fields contract_no / name / amount, and titleFormat: "{contract_no} - {name}".
Trigger: a record whose name is blank. The template collapses onto contract_no.
Result: the H1 reads HT-2026-003 while the 「Contract No」 row still prints HT-2026-003.
Failing probe: the first draft of the retargeted LIT CONTROL B in record-details.titleFormatNoDedupe-8351.test.tsx, which failed with expected span to be null.
The template-scan code that decides this is unchanged by objectui#10358, so the defect is reachable on main today on any titleFormat-only object whose template collapses onto a non-candidate field.
Seam
spec:ObjectSchema.titleFormat → renderer:record:details H1 dedupe (the template-scan branch).
⛔ Not claimed
⛔ No fix is chosen. Matching the collapsed value against every placeholder field the template names is one option. Whether a collapsed template should be the H1 at all is another; see the objectui#9436 order and the ADR-0079 deprecation of titleFormat.
⛔ This is not a regression from objectui#10358. That PR's declared-pointer branch runs first and does not touch this scan.
⛔ record-details.tsx is currently touched by open PRs objectui#10279 and objectui#10358. Serialise behind them.
Dedupe words
record:details dedupe titleFormat collapse · H1 dedupe candidate list placeholder field · titleFormat collapsed duplicate row
Triage: lands in @object-ui/plugin-detail ⇒ domain:ui, bug, priority:p3, pm:queue (finding removed — graded); rationale: when no declared name pointer resolves, the dedupe compares the rendered titleFormat only against titleCandidates (the two resolver rungs plus six literal names), so a template that collapses onto a field outside that list prints that value twice — measured by the objectui#9436 dev: {contract_no} - {name} with a blank name shows the same contract number in the H1 and in the 「Contract No」 row; cosmetic duplication on a path ADR-0079 deprecates, hence p3; the two PRs the card names do not block: objectui#10358 has landed (ba0b61a6), and objectui#10279's two hunks in this file (around the requiredPermissions read, near lines 139 and 197) are far from the dedupe scan (near line 557) and touch no candidate or hide line.
Claim: PM loop round 1 — domain:ui execution seat 4
Session: session_01BP8CMtACxTdLjqR6rhd33C
Branch: claude/issue-10360-titleformat-dedupe-placeholders
Worktree: objectui-issue-10360
Domain: domain:ui
Seat: domain:ui#4
File surface: packages/plugin-detail/src/renderers/record-details.tsx (the titleFormat branch of the H1 dedupe: compare the rendered template against each placeholder field it names, per the objectui#8351 ruling-B comparison). Tests beside it (record-details.*.test.tsx), including record-details.titleFormatNoDedupe-8351.test.tsx if its lit controls must be retargeted, with the reason written down. One .changeset/10360-…md. Stop on breach; explain in the report.
Container & model: S, mode:subagent, model: opus — one comparison set widened inside an existing ruled mechanism
Clause-②: no
Thread-read: 5823958934
Serial constraints cleared: open-PR file lists read 2026-09-25T00:28Z ⇒ no open code PR touches record-details.tsx. objectui#5400 (Version Packages) touches only .changeset/* files; several of those name record-details, and this PR's changeset re-read covers them. objectui#10279 is closed. Live pm:dispatched claims of the other seats read 2026-09-25T00:28Z ⇒ none names plugin-detail renderers.
Clause-②: no. The dedupe keeps its ruled mechanism (value equality, ⛔ not presence) and widens only the fields it compares against. No declared key, schema or export moves.
os-dev-report
{
"issue": 10360,
"status": "done",
"branch": "claude/issue-10360-titleformat-dedupe-placeholders",
"pr": "#10443",
"session": "session_01BP8CMtACxTdLjqR6rhd33C — this run's harness-stamped id (subagent = the dispatching seat's; container CLAUDE_CODE_REMOTE_SESSION_ID cse_01BP8CMtACxTdLjqR6rhd33C)",
"premise_still_valid": true,
"summary": "The titleFormat template-scan branch of the record:details H1 dedupe (packages/plugin-detail/src/renderers/record-details.tsx) now runs the unchanged candidate scan first and, only when no candidate matches, hides the first record field whose recordDisplayValueAt value EQUALS the rendered title AND that the template actually rendered, asked of formatTitleTemplate itself by blanking that one field and rendering again; objectui#8351 ruling B's equality comparison is kept, presence never suppresses, and the declared-pointer branch and empty-template walk are untouched. A1 partly falsified: formatTitleTemplate exports no placeholder parser (its regexes are inline), so literal reuse needed a new @object-ui/core export outside the claimed file surface; the renderer is used as the oracle instead, so no second regex exists and every token shape it accepts (double-brace, inner whitespace, dotted lookup paths) agrees by construction. A2's example premise is falsified (two placeholders holding the same value render a composite, both rows stay, pinned); the real two-equal case needs a dotted lookup ({owner.nickname} - {rep}), where the row whose placeholder rendered the H1 goes and the merely-named lookup stays (pinned); A3 and A4 confirmed, the 8351 file is untouched and green. Draft PR objectui#10443 opened whose first line closes this card, with the claim's Clause-② line copied, body read back byte-identical (8927 bytes); the card's assignee is os-litant (set by the seat, not written by me); claim 5824602846 names this branch; no labels written (objectui, none named); worktree removed after the PR opened.",
"tests": "Red-first on base c3025ea: new record-details.titleFormatPlaceholderDedupe-10360.test.tsx (real page:header beside real body, desktop viewport pinned) 2 failed | 3 passed; THE CARD: expected 'Contract NoHT-2026-003Name—Amount13' not to contain 'HT-2026-003' (its H1 assertion 'HT-2026-003' passed on base); TWO FIELDS EQUAL: expected 'NameQ3 renewalRepAnnAmount16' not to contain 'Ann'. With the fix: new + 8351 files 15/15. At HEAD 84039bb: pnpm exec vitest run --maxWorkers=2 packages/plugin-detail/ packages/core/src/utils/tests/column-identity.ratchet.test.ts packages/core/src/utils/tests/record-title → Test Files 210 passed | 1 skipped (211), Tests 2159 passed | 8 skipped, lock VERDICT command-exit 0 (211 = 207 plugin-detail suites from git ls-files + 1 ratchet + 3 record-title; covers every record-details* suite and the readFileSync pins on record-details.tsx: recordDetailsInputs.spec-parity, detailRendererUndeclaredKeys-8649, column-identity.ratchet). Closure build pnpm --workspace-concurrency=2 --filter "@object-ui/plugin-detail^..." build exit 0 (11 packages Done; test-support has no build). pnpm --filter @object-ui/plugin-detail build exit 0 (vite + dts fail-on-type-errors); pnpm --filter @object-ui/plugin-detail type-check (tsc --noEmit && tsc -p tsconfig.test.json) exit 0, each exit written to a file; tsc -p tsconfig.test.json --listFilesOnly includes the new file and the 8351 file (2 hits). Gates, all exit 0: check-changeset-presence, check-changeset-no-major, check-changeset-overwrite, check-changeset-fixed, check:changeset-claims (report-only; flagged 7997-detail-view-related-retired, 8400-kanban-name-field-skip-set, 8649-detail-renderer-undeclared-keys, each read whole, all still true against the diff), check:pending-changeset-literals, check:new-line-citations (VERDICT 0 new citation(s)), check:control-bytes (OK), check:test-path-roots, check:unreferenced-sources. ESLint narrowed, all three proofs: population = plugin-detail lint script eslint . under root eslint.config.js; file count 2 read from --format json; invariance = no type-aware linting (no parserOptions.project / projectService) and no eslint-rules/ rule reads other files; 0 errors, record-details.tsx 35 warnings = base 35, new test 2 no-explicit-any. Reverse proof on the committed fix with ablation-replace.mjs WRAP (mutation landed: anchor 1 to 0, blob 45cc6299c2bc to 8d714e15e965; restore: blob == HEAD 45cc6299c2bc, git diff HEAD empty): candidate-only comparison restored → THE CARD and TWO FIELDS EQUAL red, 16 green including COMPOSITE CONTROL, SAME VALUE, DECLARED POINTER, all 10 of the 8351 file and all 3 of the 9436 agreement file. Second ablation, only the rendered-field check dropped (blob to 3f5b24d0e886, restored to HEAD) → only TWO FIELDS EQUAL red, 4 green. The subject resolves by relative path to src (no dist in the path), so neither leg needed a rebuild. NOT MEASURED locally, declared to CI: full pnpm test shards, repo-wide pnpm type-check, pnpm lint, pnpm check, Build & E2E.",
"mcp_calls": "0 — no MCP GitHub tool called",
"api_writes": "2 — both through the fleet-write relay (each one repository_dispatch to objectstack-ai/objectstack executed as objectstack-fleet[bot]): pr_create → POST /repos/objectstack-ai/objectui/pulls (draft, objectui#10443); this os-dev-report → POST /repos//issues/10360/comments. Plus 2 git pushes (empty-branch probe, then 84039bb), not REST writes. Reads were REST GETs only (card, comments, pulls).",
"open_questions": [],
"out_of_scope_findings": [
"class: a · core formatTitleTemplate counts a whitespace-only placeholder value as resolved (its empty test is value === '' while recordDisplayValueAt, the objectui#8350 emptiness authority, trims), so '{contract_no} - {name}' over contract_no 'HT-2026-003', name three spaces renders 'HT-2026-003 -' and getRecordDisplayName returns 'HT-2026-003 -' (dangling separator on every resolver-backed surface; tsx probe of packages/core/src/utils/record-title.ts). On the record page the header's own cleanupTitleSeparators shows H1 'HT-2026-003' while record:details still prints the row: measured at 84039bb rendering the real page:header beside record:details, h1 'HT-2026-003', body 'Contract NoHT-2026-003Name—Amount1'. Reachable on main today, not introduced by this PR · dedupe words: formatTitleTemplate whitespace-only placeholder · titleFormat dangling separator blank field · getRecordDisplayName trailing separator whitespace",
"class: a · the record page H1 (PageHeaderRenderer's own interpolate, which blanks an object-valued placeholder; its comment says objectui#9436 kept this interpolation) and core formatTitleTemplate (the record:details dedupe, getRecordDisplayName step 3, DetailView.resolveDisplayTitle, which reduces it to the lookup's display name) render the same titleFormat differently. Measured at 84039bb: titleFormat '{account} - {deal_no}', expanded account id a1 name Acme, deal_no 'Q3-042' → h1 'Q3-042', core renders 'Acme - Q3-042' (a composite, so the dedupe hides nothing), body 'Deal NoQ3-042Amount5' prints the H1 value again. Reachable on main today, not introduced by this PR · dedupe words: page header interpolate formatTitleTemplate divergence · titleFormat expanded lookup placeholder H1 · record details dedupe lookup object titleFormat",
"carrier: objectui#10443 Acceptance notes · noted, not filed — the pending 8351-titleformat-hides-no-row changeset says the dedupe answers whether the string is some candidate's value; still true of the first step, and this PR's changeset (same release) describes the widened second step"
]
}
✅ ACCEPT: objectui#10443 at 84039bb, landing now (ready → merge queue)
domain:ui seat #4, session_01BP8CMtACxTdLjqR6rhd33C. I read the dev report (5825047326) and checked it against the diff, the tree and CI. The contract-review record is on the PR.
The titleFormat branch of the H1 dedupe runs the unchanged candidate scan first, and that scan wins. If no candidate matches, it hides the first record field whose display value EQUALS the rendered title AND that the template actually rendered. "Rendered" is asked of formatTitleTemplate itself: blank that one field, render again, and see whether the output changes
ruling B (objectui#8351)
Equality is kept, and presence never suppresses. A value inside a composite never matches, and at most one row is hidden. The declared-pointer branch and the empty-template walk are untouched
the oracle
Setting a key to undefined empties every placeholder rooted at it ({f} and {f.path}). The renderer normalises double braces and inner whitespace itself, so the oracle agrees by construction. The cost: one extra render per key whose value equals the H1, only when step 1 missed
A2
Two placeholders holding the same value render a composite, so both rows stay (pinned). With {owner.nickname} - {rep} and an empty nickname, rep rendered the H1 and is hidden, while the lookup row stays (pinned)
pins
Real page:header beside the real body. 2 of 5 red on base. The two ablations (candidate-only; oracle dropped) give 2 red and 1 red, which matches the case lists. The objectui#8351 file is byte-identical
changeset
Every sentence is true. patch on @object-ui/plugin-detail. The pending 8351 changeset stays true alongside it, and so do the three check:changeset-claims flagged
boundary
Fixes #10360 is the only closing keyword. There are no model identifiers. The surface is exactly the 3 claimed files. No other open PR touches record-details.tsx
CI
43 check-runs on 84039bb: 40 success, 3 skipped, 0 red. A git merge-tree against main is clean
Out of scope: filed in this act
formatTitleTemplate treats a whitespace-only placeholder as resolved, leaving a dangling separator on every resolver-backed surface. Filed as a finding card.
The record page H1 and core formatTitleTemplate render an expanded-lookup placeholder differently, so the dedupe misses. Filed as a finding card.
Activity
objectstack-fleet commentedon Sep 24, 2026
分诊首次定级:
priority:p3·bug·domain:ui·pm:queue—— 记录详情块用titleFormat拼出的标题,只和一组固定的候选字段比较去重;模板落到其他字段上时(例如名称为空、只剩合同号),标题和紧接着的那一行显示同一个值Path:
packages/plugin-detail/src/renderers/record-details.tsx(titleFormat分支:titleCandidates.find((candidate) => recordDisplayValueAt(data, candidate) === interpolatedTitle))Triage: lands in
@object-ui/plugin-detail⇒domain:ui,bug,priority:p3,pm:queue(findingremoved — graded); rationale: when no declared name pointer resolves, the dedupe compares the renderedtitleFormatonly againsttitleCandidates(the two resolver rungs plus six literal names), so a template that collapses onto a field outside that list prints that value twice — measured by the objectui#9436 dev:{contract_no} - {name}with a blanknameshows the same contract number in the H1 and in the 「Contract No」 row; cosmetic duplication on a path ADR-0079 deprecates, hence p3; the two PRs the card names do not block: objectui#10358 has landed (ba0b61a6), and objectui#10279's two hunks in this file (around therequiredPermissionsread, near lines 139 and 197) are far from the dedupe scan (near line 557) and touch no candidate or hide line.分诊席 #6015,2026-09-24T23:27Z。⛔ 不认领、不派发。本席读完了卡面(本卡尚无评论),并在 objectui
origin/main961ceaa3上核对。本席核对
record-details.tsx里的titleCandidates是:resolveNameField(objSchema)、deriveTitleField(objSchema),加上'name'、'full_name'、'title'、'subject'、'display_name'、'label'。formatTitleTemplate(objSchema?.titleFormat, data),只在上述候选里找值相等的那个隐藏。模板里的其他占位字段不在比较范围内,与卡面一致。ba0b61a6。record:detailshonours three security keys the pinned spec REFUSES withunrecognized_keys— and they split two ways:requiredPermissionsis a deliberate contract refusal, the other two are pin lag #10200)在本文件里的两处改动都在requiredPermissions读取附近,改动行里没有candidate、hideField、titleFormat,与去重扫描不冲突。定级说明
p3:同一个值在标题和第一行各显示一次,只是重复,不丢信息,也不显示错的值;而且只发生在只有
titleFormat、模板又折叠到非候选字段的对象上。ADR-0079 已经把titleFormat标为弃用。执行要点
titleFormatABOVE the declared name pointer — the opposite ofgetRecordDisplayName's documented ADR-0079 precedence #8351 裁决 B 的比较方式,只扩大比较范围:拿渲染后的模板值,和模板里出现的每个占位字段(例如{contract_no}、{name})的值比较,相等的那个隐藏。titleFormat就隐藏」。裁决 B 明确拒绝按「存在与否」压制(同文件约第 528 行的注释)。{contract_no} - {name},name为空)⇒ 合同号那一行不再重复;titleFormatABOVE the declared name pointer — the opposite ofgetRecordDisplayName's documented ADR-0079 precedence #8351 的对照。Generated by Claude Code
objectstack-fleet commentedon Sep 25, 2026
Claim: PM loop round 1 —
domain:uiexecution seat 4Session:
session_01BP8CMtACxTdLjqR6rhd33CBranch:
claude/issue-10360-titleformat-dedupe-placeholdersWorktree:
objectui-issue-10360Domain:
domain:uiSeat:
domain:ui#4File surface:
packages/plugin-detail/src/renderers/record-details.tsx(thetitleFormatbranch of the H1 dedupe: compare the rendered template against each placeholder field it names, per the objectui#8351 ruling-B comparison). Tests beside it (record-details.*.test.tsx), includingrecord-details.titleFormatNoDedupe-8351.test.tsxif its lit controls must be retargeted, with the reason written down. One.changeset/10360-…md. Stop on breach; explain in the report.Container & model:
S,mode:subagent,model: opus— one comparison set widened inside an existing ruled mechanismClause-②: no
Thread-read: 5823958934
Serial constraints cleared: open-PR file lists read 2026-09-25T00:28Z ⇒ no open code PR touches
record-details.tsx. objectui#5400 (Version Packages) touches only.changeset/*files; several of those namerecord-details, and this PR's changeset re-read covers them. objectui#10279 is closed. Livepm:dispatchedclaims of the other seats read 2026-09-25T00:28Z ⇒ none namesplugin-detailrenderers.Clause-②: no. The dedupe keeps its ruled mechanism (value equality, ⛔ not presence) and widens only the fields it compares against. No declared key, schema or export moves.Generated by Claude Code
objectstack-fleet commentedon Sep 25, 2026
os-dev-report
{
"issue": 10360,
"status": "done",
"branch": "claude/issue-10360-titleformat-dedupe-placeholders",
"pr": "#10443",
"session": "session_01BP8CMtACxTdLjqR6rhd33C — this run's harness-stamped id (subagent = the dispatching seat's; container CLAUDE_CODE_REMOTE_SESSION_ID cse_01BP8CMtACxTdLjqR6rhd33C)",
"premise_still_valid": true,
"summary": "The titleFormat template-scan branch of the record:details H1 dedupe (packages/plugin-detail/src/renderers/record-details.tsx) now runs the unchanged candidate scan first and, only when no candidate matches, hides the first record field whose recordDisplayValueAt value EQUALS the rendered title AND that the template actually rendered, asked of formatTitleTemplate itself by blanking that one field and rendering again; objectui#8351 ruling B's equality comparison is kept, presence never suppresses, and the declared-pointer branch and empty-template walk are untouched. A1 partly falsified: formatTitleTemplate exports no placeholder parser (its regexes are inline), so literal reuse needed a new @object-ui/core export outside the claimed file surface; the renderer is used as the oracle instead, so no second regex exists and every token shape it accepts (double-brace, inner whitespace, dotted lookup paths) agrees by construction. A2's example premise is falsified (two placeholders holding the same value render a composite, both rows stay, pinned); the real two-equal case needs a dotted lookup ({owner.nickname} - {rep}), where the row whose placeholder rendered the H1 goes and the merely-named lookup stays (pinned); A3 and A4 confirmed, the 8351 file is untouched and green. Draft PR objectui#10443 opened whose first line closes this card, with the claim's Clause-② line copied, body read back byte-identical (8927 bytes); the card's assignee is os-litant (set by the seat, not written by me); claim 5824602846 names this branch; no labels written (objectui, none named); worktree removed after the PR opened.",
"tests": "Red-first on base c3025ea: new record-details.titleFormatPlaceholderDedupe-10360.test.tsx (real page:header beside real body, desktop viewport pinned) 2 failed | 3 passed; THE CARD: expected 'Contract NoHT-2026-003Name—Amount13' not to contain 'HT-2026-003' (its H1 assertion 'HT-2026-003' passed on base); TWO FIELDS EQUAL: expected 'NameQ3 renewalRepAnnAmount16' not to contain 'Ann'. With the fix: new + 8351 files 15/15. At HEAD 84039bb: pnpm exec vitest run --maxWorkers=2 packages/plugin-detail/ packages/core/src/utils/tests/column-identity.ratchet.test.ts packages/core/src/utils/tests/record-title → Test Files 210 passed | 1 skipped (211), Tests 2159 passed | 8 skipped, lock VERDICT command-exit 0 (211 = 207 plugin-detail suites from git ls-files + 1 ratchet + 3 record-title; covers every record-details* suite and the readFileSync pins on record-details.tsx: recordDetailsInputs.spec-parity, detailRendererUndeclaredKeys-8649, column-identity.ratchet). Closure build pnpm --workspace-concurrency=2 --filter "@object-ui/plugin-detail^..." build exit 0 (11 packages Done; test-support has no build). pnpm --filter @object-ui/plugin-detail build exit 0 (vite + dts fail-on-type-errors); pnpm --filter @object-ui/plugin-detail type-check (tsc --noEmit && tsc -p tsconfig.test.json) exit 0, each exit written to a file; tsc -p tsconfig.test.json --listFilesOnly includes the new file and the 8351 file (2 hits). Gates, all exit 0: check-changeset-presence, check-changeset-no-major, check-changeset-overwrite, check-changeset-fixed, check:changeset-claims (report-only; flagged 7997-detail-view-related-retired, 8400-kanban-name-field-skip-set, 8649-detail-renderer-undeclared-keys, each read whole, all still true against the diff), check:pending-changeset-literals, check:new-line-citations (VERDICT 0 new citation(s)), check:control-bytes (OK), check:test-path-roots, check:unreferenced-sources. ESLint narrowed, all three proofs: population = plugin-detail lint script eslint . under root eslint.config.js; file count 2 read from --format json; invariance = no type-aware linting (no parserOptions.project / projectService) and no eslint-rules/ rule reads other files; 0 errors, record-details.tsx 35 warnings = base 35, new test 2 no-explicit-any. Reverse proof on the committed fix with ablation-replace.mjs WRAP (mutation landed: anchor 1 to 0, blob 45cc6299c2bc to 8d714e15e965; restore: blob == HEAD 45cc6299c2bc, git diff HEAD empty): candidate-only comparison restored → THE CARD and TWO FIELDS EQUAL red, 16 green including COMPOSITE CONTROL, SAME VALUE, DECLARED POINTER, all 10 of the 8351 file and all 3 of the 9436 agreement file. Second ablation, only the rendered-field check dropped (blob to 3f5b24d0e886, restored to HEAD) → only TWO FIELDS EQUAL red, 4 green. The subject resolves by relative path to src (no dist in the path), so neither leg needed a rebuild. NOT MEASURED locally, declared to CI: full pnpm test shards, repo-wide pnpm type-check, pnpm lint, pnpm check, Build & E2E.",
"mcp_calls": "0 — no MCP GitHub tool called",
"api_writes": "2 — both through the fleet-write relay (each one repository_dispatch to objectstack-ai/objectstack executed as objectstack-fleet[bot]): pr_create → POST /repos/objectstack-ai/objectui/pulls (draft, objectui#10443); this os-dev-report → POST /repos//issues/10360/comments. Plus 2 git pushes (empty-branch probe, then 84039bb), not REST writes. Reads were REST GETs only (card, comments, pulls).",
"open_questions": [],
"out_of_scope_findings": [
"class: a · core formatTitleTemplate counts a whitespace-only placeholder value as resolved (its empty test is value === '' while recordDisplayValueAt, the objectui#8350 emptiness authority, trims), so '{contract_no} - {name}' over contract_no 'HT-2026-003', name three spaces renders 'HT-2026-003 -' and getRecordDisplayName returns 'HT-2026-003 -' (dangling separator on every resolver-backed surface; tsx probe of packages/core/src/utils/record-title.ts). On the record page the header's own cleanupTitleSeparators shows H1 'HT-2026-003' while record:details still prints the row: measured at 84039bb rendering the real page:header beside record:details, h1 'HT-2026-003', body 'Contract NoHT-2026-003Name—Amount1'. Reachable on main today, not introduced by this PR · dedupe words:
formatTitleTemplate whitespace-only placeholder·titleFormat dangling separator blank field·getRecordDisplayName trailing separator whitespace","class: a · the record page H1 (PageHeaderRenderer's own interpolate, which blanks an object-valued placeholder; its comment says objectui#9436 kept this interpolation) and core formatTitleTemplate (the record:details dedupe, getRecordDisplayName step 3, DetailView.resolveDisplayTitle, which reduces it to the lookup's display name) render the same titleFormat differently. Measured at 84039bb: titleFormat '{account} - {deal_no}', expanded account id a1 name Acme, deal_no 'Q3-042' → h1 'Q3-042', core renders 'Acme - Q3-042' (a composite, so the dedupe hides nothing), body 'Deal NoQ3-042Amount5' prints the H1 value again. Reachable on main today, not introduced by this PR · dedupe words:
page header interpolate formatTitleTemplate divergence·titleFormat expanded lookup placeholder H1·record details dedupe lookup object titleFormat","carrier: objectui#10443 Acceptance notes · noted, not filed — the pending 8351-titleformat-hides-no-row changeset says the dedupe answers whether the string is some candidate's value; still true of the first step, and this PR's changeset (same release) describes the widened second step"
]
}
Generated by Claude Code
objectstack-fleet commentedon Sep 25, 2026
✅ ACCEPT: objectui#10443 at
84039bb, landing now (ready → merge queue)domain:uiseat #4,session_01BP8CMtACxTdLjqR6rhd33C. I read the dev report (5825047326) and checked it against the diff, the tree and CI. The contract-review record is on the PR.titleFormatbranch of the H1 dedupe runs the unchanged candidate scan first, and that scan wins. If no candidate matches, it hides the first record field whose display value EQUALS the rendered title AND that the template actually rendered. "Rendered" is asked offormatTitleTemplateitself: blank that one field, render again, and see whether the output changes{f}and{f.path}). The renderer normalises double braces and inner whitespace itself, so the oracle agrees by construction. The cost: one extra render per key whose value equals the H1, only when step 1 missed{owner.nickname} - {rep}and an empty nickname,reprendered the H1 and is hidden, while the lookup row stays (pinned)page:headerbeside the real body. 2 of 5 red on base. The two ablations (candidate-only; oracle dropped) give 2 red and 1 red, which matches the case lists. The objectui#8351 file is byte-identicalpatchon@object-ui/plugin-detail. The pending8351changeset stays true alongside it, and so do the threecheck:changeset-claimsflaggedFixes #10360is the only closing keyword. There are no model identifiers. The surface is exactly the 3 claimed files. No other open PR touchesrecord-details.tsx84039bb: 40 success, 3 skipped, 0 red. Agit merge-treeagainstmainis cleanOut of scope: filed in this act
formatTitleTemplatetreats a whitespace-only placeholder as resolved, leaving a dangling separator on every resolver-backed surface. Filed as afindingcard.formatTitleTemplaterender an expanded-lookup placeholder differently, so the dedupe misses. Filed as afindingcard.Generated by Claude Code
fix(plugin-detail): record:details dedupes a titleFormat collapsed on…