fix(actions): resolve the declared nameField for record_label, unify the log_call/log_meeting twins - #569
Merged
Conversation
…the log twins `log_call` / `log_meeting` stamped `record_label: ctx.record?.name`, but `name` is not the display field on almost anything here: 14 of 15 objects declare a different `nameField` (`display_title`, `full_name`, `subject`, `contract_number`, …) and most have no `name` column at all — including `crm_case`, the object both actions are scoped to. Every logged call and meeting therefore landed on the timeline with a null label. The bodies now resolve the object's declared `nameField` through a map derived from the object definitions, so it cannot drift and it survives a restore of the global design these actions document. The two actions were also near-verbatim copies that had quietly stopped agreeing on whether `duration` is required (yes for calls, no for meetings, undocumented either way). Everything they share — body, dispatch declarations, the subject/duration/notes param core — now comes from one builder, and `duration` is optional on both, which is what the shared body was already written for: its `duration ? … : subject` summary branch was unreachable while the field was mandatory. Adds `test/global-actions.test.ts`, which EXECUTES the bodies instead of regex-matching them (a new file rather than an append to the high-traffic `test/metadata-references.test.ts`). It asserts the label resolves for every object declaring a `nameField`, and that the twins emit the same activity row apart from the summary prefix and per-kind metadata. Five of its assertions fail against the pre-fix source. Refs #514. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016YKtPTGAZEycQ2bt4BmtpK
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
yinlianghui
marked this pull request as ready for review
July 31, 2026 08:47
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Two items from #514, both confined to
src/actions/global.actions.ts. Each was re-verified against currentmainbefore being touched — both still reproduce.Item 2 —
record_labelis null. The activity writers stampedrecord_label: ctx.record?.name, butnameis not the display field on almost anything in this app. Verified against the current object definitions: 14 of the 15 objects declare anameFieldother thanname(display_title,full_name,subject,contract_number,member_number), and most have nonamecolumn at all —crm_caseincluded, which is the object both actions are scoped to today. Every logged call and meeting therefore landed on the unified timeline with a null label. The bodies now resolve the object's declarednameFieldthrough a map derived from the object definitions themselves, so it cannot drift when an object retargets itsnameField, and it keeps working if these actions are restored to the global design their own comments describe. FormulanameFields resolve fine — the data engine materialises formula fields on read (applyFormulaPlan), so the loadedctx.recordcarriesdisplay_titlealongside the stored columns.Item 15 (the
global.actions.tshalf) — the twins.log_callandlog_meetingwere near-verbatim copies differing only in a summary prefix and a metadata key, and had quietly stopped agreeing on whetherdurationis required (yes for calls, no for meetings, undocumented either way). Everything they share now comes from one builder, anddurationis optional on both — the direction that keeps both forms submittable and the one the shared body was already written for, since itsduration ? … : subjectsummary branch was unreachable while the field was mandatory.The
opportunity_line_item/quote_line_itemhook half of item 15, and every other item in #514, are untouched.Type of Change
Related Issues
Related to #514 (items 2 and 15-half only — this PR deliberately does not close the issue)
Changes Made
record_labelnow reads the object's declarednameFieldviaNAME_FIELD_BY_OBJECT, derived fromsrc/objectsrather than hand-listed, instead of the hardcoded.namecolumn.objectNameresolution in the body also checksctx.object(the name the sandbox context actually carries) — the label lookup is only as good as that value.log_call/log_meetingare built from onelogActivityAction(spec)factory; aLogActivitySpectype is the complete list of what a twin may still differ on (icon, labels, summary prefix,metadata.kind+ per-kind extras, extra params).durationisrequired: falseon both actions. Params, locations, capabilities,timeoutMsandrefreshAfterare now single-sourced.test/global-actions.test.ts(a new file rather than an append to the high-traffictest/metadata-references.test.ts)..changeset/activity-actions-record-label-and-twins.md.Testing
pnpm test) — 22 files, 400 passed / 2 skippedpnpm lint)pnpm build)pnpm verify(validate → typecheck → lint → hygiene → build → test) exits 0.The new tests execute the action bodies against a recording
ctxrather than regex-matching the source, so they pin behavior rather than the fix's spelling — #514 item 17 notes that actions were only ever regex-checked. Five of the 18 assertions fail against the pre-fix source (confirmed by stashing onlysrc/actions/global.actions.tsand re-running):record_labelresolves to the declarednameFieldfor every object that declares one, plus a meta-assertion that mostnameFields are notnameso the guard cannot go vacuous.crm_caseis labelled bydisplay_title(the pre-fix path returnednull).nullinstead of throwing.durationrequiredness, on the subject/notes core, and on every dispatch-level declaration;attendeesis the only param the meeting adds.(N min)suffix whendurationis omitted — a branch that was dead code forlog_call.Not a sandbox-accurate harness: the real runtime executes the source under QuickJS, this is
new Functionover the same string. That gap is #514 item 17 and is left open.Screenshots
n/a — no UI surface changed. The visible effect is that timeline entries for logged calls/meetings now show the record's title instead of a blank label.
Checklist
pnpm changeset)Additional Notes
No translation changes were needed: param labels are unchanged, and the locale packs guard only
label/confirmText/successMessage, all of which keep their existing values.Choosing optional for
durationrather than required is the one judgement call here. Tightening meetings to required would be a UX regression on a form that has shipped; loosening calls matches the body's own fallback and is non-breaking in both directions.Generated by Claude Code