Repository navigation
fix(metadata-protocol): the search palette titles a hit by nameField before the deprecated titleFormat - #24202
Conversation
…e deprecated titleFormat ADR-0079 D3 and the spec's titleFormat describe give an explicit nameField precedence; renderTitle rendered the template first. Claude-Session: https://claude.ai/code/session_014pQA9SjSrUuG8NSnD7xyYH Co-authored-by: Claude <noreply@anthropic.com>
…nnable Claude-Session: https://claude.ai/code/session_014pQA9SjSrUuG8NSnD7xyYH Co-authored-by: Claude <noreply@anthropic.com>
…ormat Claude-Session: https://claude.ai/code/session_014pQA9SjSrUuG8NSnD7xyYH Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014pQA9SjSrUuG8NSnD7xyYH Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 2 package(s): ⛔ 1 release-owned page(s) name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 144 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 35faf20e10e6987737946b58ce2756e3bc0610b4 && git checkout 35faf20e10e6987737946b58ce2756e3bc0610b4
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8a88901be1c317e2e078e6d29f21efcae5b9485e a8fe932ef92d227f881c051a17a3916e2abf0545 && git checkout -B drift-repro 8a88901be1c317e2e078e6d29f21efcae5b9485e && git merge --no-ff a8fe932ef92d227f881c051a17a3916e2abf0545
node scripts/docs-audit/affected-docs.mjs --json 8a88901be1c317e2e078e6d29f21efcae5b9485e
|
Contract reviewServed-tier: Scope note: the schema face is ① Derived judgments
② Semver levelRIGHT: ③ Boundary flagsEvery
Implemented-by: VERDICT: PASS Generated by Claude Code |
席位核对 ·
|
| Item | Reading |
|---|---|
| Shape | Draft PR → main. The body opens Fixes #24087, its only closing keyword (full-body scan). |
| Scope | 5 files (+153 / −38): searchAll's renderTitle and its comment in packages/metadata-protocol/src/protocol.ts, its pin, the changeset, and the SearchAllHitSchema.title describe in packages/spec/src/api/protocol.zod.ts with its two generated mdx rows. The spec hunk is os-dev's bounded in-place fix (a shipped sentence this change made false). The claim is re-declared with it (6238219129), and it is declared to domain:spec on #6017. Not governed (check-governed-merges.mjs --pr 24202); 191 lines. |
| Premise and ruling | Done-when arm 1 as dispatched: the pointer, then titleFormat, then the fallbacks. H1 measured: a provisioned nameField cannot be told from an authored one after the registry's stamp, so the reader mirrors resolveDisplayField. |
| Contract review | CONTRACT_REVIEW_TIER, an isolated reviewer: record 6238191743, PASS on this head (schema face). The seat re-measured its reach count before adopting it: 65 *.object.ts files declare titleFormat, and 5 of them have no nameField. |
| Prose faces | Changeset and mdx, sentence by sentence. GET /api/v1/search is the route (rest-route-ledger.ts). os explain title-format-retired exists (packages/lint rule explanations). The order sentence matches the code. The mdx rows are byte-equal to the new describe. |
| Pins and ablation | 4 pins through the real provisionPrimary. One ablation (template-first restored) turns exactly the 2 predicted pins red; the restore is clean. The double is the file's boundary stand-in, because of the objectql package cycle. |
Clause-② |
no, at a line start in the PR body and the changeset. patch for @objectstack/metadata-protocol and @objectstack/spec. |
| Gates | Dev union: 111 derived, 110 run, 1 NOT MEASURED (check:dual-build-cjs-loads, which CI hosts). CI on this head: 41 check-runs, 36 success, 5 skipped, 0 failed. Every skip is rostered in EXPECTED_SKIPS: Console Pin Gate, Dogfood Verify CLI, Temporal Conformance, the Dogfood matrix template, Packed-tarball smoke. |
Disposition:
open_questions[0](H1): A, as landed. Governing text: ADR-0079 D3/D4; the key is deprecated and lint-warned.out_of_scope_findings[0](the objectui display-name chain readingtitleFormatfirst): dropped — measured false. At objectuiorigin/main285ddb2,packages/core/src/utils/record-title.tsordersnameField→displayNameField→titleFormat, andcontainers.tsxsays the declared pointer outrankstitleFormat(objectui#9436, ruled C1). The residue is two stale JSDoc blocks inpackages/spec/src/ui/view.zod.ts. They are below the filing gate and were handed todomain:specseat 1 as pointer 6237975441.out_of_scope_findings[1](the real-engine palette pin's home inpackages/objectql): Acceptance notes,carrier: none.- Reviewer item 8: three first-party
titleFormat-only objects in the palette (sys_attachment,sys_notification_template,sys_record_share) are now titled by their stamped field. Acceptance notes, noted, not filed. It is the intended ADR-0079 order, the changeset states the migration, and it is the remainder of the closed family ADR-0079 title: 19 objects that declaretitleFormatand NO pointer getnameField: idstamped by the registry designation pass, so a renderer honouring the declared pointer (objectui#9436) shows the raw record id as the title #20044 / platform-objects: ten system objects declaretitleFormatand no pointer, so the registry stampsnameField: idand a renderer honouring the declared pointer shows the raw record id as the title — the engine half of #20044 #20059. No door was measured giving a wrong answer. deviations: accepted (the spec hunk above; the pin's double; the worktree start; spec's ownpnpm testhosted by CI). The PR body's "roughly 30" count oftitleFormatobjects reads 65 at this head; it is not load-bearing.
Landing: ordinary queue (pr_ready + automerge_enable through the relay), in this stroke.
Generated by Claude Code
Fixes #24087
Clause-②: no
What changed
searchAll(GET /api/v1/search, the console's global search palette) now titles a hit in this order: the primary-title pointer (nameField, then the deprecated aliasdisplayNameField), then thetitleFormattemplate, then the conventional name fields, then first/last name, then the record id. Before,renderTitlerenderedtitleFormatfirst and returned it whenever every placeholder resolved. ADR-0079 D3 says "an explicitnameFieldtakes precedence over it", and the spec'stitleFormatdescribe says the same.packages/metadata-protocol/src/protocol.ts: inrenderTitle, the pointer is read before the template. The comment above it now states the new order and why. The pointer moved out of the conventional candidate list; the list is otherwise unchanged.packages/metadata-protocol/src/protocol.search-title-namefield.test.ts: the old pintitleFormat still outranks the pointerasserted the defect. It is replaced by a[#24087]block (below).packages/spec/src/api/protocol.zod.ts:SearchAllHitSchema.title's describe stated the old order (titleFormatfirst). This change made it false, so it now states the new order.content/docs/references/api/protocol.mdxis regenerated from it (check:generated --fix, thecheck:docsartifact only, two table rows).patchfor@objectstack/metadata-protocoland@objectstack/spec.File-surface note. The claim fences out
packages/spec, namingresolveDisplayFieldand thetitleFormatdescribe; both are untouched. TheSearchAllHitSchema.titledescribe is a third spec site: it is the published contract of the very reader this PR changes, and the reorder made its text false. The dev rules require fixing a shipped statement the change makes false, so it is fixed here (describe text only, no shape change) and named in the report.H1 measured: a provisioned
nameFieldoutrankstitleFormatprovisionPrimaryruns designate-only at the registry's materialization seam (packages/objectql/src/registry.ts,materializeBaseLayer). It stampsnameFieldon any object that has a title-eligible field.ObjectTitleCompleteness.status's docblock inspec/src/data/display-name.tsrecords that authorship cannot be recovered after that stamp: "'the author wrotenameField' and 'the read derivednameField' are the same bytes". SosearchAll, which readsregistry.getAllObjects(), cannot tell an authored pointer from a stamped one.resolveDisplayFielddoes not readtitleFormatat all.Mirroring it means
titleFormattitles a row only when (a) the object has no title-eligible field, so nothing is stamped, or (b) the pointer's value is empty on that row. This is wider than "an explicit nameField". It was settled by the four axes and is listed in the report'sopen_questions. In short: the key is deprecated and lint-warned (title-format-retired), ADR-0079 sets the direction, and the reader cannot see authorship. The changeset gives the migration ADR-0079 prescribes for an author who wants a composite title: a text formula designated asnameField.Pins
All in
protocol.search-title-namefield.test.ts. Each fixture goes through the realprovisionPrimary(..., { synthesize: false }), so the pins see the body the registry serves:titleFormat: '{process_name} · {record_id}'andnameField: 'display_title'(a text formula). It is titledDiscount Sign-off · opp_45, andnot.toBe('flow:deal_desk · opp_45').titleFormatand no title-eligible field gets no stamp, and the template still renders (Order 42).titleFormatplus a text field is titled by the stamped pointer (TK-9).[#8786]block is unchanged and still green. It includes an object with neither key, which falls back tonameas before.Ablation (one run, source-resolved). The test imports
./protocol.jsrelatively, so it readssrc/and nodist/leg applies. The mutation went throughscripts/ablation-replace.mjs: the pointer guard was given&& typeof titleFormatSource !== 'string', which restores template-first. The anchor went 1 → 0 and the marker 0 → 1, and the blob changed375717c98f5d→cd9eb0ea1a25. Result: 2 failed | 7 passed, namely THE PIN and pin 4, as predicted. Restore: blob equals HEAD (375717c98f5d) andgit diff HEADis empty.Real engine. The pin runs over the boundary double this file already uses, not a real ObjectQL.
metadata-protocolcannot import@objectstack/objectql(objectql depends on it, a package cycle; see the header ofobjectql/src/global-search-palette-recall.test.ts). The real-engine home is inpackages/objectql, outside this claim's file surface. Using the realprovisionPrimarytransform is the part of the engine that decides this behaviour.Census: other title readers that read
titleFormatfirsttitleFormatfirst?metadata-protocolsearchAllrenderTitlespecresolveDisplayField/resolveRecordDisplayName/objectqlresolveRecordTitledisplay-name.ts:nameField ?? displayNameField ?? derivedmetadata-coreobject-schema-fls-references.tslintvalidate-record-title.tsand friendstitle-format-retiredspec/src/ui/view.zod.tsdocblocks state the objectui chain astitleFormat → displayNameField → type-aware derivation → 'Untitled'; the liveness ledger recordstitleFormataslivevia objectui interpolation. objectui is outside this session's scope, so this is a lead for the seat, not a reading.In this repository,
searchAllwas the only runtime reader that renderedtitleFormat. The remaining family is the objectui display-name chain. It is reported inout_of_scope_findingsas one family, and nothing in it is changed here.Verification (head
a8fe932ef)pnpm --filter '@objectstack/metadata-protocol^...' build: exit 0. Specbuild+check:generated: 1 stale (check:docs), fixed with--fix, regenerated file committed.pnpm --filter @objectstack/metadata-protocol build && … typecheck: exit 0 (tsconfigincludessrc/**/*, tests included).pnpm --filter @objectstack/metadata-protocol exec vitest run --maxWorkers=2: exit 0, 243 files passed, 3 skipped; 20631 tests passed, 19 skipped.node scripts/pm/dispatch-gates.mjs --commands(no paths): 111 commands, each run with its exit code captured before any pipe. 110 exit 0. Three first exited 3 (prerequisite) and were rerun to exit 0 after clearing the prerequisite:check-plugin-teardown-shape --self-test(fetched its pinned fixture commit),check:lean-entry-closure(built objectql),check:skill-examples(built client and client-react).check:dual-build-cjs-loads: exit 3, NOT MEASURED, because it needs every package'sdist/(a fullpnpm build); CI runs it.--ranreconciliation:111 derived famil(ies) accounted for — 110 run, 1 NOT-MEASURED.@objectstack/spec's ownpnpm test(the spec diff is describe text only, and no test pins the old sentence:git grepfinds it only in the regenerated mdx).test:repois CI's.Acceptance notes
titleFormatbeside a title-eligible field (stamped or authorednameField).sys_approval_request(the card's case, which declaresnameField: 'display_title') is measured by THE PIN's fixture shape. The roughly 30 other*.object.tsfiles declaringtitleFormatwere not measured one by one. Somesys_*prefixes are skipped by the palette entirely (sys_audit_log,sys_activity,sys_presence, …).objectql/src/registry.tshas a comment saying title-less system tables "keep resolving their title on read viaresolveDisplayField/titleFormat". It stays accurate.Generated by Claude Code