@salesforce/afv-skills 1.66.0 → 1.68.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 (165) hide show
  1. package/README.md +55 -5
  2. package/package.json +2 -4
  3. package/skills/agentforce-offline-experimentation-run/SKILL.md +26 -49
  4. package/skills/agentforce-offline-experimentation-run/scripts/bt_compare.py +81 -0
  5. package/skills/agentforce-offline-experimentation-run/scripts/bt_fetch.py +358 -0
  6. package/skills/agentforce-offline-experimentation-run/scripts/bt_patch_agent.py +110 -0
  7. package/skills/agentforce-offline-experimentation-run/scripts/btlib/__init__.py +34 -0
  8. package/skills/agentforce-offline-experimentation-run/scripts/btlib/agentpatch.py +483 -0
  9. package/skills/agentforce-offline-experimentation-run/scripts/btlib/agentsrc.py +565 -0
  10. package/skills/agentforce-offline-experimentation-run/scripts/btlib/cache.py +95 -0
  11. package/skills/agentforce-offline-experimentation-run/scripts/btlib/compare.py +617 -0
  12. package/skills/agentforce-offline-experimentation-run/scripts/btlib/fetch.py +1012 -0
  13. package/skills/agentforce-offline-experimentation-run/scripts/btlib/judge.py +148 -0
  14. package/skills/agentforce-offline-experimentation-run/scripts/btlib/messages.py +92 -0
  15. package/skills/agentforce-offline-experimentation-run/scripts/btlib/patch.py +327 -0
  16. package/skills/agentforce-offline-experimentation-run/scripts/btlib/redact.py +40 -0
  17. package/skills/agentforce-offline-experimentation-run/scripts/btlib/results.py +288 -0
  18. package/skills/agentforce-offline-experimentation-run/scripts/btlib/scoring.py +340 -0
  19. package/skills/agentforce-offline-experimentation-run/scripts/btlib/sfap.py +238 -0
  20. package/skills/agentforce-offline-experimentation-run/scripts/btlib/splits.py +136 -0
  21. package/skills/agentforce-offline-experimentation-run/scripts/btlib/stdm.py +98 -0
  22. package/skills/agentforce-offline-experimentation-run/scripts/btlib/tokens.py +173 -0
  23. package/skills/agentforce-offline-experimentation-run/scripts/btlib/units.py +199 -0
  24. package/skills/agentforce-offline-experimentation-run/scripts/btlib/versions.py +194 -0
  25. package/skills/agentforce-offline-experimentation-run/scripts/build_report.py +366 -378
  26. package/skills/agentforce-offline-experimentation-run/scripts/resolve-token.sh +14 -4
  27. package/skills/agentforce-offline-experimentation-run/scripts/sfap_replay.py +472 -796
  28. package/skills/commerce-react-storefront-create/SKILL.md +350 -0
  29. package/skills/consumer-goods-promotion-bo-api-deploy/SKILL.md +2 -2
  30. package/skills/consumer-goods-promotion-bo-api-deploy/references/generate-and-wire.md +28 -16
  31. package/skills/consumer-goods-promotion-bo-api-deploy/references/smoke-and-verify.md +18 -1
  32. package/skills/dx-lifecycle-center/SKILL.md +5 -2
  33. package/skills/dx-lifecycle-center/assets/widgets/connect-connected/connect-connected.json +65 -0
  34. package/skills/dx-lifecycle-center/assets/widgets/connect-connected/schema.json +32 -0
  35. package/skills/dx-lifecycle-center/assets/widgets/connect-sign-in/connect-sign-in.json +57 -0
  36. package/skills/dx-lifecycle-center/assets/widgets/connect-sign-in/schema.json +21 -0
  37. package/skills/dx-lifecycle-center/examples/workflows.md +20 -6
  38. package/skills/dx-lifecycle-center/references/connect-org.md +21 -2
  39. package/skills/dx-lifecycle-center/references/deploy.md +2 -2
  40. package/skills/dx-lifecycle-center/references/list-orgs.md +1 -1
  41. package/skills/dx-lifecycle-center/scripts/card-policy.jq +71 -0
  42. package/skills/dx-lifecycle-center/scripts/fill-widget.jq +29 -0
  43. package/skills/dx-lifecycle-center/scripts/widget.sh +28 -0
  44. package/skills/dx-org-devhub-configure/SKILL.md +85 -84
  45. package/skills/dx-org-devhub-configure/examples/status-output.md +25 -2
  46. package/skills/dx-org-devhub-configure/scripts/devhub.sh +265 -140
  47. package/skills/dx-org-devhub-configure/scripts/test-devhub.sh +100 -15
  48. package/skills/dx-packaging-move-to-2gp-migrate/SKILL.md +89 -0
  49. package/skills/dx-packaging-move-to-2gp-migrate/references/api-operations.md +164 -0
  50. package/skills/dx-scratch-def-configure/SKILL.md +163 -0
  51. package/skills/dx-scratch-def-configure/examples/confirm-card.md +53 -0
  52. package/skills/dx-scratch-def-configure/examples/report-recipes.md +100 -0
  53. package/skills/dx-scratch-def-configure/references/features.json +3270 -0
  54. package/skills/dx-scratch-def-configure/references/project-scratch-def.schema.json +1841 -0
  55. package/skills/dx-scratch-def-configure/references/settings-map.json +682 -0
  56. package/skills/dx-scratch-def-configure/scripts/lib_scratch_def.py +1306 -0
  57. package/skills/dx-scratch-def-configure/scripts/requirements.txt +3 -0
  58. package/skills/dx-scratch-def-configure/scripts/scrape_config_values.py +848 -0
  59. package/skills/education-cloud-domain-configure/SKILL.md +22 -24
  60. package/skills/education-cloud-domain-configure/references/dependent-features.md +9 -0
  61. package/skills/education-cloud-domain-configure/references/domain-features.md +15 -0
  62. package/skills/education-cloud-domain-configure/references/gotchas-extended.md +8 -0
  63. package/skills/education-cloud-domain-configure/references/setup-widgets.md +123 -0
  64. package/skills/education-cloud-multi-campus-configure/SKILL.md +1 -1
  65. package/skills/education-cloud-student-recruitment-agent-configure/SKILL.md +1 -1
  66. package/skills/experience-design-validate/SKILL.md +1 -1
  67. package/skills/experience-search-coordinate/SKILL.md +19 -13
  68. package/skills/experience-search-coordinate/references/content-route.md +79 -1
  69. package/skills/experience-search-coordinate/references/media-route.md +30 -4
  70. package/skills/experience-ui-bundle-features-generate/SKILL.md +1 -1
  71. package/skills/experience-ui-bundle-mfa-configure/SKILL.md +1 -1
  72. package/skills/field-service-data-capture-migrate/SKILL.md +1 -1
  73. package/skills/platform-apex-generate/SKILL.md +14 -11
  74. package/skills/platform-apex-test-generate/SKILL.md +2 -1
  75. package/skills/platform-datamask-run/SKILL.md +52 -71
  76. package/skills/platform-datamask-run/references/api-surface.md +10 -4
  77. package/skills/platform-datamask-run/references/policy-authoring.md +56 -7
  78. package/skills/platform-datamask-run/references/run-and-abort.md +17 -10
  79. package/skills/platform-datamask-run/scripts/poll-job.sh +15 -25
  80. package/skills/platform-dataspace-access-configure/SKILL.md +19 -1
  81. package/skills/platform-metadata-deploy/README.md +1 -1
  82. package/skills/platform-metadata-deploy/SKILL.md +114 -15
  83. package/skills/platform-metadata-deploy/references/agent-deployment-guide.md +3 -4
  84. package/skills/platform-metadata-deploy/references/orchestration.md +2 -3
  85. package/skills/platform-metadata-discovery-get/SKILL.md +185 -0
  86. package/skills/platform-metadata-discovery-get/references/api-map.md +25 -0
  87. package/skills/platform-metadata-discovery-get/references/h360-routes.md +30 -0
  88. package/skills/platform-metadata-discovery-get/references/scoped-soql.md +52 -0
  89. package/skills/platform-metadata-grounding-get/SKILL.md +170 -0
  90. package/skills/platform-policy-rule-generate/SKILL.md +84 -232
  91. package/skills/platform-policy-rule-generate/references/condition-model.md +47 -0
  92. package/skills/platform-policy-rule-generate/references/condition-templates.md +89 -0
  93. package/skills/platform-policy-rule-generate/references/conjunction-compiler.md +25 -0
  94. package/skills/platform-policy-rule-generate/references/conjunction-expression.md +22 -0
  95. package/skills/platform-policy-rule-generate/references/consumer-all.md +9 -0
  96. package/skills/platform-policy-rule-generate/references/consumer-datacloud-ui.md +91 -0
  97. package/skills/platform-policy-rule-generate/references/deploy-errors.md +24 -36
  98. package/skills/platform-policy-rule-generate/references/examples/ExistsJoinRLS/package.xml +12 -0
  99. package/skills/platform-policy-rule-generate/references/examples/ExistsJoinRLS/policyRuleDefinitionSets/ExistsJoinRLS.policyRuleDefinitionSet +6 -0
  100. package/skills/platform-policy-rule-generate/references/examples/ExistsJoinRLS/policyRuleDefinitions/ExistsJoinRLS_Rule_1.policyRuleDefinition +91 -0
  101. package/skills/platform-policy-rule-generate/references/examples/FieldReadDeny/package.xml +12 -0
  102. package/skills/platform-policy-rule-generate/references/examples/FieldReadDeny/policyRuleDefinitionSets/FieldReadDeny.policyRuleDefinitionSet +6 -0
  103. package/skills/platform-policy-rule-generate/references/examples/FieldReadDeny/policyRuleDefinitions/FieldReadDeny_Rule_1.policyRuleDefinition +72 -0
  104. package/skills/platform-policy-rule-generate/references/examples/LastCharactersFieldMasking/package.xml +12 -0
  105. package/skills/platform-policy-rule-generate/references/examples/LastCharactersFieldMasking/policyRuleDefinitionSets/LastCharactersFieldMasking.policyRuleDefinitionSet +6 -0
  106. package/skills/platform-policy-rule-generate/references/examples/LastCharactersFieldMasking/policyRuleDefinitions/LastCharactersFieldMasking_Rule_1.policyRuleDefinition +77 -0
  107. package/skills/platform-policy-rule-generate/references/examples/PrincipalFieldMatchRLS/package.xml +12 -0
  108. package/skills/platform-policy-rule-generate/references/examples/PrincipalFieldMatchRLS/policyRuleDefinitionSets/PrincipalFieldMatchRLS.policyRuleDefinitionSet +6 -0
  109. package/skills/platform-policy-rule-generate/references/examples/PrincipalFieldMatchRLS/policyRuleDefinitions/PrincipalFieldMatchRLS_Rule_1.policyRuleDefinition +77 -0
  110. package/skills/platform-policy-rule-generate/references/examples/TaggedObjectAccess/package.xml +12 -0
  111. package/skills/platform-policy-rule-generate/references/examples/TaggedObjectAccess/policyRuleDefinitionSets/TaggedObjectAccess.policyRuleDefinitionSet +4 -0
  112. package/skills/platform-policy-rule-generate/references/examples/TaggedObjectAccess/policyRuleDefinitions/TaggedObjectAccess_Rule_1.policyRuleDefinition +65 -0
  113. package/skills/platform-policy-rule-generate/references/headless-transport.md +87 -0
  114. package/skills/platform-policy-rule-generate/references/policy-schema-full.md +17 -10
  115. package/skills/platform-policy-rule-generate/references/policy-shapes.md +74 -0
  116. package/skills/platform-policy-rule-generate/references/principal-expression.md +31 -0
  117. package/skills/platform-policy-rule-generate/references/reference-resolution.md +51 -0
  118. package/skills/platform-policy-rule-generate/references/resource-expression.md +48 -0
  119. package/skills/platform-policy-rule-generate/references/runtime-context.md +9 -0
  120. package/skills/platform-policy-rule-generate/references/templates-access.md +11 -9
  121. package/skills/platform-policy-rule-generate/references/templates-advanced.md +4 -2
  122. package/skills/platform-policy-rule-generate/references/templates-record.md +37 -22
  123. package/skills/platform-policy-rule-generate/references/templates-transform.md +10 -8
  124. package/skills/platform-policy-rule-generate/references/templates.md +2 -2
  125. package/skills/platform-policy-rule-generate/references/ui-compatibility.md +35 -17
  126. package/skills/platform-report-generate/SKILL.md +9 -4
  127. package/skills/platform-report-generate/references/chart-types.md +26 -2
  128. package/skills/platform-report-generate/references/column-names.md +43 -0
  129. package/skills/platform-report-generate/references/errors-and-troubleshooting.md +1 -1
  130. package/skills/platform-report-generate/references/verification-checklist.md +10 -2
  131. package/skills/platform-value-set-generate/SKILL.md +19 -19
  132. package/skills/platform-widget-generate/SKILL.md +25 -51
  133. package/skills/platform-widget-generate/examples/formulas.json +19 -2
  134. package/skills/platform-widget-generate/examples/localized-labels.json +57 -0
  135. package/skills/platform-widget-generate/references/widget-actions.md +29 -0
  136. package/skills/platform-widget-generate/references/widget-bundle-validation.md +1 -0
  137. package/skills/platform-widget-generate/references/widget-formulas.md +24 -7
  138. package/skills/platform-widget-generate/references/widget-gotchas.md +10 -0
  139. package/skills/platform-widget-generate/references/widget-labels.md +78 -0
  140. package/skills/platform-widget-generate/references/widget-styling.md +12 -0
  141. package/skills/sales-call-scoring-configure/SKILL.md +17 -10
  142. package/skills/sales-call-scoring-configure/scripts/enable-call-scoring.sh +55 -33
  143. package/skills/service-digital-engagement-channel-configure/SKILL.md +11 -7
  144. package/skills/service-digital-engagement-channel-configure/assets/messaging_channel_template.xml +33 -0
  145. package/skills/service-digital-engagement-channel-configure/references/channel_settings.md +123 -16
  146. package/skills/service-digital-engagement-deployment-configure/SKILL.md +37 -100
  147. package/skills/service-digital-engagement-deployment-configure/assets/esd_web_update_template.xml +83 -8
  148. package/skills/service-digital-engagement-deployment-configure/examples/esd_web_prechat_fields.xml +74 -0
  149. package/skills/service-digital-engagement-deployment-configure/references/connect_api_creation.md +13 -3
  150. package/skills/service-digital-engagement-deployment-configure/references/deployment_settings.md +13 -78
  151. package/skills/service-digital-engagement-deployment-configure/references/onboarding_contract.md +5 -6
  152. package/skills/service-digital-engagement-deployment-configure/references/prechat_forms.md +245 -0
  153. package/skills/service-itsm-agentic-setup-incident-management/SKILL.md +164 -120
  154. package/skills/service-itsm-agentic-setup-incident-management/examples/output-templates.md +61 -37
  155. package/skills/service-itsm-agentic-setup-incident-management/references/audit-tracking.md +42 -0
  156. package/skills/service-itsm-agentic-setup-incident-management/references/broadcast-communications.md +23 -0
  157. package/skills/service-itsm-agentic-setup-incident-management/references/email-to-incident.md +23 -0
  158. package/skills/service-itsm-agentic-setup-incident-management/references/incident-dashboards.md +25 -0
  159. package/skills/service-itsm-agentic-setup-incident-management/references/incident-persona-psg.md +30 -146
  160. package/skills/service-itsm-agentic-setup-incident-management/references/incident-preferences.md +32 -136
  161. package/skills/service-itsm-agentic-setup-incident-management/references/major-incident-management.md +32 -155
  162. package/skills/service-itsm-agentic-setup-incident-management/references/manage-incidents-with-ai.md +45 -0
  163. package/skills/service-itsm-agentic-setup-incident-management/references/priority-matrix.md +32 -0
  164. package/skills/service-itsm-agentic-setup-incident-management/references/service-mgmt-privilege.md +30 -140
  165. package/skills/service-itsm-agentic-setup-incident-management/references/sla-milestones.md +110 -0
@@ -0,0 +1,48 @@
1
+ # Resource Expressions
2
+
3
+ Use `resourceExpression` when the resource-side operand is computed from a projection instead of a direct path. The condition must use `<resourcePath>EXPRESSION</resourcePath>`.
4
+
5
+ A transform argument list is different: it is a top-level `resourceExpression` on the rule, not inside a condition. Use `ARGLIST` exactly as documented in `policy-shapes.md` and the retrieved masking example.
6
+
7
+ The validated RLS join shape is:
8
+
9
+ ```xml
10
+ <conditions>
11
+ <clause>WHEN</clause>
12
+ <operator>EXISTS</operator>
13
+ <policyRuleDefinitionCondition>
14
+ <clause>WHEN</clause>
15
+ <operator>EQUALS</operator>
16
+ <policyRuleValueSet>
17
+ <valueText>${User.Email}</valueText>
18
+ </policyRuleValueSet>
19
+ <resourcePath>RECORDFIELD</resourcePath>
20
+ <valueDomain>RESOURCE_DMO:RESOURCE_FIELD</valueDomain>
21
+ </policyRuleDefinitionCondition>
22
+ <resourceExpression>
23
+ <projection>
24
+ <join>
25
+ <alias>JOIN_ALIAS</alias>
26
+ <predicate>
27
+ <attribute>JOIN_DMO:JOIN_FIELD</attribute>
28
+ <comparator>EQUALS</comparator>
29
+ <on>
30
+ <field>RESOURCE_FIELD</field>
31
+ <resourceAlias>resource</resourceAlias>
32
+ <schema>RESOURCE_DMO</schema>
33
+ </on>
34
+ </predicate>
35
+ <schema>JOIN_DMO</schema>
36
+ </join>
37
+ </projection>
38
+ <type>PROJECTION</type>
39
+ <version>1</version>
40
+ </resourceExpression>
41
+ <resourcePath>EXPRESSION</resourcePath>
42
+ <whereClauseConjunction>1</whereClauseConjunction>
43
+ </conditions>
44
+ ```
45
+
46
+ For a join, define an `<alias>`, a `<schema>`, and a `<predicate>`. `<attribute>` belongs to the joined schema; `<on>` identifies the evaluated resource schema and field. Verify that join keys have compatible types. `whereClauseConjunction` numbers the nested `policyRuleDefinitionCondition` elements from `1`; it does not refer to top-level rule conditions.
47
+
48
+ Do not invent projection structure or substitute a different operator. Start from a retrieved, deployed example for the same relationship shape and change only resolved schema, field, and alias values while preserving which side is joined and which side is the evaluated resource.
@@ -0,0 +1,9 @@
1
+ # Runtime Context
2
+
3
+ Keep three version concepts separate:
4
+
5
+ - `MIN_API_VERSION`: static skill capability floor (`66.0` in the skill metadata).
6
+ - `ORG_API_VERSION`: target org's discovered maximum API version; use it for every API call, manifest, deploy, and retrieve.
7
+ - `EVIDENCE_API_VERSION`: historical version attached to retrieved examples; provenance only.
8
+
9
+ In normal author mode, resolve `ORG_API_VERSION` once from `/services/data`, verify it is at least `MIN_API_VERSION`, and carry it unchanged through the operation. Never copy an evidence version such as `69.0` into authored output unless the target org resolves to that version. Explicit evidence-recreation eval fixtures retain `{API_VERSION}` for harness substitution while recording API 69.0 as provenance in their instructions. Never modify `sfdx-project.json` to set an operation-specific version.
@@ -1,10 +1,12 @@
1
1
  # ACCESS / GOVERNANCE Templates
2
2
 
3
- Each template is a verified shape from a passing test fixture. Copy, then change names/values.
3
+ The GOVERNANCE TupleRead shape is MDAPI persistence-validated. Policy Builder open/save compatibility is not yet validated. The ACCESS examples are older fixture-only shapes retained for explicitly requested API-only metadata.
4
+
5
+ Prefer the complete semantic OLS evidence under `examples/TaggedObjectAccess/` and resolve every target-org value again.
4
6
 
5
7
  ---
6
8
 
7
- ## ACCESS — Simple Permit (no conditions)
9
+ ## API-only ACCESS — Simple Permit (no conditions)
8
10
 
9
11
  Source: `baseSteelthread`
10
12
 
@@ -26,9 +28,9 @@ Source: `baseSteelthread`
26
28
 
27
29
  ---
28
30
 
29
- ## ACCESS / GOVERNANCE — "Objects AND all their fields" via TupleRead (UI-compatible)
31
+ ## GOVERNANCE — "Objects AND all their fields" via TupleRead
30
32
 
31
- Source: see §8.2.1 of policy.md
33
+ Source: `references/examples/TaggedObjectAccess/`
32
34
 
33
35
  Three required pieces:
34
36
  1. `<action>TupleRead</action>` — cascades object-level condition to fields
@@ -54,7 +56,7 @@ Three required pieces:
54
56
  <clause>WHEN</clause>
55
57
  <operator>IS</operator>
56
58
  <policyRuleValueSet>
57
- <valueString>{&quot;t&quot;:&quot;Text&quot;,&quot;v&quot;:&quot;OBJECT&quot;}</valueString>
59
+ <valueText>OBJECT</valueText>
58
60
  </policyRuleValueSet>
59
61
  <resourcePath>ENTITYTYPE</resourcePath>
60
62
  </conditions>
@@ -62,7 +64,7 @@ Three required pieces:
62
64
  <clause>WHEN</clause>
63
65
  <operator>IS</operator>
64
66
  <policyRuleValueSet>
65
- <valueString>{&quot;t&quot;:&quot;Text&quot;,&quot;v&quot;:&quot;FIELD&quot;}</valueString>
67
+ <valueText>FIELD</valueText>
66
68
  </policyRuleValueSet>
67
69
  <resourcePath>ENTITYTYPE</resourcePath>
68
70
  </conditions>
@@ -82,11 +84,11 @@ Three required pieces:
82
84
  </PolicyRuleDefinition>
83
85
  ```
84
86
 
85
- For **deny semantics**: `<effect>Forbid</effect>`. To add "deny unless permission Y", insert a 4th condition with `ASSIGNED_PERMISSIONS_PATH CONTAINS_NONE Y` and use `(AND (OR 1 2) (AND 3) (AND 4))`.
87
+ Do not infer deny semantics from this Permit example. Use a separately retrieved and target-org-validated shape.
86
88
 
87
89
  ---
88
90
 
89
- ## ACCESS — Gated by Tag / Classification / Permission
91
+ ## API-only ACCESS — Gated by Tag / Classification / Permission
90
92
 
91
93
  Source: `conditionTagValidSteelthread`, `conditionClassificationValidClauseSteelthread`, `conditionAssignedPermPathValidSteelthread`
92
94
 
@@ -113,7 +115,7 @@ Source: `conditionTagValidSteelthread`, `conditionClassificationValidClauseSteel
113
115
  <valueReferenceType>CUSTOM_TAG</valueReferenceType>
114
116
  </policyRuleValueSet>
115
117
  </conditions>
116
- <conjunctionExpression>1</conjunctionExpression>
118
+ <conjunctionExpression>(AND 1)</conjunctionExpression>
117
119
  </whenPolicyRuleDefinitionClauseConjunction>
118
120
  </PolicyRuleDefinition>
119
121
  ```
@@ -1,10 +1,12 @@
1
- # Advanced Templates — Multi-Condition, Hierarchy, Unauthorable
1
+ # Advanced Templates — API-only Multi-Condition, Hierarchy, Unauthorable
2
2
 
3
3
  Each template is a verified shape from a passing test fixture. Copy, then change names/values.
4
4
 
5
5
  ---
6
6
 
7
- ## Multi-Condition with Custom Conjunction (AND/OR mix)
7
+ > These examples are API-only exceptions. Do not copy them for the default UI-compatible output without explicit operator confirmation.
8
+
9
+ ## API-only Multi-Condition with Custom Conjunction (AND/OR mix)
8
10
 
9
11
  Source: `conjunctionExpressionSteelthread`
10
12
 
@@ -1,14 +1,16 @@
1
1
  # RECORD Templates
2
2
 
3
- Each template is a verified shape from a passing test fixture. Copy, then change names/values.
3
+ These examples are distilled from retrieved policies. Use them to understand persisted structure, but generate only values published by the target release's MDAPI contract.
4
4
 
5
5
  ---
6
6
 
7
7
  ## RECORD — Basic RLS (record field = user attribute)
8
8
 
9
- Source: `conditionRLSValidSteelthread` (first condition), `conditionStandardIdRLSValidSteelthread`
9
+ Source: `references/examples/PrincipalFieldMatchRLS/`
10
10
 
11
- > **RLS MDAPI round-trip is fragile in real orgs.** Deploy/retrieve can fail with opaque gacks if a DMO field in `<valueDomain>` is not mapped in the org's data streams. Build the rule in the UI first; use MDAPI templates as verification shapes, not first-try authoring. See §8.3 of policy.md.
11
+ > **RLS MDAPI round-trip is fragile in real orgs.** Deploy/retrieve can fail with opaque gacks if a DMO field in `<valueDomain>` is not mapped in the org's data streams. Use read-only metadata inspection to verify the field mapping before generating XML; do not create or edit the rule in Policy Builder from this skill.
12
+
13
+ > `SCALAR_ATTRIBUTE` is a confirmed, deployable, Policy Builder-compatible principal path for record-field-to-principal-attribute comparisons, per DG UI source (this is how the builder itself authors the condition, not established by a per-shape round-trip). Use this template directly in normal author mode.
12
14
 
13
15
  ```xml
14
16
  <?xml version="1.0" encoding="UTF-8"?>
@@ -16,10 +18,10 @@ Source: `conditionRLSValidSteelthread` (first condition), `conditionStandardIdRL
16
18
  <action>Read</action>
17
19
  <category>RECORD_POLICY_RULE_DEFINITION</category>
18
20
  <effect>Permit</effect>
19
- <label>Rule1</label>
20
- <policyRuleDefinitionSetName>StandardFieldSet3</policyRuleDefinitionSetName>
21
+ <label>Rule 1</label>
22
+ <policyRuleDefinitionSetName>EXACT_SET_NAME</policyRuleDefinitionSetName>
21
23
  <policyRuleResourceDomains>
22
- <resourceDomain>testDMO__dlm</resourceDomain>
24
+ <resourceDomain>EXACT_DMO</resourceDomain>
23
25
  </policyRuleResourceDomains>
24
26
  <principalAuthenticationLevel>INTERNAL</principalAuthenticationLevel>
25
27
  <principalScopeType>ANY</principalScopeType>
@@ -30,46 +32,59 @@ Source: `conditionRLSValidSteelthread` (first condition), `conditionStandardIdRL
30
32
  <conditions>
31
33
  <clause>WHEN</clause>
32
34
  <operator>EQUALS</operator>
35
+ <principalExpression>
36
+ <soqlTarget>
37
+ <select>EXACT_USER_FIELD</select>
38
+ </soqlTarget>
39
+ <type>SOQLTARGETLISTEXPR</type>
40
+ <version>1</version>
41
+ </principalExpression>
33
42
  <resourcePath>RECORDFIELD</resourcePath>
34
- <valueDomain>testDMO__dlm:name__c</valueDomain>
35
- <valuePrincipalPath>USER_ID</valuePrincipalPath>
43
+ <valueDomain>EXACT_DMO:EXACT_FIELD</valueDomain>
44
+ <valuePrincipalPath>SCALAR_ATTRIBUTE</valuePrincipalPath>
36
45
  </conditions>
37
- <conjunctionExpression>1</conjunctionExpression>
46
+ <conjunctionExpression>(AND 1)</conjunctionExpression>
38
47
  </whenPolicyRuleDefinitionClauseConjunction>
39
48
  </PolicyRuleDefinition>
40
49
  ```
41
50
 
42
- For literal-value RLS (e.g. `record.field == 'X'`), use `<policyRuleValueSet><valueString>X</valueString></policyRuleValueSet>` instead of `<valuePrincipalPath>`.
43
-
44
- ---
45
-
46
51
  ## RECORD — RLS via PROJECTION Join
47
52
 
48
- Source: `conditionRLSValidSteelthread` (second condition)
53
+ Source: `references/examples/ExistsJoinRLS/`
49
54
 
50
55
  ```xml
51
56
  <conditions>
52
57
  <clause>WHEN</clause>
53
58
  <operator>EXISTS</operator>
54
- <resourcePath>EXPRESSION</resourcePath>
59
+ <policyRuleDefinitionCondition>
60
+ <clause>WHEN</clause>
61
+ <operator>EQUALS</operator>
62
+ <policyRuleValueSet>
63
+ <valueText>${User.Email}</valueText>
64
+ </policyRuleValueSet>
65
+ <resourcePath>RECORDFIELD</resourcePath>
66
+ <valueDomain>RESOURCE_DMO:RESOURCE_FIELD</valueDomain>
67
+ </policyRuleDefinitionCondition>
55
68
  <resourceExpression>
56
- <type>PROJECTION</type>
57
- <version>1</version>
58
69
  <projection>
59
70
  <join>
60
- <schema>testDMO__dlm</schema>
61
- <alias>test 1</alias>
71
+ <alias>JOIN_ALIAS</alias>
62
72
  <predicate>
73
+ <attribute>JOIN_DMO:JOIN_FIELD</attribute>
63
74
  <comparator>EQUALS</comparator>
64
- <attribute>testDMO__dlm:name__c</attribute>
65
75
  <on>
76
+ <field>RESOURCE_FIELD</field>
66
77
  <resourceAlias>resource</resourceAlias>
67
- <schema>testDMO__dlm</schema>
68
- <field>age__c</field>
78
+ <schema>RESOURCE_DMO</schema>
69
79
  </on>
70
80
  </predicate>
81
+ <schema>JOIN_DMO</schema>
71
82
  </join>
72
83
  </projection>
84
+ <type>PROJECTION</type>
85
+ <version>1</version>
73
86
  </resourceExpression>
87
+ <resourcePath>EXPRESSION</resourcePath>
88
+ <whereClauseConjunction>1</whereClauseConjunction>
74
89
  </conditions>
75
90
  ```
@@ -1,6 +1,6 @@
1
1
  # TRANSFORM Templates
2
2
 
3
- Each template is a verified shape from a passing test fixture. Copy, then change names/values.
3
+ The `LAST_N_CHARS_RESOURCE_TRANSFORM` shape is MDAPI persistence-validated in `references/examples/LastCharactersFieldMasking/`. Other transforms in this file are older fixture-only references.
4
4
 
5
5
  ---
6
6
 
@@ -28,7 +28,7 @@ Source: `conditionClassificationValidDataMaskingSteelthread`
28
28
  <operator>IS</operator>
29
29
  <resourcePath>ENTITYTYPE</resourcePath>
30
30
  <policyRuleValueSet>
31
- <valueString>{&quot;t&quot;:&quot;Text&quot;,&quot;v&quot;:&quot;FIELD&quot;}</valueString>
31
+ <valueText>FIELD</valueText>
32
32
  </policyRuleValueSet>
33
33
  </conditions>
34
34
  <conditions>
@@ -54,17 +54,19 @@ Source: `conditionClassificationValidDataMaskingSteelthread`
54
54
  </PolicyRuleDefinition>
55
55
  ```
56
56
 
57
- For parameterized masking (e.g. mask all but first 4 chars):
57
+ Validated `LAST_N_CHARS_RESOURCE_TRANSFORM` argument shape:
58
58
  ```xml
59
- <resourceTransform>ALL_BUT_FIRST_N_CHARS_RESOURCE_TRANSFORM</resourceTransform>
60
59
  <resourceExpression>
61
- <type>ARGLIST</type>
62
- <version>1</version>
63
60
  <transformExpression>
64
61
  <argument>
65
- <type>NUMBER</type>
66
- <value>4</value>
62
+ <type>STRING</type>
63
+ <value>12</value>
67
64
  </argument>
68
65
  </transformExpression>
66
+ <type>ARGLIST</type>
67
+ <version>1</version>
69
68
  </resourceExpression>
69
+ <resourceTransform>LAST_N_CHARS_RESOURCE_TRANSFORM</resourceTransform>
70
70
  ```
71
+
72
+ Do not infer argument type or count for another transform.
@@ -1,10 +1,10 @@
1
1
  # Policy Templates — Index
2
2
 
3
- Each template is a verified shape from a passing test fixture. Pick the file matching the category you need.
3
+ Evidence levels differ by file. Prefer API 69.0 retrieved examples for OLS, FLS deny, masking, and RLS; treat remaining templates as fixture-only references that require target-org validation.
4
4
 
5
5
  | File | What's inside |
6
6
  |------|---------------|
7
7
  | [`templates-access.md`](templates-access.md) | ACCESS and GOVERNANCE: simple Permit, TupleRead "objects + all fields", tag/classification/permission gates |
8
8
  | [`templates-record.md`](templates-record.md) | RECORD: basic RLS (record field = user attribute), RLS via PROJECTION join |
9
- | [`templates-transform.md`](templates-transform.md) | TRANSFORM: field masking with permission + classification gates, parameterized masking (ARGLIST) |
9
+ | [`templates-transform.md`](templates-transform.md) | TRANSFORM: field masking gates and validated `LAST_N_CHARS` ARGLIST shape |
10
10
  | [`templates-advanced.md`](templates-advanced.md) | Multi-condition with custom conjunction (AND/OR mix), hierarchy traversal, IDENTIFIED_RECORD (not authorable via MDAPI) |
@@ -1,8 +1,12 @@
1
1
  # UI Compatibility — Data Governance Policy Builder
2
2
 
3
- The Data Governance Policy Builder edits a **strict subset** of the MDAPI. Anything outside that subset must be maintained via MDAPI/Tooling for the policy's lifetime — admins cannot open it in the builder without silent data loss or a hard crash.
3
+ The Data Governance Policy Builder edits a **strict subset** of the MDAPI. Anything outside that subset must be maintained through the MDAPI package path for the policy's lifetime — admins cannot open it in the builder without silent data loss or a hard crash.
4
4
 
5
- > **Default goal**: produce UI-compatible policies. Only fall back to API-only after asking the operator and getting explicit confirmation.
5
+ > **Default goal**: produce policies that can eventually be validated in Policy Builder. `<builderCompatible>` and `<builderValidated>` are both server-managed fields — the server sets them on save/create, authoring either one in generated XML has no effect, and authoring `true` is never legitimate regardless of how many items on this checklist a shape satisfies. Omit both. Only an actual Policy Builder open/save/retrieve comparison can establish UI compatibility for a specific shape.
6
+
7
+ > **Evidence boundary:** MDAPI dry-run, deploy, and retrieve prove metadata validity and persistence. They do not prove that Policy Builder can open and save the policy without normalization or loss. A retrieved set with `<builderCompatible>false</builderCompatible>` is persisted-shape evidence only.
8
+
9
+ > **ACCESS distinction:** An OR-of-ENTITYTYPE discriminator prevents the builder crash for object-level ACCESS-shaped rules, but ACCESS categories still do not round-trip as ACCESS; the builder rewrites them to GOVERNANCE. Treat explicitly requested ACCESS output as API-only and record that status in the description or an XML comment, not in compatibility fields.
6
10
 
7
11
  ---
8
12
 
@@ -31,7 +35,7 @@ The Data Governance Policy Builder edits a **strict subset** of the MDAPI. Anyth
31
35
 
32
36
  **Top-level conjunction**: only `<whenPolicyRuleDefinitionClauseConjunction>`. The UI forces `<unlessPolicyRuleDefinitionClauseConjunction>` to `null` on save.
33
37
 
34
- **Conjunction expression**: the UI builds `(AND …)` of up to four sections dispatched by path type. A pure flat `(OR 1 2)` at the top level triggers `// ERROR: Unsupported rule!` — rule silently dropped. `OR` only round-trips inside a single section's group.
38
+ **Conjunction expression**: the UI builds one top-level `(AND …)` from typed sections dispatched by path type. Conditions are not combined as one undifferentiated list. Put all conditions for the same UI section into that section's local group, then combine the non-empty section groups under the top-level `AND`. A pure flat `(OR 1 2)` at the top level triggers `// ERROR: Unsupported rule!` — rule silently dropped. `OR` only round-trips inside a single section's group.
35
39
 
36
40
  **Path types per UI section:**
37
41
 
@@ -45,6 +49,16 @@ The Data Governance Policy Builder edits a **strict subset** of the MDAPI. Anyth
45
49
 
46
50
  Any other path type → condition silently ignored when UI rebuilds the rule.
47
51
 
52
+ **Required grouping examples**:
53
+
54
+ - Two classifications that are alternatives belong in one Tag / Classification group: `(OR 1 2)`.
55
+ - A permission condition belongs in the Users / Permission group: `(AND 3)`.
56
+ - The complete policy expression combines those section groups: `(AND (OR 1 2) (AND 3))`.
57
+ - If the policy also has object/field entity discriminators, add a separate Entity Type group, for example `(AND (OR 1 2) (AND 3) (OR 4 5))`.
58
+ - A record-field or join condition belongs in the RLS rule criteria group; it must not be placed directly beside a classification condition at the top level.
59
+
60
+ The exact condition numbers depend on final document order. The invariant is section-local grouping followed by a top-level `AND`, not the example numbers.
61
+
48
62
  **Operators per path**:
49
63
  - Tag/Classification: `CONTAINS_ANY`, `CONTAINS_NONE`. (`CONTAINS_ALL` exists in schema but not offered in dropdowns)
50
64
  - Permission: `CONTAINS_ANY` (Permit) / `CONTAINS_NONE` (Forbid/Transform)
@@ -68,33 +82,36 @@ When the UI saves, it auto-injects these — if your hand-authored XML omits the
68
82
  | `actions` | only first action kept |
69
83
  | `policyRuleResourceDomains` | only first `<resourceDomain>` kept |
70
84
 
85
+ `policyRuleResourceDomains` scopes a **RECORD (RLS)** rule to the named object; it does **not** confine a `GOVERNANCE` (OLS) rule, whose entity-type conditions match every object, and it is **not** a condition — every renderable rule still needs at least one resource `<conditions>`. To scope read access to one named object, author RLS with a row criterion — see `policy-shapes.md` shape-selection.
86
+
71
87
  ---
72
88
 
73
89
  ## The Non-Round-Trip Checklist
74
90
 
75
91
  The policy will **not** round-trip through the UI without data loss or silent failure if **any** of the following is true:
76
92
 
93
+ - [ ] **No resource-side condition present** — zero `<conditions>`, or only principal conditions (`ASSIGNED_PERMISSIONS_PATH` / `SCALAR_ATTRIBUTE`) and no resource condition (`ENTITYTYPE` / `TAG` / `CLASSIFICATION` / `RECORDFIELD` / `EXPRESSION` / `DATASPACE`). Every renderable rule needs ≥1 resource condition; `policyRuleResourceDomains` does not count. Not deployable/renderable — see `policy-shapes.md`.
77
94
  - [ ] `category` is `ACCESS_POLICY_RULE_DEFINITION` or `IDENTIFIED_RECORD_POLICY_RULE_DEFINITION`
78
95
  - [ ] `ruleConsumer` ≠ `DATACLOUD`
79
96
  - [ ] More than one `<action>`, or action is not `Read` / `TupleRead`
80
- - [ ] **No top-level `resourcePath=ENTITYTYPE` discriminator group** for ACCESS/GOVERNANCE rules — this causes a **hard crash** (`Cannot use 'in' operator to search for 'Permit' in undefined`), not a graceful degradation. A `TupleRead` rule without the OR-of-ENTITYTYPE clause still deploys and works at runtime — the crash is UI-only.
97
+ - [ ] **No top-level `resourcePath=ENTITYTYPE` discriminator group** for ACCESS/GOVERNANCE rules — this causes a **hard crash** (`Cannot use 'in' operator to search for 'Permit' in undefined`), not a graceful degradation. OLS uses an `(OR OBJECT FIELD)` group; FLS uses `FIELD` only. A `TupleRead` OLS rule without its OR group still deploys and works at runtime — the crash is UI-only.
81
98
  - [ ] **Bare top-level condition index** in `<conjunctionExpression>` (e.g. `3` instead of `(AND 3)`) — causes crash in `buildCriteria` (`param.params.map(...)` = `undefined.map()`)
82
99
  - [ ] More than one `<resourceDomain>`
83
100
  - [ ] An `<unlessPolicyRuleDefinitionClauseConjunction>` block present
84
101
  - [ ] Any `<conditions>` uses `<clause>UNLESS</clause>`
85
102
  - [ ] `<conjunctionExpression>` uses top-level `OR` (e.g. `(OR 1 2)`)
86
- - [ ] `<principalPath>` other than `ASSIGNED_PERMISSIONS_PATH` (user ID etc. may appear only inside SOQL `${User.X}` substitutions)
103
+ - [ ] `<principalPath>` other than `ASSIGNED_PERMISSIONS_PATH` or `SCALAR_ATTRIBUTE` (paired with a `SOQLTARGETLISTEXPR` `principalExpression`) — other values such as raw user ID may appear only inside SOQL `${User.X}` substitutions
87
104
  - [ ] `<resourcePath>` other than `TAG`, `CLASSIFICATION`, `DATASPACE`, `RECORDFIELD`, `EXPRESSION`, `ENTITYTYPE`
88
105
  - [ ] `<valuePrincipalPath>` is not one of `USER_ID`, `USER_ROLE_ID`, `ORGANIZATION_ID`, `SCALAR_ATTRIBUTE`, `PLURAL_ATTRIBUTE` (with `${User.X}` expression)
89
106
  - [ ] `<contextPath>` other than `SESSION_DATASPACE`
90
107
  - [ ] Operator is `HIERARCHICALLY_BELOW`, `IN`, or `CONTAINS_ALL`
91
108
  - [ ] `<valueReferenceType>` is `HIERARCHY` or `DATASPACE`
92
- - [ ] `<valueString>` is typed JSON other than `{"t":"Text","v":"FIELD"|"RECORD"|"OBJECT"}` or `{"t":"Boolean","v":…}` with a UI-recognized boolean field
109
+ - [ ] Entity-type conditions do not use the MDAPI-authorable `<valueText>OBJECT</valueText>` / `<valueText>FIELD</valueText>` form, or the persisted UI JSON representation is assumed to be authorable without a target-org dry-run
93
110
  - [ ] `<resourceTransform>` not in the masking-category mapped set
94
111
  - [ ] `<resourceExpression>` ARGLIST has multiple arguments
95
112
  - [ ] `<replicated>true</replicated>` in an org with replication frozen
96
113
 
97
- If **none** of the above is true, the policy is **UI-compatible**.
114
+ If none of the above is true, the policy is a candidate for UI validation. It is not proven UI-compatible until Policy Builder opens and saves it and a subsequent MDAPI retrieval shows no semantic loss.
98
115
 
99
116
  > **Important**: The UI shows NO banner when it drops unsupported pieces on save (`// ERROR: Unsupported rule!` comment, no surfaced message). Operator-confirmation is the only line of defense.
100
117
 
@@ -112,16 +129,16 @@ Whenever a request would produce a UI-incompatible policy:
112
129
  | `unless resource has tag X` | `WHEN TAG CONTAINS_NONE X` |
113
130
  | `unless record field = value` | `WHEN RECORDFIELD NOT_EQUALS value` |
114
131
  - Top-level `OR` between two tags → nest inside a tag/classification section group
115
- - Multiple `<action>` → split into multiple rules
132
+ - Multiple `<action>` → reject the request or generate separate one-rule policy sets; one policy set in this skill contains exactly one rule
116
133
 
117
134
  2. **If a UI-compatible rewrite is not possible**, tell the operator:
118
135
  - Which traits make it incompatible (cite items from the checklist above)
119
136
  - That the Data Governance Policy Builder will silently drop unsupported pieces on save with no warning
120
- - That maintenance must happen through MDAPI/Tooling for the policy's lifetime
137
+ - That maintenance must happen through the MDAPI package path for the policy's lifetime
121
138
 
122
139
  3. **Wait for explicit confirmation.** Do not write the file until confirmed.
123
140
 
124
- 4. **On confirmation**, add an in-source marker to `<description>` (or a comment above the rule): `# API-only: not editable in Data Governance Policy Builder. Reasons: <bullets>`. Also set `<builderCompatible>false</builderCompatible>` on the parent set.
141
+ 4. **On confirmation**, add an in-source marker to `<description>` (or a comment above the rule): `# API-only: not editable in Data Governance Policy Builder. Reasons: <bullets>`. Do not author server-managed compatibility fields on the parent set.
125
142
 
126
143
  ---
127
144
 
@@ -130,13 +147,14 @@ Whenever a request would produce a UI-incompatible policy:
130
147
  | Template | UI-compatible? | Notes |
131
148
  |----------|----------------|-------|
132
149
  | Bare permit, no conditions | Partial | Single `<action>Read</action>` only; `ruleConsumer=DATACLOUD`. UI maps ACCESS → Governance on load. |
133
- | Tag / Classification / Permission gate | Yes | `CONTAINS_ANY` / `CONTAINS_NONE` only. Tag refs must resolve in org. |
134
- | Basic RLS (RECORDFIELD = user attribute) | Yes | `USER_ID` / `ORGANIZATION_ID` / `USER_ROLE_ID` round-trips. |
135
- | TupleRead with OR-of-ENTITYTYPE | Yes | The canonical UI-compatible OLS/FLS shape. |
150
+ | GOVERNANCE / RECORD / TRANSFORM tag, classification, or permission gate | Candidate; requires Policy Builder validation | `CONTAINS_ANY` / `CONTAINS_NONE` only. Tag refs must resolve in org. Explicit ACCESS-category variants are API-only because the builder rewrites ACCESS to GOVERNANCE. |
151
+ | Basic RLS (RECORDFIELD = user attribute) | UI-compatible (per DG UI source) | `SCALAR_ATTRIBUTE` is confirmed deployable; UI-compatible per DG UI source (this is how the builder itself authors the condition), not by a per-shape round-trip. |
152
+ | TupleRead with OR-of-ENTITYTYPE | Candidate; requires Policy Builder validation | Persistence-validated OLS/FLS shape. |
136
153
  | IDENTIFIED_RECORD | Not MDAPI-authorable | Must be a runtime RuleProvider. |
137
- | RLS via PROJECTION join | Yes | Single PROJECTION editable. |
138
- | Scalar/plural SOQL principal | Out of MDAPI contract | `SCALAR_ATTRIBUTE`/`PLURAL_ATTRIBUTE` not in `RulePrincipalPathType`. Fixture-only. |
139
- | TRANSFORM with permission + classification | Yes | Use masking-category-mapped transforms only. |
140
- | `(AND 1 2)` multi-condition | Yes (if each section is one of the four UI buckets) | |
154
+ | RLS via PROJECTION join | Requires UI validation | API 69.0 MDAPI persistence is validated for one `EXISTS`/PROJECTION shape; Policy Builder open/save is not. |
155
+ | Scalar SOQL principal | UI-compatible (per DG UI source) | `SCALAR_ATTRIBUTE`/`SOQLTARGETLISTEXPR` is confirmed deployable; UI-compatible per DG UI source (this is how the builder itself authors the condition), not by a per-shape round-trip. |
156
+ | Plural SOQL principal | Unvalidated | No retrieved and round-trip-tested example is included. |
157
+ | TRANSFORM with permission + classification | Candidate; requires Policy Builder validation | Use masking-category-mapped transforms only. |
158
+ | `(AND 1 2)` multi-condition | Candidate; requires Policy Builder validation | Each section must use a supported UI bucket. |
141
159
  | Top-level `(OR 1 2)` | No | Triggers unsupported-rule path; silently dropped. |
142
160
  | Hierarchy traversal | No | `HIERARCHICALLY_BELOW` and `HIERARCHY` not in UI dropdowns. Always API-only. |
@@ -21,10 +21,14 @@ Lightning Reports define how Salesforce data is queried, grouped, filtered, and
21
21
 
22
22
  **TOP DEPLOYMENT KILLERS — check these BEFORE generating any report:**
23
23
  1. **Grouping fields in columns** — Fields in `<groupingsDown>` or `<groupingsAcross>` must NEVER also appear in `<columns>`
24
- 2. **Wrong column names** — Column names are report-type-specific. ALWAYS call MCP tools to verify (see `references/column-names.md`)
24
+ 2. **Wrong column names (REQUIRED lookup)** — Before writing any `<columns>`, `<groupingsDown>`, `<groupingsAcross>`, filter `<column>`, or chart `<groupingColumn>`, take every name from the table for the chosen `<reportType>` in `references/column-names.md`, or confirm it with `get_metadata_type_sections`. NEVER derive a column name from the field's API name: `CASENUMBER`, `ISCLOSED`, `PHONE`, `MAILING_CITY` all fail (use `CASE_NUMBER`, a `STATUS` filter, `PHONE1`, `ADDRESS2_CITY`)
25
25
  3. **Wrong scope** — LeadList uses `org`, not `organization`
26
26
  4. **Filter column dot notation** — Filter `<column>` values use FLAT names (`INDUSTRY`, `TYPE`) NOT dot notation (`ACCOUNT.INDUSTRY` is INVALID)
27
27
  5. **Multi-value picklist filters** — Use ONE `<criteriaItems>` with comma-separated `<value>` (e.g., `Technology,Financial Services`). Do NOT split into multiple criteriaItems with booleanFilter
28
+ 6. **Report `<name>` over 40 characters** — Count the characters before writing. `Opportunities by Stage with Avg Deal Size` (41 characters) fails with `Value too long for field: Name maximum length is:40`; use something like `Opps by Stage - Avg Deal Size`
29
+ 7. **Bare `NAME` / `USERS.NAME`** — Never use a bare `NAME` or `USERS.NAME` in columns or groupings; they are invalid on every standard report type. Look up the name column for the report type in `references/column-names.md` (e.g. `OPPORTUNITY_NAME`, `FULL_NAME` for the opportunity owner, `OWNER` for Case/Lead owner, `FIRST_NAME` + `LAST_NAME`)
30
+ 8. **Unrequested or invalid `<params>`** — Do NOT add `<params>` the request didn't ask for. On Opportunity reports the only accepted `probability` value is `>0` (`0`, `all`, `>50` fail with `is not one of the picklist choices`); for a probability threshold, filter on `PROBABILITY` instead
31
+ 9. **`RowCount` as a column** — `RowCount` is NOT a report column: `<columns><field>RowCount</field></columns>` fails with `columns-field: Invalid value specified: RowCount`. It is valid ONLY as `<chartSummaries><column>RowCount</column>`, as a `<sortByName>` value, or inside a custom summary formula's `<calculatedFormula>` (e.g. `AMOUNT:SUM / RowCount`). When the request asks for a record count, a Summary/Matrix report already shows the count per grouping — add no column; chart it with `RowCount` in `<chartSummaries>` if a chart is requested
28
32
 
29
33
  ### Rule 1: Format Determines Required Elements
30
34
 
@@ -41,11 +45,11 @@ Report metadata uses **platform report column names**, NOT raw API field names.
41
45
 
42
46
  ### Rule 3: Valid Report Type Required
43
47
 
44
- `<reportType>` must be a standard API name (e.g., `Opportunity`, `AccountList`, `CaseList`, `LeadList`, `AccountContactRole`) or a deployed custom report type developer name.
48
+ `<reportType>` must be a standard API name (e.g., `Opportunity`, `AccountList`, `CaseList`, `LeadList`, `AccountContactRole` for "Accounts with Contacts" — there is no `AccountContact`; see the label → API name table in `references/column-names.md`) or a deployed custom report type developer name **with a `__c` suffix** (`Accounts_with_Projects.reportType-meta.xml` → `<reportType>Accounts_with_Projects__c</reportType>`; without the suffix the deploy fails with `invalid report type`). Custom report type columns use `$` paths, not platform names: `Account$Name` for the base object, `Account.Projects__r$Budget_Amount__c` for a joined object. See the Custom Report Types section in `references/column-names.md`.
45
49
 
46
50
  ### Rule 4–5: Chart & Aggregates Require Summary/Matrix
47
51
 
48
- Charts and `<aggregateTypes>` (Sum, Average, etc.) only work in Summary and Matrix reports.
52
+ Charts and `<aggregateTypes>` (Sum, Average, etc.) only work in Summary and Matrix reports. Use only the `<chart>` child elements listed in `references/chart-types.md` — invented elements such as `<summaryAxisManualRangeEnabled>` or `<showInlineChart>` fail parsing. Use `<legendPosition>` ONLY on grouped/stacked chart types (`Right` or `Bottom`) or on `Pie`, `Donut`, `Funnel`, `Scatter`; on a single-series `HorizontalBar`, `VerticalColumn`, `Line`, or `LineCumulative` any value fails with `chart-legendPosition: Invalid value specified: Right` — omit it. A record-count chart summary is `<chartSummaries><column>RowCount</column></chartSummaries>` with NO `<aggregate>` (`Sum`/`Count` with `RowCount` fails).
49
53
 
50
54
  ### Rule 6–8: Limits
51
55
 
@@ -71,6 +75,7 @@ Determine `<sourceDir>` from `sfdx-project.json` (commonly `force-app/main/defau
71
75
 
72
76
  - `<description>` max **255 characters**
73
77
  - Grouping fields must NOT appear in `<columns>` — automatic deployment failure
78
+ - Each `<columns>` element holds exactly ONE `<field>` — repeat `<columns>` per field (multiple `<field>`s fail with `Element field is duplicated`)
74
79
 
75
80
  ### Rule 14: Folder Metadata Requires `<sharedTo>`
76
81
 
@@ -139,7 +144,7 @@ Common operators: `equals`, `notEqual`, `lessThan`, `greaterThan`, `contains`, `
139
144
 
140
145
  1. **Gather Requirements** — object, fields, groupings, filters, chart needs
141
146
  2. **Determine Format** — no groupings → Tabular; row groupings → Summary; row + column → Matrix; multiple objects → Joined
142
- 3. **Identify Column Names** — call `get_metadata_type_sections` MCP tool to get valid platform column names for the report type
147
+ 3. **Look Up Every Column Name (required)** — list every field the report needs, then take each name from the `references/column-names.md` table for the chosen `<reportType>` or confirm it with `get_metadata_type_sections`. Do not write XML until every column, grouping, filter column, and chart grouping column is looked up
143
148
  4. **Author Metadata** — start from closest example in `examples/` and adapt
144
149
  5. **Create Folder** — generate folder directory + `<FolderName>-meta.xml` with `<folderShares>`
145
150
  6. **Validate** — run through `references/verification-checklist.md`
@@ -26,6 +26,30 @@ Charts can only be added to Summary or Matrix reports. A Tabular report with a `
26
26
 
27
27
  ## legendPosition
28
28
 
29
- Only use `legendPosition` with grouped/stacked chart types (e.g., `VerticalColumnGrouped`, `HorizontalBarStacked`). Do NOT include it for simple single-series charts like `VerticalColumn`, `HorizontalBar`, `Pie`, `Donut`.
29
+ `legendPosition` is only accepted on some chart types. On the others, ANY value fails with `chart-legendPosition: Invalid value specified: Right` — omit the element.
30
30
 
31
- Valid values: `Right`, `Bottom`, `OnChart`
31
+ | Chart types | Accepted `legendPosition` |
32
+ |-------------|---------------------------|
33
+ | Single-series `HorizontalBar`, `VerticalColumn`, `Line`, `LineCumulative` | None — omit it |
34
+ | Grouped/stacked (`VerticalColumnGrouped`, `HorizontalBarStacked`, …) | `Right`, `Bottom` (`OnChart` fails) |
35
+ | `Pie`, `Donut`, `Funnel`, `Scatter` | `Right`, `Bottom`, `OnChart` |
36
+
37
+ ## Allowed `<chart>` Child Elements
38
+
39
+ Use only these elements inside `<chart>`. Anything else (e.g. `<summaryAxisManualRangeEnabled>`, `<showInlineChart>`) fails with `Element ... invalid at this location in type ReportChart`.
40
+
41
+ `backgroundColor1`, `backgroundColor2`, `backgroundFadeDir`, `chartSummaries` (`aggregate`, `axisBinding`, `column`), `chartType`, `enableHoverLabels`, `expandOthers`, `groupingColumn`, `legendPosition`, `location`, `secondaryGroupingColumn`, `showAxisLabels`, `showPercentage`, `showTotal`, `showValues`, `size`, `summaryAxisRange` (`Auto` or `Manual`), `textColor`, `textSize`, `title`, `titleColor`, `titleSize`.
42
+
43
+ A minimal chart needs only `chartType`, `groupingColumn`, `chartSummaries`, and `location`.
44
+
45
+ ## Record Count Charts
46
+
47
+ To chart a record count, `<chartSummaries>` holds ONLY `<column>RowCount</column>` — no `<aggregate>`. `Sum` with `RowCount` fails with `aggregate type cannot be specified with RowCount summary`, and `Count` is not a valid aggregate at all.
48
+
49
+ ```xml
50
+ <chartSummaries>
51
+ <column>RowCount</column>
52
+ </chartSummaries>
53
+ ```
54
+
55
+ For any other column, `<aggregate>` is required and must be `Sum`, `Average`, `Maximum`, or `Minimum`.
@@ -2,6 +2,20 @@
2
2
 
3
3
  Report metadata uses **platform report column names**, NOT raw API field names. These names are report-type-specific — ALWAYS verify using MCP tools (`get_metadata_type_sections` or `get_metadata_type_context`).
4
4
 
5
+ ## Standard Report Type API Names
6
+
7
+ Use the API name, never a name guessed from the UI label. There is NO `AccountContact` report type.
8
+
9
+ | UI label | `<reportType>` |
10
+ |----------|----------------|
11
+ | Accounts | `AccountList` |
12
+ | Accounts with Contacts / Accounts with Contact Roles | `AccountContactRole` |
13
+ | Contacts & Accounts | `ContactList` |
14
+ | Opportunities | `Opportunity` |
15
+ | Opportunities with Products | `OpportunityProduct` |
16
+ | Cases | `CaseList` |
17
+ | Leads | `LeadList` |
18
+
5
19
  ## Opportunity
6
20
 
7
21
  | Object.Field | Report Column Name |
@@ -69,6 +83,19 @@ Filter `<column>` values use plain names for Account fields — NOT dot notation
69
83
 
70
84
  ## Common Mistakes
71
85
 
86
+ - `RowCount` in `<columns><field>` → NEVER valid (fails with `columns-field: Invalid value specified: RowCount`). `RowCount` is valid only in `<chartSummaries><column>`, as a `<sortByName>` value, or inside a `<calculatedFormula>`; a Summary/Matrix report shows the record count per grouping without any column
87
+ - Bare `NAME` or `USERS.NAME` → NEVER valid on any standard report type (fails with `columns-field: Invalid value specified: NAME` / `Grouping: Invalid value specified: USERS.NAME`). Pick the name column for the report type from the tables above:
88
+ - Opportunity name → `OPPORTUNITY_NAME`; opportunity owner → `FULL_NAME`; account → `ACCOUNT_NAME`
89
+ - Case or Lead owner → `OWNER`
90
+ - Lead or contact person → `FIRST_NAME` + `LAST_NAME`
91
+ - Account (AccountList) → `ACCOUNT_NAME`; account on AccountContactRole → `ACCOUNT.NAME`
92
+ - `USERS.NAME` as the owner → `OWNER` (CaseList, LeadList) or `FULL_NAME` (Opportunity)
93
+ - `CASENUMBER` → `CASE_NUMBER` (CaseList)
94
+ - `ISCLOSED` filter → NOT a valid filter column; to exclude closed cases filter `STATUS` `notEqual` `Closed`
95
+ - `PHONE` → `PHONE1` (AccountContactRole)
96
+ - `MAILING_CITY` → `ADDRESS2_CITY` (AccountContactRole)
97
+ - `FULL_NAME`, `ACCOUNT_NAME` on AccountContactRole → `FIRST_NAME` + `LAST_NAME`, `ACCOUNT.NAME`
98
+ - Never derive a column from the field API name (`CaseNumber` → `CASENUMBER`, `IsClosed` → `ISCLOSED`); take it from the table for the report type
72
99
  - `OWNER_FULL_NAME` → Use `FULL_NAME` (Opportunity) or `OWNER` (Case/Lead)
73
100
  - `OWNER_NAME` → Use `OWNER` (CaseList) or `FULL_NAME` (Opportunity)
74
101
  - `CONTACT_NAME` → Verify per report type; some use `FIRST_NAME` + `LAST_NAME`
@@ -78,3 +105,19 @@ Filter `<column>` values use plain names for Account fields — NOT dot notation
78
105
  ## Custom Fields
79
106
 
80
107
  Custom fields use the format `<ObjectApiName>.<FieldApiName__c>` (e.g., `Opportunity.Custom_Field__c`).
108
+
109
+ ## Custom Report Types
110
+
111
+ A report built on a custom report type (`reportTypes/<Name>.reportType-meta.xml`) follows different naming than standard report types:
112
+
113
+ - `<reportType>` is the developer name **plus `__c`**: `Accounts_with_Projects__c`.
114
+ - Every column, grouping, filter, chart, and time-frame column is a `$` path built from the report type's section `<table>` and `<field>`: `<table>$<field>`.
115
+ - Only fields listed in the report type's `<sections>` are valid. Do not add a `<timeFrameFilter>` on a date field (e.g. `CreatedDate`) the layout does not include.
116
+
117
+ For a report type with `<baseObject>Account</baseObject>` joined through `<relationship>Projects__r</relationship>`:
118
+
119
+ | Section `<table>` | Section `<field>` | Report column |
120
+ |-------------------|-------------------|---------------|
121
+ | `Account` | `Name` | `Account$Name` (NOT `ACCOUNT_NAME`) |
122
+ | `Account.Projects__r` | `Name` | `Account.Projects__r$Name` (NOT `Project__c.Name`) |
123
+ | `Account.Projects__r` | `Budget_Amount__c` | `Account.Projects__r$Budget_Amount__c` |
@@ -61,7 +61,7 @@ The `<summaryColumn>` in a chart uses a special syntax for aggregate references:
61
61
  - `a!AMOUNT` — Average of Amount
62
62
  - `m!AMOUNT` — Max of Amount
63
63
  - `x!AMOUNT` — Min of Amount
64
- - `RowCount` — Record count
64
+ - `RowCount` — Record count (valid only here, in `<sortByName>`, and in a `<calculatedFormula>`; never as a `<columns><field>`)
65
65
 
66
66
  ### Pitfall 5: Joined Report Restrictions
67
67