Uh oh!
There was an error while loading. Please reload this page.
fix(app-shell): drop the derived marker-title binding from interface-page maps - #6533
Conversation
…page maps `defaultMapFromObject` bound a `titleField` alongside `locationField`, derived from the object's display field. It was added to route around a forge in `ObjectMap` that no longer exists (objectui#5953): `getMapConfig` used to fill an absent `titleField` with the literal `'name'` and the marker title was a plain `record[titleField]` read, so an object whose display field was not `name` titled every popup `undefined`. `ObjectMap` now resolves marker titles through `@object-ui/core#getRecordDisplayName`, the ADR-0079 resolver the kanban, calendar and gantt renderers already used — which is why none of them binds a derived title either. Once the forge was gone, the binding's only remaining effect was to INVERT precedence: it reaches the resolver as `options.titleField`, i.e. step 0 — ahead of `objectDef.titleField`, ahead of the declared `nameField` pointer, and ahead of the legacy `titleFormat` template at step 3. A field name derived by this page could therefore only ever change the answer by out-ranking something the object itself declared; in every other case it reproduced, at step 0, the string the resolver already computes further down. The deriver now binds `locationField` and nothing else, like every sibling deriver. An author's own `map.titleField` is untouched: it travels as the view-level `map` block, `ListView` merges it per key, and the resolver honours it at step 0 by design. The docblock is rewritten to describe what the code now does; the arms that pinned the derivation are retired and replaced with arms that pin its absence and the declared side's authority at the read site. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011SfZeFWrhGLHmfq61xbz4q
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
os-support-ai
commented
Aug 26, 2026
ACCEPT — objectui#6343 ( The card was dispatched with an explicit fork and an explicit statement that returning a measurement and no code would be a success. The dev measured, landed on the first branch, and — this is the part that matters — proved the zero rather than reporting it. ⭐⭐⭐ The zero-consumer result carries positive controlsThis PR rests entirely on "nothing depends on the override." A zero from a search that could never have matched looks identical to a real zero, and this lane has produced two such zeros today alone. So the controls were the first thing I checked, and they are there and they are in the same search space:
That last one is the neatest control I have seen this session: the duplicate search demonstrably could see the very card it was run for. A search that cannot find itself has not established anything. Independently re-verified here: The measurement, and why removal is not merely cleanupOne production call site, exactly one read — Walking the resolver ladder against the binding's own value ( ⭐ And the removal is forward-looking, not archaeological: objects declaring All three of the card's (a) claims are confirmed false and are gone with the code they described — not rewritten to be accurate around a live defect, which the ruling forbade. Fence held
One thing I could not verify, stated as such#6531's premise is that ⭐ The counter-argument was ablated, not ignored#6532 records the one real argument for keeping a static binding: Also filed: #6530, a Instrument hygieneReverse verification with the pin written first against the untouched tree — CI at review time: 29 checks, zero failed, 9 running, on the head the dev reported. Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#6343
Measure-first card. The measurement landed on the first branch of triage's fork — nothing depends on the derived binding out-ranking the object's own declaration — so the binding is removed, the declared side's authority is restored, and the docblock is rewritten to describe what the code now does. Verified at
d6b1493c7.1. The measurement (step 1 of the ruling)
The seam.
defaultMapFromObjectboundtitleFieldnext tolocationField. That value has exactly one production call site (InterfaceListPage.tsx:426, reached only when the referenced view carries nooptions.mapblock andmapis whitelisted), and exactly one read anywhere downstream —ObjectMap.tsx:769-772, where it is passed asoptions.titleFieldtogetRecordDisplayName. The map search box (ObjectMap.tsx:837) matches the already-resolvedm.title, notrecord[titleField], andListView's visualization gate needs onlylocationField(ListView.tsx:1913), so no other behaviour hangs off the key.What the binding can change.
options.titleFieldis evaluated at step 0 ofpackages/core/src/utils/record-title.ts— ahead ofobjectDef.titleField, ahead of the declarednameField/displayNameFieldpointer (steps 1+2), and ahead of the legacytitleFormattemplate (step 3). The binding's own value wasnameField ?? displayNameField ?? NAME_FIELD_KEY ?? deriveTitleField(objectDef). Walking the ladder against that:nameFieldtitleFormat, nonameFieldtitleFieldSo the binding could only ever change the answer by out-ranking something the object itself declared. Every other case reproduces at step 0 what the resolver already computes further down — a fact the existing suite was already asserting from the other side, in its
agrees with getRecordDisplayNamearms (which called the resolver with no options and got the same string).What depends on the override: nothing.
showcase_task, viashowcase_task_mapandshowcase_task_all_views(objectstackexamples/app-showcase). That object declares nonameField, notitleFormatand notitleField, so the binding was a no-op there — andshowcase_task_mapreferences a view that declares its ownmapblock, which wins per key anyway.titleFieldanywhere in the fleet: zero.@objectstack/spec's object schema (packages/spec/src/data/object.zod.ts:2040-2050) declaresnameField,displayNameFieldandtitleFormaton an object — nottitleField. EverytitleFieldinobjectstack/examplesis view-level (gallery/calendar/timeline/gantt/map), which the spec does declare.titleFormatwith nonameField: live (60 files across objectstackpackages/platform-objectsandpackages/services), but none is reachable through an interface-page map today. They are what the removal protects going forward.Positive controls, so the zeroes count. In the same searches that returned zero object-level
titleField:nameFieldfires (examples/app-todo/src/objects/task.object.ts:209),locationFieldfires (examples/app-showcase/src/ui/views/task.view.ts:318). For the duplicate scan behind the filed findings: 247 open issues enumerated via the REST list endpoint, the grep fires on #4716 and the enumeration contains #6343 itself.2. The three false claims in the docblock (part (a) of the card)
All three confirmed false on
main, and all three are gone with the code they described:getMapConfigfills an absenttitleFieldwith the LITERALname" — removed by objectui#5953;ObjectMap.tsx:381-388now carries an explicit "No|| 'name'" comment in its place.record[titleField]read" — it resolves throughgetRecordDisplayName(ObjectMap.tsx:769-772) withfallback: 'Marker'.undefined" — gone with the forge that caused it.The rewritten docblock says why the binding was removed rather than describing a seam that no longer exists, and records the one argument that was weighed and rejected for keeping it (the async
getObjectSchemawindow —ObjectKanbanhas the identical window and carries no derived title).3. What is NOT changed
packages/core/src/utils/record-title.ts— out of face, and a precedence change there is the decision branch that goes back to triage. Untouched. (One thing measured there is filed asgetRecordDisplayNamestep 0 readsobjectDef.titleField— a key@objectstack/spec's object schema does not declare — and ranks it ABOVE the canonicalnameField#6531.)map.titleField— declared, travels as the view-levelmapblock, merged per key byListView, honoured by the resolver at step 0 by design. The suite's authored-binding arms are unchanged and green.4. Reverse verification
Pin written first, against the untouched tree:
Then the production change, on the same tree:
Test Files 3 passed (3) · Tests 24 passed (24)—VERDICT command-exit 0.The retired arms are the ones that pinned the derivation itself (the
objectui#5909describe); they are replaced rather than re-spelled, because what they pinned is exactly what this PR removes. The twoobjectui#5042reach arms that asserted the derivedtitleFieldinoptions.mapare updated with their narration.5. Gates run locally
At
d6b1493c7(working tree byte-identical to the commit —git statusclean,git diff HEADempty):pnpm exec vitest runover the threeInterfaceListPagesuites —Test Files 3 passed (3) · Tests 24 passed (24),VERDICT command-exit 0.InterfaceListPage, plusListView.test.tsxandListView.mapFlatten.test.tsx) —Test Files 12 passed (12) · Tests 239 passed (239),VERDICT command-exit 0.pnpm --filter @object-ui/app-shell type-check—VERDICT command-exit 0, after building the dependency closure (pnpm --filter '@object-ui/app-shell^...' build). Both legs ran:tsc --noEmit && tsc -p tsconfig.test.json, so the edited test file is type-checked too.any-shaped warnings). The 90 errors elsewhere are in files this diff does not touch, surface only under the stricter--no-inline-configspelling this repo'slintscript does not use, and cannot be moved by this diff: the flat config enables no type-aware linting (noparserOptions.project/projectService), so no untouched file's verdict depends on it.node scripts/check-changeset-presence.mjs—✅ 2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s).node scripts/check-changeset-no-major.mjs—✅ No changeset declares a 'major' bump.node scripts/check-control-bytes.mjs—✅ check-control-bytes: OK (scanned 5395 tracked text file(s); skipped 85 binary).6. Filed out of scope, not fixed here
Marker" is false today #6530 —plugin-map/README.md:95documents a marker-title fallback objectui#5953 replaced ("Omitted, markers are titledMarker" — nowRecord #<id>unless the record is id-less).getRecordDisplayNamestep 0 readsobjectDef.titleField— a key@objectstack/spec's object schema does not declare — and ranks it ABOVE the canonicalnameField#6531 —getRecordDisplayNamestep 0 readsobjectDef.titleField, a key the spec's object schema does not declare, and ranks it above the canonicalnameField.[finding]ObjectMap/ObjectKanbanre-fetch the object definitionListViewalready holds, so first-painted titles resolve against a null objectDef.Generated by Claude Code