@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.
- package/package.json +1 -1
- package/skills/agentforce-generate/SKILL.md +8 -0
- package/skills/agentforce-generate/references/actions-reference.md +2 -2
- package/skills/agentforce-generate/references/voice-modality-reference.md +51 -15
- package/skills/agentforce-generate/references/voice-telephony-cli.md +193 -0
- package/skills/agentforce-observe/SKILL.md +13 -9
- package/skills/agentforce-observe/references/ahm-alerts.md +193 -14
- package/skills/automation-sandbox-post-copy-config-generate/SKILL.md +24 -15
- package/skills/automation-sandbox-post-copy-config-generate/assets/config_template.json +11 -0
- package/skills/automation-sandbox-post-copy-config-generate/assets/json_schema.json +33 -1
- package/skills/automation-sandbox-post-copy-config-generate/references/configuration_catalog.md +32 -1
- package/skills/automation-sandbox-post-copy-configure/SKILL.md +75 -71
- package/skills/automation-sandbox-post-copy-configure/assets/scheduled_apex_template.apex +13 -0
- package/skills/automation-sandbox-post-copy-configure/examples/sample_scheduled_apex_config.json +13 -0
- package/skills/automation-sandbox-post-copy-configure/references/scheduled_apex_path.md +155 -0
- package/skills/automation-sandbox-post-copy-configure/scripts/build-scheduled-apex.mjs +62 -0
- package/skills/automation-sandbox-post-copy-configure/scripts/soql-escape-job-name.mjs +28 -0
- package/skills/consumer-goods-accruals-datakit-deploy/SKILL.md +383 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/setup.js +324 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/00-check-prerequisites.js +63 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/01-download-static-resource.js +100 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/02-replace-org-id.js +46 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/03-deploy-metadata.js +46 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/04-deploy-engine.js +198 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/05-deploy-tpm-accruals.js +231 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/06-create-dataspace.js +82 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/07-deploy-accruals-reports.js +517 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/08-deploy-ui.js +416 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/09-completion.js +44 -0
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/utils.js +514 -0
- package/skills/consumer-goods-sync-management-configure/SKILL.md +137 -0
- package/skills/consumer-goods-sync-management-configure/examples/scenarios.md +294 -0
- package/skills/consumer-goods-sync-management-configure/references/act1-setup-sync.md +333 -0
- package/skills/consumer-goods-sync-management-configure/references/act2-assign-users.md +324 -0
- package/skills/consumer-goods-sync-management-configure/references/act3-plan-verify.md +113 -0
- package/skills/consumer-goods-sync-management-configure/references/readiness-and-enablement.md +164 -0
- package/skills/consumer-goods-sync-management-configure/references/sync-management-app-install-backbone.md +159 -0
- package/skills/consumer-goods-sync-management-configure/references/transports-and-namespace.md +220 -0
- package/skills/consumer-goods-sync-management-configure/references/verify-and-smoke.md +175 -0
- package/skills/dx-org-analyze/SKILL.md +0 -1
- package/skills/dx-org-analyze/scripts/collect_org_data.py +2 -2
- package/skills/dx-org-analyze/scripts/compute_diff.py +2 -4
- package/skills/dx-org-analyze/scripts/introspect_org.py +4 -40
- package/skills/dx-org-manage/SKILL.md +6 -50
- package/skills/dx-org-manage/examples/README.md +10 -16
- package/skills/dx-org-manage/references/scratch-org-create.md +1 -1
- package/skills/dx-org-manage/references/scratch-org-operations.md +1 -1
- package/skills/dx-org-shape-manage/SKILL.md +4 -3
- package/skills/education-cloud-domain-configure/references/gotchas-extended.md +1 -0
- package/skills/experience-accessibility-validate/SKILL.md +8 -5
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-1-1-non-text-content.md +1 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-i-lists.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-ii-tables.md +20 -85
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-iii-form-labels.md +4 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-iv-regions.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-1-v-groups.md +2 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-3-5-identify-input.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-1-4-3-contrast.md +4 -14
- package/skills/experience-accessibility-validate/references/reviewers/sc-2-1-1-keyboard.md +9 -5
- package/skills/experience-accessibility-validate/references/reviewers/sc-2-4-4-link-purpose.md +1 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-2-4-6-headings-labels.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-1-pointer-gestures.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-2-pointer-cancellation.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-3-label-in-name.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-2-5-7-dragging-movement.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-3-2-1-on-focus.md +0 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-3-2-2-on-input.md +1 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-1-error-identification.md +1 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-2-labels-instructions.md +1 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-3-3-3-error-suggestion.md +1 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-i-name.md +4 -5
- package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-ii-role.md +1 -4
- package/skills/experience-accessibility-validate/references/reviewers/sc-4-1-2-iii-value.md +0 -4
- package/skills/experience-lwc-accessibility-jest-run/SKILL.md +104 -25
- package/skills/experience-lwc-accessibility-jest-run/assets/jest.config.js +4 -0
- package/skills/experience-lwc-accessibility-jest-run/assets/sa11y-jest-setup.js +5 -0
- package/skills/experience-ui-bundle-app-coordinate/SKILL.md +5 -5
- package/skills/experience-ui-bundle-features-generate/SKILL.md +65 -36
- package/skills/experience-ui-bundle-features-generate/references/angular/features.md +74 -0
- package/skills/experience-ui-bundle-features-generate/references/react/features.md +59 -0
- package/skills/experience-ui-bundle-features-generate/scripts/detect-framework.sh +73 -0
- package/skills/experience-ui-bundle-frontend-generate/SKILL.md +2 -2
- package/skills/experience-ui-bundle-metadata-generate/SKILL.md +26 -14
- package/skills/experience-ui-bundle-metadata-generate/references/angular-metadata-generate.md +37 -0
- package/skills/experience-ui-bundle-metadata-generate/references/react-metadata-generate.md +32 -0
- package/skills/experience-ui-bundle-metadata-generate/scripts/detect-framework.sh +73 -0
- package/skills/experience-ui-bundle-metadata-generate/scripts/verify-bundle-location.sh +30 -8
- package/skills/field-service-data-capture-migrate/SKILL.md +391 -0
- package/skills/field-service-data-capture-migrate/assets/sample-legacy-flow.flow-meta.xml +163 -0
- package/skills/field-service-data-capture-migrate/references/architecture-notes.md +40 -0
- package/skills/field-service-data-capture-migrate/references/component-mapping.md +278 -0
- package/skills/field-service-data-capture-migrate/references/converter-builder-contract.md +183 -0
- package/skills/field-service-data-capture-migrate/references/dc-platform-rules.md +130 -0
- package/skills/field-service-data-capture-migrate/references/fsm-dc-capability-catalog.md +215 -0
- package/skills/field-service-data-capture-migrate/references/known-deploy-errors.md +36 -0
- package/skills/field-service-data-capture-migrate/references/migration-checklist.md +121 -0
- package/skills/field-service-data-capture-migrate/references/transformer-rules.md +132 -0
- package/skills/field-service-data-capture-migrate/scripts/analyze_flow.py +277 -0
- package/skills/field-service-data-capture-migrate/scripts/convert_to_dc_spec.py +1311 -0
- package/skills/field-service-data-capture-migrate/scripts/cud_analysis.py +402 -0
- package/skills/field-service-data-capture-migrate/scripts/deploy_flow.sh +230 -0
- package/skills/field-service-data-capture-migrate/scripts/discover_subflow_tree.py +230 -0
- package/skills/field-service-data-capture-migrate/scripts/flow_input.py +186 -0
- package/skills/field-service-data-capture-migrate/scripts/flow_xml_utils.py +39 -0
- package/skills/field-service-data-capture-migrate/scripts/fsm_dc_catalog.py +413 -0
- package/skills/field-service-data-capture-migrate/scripts/generate_summary.py +199 -0
- package/skills/field-service-data-capture-migrate/scripts/json_to_flow_xml.py +146 -0
- package/skills/field-service-data-capture-migrate/scripts/manual_review_flags.py +42 -0
- package/skills/field-service-data-capture-migrate/scripts/retrieve_flow_rest.sh +155 -0
- package/skills/field-service-data-capture-migrate/scripts/subflow_names.py +49 -0
- package/skills/field-service-data-capture-migrate/scripts/transform_flow.py +1661 -0
- package/skills/field-service-data-capture-migrate/scripts/validate_flow.sh +147 -0
- package/skills/field-service-data-capture-migrate/scripts/vendor/build_flow.py +1258 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/SKILL.md +1 -1
- package/skills/life-sciences-fieldsalesrep-coordinate/references/orchestration-flow.md +1 -1
- package/skills/life-sciences-kam-coordinate/references/stage-5-data-and-plan-templates-overview.md +14 -1
- package/skills/mobile-apps-create/SKILL.md +1 -1
- package/skills/{platform-agentsetup-categories-fetch → platform-agenticsetup-categories-get}/SKILL.md +7 -7
- package/skills/platform-sandbox-configure/SKILL.md +108 -133
- package/skills/platform-sandbox-configure/references/api-response-shapes.md +39 -0
- package/skills/platform-sandbox-configure/references/definition-file-approach.md +73 -0
- package/skills/platform-widget-generate/SKILL.md +26 -18
- package/skills/platform-widget-generate/examples/formulas.json +191 -0
- package/skills/platform-widget-generate/references/widget-formulas.md +123 -0
- package/skills/platform-widget-generate/references/widget-meta-directives.md +4 -4
- package/skills/sales-call-scoring-configure/SKILL.md +318 -0
- package/skills/sales-call-scoring-configure/assets/best-practice-competencies.json +67 -0
- package/skills/sales-call-scoring-configure/assets/ootb-competencies.json +58 -0
- package/skills/sales-call-scoring-configure/references/admin-communication.md +79 -0
- package/skills/sales-call-scoring-configure/references/competency-crud.md +130 -0
- package/skills/sales-call-scoring-configure/scripts/create-competency.sh +166 -0
- package/skills/sales-call-scoring-configure/scripts/create-custom-competency.sh +166 -0
- package/skills/sales-call-scoring-configure/scripts/edit-competency.sh +185 -0
- package/skills/sales-call-scoring-configure/scripts/edit-custom-competency.sh +190 -0
- package/skills/sales-call-scoring-configure/scripts/enable-call-scoring.sh +436 -0
- package/skills/sales-call-scoring-configure/scripts/get-competency.sh +72 -0
- package/skills/sales-call-scoring-configure/scripts/get-custom-competency.sh +78 -0
- package/skills/sales-call-scoring-configure/scripts/install-best-practice-competencies.sh +223 -0
- package/skills/sales-call-scoring-configure/scripts/install-ootb-competencies.sh +237 -0
- package/skills/sales-call-scoring-configure/scripts/list-competencies.sh +99 -0
- package/skills/sales-call-scoring-configure/scripts/shared/auth.sh +116 -0
- package/skills/sales-call-scoring-configure/scripts/shared/cap.sh +86 -0
- package/skills/sales-call-scoring-configure/scripts/shared/soap.sh +267 -0
- package/skills/sales-call-scoring-configure/scripts/shared/soql.sh +25 -0
- package/skills/sales-call-scoring-configure/scripts/toggle-competency.sh +112 -0
- package/skills/sales-call-scoring-configure/scripts/toggle-custom-competency.sh +125 -0
- package/skills/sales-call-scoring-configure/scripts/verify-ootb-competencies.sh +116 -0
- package/skills/service-concierge-portal-generate/references/portal-deploy-runbook.md +1 -0
- package/skills/service-de-channel-activate/SKILL.md +6 -5
- package/skills/service-de-channel-create/SKILL.md +3 -3
- package/skills/service-de-channel-routing-configure/SKILL.md +3 -3
- package/skills/service-de-channel-settings-configure/SKILL.md +195 -0
- package/skills/service-de-channel-settings-configure/references/channel-settings-facets.md +152 -0
- package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/gotchas.md +3 -3
- package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/language-keywords.md +4 -4
- package/skills/{service-de-channel-consent-configure → service-de-channel-settings-configure}/references/worked-examples.md +14 -14
- package/skills/service-de-headless-channel-configure/SKILL.md +6 -6
- package/skills/service-de-headless-channel-configure/references/worked-examples.md +1 -1
- package/skills/service-helpagent-coordinate/SKILL.md +3 -2
- package/skills/service-helpagent-coordinate/references/channel-voice.md +15 -4
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +49 -31
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +71 -6
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/scripts/verify-child-verdict.mjs +26 -4
- package/skills/service-itsm-agentic-setup-cmdb-access-assign/SKILL.md +35 -10
- package/skills/service-itsm-agentic-setup-cmdb-access-assign/references/mcp-invocation.md +25 -5
- package/skills/service-itsm-agentic-setup-cmdb-bundle-deploy/SKILL.md +1 -1
- package/skills/service-itsm-agentic-setup-cmdb-configure/SKILL.md +5 -5
- package/skills/service-itsm-agentic-setup-cmdb-configure/references/mcp-invocation.md +1 -1
- package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +2 -2
- package/skills/service-itsm-agentic-setup-cmdb-coordinate/examples/output-templates.md +1 -1
- package/skills/service-itsm-agentic-setup-cmdb-discovery-configure/SKILL.md +25 -15
- package/skills/service-itsm-agentic-setup-employee-agent-configure/SKILL.md +8 -5
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/report-format.md +4 -2
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/workflow-detail.md +1 -1
- package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/render-report.mjs +29 -16
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md +8 -5
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/report-format.md +4 -2
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/workflow-detail.md +1 -1
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs +29 -16
- package/skills/service-itsm-agentic-setup-incident-management/SKILL.md +138 -68
- package/skills/service-itsm-agentic-setup-incident-management/examples/output-templates.md +31 -15
- package/skills/service-itsm-agentic-setup-incident-management/references/incident-persona-psg.md +156 -0
- package/skills/service-itsm-agentic-setup-incident-management/references/incident-preferences.md +148 -0
- package/skills/service-itsm-agentic-setup-incident-management/references/major-incident-management.md +162 -0
- package/skills/service-itsm-agentic-setup-incident-management/references/service-mgmt-privilege.md +149 -0
- package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +103 -89
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone.json +2 -2
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/predefined-incident-policy.json +21 -39
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +3 -3
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +18 -1
- package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +63 -37
- package/skills/service-omni-attribute-routing-configure/SKILL.md +53 -0
- package/skills/service-omni-attribute-routing-configure/references/api-notes.md +7 -0
- package/skills/service-omni-attribute-routing-configure/scripts/configure-and-report.sh +224 -0
- package/skills/service-omni-attribute-routing-configure/scripts/tests/test_attribute_routing_contracts.py +137 -0
- package/skills/service-omni-channel-inventory-analyze/SKILL.md +96 -0
- package/skills/service-omni-channel-inventory-analyze/references/api-notes.md +52 -0
- package/skills/service-omni-channel-inventory-analyze/scripts/analyze.sh +185 -0
- package/skills/service-omni-channel-inventory-analyze/scripts/tests/_bootstrap.py +84 -0
- package/skills/service-omni-channel-inventory-analyze/scripts/tests/test_inventory_analyze_contracts.py +141 -0
- package/skills/service-omni-channel-limits-analyze/SKILL.md +70 -0
- package/skills/service-omni-channel-limits-analyze/references/api-notes.md +22 -0
- package/skills/service-omni-channel-limits-analyze/scripts/analyze.sh +159 -0
- package/skills/service-omni-channel-limits-analyze/scripts/tests/_bootstrap.py +87 -0
- package/skills/service-omni-channel-limits-analyze/scripts/tests/test_limits_analyze_contracts.py +99 -0
- package/skills/service-omni-channel-setup-coordinate/SKILL.md +12 -20
- package/skills/service-omni-channel-setup-coordinate/scripts/integration-driver.sh +55 -5
- package/skills/service-omni-channel-setup-coordinate/scripts/tests/test_omni_contracts.py +38 -0
- package/skills/service-omni-command-center-analyze/SKILL.md +2 -2
- package/skills/service-omni-command-center-analyze/scripts/analyze.sh +3 -3
- package/skills/dx-org-manage/examples/snapshots/error_output.json +0 -9
- package/skills/dx-org-manage/examples/snapshots/success_output.json +0 -15
- package/skills/dx-org-manage/references/cli_flags.md +0 -67
- package/skills/dx-org-manage/references/creating-snapshot.md +0 -103
- package/skills/dx-org-manage/references/snapshot_usage.md +0 -74
- package/skills/experience-accessibility-validate/scripts/contrast-ratio.py +0 -153
- package/skills/experience-lwc-accessibility-jest-run/references/running-sa11y-jest-tests.md +0 -205
- package/skills/experience-ui-bundle-features-generate/scripts/verify-react-bundle.sh +0 -14
- /package/skills/experience-ui-bundle-features-generate/references/{conflict-resolution-schema.json → common/conflict-resolution-schema.json} +0 -0
- /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.
|