@salesforce/afv-skills 1.28.0 → 1.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/package.json +1 -1
  2. package/skills/dx-code-analyzer-configure/SKILL.md +31 -13
  3. package/skills/dx-code-analyzer-custom-rule-create/SKILL.md +484 -0
  4. package/skills/dx-code-analyzer-custom-rule-create/assets/pmd-ruleset-template.xml +31 -0
  5. package/skills/dx-code-analyzer-custom-rule-create/examples/metadata-xml-example-fields-api.md +87 -0
  6. package/skills/dx-code-analyzer-custom-rule-create/examples/metadata-xml-example-flows.md +105 -0
  7. package/skills/dx-code-analyzer-custom-rule-create/examples/metadata-xml-example-permissions.md +95 -0
  8. package/skills/dx-code-analyzer-custom-rule-create/examples/metadata-xml-examples.md +84 -0
  9. package/skills/dx-code-analyzer-custom-rule-create/examples/regex-examples.md +127 -0
  10. package/skills/dx-code-analyzer-custom-rule-create/examples/xpath-examples.md +227 -0
  11. package/skills/dx-code-analyzer-custom-rule-create/references/advanced-pmd-patterns.md +288 -0
  12. package/skills/dx-code-analyzer-custom-rule-create/references/apex-ast-reference.md +127 -0
  13. package/skills/dx-code-analyzer-custom-rule-create/references/eslint-custom-plugins.md +247 -0
  14. package/skills/dx-code-analyzer-custom-rule-create/references/eslint-rules-discovery.md +188 -0
  15. package/skills/dx-code-analyzer-custom-rule-create/references/eslint-tier2-configurable.md +114 -0
  16. package/skills/dx-code-analyzer-custom-rule-create/references/eslint-tier3-custom-plugins.md +113 -0
  17. package/skills/dx-code-analyzer-custom-rule-create/references/metadata-xml-rules.md +285 -0
  18. package/skills/dx-code-analyzer-custom-rule-create/references/regex-rule-schema.md +174 -0
  19. package/skills/dx-code-analyzer-custom-rule-create/references/troubleshooting.md +141 -0
  20. package/skills/dx-code-analyzer-custom-rule-create/references/xpath-patterns-governor-limits.md +83 -0
  21. package/skills/dx-code-analyzer-custom-rule-create/references/xpath-patterns-method-calls.md +108 -0
  22. package/skills/dx-code-analyzer-custom-rule-create/references/xpath-patterns-security.md +45 -0
  23. package/skills/dx-code-analyzer-custom-rule-create/references/xpath-patterns-structure.md +127 -0
  24. package/skills/dx-code-analyzer-custom-rule-create/references/xpath-patterns.md +131 -0
  25. package/skills/dx-code-analyzer-custom-rule-create/scripts/create-pmd-rule.js +209 -0
  26. package/skills/dx-code-analyzer-custom-rule-create/scripts/create-regex-rule.js +220 -0
  27. package/skills/dx-code-analyzer-run/SKILL.md +41 -8
  28. package/skills/mobile-platform-native-capabilities-integrate/SKILL.md +3 -3
  29. package/skills/platform-custom-field-generate/SKILL.md +86 -126
  30. package/skills/platform-custom-field-generate/references/advanced-picklists.md +590 -0
  31. package/skills/platform-value-set-generate/SKILL.md +305 -0
@@ -0,0 +1,590 @@
1
+ # Advanced Picklist Reference
2
+
3
+ Detailed rules and worked examples for picklist CustomFields that go beyond a
4
+ simple inline value list. All XML uses the `http://soap.sforce.com/2006/04/metadata`
5
+ namespace with a `<CustomField>` root, exactly like the simple-picklist examples in
6
+ the main skill.
7
+
8
+ Covered here:
9
+
10
+ 1. [Value Set References (`<valueSetName>`)](#1-value-set-references-valuesetname)
11
+ 2. [Controlling / Dependent Picklists](#2-controlling--dependent-picklists)
12
+ 3. [Enhanced Value Attributes (`color`, `isActive`, value-level `<description>`)](#3-enhanced-value-attributes)
13
+ 4. [Picklist Validation Rules](#4-picklist-validation-rules)
14
+ 5. [Scoping a Picklist to a Record Type](#5-scoping-a-picklist-to-a-record-type)
15
+
16
+ ---
17
+
18
+ ## 1. Value Set References (`<valueSetName>`)
19
+
20
+ A picklist field can either define its values **inline** or **reference an existing
21
+ value set** (a Global Value Set or a Standard Value Set). The shared set is defined
22
+ once and reused across many fields.
23
+
24
+ ### ⭐ HARD RULE: `<valueSet>` is EITHER a reference OR inline — never both
25
+
26
+ A `<valueSet>` element must contain **exactly one** of:
27
+
28
+ - `<valueSetName>` — references an existing value set (this section), **OR**
29
+ - `<valueSetDefinition>` — defines values inline (the simple-picklist case).
30
+
31
+ Including both in the same `<valueSet>` is a deployment error.
32
+
33
+ #### ❌ INCORRECT — both reference and inline definition:
34
+
35
+ ```xml
36
+ <CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
37
+ <fullName>Priority__c</fullName>
38
+ <label>Priority</label>
39
+ <type>Picklist</type>
40
+ <valueSet>
41
+ <restricted>true</restricted>
42
+ <valueSetName>Priority_Levels</valueSetName> <!-- WRONG: reference … -->
43
+ <valueSetDefinition> <!-- WRONG: … AND inline -->
44
+ <sorted>false</sorted>
45
+ <value>
46
+ <fullName>High</fullName>
47
+ <default>false</default>
48
+ <label>High</label>
49
+ </value>
50
+ </valueSetDefinition>
51
+ </valueSet>
52
+ </CustomField>
53
+ ```
54
+
55
+ **Error:** `Value set must reference a value set name or define a value set, but not both.`
56
+
57
+ #### ✅ CORRECT — reference a Global Value Set:
58
+
59
+ ```xml
60
+ <CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
61
+ <fullName>Priority__c</fullName>
62
+ <label>Priority</label>
63
+ <description>Account priority drawn from the shared Priority Levels value set</description>
64
+ <inlineHelpText>Select the priority defined by the central Priority Levels list</inlineHelpText>
65
+ <type>Picklist</type>
66
+ <valueSet>
67
+ <restricted>true</restricted>
68
+ <valueSetName>Priority_Levels</valueSetName>
69
+ </valueSet>
70
+ </CustomField>
71
+ ```
72
+
73
+ ### Same `<valueSetName>` element — Global vs. Standard value sets
74
+
75
+ The SAME `<valueSetName>` element is used to reference both kinds of value set; only
76
+ the name you put inside it differs.
77
+
78
+ | Referenced set | `<valueSetName>` value | Suffix |
79
+ |----------------|------------------------|--------|
80
+ | **StandardValueSet** (platform-defined, e.g. Industry, LeadSource) | Bare enum name | NO `__c`, NO `__gvs` → `<valueSetName>Industry</valueSetName>` |
81
+ | **GlobalValueSet** | Bare developer name | NO `__c`, **NO `__gvs`** → `<valueSetName>Priority_Levels</valueSetName>` |
82
+
83
+ > **Rule: always use the bare developer name — never add `__gvs`.** In API 57.0+ orgs the
84
+ > platform stores/displays a GlobalValueSet's name with a `__gvs` suffix internally, but the
85
+ > **Metadata API (deploy AND retrieve) uses the bare name** (the suffix came from a patched-out
86
+ > Winter '23 change that broke deploys). So `<valueSetName>Priority_Levels</valueSetName>`, never
87
+ > `Priority_Levels__gvs`. A retrieve showing `__gvs` (or a "returned from org but not found in
88
+ > local project" warning) is expected org-storage display — keep local metadata on the bare name.
89
+ > Never append `__c` to a value-set name either.
90
+
91
+ #### ✅ CORRECT — reference a Standard Value Set (bare name, no suffix):
92
+
93
+ ```xml
94
+ <CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
95
+ <fullName>Industry__c</fullName>
96
+ <label>Industry</label>
97
+ <description>Industry classification from the standard Industry value set</description>
98
+ <inlineHelpText>Pick the industry that best describes this account</inlineHelpText>
99
+ <type>Picklist</type>
100
+ <valueSet>
101
+ <restricted>true</restricted>
102
+ <valueSetName>Industry</valueSetName>
103
+ </valueSet>
104
+ </CustomField>
105
+ ```
106
+
107
+ ### A value-set-backed field is `<restricted>` by design
108
+
109
+ When a field references a value set, its values can only change by editing the value
110
+ set itself — the field cannot define ad-hoc values. Set `<restricted>true</restricted>`
111
+ on these fields. Leaving it unrestricted is meaningless for a referenced set.
112
+
113
+ ### Cross-reference: creating the value set itself
114
+
115
+ This skill only **references** an existing value set. **Creating** the GlobalValueSet
116
+ or editing a StandardValueSet (the `.globalValueSet-meta.xml` / `.standardValueSet-meta.xml`
117
+ metadata) is the job of the `platform-value-set-generate` skill. If the value set does not yet
118
+ exist, generate it there first, then reference it here.
119
+
120
+ ---
121
+
122
+ ## 2. Controlling / Dependent Picklists
123
+
124
+ A **dependent** picklist filters its available values based on the selected value of a
125
+ **controlling** field (another picklist, or a checkbox). The dependency lives on the
126
+ **dependent** field via a `<controllingField>` element plus one `<valueSettings>` block
127
+ per (controlling value → dependent value) pair.
128
+
129
+ ### ⭐ Use the MODERN API 38.0+ form ONLY
130
+
131
+ | Form | Elements | Status |
132
+ |------|----------|--------|
133
+ | **Modern (API 38.0+)** | `<valueSet>` → `<controllingField>` + `<valueSetDefinition>` + `<valueSettings>` (`<controllingFieldValue>` + `<valueName>`) | ✅ USE THIS |
134
+ | **Legacy (API ≤ 37.0)** | `<picklist>` / `<picklistValues>` / `<controllingFieldValues>` | ❌ DEPRECATED — do NOT generate |
135
+
136
+ Never emit the legacy `<picklist>`, `<picklistValues>`, or `<controllingFieldValues>`
137
+ tags. They are not valid against the modern Metadata API and will fail deployment.
138
+
139
+ ### ⭐ HARD RULE: both the controlling and dependent field must be `<restricted>true</restricted>`
140
+
141
+ A field dependency requires a fixed, admin-defined value set on **both** ends. **Always emit
142
+ `<restricted>true</restricted>` inside the `<valueSet>` of the controlling field AND the
143
+ dependent field** — even when the request does not mention "restricted". Omitting it produces
144
+ an unrestricted picklist, which cannot reliably participate in a field dependency and diverges
145
+ from the expected metadata. This is non-negotiable for dependent picklists: if you write a
146
+ `<controllingField>` or `<valueSettings>`, the same `<valueSet>` must also carry
147
+ `<restricted>true</restricted>`.
148
+
149
+ ### Structure of a dependent picklist
150
+
151
+ Inside the dependent field's `<valueSet>`, in this order:
152
+
153
+ 1. `<controllingField>` — API name of the controlling field (e.g. `Country__c`).
154
+ 2. `<valueSetDefinition>` — defines the dependent field's own values (as usual). The dependency
155
+ mapping does **NOT** go in here.
156
+ 3. one or more `<valueSettings>` blocks — **siblings** of `<valueSetDefinition>`, NOT nested
157
+ inside it or inside any `<value>`. One block **per (controlling value, dependent value) pair**:
158
+ - `<controllingFieldValue>` — a controlling-field value that enables this dependent value.
159
+ - `<valueName>` — the dependent value that becomes available.
160
+
161
+ > ### ⛔ THE #1 MISTAKE: do NOT put `<controllingFieldValue>` inside `<value>`
162
+ > The mapping lives in **separate `<valueSettings>` blocks**, never as a child of a
163
+ > `<value>` in `<valueSetDefinition>`. Putting `<controllingFieldValue>` inside a `<value>`
164
+ > fails deployment with `Element controllingFieldValue invalid at this location in type CustomValue`.
165
+ >
166
+ > ```xml
167
+ > <!-- ❌ WRONG — controllingFieldValue nested in the value definition -->
168
+ > <valueSetDefinition>
169
+ > <value>
170
+ > <fullName>USA</fullName><label>USA</label><default>false</default>
171
+ > <controllingFieldValue>Americas</controllingFieldValue> <!-- INVALID HERE -->
172
+ > </value>
173
+ > </valueSetDefinition>
174
+ >
175
+ > <!-- ✅ CORRECT — values defined plainly; mapping in SEPARATE valueSettings siblings -->
176
+ > <valueSetDefinition>
177
+ > <value><fullName>USA</fullName><label>USA</label><default>false</default></value>
178
+ > </valueSetDefinition>
179
+ > <valueSettings>
180
+ > <controllingFieldValue>Americas</controllingFieldValue>
181
+ > <valueName>USA</valueName>
182
+ > </valueSettings>
183
+ > ```
184
+ >
185
+ > **One `<valueSettings>` per pair.** With multiple controlling values (Americas→USA,Canada;
186
+ > EMEA→UK,Germany) you emit **one block for each (controllingValue, dependentValue) pair** — four
187
+ > pairs = four `<valueSettings>` blocks. And remember: both fields carry `<restricted>true</restricted>`.
188
+
189
+ ### ✅ CORRECT — State dependent on Country (USA → California, Texas)
190
+
191
+ **Controlling field — `Country__c` (a plain restricted picklist):**
192
+
193
+ ```xml
194
+ <CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
195
+ <fullName>Country__c</fullName>
196
+ <label>Country</label>
197
+ <description>Country used to filter the dependent State picklist</description>
198
+ <inlineHelpText>Select the country first; the State list filters to match</inlineHelpText>
199
+ <type>Picklist</type>
200
+ <valueSet>
201
+ <restricted>true</restricted>
202
+ <valueSetDefinition>
203
+ <sorted>false</sorted>
204
+ <value>
205
+ <fullName>USA</fullName>
206
+ <default>false</default>
207
+ <label>USA</label>
208
+ </value>
209
+ <value>
210
+ <fullName>Canada</fullName>
211
+ <default>false</default>
212
+ <label>Canada</label>
213
+ </value>
214
+ </valueSetDefinition>
215
+ </valueSet>
216
+ </CustomField>
217
+ ```
218
+
219
+ **Dependent field — `State__c`, controlled by `Country__c`:**
220
+
221
+ ```xml
222
+ <CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
223
+ <fullName>State__c</fullName>
224
+ <label>State</label>
225
+ <description>State filtered by the selected Country</description>
226
+ <inlineHelpText>Available states depend on the Country you picked</inlineHelpText>
227
+ <type>Picklist</type>
228
+ <valueSet>
229
+ <controllingField>Country__c</controllingField>
230
+ <restricted>true</restricted>
231
+ <valueSetDefinition>
232
+ <sorted>false</sorted>
233
+ <value>
234
+ <fullName>California</fullName>
235
+ <default>false</default>
236
+ <label>California</label>
237
+ </value>
238
+ <value>
239
+ <fullName>Texas</fullName>
240
+ <default>false</default>
241
+ <label>Texas</label>
242
+ </value>
243
+ </valueSetDefinition>
244
+ <valueSettings>
245
+ <controllingFieldValue>USA</controllingFieldValue>
246
+ <valueName>California</valueName>
247
+ </valueSettings>
248
+ <valueSettings>
249
+ <controllingFieldValue>USA</controllingFieldValue>
250
+ <valueName>Texas</valueName>
251
+ </valueSettings>
252
+ </valueSet>
253
+ </CustomField>
254
+ ```
255
+
256
+ > Each dependent value gets its own `<valueSettings>` block per enabling controlling
257
+ > value. If California were also valid under a second country, you would add another
258
+ > `<valueSettings>` block with that country's `<controllingFieldValue>` and
259
+ > `<valueName>California</valueName>`.
260
+
261
+ ### ❌ INCORRECT — deprecated legacy form:
262
+
263
+ ```xml
264
+ <CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
265
+ <fullName>State__c</fullName>
266
+ <label>State</label>
267
+ <type>Picklist</type>
268
+ <picklist> <!-- WRONG: deprecated wrapper -->
269
+ <controllingField>Country__c</controllingField>
270
+ <picklistValues> <!-- WRONG: use valueSetDefinition/value -->
271
+ <fullName>California</fullName>
272
+ <controllingFieldValues>USA</controllingFieldValues> <!-- WRONG: use valueSettings -->
273
+ </picklistValues>
274
+ </picklist>
275
+ </CustomField>
276
+ ```
277
+
278
+ **Error:** `Element {http://soap.sforce.com/2006/04/metadata}picklist is not allowed` — the
279
+ legacy dependency elements are not valid in the modern `<valueSet>` structure.
280
+
281
+ ---
282
+
283
+ ## 3. Enhanced Value Attributes
284
+
285
+ ### ⭐ Value-name fidelity — do NOT underscore picklist value names
286
+
287
+ A **picklist value's `<fullName>` is NOT a field API name** and must NOT be transformed.
288
+ Use the value text **exactly as the user spelled it**, spaces and all. A value the user
289
+ calls `Closed Won` is `<fullName>Closed Won</fullName>` and `<label>Closed Won</label>` —
290
+ **never** `Closed_Won`. Picklist value `<fullName>` permits spaces (and is not required to
291
+ carry `__c`); the space-to-underscore + `__c` rule applies ONLY to the **field**
292
+ `<fullName>` (e.g. field `Total Contract Value` → `Total_Contract_Value__c`), not to the
293
+ values inside it. Underscoring a value name changes the value's identity, diverges from what
294
+ the user asked for, and breaks any RecordType `<picklistValues>` / `<valueSettings>` that
295
+ reference the value by its real name.
296
+
297
+ | Element | Spaces? | `__c` suffix? | Example for "Closed Won" |
298
+ |---|---|---|---|
299
+ | **Field** `<fullName>` | ❌ replace with `_` | ✅ required | (field named) `Status__c` |
300
+ | **Picklist value** `<fullName>` | ✅ keep as written | ❌ never | `Closed Won` |
301
+ | **Picklist value** `<label>` | ✅ keep as written | ❌ never | `Closed Won` |
302
+
303
+ > ❌ `<fullName>Closed_Won</fullName>` ✅ `<fullName>Closed Won</fullName>`
304
+ > When a RecordType filters this value it must also reference `Closed Won` (with the space)
305
+ > in `<values><fullName>` — the names must match exactly across field and record type.
306
+
307
+ Inline `<value>` entries (CustomValue subfields) support more than `<fullName>`,
308
+ `<default>`, and `<label>`. The common extras:
309
+
310
+ | Subfield | Type | Notes |
311
+ |----------|------|-------|
312
+ | `<color>` | Hex string | UI chart/badge color, e.g. `#FF0000`. Include the leading `#`. |
313
+ | `<isActive>` | Boolean | `false` retires a value without deleting it (preserves history). Inactive values still count toward the 1,000-value restricted limit. |
314
+ | `<description>` | String | Value-level documentation, distinct from the field-level `<description>`. |
315
+
316
+ These are independent of `<default>` and `<label>` and may be combined freely.
317
+
318
+ ### ✅ CORRECT — Status picklist with colors and an inactive value
319
+
320
+ ```xml
321
+ <CustomField xmlns="http://soap.sforce.com/2006/04/metadata">
322
+ <fullName>Status__c</fullName>
323
+ <label>Status</label>
324
+ <description>Lifecycle status of the record</description>
325
+ <inlineHelpText>Select the current lifecycle stage</inlineHelpText>
326
+ <type>Picklist</type>
327
+ <valueSet>
328
+ <restricted>true</restricted>
329
+ <valueSetDefinition>
330
+ <sorted>false</sorted>
331
+ <value>
332
+ <fullName>Cancelled</fullName>
333
+ <default>false</default>
334
+ <label>Cancelled</label>
335
+ <color>#FF0000</color>
336
+ <isActive>true</isActive>
337
+ <description>Work was stopped before completion</description>
338
+ </value>
339
+ <value>
340
+ <fullName>Complete</fullName>
341
+ <default>false</default>
342
+ <label>Complete</label>
343
+ <color>#00FF00</color>
344
+ <isActive>true</isActive>
345
+ <description>All work finished and accepted</description>
346
+ </value>
347
+ <value>
348
+ <fullName>Draft</fullName>
349
+ <default>false</default>
350
+ <label>Draft</label>
351
+ <isActive>false</isActive>
352
+ <description>Legacy draft state, retired from new records</description>
353
+ </value>
354
+ </valueSetDefinition>
355
+ </valueSet>
356
+ </CustomField>
357
+ ```
358
+
359
+ ---
360
+
361
+ ## 4. Picklist Validation Rules
362
+
363
+ The Metadata API rejects malformed picklist values at deploy time. Two common failures:
364
+
365
+ ### Duplicate value names
366
+
367
+ Two `<value>` entries with the same `<fullName>` inside one `<valueSetDefinition>` are
368
+ rejected.
369
+
370
+ #### ❌ INCORRECT — duplicate value:
371
+
372
+ ```xml
373
+ <valueSetDefinition>
374
+ <sorted>false</sorted>
375
+ <value>
376
+ <fullName>Open</fullName>
377
+ <default>false</default>
378
+ <label>Open</label>
379
+ </value>
380
+ <value>
381
+ <fullName>Open</fullName> <!-- WRONG: duplicate fullName -->
382
+ <default>false</default>
383
+ <label>Open (again)</label>
384
+ </value>
385
+ </valueSetDefinition>
386
+ ```
387
+
388
+ **Error:** `duplicate value found: Open is defined multiple times`
389
+
390
+ ### Invalid API-name format
391
+
392
+ A picklist `<value>`'s `<fullName>` must start with a letter and must NOT contain
393
+ hyphens or begin with a digit. Unlike field API names, spaces ARE permitted (e.g.
394
+ `Closed Won`, `United Kingdom`) — see §3 value-name fidelity; do NOT underscore them.
395
+ The `__c` suffix is not required on value `<fullName>` values.
396
+
397
+ The stricter "only alphanumerics and single underscores, no leading digit, no double
398
+ or trailing underscore" rule applies to the *field* `<fullName>` (the `__c`-suffixed
399
+ API name), not to picklist value fullNames.
400
+
401
+ #### ❌ INCORRECT — invalid value API name:
402
+
403
+ ```xml
404
+ <value>
405
+ <fullName>1st-Choice</fullName> <!-- WRONG: starts with digit, has hyphen -->
406
+ <default>false</default>
407
+ <label>1st Choice</label>
408
+ </value>
409
+ ```
410
+
411
+ **Error:** `Invalid fullName: must begin with a letter and use only alphanumeric characters and underscores`
412
+
413
+ #### ✅ CORRECT:
414
+
415
+ ```xml
416
+ <value>
417
+ <fullName>First Choice</fullName> <!-- fixed: letter-first, hyphen removed, space preserved -->
418
+ <default>false</default>
419
+ <label>1st Choice</label>
420
+ </value>
421
+ ```
422
+
423
+ ---
424
+
425
+ ## 5. Scoping a Picklist to a Record Type
426
+
427
+ > **Scope note.** This section covers ONLY the picklist seam between a CustomField and a
428
+ > RecordType — i.e. "expose a subset of *this field's* values for a given record type." It
429
+ > is NOT a general record-type authoring guide. Record types also carry compact layouts,
430
+ > page-layout assignments, branding, and more, which are out of scope here and owned by the
431
+ > record-type / UI metadata area. When a request goes beyond picklist value visibility, say
432
+ > so and defer the broader record-type work rather than guessing.
433
+
434
+ A common follow-on to creating a picklist field is "…and for the *X* record type, only show
435
+ values A and B." That visibility is expressed on the **RecordType**, not the field — the
436
+ field keeps its full value set; the record type filters which values appear.
437
+
438
+ ### Picklist value filtering
439
+
440
+ Add one `<picklistValues>` block per filtered field inside the `<RecordType>`:
441
+
442
+ | Element | Requirement | Notes |
443
+ |---|---|---|
444
+ | `<picklistValues>` | One per filtered picklist | Repeat per field you filter |
445
+ | `<picklist>` | Required | The field API name (e.g. `Status__c`, or `StageName` for a standard field) |
446
+ | `<values>` | One per **exposed** value | List ONLY the values this record type should show; omitted values are hidden (NOT deleted from the field) |
447
+ | `<values><fullName>` | Required | The picklist value's API name |
448
+ | `<values><default>` | Required | `true` on exactly one value, `false` on the rest |
449
+
450
+ ### The RecordType file always carries its own `<fullName>`
451
+
452
+ Unlike a CustomObject (whose name is derived from the folder/filename), a `<RecordType>` **must
453
+ include a `<fullName>`** element — the record type's developer name (e.g. `<fullName>Internal</fullName>`),
454
+ matching the filename `Internal.recordType-meta.xml`. It's bare (no object prefix); the object
455
+ comes from the `objects/<Object>/` folder path.
456
+
457
+ ### ⭐ STEP 1 — Decide if this object needs a BusinessProcess (do this BEFORE writing files)
458
+
459
+ A record type on a **BusinessProcess-gated object — Opportunity, Lead, Case, or Solution —
460
+ will NOT deploy without a `<businessProcess>` reference**, even when it only filters a *custom*
461
+ picklist and never touches the standard status field (`Required field is missing: businessProcess`).
462
+ **Every other object — all custom objects (`*__c`) and other standard objects like Account or
463
+ Contact — needs NO BusinessProcess.** Decide first:
464
+
465
+ | Object | BusinessProcess? | Files to emit |
466
+ |---|---|---|
467
+ | Opportunity / Lead / Case / Solution | **REQUIRED** | BusinessProcess file **+** RecordType that references it (two files) |
468
+ | Custom object (`*__c`), Account, Contact, everything else | **None** | RecordType alone (one file) |
469
+
470
+ For the gated four, a suitable BusinessProcess may already exist in the org — reference its
471
+ developer name instead of generating a new one (confirm via the grounding MCP's `search_metadata`
472
+ if available; otherwise generate a minimal one). For everything else, **do not invent a
473
+ BusinessProcess** — adding one to a custom-object record type is wrong.
474
+
475
+ #### ✅ CORRECT — Opportunity "Enterprise" record type, two deployable files
476
+
477
+ ```xml
478
+ <!-- File 1: objects/Opportunity/businessProcesses/Enterprise_Sales_Process.businessProcess-meta.xml -->
479
+ <BusinessProcess xmlns="http://soap.sforce.com/2006/04/metadata">
480
+ <fullName>Enterprise_Sales_Process</fullName> <!-- BARE — see the api-context translation note below -->
481
+ <isActive>true</isActive>
482
+ <values><fullName>Prospecting</fullName></values> <!-- these are Opportunity STAGE (StageName) values, NOT Status__c — the BP governs the standard stage picklist. Do NOT add <default> (fails: "Cannot specify a default on: Opportunity") -->
483
+ <values><fullName>Qualification</fullName></values>
484
+ <values><fullName>Closed Won</fullName></values>
485
+ <values><fullName>Closed Lost</fullName></values>
486
+ </BusinessProcess>
487
+ ```
488
+
489
+ > ⛔ **`<fullName>` is BARE in the source file — strip the entity prefix that api-context gives you.**
490
+ > The metadata grounding / api-context for `BusinessProcess` reports the fullName in its **API
491
+ > form**, entity-qualified: `Opportunity.Enterprise_Sales_Process`. That is correct for the API —
492
+ > but in the **source/DX-format file you author**, the entity is already conveyed by the
493
+ > `objects/Opportunity/` folder path, so the `<fullName>` element is the **bare process name**:
494
+ > `Enterprise_Sales_Process`, NOT `Opportunity.Enterprise_Sales_Process`. (Same API-vs-source split
495
+ > as the GlobalValueSet `__gvs` suffix in §1.) Writing the entity-qualified form makes the
496
+ > RecordType's bare `<businessProcess>Enterprise_Sales_Process</businessProcess>` reference fail to
497
+ > resolve → `no BusinessProcess named Opportunity.Enterprise_Sales_Process found`. **When you pull
498
+ > the BP name from api-context and it looks like `Opportunity.X`, write `X` in the file.** The BP
499
+ > file's `<fullName>` and the RecordType's `<businessProcess>` must be the identical bare string.
500
+
501
+ ```xml
502
+ <!-- File 2: objects/Opportunity/recordTypes/Enterprise.recordType-meta.xml -->
503
+ <RecordType xmlns="http://soap.sforce.com/2006/04/metadata">
504
+ <fullName>Enterprise</fullName>
505
+ <label>Enterprise</label>
506
+ <active>true</active>
507
+ <businessProcess>Enterprise_Sales_Process</businessProcess> <!-- REQUIRED; must precede <picklistValues> -->
508
+ <picklistValues>
509
+ <picklist>Status__c</picklist>
510
+ <values>
511
+ <fullName>Qualified</fullName>
512
+ <default>true</default>
513
+ </values>
514
+ <values>
515
+ <fullName>Closed Won</fullName>
516
+ <default>false</default>
517
+ </values>
518
+ </picklistValues>
519
+ </RecordType>
520
+ ```
521
+
522
+ #### ❌ INCORRECT — BusinessProcess file emitted but NOT referenced (most common failure)
523
+
524
+ ```xml
525
+ <!-- File 1 (businessProcesses/Enterprise_Sales_Process...) was generated correctly, BUT -->
526
+ <!-- File 2, the RecordType, FORGOT the <businessProcess> element: -->
527
+ <RecordType xmlns="http://soap.sforce.com/2006/04/metadata">
528
+ <fullName>Enterprise</fullName>
529
+ <active>true</active>
530
+ <label>Enterprise</label>
531
+ <!-- WRONG: no <businessProcess> here → the BP file is orphaned and the deploy fails -->
532
+ <picklistValues> ... </picklistValues>
533
+ </RecordType>
534
+ ```
535
+
536
+ **Error:** `Required field is missing: businessProcess`. Generating the BusinessProcess file is
537
+ only half the job — the `<RecordType>` MUST also carry the `<businessProcess>NameMatchingTheFile</businessProcess>`
538
+ element. Both, every time, for Opportunity/Lead/Case/Solution.
539
+
540
+ **BusinessProcess gotchas (these block deployment):**
541
+ - **`<fullName>` is BARE — never object-qualified.** Inside
542
+ `objects/Opportunity/businessProcesses/Enterprise_Sales_Process.businessProcess-meta.xml`, the
543
+ `<fullName>` is just `Enterprise_Sales_Process` — NOT `Opportunity.Enterprise_Sales_Process`.
544
+ The object comes from the folder path. Qualifying it (`<fullName>Opportunity.Enterprise_Sales_Process</fullName>`)
545
+ makes the RecordType's bare `<businessProcess>Enterprise_Sales_Process</businessProcess>`
546
+ reference unresolvable → `no BusinessProcess named Opportunity.Enterprise_Sales_Process found`.
547
+ The BP file's `<fullName>` and the RecordType's `<businessProcess>` value must be the **same
548
+ bare string**.
549
+ - **Two coupled parts** — (1) the `businessProcesses/<Name>.businessProcess-meta.xml` file AND
550
+ (2) a `<businessProcess><Name></businessProcess>` element inside the `<RecordType>`. The
551
+ developer name must match. Doing only one is the #1 deploy failure.
552
+ - **Element order** — `<businessProcess>` must appear **before** `<picklistValues>` inside
553
+ `<RecordType>` (it follows `<active>`). Out-of-order elements fail schema validation.
554
+ - **No `<default>` on Opportunity BP values** — specifying `<default>` on a `<values>` entry
555
+ fails with `Cannot specify a default on: Opportunity`. (Lead / Case / Solution DO allow a
556
+ BP default; Opportunity is the exception.)
557
+
558
+ ### Deployment ordering
559
+
560
+ ```text
561
+ GlobalValueSet / StandardValueSet (if the field draws from a value set)
562
+
563
+ CustomField (the picklist field, with its full value set)
564
+ BusinessProcess (REQUIRED for Opportunity/Lead/Case/Solution record types)
565
+
566
+ RecordType (filters the field's values; references the BusinessProcess)
567
+ ```
568
+
569
+ - The CustomField (and ALL the values the record type references) MUST deploy **before** the
570
+ RecordType, or you get `Cannot find the picklist value: <X>`.
571
+ - For Opportunity/Lead/Case/Solution, the `<businessProcess>` must exist (same package or
572
+ already in the org) before the RecordType.
573
+
574
+ ### ⭐ UI-sync gotcha — values may not auto-display after API deploy
575
+
576
+ When `<picklistValues>` are loaded via the Metadata API, the values are correctly associated
577
+ under the hood, **but they may not automatically appear as "Selected Values" in the Record
578
+ Type editing screen in Setup.** The API deploy succeeds; this is a platform UI-sync
579
+ limitation, not a deployment error. Tell the user they may need to: **Setup → Object Manager →
580
+ [Object] → Record Types → [Record Type] → Edit next to the picklist → move values into
581
+ Selected Values → Save.** Always call this out when delivering record-type picklist filtering.
582
+
583
+ ### Common failures
584
+
585
+ | Error / Symptom | Cause | Fix |
586
+ |---|---|---|
587
+ | `Required field is missing: businessProcess` | Opportunity/Lead/Case/Solution record type without a `<businessProcess>` | Add a BusinessProcess (deploy it first or reference an existing one) |
588
+ | `Cannot specify a default on: Opportunity` | `<default>` set on an Opportunity BusinessProcess value | Remove `<default>` from the Opportunity BP `<values>` |
589
+ | `Cannot find the picklist value: <X>` | A value in `<picklistValues>` doesn't exist on the field | Deploy the field with that value first; check spelling/case |
590
+ | Filtered values still show full set in UI | API-loaded values not promoted to Selected Values | Perform the manual Setup step above |