Skip to content

fix(metadata-protocol): title global-search hits from the canonical nameField, not only the deprecated alias - #8809

Merged
hotlong merged 2 commits into
mainfrom
claude/issue-8786-searchall-title-namefield
Aug 15, 2026
Merged

fix(metadata-protocol): title global-search hits from the canonical nameField, not only the deprecated alias#8809
hotlong merged 2 commits into
mainfrom
claude/issue-8786-searchall-title-namefield

Conversation

@hotlong

Copy link
Copy Markdown
Contributor

Fixes#8786

searchAll — the global-search (⌘K) palette — resolved a hit's title from a candidate list that opened with obj.displayNameFieldalone. Under ADR-0079 nameField is the canonical primary-title pointer and displayNameField is the deprecated alias, so this was the one consumer a canonical designation could not reach.

Why it was reachable, not theoretical

provisionPrimary — the ADR-0079 designation seat the SchemaRegistry runs on every object at registration — stamps nameFieldonly, never the alias:

packages/spec/src/data/display-name.ts:301 return { ...objectMeta, nameField: resolved };
packages/spec/src/data/display-name.ts:314 return { ...objectMeta, fields, nameField: 'name' };

So an object that declared its primary title canonically, without also carrying the deprecated alias, produced undefined for that entry, the entry was filtered out of the candidate list, and the title fell through to return String(row.id) — the palette showing a raw record id where the object's own declared, populated title existed.

Impact was bounded to objects whose primary title is outsidename / full_name / title / subject / label / company; anything in that conventional list already resolved through the later entries, which is why this stayed invisible.

The change

One line, plus the doc comment directly above it that described the old order:

- obj.displayNameField,
+ obj.nameField ?? obj.displayNameField,

That is the spelling the rest of the platform already uses — resolveDisplayField in @objectstack/spec, the #4254 ingress gate, and this same function's own search-field resolution 44 lines below (displayField: obj.nameField ?? obj.displayNameField). A fourth spelling here would have re-split what those merged.

Precedence, measured rather than assumed

If an object carries both pointers naming different fields, this flips which one wins — so I measured the repo before calling it safe. Scanning every displayNameField declaration in packages, examples and apps (52 files, 38 declarations with a co-located nameField):

  • 33 agree exactly — every real object carrying both spells them identically, under an [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField) comment.
  • 5 disagree, and all five are test fixtures that exist precisely to pin precedence — and every one of them already pins nameField as the winner. resolveDisplayField({ nameField: 'a', displayNameField: 'b' }) returns 'a', pinned in display-name.test.ts as "prefers nameField over displayNameField over derivation".

No real object is in the disagreeing state, and the precedence landed on is the platform's existing answer rather than a new one. It is now pinned here too.

Tests

New file packages/metadata-protocol/src/protocol.search-title-namefield.test.ts — 6 cases. The fixtures use non-conventional title fields (company_name, ref_no, ref_code), since a conventional one would pass identically before and after.

  • the pinnameField: 'company_name', no alias, populated row, title is Acme Industrial and not acc_1;
  • control — an object using a conventional name, with no pointer at all, still titles correctly (a short-circuit rewrite would pass the pin and break this);
  • control — an empty pointer value falls through to the conventional entry, proving the pointer is a candidate in one ordered list, not a short-circuit return;
  • the deprecated alias on its own is still honored (deprecated, not withdrawn);
  • both pointers naming different fields: nameField wins;
  • titleFormat still outranks the pointer.

Reverse verification, direction predicted before running and observed as predicted: restoring obj.displayNameField, alone turns exactly 2 of 6 red, with the defect's own signature —

× titles from a canonically-designated nameField with no displayNameField
→ expected 'acc_1' to be 'Acme Industrial'
× prefers nameField when an object carries BOTH pointers naming different fields
→ expected 'OLD-11' to be 'TK-77'
Tests 2 failed | 4 passed (6)

The 4 that stay green are the controls, which by design do not discriminate this fix. The fix was committed before the ablation and restored with git checkout from that commit (git status clean afterwards).

Verification

All at HEAD cd974da6e (after the merge of origin/main, which is the final commit):

  • pnpm --filter @objectstack/metadata-protocol test92 files, 1375 tests, all passing
  • gate union re-derived against the actual changed paths with node scripts/pm/dispatch-gates.mjs, all green: check:nul-bytes, check:cross-package-test-inputs, check:durability-log-level, check:filter-alias-parity, check:changeset-gate-self-tests, check:objectui-changeset, check:query-options-erasure, check:engine-double-contract, check:type-check-coverage, check:type-check-debt
  • the re-derivation surfaced four families the dispatch prompt's list did not name (the three .changeset families plus check:query-options-erasure / the type-check pair, triggered by adding a test file). check:type-check-debt --re-measure was run over the built workspace closure — @objectstack/metadata-protocol sits in the DEBT ledger, so a new test file genuinely moves it: "33 ledger entries re-measured, 1926 raw tsc errors total, none above its recorded number."

Scope

Presentation only. #7643 addressed recall (which rows come back) and deliberately left titling alone; that contract stays untouched here, and its pins in protocol.search-case-fold.test.ts still pass. Search-field resolution, the object sweep, caps and ordering are unmodified. Region held: renderTitle inside searchAll. No other region of protocol.ts was touched, so the concurrent work in auditMetaItem and diffMetaItem is unaffected.


Generated by Claude Code

…8786)
`searchAll`'s `renderTitle` opened its candidate list with
`obj.displayNameField` alone — the ADR-0079 DEPRECATED alias. The canonical
pointer is `nameField`, and `provisionPrimary` (the designation seat the
SchemaRegistry runs on every object at registration) stamps `nameField` only,
never the alias. So an object that declared its primary title canonically fell
through the candidate list to `String(row.id)` and the palette showed a raw id.
Reads `obj.nameField ?? obj.displayNameField` instead — the spelling
`resolveDisplayField`, the #4254 ingress gate, and this same function's
search-field resolution 44 lines below already use.
Presentation only: #7643's recall half is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeQRiAa7vYRVX5Fog7Zby8
@vercel

vercelBot commented Aug 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 15, 2026 3:47am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/metadata-protocol.

3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx(via @objectstack/metadata-protocol)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/metadata-protocol)
  • content/docs/protocol/kernel/http-protocol.mdx(via @objectstack/metadata-protocol)

1 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/v9.mdx(via @objectstack/metadata-protocol)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling labels Aug 15, 2026
@hotlong
hotlong marked this pull request as ready for review August 15, 2026 04:05
@hotlong
hotlong added this pull request to the merge queueAug 15, 2026
Merged via the queue into main with commit add2d19Aug 15, 2026
27 checks passed
@hotlong
hotlong deleted the claude/issue-8786-searchall-title-namefield branch August 15, 2026 04:21
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

searchAll's title rendering reads only the deprecated displayNameField, so a canonically-designated primary title never titles a ⌘K hit

2 participants

@hotlong@claude