Repository navigation
finding(platform-objects): five system objects declare nameField: id beside a titleFormat — once objectui honours ADR-0079's order (objectui#9436), their record-page H1 becomes the raw record id #20015
Description
Activity
objectstack-fleet commented
on Sep 24, 2026 ContributorAuthorMore actions分诊首次定级:
priority:p2·bug·domain:services·pm:queue—— 五个系统对象声明了nameField: id,旁边另有titleFormat;objectui 按 ADR-0079 改成「声明的名称字段优先」(objectui#9436)之后,这五种记录页的大标题会变成原始的记录 idPath:
packages/plugins/plugin-approvals/src/(sys-approval-action/sys-approval-approver/sys-approval-request)·packages/services/service-automation/src/sys-automation-run.object.ts·packages/services/service-messaging/src/objects/http-delivery.object.tsTriage: the five objects that visibly regress all sit in
plugin-approvals/packages/services/*⇒domain:services(lane table),bug,priority:p2,pm:queue(findingremoved — graded); rationale: objectui#9436 (ruling C1, maintainer 「同意」, in flight) makes the record page honour the declared pointer overtitleFormat, as the spec's own describe says ("an explicit nameField now takes precedence") — objects that declarenameField: 'id'beside a realtitleFormat(e.g.sys_approval_request:nameField: 'id',titleFormat: '{process_name} · {record_id}') will then show the raw id as their H1; objectui cannot fix a declared pointer without breaking ADR-0079, so the metadata is objectstack's to change, ideally before or with that landing.分诊席 #6015,2026-09-24T20:29Z。⛔ 不认领、不派发。本席读完了卡面(本卡尚无评论),并在 objectstack
origin/main44639665ee上核对。本席核对
sys-approval-request.object.ts:nameField: 'id', // [ADR-0079] canonical primary-title pointer …,下一行titleFormat: '{process_name} · {record_id}'。- main 上声明
nameField: 'id'的对象文件,本席实测有 8 个:sys-migration(platform-objects);sys-approval-action/-approver/-request/-token(plugin-approvals);sys-automation-run、sys-flow-dispatch(service-automation);http-delivery(service-messaging)。
- 卡面点名的五个都在其中。另外三个(
sys_migration、sys_approval_token、sys_flow_dispatch)要看它们有没有titleFormat,接手时一并测量。 - 卡面的全量普查(71 个文件带
titleFormat,其中 16 个标题会变)是 objectui 开发在61609edf上做的,卡面要求动手前重跑。
路由说明
卡面标题写的是 platform-objects。但真正会「退化成原始 id」的五个对象,都在
plugin-approvals和packages/services/*,按车道表属于domain:services。另外 11 个「标题会换成别的字段」的对象多在 platform-objects(domain:engine),可能是有意为之,由接手者逐个判断。需要改的,另开给domain:engine的卡或在 PR 里说明。定级说明
p2:objectui#9436 一落地,审批请求、自动化运行、HTTP 投递这些记录页的大标题就会显示成一串 id,用户看得见的退化。不给 p1:不影响数据。
执行要点
- 重跑普查:在当时的 main 上重跑卡面的普查,确认受影响对象的最新清单。
- 给
nameField: id的对象换成有意义的名称字段:按 spec describe 的建议,把titleFormat表达的标题改成一个公式型nameField,⛔ 不要继续依赖只用于渲染的模板。每个对象的具体写法由接手者决定。 - 时间上:最好在 objectui#9436 落地之前或同时完成。卡面说那张卡不会为此等待,落地顺序已写进它的回合报告,由维护者决定。
- 钉住:每个改过的对象,记录页标题取到的是有意义的名称,⛔ 不是 id。
Generated by Claude Code
- addedbugSomething isn't workingSomething isn't workingpriority:p2Medium: important, M3Medium: important, M3and removed
on Sep 24, 2026 objectstack-fleet commented
on Sep 24, 2026 ContributorAuthorMore actionsClaim: PM loop round 1
Session:session_01Evb5jFDZGKQE9KG4jbMfMF
Branch:claude/issue-20015-name-field-id
Worktree:objectstack-issue-20015
Domain:domain:services
Seat:domain:services#1
File surface: the services-lane object definitions that declarenameField: 'id', namelypackages/plugins/plugin-approvals/src/sys-approval-{action,approver,request,token}.object.ts,packages/services/service-automation/src/sys-automation-run.object.tsandsys-flow-dispatch.object.ts, andpackages/services/service-messaging/src/objects/http-delivery.object.ts; the tests that pin their pointers (e.g.sys-automation-run-pointer-pair-verdict.test.ts); new test file(s);.changeset/20015-*.md. ⛔ Notpackages/platform-objects(sys-migration.object.tsisdomain:engine: report it, do not edit). ⛔ Nopackages/spec. Measurement first: re-run the census on currentmain. (Stop on breach; explain in the report.)
Container & model:M,mode:subagent,model: opus(dispatch-gates --tier: no path-derived mandate ⇒ default tier)
Clause-②: no
Thread-read: 5821737695
Serial constraints cleared at 2026-09-24T21:34Z: over all 19 open PRs, none touches any file above. objectui#9436 (objectui lane) is the consumer this card lands ahead of; ⛔ it is not held.objectstack-fleet commented
on Sep 24, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 20015,
"status": "done",
"branch": "claude/issue-20015-name-field-id",
"pr": "#20042",
"session": "session_01Evb5jFDZGKQE9KG4jbMfMF — the dispatching seat's session (this run is a subagent; parent's id per the role file)",
"premise_still_valid": true,
"summary": "Census re-run on main 9d81af7 reproduced the card: 8 object files declare nameField 'id' (each mirrored by displayNameField 'id'), and 5 of them carry a composite titleFormat, so under ADR-0079's order their record-page H1 would be the raw id. Each of the 5 (sys_approval_request / _action / _approver, sys_automation_run, sys_http_delivery) now declares display_title, a formula with returnType 'text' reproducing its titleFormat (null-guarded where a source column is nullable), and points nameField and the displayNameField mirror at it; titleFormat is kept unchanged, and the formula adds no stored column (measured on the synced SQLite table). sys_approval_token and sys_flow_dispatch (no titleFormat) and sys_migration (domain:engine, titleFormat '{id}') are left with one-line verdicts, and the one existing pointer pin (sys-automation-run-pointer-pair-verdict) is re-judged with a note, not dropped. Assignee read as os-sales and untouched; the newest Claim names this branch; no spec capability was missing, so no needs_decision.",
"census": "| Object | File | Lane |titleFormat| H1 under ADR-0079 order, before | Verdict |\n|:---|:---|:---|:---|:---|:---|\n|sys_approval_request|plugin-approvals/src/sys-approval-request.object.ts| services |{process_name} · {record_id}| raw id | changed →display_title|\n|sys_approval_action|plugin-approvals/src/sys-approval-action.object.ts| services |{action} · {step_name}| raw id | changed →display_title|\n|sys_approval_approver|plugin-approvals/src/sys-approval-approver.object.ts| services |{approver} · {request_id}| raw id | changed →display_title|\n|sys_automation_run|service-automation/src/sys-automation-run.object.ts| services |{flow_name} · {node_id}| raw run id | changed →display_title|\n|sys_http_delivery|service-messaging/src/objects/http-delivery.object.ts| services |{label} → {url}| raw delivery UUID | changed →display_title|\n|sys_approval_token|plugin-approvals/src/sys-approval-token.object.ts| services | none | raw id, same as today | left: notitleFormat, so the id is today's title too; no regression |\n|sys_flow_dispatch|service-automation/src/sys-flow-dispatch.object.ts| services | none | raw dispatch key, same as today | left: notitleFormat; the dispatch key is the row's identity by design |\n|sys_migration|platform-objects/src/system/sys-migration.object.ts| engine |{id}| raw id, same astitleFormat| reported, not edited (domain:engine): the template is the id itself, so no regression |",
"tests": "All at HEAD a02c867 (the final commit). New pins: plugin-approvals src/sys-approval-display-title.test.ts (5 tests), service-automation src/sys-automation-run-display-title.test.ts (4) plus the re-judged src/sys-automation-run-pointer-pair-verdict.test.ts (4), service-messaging src/objects/http-delivery-display-title.test.ts (4): real ObjectQL + SqlDriver(better-sqlite3 :memory:) with the real object declarations; each asserts resolveDisplayField -> 'display_title', findOne H1 equals the intended text (e.g. 'flow:deal_desk · opp_42') and is not the row id, equals the titleFormat rendering, resolveRecordTitle agrees, the nullable leg, and display_title absent from columnInfo(). Full consumer suites (vitest run --maxWorkers=2, under os-verify-lock, VERDICT command-exit 0 each): plugin-approvals 50 files / 785 passed; service-automation 145 files / 1729 passed; service-messaging 45 files / 483 passed. typecheck of all three (incl. check:test-typecheck ledgers): VERDICT command-exit 0; tsc --listFiles confirms every new test file is inside a typecheck program. Ablations (committed state; scripts/ablation-replace.mjs wrap mode inside an outer trap-restore script; relative source import, so no dist on the resolution path and no rebuild): 5 pointer reverts nameField 'display_title' -> 'id' all red (request 2/5 'expected 1noNVpCJW8_iN7Aq to be flow:deal_desk · opp_42'; action 2/5; approver 2/5; run 4/8 incl. the re-judged pointer-pair pin 'expected id to be display_title'; http 3/4); 3 stored-column mutations Field.formula -> Field.text all red incl. 'expected [ id, created_at, …(20) ] to not include display_title' (request 3/5, run 5/8, http 4/4); every leg printed 'ok mutation landed' (anchor 1 -> 0, blob changed) and 'ok restored: blob == HEAD'; post-batch git status clean. Gates: dispatch-gates --commands derived 62 families; all 62 run; --ran reconcile: '62 derived, 62 run, 0 NOT-MEASURED, 0 UNRUN' (check:dual-build-cjs-loads first PREREQUISITE NOT MET exit 3 on six unrelated missing dists, re-run green after building them: '104 published require entry point(s) across 67 package(s) load'). Also: check:i18n OK (9 packages in sync); check:i18n-coverage OK (621 baselined, none new); check:i18n-stale-fill OK; GITHUB_TOKEN=$GH_TOKEN node scripts/check-issue-citations.mjs exit 0; check:nul-bytes OK; check:test-source-alias OK; check:cross-package-test-inputs OK; check-empty-changeset: 1 declaring changeset added, none modified. Narrowed eslint (repo-wide pnpm lint is CI's): population = the 17 changed .ts files, none ignored by eslint.config.mjs (json messages carry no 'ignored' notice); --format json count 17 files / 0 errors / 0 warnings; invariance: eslint.config.mjs never enables type-aware linting (its own statement near line 328), so this diff cannot move a verdict on an untouched file. Derivation note: tree is 4 commits behind origin/main; the one stale input is scripts/engine-double-contract.pinned.json, and this diff adds no fake engine. CI: not awaited (in_progress at report time), per the role file.",
"mcp_calls": "0 — no MCP GitHub calls",
"api_writes": "2 — both through the fleet-write relay as objectstack-fleet[bot]: (1) POST /repos/objectstack-ai/objectstack/dispatches (204) executing pr_create -> POST /repos/objectstack-ai/objectstack/pulls draft:true = PR #20042 (run 36070248629, success); (2) this os-dev-report comment, post-stamped -> POST /repos//issues/20015/comments. label-write: 0 (the dispatch names no label beyond the role file's, and skip-changeset does not apply because the diff publishes). git push x4 to the branch (not REST). Reads: plain REST GETs (issue, comments, pulls?head=).",
"open_questions": [
{
"question": "Clause-② is carried as 'no' from the claim. The change adds display_title, a read-only virtual field, to five objects' read and write-response shapes. Does that count as public-surface growth?",
"options": [
"A keep 'no' (patch): no accepted input widens, since a formula field is not writable; the field only makes the declared title readable",
"B 'yes' (minor): treat any new field in a served object shape as surface growth"
],
"recommendation": "A, because the declaration answers whether the accepted set or public surface widens, and this fix only realises a title the objects already declared in titleFormat. The PR and changeset carry 'no' as the claim dictates; flip both lines if the seat rules B."
}
],
"out_of_scope_findings": [
"class: b · Seam: spec:ObjectSchema.titleFormat (describe: 'an explicit nameField now takes precedence') → runtime:SchemaRegistry.registerObject provisionPrimary(synthesize:false), served via materializeServedObjectOnto (packages/spec/src/data/display-name.ts:331: 'A body served by a /meta READ EXIT is already designated') | renderer: objectui record page (objectstack-ai/objectui#9436) · evidence: registering each declaration in a real ObjectQL registry at a02c867 stamps nameField 'id' on 19 objects that declare titleFormat and NO pointer, so the served body presents a pointer the author never wrote as if explicit, and the renderer draws the raw id as H1, the same regression as #20015, reachable on the same premise (objectui#9436 landing). By lane: platform-objects (domain:engine) sys_account, sys_business_unit_member, sys_invitation, sys_member, sys_scim_group_member, sys_scim_projection_grant, sys_scim_subject, sys_team_member, sys_two_factor, sys_verification; plugin-approvals sys_approval_delegation; plugin-security sys_position_permission_set, sys_user_permission_set, sys_user_position; service-messaging sys_notification_delivery, sys_notification_preference, sys_notification_receipt, sys_notification_subscription; service-realtime sys_presence. Remedy has two readings (per-object formula titles, as this PR does, vs a designation pass that never stamps id), so it is not fixed here and was outside the claim's file surface. Dedupe words:titleFormat no nameField designated id·provisionPrimary designate id H1·registry stamps nameField id titleFormat·ADR-0079 derived pointer served as explicit·sys_notification_delivery record title raw id",
"carrier: 承接者:无 · noted in PR Acceptance notes, not filed — six more no-pointer titleFormat objects get a non-id field designated, so their H1 moves to that field: sys_attachment→file_name, sys_report_schedule→name, sys_audience_binding_suggestion→permission_set_name, sys_record_share→object_name, sys_share_link→label, sys_notification_template→subject (same shape as the card's eleven 'moves to another field' objects; may be intended)",
"carrier: 承接者:无 · noted in the PR i18n section, not filed — sys_approval_approver and sys_approval_token are outside plugin-approvals' i18n extract config (and sys_automation_run has no bundle at all), so their labels, the new display_title label included, ship untranslated; pre-existing scope, unchanged by this PR"
],
"deviations": "Commit trailers use AGENTS.md's model-free pair (Claude-Session + 'Co-authored-by: Claude'); the harness reminder's model-named Co-Authored-By was not used because the pre-push hook refuses a model identifier. The PR body ends with the role file's session-URL footer, not the harness's footer form. Worktree ../objectstack-issue-20015 is removed after this comment (node_modules first, no --force).",
"pr_body_new": "Fixes #20015\n\nClause-②: no\n\n## What this changes\n\nADR-0079 resolves a record's title asnameField, thendisplayNameField, then a derivation. An explicitnameFieldtakes precedence over the render-onlytitleFormat. The spec says so in thetitleFormatdescribe (packages/spec/src/data/object.zod.ts:2149onmain):\n\n> [DEPRECATED → nameField (ADR-0079)] Render-only title template; the server cannot return or query it, and an explicit nameField now takes precedence. Migrate a single-field title to nameField, a composite to a formula field designated as nameField.\n\nobjectstack-ai/objectui#9436 makes the record page follow that order. Five services-lane objects declarednameField: 'id'beside a compositetitleFormat, so their record-page H1 would become the raw id.\n\nEach of the five now declaresdisplay_title, a formula field withreturnType: 'text'that reproduces itstitleFormat.nameFieldand thedisplayNameFieldmirror point at it. This is the migration the describe prescribes.\n\n| Object | Formula (display_title) |\n|:---|:---|\n|sys_approval_request|record.process_name + ' · ' + record.record_id|\n|sys_approval_action|record.step_name != null ? record.action + ' · ' + record.step_name : record.action|\n|sys_approval_approver|record.approver + ' · ' + record.request_id|\n|sys_automation_run|record.node_id != null ? record.flow_name + ' · ' + record.node_id : record.flow_name|\n|sys_http_delivery|record.label != null ? record.label + ' → ' + record.url : record.url|\n\nWhere a source column is nullable, a row without it is titled by the other column alone, so the formula does not fail to evaluate.\n\n- No stored column. A formula is virtual.SqlDriver.createColumnemits nothing fortype: 'formula', and the new tests read the synced table's columns to confirmdisplay_titleis absent. No migration runs.\n-titleFormatis unchanged on all five objects, for renderers that still read it first. The new tests hold the formula and the template to the same text for a fully populated row.\n-$searchis unchanged. Neitheridnor a formula is ever a search target (SEARCH_AUTO_EXCLUDED_FIELDS,SEARCH_VIRTUAL_TYPES), so the lead and the membership of the auto-default set are identical.\n- No server-side sort reads the title pointer. A formula cannot be an ORDER BY target, and a grep for sorts overnameField/displayField/titleFieldfound none.\n- The formula form follows the ADR-0079 worked example (content/docs/data-modeling/formulas.mdx,display_titlewithreturnType: 'text') and the system-object import precedent for expression tags (import { P } from '@objectstack/spec'insys-permission-set.object.ts). No system object declared a formula field before this PR, and no object in this repo designated a formulanameField.\n\n## Census (re-run onmain9d81af714f)\n\nEvery object definition declaringnameField: 'id'(all eight also declaredisplayNameField: 'id'):\n\n| Object | File | Lane |titleFormat| H1 under ADR-0079 order, before | Verdict |\n|:---|:---|:---|:---|:---|:---|\n|sys_approval_request|plugin-approvals/src/sys-approval-request.object.ts| services |{process_name} · {record_id}| raw id | changed →display_title|\n|sys_approval_action|plugin-approvals/src/sys-approval-action.object.ts| services |{action} · {step_name}| raw id | changed →display_title|\n|sys_approval_approver|plugin-approvals/src/sys-approval-approver.object.ts| services |{approver} · {request_id}| raw id | changed →display_title|\n|sys_automation_run|service-automation/src/sys-automation-run.object.ts| services |{flow_name} · {node_id}| raw run id | changed →display_title|\n|sys_http_delivery|service-messaging/src/objects/http-delivery.object.ts| services |{label} → {url}| raw delivery UUID | changed →display_title|\n|sys_approval_token|plugin-approvals/src/sys-approval-token.object.ts| services | none | raw id, same as today | left: notitleFormat, so the id is today's title too; no regression |\n|sys_flow_dispatch|service-automation/src/sys-flow-dispatch.object.ts| services | none | raw dispatch key, same as today | left: notitleFormat; the dispatch key is the row's identity by design |\n|sys_migration|platform-objects/src/system/sys-migration.object.ts| engine |{id}| raw id, same astitleFormat| reported, not edited (domain:engine): the template is the id itself, so no regression |\n\n## Pointer pins, re-judged\n\n-service-automation/src/sys-automation-run-pointer-pair-verdict.test.tspinnedSysAutomationRun.nameFieldto'id'as one leg of the #11386 "pointer pair stays undeclared" verdict ("no natural key a seed dataset could address its rows by"). Re-judged, not dropped. The leg still holds: a formula has no stored column a seed row could match, and the seed loader's defaultexternalIdisname, which this object does not have. The pin now asserts that the pointer namesdisplay_titleand that its type isformula, so it goes red if the pointer ever names a stored column. The object's own comment carrying the same leg is updated to match.\n- No other test pins these objects' pointers.grep -rln \"sys_approval_request\\|sys_automation_run\\|sys_http_delivery\" packages --include=*.test.tsfinds 37 files in 15 other packages. None reads these objects'nameField/displayNameField/titleFormator enumerates their real field sets. They use hand-built fixtures or mention the names in prose.\n\n## Tests\n\nNew, one per package, each through the realObjectQLengine on in-memory SQLite and the real object declarations:\n\n-plugin-approvals/src/sys-approval-display-title.test.ts\n-service-automation/src/sys-automation-run-display-title.test.ts\n-service-messaging/src/objects/http-delivery-display-title.test.ts\n\nPer object, each test asserts:\n\n-resolveDisplayFieldresolvesdisplay_title;\n- a seeded row read back withfindOnecarries the H1 thetitleFormatintended (for exampleflow:deal_desk · opp_42), and that H1 is not the row's id;\n- the H1 equals thetitleFormatrendering of the same row;\n- the server-side accessorresolveRecordTitleagrees;\n- the nullable-column leg titles the row by the other column;\n-display_titleis absent from the synced table's columns.\n\nRuns ata02c8673d7:\n\n| Suite | Result |\n|:---|:---|\n|@objectstack/plugin-approvals, full (vitest run --maxWorkers=2) | 50 files, 785 tests passed |\n|@objectstack/service-automation, full | 145 files, 1729 tests passed |\n|@objectstack/service-messaging, full | 45 files, 483 tests passed |\n|typecheck, all three packages (incl. thecheck:test-typecheckledgers) | exit 0 |\n\ntsc --listFilesconfirms every new test file is inside a typecheck program: service-messagingtsconfig.json, plugin-approvalstsconfig.test.json, and service-automationtsconfig.test.jsonandtsconfig.json.\n\n### Ablations (committed state,scripts/ablation-replace.mjs, each restore proven blob == HEAD)\n\nThe object files are imported relatively from source, so nodist/sits on the resolution path and no rebuild is involved.\n\n| Leg | Mutation | Result |\n|:---|:---|:---|\n| ptr-request |nameField: 'display_title'→'id'| red 2/5:expected 'id' to be 'display_title';expected '1noNVpCJW8_iN7Aq' to be 'flow:deal_desk · opp_42'|\n| ptr-action | same | red 2/5: H1'9kMVUkyx9hCJHlrr', expected'approve · manager_review'|\n| ptr-approver | same | red 2/5: H1'CQJXqZmwf6e_0vl4', expected'role:finance · N3bOxv5ejSt1FZj9'|\n| ptr-run | same | red 4/8, including the re-judged pointer-pair pin (expected 'id' to be 'display_title') |\n| ptr-http | same | red 3/4: H1'JNhfRQXBccs860NR', expected'order.created → https://hooks.example.com/in'|\n| col-request |Field.formula(→Field.text(| red 3/5, includingexpected [ 'id', 'created_at', …(20) ] to not include 'display_title'|\n| col-run | same | red 5/8, including the stored-column pin |\n| col-http | same | red 4/4, including the stored-column pin |\n\nEvery leg printedok mutation landedbefore its run andok restored: blob == HEADafter it. The post-batch tree was clean.\n\n## Gates\n\nnode scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsfrom the real diff derived 62 families. All 62 were run, and--ranreconciles: "62 derived, 62 run, 0 NOT-MEASURED, 0 UNRUN".check:dual-build-cjs-loadsfirst answered PREREQUISITE NOT MET (six unrelated packages had nodist/). It was re-run green after building them: "104 published require entry point(s) across 67 package(s) load".\n\nAlso run:\n\n-check:i18n-coverage: OK, 621 baselined, none new;\n-GITHUB_TOKEN=\"$GH_TOKEN\" node scripts/check-issue-citations.mjs: exit 0;\n- narrowed eslint over the 17 changed.tsfiles (--no-inline-config --format json): 17 files, 0 errors, 0 warnings, 0 ignored. The config never enables type-aware linting (eslint.config.mjs, around line 328), so a file's verdict depends on that file alone. The repo-widepnpm lintis CI's.\n\nThe derivation noted the tree is a few commits behindorigin/main. The one stale input isscripts/engine-double-contract.pinned.json, and this diff adds no fake engine.\n\n## i18n\n\ndisplay_titlelabel and help are extracted into the plugin-approvals (request, action) and service-messaging bundles, and translated by hand in zh-CN, ja-JP and es-ES. A second--writereturned the source-hash companions to their prior bytes, because none of the new leaves is a fill.sys_approval_approverandsys_automation_runare outside any extract config, before and after this PR.\n\n## Acceptance notes\n\n- Finding for the seat (not filed from here): 19 objects declaretitleFormatwith no pointer, and the registry stampsnameField: 'id'on them. Measured by registering each declaration in a realObjectQLregistry ata02c8673d7. The designate-only pass (provisionPrimary(…, { synthesize: false })) derivesidas the first title-eligible field. A body served by a/metaread carries that stamp (packages/spec/src/data/display-name.ts:331), so the renderer in objectstack-ai/objectui#9436 would draw the raw id as the H1 for these too, the same regression as this card. The 19 are, by lane:\n -platform-objects:sys_account,sys_business_unit_member,sys_invitation,sys_member,sys_scim_group_member,sys_scim_projection_grant,sys_scim_subject,sys_team_member,sys_two_factor,sys_verification;\n -plugin-approvals:sys_approval_delegation;\n -plugin-security:sys_position_permission_set,sys_user_permission_set,sys_user_position;\n -service-messaging:sys_notification_delivery,sys_notification_preference,sys_notification_receipt,sys_notification_subscription;\n -service-realtime:sys_presence.\n\n Not fixed here. They are outside the claim's file surface, and the remedy has two readings: per-object formula titles, or a designation pass that never stampsid.\n- Six more no-pointer objects get a non-id field designated, so their H1 moves to that field's value:sys_attachment→file_name,sys_report_schedule→name,sys_audience_binding_suggestion→permission_set_name,sys_record_share→object_name,sys_share_link→label,sys_notification_template→subject. This is like the card's eleven "moves to another field" objects, which may be intended. Noted only.\n-Clause-②: nois carried from the claim. The change adds a read-only virtual field to five objects' read shapes, and widens no accepted input.\n"
}
Generated by Claude Code
objectstack-fleet commented
on Sep 24, 2026 ContributorAuthorMore actionsReview — ACCEPT (landing gated on CI) · PR #20042 · head
a02c8673d7·domain:servicesseat · 2026-09-24T23:04ZSeat
session_01Evb5jFDZGKQE9KG4jbMfMF. Checked against GitHub andorigin/main, ⛔ not against the report's own account.Checklist
-
PR shape. Draft, targeting
main. The first line isFixes #20015, andClause-②: nostarts its own line. No other closing keyword. -
Scope. 18 files, +580 / −17, all in the three claimed packages:
- five object definitions and the re-judged pointer pin;
- three new test files;
- generated translation bundles;
.changeset/20015-name-field-id.md(patch for each package).
No
platform-objects(sys_migrationis reported, with the verdict "the template is the id itself, no regression"). Nopackages/spec. NOT governed, 597 lines, merges clean overorigin/main. -
Census re-run on
main. 8 objects declarenameField: 'id', and 5 of them have a compositetitleFormat. Those 5 changed. The other 3 are left with one-line verdicts. -
Diff, read line by line.
- Each of the five objects gains
display_title, aField.formulawithreturnType: 'text'reproducing itstitleFormat, null-guarded where a source column is nullable.nameFieldand thedisplayNameFieldmirror point at it. titleFormatis kept.- This is the migration the
titleFormatdescribe prescribes: 「a composite to a formula field designated as nameField」. - A formula is virtual, and the tests read the synced columns to confirm it: no stored column, no migration.
- I checked the consumer paths myself. The engine plans formula projections: a projection naming
display_titleis rewritten and computed after the query. So lookup, audit and approval title reads that select the name field are served.$searchexcludes virtual types.
- Each of the five objects gains
-
Tests. In three packages, a real
ObjectQL+ SQLite with the real declarations: the resolved field, the H1 equal to thetitleFormatrendering (not the id),resolveRecordTitleagreeing, the nullable leg, and no stored column. Ablations: 5 pointer reverts and 3 stored-column mutations, all red, every restore blob-identical. plugin-approvals (785), service-automation (1729) and service-messaging (483) are green.
Open question, answered: A (
Clause-②: no, patch). No accepted input widens: a formula is not writable. The field realises a title the objects already declared intitleFormat. No spec accept set moves.Out-of-scope findings, one line each:
- 19 objects that declare
titleFormatand no pointer getnameField: 'id'stamped by the registry's designation pass, and would show the raw id under objectui#9436:filed #20044(class b, cross-lane; the remedy has two readings, routed by triage). - Six no-pointer objects whose title moves to another field: carried in ADR-0079 title: 19 objects that declare
titleFormatand 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's body as "may be intended". sys_approval_approver/sys_automation_runsit outside any i18n extract config. This is pre-existing, and noted in the PR.
Landing. No Clause-② limb is hit. The seat's review covers the changeset prose, per the maintainer's 2026-09-10 tier ruling. The PR goes ready and auto-merge when every check is green.
Generated by Claude Code
-
objectstack-fleet commented
on Sep 24, 2026 ContributorAuthorMore actionsLanded ·
domain:servicesseat ·session_01Evb5jFDZGKQE9KG4jbMfMF· 2026-09-24T23:37Z- PR fix(plugin-approvals, service-automation, service-messaging): title five system objects with a text formula instead of the raw id #20042 →
7e6ca1787aonorigin/main. Parent count 1 (a queue squash).display_titleis present insys-approval-request.object.tsat that commit. The card closedcompletedthrough the PR's one closing keyword. - Five services-lane system objects now title their records with a text formula reproducing their
titleFormat, andnameFieldpoints at it. This lands ahead of ruling needed(components/core): which rung wins the record title — PageHeaderRenderer rankstitleFormatabove the ADR-0079 declared pointer,getRecordDisplayNameranks it below (option C of objectui#8351) objectui#9436. - Removed in this stroke, with read-back:
pm:dispatchedand the assignee. The claim is discharged. - Carried off this card: ADR-0079 title: 19 objects that declare
titleFormatand 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 (19 objects with atitleFormatand no pointer, stampednameField: 'id'by the registry; cross-lane, awaiting triage).
Generated by Claude Code
- PR fix(plugin-approvals, service-automation, service-messaging): title five system objects with a text formula instead of the raw id #20042 →
- added 2 commits that reference this issue
on Sep 28, 2026
Filed by the objectui
domain:uiexecution seat (seat #1, sessionsession_01BA3nKVUwKQJf8DBxrSVtNC). The source is the census in objectui#9436's dev stop report (objectstack-ai/objectui#9436, comment5820114435), taken at objectstackorigin/main61609edf. ⛔ Not graded and not routed:domain:*,priority:*andtypeare the triage seat's.Fact
objectui is moving its record page to the order ADR-0079 and
@objectstack/spec's owntitleFormatdescribe declare: 「an explicit nameField now takes precedence」. That move is objectui#9436, ruling C1, maintainer 「同意」, and it is in flight now. The census of objectstack objects that declare both keys:titleFormatkey. 42 of them are platform objects that also declare a pointer (nameField/displayNameField).sys_import_job,sys_job_queue,sys_job_run,sys_session,sys_setting,sys_migration_journal,sys_activity,sys_audit_log,sys_comment,sys_sharing_rule,sys_webhook.nameField: id, so their H1 becomes the raw record id:sys_approval_action,sys_approval_approver,sys_approval_request,sys_automation_run,sys_http_delivery.Why it is objectstack's
The metadata is objectstack's. The spec describe itself advises the remedy: express the title as a formula
nameFieldinstead of a render-only template. objectui cannot fix a declarednameField: idwithout breaking ADR-0079's order.⛔ Not claimed
nameField: idobjects are the ones that visibly regress. The other eleven may be intended.61609edf. Re-run it before acting on it.Dedupe words
nameField id titleFormat·ADR-0079 record title raw id·sys_approval_request H1·formula nameField migration·titleFormat nameField census