@salesforce/afv-skills 1.55.0 → 1.56.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 (220) hide show
  1. package/package.json +1 -1
  2. package/skills/agentforce-generate/SKILL.md +8 -0
  3. package/skills/agentforce-generate/references/actions-reference.md +2 -2
  4. package/skills/agentforce-generate/references/voice-modality-reference.md +51 -15
  5. package/skills/agentforce-generate/references/voice-telephony-cli.md +193 -0
  6. package/skills/agentforce-observe/SKILL.md +13 -9
  7. package/skills/agentforce-observe/references/ahm-alerts.md +193 -14
  8. package/skills/automation-sandbox-post-copy-config-generate/SKILL.md +24 -15
  9. package/skills/automation-sandbox-post-copy-config-generate/assets/config_template.json +11 -0
  10. package/skills/automation-sandbox-post-copy-config-generate/assets/json_schema.json +33 -1
  11. package/skills/automation-sandbox-post-copy-config-generate/references/configuration_catalog.md +32 -1
  12. package/skills/automation-sandbox-post-copy-configure/SKILL.md +75 -71
  13. package/skills/automation-sandbox-post-copy-configure/assets/scheduled_apex_template.apex +13 -0
  14. package/skills/automation-sandbox-post-copy-configure/examples/sample_scheduled_apex_config.json +13 -0
  15. package/skills/automation-sandbox-post-copy-configure/references/scheduled_apex_path.md +155 -0
  16. package/skills/automation-sandbox-post-copy-configure/scripts/build-scheduled-apex.mjs +62 -0
  17. package/skills/automation-sandbox-post-copy-configure/scripts/soql-escape-job-name.mjs +28 -0
  18. package/skills/consumer-goods-accruals-datakit-deploy/SKILL.md +383 -0
  19. package/skills/consumer-goods-accruals-datakit-deploy/scripts/setup.js +324 -0
  20. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/00-check-prerequisites.js +63 -0
  21. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/01-download-static-resource.js +100 -0
  22. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/02-replace-org-id.js +46 -0
  23. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/03-deploy-metadata.js +46 -0
  24. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/04-deploy-engine.js +198 -0
  25. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/05-deploy-tpm-accruals.js +231 -0
  26. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/06-create-dataspace.js +82 -0
  27. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/07-deploy-accruals-reports.js +517 -0
  28. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/08-deploy-ui.js +416 -0
  29. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/09-completion.js +44 -0
  30. package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/utils.js +514 -0
  31. package/skills/consumer-goods-sync-management-configure/SKILL.md +137 -0
  32. package/skills/consumer-goods-sync-management-configure/examples/scenarios.md +294 -0
  33. package/skills/consumer-goods-sync-management-configure/references/act1-setup-sync.md +333 -0
  34. package/skills/consumer-goods-sync-management-configure/references/act2-assign-users.md +324 -0
  35. package/skills/consumer-goods-sync-management-configure/references/act3-plan-verify.md +113 -0
  36. package/skills/consumer-goods-sync-management-configure/references/readiness-and-enablement.md +164 -0
  37. package/skills/consumer-goods-sync-management-configure/references/sync-management-app-install-backbone.md +159 -0
  38. package/skills/consumer-goods-sync-management-configure/references/transports-and-namespace.md +220 -0
  39. package/skills/consumer-goods-sync-management-configure/references/verify-and-smoke.md +175 -0
  40. package/skills/dx-org-analyze/SKILL.md +0 -1
  41. package/skills/dx-org-analyze/scripts/collect_org_data.py +2 -2
  42. package/skills/dx-org-analyze/scripts/compute_diff.py +2 -4
  43. package/skills/dx-org-analyze/scripts/introspect_org.py +4 -40
  44. package/skills/dx-org-manage/SKILL.md +6 -50
  45. package/skills/dx-org-manage/examples/README.md +10 -16
  46. package/skills/dx-org-manage/references/scratch-org-create.md +1 -1
  47. package/skills/dx-org-manage/references/scratch-org-operations.md +1 -1
  48. package/skills/dx-org-shape-manage/SKILL.md +4 -3
  49. package/skills/education-cloud-domain-configure/references/gotchas-extended.md +1 -0
  50. package/skills/experience-accessibility-validate/SKILL.md +8 -5
  51. package/skills/experience-accessibility-validate/references/reviewers/sc-1-1-1-non-text-content.md +1 -4
  52. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-i-lists.md +0 -4
  53. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-ii-tables.md +20 -85
  54. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-iii-form-labels.md +4 -4
  55. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-iv-regions.md +0 -4
  56. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-v-groups.md +2 -4
  57. package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-5-identify-input.md +0 -4
  58. package/skills/experience-accessibility-validate/references/reviewers/sc-1-4-3-contrast.md +4 -14
  59. package/skills/experience-accessibility-validate/references/reviewers/sc-2-1-1-keyboard.md +9 -5
  60. package/skills/experience-accessibility-validate/references/reviewers/sc-2-4-4-link-purpose.md +1 -4
  61. package/skills/experience-accessibility-validate/references/reviewers/sc-2-4-6-headings-labels.md +0 -4
  62. package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-1-pointer-gestures.md +0 -4
  63. package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-2-pointer-cancellation.md +0 -4
  64. package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-3-label-in-name.md +0 -4
  65. package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-7-dragging-movement.md +0 -4
  66. package/skills/experience-accessibility-validate/references/reviewers/sc-3-2-1-on-focus.md +0 -4
  67. package/skills/experience-accessibility-validate/references/reviewers/sc-3-2-2-on-input.md +1 -4
  68. package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-1-error-identification.md +1 -4
  69. package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-2-labels-instructions.md +1 -4
  70. package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-3-error-suggestion.md +1 -4
  71. package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-i-name.md +4 -5
  72. package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-ii-role.md +1 -4
  73. package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-iii-value.md +0 -4
  74. package/skills/experience-lwc-accessibility-jest-run/SKILL.md +104 -25
  75. package/skills/experience-lwc-accessibility-jest-run/assets/jest.config.js +4 -0
  76. package/skills/experience-lwc-accessibility-jest-run/assets/sa11y-jest-setup.js +5 -0
  77. package/skills/experience-ui-bundle-app-coordinate/SKILL.md +5 -5
  78. package/skills/experience-ui-bundle-features-generate/SKILL.md +65 -36
  79. package/skills/experience-ui-bundle-features-generate/references/angular/features.md +74 -0
  80. package/skills/experience-ui-bundle-features-generate/references/react/features.md +59 -0
  81. package/skills/experience-ui-bundle-features-generate/scripts/detect-framework.sh +73 -0
  82. package/skills/experience-ui-bundle-frontend-generate/SKILL.md +2 -2
  83. package/skills/experience-ui-bundle-metadata-generate/SKILL.md +26 -14
  84. package/skills/experience-ui-bundle-metadata-generate/references/angular-metadata-generate.md +37 -0
  85. package/skills/experience-ui-bundle-metadata-generate/references/react-metadata-generate.md +32 -0
  86. package/skills/experience-ui-bundle-metadata-generate/scripts/detect-framework.sh +73 -0
  87. package/skills/experience-ui-bundle-metadata-generate/scripts/verify-bundle-location.sh +30 -8
  88. package/skills/field-service-data-capture-migrate/SKILL.md +391 -0
  89. package/skills/field-service-data-capture-migrate/assets/sample-legacy-flow.flow-meta.xml +163 -0
  90. package/skills/field-service-data-capture-migrate/references/architecture-notes.md +40 -0
  91. package/skills/field-service-data-capture-migrate/references/component-mapping.md +278 -0
  92. package/skills/field-service-data-capture-migrate/references/converter-builder-contract.md +183 -0
  93. package/skills/field-service-data-capture-migrate/references/dc-platform-rules.md +130 -0
  94. package/skills/field-service-data-capture-migrate/references/fsm-dc-capability-catalog.md +215 -0
  95. package/skills/field-service-data-capture-migrate/references/known-deploy-errors.md +36 -0
  96. package/skills/field-service-data-capture-migrate/references/migration-checklist.md +121 -0
  97. package/skills/field-service-data-capture-migrate/references/transformer-rules.md +132 -0
  98. package/skills/field-service-data-capture-migrate/scripts/analyze_flow.py +277 -0
  99. package/skills/field-service-data-capture-migrate/scripts/convert_to_dc_spec.py +1311 -0
  100. package/skills/field-service-data-capture-migrate/scripts/cud_analysis.py +402 -0
  101. package/skills/field-service-data-capture-migrate/scripts/deploy_flow.sh +230 -0
  102. package/skills/field-service-data-capture-migrate/scripts/discover_subflow_tree.py +230 -0
  103. package/skills/field-service-data-capture-migrate/scripts/flow_input.py +186 -0
  104. package/skills/field-service-data-capture-migrate/scripts/flow_xml_utils.py +39 -0
  105. package/skills/field-service-data-capture-migrate/scripts/fsm_dc_catalog.py +413 -0
  106. package/skills/field-service-data-capture-migrate/scripts/generate_summary.py +199 -0
  107. package/skills/field-service-data-capture-migrate/scripts/json_to_flow_xml.py +146 -0
  108. package/skills/field-service-data-capture-migrate/scripts/manual_review_flags.py +42 -0
  109. package/skills/field-service-data-capture-migrate/scripts/retrieve_flow_rest.sh +155 -0
  110. package/skills/field-service-data-capture-migrate/scripts/subflow_names.py +49 -0
  111. package/skills/field-service-data-capture-migrate/scripts/transform_flow.py +1661 -0
  112. package/skills/field-service-data-capture-migrate/scripts/validate_flow.sh +147 -0
  113. package/skills/field-service-data-capture-migrate/scripts/vendor/build_flow.py +1258 -0
  114. package/skills/life-sciences-fieldsalesrep-coordinate/SKILL.md +1 -1
  115. package/skills/life-sciences-fieldsalesrep-coordinate/references/orchestration-flow.md +1 -1
  116. package/skills/life-sciences-kam-coordinate/references/stage-5-data-and-plan-templates-overview.md +14 -1
  117. package/skills/mobile-apps-create/SKILL.md +1 -1
  118. package/skills/{platform-agentsetup-categories-fetch → platform-agenticsetup-categories-get}/SKILL.md +7 -7
  119. package/skills/platform-sandbox-configure/SKILL.md +108 -133
  120. package/skills/platform-sandbox-configure/references/api-response-shapes.md +39 -0
  121. package/skills/platform-sandbox-configure/references/definition-file-approach.md +73 -0
  122. package/skills/platform-widget-generate/SKILL.md +26 -18
  123. package/skills/platform-widget-generate/examples/formulas.json +191 -0
  124. package/skills/platform-widget-generate/references/widget-formulas.md +123 -0
  125. package/skills/platform-widget-generate/references/widget-meta-directives.md +4 -4
  126. package/skills/sales-call-scoring-configure/SKILL.md +318 -0
  127. package/skills/sales-call-scoring-configure/assets/best-practice-competencies.json +67 -0
  128. package/skills/sales-call-scoring-configure/assets/ootb-competencies.json +58 -0
  129. package/skills/sales-call-scoring-configure/references/admin-communication.md +79 -0
  130. package/skills/sales-call-scoring-configure/references/competency-crud.md +130 -0
  131. package/skills/sales-call-scoring-configure/scripts/create-competency.sh +166 -0
  132. package/skills/sales-call-scoring-configure/scripts/create-custom-competency.sh +166 -0
  133. package/skills/sales-call-scoring-configure/scripts/edit-competency.sh +185 -0
  134. package/skills/sales-call-scoring-configure/scripts/edit-custom-competency.sh +190 -0
  135. package/skills/sales-call-scoring-configure/scripts/enable-call-scoring.sh +436 -0
  136. package/skills/sales-call-scoring-configure/scripts/get-competency.sh +72 -0
  137. package/skills/sales-call-scoring-configure/scripts/get-custom-competency.sh +78 -0
  138. package/skills/sales-call-scoring-configure/scripts/install-best-practice-competencies.sh +223 -0
  139. package/skills/sales-call-scoring-configure/scripts/install-ootb-competencies.sh +237 -0
  140. package/skills/sales-call-scoring-configure/scripts/list-competencies.sh +99 -0
  141. package/skills/sales-call-scoring-configure/scripts/shared/auth.sh +116 -0
  142. package/skills/sales-call-scoring-configure/scripts/shared/cap.sh +86 -0
  143. package/skills/sales-call-scoring-configure/scripts/shared/soap.sh +267 -0
  144. package/skills/sales-call-scoring-configure/scripts/shared/soql.sh +25 -0
  145. package/skills/sales-call-scoring-configure/scripts/toggle-competency.sh +112 -0
  146. package/skills/sales-call-scoring-configure/scripts/toggle-custom-competency.sh +125 -0
  147. package/skills/sales-call-scoring-configure/scripts/verify-ootb-competencies.sh +116 -0
  148. package/skills/service-concierge-portal-generate/references/portal-deploy-runbook.md +1 -0
  149. package/skills/service-de-channel-activate/SKILL.md +6 -5
  150. package/skills/service-de-channel-create/SKILL.md +3 -3
  151. package/skills/service-de-channel-routing-configure/SKILL.md +3 -3
  152. package/skills/service-de-channel-settings-configure/SKILL.md +195 -0
  153. package/skills/service-de-channel-settings-configure/references/channel-settings-facets.md +152 -0
  154. package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/gotchas.md +3 -3
  155. package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/language-keywords.md +4 -4
  156. package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/worked-examples.md +14 -14
  157. package/skills/service-de-headless-channel-configure/SKILL.md +6 -6
  158. package/skills/service-de-headless-channel-configure/references/worked-examples.md +1 -1
  159. package/skills/service-helpagent-coordinate/SKILL.md +3 -2
  160. package/skills/service-helpagent-coordinate/references/channel-voice.md +15 -4
  161. package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +49 -31
  162. package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +71 -6
  163. package/skills/service-itsm-agentic-setup-agentforce-coordinate/scripts/verify-child-verdict.mjs +26 -4
  164. package/skills/service-itsm-agentic-setup-cmdb-access-assign/SKILL.md +35 -10
  165. package/skills/service-itsm-agentic-setup-cmdb-access-assign/references/mcp-invocation.md +25 -5
  166. package/skills/service-itsm-agentic-setup-cmdb-bundle-deploy/SKILL.md +1 -1
  167. package/skills/service-itsm-agentic-setup-cmdb-configure/SKILL.md +5 -5
  168. package/skills/service-itsm-agentic-setup-cmdb-configure/references/mcp-invocation.md +1 -1
  169. package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +2 -2
  170. package/skills/service-itsm-agentic-setup-cmdb-coordinate/examples/output-templates.md +1 -1
  171. package/skills/service-itsm-agentic-setup-cmdb-discovery-configure/SKILL.md +25 -15
  172. package/skills/service-itsm-agentic-setup-employee-agent-configure/SKILL.md +8 -5
  173. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/report-format.md +4 -2
  174. package/skills/service-itsm-agentic-setup-employee-agent-configure/references/workflow-detail.md +1 -1
  175. package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/render-report.mjs +29 -16
  176. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md +8 -5
  177. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/report-format.md +4 -2
  178. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/workflow-detail.md +1 -1
  179. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs +29 -16
  180. package/skills/service-itsm-agentic-setup-incident-management/SKILL.md +138 -68
  181. package/skills/service-itsm-agentic-setup-incident-management/examples/output-templates.md +31 -15
  182. package/skills/service-itsm-agentic-setup-incident-management/references/incident-persona-psg.md +156 -0
  183. package/skills/service-itsm-agentic-setup-incident-management/references/incident-preferences.md +148 -0
  184. package/skills/service-itsm-agentic-setup-incident-management/references/major-incident-management.md +162 -0
  185. package/skills/service-itsm-agentic-setup-incident-management/references/service-mgmt-privilege.md +149 -0
  186. package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +103 -89
  187. package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone.json +2 -2
  188. package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/predefined-incident-policy.json +21 -39
  189. package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +3 -3
  190. package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +18 -1
  191. package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +63 -37
  192. package/skills/service-omni-attribute-routing-configure/SKILL.md +53 -0
  193. package/skills/service-omni-attribute-routing-configure/references/api-notes.md +7 -0
  194. package/skills/service-omni-attribute-routing-configure/scripts/configure-and-report.sh +224 -0
  195. package/skills/service-omni-attribute-routing-configure/scripts/tests/test_attribute_routing_contracts.py +137 -0
  196. package/skills/service-omni-channel-inventory-analyze/SKILL.md +96 -0
  197. package/skills/service-omni-channel-inventory-analyze/references/api-notes.md +52 -0
  198. package/skills/service-omni-channel-inventory-analyze/scripts/analyze.sh +185 -0
  199. package/skills/service-omni-channel-inventory-analyze/scripts/tests/_bootstrap.py +84 -0
  200. package/skills/service-omni-channel-inventory-analyze/scripts/tests/test_inventory_analyze_contracts.py +141 -0
  201. package/skills/service-omni-channel-limits-analyze/SKILL.md +70 -0
  202. package/skills/service-omni-channel-limits-analyze/references/api-notes.md +22 -0
  203. package/skills/service-omni-channel-limits-analyze/scripts/analyze.sh +159 -0
  204. package/skills/service-omni-channel-limits-analyze/scripts/tests/_bootstrap.py +87 -0
  205. package/skills/service-omni-channel-limits-analyze/scripts/tests/test_limits_analyze_contracts.py +99 -0
  206. package/skills/service-omni-channel-setup-coordinate/SKILL.md +12 -20
  207. package/skills/service-omni-channel-setup-coordinate/scripts/integration-driver.sh +55 -5
  208. package/skills/service-omni-channel-setup-coordinate/scripts/tests/test_omni_contracts.py +38 -0
  209. package/skills/service-omni-command-center-analyze/SKILL.md +2 -2
  210. package/skills/service-omni-command-center-analyze/scripts/analyze.sh +3 -3
  211. package/skills/dx-org-manage/examples/snapshots/error_output.json +0 -9
  212. package/skills/dx-org-manage/examples/snapshots/success_output.json +0 -15
  213. package/skills/dx-org-manage/references/cli_flags.md +0 -67
  214. package/skills/dx-org-manage/references/creating-snapshot.md +0 -103
  215. package/skills/dx-org-manage/references/snapshot_usage.md +0 -74
  216. package/skills/experience-accessibility-validate/scripts/contrast-ratio.py +0 -153
  217. package/skills/experience-lwc-accessibility-jest-run/references/running-sa11y-jest-tests.md +0 -205
  218. package/skills/experience-ui-bundle-features-generate/scripts/verify-react-bundle.sh +0 -14
  219. /package/skills/experience-ui-bundle-features-generate/references/{conflict-resolution-schema.json → common/conflict-resolution-schema.json} +0 -0
  220. /package/skills/{platform-agentsetup-categories-fetch → platform-agenticsetup-categories-get}/references/api-response-schema.md +0 -0
@@ -0,0 +1,294 @@
1
+ # Validation Scenarios — `consumer-goods-sync-management-configure`
2
+
3
+ Behavioral checks for the skill. Each scenario is a user utterance + the correct routing and
4
+ outcome, with special attention to the **honesty contract**: steps no transport can complete must
5
+ be reported (not faked), and the transport for every step must be correct (`core` /
6
+ `Sync Management App`). Each check below is labeled **Pass** (a behavior the agent must exhibit) or **Fail** (an anti-pattern it must avoid); the scenario passes when the agent does all the **Pass** behaviors and none of the **Fail** ones.
7
+
8
+ ---
9
+
10
+ ## 1. Full end-to-end setup (the steel thread)
11
+
12
+ **Utterance:** "Set up CG Cloud mobile sync for this org."
13
+
14
+ - **Pass:** Routes through **all three Acts** in order (Setup → Assign → Plan & Verify); does not stop
15
+ after the install and call it done.
16
+ - **Pass:** Writes the mandatory pre-write plan first (per orchestrator).
17
+ - **Pass:** Resolves the namespace prefix at runtime before any package-object reference.
18
+ - **Pass:** Reaches Act 3 end state or reports exactly which step blocked and why.
19
+ - **Fail:** Does **not** report "sync is set up" when only Act 1 ran.
20
+
21
+ ## 2. Install only (A1.3 headless install)
22
+
23
+ **Utterance:** "Install the RE sync baseline into this org."
24
+
25
+ - **Pass:** **Posts the mandatory pre-write plan before the `installConfig` POST** (per orchestrator
26
+ §"Mandatory pre-write plan"): lists all three acts, marks Act 1 A1.3 as the only step it will run,
27
+ and **quotes the exact narrowing words** ("Install the RE sync baseline") that justify skipping
28
+ Acts 2–3 and the other Act-1 sub-acts (readiness A1.1/A1.2 still gate the install; field sets not
29
+ requested → reported not-done), and confirms the target org + resolved namespace prefix. Does
30
+ **not** jump straight to the POST without it.
31
+ - **Pass:** Uses the `/v1/syncconfig/install` endpoint (`SyncConfigInstallEndpoint`): **GET
32
+ `discoverConfigs`** to find the baseline (picks the Retail Execution baseline — its exact `staticResourceName`
33
+ comes from `discoverConfigs` at runtime, never hardcoded — verifying it's
34
+ `AVAILABLE`), then **POST `installConfig`** with `{"req":{"staticResourceName":"..."}}`, then
35
+ confirms landing with the cheap **aggregate** check — the sum of the four `core` COUNT()s (read in
36
+ **one batched anon-Apex call**, not a per-object `sf data query` loop) ==
37
+ `InstallResponse.recordsInserted` (no manifest fetch) — or a re-GET showing `ALREADY_INSTALLED`.
38
+ Because the ask was narrowed to the install (Act 3 not run), it **says plainly that the fuller
39
+ per-object verification against the baseline manifest — Act 3's A3.1/A3.2 — was not performed**,
40
+ rather than running that per-object comparison here.
41
+ - **Pass:** Treats the install as `Sync Management App` via `SyncConfigInstallEndpoint`.
42
+ - **Fail:** Does **not** tag the step `Sync Management App` on the basis of a `public` (namespace-private)
43
+ Apex method, and does **not** claim the install succeeded without a `core` SOQL read-back of the four objects.
44
+ - **Pass:** On a `FAILED` `InstallResponse` (or a thrown call), **reports `errorMessage` and stops** — no
45
+ read-back, no field sets, no Act 2; treats a `FAILED` body inside an HTTP 200 as a failure, not
46
+ success.
47
+ - **Fail:** Does **not** hand-insert `Sync_Config__c` rows via raw `sobjects` POST to fake the install
48
+ (that skips the ZIP orchestration, `$$NS` macro, ordering, and state rows) — including as a
49
+ "recovery" after a `FAILED` response.
50
+ - **Fail:** Does **not** pass a `parentConfigId` argument to the POST — there is none; parent linkage
51
+ comes from the baseline manifest (a child reads `REQUIRES_PARENT` from GET until its parent is
52
+ installed).
53
+
54
+ ## 3. Namespace / metadata-present gate (A1.1 — `core`, the hard prerequisite)
55
+
56
+ **Utterance:** "Set up sync" / "Check that this org is ready for sync."
57
+
58
+ - **Pass:** **Verifies the Sync Management App metadata is present and resolves its namespace FIRST**,
59
+ before the RE-enablement check (A1.2), via the **Tooling API** (`GET /tooling/query?q=... FROM
60
+ InstalledSubscriberPackage`, matching the Sync Management App package by `SubscriberPackage.Name`
61
+ client-side — the object has no server-side `WHERE` — then reading `NamespacePrefix` off the
62
+ matched row rather than assuming a fixed value). Uses the match to resolve **both** the namespace
63
+ prefix and the **installed version**.
64
+ - **Pass:** Prefers Tooling over the package's own `GET /v1/managedpackage` for the absence check
65
+ (that route is served by the package, so it **404s when the package is missing** and can't report
66
+ absence); may use `/v1/managedpackage` only as a confirming call once Tooling says present.
67
+ - **Pass:** **Resolves the namespace from either source — package OR org.** On **no matching package
68
+ row**, does **not** immediately stop; **falls back to the org's own namespace** (`SELECT
69
+ NamespacePrefix FROM Organization`, `core`) and, if non-null, confirms by resolving
70
+ `<orgNs>Sync_Config__c` — the source-deployed DE/packaging-org case (e.g. an org whose
71
+ `Organization.NamespacePrefix` is set and whose `InstalledSubscriberPackage` is empty). Treats
72
+ that org prefix as `ns_prefix` and proceeds.
73
+ - **Pass:** **Hard miss (STOP and report) only when NEITHER source resolves** — no package row **and** no
74
+ org namespace (or `<orgNs>Sync_Config__c` doesn't describe) **and** no bare unmanaged
75
+ `Sync_Config__c`. Reports "Sync Management App metadata not present"; does **not** fall through to
76
+ the RE-enablement check (A1.2), and does **not** attempt to install/deploy it (org setup, out of scope).
77
+ - **Fail:** Does **not** treat an empty `InstalledSubscriberPackage` as an automatic hard miss without
78
+ first checking the org namespace (that false-negatives a source-deployed org where the sync
79
+ objects exist under `Organization.NamespacePrefix`).
80
+ - **Pass:** Runs **no** license query here — installing and using the Sync Management App is **not**
81
+ license-gated (there is no license or SKU to detect, and install is not entitlement-gated).
82
+ A1.1's only hard gate is **metadata-present + namespace-resolved**; the next Act-1 gate is
83
+ **RE-enabled** (A1.2), an org preference rather than a license.
84
+ - **Fail:** Does **not** probe for a license or "base entitlement", nor declare a license `accessCheck` —
85
+ there is no such entitlement to detect, so doing so would false-block a fully-capable org.
86
+ - **Fail:** Does **not** verify a named **permission set** (e.g. `Sync_Admin`) exists as a readiness gate —
87
+ perm-set names can be renamed or folded into another set across orgs/releases, so a name-based
88
+ existence check would false-block a capable org. Readiness is exactly two gates: metadata-present
89
+ (this scenario) and RE-enabled (A1.2).
90
+
91
+ ## 4. Enable Retail Execution (A1.2 — `core` write)
92
+
93
+ **Utterance:** "Enable Retail Execution and finish sync setup."
94
+
95
+ - **Pass:** **Posts the mandatory pre-write plan before the RE-enable write.** "…finish sync setup" is
96
+ **not** a narrowing qualifier — the plan treats this as the full three-act journey (no acts
97
+ skipped on the strength of these words), names the target org + resolved namespace, and states it
98
+ starts at A1.1 readiness, not at the A1.2 write. Does **not** enable RE before stating the plan.
99
+ - **Pass:** **Reads first, via whichever transport is present** — dispatcher
100
+ `getRetailExecutionEnableSetting` (5 prefs + 4 echo flags) or MDAPI `Settings:RetailExecution`
101
+ (3 booleans). Does not claim "5 sub-prefs" when it only read 3 via CLI.
102
+ - **Pass:** **Enables via the transport that fits:** dispatcher present → PATCH the `RetailExecutionSettings` route
103
+ (5 *separate* setters, not one combined call); dispatcher-absent (`sf` CLI) → deploy
104
+ `settings/RetailExecution.settings` (member `RetailExecution`) via
105
+ `sf project deploy start --metadata "Settings:RetailExecution"`. **Dry-runs first, then re-reads
106
+ after the write** (false→true, deploy `changed:true`, read-back true).
107
+ - **Pass:** **Re-reads for dependent-default side effects** — enabling `enableRetailExecution` can auto-set
108
+ `enableVisitSharing` even though the deploy file didn't carry it; the agent reports
109
+ the actual post-write state, not the file it deployed.
110
+ - **Pass:** Treats `RetailExecution.orgHasAdvncdRetailExecutionPilot` as **out of reach** for
111
+ *advanced*-RE only (no read/write API; a CG Cloud platform / RE concern) — and
112
+ does **not** let it block base enablement, which is `core` and works today.
113
+ - **Fail:** Does **not** report RE-enablement as **across-the-board unavailable**
114
+ (the base write is proven `core`), and does **not** claim RE is enabled without a read-back.
115
+
116
+ ## 5. Field sets per tracked object (A1.4 — names via CSV, definitions RE-provisioned, verified `core`)
117
+
118
+ **Utterance:** "Make sure the sync config has all its field sets."
119
+
120
+ - **Pass:** Distinguishes **names** (the `Fieldset_Name_List__c` / `List_Header_Fieldset__c` columns
121
+ are populated by the baseline CSV once the install runs) from **definitions** (the `FieldSet`
122
+ metadata on the referenced objects — **not** shipped in the package, and by packaging rules a
123
+ managed package can't ship a FieldSet onto a standard object it doesn't own).
124
+ - **Pass:** Knows the definitions are **provisioned by Retail Execution** (A1.2), **not** deployed by this
125
+ skill — so A1.4 is a **read-only `core` describe that VERIFIES**, not a deploy. For each distinct
126
+ referenced set (chiefly `RetailMobilityRelevant`), describes the object's `fieldSets`
127
+ (`Schema...fieldSets.getMap()` or Tooling `FROM FieldSet`) and asserts it's present.
128
+ - **Pass:** Compares **case-insensitively on the bare local name**, namespace-agnostic — builds the
129
+ present-set from `FieldSet.getName().toLowerCase()` (or Tooling `DeveloperName`) and strips any
130
+ `<prefix>__` off the referenced name before diffing. Handles the set being **org-namespaced**
131
+ (`<ns>__retailmobilityrelevant` in a source-deployed org) **or** unprefixed (RE-provisioned
132
+ standard set in a subscriber org) — the same check passes for both.
133
+ - **Pass:** On a **missing** set, **reports and stops that object**, naming the object + absent set and the
134
+ owner (**RE provisioning / core-RE**) — and knows *why* it matters: the sync query-field path
135
+ (`TrackedObjectUtils` → `SYNC_MetaDataUtils`) **throws** a `SYNCException` on a missing set (a hard
136
+ failure at **first sync**, not at install).
137
+ - **Fail:** Does **not** call `fieldSets.getMap().containsKey('RetailMobilityRelevant')` with the raw
138
+ referenced name — the map keys are **all-lowercase and namespace-qualified**, so an original-case or
139
+ bare lookup returns a **false "missing"** for a set that exists. Nor does it assert a fixed
140
+ namespace prefix, nor run an **unfiltered** Tooling `FROM FieldSet` (which returns zero rows — the
141
+ `WHERE EntityDefinition.QualifiedApiName` filter is mandatory).
142
+ - **Fail:** Does **not** deploy `RetailMobilityRelevant` (or any referenced set) as a `FieldSet`-metadata
143
+ workaround — RE owns it; a hand-deployed set risks drifting from what RE and the baseline expect.
144
+ A missing set is escalated to RE provisioning, not papered over with a deploy.
145
+ - **Fail:** Does **not** treat "config with defaults" as a separate deficiency or a separate create-config step —
146
+ the installed baseline root config's values come fully-enumerated from the baseline CSVs (no
147
+ schema-default problem). The install *is* the config; there is no config named "Standard."
148
+
149
+ ## 6. Verify user exists (A2.1 core)
150
+
151
+ **Utterance:** "Assign Jordan Lee to sync." (start of Act 2)
152
+
153
+ - **Pass:** First runs a `core` User SOQL (`SELECT Id, IsActive, Profile.Name FROM User WHERE ...`)
154
+ as a `purpose: validate` pre-flight.
155
+ - **Pass:** If the user is missing/inactive, stops and reports — does not assign into a phantom.
156
+
157
+ ## 7. IOU membership precondition (A2.2 — `core` read-only, Default_IOU only)
158
+
159
+ **Utterance:** "Assign Jordan Lee to sync." (the IOU precondition, reached under `Default_IOU`)
160
+
161
+ - **Pass:** Treats A2.2 as a **`core` read-only precondition**, not a write — and only under
162
+ `Default_IOU`. Under `Custom_User_Field` (the default strategy) the binding comes from a
163
+ `Sync_Client_App_Profile_Mapping__c` row with no IOU, so **A2.2 is skipped entirely**.
164
+ - **Pass:** **A missing default mobility IOU stops the Act ONLY under `Default_IOU`.** Under
165
+ `Custom_User_Field`, a user with no IOU is **not** blocked — the mapping row binds them with the
166
+ all-scope default (`businessArea` = `'All'`, the all-areas value). The report-and-stop is scoped to
167
+ `Default_IOU`, where the IOU *is* the binding and its absence leaves nothing to bind.
168
+ - **Fail:** Does **not** generalize the `Default_IOU` "no IOU ⇒ stop" into a blanket rule that also halts a
169
+ `Custom_User_Field` assignment for a user who happens to lack an IOU.
170
+ - **Pass:** Under `Default_IOU`, **reads** the user's default mobility IOU with the exact query
171
+ `ClientAppMapperService.getDefaultIouId()` uses — `SELECT InternalOrganizationUnitId FROM
172
+ InternalOrgUnitUser WHERE UserId = :userId AND IsDfltMobIntrOrgUnit = true LIMIT 1`. A row →
173
+ carries the `InternalOrganizationUnitId` forward as the `iouId` scope for A2.3 and proceeds.
174
+ - **Pass:** If the read returns **no row** — the user has no default mobility IOU — **reports and stops**:
175
+ no further steps, names the owner (CG Cloud **core / RE** provisions IOU membership outside this
176
+ flow), and does **not** proceed to A2.3.
177
+ - **Pass:** In a **pure managed-package org** the query throws `QueryException` (the object is absent);
178
+ degrades to the MP path (`null`) exactly as `ClientAppMapperService` does, rather than
179
+ hard-failing.
180
+ - **Fail:** Does **not** attempt to **create** IOU membership — no `POST /sobjects/InternalOrgUnitUser`,
181
+ no Sync Management App Apex. The absence of a default mobility IOU is a
182
+ report-and-stop precondition, not a missing capability. Creating IOU membership is a CG Cloud
183
+ core / RE task outside this flow.
184
+
185
+ ## 8. Resolution-strategy coupling (A2.2 ↔ A2.3)
186
+
187
+ **Utterance:** "Bind Jordan to the RE sync configuration."
188
+
189
+ - **Pass:** **Posts the mandatory pre-write plan before the assignment POST.** Lists all three acts, marks
190
+ this as an Act 2 / A2.3-only run, and **quotes the narrowing words** ("Bind Jordan to the RE sync
191
+ configuration") that justify skipping Act 1 and Act 3, confirming the target org + resolved
192
+ namespace. Does **not** write the mapping row before stating the plan. (The strategy read and
193
+ config/target elicitation below happen *within* that planned scope.)
194
+ - **Pass:** Reads `Business_Area_Resolution_Strategy__c` **first** — via `GET /v1/syncconfig/configs`
195
+ (`SyncConfigListEndpoint`, which returns each deployed config's `resolutionStrategy`) — because
196
+ the strategy decides whether A2.2 is even on the critical path.
197
+ - **Pass:** **Elicits the config and target correctly:** confirms the named config is in the `/configs`
198
+ list (or lists deployed `name`s for the admin to pick if none was given, stopping if a named
199
+ config isn't deployed); asks whether the mapping is by Profile/Role/User; and **resolves the
200
+ profile/role name (or user) to its `00e`/`00E`/`005` Id via a `core` SOQL** before the POST —
201
+ never passes a raw name as `mappedRecordId`. On the User path, **stops if the user isn't in the
202
+ org** rather than binding a phantom, and (under `Default_IOU`) fetches the IOU from
203
+ `InternalOrgUnitUser` (`IsDfltMobIntrOrgUnit = true`).
204
+ - **Pass:** Under **`Custom_User_Field`** (the default), binds via a `Sync_Client_App_Profile_Mapping__c`
205
+ **Role/Profile/User** row through `POST /v1/syncconfig/assignment` (`SyncConfigAssignmentEndpoint`)
206
+ + read-back — **with no IOU**, and **skips the A2.2 precondition** (it does not apply here). Passes
207
+ the config's **`name`** (or `clientAppId`) from `/configs` as `configPath` — the endpoint
208
+ normalises either to the canonical `clientAppId` before storing, so the row is keyed the way the
209
+ admin Assignments page and the runtime resolver expect (a config `name` like `<AppId>__Default` →
210
+ stored short `clientAppId` `<AppId>`); **verifies the read-back's `clientAppId` is the short
211
+ canonical value**, since a row stored
212
+ under the Name would be invisible on the admin page and unresolvable at runtime. May bind a
213
+ **Role (`00E`)** or **Profile (`00e`)** to cover a whole cohort in one write.
214
+ - **Pass:** Under **`Default_IOU`**, treats the IOU (the A2.2 precondition read) **as** the binding — no
215
+ separate mapping row. If the A2.2 read finds **no** default mobility IOU, the Act has already
216
+ **reported and stopped** at A2.2, so A2.3 is never reached (a Role/Profile row won't rescue an
217
+ IOU-less user, since that root isn't evaluated for them); the skill does **not** create the IOU
218
+ to unblock it.
219
+ - **Fail:** Does **not** write the mapping row raw via `POST /sobjects/<ns>Sync_Client_App_Profile_Mapping__c`
220
+ (that corrupts the overloaded `Business_Area_Name__c` — IOU Id vs Business Area picklist per
221
+ strategy — and skips the dedup + unique-Name convention the service enforces).
222
+ - **Fail:** Does not write a mapping row that a `Default_IOU` strategy will ignore; does not report
223
+ A2.3 done when the A2.2 precondition already reported-and-stopped (no default mobility IOU under
224
+ `Default_IOU`); and does **not** wrongly run or block on the A2.2 IOU precondition when the
225
+ strategy is `Custom_User_Field` (where it does not apply).
226
+ - **Fail:** Does **not** pass a profile/role **name** (or a username) as `mappedRecordId` — the endpoint
227
+ requires a resolved `00e`/`00E`/`005` **Id** — and does **not** stuff an IOU Id into
228
+ `businessArea` under `Custom_User_Field` (the IOU field is `iouId`, only under `Default_IOU`); if
229
+ the admin asks for an IOU under `Custom_User_Field`, surfaces the strategy mismatch instead.
230
+ - **Pass:** **Uses the endpoint, never a raw write:** the assignment + configs endpoints are the only
231
+ safe A2.3 path and the skill does **not** fall back to a raw
232
+ `Sync_Client_App_Profile_Mapping__c` write.
233
+ - **Pass:** On an assignment POST that **fails** (failure status or a thrown call — e.g. an unresolvable
234
+ `configPath`, which the endpoint now hard-rejects rather than silently defaulting the strategy),
235
+ **reports the error and stops**: no read-back, no further processing, and no raw-write "recovery."
236
+ A failure body inside an HTTP 200 is treated as a failure, not success.
237
+
238
+ ## 9. List & verify activated config (A3.1)
239
+
240
+ **Utterance:** "Show me the activated sync configuration."
241
+
242
+ - **Pass:** **Lists the deployed configs via the `Sync Management App` endpoint** — `GET /v1/syncconfig/configs`
243
+ (`SyncConfigListEndpoint`) returns every deployed `Sync_Config__c` as
244
+ `{name, clientAppId, resolutionStrategy}` in one package-blessed call (a `core` SOQL list is an
245
+ equivalent fallback for this read). The *list* half of A3.1 is closed.
246
+ - **Pass:** Gets counts + keys across the four objects + `Sync_Config_State__c` in **one batched
247
+ anonymous-Apex `COUNT()` call** (the objects are custom settings) — **not** a per-object
248
+ `sf data query` loop, whose ~15–20s cold-starts blow the 2-min timeout — ending with an `assert:`
249
+ verify step. Parses the debug log by grepping `USER_DEBUG` first (the block is echoed as
250
+ `Execute Anonymous:` source). Verification is **not** blocked.
251
+ - **Pass:** Does **not** rely on `SyncConfigOrchestrator.buildStateMap()` (it's `public`/namespace-private
252
+ — unreachable from a subscriber org).
253
+ - **Pass:** **Proposes NO new Sync Management App endpoint for verification** — record counts via `core` SOQL are the
254
+ intended method, so it does **not** suggest, wait on, or block on a `/v1/syncconfig/verify`
255
+ endpoint. Act 3 adds no calls to the package.
256
+
257
+ ## 10. Verify against the baseline files (A3.2)
258
+
259
+ **Utterance:** "Verify the installed sync config matches the baseline."
260
+
261
+ - **Pass:** Runs the **baseline count check** — compares installed per-object counts (`core` COUNT()
262
+ reads) to the **installed baseline's own declared counts, derived at runtime from that baseline's
263
+ manifest/CSVs (never hardcoded literals)** — and reports pass/fail per object.
264
+ - **Pass:** **Verification is record counts only:** does **not** issue a representative `/v1/*` device call
265
+ as part of verification, and does **not** add or propose any Sync Management App endpoint for it.
266
+ - **Pass:** **Says exactly what was verified** — reports a green count check as proof the *server side*
267
+ installed the baseline's artefacts, nothing more.
268
+ - **Fail:** Does **not** assert against a hardcoded literal count instead of the installed baseline's
269
+ declared value.
270
+
271
+ ---
272
+
273
+ ## Cross-cutting checks (apply to every scenario)
274
+
275
+ - **Transport tag present:** every step the agent takes is explicitly `core` or
276
+ `Sync Management App` — never untagged; and any step no transport can complete is reported
277
+ plainly with its owner named, never faked.
278
+ - **No faking:** a rejected write / missing capability is reported with the owner named, never
279
+ papered over.
280
+ - **Namespace resolved at runtime (from either source):** package objects use the discovered
281
+ `<ns>` prefix — resolved from the installed package (`InstalledSubscriberPackage`) **or**, when no
282
+ package is installed, the org's own namespace (`Organization.NamespacePrefix`); core objects carry
283
+ none.
284
+ - **Read-back on writes:** every write ends with a verify (`assert:`) read.
285
+ - **Pre-write plan before the FIRST write:** in any scenario that performs a write (enable RE,
286
+ install a baseline, create a mapping row), the agent posts the mandatory pre-write plan *before*
287
+ that first write, per orchestrator §"Mandatory pre-write plan": all three acts listed, which it
288
+ runs/skips/reports as unreachable, and — for every skip — **the exact narrowing words quoted** from the request
289
+ ("set up sync" / "…finish sync setup" are **not** narrowing → full journey), plus the confirmed
290
+ target org and resolved namespace. Applies to **#1, #2, #4, #8** (always write-bearing).
291
+ Read-only scenarios take no write, so this check does not apply to them: **#3** namespace/metadata-present gate, **#5**
292
+ field-set verify (A1.4 is a read-only describe — RE provisions the definitions, the skill does
293
+ not deploy them), **#6** user-exists, **#7** IOU precondition, **#9** list, **#10**
294
+ baseline count check.
@@ -0,0 +1,333 @@
1
+ # Act 1 of 3 — Setup Sync
2
+
3
+ Part of the [`consumer-goods-sync-management-configure`](../SKILL.md) skill — the **first of three acts**.
4
+ Runs first; nothing in Acts 2–3 should be attempted until this Act's end state is reached.
5
+ After it, continue to [Act 2](act2-assign-users.md) → [Act 3](act3-plan-verify.md).
6
+
7
+ **This Act both gates and writes.** It *validates* things external to the package (the sync
8
+ metadata is present and its namespace resolves — from a package install **or** the org's own
9
+ namespace — and Retail Execution enablement — you can only check these, and a hard miss on either
10
+ halts the run),
11
+ and it *performs writes* (install the admin-confirmed baseline; field-set definitions are
12
+ provisioned by RE, so A1.4 only verifies them — no field-set deploy).
13
+ Having only *validated readiness* does **not**
14
+ mean Act 1 is done — you must complete the install + configuration writes and reach the end
15
+ state below.
16
+
17
+ **Read the transport contract first.** Every step here is `core` or `Sync Management App` (see the
18
+ parent `SKILL.md` and `transports-and-namespace.md`). Where neither transport
19
+ can complete a step, report what's needed and who provides it, then stop that step — never fake
20
+ it. The exceptions that **halt** the run are the hard readiness misses in steps 1–2: the sync
21
+ metadata absent (A1.1's gate — **neither** a managed-package install **nor** an org-namespaced/
22
+ unmanaged deploy resolves), or RE cannot be enabled and isn't already on (A1.2).
23
+
24
+ ## What this Act does
25
+
26
+ ### 1. A1.1 — Verify the Sync metadata is present and resolve its namespace (hard gate) — `core`
27
+
28
+ - **FIRST — verify the Sync Management App metadata is present in the org and resolve its
29
+ namespace. This is the hard prerequisite for the entire skill** — without the sync objects no
30
+ endpoint or namespace exists, so every downstream step is meaningless. The namespace has **two
31
+ possible sources** (see below): a **managed-package install** (`InstalledSubscriberPackage`) or
32
+ the **org's own registered namespace** (`Organization.NamespacePrefix`, for source-deployed
33
+ DE/packaging orgs). Start with the package check via the **Tooling API** (generic `core`, no
34
+ package code — so it answers even when the package is *absent*, which the package's own
35
+ `GET /v1/managedpackage` cannot, since that route 404s when the package isn't installed):
36
+ ```text
37
+ GET /services/data/vXX.0/tooling/query?q=
38
+ SELECT SubscriberPackage.Name, SubscriberPackage.NamespacePrefix,
39
+ SubscriberPackageVersion.MajorVersion, SubscriberPackageVersion.MinorVersion,
40
+ SubscriberPackageVersion.IsBeta
41
+ FROM InstalledSubscriberPackage
42
+ ```
43
+ `InstalledSubscriberPackage` does not support server-side `WHERE` filtering, so **query all rows
44
+ and match client-side** by `SubscriberPackage.Name` (the Sync Management App package), then
45
+ **read the matched row's `NamespacePrefix` off the result** rather than assuming a fixed value —
46
+ the org's installed package carries whichever prefix it was built with; that value (with a
47
+ trailing `__` appended) becomes `ns_prefix`. Transport: `sf data query --use-tooling-api`
48
+ when the CLI is present, else a plain REST `GET /services/data/vXX.0/tooling/query?q=<url-encoded SOQL>`
49
+ via `execute_api` / any session-token client — the CLI is only sugar over this.
50
+ - **A matched row confirms the package is installed** — and its `SubscriberPackageVersion`
51
+ resolves **two** things at once: (a) the namespace prefix to use for every later
52
+ package-object reference, and (b) the **installed version**, which you compare against the
53
+ release that carries the `/v1/syncconfig/*` endpoints (A1.3 install, A2.3 assignment,
54
+ A3.1-list) — an org on an older version won't have those routes even though the package is present.
55
+ - **The namespace can come from two sources — package OR org.** A match above is the
56
+ **package-install** case (a subscriber org). But the sync metadata can also be **source-deployed
57
+ into the org under the org's *own* registered namespace** (a DE / packaging / dev org), where
58
+ `InstalledSubscriberPackage` returns **no row at all** even though the objects are present. So an
59
+ empty `InstalledSubscriberPackage` is **not** an automatic hard miss.
60
+ - **No matched row → do NOT stop; fall back to the org namespace.** Read the org's own prefix
61
+ with a generic `core` query — `SELECT NamespacePrefix FROM Organization` — and if it is
62
+ non-null, treat that value (with the trailing `__`) as `ns_prefix`. **Confirm** by resolving one
63
+ known object under it (`GET /sobjects/<orgNs>Sync_Config__c/describe`, or `SELECT COUNT() FROM
64
+ <orgNs>Sync_Config__c`): a 200/successful describe means the sync objects live under the org
65
+ namespace and the run proceeds. (There is no `SubscriberPackageVersion` in this case — version
66
+ gating for the `/v1/syncconfig/*` endpoints doesn't apply to a source-deployed org; those
67
+ classes are either deployed or not, verified by probing the route.)
68
+ - **Hard miss = STOP only when NEITHER resolves.** If no `InstalledSubscriberPackage` row matches
69
+ **and** the org has no namespace (or `<orgNs>Sync_Config__c` doesn't describe) **and** the
70
+ object isn't present unmanaged (bare `Sync_Config__c`), then report "the Sync Management App
71
+ metadata is not present in this org (no managed package, no org-namespaced deploy)" and halt the
72
+ whole run — installing/deploying it is an org-setup prerequisite **outside this skill's scope**.
73
+ Do not fall through to the RE-enablement check (A1.2); it presupposes the sync objects exist.
74
+ - **Describe fallback (no Tooling access):** attempt `GET /sobjects/<ns>Sync_Config__c/describe`
75
+ across the candidate prefixes — the package's known namespace(s) **and** the org namespace from
76
+ `SELECT NamespacePrefix FROM Organization` (a `core` query, no Tooling), plus the bare
77
+ (unmanaged) name — a 200 confirms that prefix is the live one (but yields no version); a
78
+ `NOT_FOUND` = that prefix absent. `NOT_FOUND` on all probed = the metadata is absent. Prefer the
79
+ Tooling query when available — only it returns the installed *version* for the package case.
80
+ - **No license read — installing and using the Sync Management App is not license-gated.**
81
+ There is no license or SKU to detect, and package install is not entitlement-gated. So A1.1 does
82
+ **not** run any license query and declares no license `accessCheck`: the Act-1 readiness gates are
83
+ **metadata-present** (the namespace gate above) and **RE-enabled** (A1.2 below). Retail Execution
84
+ is an org *preference*, not a license — enable it in A1.2 rather than probing for an entitlement
85
+ here.
86
+ - **Do NOT verify the existence of any named permission set as a readiness gate.** Permission-set
87
+ names are unstable — they can be renamed or folded into another set with a different name across
88
+ releases and orgs — so a name-based existence check false-blocks a perfectly capable org. The
89
+ **only** two Act-1 prechecks are (1) the **Sync Management objects are present** (A1.1 above) and
90
+ (2) **Retail Execution is enabled** (A1.2 below). Access to the install/assignment endpoints is
91
+ granted by *some* permission set in the target org (its name is the admin's concern, not a fixed
92
+ value the skill asserts); if a call is denied for lack of access, report the access boundary and
93
+ who grants it — never gate readiness on a specific permission-set name.
94
+
95
+ ### 2. A1.2 — Enable Retail Execution — `core` read + `core` write
96
+
97
+ - **Read** the current setting one of two ways — **the transport determines what you see:**
98
+ - **Headless-360 dispatcher present:** GET the CG Cloud core
99
+ `RetailExecutionSettings` node (`getRetailExecutionEnableSetting`) — returns **5 prefs**
100
+ (`isRetailExecutionEnablePrefEnable`, `isProductHierarchyPrefEnabled`,
101
+ `isVisitSharingPrefEnabled`, `isCGAgentsPrefEnabled`, `isCGGenAIPrefEnabled`) + 4 read-only
102
+ echo flags.
103
+ - **Dispatcher-absent (e.g. `sf` CLI):** retrieve `Settings:RetailExecution` via MDAPI
104
+ (`sf project retrieve start --metadata "Settings:RetailExecution"`). The Settings surface
105
+ exposes **3** booleans — `enableRetailExecution`, `enableProductHierarchy`,
106
+ `enableVisitSharing` — **not** the dispatcher's 5. Same underlying org pref
107
+ (`ORG_PREFERENCE_RETAIL_EXECUTION_ENABLED` via `PermAndPrefUtil.setOrgPref`, controller
108
+ `RetailExecutionEnableController`), different projection. If already enabled, record and move on.
109
+ - **CLI absent → plain REST via the Tooling API (no dispatcher needed):**
110
+ `RetailExecutionSettings` is a queryable Tooling *singleton* sObject. **Prefer the SOQL
111
+ projection — one call, returns the values directly:**
112
+ `GET /services/data/vXX.0/tooling/query?q=SELECT+IsRetailExecutionEnabled,IsProductHierarchyEnabled,IsVisitSharingEnabled+FROM+RetailExecutionSettings`.
113
+ It returns the fields under **Tooling names** — `IsRetailExecutionEnabled`,
114
+ `IsProductHierarchyEnabled`, `IsVisitSharingEnabled` (note: `Is…Enabled`, distinct again from
115
+ both the dispatcher's `is…PrefEnable(d)` and MDAPI's `enable…`). **Avoid the two-call
116
+ singleton GET** (`SELECT Id …` → `GET /tooling/sobjects/RetailExecutionSettings/<id>`) as the
117
+ primary read — the per-id `sobjects` fetch can return `UNKNOWN_EXCEPTION`; keep it only as a
118
+ fallback. This is the read to use when neither the `sf` CLI nor the Headless-360 dispatcher is
119
+ present.
120
+ - **Enabling it is `core` and works today** on both transports below:
121
+ - **Dispatcher present:** PATCH the `RetailExecutionSettings` route
122
+ `.../retail-execution-settings/set-retail-execution-enable-setting` with `{enable:true}`.
123
+ There are **5 separate PATCH setters, not one combined call** — `set-retail-execution-enable-setting`,
124
+ `set-product-hierarchy-pref`, `set-visit-sharing-pref`, `set-cgagent-pref`, `set-cgcgen-aipref`,
125
+ each body `{enable:boolean}`. Guards: all need View Setup & Configuration;
126
+ `set-visit-sharing-pref` needs the Visit Share Pilot perm on `enable=true`; the two
127
+ CG-agent/GenAI setters are gated by `RetailExecution.userCanUseCGGenAI`.
128
+ - **Dispatcher-absent (`sf` CLI):** deploy a
129
+ `settings/RetailExecution.settings-meta.xml` (source) / `settings/RetailExecution.settings`
130
+ (MDAPI) whose member is named **`RetailExecution`** (the bare setting-type name — *not*
131
+ `RetailExecutionSettings.*`) carrying
132
+ `<enableRetailExecution>true</enableRetailExecution>`, then
133
+ `sf project deploy start --metadata "Settings:RetailExecution"`. This is a generic **`core`**
134
+ Metadata-API Settings deploy. Always dry-run first (`--dry-run`), then
135
+ re-read after the real write to confirm the value took.
136
+ - **CLI absent → plain REST via the Metadata deploy resource** (this is exactly what
137
+ `sf project deploy start` wraps): `POST /services/data/vXX.0/metadata/deployRequest` with a
138
+ base64-encoded zip (`package.xml` selecting `Settings:RetailExecution` +
139
+ `settings/RetailExecution.settings`) and `{"deployOptions":{"checkOnly":true}}` to dry-run,
140
+ then poll `GET /services/data/vXX.0/metadata/deployRequest/<id>` to completion; repeat with
141
+ `checkOnly:false` for the real write.
142
+ **Do NOT try a direct Tooling field PATCH** —
143
+ `PATCH /tooling/sobjects/RetailExecutionSettings/<id>` with `{"IsRetailExecutionEnabled":true}`
144
+ is **rejected** (`METADATA_FIELD_UPDATE_ERROR: Could not find a name resolver for Metadata`).
145
+ Settings sObjects are read-only to a direct Tooling PATCH; the write must go
146
+ through the Metadata deploy resource (or the dispatcher's PATCH setter). So: read is a clean
147
+ Tooling GET, but write is *always* the metadata-deploy path.
148
+ - **Dependent-default side effect:** enabling `enableRetailExecution` also enables
149
+ `enableVisitSharing` as a dependent default (if it was absent/off before) — the platform applies
150
+ dependent sub-pref defaults on enable, even though the deploy file carried only the one field.
151
+ **Re-read after the write; don't assume the sub-prefs match exactly what you deployed.**
152
+ - **A narrow exception: the advanced-pilot GA gate.**
153
+ `RetailExecution.orgHasAdvncdRetailExecutionPilot` has **no read/write API surface**
154
+ — it is a Core-source admission-gate expression on the setup tree, not an OrgPreference/PSL row.
155
+ But **base RE enablement does *not* require it** — RE enables cleanly without touching it; it
156
+ gates only *advanced* RE. When an advanced-RE feature needs it, report that it has no
157
+ automatable read/write path and that it's owned by the CG Cloud platform / Core setup tree, then
158
+ stop that step — do **not** let it block the base toggle, which is `core` and works today.
159
+ - **On a hard miss** (RE cannot be enabled and isn't already on): halt — like A1.1, an install
160
+ into a non-RE org produces a config that can't sync.
161
+
162
+ ### 3. A1.3 — Install sync artefacts into the four objects — `Sync Management App`
163
+
164
+ - **A headless install endpoint exists for this step.**
165
+ `SyncConfigInstallEndpoint` is a `global @RestResource(urlMapping='/v1/syncconfig/install/*')`
166
+ wrapper over the existing `SyncConfigInstall.installBaseline(...)` logic. It exposes:
167
+ - **POST `installConfig`** — install a baseline. Body `{"req":{"staticResourceName":"..."}}` →
168
+ `InstallResponse` (`status` SUCCESS/FAILED, `configId`, `version`, `recordsInserted`,
169
+ `errorMessage`). **The only argument is `staticResourceName`** — see the discovery step for how
170
+ to obtain a valid one.
171
+ - **GET `discoverConfigs`** — list installable baselines *before* POSTing, so you don't guess the
172
+ resource name. Returns `ConfigOption`s: `configId`, `displayName`, `parentConfigId`,
173
+ `staticResourceName` (the value to POST), `availability` (`AVAILABLE` / `ALREADY_INSTALLED` /
174
+ `REQUIRES_PARENT`), and `requiresLabel` (the blocking parent's configId when
175
+ `REQUIRES_PARENT`). Read-only.
176
+ - **On failure, report and STOP.** If the POST returns `status == FAILED` (or the call throws),
177
+ surface `errorMessage` to the admin and **halt this step — no verify, no field sets, no Act 2.**
178
+ A `FAILED` body inside an HTTP 200 is still a failure; never read it as success and never fall
179
+ back to a raw sObject insert to "recover." Only a `SUCCESS` response proceeds to the verify below.
180
+ - **Flow:** GET to discover → present the `AVAILABLE` baselines and **get the admin's explicit
181
+ confirmation of which one to install** (see the confirmation gate below) → POST the confirmed
182
+ baseline's `staticResourceName` to install → on `FAILED`, report `errorMessage` and stop → on
183
+ `SUCCESS`, **confirm the install landed — the cheap *aggregate* landing check only.** This is a
184
+ lightweight post-write gate, **not** Act 3's verification; do **not** run the per-object /
185
+ baseline-manifest comparison here (that is A3.1/A3.2's job — running it in Act 1 just re-does Act
186
+ 3 a step early). Two reads, not one: a re-GET showing `ALREADY_INSTALLED` is a quick confirmation
187
+ that the state row was written, but it does **not** prove the artefacts landed. The landing check
188
+ is a single **aggregate** read-back: sum the four `core` COUNT()s (`Sync_Config__c`,
189
+ `Sync_Tracked_Object_Config__c`, `Sync_Named_Fetch_Tree_Nodes__c`, `Sync_Named_Query__c`) and
190
+ compare that sum to **`InstallResponse.recordsInserted`** — which equals the manifest's total row
191
+ count, so this needs **no** static-resource fetch and **no** manifest at all. **Read the four
192
+ counts with ONE batched anonymous-Apex call — do NOT loop `sf data query` per object** (each `sf`
193
+ cold-start is ~15–20s, so a per-object loop blows the 2-min timeout; and when you parse the
194
+ `sf apex run` output, **grep `USER_DEBUG` first** — the block is echoed as `Execute Anonymous:`
195
+ source, so a bare marker grep matches twice; see the batched form in
196
+ [transports-and-namespace.md](transports-and-namespace.md)). Capture
197
+ `recordsInserted` + `version` from the `InstallResponse` into session state for Act 3 to reuse.
198
+ **Run this aggregate landing check even for a narrow install-only ask** (where Act 3 may not
199
+ otherwise run), so an install is never reported successful on a bare `SUCCESS`/state-row flip
200
+ without confirming the rows inserted — and if the caller needs the per-object split for an
201
+ install-only ask, say plainly that the fuller Act-3 verification (per-object counts vs the
202
+ baseline manifest) was not run.
203
+ - **Confirmation gate (mandatory, skill-side).** The install is a write, so **never POST without
204
+ the admin's explicit OK.** Before installing, present what will be written: the chosen baseline
205
+ (there is **no** config named "Standard" — the installable baselines are **discovered at runtime
206
+ via `discoverConfigs`, never hardcoded**; Act 1 targets the **Retail Execution** baseline, whose
207
+ exact `staticResourceName` comes from `discoverConfigs`), its per-object counts (read from the
208
+ selected baseline's own manifest/CSVs at runtime — **never hardcoded**), and any additional
209
+ sub-configs the admin also wants. Install only the confirmed set. **Sub-configs are just more
210
+ baselines** installed through the same POST, each behind its own confirmation; parent-before-child
211
+ ordering is enforced by the manifest's `parentConfigId` (a child shows `REQUIRES_PARENT` until its
212
+ parent is installed) — not by a caller-supplied param.
213
+ - **Verify by re-GET after install** (GET → POST install of the discovered Retail Execution baseline → SUCCESS;
214
+ re-GET shows `ALREADY_INSTALLED`). The endpoint's package-release rollout is a separate
215
+ workstream from this skill.
216
+ - **What the logic does:** reads the discovered baseline's static-resource ZIP
217
+ (`manifest.json` + CSVs) and inserts rows into all four objects: `Sync_Config__c`,
218
+ `Sync_Tracked_Object_Config__c`, `Sync_Named_Fetch_Tree_Nodes__c`, `Sync_Named_Query__c`
219
+ (namespace-agnostic via `SYNC_NamespaceHandler`; `$$NS` macro rewritten at install; per-config
220
+ `Sync_Config_State__c` version rows written). Guards: blocks a duplicate `configId`, blocks a
221
+ missing parent — **the parent linkage (`parentConfigId`) is read from the ZIP's `manifest.json`,
222
+ not passed as a param**; a re-run is a no-op.
223
+ - **Do not hand-roll the install.** Do **not** substitute generic `core` sObject REST for the
224
+ endpoint: the baseline install is an *orchestration* (unzip → macro → ordered multi-object
225
+ insert → state bookkeeping) that hand-inserting rows via `POST /sobjects/<ns>...` would not
226
+ reproduce faithfully (it skips the state rows and ordering guarantees). Use the endpoint, or have
227
+ an admin run it via the VF page in a non-headless context.
228
+ - **The installed root config carries its values from the CSVs — there is no separate "defaults" concern.**
229
+ The four sync objects are List custom settings, whose schema `<defaultValue>`s do **not** fire on
230
+ DML — but the baseline CSVs enumerate every value, so installing the baseline yields a
231
+ fully-populated root `Sync_Config__c` (plus any child/sub-configs). Creating the config is
232
+ therefore not a separate "create-with-defaults" step and needs no confirmation beyond the install
233
+ gate above; a bare hand-rolled insert, by contrast, would land an empty row.
234
+ - Several baseline **editions** ship (e.g. a Consumer Goods edition, a Direct-Store-Delivery
235
+ edition, and a Retail Execution edition), each as its own static resource whose exact name is
236
+ returned by `discoverConfigs`; **enumerate them from the endpoint at runtime, never hardcode the
237
+ names** (the set expands across releases). Act 1 targets the **Retail Execution** edition — its
238
+ exact static-resource name comes from `discoverConfigs` at runtime. A custom baseline beyond the
239
+ shipped editions requires authoring the ZIP by hand — out of scope.
240
+
241
+ ### 4. A1.4 — Verify the referenced field-set definitions exist — `core` (read-only describe)
242
+
243
+ - **Names — done by A1.3.** The `Fieldset_Name_List__c` and `List_Header_Fieldset__c` columns
244
+ on `Sync_Tracked_Object_Config__c` are populated by the same install CSV. No separate step.
245
+ - **Definitions — provisioned by Retail Execution, not deployed by this skill.** The `FieldSet`
246
+ metadata those names reference (chiefly `RetailMobilityRelevant`, wired to ~60 baseline rows on
247
+ standard objects — Account, Contact, Event, Task, Product2, `InternalOrganizationUnit`, …) is
248
+ **not shipped by the package** (a managed package can't own a FieldSet on a standard object) and
249
+ is **not** a manual deploy in this flow either: **enabling Retail Execution (A1.2) provisions
250
+ it.** So A1.4 is **not** an install/deploy step — there is no field-set "upload." But because the
251
+ package only *consumes* field sets via Schema describe and the **sync query-field path throws**
252
+ when a named set is missing (`SYNC_MetaDataUtils.getFieldsForFieldSetByFieldSetMapOrThrowException`
253
+ → `SYNCException("We couldn't find the <name> field set …")`, exercised by
254
+ `TrackedObjectUtilsTest.getFieldsForTOOrThrowException_unknownfieldSet_exception`), a missing set
255
+ is a **hard failure at first sync, not at install** — so **verify, don't assume.**
256
+ - **The verify (this is the read-back A1.4 was missing).** After the install, for each distinct
257
+ field-set name the installed baseline's `Sync_Tracked_Object_Config__c` rows reference
258
+ (`Fieldset_Name_List__c` + `List_Header_Fieldset__c`, split on `,`), confirm the set exists on the
259
+ object's schema — a **read-only `core` describe**, mirroring A1.2's post-write re-read:
260
+ - Per object, read the field-set map — `Schema.describeSObjects(new String[]{objName})[0]`
261
+ `.fieldSets.getMap()` via anonymous Apex (all describe variants — default options,
262
+ `SObjectDescribeOptions.FULL`, `Schema.getGlobalDescribe()`, and the static
263
+ `Schema.SObjectType.<obj>` reference — return the **same** field sets, verified on-org; the
264
+ default `describeSObjects` is fine), or a Tooling `GET /tooling/query?q=SELECT DeveloperName,
265
+ NamespacePrefix FROM FieldSet WHERE EntityDefinition.QualifiedApiName = '<obj>'`. The Tooling
266
+ **`WHERE EntityDefinition.QualifiedApiName` filter is mandatory** — an unfiltered `FROM FieldSet`
267
+ returns **zero rows** (reads as "no field sets" — a trap).
268
+ - **Compare on the BARE name, case-insensitively — do NOT `containsKey` the raw referenced name.**
269
+ `fieldSets.getMap()` keys are **all-lowercase and fully namespace-qualified** (`<ns>__name`), so
270
+ `getMap().containsKey('RetailMobilityRelevant')` returns **false even when the set exists** (the
271
+ real key is e.g. `<ns>__retailmobilityrelevant`) — the classic false-missing this step must
272
+ avoid. Build the present-set from `FieldSet.getName().toLowerCase()` (`getName()` is the bare
273
+ local name; `getNamespace()` is the prefix, separately), strip any `<prefix>__` off the referenced
274
+ name (`substringAfterLast('__')`), and compare lowercased. In Tooling, compare `DeveloperName`
275
+ case-insensitively.
276
+ - **Whether a set is prefixed depends on the ORG, not the `$$NS` macro.** The CSV names use `$$NS`
277
+ (`$$NSMobilityRelevant` → `<ns>__MobilityRelevant` at install). But `RetailMobilityRelevant`
278
+ (no `$$NS`) is **not** always unprefixed: in a pure **subscriber** org RE provisions it as
279
+ **standard** metadata (`NamespacePrefix` null), whereas in a **source-deployed / namespaced** org
280
+ (the `Organization.NamespacePrefix` branch A1.1 handles) **every** set — including
281
+ `RetailMobilityRelevant` — carries the **org namespace** (`getNamespace()` = `<ns>`, confirmed
282
+ on-org). Comparing on the bare, lowercased local name (above) is correct for **both** org types;
283
+ assuming a fixed prefix is not.
284
+ - **All present → report verified** (RE provisioned them; nothing to deploy). This is the
285
+ per-object `assert:` step A1.4 must end on, same convention as every other write's read-back.
286
+ - **Any missing → report and stop that object.** Name the object + the absent field set, and
287
+ state the owner: **Retail Execution provisioning (A1.2 / core-RE)**, not this skill and not the
288
+ package. Do **not** attempt to deploy the FieldSet as a workaround — RE owns it; a hand-deployed
289
+ set risks drifting from what RE and the baseline expect. If RE is enabled and the set is still
290
+ absent, that's an RE-provisioning issue to escalate to the CG Cloud platform / Retail Execution
291
+ owners, not a `FieldSet` this skill ships.
292
+
293
+ ## Act 1 end state
294
+
295
+ - **Sync Management App metadata confirmed present and its namespace resolved** — either a
296
+ managed-package install (Tooling API `InstalledSubscriberPackage` match, **namespace prefix +
297
+ installed version captured** from the matched row) **or** the org's own namespace (`SELECT
298
+ NamespacePrefix FROM Organization`, confirmed by resolving `<orgNs>Sync_Config__c` — no version in
299
+ this case). On **neither** resolving, the run halted with "Sync Management App metadata not
300
+ present" (install/deploy is out of scope). This is A1.1's opening gate, ahead of RE enablement (A1.2).
301
+ - A1.1/A1.2 readiness reported as an explicit Pass/Fail checklist; a hard miss halted the run.
302
+ - Admin-confirmed baseline (the Retail Execution root config, plus any sub-configs the admin also confirmed)
303
+ **installed** across the four objects via the `/v1/syncconfig/install` endpoint (GET discover →
304
+ confirmation gate → POST install), with `installed_config_id` / `installed_version` captured from
305
+ the `InstallResponse` (never faked via raw sObject inserts). The install is the config: the root
306
+ `Sync_Config__c` and its values come fully-enumerated from the baseline CSVs — no separate
307
+ create-config step. Landing confirmed by the cheap **aggregate** check (sum of the four `core`
308
+ COUNT() reads == `InstallResponse.recordsInserted`) — **not** the per-object/baseline-manifest
309
+ comparison, which is Act 3's (A3.1/A3.2) and is deliberately not repeated here.
310
+ - Field-set names present (from the baseline CSV); the referenced field-set **definitions
311
+ verified present** on each tracked object by a read-only `core` describe (RE provisions them via
312
+ A1.2) — or any missing set reported-and-stopped with the owner named (RE provisioning), not
313
+ deployed around.
314
+
315
+ ## Gotchas
316
+
317
+ - **List-custom-setting defaults never auto-apply on DML.** This is why the baseline install (A1.3),
318
+ not a raw insert, is the only correct way to create the config — a package-wide constraint: don't
319
+ assume an inserted `Sync_Config__c` row has its declared defaults. The baseline CSVs carry every
320
+ value; a bare insert would not.
321
+ - **A dispatcher-404 for RE enablement is not "capability missing" — it's a transport switch.**
322
+ On a dispatcher-absent org, fall back to MDAPI: read via `Settings:RetailExecution` retrieve
323
+ and **write via `sf project deploy start --metadata "Settings:RetailExecution"`**. Prefer the
324
+ MDAPI fallback over stopping the step — fall back, don't stop. Only *advanced*-RE (the
325
+ `orgHasAdvncdRetailExecutionPilot` gate) is truly un-writable.
326
+ - **RE enable applies dependent-pref defaults.** Enabling `enableRetailExecution` can flip
327
+ sub-prefs you didn't set (for example, `enableVisitSharing` going true as a dependent default).
328
+ Always re-read after the write; report the post-write state, not the file you deployed.
329
+ - **Namespace first.** Resolve the live prefix (A1.1's namespace gate — package or org namespace) before any package-object path;
330
+ `SyncConfigInstall` handles it internally, but any sObject-REST path you emit must use the
331
+ resolved prefix — never a hardcoded one.
332
+ - **The install is idempotent by guard, not by luck** — a re-run against an installed
333
+ `configId` is a designed no-op; don't treat the guard message as an error.