Takeda Salesforce field mappings and audit¶
Status: Historical MCP audit | Last reviewed: 2026-10-07
The native replacement is documented in Takeda native Salesforce workflows, including the controls for each mapping and the revised completion rule. The audit below describes the earlier MCP path and remains relevant to retained legacy versions.
Subsequent native readback: Subject values in the tables are request inputs. Salesforce's DCC_Construct_and_update_Case_subject flow replaces displayed Case titles with Case number, Origin and the Reason label. See Salesforce-owned Case titles for its controls and branches.
Use these tables to find the source of each Case, Task, summary and handoff value on the Vanguard Genesys AI route. Read the action logic reference for execution order and workflow migration options. The schema mappings checked out, but the completion logic has confirmed defects; the implementation is not fully verified as correct.
Scope and evidence¶
The October 7 audit read Vanguard's published agent 4463:v28, workflows 1856:v5, 1918:v1, 1857:v7, legacy 1855:v5, and their tool bindings. It inspected the current local handler/renderer source, queried DevSDO field metadata, and read existing records. It did not write Salesforce records, publish workflows, or change the application implementation.
The source implementation is not independently tied to a deployed image/revision by this audit. The behavioral reproductions exercise that source with simulated Salesforce responses; they establish code defects, not that each defect occurred in a live call.
Private evidence is under .local-data/takeda-demo/mapping-audit-2026-10-07/: read-only-report.json, sample-report.json, their read-only scripts, and edge-cases.ts. Keep record-level evidence and credentials out of documentation and Git.
The read-only sample selected the 12 most recent distinct calls with workflow 1918 executions. It found 12 parent Cases and 22 children:
- All parent reasons were
MultiPatientAccessReview. - Every sampled parent had one correctly linked voice Task.
- All child parent links, external keys, inherited record types and status flags matched.
- Twenty-one children had CareRequest/source Case links consistent with that request's Member Account and historical Case. One had neither optional link; absence is permitted by the handler and is not proof that a link should exist.
- All parents had HTML; four had no Customer Intents. The MCP does not write Customer Intents.
This is a limited sample, not an audit of every record, Salesforce automation or record-type-specific picklist rule.
Names used in the mappings¶
| Name | Source |
|---|---|
id |
Lowercased, validated original Genesys conversation UUID |
K(suffix) |
takeda:00000000-0000-0000-0000-000000000001:genesys:<id>:<suffix> |
ctx.caseId / ctx.activityId |
Verified parent Case / inbound Task IDs |
ctx.coordinatorId / ctx.contactId |
Selected coordinator Account / Person Contact IDs |
ctx.coordinatorName |
Parent Account.Name on readback |
patient |
One entry in this call's Account-ID-based roster, selected by pN |
saved |
Child records validated against this call and roster |
params |
Nested sessionEnd.params overlaid with top-level sessionEnd |
The field payloads live in genesys-call.ts. Constants and object-field names in these tables are code-owned unless the table says otherwise.
Parent Case¶
prepareCall creates this record. saveRosterPatientOutcome and the finalizer can later update it.
| Salesforce field | Source/value | When written |
|---|---|---|
External_ID__c |
K("parent") |
Create |
AccountId |
Selected coordinator Account ID | Create |
ContactId |
Selected coordinator Person Contact ID | Create |
RecordTypeId |
012Kd000000pk1VIAQ — Agnostic Case |
Create |
Subject |
Takeda Clearway \| Multi-Patient Access Review |
Create |
Reason |
API value MultiPatientAccessReview |
Create |
Status |
New |
Create |
Origin |
Voice |
Create |
Priority |
Medium |
Create |
DCC_Case_Summary__c |
summaryHtml(ctx, saved) |
Patient save; limited finalizer repair |
Status |
Closed unless String(params.session_escalated) === "true" |
Finalization |
The MCP does not explicitly set parent ParentId, Description, OwnerId, or DCC_Customer_Intents__c. Defaults and Salesforce automation can populate omitted fields. The parent remains open on the explicit escalation branch.
The matching Account's name is not accepted as the final identity merely because it appeared in an input: the returned callContext takes Account.Name from parent readback. Existing parent reuse does not revalidate every configured default, such as Reason, Subject, Origin or the exact configured record type.
Inbound call Task¶
| Salesforce field | Source/value | When written |
|---|---|---|
External_ID__c |
K("interaction") |
Create / missing-Task upsert key |
WhatId |
@{parent.id} in Composite; existing parent ID in recovery |
Create/recovery |
WhoId |
Coordinator Person Contact ID | Create/recovery |
CallObject |
Original Genesys conversation UUID | Create/recovery |
Subject |
Inbound Voice |
Create/recovery |
Type |
Voice |
Create/recovery |
CallType |
Inbound |
Create/recovery |
Status |
In Progress |
Create/recovery |
Priority |
Normal |
Create/recovery |
Description |
Deterministic saved-child summary plus job warnings in background mode | Finalization |
Status |
In Progress for explicit escalation; otherwise Completed |
Finalization |
With backgroundUpdates=false, Description instead takes params.summary, limited to 8,000 characters. The configured end workflow enables background mode, so it replaces that input with the record-derived summary. That generated branch does not apply the 8,000-character cut.
The MCP does not explicitly write Task ownership or Customer Intents. Task completion describes the call activity, not completion of a historical payer submission.
Roster-based patient child Case¶
saveRosterPatientOutcome creates at most one child per Account under a given call's parent.
| Salesforce field | Source/value |
|---|---|
External_ID__c |
K("patient:" + patient.id) |
ParentId |
ctx.caseId |
DCC_Related_Case__c |
Also ctx.caseId; not the historical source Case |
AccountId |
patient.id |
RecordTypeId |
Parent's actual RecordTypeId |
Reason |
Linked historical Case's Reason; fallback MultiPatientAccessReview |
Subject |
Voice - plus the Reason API value, not its label |
Origin |
Voice |
ContactId |
Patient Account.PersonContactId, when returned |
Takeda_Request__c |
Latest returned CareRequest ID, when present |
Takeda_Source_Case__c |
That CareRequest's CareRequestCaseId, when present |
Status, IsEscalated, Description |
Effective disposition below |
| Disposition | Status / escalation flag | Exact description |
|---|---|---|
discussed |
New / false |
Recorded the caller’s patient inquiry. The discussion is in progress. |
completed |
Closed / false |
Completed the caller’s patient inquiry. No historical request or submission was changed. |
escalated |
Escalated / true |
Caller accepted a case-manager handoff for this patient’s inquiry. |
Existing-child updates normally write only Status, IsEscalated, and Description; source links are verified, not silently rebound. Equal-status saves do not repair Description. A delayed lower disposition keeps the existing higher state.
IsClosed is read-only in DevSDO and derived from Status. The payload does not write it. Child Priority and OwnerId are omitted. Closing a child means the call's inquiry is complete; it does not approve the underlying authorization or close the historical request Case.
The finalizer separately closes every New child and writes the completed description. This bypasses the normal disposition decision and is one of the audit findings.
Legacy child differences¶
Workflow 1855's savePatientOutcome uses fixed names and K("outcome:thomas") / K("outcome:renee"), not Account-ID keys.
| Outcome | Fixed name | Reason / status / description |
|---|---|---|
thomas |
Thomas Whitfield | StepTherapyAppeal; Closed; Completed the caller’s appeal-status inquiry and recorded its outcome. No historical appeal Task was changed. |
renee |
Renee Catellano | PriorAuthorizationFollowUp; Escalated; Caller accepted a case-manager handoff for the prior authorization follow-up. |
Other create fields are parent links, patient Account, inherited record type, Subject="Voice - " + reason, Origin=Voice, and Renee's escalation flag. It omits patient Contact, CareRequest and source Case links.
Patient facts and call context¶
loadPatientContext sets these roster fields:
| Roster value | Salesforce source |
|---|---|
id, name, optional contactId |
Enrollee AccountId, Account.Name, Account.PersonContactId |
reference |
p1, p2, … after deduplication and sorting by Account ID |
requestId |
Latest CareRequest.Id for MemberId=patient.id |
sourceCaseId |
CareRequest.CareRequestCaseId |
reason |
Source Case Reason, otherwise MultiPatientAccessReview |
The brief is a startup snapshot, not refreshed on every turn:
| Brief label | Source |
|---|---|
| Records loaded on | Current UTC date |
| Patient reference / Name | Generated roster reference / patient Account name |
| Request | CareRequest.Name |
| Recorded request status | Source Case.Status |
| Requested date / Decision date | CareRequest.RequestedDate / DecisionDate, date portion |
| Decision notes / Recorded cause notes | CareRequest.DecisionNotes / RootCauseNotes |
| Recorded policy effective date | CareRequest.Takeda_Policy_Effective_Date__c |
| Recorded prior / current criteria | CareRequest.Takeda_Prior_Criteria__c / Takeda_Current_Criteria__c |
| Recorded payer average days | CareRequest.Takeda_Payer_Average_Days__c |
| Case notes | Source Case.Description |
| Activity | Source Task Subject, Status, ActivityDate, Description |
| Event | Source Event Subject, Description |
Missing facts are omitted, missing Task details receive explicit “not recorded”/“none” text, and a missing CareRequest produces “No care request is recorded.” No payer endpoint is called.
Workflow 1856 exposes:
| Workflow output | Configured source |
|---|---|
context_status |
patients.ok=true → ready; otherwise unavailable |
coordinator_first_name |
First space-delimited token of records.callContext.coordinatorName |
patient_brief |
patients.patientBrief when ready; otherwise empty |
call_context |
Enriched patient context when ready; otherwise records context |
transfer_params |
records.transferParams |
The raw patient action also returns a first-name value, but the workflow uses the records expression above. For compound first names, the current greeting takes only the first token.
Four different summaries¶
| Output | Generator and content | Important distinction |
|---|---|---|
Parent Case.DCC_Case_Summary__c |
HTML renderer: coordinator, one card per verified child, badges, optional coaching/handoff paragraph | Fixed wording from saved record state; no transcript summarization |
Task Description |
transferParams(...).summary plus background-job warnings |
Plain text such as “Patient’s inquiry was recorded as completed.” |
VoiceCall DCC_Summary__c |
First 255 characters of final Task summary | Can omit later patients or warnings because of truncation |
| Human wrap-up draft | Apex getTakedaSummary |
Separate bullets from saved children, clinical-note fields and activity receipts |
Parent HTML labels IsClosed=true, IsEscalated=false as Resolved; open/escalated as Escalated; both false as In progress. Inconsistent flags become Needs review and missing flags become Pending verification.
Its per-card description recognizes only StepTherapyAppeal and PriorAuthorizationFollowUp; all other reasons display Patient support inquiry. Names are HTML-escaped. A verified escalated child adds fixed case-manager coaching and a handoff sentence.
The plain-text formatter uses different checks: escalation flag first, then closed flag, otherwise in progress. It does not share the HTML renderer's full contradictory-flag policy.
Changing the agent's spoken prompt or sending a different params.summary does not customize the background-mode parent HTML or final summary. Neither transcriptSummarySaved nor a “Resolved” badge proves that transcript details or clinical resolution were recorded.
VoiceCall final fields¶
The finalizer matches VendorCallKey LIKE '%:<id>:call.%', allows at most one match, and checks that RelatedRecordId is empty or already points to this parent.
| Field | Source |
|---|---|
RelatedRecordId |
ctx.caseId |
DCC_Summary__c |
Final plain-text summary, first 255 characters |
DCC_Call_Reason_Display__c |
Ending params.reason, first 255 characters |
DCC_Caller_Name__c |
Verified coordinator name |
The displayed Call Reason therefore receives a machine ending reason such as case_manager_requested, not Case.Reason or its human label. Decide whether this is the desired display.
This action does not write DCC_CaseId__c, DCC_TaskId__c, or DCC_Call_Reason__c. Genesys/Salesforce integration and handoff recovery have separate mappings. Recovery can restore Case/Task links and copy a sibling summary or stripped parent HTML; it preserves an existing nonblank summary.
Transfer fields and their freshness¶
end_session.params is bound to startup transfer_params. Background save results are not merged back into it.
| Field | Formatter rule | Value on the current startup projection |
|---|---|---|
CaseId, parentCaseId |
Parent Case ID | Verified parent |
ActivityId |
Inbound Task ID | Verified Task |
Name |
Coordinator name | Verified name |
coordinatorAccountId |
Coordinator Account | Verified Account |
childCaseIds |
JSON-encoded array of saved child IDs | String "[]" |
escalatedCaseId |
First escalated child's ID | Empty |
patientAccountId |
First escalated patient's Account, else first child's | Empty |
journeyStatus |
complete only with children all closed/escalated and HTML saved |
partial |
transcriptSummarySaved |
String(summarySaved) |
String "false" |
summary |
Saved-child sentences or fallback | Call records are ready; no patient outcome saves have been verified. |
The richer formatter results returned by patient saves are available inside that action but are discarded by the current voice-tool output mapping. Genesys/human consumers must read saved Salesforce outcomes instead of treating startup fields as a final child list.
An accepted escalation submission triggers end_session with literal session_escalated="true". That routing signal is separate from a persisted child receipt and can precede the Salesforce write.
Customer Intents and human wrap-up¶
The MCP sets child Reason; it does not set parent or Task DCC_Customer_Intents__c.
Salesforce applyTakedaDefaults validates the call parent/Task relationship, collects valid existing parent intents plus generic patient-child Reasons that are active Customer Intent values, sorts/deduplicates them, and proposes them in the wrap-up form. It also proposes parent status Closed. Loading the form does not persist those proposals; the existing Complete action owns the save.
getTakedaSummary separately builds the human's summary and suggested follow-up Tasks from saved records. Human edits, appeal intake and payer/demo actions therefore have their own Salesforce owners; they are not configurable through this MCP.
What the schema audit verified¶
DevSDO's describe responses confirmed:
- Every mapped write field exists and is writable for the configured integration.
- Case and Task
External_ID__care both unique external-ID fields. - Record type
012Kd000000pk1VIAQis active and available, developer nameDCC_Agnostic_Case. - Configured Reason, Status, Origin, Type, CallType and Priority API values appear in active object-level picklists.
Case.IsClosedis read-only;Closedis a closed CaseStatus andEscalatedis open.- Parent HTML capacity is 131,072 characters; Task Description 32,000; the three VoiceCall text fields 255 each.
This does not establish record-type-specific allowed values, validation-rule success for every possible input, or that arbitrary inherited Reasons will produce the intended display.
Confirmed problems¶
These reproductions call the current TypeScript functions against simulated Salesforce state, including IsClosed changing when a parent is closed.
| Finding | Reproduction/result | Required correction before equivalence is claimed |
|---|---|---|
| Unfinished inquiry is declared completed | Save discussed; finish with only reason=caller_disconnected. Child/parent become Closed, Task Completed. |
Define explicit completion/disconnect policy; do not infer resolution from call end |
| Late workers can be blocked | Leave a job pending for the 30-second wait; finalizer closes parent. Subsequent patient save fails the active-parent check. | Preserve pending work and permit safe reconciliation |
| Finalization is not retry-safe | Finish a non-escalated call, then retry. verifiedCall rejects its closed parent before linking/reconciling. |
Separate ownership validation from “must still be open” |
| Child mutation precedes validation | Add an unrecognized New child beneath the parent; finish. Child is closed before roster validation throws. |
Verify every target child before any write |
| Stale parent HTML can remain | Complete a child, replace parent HTML with stale text, finish with no New children. Returns ok=true; HTML remains stale. |
Reconcile HTML independently of whether children were closed |
The normal patient-save path does validate children before writing and verifies its summary. These finalizer findings do not invalidate that distinction.
Gaps and decisions¶
- Ending display: confirm whether VoiceCall Call Reason should show the machine ending reason, the parent's label, or the escalated patient's reason.
- Narrative detail: current summaries record inquiry state, not what was explained, promised or agreed. Decide which verified facts belong in each destination before changing templates.
- Optional source links: explicitly distinguish “no request exists” from “request data could not be loaded.”
- Roster scope: all matching programs are included, with no active-membership filter.
- Readback coverage: final Task, parent closure and VoiceCall PATCHes have no independent final readback.
- Length coverage: the HTML, generated Task summary, child Subject and coordinator name are not checked against every destination's length. A 500-patient roster can exceed the parent HTML capacity if enough children are discussed.
- Operation-list drift: the saved MCP tool's filter lists five operations and omits
takeda_save_roster_patient. Workflow 1918 still explicitly calls it through the MCP executor, which does not use that list as an execution allow-list. Align discovery metadata; do not describe the filter as a security boundary. - Shared code: handler and HTML renderer changes affect callers independently of agent/workflow publication. Pin or version this dependency during a migration.
Verification performed¶
Thirty-four existing focused tests passed across the handler, generic patient configuration, and backup-flow definition suites:
cd apps/ai-manager
node --import tsx --test \
lib/takeda-demo/genesys-call.test.ts \
scripts/takeda-demo/dynamic-patient-definition.test.ts \
scripts/takeda-demo/genesys-backup-definition.test.ts
Those tests include assertions for the current automatic-closing behavior; passing them does not establish that this business policy is correct. The private edge-case script reproduced the five problems above without live writes. The existing fake does not automatically mark a PATCHed parent closed; the audit fixture adds that Salesforce behavior to expose the retry/late-worker failures.
No end-to-end live-call qualification or record repair was performed as part of this documentation audit.