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 }}
Repository navigation
searchAll's title rendering reads only the deprecated displayNameField, so a canonically-designated primary title never titles a ⌘K hit #8786
Filing unassigned; domain:* routing is the triage seat's. Found while implementing #7643 (which fixed the RECALL half of searchAll and deliberately left titling alone — different concern, same function).
The defect
packages/metadata-protocol/src/protocol.ts, searchAll's renderTitle, resolves a hit's title from this candidate list:
Under ADR-0079, nameField is the CANONICAL primary-title pointer and displayNameField is the deprecated alias. This list reads only the alias.
Why it is reachable rather than theoretical
provisionPrimary — the ADR-0079 designation seat the SchemaRegistry runs on every object at registration (materializeBaseLayer, objectql/src/registry.ts) — writes nameField only:
It never stamps displayNameField. So for an object that declares nameField (or has one designated) and does not also carry the deprecated alias, obj.displayNameField is undefined, the entry is filtered out, and title resolution falls through to the conventional-name list.
Impact is confined to objects whose primary title is NOT one of name / full_name / title / subject / label / company. For those, a ⌘K hit falls all the way through to return String(row.id) — the palette shows a raw id where the object's own declared primary title exists and is populated. Objects using a conventional name are unaffected, which is why this has stayed invisible.
The fix
Read the same precedence every other consumer of this pointer already uses — obj.nameField ?? obj.displayNameField — as the first candidate. Three call sites in this file already spell exactly that (the #4254 ingress gate at assertSearchFieldsAreSearchable, the engine's expandSearchOnAst, and, since #7643, searchAll's own search-field resolution one screen above renderTitle). This would make the fourth, in the same function as the third.
Suggested test: an object declaring nameField: 'company_name' with no displayNameField, seeded with a populated company_name, must produce a hit whose title is that value rather than the record id.
Scope note
Not fixed in PR for #7643 on purpose: that card is about RECALL (which rows come back), this is about PRESENTATION (what the returned row is called). They share a function but not a contract, and #7643's file surface was declared region-limited while another PR was open on the same file.
Triage: lands in packages/metadata-protocol ⇒ domain:metadata; graded pm:queue, type Bug. Restores a canonical pointer the platform already declares (ADR-0079) — accept set unchanged ⇒ Bug, not Feature, and nothing here is escalable.
Premise verified on origin/main @ 84cb121, not inherited
provisionPrimary does stamp nameField only. Zero-hit discipline satisfied — displayNameField returns 8 hits in that same file, so its absence from the two return statements is a real reading rather than a bad probe.
⚠️ One supporting claim in the card is measurably wrong — do not inherit it
"Three call sites in this file already spell exactly that … This would make the fourth, in the same function as the third."
Counter-probe: nameField occurs only 5 times in the whole 16,480-line file, so the narrow match is real. The other two named symbols live in other packages — assertSearchFieldsAreSearchable in packages/lint and packages/spec/src/data/search-fields.ts, expandSearchOnAst in packages/objectql/src/engine.ts — and the third ("since #7643, searchAll's own search-field resolution") does not exist on main yet, because #7643 is still pm:dispatched.
The defect itself is unaffected: the fix is still obj.nameField ?? obj.displayNameField as the first candidate, and the precedent for that spelling is still real — it is just cross-package precedent plus one local site, not a local pattern of three. The dev should not open the file expecting to find three.
⛔ Hard serial constraint — same function as an in-flight card
#7643 is pm:dispatched on searchAll, the same function, and this card's own scope note records that #7643 declared a region-limited file surface precisely because another PR was open on this file. This card must therefore either wait for #7643 to land or declare renderTitle at region level and hold to it. Do not dispatch this in the same batch as #7643.
Full picture for the file — four cards, regions listed on #8783. domain:metadata seat #6367 is vacant, so no seat currently holds this file's serial queue; flagged to the maintainer in this round's brief.
Impact bound is accepted as filed and is genuinely narrow: only objects whose primary title is outside name / full_name / title / subject / label / company fall through to String(row.id). That narrowness is why it stayed invisible, and it is also why it grades pm:queue rather than a release nomination.
Claim: PM loop round 5
Session: session_01XeQRiAa7vYRVX5Fog7Zby8
Branch: claude/issue-8786-searchall-title-namefield
Worktree: objectstack-issue-8786
Domain: domain:metadata
File surface: packages/metadata-protocol/src/protocol.ts — region-declared: renderTitle inside searchAll, around :8640 — plus its co-located pins. ⛔ Stop on breach and report.
Container & model: S, mode:subagent, model: opus — above the sonnet floor deliberately: the change alters what a user sees in ⌘K, and the nameField / displayNameField precedence is a judgement if an object carries both.
Serial constraints cleared: ⛔ triage's hard serial behind #7643 is DISCHARGED — PR #8787 merged at 02:09Z, confirmed on both readings (timeline merge event + the artifact on origin/main). Concurrent region in this file: auditMetaItem:6091 (#8747, in flight) — ~2,500 lines away. diffMetaItem:15349 (#8671) has its PR open at #8797; no dev is editing the file. #8770 (#8421) is a held draft, parked.
⚠️ Triage's call-site count is now stale — I re-measured, and the news is good
Triage measured onenameField ?? site and correctly flagged that the card's "three call sites in this file" claim was wrong. That measurement was taken at 84cb121 while #7643 was still pm:dispatched. #7643 has since landed, and it added exactly the site triage said "does not exist on main yet".
Re-measured on the current origin/mainf039a4ca:
:7221 displayField: gate.schema?.nameField ?? gate.schema?.displayNameField
:8684 displayField: obj.nameField ?? obj.displayNameField <- NEW, from #7643
:8640 obj.displayNameField, <- the defect, unchanged
Counter-probe: nameField occurs 7 times in the whole file (was 5 pre-#7643), so the narrow match is real rather than a bad pattern.
The operative fact: searchAll now contains both the correct spelling and the broken one, 44 lines apart, in the same function. You are not importing a convention from another package — you are making renderTitle agree with the line 44 below it. Copy the spelling from :8684.
So: the card says "three sites, this would be the fourth" — wrong. Triage says "one site, cross-package precedent" — true when written, now stale. Two sites, one of them in your own function. Verify all three line numbers from the tree yourself; the file has moved twice tonight and will move again.
The defect (premise verified by triage on 84cb121, re-confirm on current main)
renderTitle's candidate list reads obj.displayNameField — the deprecated alias — while provisionPrimary, the ADR-0079 designation seat the SchemaRegistry runs on every object at registration, stamps nameField only:
Triage's zero-hit discipline: displayNameField returns 8 hits in display-name.ts, so its absence from those two returns is a real reading.
Consequence: an object declaring nameField without the deprecated alias gets undefined, the entry is filtered out, and title falls through the conventional-name list to return String(row.id) — the palette shows a raw id where a declared, populated primary title exists.
Scope — ⛔ presentation only
#7643 fixed recall (which rows come back) and deliberately left titling alone. This card is titling. Same function, different contract. ⛔ Do not touch search-field resolution, the object sweep, caps, ordering, or anything #7643 just landed — that code is hours old and its pins are load-bearing.
Impact bound — accepted as filed, and it bounds your test too
Only objects whose primary title is outsidename / full_name / title / subject / label / company are affected; everything else already resolves through the conventional list. That narrowness is why this stayed invisible, and it means your fixture must use a non-conventional title field or it will pass before and after.
Verification bar
The card names the pin and it is a good one: an object declaring nameField: 'company_name' with nodisplayNameField, seeded with a populated company_name, must produce a hit whose title is that value rather than the record id. Add the discriminating control in the same test — an object using a conventional name still titles correctly — so the pin shows you changed precedence rather than bypassing the candidate list.
⚠️One judgement I want measured, not assumed: if an object carries bothnameField and displayNameField and they name different fields, your change flips which one wins. Measure whether any object in the repo is in that state before deciding it is safe, and pin the precedence you land on. If real objects disagree, ⛔ stop and report — that is a behaviour change beyond this card.
{
"issue": 8786,
"status": "done",
"branch": "claude/issue-8786-searchall-title-namefield",
"pr": "https://github.com/objectstack-ai/objectstack/pull/8809",
"premise_still_valid": true,
"summary": "renderTitle's candidate list in searchAll now opens with `obj.nameField ?? obj.displayNameField` instead of the deprecated alias alone, matching the spelling #7643 landed 44 lines below it at :8699 (was :8684 pre-merge). Re-derived all four dispatch numbers from the tree before editing and they held exactly: :8640 defect, :8684 correct spelling, :7221 gate, :8552 searchAll, with `nameField` at 7 occurrences and exactly 2 `nameField ??` sites — the claim comment's corrected count, not the card's 'three' nor triage's stale 'one'. ZONE 3 measured rather than assumed: across 52 files carrying `displayNameField`, 38 declarations have a co-located `nameField`; 33 agree exactly and the 5 that disagree are ALL test fixtures that exist to pin precedence — every one already pinning `nameField` as the winner (`resolveDisplayField({nameField:'a',displayNameField:'b'}) === 'a'`). No real object is in the disagreeing state, so the precedence landed on is the platform's existing answer and no escalation was needed. Region held: only renderTitle and its own doc comment; nothing #7643 wrote was touched. origin/main was merged (it had advanced to caaae2cca under me) before the PR.",
"tests": "All at HEAD cd974da6e, quoted from the post-merge union run (the merge commit is the final commit). `pnpm --filter @objectstack/metadata-protocol test` -> 'Test Files 92 passed (92) / Tests 1375 passed (1375)'. New file protocol.search-title-namefield.test.ts, 6 cases, all green in isolation. REVERSE VERIFICATION with the direction predicted before running and observed as predicted — restoring `obj.displayNameField,` alone turns exactly 2 of 6 red with the defect's own signature: \"expected 'acc_1' to be 'Acme Industrial'\" and \"expected 'OLD-11' to be 'TK-77'\", 'Tests 2 failed | 4 passed (6)'; the 4 green are the controls, which by design do not discriminate this fix. Fix was committed BEFORE the ablation and restored via `git checkout <branch> -- <path>`, `git status` clean after. Gate union re-derived against actual changed paths via 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. No dogfood ablation in this card (no dist/-resolved test), so nothing to rebuild on that axis; the type-check ratchet DID need the built closure and got it — `turbo run build --filter=./packages/* --filter=./packages/*/*`, 70/70 successful, then '33 ledger entries re-measured, 1926 raw tsc errors total, none above its recorded number'.",
"open_questions": [],
"out_of_scope_findings": [
"NOT FILED (already tracked, no duplicate): check:type-check-debt reports @objectstack/lint's TEST_DEBT records 20 while tsc now measures 19 — a 1-error surplus another card's improvement opened. The gate itself calls it informational and cites its own tracking issue #6376, and closing it (`--lower`) would be an unrelated ledger edit in this PR, so I left it. Flagging so the PM can decide whether to queue the `--lower`."
]
}
Gate-list delta worth the PM's attention: the dispatch prompt named the gates from dispatch-gates.mjs against protocol.ts alone. Re-deriving against my actual changed paths (source + new test + changeset) surfaced four families the prompt could not have listed — the three .changeset families (check:changeset-gate-self-tests, check:objectui-changeset, and the adr-0087 / no-major / empty-changeset trio) plus the convention-triggered check:query-options-erasure and the check:type-check-coverage / check:type-check-debt pair, which fire because the change adds a test file. The last one mattered: @objectstack/metadata-protocol sits in the DEBT ledger, so a new test file genuinely moves that ratchet, and it refuses to measure at all on an unbuilt worktree. Ran green after a full closure build.
You resolved the one stop-condition by measurement, which is exactly what it was for
I made this a hard stop: if an object carries both pointers naming different fields, your change flips which one wins — measure whether any object is in that state, and if real objects disagree, stop and report.
You measured it rather than reasoning about it. Across 52 files carrying displayNameField, 38 declarations have a co-located nameField:
33 agree exactly, each 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 — every one of them already pinning nameField as the winner, matching resolveDisplayField({nameField:'a', displayNameField:'b'}) === 'a' as pinned in display-name.test.ts.
So no real object is in the disagreeing state, and the precedence you landed on is the platform's existing answer rather than a new one. That is the difference between "the stop condition did not fire" and "I checked whether it fired" — and it is now pinned here too, so the next person does not have to re-derive it.
The two controls that make the pin mean something
The pin alone (nameField: 'company_name', no alias ⇒ title is Acme Industrial, not acc_1) would pass under a rewrite that short-circuits on the pointer and bypasses the candidate list entirely. Two of your six cases close that off:
an object with a conventional name and no pointer at all still titles correctly;
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.
Using non-conventional title fields (company_name, ref_no, ref_code) throughout was necessary rather than incidental: a conventional field would have passed identically before and after the fix, and the test would have proved nothing.
Reverse verification: predicted before running, measured exactly 2 of 6 red, with the defect's own signature (expected 'acc_1' to be 'Acme Industrial', expected 'OLD-11' to be 'TK-77'). The 4 that stayed green are the controls, which by design do not discriminate this fix — worth saying, because a reverse verification where everything goes red is measuring the file, not the change.
The line numbers held — and the corrected count was the operative one
You re-derived all four numbers from the tree before editing and they held exactly (:8640 defect, :8684 correct spelling, :7221 gate, :8552searchAll), with nameField at 7 occurrences and exactly 2nameField ?? sites.
That count is the thing worth recording: the card claimed three local call sites (wrong), triage corrected it to one plus cross-package precedent (true when written, stale by dispatch — #7643 landed and added the second), and the truth was two, one of them 44 lines below the defect in the same function. Re-measuring at dispatch turned "import a convention from another package" into "make this line agree with the one below it", which is a materially easier and safer change.
Scope held
Presentation only. #7643's recall contract untouched, its protocol.search-case-fold.test.ts pins still passing, search-field resolution / object sweep / caps / ordering unmodified. Region held to renderTitle, so the concurrent auditMetaItem and diffMetaItem work was unaffected — three cards in one 16,000-line file this round, no collisions.
Noted, not actioned
check:type-check-debt reports @objectstack/lint's TEST_DEBT records 20 while tsc measures 19 (-1) — a surplus another card's improvement opened. You left it, correctly: --lower in this PR would be an unrelated ledger edit. It is informational per the gate's own wording and tracked in #6376. Three separate devs have now reported it tonight, which is enough signal that it wants its own one-line card rather than a recurring footnote; I am carrying that rather than asking anyone to fold it in.
Docs
Drift check flagged 3 pages; no action — this changes which declared field titles a search hit, and no page documents that resolution order.
Landing
ready → auto-merge → merge queue. Confirmation on both readings — the timeline merge event and the artifact on origin/main.
Activity
hotlong commentedon Aug 15, 2026
Triage: lands in
packages/metadata-protocol⇒domain:metadata; gradedpm:queue, typeBug. Restores a canonical pointer the platform already declares (ADR-0079) — accept set unchanged ⇒Bug, notFeature, and nothing here is escalable.Premise verified on
origin/main@84cb121, not inheritedBoth load-bearing claims hold verbatim:
provisionPrimarydoes stampnameFieldonly. Zero-hit discipline satisfied —displayNameFieldreturns 8 hits in that same file, so its absence from the two return statements is a real reading rather than a bad probe.Measured: one, not three.
Counter-probe:
nameFieldoccurs only 5 times in the whole 16,480-line file, so the narrow match is real. The other two named symbols live in other packages —assertSearchFieldsAreSearchableinpackages/lintandpackages/spec/src/data/search-fields.ts,expandSearchOnAstinpackages/objectql/src/engine.ts— and the third ("since #7643,searchAll's own search-field resolution") does not exist onmainyet, because #7643 is stillpm:dispatched.The defect itself is unaffected: the fix is still
obj.nameField ?? obj.displayNameFieldas the first candidate, and the precedent for that spelling is still real — it is just cross-package precedent plus one local site, not a local pattern of three. The dev should not open the file expecting to find three.⛔ Hard serial constraint — same function as an in-flight card
#7643 is
pm:dispatchedonsearchAll, the same function, and this card's own scope note records that #7643 declared a region-limited file surface precisely because another PR was open on this file. This card must therefore either wait for #7643 to land or declarerenderTitleat region level and hold to it. Do not dispatch this in the same batch as #7643.Full picture for the file — four cards, regions listed on #8783.
domain:metadataseat #6367 is vacant, so no seat currently holds this file's serial queue; flagged to the maintainer in this round's brief.Impact bound is accepted as filed and is genuinely narrow: only objects whose primary title is outside
name/full_name/title/subject/label/companyfall through toString(row.id). That narrowness is why it stayed invisible, and it is also why it gradespm:queuerather than a release nomination.Generated by Claude Code
hotlong commentedon Aug 15, 2026
Claim: PM loop round 5
Session:
session_01XeQRiAa7vYRVX5Fog7Zby8Branch:
claude/issue-8786-searchall-title-namefieldWorktree:
objectstack-issue-8786Domain:
domain:metadataFile surface:
packages/metadata-protocol/src/protocol.ts— region-declared:renderTitleinsidesearchAll, around:8640— plus its co-located pins. ⛔ Stop on breach and report.Container & model:
S,mode:subagent,model: opus— above the sonnet floor deliberately: the change alters what a user sees in ⌘K, and thenameField/displayNameFieldprecedence is a judgement if an object carries both.Serial constraints cleared: ⛔ triage's hard serial behind #7643 is DISCHARGED — PR #8787 merged at 02:09Z, confirmed on both readings (timeline merge event + the artifact on
origin/main). Concurrent region in this file:auditMetaItem:6091(#8747, in flight) — ~2,500 lines away.diffMetaItem:15349(#8671) has its PR open at #8797; no dev is editing the file. #8770 (#8421) is a held draft, parked.Triage measured one
nameField ??site and correctly flagged that the card's "three call sites in this file" claim was wrong. That measurement was taken at84cb121while #7643 was stillpm:dispatched. #7643 has since landed, and it added exactly the site triage said "does not exist onmainyet".Re-measured on the current
origin/mainf039a4ca:Counter-probe:
nameFieldoccurs 7 times in the whole file (was 5 pre-#7643), so the narrow match is real rather than a bad pattern.The operative fact:
searchAllnow contains both the correct spelling and the broken one, 44 lines apart, in the same function. You are not importing a convention from another package — you are makingrenderTitleagree with the line 44 below it. Copy the spelling from:8684.So: the card says "three sites, this would be the fourth" — wrong. Triage says "one site, cross-package precedent" — true when written, now stale. Two sites, one of them in your own function. Verify all three line numbers from the tree yourself; the file has moved twice tonight and will move again.
The defect (premise verified by triage on
84cb121, re-confirm on current main)renderTitle's candidate list readsobj.displayNameField— the deprecated alias — whileprovisionPrimary, the ADR-0079 designation seat the SchemaRegistry runs on every object at registration, stampsnameFieldonly:Triage's zero-hit discipline:
displayNameFieldreturns 8 hits indisplay-name.ts, so its absence from those two returns is a real reading.Consequence: an object declaring
nameFieldwithout the deprecated alias getsundefined, the entry is filtered out, and title falls through the conventional-name list toreturn String(row.id)— the palette shows a raw id where a declared, populated primary title exists.Scope — ⛔ presentation only
#7643 fixed recall (which rows come back) and deliberately left titling alone. This card is titling. Same function, different contract. ⛔ Do not touch search-field resolution, the object sweep, caps, ordering, or anything #7643 just landed — that code is hours old and its pins are load-bearing.
Impact bound — accepted as filed, and it bounds your test too
Only objects whose primary title is outside
name/full_name/title/subject/label/companyare affected; everything else already resolves through the conventional list. That narrowness is why this stayed invisible, and it means your fixture must use a non-conventional title field or it will pass before and after.Verification bar
The card names the pin and it is a good one: an object declaring
nameField: 'company_name'with nodisplayNameField, seeded with a populatedcompany_name, must produce a hit whosetitleis that value rather than the record id. Add the discriminating control in the same test — an object using a conventionalnamestill titles correctly — so the pin shows you changed precedence rather than bypassing the candidate list.nameFieldanddisplayNameFieldand they name different fields, your change flips which one wins. Measure whether any object in the repo is in that state before deciding it is safe, and pin the precedence you land on. If real objects disagree, ⛔ stop and report — that is a behaviour change beyond this card.Generated by Claude Code
hotlong commentedon Aug 15, 2026
{ "issue": 8786, "status": "done", "branch": "claude/issue-8786-searchall-title-namefield", "pr": "https://github.com/objectstack-ai/objectstack/pull/8809", "premise_still_valid": true, "summary": "renderTitle's candidate list in searchAll now opens with `obj.nameField ?? obj.displayNameField` instead of the deprecated alias alone, matching the spelling #7643 landed 44 lines below it at :8699 (was :8684 pre-merge). Re-derived all four dispatch numbers from the tree before editing and they held exactly: :8640 defect, :8684 correct spelling, :7221 gate, :8552 searchAll, with `nameField` at 7 occurrences and exactly 2 `nameField ??` sites — the claim comment's corrected count, not the card's 'three' nor triage's stale 'one'. ZONE 3 measured rather than assumed: across 52 files carrying `displayNameField`, 38 declarations have a co-located `nameField`; 33 agree exactly and the 5 that disagree are ALL test fixtures that exist to pin precedence — every one already pinning `nameField` as the winner (`resolveDisplayField({nameField:'a',displayNameField:'b'}) === 'a'`). No real object is in the disagreeing state, so the precedence landed on is the platform's existing answer and no escalation was needed. Region held: only renderTitle and its own doc comment; nothing #7643 wrote was touched. origin/main was merged (it had advanced to caaae2cca under me) before the PR.", "tests": "All at HEAD cd974da6e, quoted from the post-merge union run (the merge commit is the final commit). `pnpm --filter @objectstack/metadata-protocol test` -> 'Test Files 92 passed (92) / Tests 1375 passed (1375)'. New file protocol.search-title-namefield.test.ts, 6 cases, all green in isolation. REVERSE VERIFICATION with the direction predicted before running and observed as predicted — restoring `obj.displayNameField,` alone turns exactly 2 of 6 red with the defect's own signature: \"expected 'acc_1' to be 'Acme Industrial'\" and \"expected 'OLD-11' to be 'TK-77'\", 'Tests 2 failed | 4 passed (6)'; the 4 green are the controls, which by design do not discriminate this fix. Fix was committed BEFORE the ablation and restored via `git checkout <branch> -- <path>`, `git status` clean after. Gate union re-derived against actual changed paths via 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. No dogfood ablation in this card (no dist/-resolved test), so nothing to rebuild on that axis; the type-check ratchet DID need the built closure and got it — `turbo run build --filter=./packages/* --filter=./packages/*/*`, 70/70 successful, then '33 ledger entries re-measured, 1926 raw tsc errors total, none above its recorded number'.", "open_questions": [], "out_of_scope_findings": [ "NOT FILED (already tracked, no duplicate): check:type-check-debt reports @objectstack/lint's TEST_DEBT records 20 while tsc now measures 19 — a 1-error surplus another card's improvement opened. The gate itself calls it informational and cites its own tracking issue #6376, and closing it (`--lower`) would be an unrelated ledger edit in this PR, so I left it. Flagging so the PM can decide whether to queue the `--lower`." ] }Gate-list delta worth the PM's attention: the dispatch prompt named the gates from
dispatch-gates.mjsagainstprotocol.tsalone. Re-deriving against my actual changed paths (source + new test + changeset) surfaced four families the prompt could not have listed — the three.changesetfamilies (check:changeset-gate-self-tests,check:objectui-changeset, and the adr-0087 / no-major / empty-changeset trio) plus the convention-triggeredcheck:query-options-erasureand thecheck:type-check-coverage/check:type-check-debtpair, which fire because the change adds a test file. The last one mattered:@objectstack/metadata-protocolsits in the DEBT ledger, so a new test file genuinely moves that ratchet, and it refuses to measure at all on an unbuilt worktree. Ran green after a full closure build.Generated by Claude Code
Generated by Claude Code
hotlong commentedon Aug 15, 2026
ACCEPTED — PR #8809 marked ready and queued. All 26 gate jobs read job-by-job; zero failures.
PM session
session_01XeQRiAa7vYRVX5Fog7Zby8, round 5.You resolved the one stop-condition by measurement, which is exactly what it was for
I made this a hard stop: if an object carries both pointers naming different fields, your change flips which one wins — measure whether any object is in that state, and if real objects disagree, stop and report.
You measured it rather than reasoning about it. Across 52 files carrying
displayNameField, 38 declarations have a co-locatednameField:[ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)comment;nameFieldas the winner, matchingresolveDisplayField({nameField:'a', displayNameField:'b'}) === 'a'as pinned indisplay-name.test.ts.So no real object is in the disagreeing state, and the precedence you landed on is the platform's existing answer rather than a new one. That is the difference between "the stop condition did not fire" and "I checked whether it fired" — and it is now pinned here too, so the next person does not have to re-derive it.
The two controls that make the pin mean something
The pin alone (
nameField: 'company_name', no alias ⇒ title isAcme Industrial, notacc_1) would pass under a rewrite that short-circuits on the pointer and bypasses the candidate list entirely. Two of your six cases close that off:nameand no pointer at all still titles correctly;Using non-conventional title fields (
company_name,ref_no,ref_code) throughout was necessary rather than incidental: a conventional field would have passed identically before and after the fix, and the test would have proved nothing.Reverse verification: predicted before running, measured exactly 2 of 6 red, with the defect's own signature (
expected 'acc_1' to be 'Acme Industrial',expected 'OLD-11' to be 'TK-77'). The 4 that stayed green are the controls, which by design do not discriminate this fix — worth saying, because a reverse verification where everything goes red is measuring the file, not the change.The line numbers held — and the corrected count was the operative one
You re-derived all four numbers from the tree before editing and they held exactly (
:8640defect,:8684correct spelling,:7221gate,:8552searchAll), withnameFieldat 7 occurrences and exactly 2nameField ??sites.That count is the thing worth recording: the card claimed three local call sites (wrong), triage corrected it to one plus cross-package precedent (true when written, stale by dispatch — #7643 landed and added the second), and the truth was two, one of them 44 lines below the defect in the same function. Re-measuring at dispatch turned "import a convention from another package" into "make this line agree with the one below it", which is a materially easier and safer change.
Scope held
Presentation only. #7643's recall contract untouched, its
protocol.search-case-fold.test.tspins still passing, search-field resolution / object sweep / caps / ordering unmodified. Region held torenderTitle, so the concurrentauditMetaItemanddiffMetaItemwork was unaffected — three cards in one 16,000-line file this round, no collisions.Noted, not actioned
check:type-check-debtreports@objectstack/lint's TEST_DEBT records 20 while tsc measures 19 (-1) — a surplus another card's improvement opened. You left it, correctly:--lowerin this PR would be an unrelated ledger edit. It is informational per the gate's own wording and tracked in #6376. Three separate devs have now reported it tonight, which is enough signal that it wants its own one-line card rather than a recurring footnote; I am carrying that rather than asking anyone to fold it in.Docs
Drift check flagged 3 pages; no action — this changes which declared field titles a search hit, and no page documents that resolution order.
Landing
ready → auto-merge → merge queue. Confirmation on both readings — the timeline merge event and the artifact on
origin/main.Generated by Claude Code
fix(metadata-protocol): title ⌘K hits from the canonical nameField (o…