@salesforce/afv-skills 1.41.0 → 1.43.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 +2 -6
- package/skills/automation-sandbox-post-copy-config-generate/SKILL.md +3 -0
- package/skills/automation-sandbox-post-copy-configure/SKILL.md +4 -0
- package/skills/design-systems-slds-validate/SKILL.md +2 -2
- package/skills/dx-app-analytics-query/SKILL.md +1 -3
- package/skills/dx-devops-conflict-resolve/SKILL.md +205 -0
- package/skills/dx-devops-conflict-resolve/examples/conflict-workflows.md +165 -0
- package/skills/dx-devops-conflict-resolve/references/deploy-failure-resolution.md +75 -0
- package/skills/dx-devops-conflict-resolve/references/git-conflict-resolution.md +124 -0
- package/skills/dx-devops-conflict-resolve/scripts/detect-conflicts.sh +91 -0
- package/skills/dx-devops-conflict-resolve/scripts/diagnose-deploy-failure.sh +156 -0
- package/skills/dx-devops-request-status/SKILL.md +160 -0
- package/skills/dx-devops-request-status/examples/polling-workflows.md +101 -0
- package/skills/dx-devops-request-status/references/cli-commands.md +176 -0
- package/skills/dx-devops-request-status/scripts/poll-status.sh +134 -0
- package/skills/dx-devops-test-failures-analyze/SKILL.md +6 -6
- package/skills/dx-devops-test-pipeline-configure/SKILL.md +7 -7
- package/skills/dx-devops-test-suite-assignments-configure/SKILL.md +6 -6
- package/skills/dx-devops-test-suite-run/SKILL.md +6 -6
- package/skills/dx-devops-work-item-manage/SKILL.md +2 -0
- package/skills/dx-org-manage/references/creating-scratch-org.md +5 -2
- package/skills/dx-org-manage/references/creating-snapshot.md +1 -0
- package/skills/dx-org-shape-manage/SKILL.md +152 -0
- package/skills/dx-org-shape-manage/examples/create_error_output.json +9 -0
- package/skills/dx-org-shape-manage/examples/create_success_output.json +9 -0
- package/skills/dx-org-shape-manage/examples/delete_output.json +11 -0
- package/skills/dx-org-shape-manage/examples/list_inactive_output.json +32 -0
- package/skills/dx-org-shape-manage/examples/list_output.json +24 -0
- package/skills/dx-org-shape-manage/references/cli_flags.md +135 -0
- package/skills/dx-org-switch/SKILL.md +2 -2
- package/skills/dx-org-trial-expiration-check/SKILL.md +2 -0
- package/skills/dx-pkg-post-install-configure/SKILL.md +3 -0
- package/skills/education-cloud-multi-campus-configure/SKILL.md +211 -0
- package/skills/education-cloud-multi-campus-configure/examples/hierarchy_visualization.md +174 -0
- package/skills/education-cloud-multi-campus-configure/examples/output_examples.md +54 -0
- package/skills/education-cloud-multi-campus-configure/examples/sample_hierarchy_input.csv +29 -0
- package/skills/education-cloud-multi-campus-configure/examples/sample_hierarchy_input_edgecases.csv +16 -0
- package/skills/education-cloud-multi-campus-configure/references/account_recordtype_prerequisite.md +44 -0
- package/skills/education-cloud-multi-campus-configure/references/delta_computation.md +33 -0
- package/skills/education-cloud-multi-campus-configure/references/error_handling.md +198 -0
- package/skills/education-cloud-multi-campus-configure/references/foundation_prerequisites.md +54 -0
- package/skills/education-cloud-multi-campus-configure/references/gotchas.md +16 -0
- package/skills/education-cloud-multi-campus-configure/references/hierarchy_parsing_rules.md +133 -0
- package/skills/education-cloud-multi-campus-configure/references/mcp-invocation.md +75 -0
- package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/SKILL.md +1 -1
- package/skills/experience-cms-brand-apply/SKILL.md +4 -1
- package/skills/experience-cms-brand-create/SKILL.md +197 -0
- package/skills/experience-cms-brand-create/assets/brand-template.json +329 -0
- package/skills/experience-cms-brand-create/references/brand-anatomy.md +120 -0
- package/skills/experience-cms-brand-create/references/disk-contract.md +84 -0
- package/skills/experience-cms-content-generate/SKILL.md +190 -0
- package/skills/experience-cms-content-generate/assets/display-formats.md +84 -0
- package/skills/experience-cms-content-generate/assets/payloads/create-content-bulk.json +11 -0
- package/skills/experience-cms-content-generate/assets/payloads/create-content-single.json +11 -0
- package/skills/experience-cms-content-generate/assets/payloads/publish-content.json +4 -0
- package/skills/experience-cms-content-generate/assets/payloads/update-content.json +9 -0
- package/skills/experience-cms-content-generate/assets/questions.md +241 -0
- package/skills/experience-cms-content-generate/examples/create-content-call.md +81 -0
- package/skills/experience-cms-content-generate/references/bulk-batching.md +56 -0
- package/skills/experience-cms-content-generate/references/content-type-classification.md +88 -0
- package/skills/experience-cms-content-generate/references/content-write-tool.md +95 -0
- package/skills/experience-cms-content-generate/references/delegation-protocol.md +37 -0
- package/skills/experience-cms-content-generate/references/edit-publish-workflow.md +63 -0
- package/skills/experience-cms-content-generate/references/error-recovery.md +72 -0
- package/skills/experience-cms-content-generate/references/identifier-resolution.md +26 -0
- package/skills/experience-cms-content-generate/references/intent-routing.md +45 -0
- package/skills/experience-cms-content-generate/references/principles.md +19 -0
- package/skills/experience-cms-content-generate/references/ux-rules.md +68 -0
- package/skills/experience-cms-content-generate/references/workspace-resolution.md +33 -0
- package/skills/experience-cms-content-type-generate/SKILL.md +449 -0
- package/skills/experience-cms-content-type-generate/assets/discovery-prompts.md +79 -0
- package/skills/experience-cms-content-type-generate/assets/schema-example.json +70 -0
- package/skills/experience-cms-content-type-generate/references/agent-checklist.md +50 -0
- package/skills/experience-cms-content-type-generate/references/anti-patterns.md +39 -0
- package/skills/experience-cms-content-type-generate/references/deployment-errors.md +27 -0
- package/skills/experience-cms-content-type-generate/references/discovery-details.md +106 -0
- package/skills/experience-cms-content-type-generate/references/discovery-query-rules.md +85 -0
- package/skills/experience-cms-content-type-generate/references/edit-fields-loop.md +48 -0
- package/skills/experience-cms-content-type-generate/references/pre-deploy-checklist.md +21 -0
- package/skills/experience-cms-content-type-generate/references/retrieve-and-reconcile.md +105 -0
- package/skills/experience-cms-content-type-generate/references/schema-rules.md +51 -0
- package/skills/experience-cms-content-type-generate/references/schema-summary-format.md +60 -0
- package/skills/experience-lds-graphql-generate/SKILL.md +4 -0
- package/skills/experience-lwc-accessibility-jest-run/SKILL.md +79 -0
- package/skills/experience-lwc-accessibility-jest-run/references/running-sa11y-jest-tests.md +205 -0
- package/skills/experience-lwc-design-generate/SKILL.md +5 -4
- package/skills/experience-lwc-generate/SKILL.md +10 -9
- package/skills/experience-ui-bundle-deploy/references/dev-preview.md +21 -0
- package/skills/experience-ui-bundle-deploy/references/social-login.md +1 -0
- package/skills/experience-ui-bundle-file-upload-generate/SKILL.md +6 -6
- package/skills/experience-ui-bundle-localize/SKILL.md +30 -37
- package/skills/experience-ui-bundle-localize/references/gotchas.md +23 -7
- package/skills/experience-ui-bundle-localize/references/i18n-setup.md +48 -4
- package/skills/experience-ui-bundle-localize/references/label-xml.md +22 -8
- package/skills/experience-ui-bundle-localize/references/verifying.md +39 -11
- package/skills/experience-ui-bundle-localize/scripts/detect-bundle-type.sh +118 -15
- package/skills/experience-ui-bundle-localize/scripts/tests/test-detect-bundle-type.sh +187 -0
- package/skills/experience-ui-bundle-mfa-configure/SKILL.md +13 -2
- package/skills/experience-ui-bundle-mfa-configure/references/social-login.md +1 -0
- package/skills/experience-ui-bundle-project-generate/SKILL.md +2 -2
- package/skills/integration-connectivity-generate/SKILL.md +11 -10
- package/skills/integration-eventing-cdc-configure/SKILL.md +6 -6
- package/skills/integration-eventing-subscription-configure/SKILL.md +6 -5
- package/skills/mobile-platform-native-capabilities-integrate/SKILL.md +2 -2
- package/skills/mobile-platform-offline-validate/scripts/package.json +1 -1
- package/skills/platform-agentexchange-partner-offers-configure/SKILL.md +8 -8
- package/skills/platform-custom-application-generate/SKILL.md +2 -0
- package/skills/platform-custom-field-generate/SKILL.md +8 -6
- package/skills/platform-custom-metadata-type-generate/SKILL.md +460 -0
- package/skills/platform-custom-metadata-type-generate/references/cmdt-records.md +251 -0
- package/skills/platform-custom-metadata-type-generate/scripts/sanitize-developer-name.sh +46 -0
- package/skills/platform-custom-setting-generate/SKILL.md +419 -0
- package/skills/platform-dataspace-access-configure/SKILL.md +3 -3
- package/skills/platform-sharing-owd-configure/SKILL.md +3 -0
- package/skills/platform-value-set-generate/SKILL.md +2 -0
- package/skills/service-agentforce-channel-configure/SKILL.md +29 -20
- package/skills/service-agentforce-channel-configure/assets/BotEmailDefinition.botEmailDefinition-meta.xml +36 -0
- package/skills/service-agentforce-channel-configure/assets/email/unfiled$public/AgentforceForServiceEmailTemplate.email +17 -0
- package/skills/service-agentforce-channel-configure/assets/email/unfiled$public/AgentforceForServiceEmailTemplate.email-meta.xml +29 -0
- package/skills/service-agentforce-channel-configure/assets/mdapi-package.xml +25 -0
- package/skills/service-agentforce-channel-configure/assets/settings-mdapi-package.xml +30 -0
- package/skills/service-agentforce-channel-configure/references/agent-wiring.md +20 -0
- package/skills/service-agentforce-channel-configure/references/botemaildefinition.md +107 -0
- package/skills/service-agentforce-channel-configure/references/channel-branch-email.md +203 -50
- package/skills/service-agentforce-channel-configure/references/channel-types.md +30 -3
- package/skills/service-agentforce-channel-configure/references/queue-resolution.md +17 -8
- package/skills/service-agentforce-channel-configure/references/routing-flow.md +14 -3
- package/skills/service-agentforce-channel-configure/scripts/validate-botemaildefinition.py +126 -0
- package/skills/service-agentforce-channel-configure/scripts/validate-emailtemplate.py +133 -0
- package/skills/service-de-channel-activate/SKILL.md +271 -0
- package/skills/service-de-channel-activate/references/gotchas.md +31 -0
- package/skills/service-de-channel-activate/references/phone-verification.md +96 -0
- package/skills/service-de-channel-activate/references/worked-examples.md +14 -0
- package/skills/service-de-channel-consent-configure/SKILL.md +230 -0
- package/skills/service-de-channel-consent-configure/references/gotchas.md +41 -0
- package/skills/service-de-channel-consent-configure/references/language-keywords.md +84 -0
- package/skills/service-de-channel-consent-configure/references/worked-examples.md +134 -0
- package/skills/service-de-channel-create/SKILL.md +369 -0
- package/skills/service-de-channel-create/references/apple.md +59 -0
- package/skills/service-de-channel-create/references/connect-insert.md +84 -0
- package/skills/service-de-channel-create/references/facebook.md +154 -0
- package/skills/service-de-channel-create/references/line.md +66 -0
- package/skills/service-de-channel-create/references/sms.md +98 -0
- package/skills/service-de-channel-create/references/whatsapp.md +98 -0
- package/skills/service-de-channel-create/references/worked-examples.md +70 -0
- package/skills/service-de-channel-routing-configure/SKILL.md +345 -0
- package/skills/service-de-channel-routing-configure/references/asa-routing.md +90 -0
- package/skills/service-de-channel-routing-configure/references/gotchas.md +27 -0
- package/skills/service-de-channel-routing-configure/references/queue-creation.md +123 -0
- package/skills/service-de-channel-routing-configure/references/target-locate.md +98 -0
- package/skills/service-de-channel-routing-configure/references/worked-examples.md +174 -0
- package/skills/service-de-headless-channel-configure/SKILL.md +305 -0
- package/skills/service-de-headless-channel-configure/references/gotchas.md +27 -0
- package/skills/service-de-headless-channel-configure/references/inputs.md +49 -0
- package/skills/service-de-headless-channel-configure/references/output-envelopes.md +53 -0
- package/skills/service-de-headless-channel-configure/references/partial-success.md +24 -0
- package/skills/service-de-headless-channel-configure/references/terms-and-conditions.md +54 -0
- package/skills/service-de-headless-channel-configure/references/worked-examples.md +108 -0
- package/skills/service-de-waba-integrate/SKILL.md +227 -0
- package/skills/service-digital-engagement-channel-configure/scripts/check-api-version.sh +29 -0
- package/skills/service-digital-engagement-messaging-site-integrate/SKILL.md +10 -9
- package/skills/service-digital-engagement-messaging-site-integrate/references/lwr_patch.md +39 -21
- package/skills/service-digital-engagement-messaging-site-integrate/scripts/patch_lwr_bundle.sh +157 -96
- package/skills/service-email-to-case-configure/SKILL.md +190 -0
- package/skills/service-email-to-case-configure/assets/CaseSettings.settings-meta.xml +45 -0
- package/skills/service-email-to-case-configure/examples/CaseSettings-two-addresses.settings-meta.xml +36 -0
- package/skills/service-email-to-case-configure/references/apply-mechanics.md +73 -0
- package/skills/service-email-to-case-configure/references/routing_address_reference.md +73 -0
- package/skills/service-email-to-case-configure/references/troubleshooting.md +25 -0
- package/skills/service-email-to-case-configure/scripts/apply-casesettings.py +1315 -0
- package/skills/service-email-to-case-configure/scripts/check-agent-email-capability.sh +26 -0
- package/skills/service-email-to-case-configure/scripts/tests/__init__.py +0 -0
- package/skills/service-email-to-case-configure/scripts/tests/_bootstrap.py +45 -0
- package/skills/service-email-to-case-configure/scripts/tests/_fakeorg.py +366 -0
- package/skills/service-email-to-case-configure/scripts/tests/_run.py +84 -0
- package/skills/service-email-to-case-configure/scripts/tests/test_apply_org_scenarios.py +655 -0
- package/skills/service-email-to-case-configure/scripts/tests/test_get_session.py +134 -0
- package/skills/service-email-to-case-configure/scripts/tests/test_new_capabilities.py +193 -0
- package/skills/service-email-to-case-configure/scripts/tests/test_validate_casesettings.py +170 -0
- package/skills/service-email-to-case-configure/scripts/validate-casesettings.py +229 -0
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +33 -15
- package/skills/service-itsm-agentic-setup-agentforce-coordinate/examples/output-templates.md +63 -47
- package/skills/service-itsm-agentic-setup-agentforce-studio-configure/SKILL.md +17 -12
- package/skills/service-itsm-agentic-setup-agentforce-studio-configure/references/cli-invocation.md +5 -3
- package/skills/service-itsm-agentic-setup-agentforce-studio-configure/scripts/classify-enable-plan.mjs +11 -3
- package/skills/service-itsm-agentic-setup-agentforce-studio-validate/SKILL.md +8 -6
- package/skills/service-itsm-agentic-setup-agentforce-studio-validate/references/cli-invocation.md +3 -3
- package/skills/service-itsm-agentic-setup-agentforce-studio-validate/scripts/classify-readiness.mjs +11 -3
- package/skills/service-itsm-agentic-setup-configure/SKILL.md +5 -5
- package/skills/service-itsm-agentic-setup-configure/examples/output-templates.md +5 -5
- package/skills/service-itsm-agentic-setup-employee-agent-configure/SKILL.md +2 -2
- package/skills/service-itsm-agentic-setup-employee-agent-configure/references/report-format.md +11 -7
- package/skills/service-itsm-agentic-setup-employee-agent-configure/scripts/render-report.mjs +20 -7
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md +10 -6
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/action-availability.md +7 -7
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/references/report-format.md +11 -7
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/build-create-body.mjs +24 -17
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/classify-action-availability.mjs +98 -58
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/render-report.mjs +20 -7
- package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/scripts/strip-release-management.mjs +176 -0
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/SKILL.md +19 -19
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/cli-invocation.md +3 -4
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/helper-contracts.md +6 -6
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/references/permset-topology.md +3 -10
- package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/scripts/classify-permset-availability.mjs +7 -9
- package/skills/service-itsm-incident-mgmt-configure/SKILL.md +2 -0
- package/skills/service-itsm-incident-priority-configure/SKILL.md +15 -12
- package/skills/service-itsm-incident-priority-configure/examples/matrix-operations.md +27 -1
- package/skills/service-itsm-incident-priority-configure/references/sf-cli-invocation.md +37 -6
- package/skills/service-native-voice-recording-transcription-configure/SKILL.md +146 -0
- package/skills/service-native-voice-recording-transcription-configure/assets/confirmation-output.json +16 -0
- package/skills/service-native-voice-recording-transcription-configure/assets/package.xml +22 -0
- package/skills/service-native-voice-recording-transcription-configure/references/thunderbird-voice-settings.md +101 -0
- package/skills/service-native-voice-recording-transcription-configure/scripts/enable-recording-transcription.sh +181 -0
- package/skills/data360-activate/README.md +0 -38
- package/skills/data360-activate/SKILL.md +0 -127
- package/skills/data360-connect/README.md +0 -57
- package/skills/data360-connect/SKILL.md +0 -163
- package/skills/data360-connect/examples/connections/heroku-postgres.json +0 -15
- package/skills/data360-connect/examples/connections/ingest-api-connection.json +0 -5
- package/skills/data360-connect/examples/connections/ingest-api-schema.json +0 -31
- package/skills/data360-connect/examples/connections/redshift.json +0 -16
- package/skills/data360-connect/examples/connections/sharepoint-unstructured.json +0 -20
- package/skills/data360-connect/examples/connections/snowflake-connection.json +0 -42
- package/skills/data360-harmonize/README.md +0 -31
- package/skills/data360-harmonize/SKILL.md +0 -126
- package/skills/data360-orchestrate/README.md +0 -120
- package/skills/data360-orchestrate/SKILL.md +0 -263
- package/skills/data360-orchestrate/assets/definitions/activation-target.template.json +0 -5
- package/skills/data360-orchestrate/assets/definitions/activation.template.json +0 -7
- package/skills/data360-orchestrate/assets/definitions/calculated-insight.template.json +0 -7
- package/skills/data360-orchestrate/assets/definitions/data-action-target.template.json +0 -5
- package/skills/data360-orchestrate/assets/definitions/data-action.template.json +0 -5
- package/skills/data360-orchestrate/assets/definitions/data-graph.template.json +0 -21
- package/skills/data360-orchestrate/assets/definitions/data-stream.template.json +0 -55
- package/skills/data360-orchestrate/assets/definitions/dmo.template.json +0 -17
- package/skills/data360-orchestrate/assets/definitions/identity-resolution.template.json +0 -30
- package/skills/data360-orchestrate/assets/definitions/mapping.template.json +0 -14
- package/skills/data360-orchestrate/assets/definitions/relationship.template.json +0 -12
- package/skills/data360-orchestrate/assets/definitions/search-index.template.json +0 -9
- package/skills/data360-orchestrate/assets/definitions/segment.template.json +0 -16
- package/skills/data360-orchestrate/references/feature-readiness.md +0 -157
- package/skills/data360-orchestrate/references/plugin-setup.md +0 -138
- package/skills/data360-orchestrate/scripts/bootstrap-plugin.sh +0 -53
- package/skills/data360-orchestrate/scripts/diagnose-org.mjs +0 -511
- package/skills/data360-orchestrate/scripts/generate-manifest.mjs +0 -68
- package/skills/data360-orchestrate/scripts/verify-plugin.sh +0 -58
- package/skills/data360-prepare/README.md +0 -50
- package/skills/data360-prepare/SKILL.md +0 -203
- package/skills/data360-prepare/examples/ingestion-api/.env.example +0 -8
- package/skills/data360-prepare/examples/ingestion-api/README.md +0 -48
- package/skills/data360-prepare/examples/ingestion-api/send-data.py +0 -144
- package/skills/data360-query/README.md +0 -43
- package/skills/data360-query/SKILL.md +0 -128
- package/skills/data360-query/examples/search-indexes/hybrid-structured.json +0 -44
- package/skills/data360-query/examples/search-indexes/vector-knowledge.json +0 -43
- package/skills/data360-segment/README.md +0 -35
- package/skills/data360-segment/SKILL.md +0 -123
- package/skills/service-helpagent-coordinate/references/channel-help-portal.md +0 -22
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-1-1-non-text-content.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-3-1-i-lists.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-3-1-ii-tables.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-3-1-iii-form-labels.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-3-1-iv-regions.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-3-1-v-groups.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-3-5-identify-input.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-1-4-3-contrast.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-2-1-1-keyboard.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-2-4-4-link-purpose.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-2-4-6-headings-labels.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-2-5-1-pointer-gestures.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-2-5-2-pointer-cancellation.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-2-5-3-label-in-name.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-2-5-7-dragging-movement.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-3-2-1-on-focus.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-3-2-2-on-input.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-3-3-1-error-identification.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-3-3-2-labels-instructions.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-3-3-3-error-suggestion.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-4-1-2-i-name.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-4-1-2-ii-role.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/reviewers/sc-4-1-2-iii-value.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/vision/sc-1-1-1-non-text-content.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/vision/sc-1-4-1-use-of-color.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/vision/sc-1-4-10-resize-reflow.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/vision/sc-1-4-11-non-text-contrast.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/references/vision/sc-1-4-3-contrast.md +0 -0
- /package/skills/{experience-lwc-accessibility-validate → experience-accessibility-validate}/scripts/contrast-ratio.py +0 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: service-de-channel-routing-configure-target-locate
|
|
3
|
+
description: "Load when configuring a non-queue routing type on service-de-channel-routing-configure (Flow, ASA, Digital Worker, or direct User). Holds the per-domain SOQL to locate and validate an eligible SessionHandler target, the exact Id shape each PATCH needs, the FallbackQueue requirement matrix, and the per-domain 'no eligible target' Setup pointer. DO NOT load this for the Omni-Channel Queue path — see references/queue-creation.md."
|
|
4
|
+
metadata:
|
|
5
|
+
version: "1.0"
|
|
6
|
+
related-skills: service-de-channel-routing-configure
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Locating a SessionHandler target (Flow / ASA / Digital Worker / User)
|
|
10
|
+
|
|
11
|
+
`MessagingChannel.SessionHandler` is a polymorphic foreign key. Its domain (from `MessagingChannel.entity.xml`) is `Queue, FlowDefinition, User, BotDefinition, AgenticCtxtDecorDefinition`. The Id prefix identifies the domain, and the server-side `validateSessionHandler` enforces a per-domain FallbackQueue rule that this skill must satisfy before the PATCH will succeed.
|
|
12
|
+
|
|
13
|
+
## FallbackQueue requirement matrix (server-enforced)
|
|
14
|
+
|
|
15
|
+
| routingType | SessionHandlerId prefix | FallbackQueueId |
|
|
16
|
+
| --- | --- | --- |
|
|
17
|
+
| queue | `00G` | **must be null** — a non-null value is rejected with `UnsupportedFallbackQueue` |
|
|
18
|
+
| flow | `300` | **required** — null is rejected with *"A Fallback Queue must be specified when selecting a Flow routing method."* (verified live on sdb6c 2026-08-12) |
|
|
19
|
+
| asa | `0Xx` | **required** — null rejected with `MissingFallbackQueueForAsaRouting` |
|
|
20
|
+
| digital_worker | `1iE` | **required** — null rejected with `MissingFallbackQueueForDigitalWorkerRouting` |
|
|
21
|
+
| user | `005` | **must be null** |
|
|
22
|
+
|
|
23
|
+
For every FallbackQueue-required path, resolve a FallbackQueue **first** (see below) so the SessionHandler + FallbackQueue can be written in a single PATCH — the record must never sit in an invalid intermediate state.
|
|
24
|
+
|
|
25
|
+
## Resolving a FallbackQueue (flow / asa / digital_worker)
|
|
26
|
+
|
|
27
|
+
The FallbackQueue is an Omni-Channel-enabled, MessagingSession-capable Queue — the same eligibility as the primary Queue path. Enumerate and let the user pick (or reuse the one they already have in mind):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
sf data query --target-org '{ORG_ALIAS}' \
|
|
31
|
+
--query "SELECT Id, Name, DeveloperName FROM Group WHERE Type = 'Queue' AND QueueRoutingConfigId != null AND Id IN (SELECT QueueId FROM QueueSobject WHERE SobjectType = 'MessagingSession') ORDER BY Name" \
|
|
32
|
+
--json > /tmp/ccr-fallback-queues.json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Each row's `Id` (a `00G` `Group.Id`) is a valid `{FALLBACK_QUEUE_ID}`. If this returns 0 rows, emit `{ok:false, kind:"no-fallback-queue", ...}` — the user must create a MessagingSession queue (queue path → `references/queue-creation.md`) before Flow/ASA/Digital Worker routing can be configured.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Flow (`300` FlowDefinition) — VERIFIED live on sdb6c
|
|
40
|
+
|
|
41
|
+
The SessionHandler value is the **`FlowDefinition.Id`** (`300`-prefixed), not the flow version. Eligible flows are `ProcessType='RoutingFlow'` with an active version. `ProcessType` lives on `FlowDefinitionView` (the `FlowDefinition` sObject has no `ProcessType` column), and `FlowDefinitionView.DurableId` equals the `300` FlowDefinition Id **only for org-local flows** (namespaced/packaged flows carry a `<namespace>__<ApiName>` DurableId that is *not* a `300` id and can't be used directly). So filter to org-local, active RoutingFlows:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
sf data query --target-org '{ORG_ALIAS}' \
|
|
45
|
+
--query "SELECT DurableId, Label, ApiName, NamespacePrefix, IsActive, ActiveVersionId FROM FlowDefinitionView WHERE ProcessType = 'RoutingFlow' AND IsActive = true AND NamespacePrefix = null ORDER BY Label" \
|
|
46
|
+
--json > /tmp/ccr-flows.json
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Keep only rows where `DurableId` starts with `300`. That `DurableId` is `{TARGET_ID}`. Present the list, let the user pick, resolve a FallbackQueue, then Stage 5 PATCH (`SessionHandlerId={TARGET_ID} FallbackQueueId={FALLBACK_QUEUE_ID}`).
|
|
50
|
+
|
|
51
|
+
If 0 eligible rows: `{ok:false, kind:"no-eligible-target", routingType:"flow", hint:"no active Omni-Channel RoutingFlow found — build one in Setup → Flows (template 'Route Work Item' / process type Routing Flow) and activate it, then re-run this skill"}`.
|
|
52
|
+
|
|
53
|
+
**Verified 2026-08-12 (sdb6c):** `DirectToAgentFlow` (`300SG0000002gw1YAA`, active RoutingFlow) + FallbackQueue `Messaging_Queue` (`00GSG0000000LSf2AM`) PATCHed onto Enhanced channel `Customer_Support` (`0MjSG0000004rIf0AI`) → success, both fields persisted. Nulling the FallbackQueue afterward was rejected with the "A Fallback Queue must be specified" message. Channel restored to null/null.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## ASA (`0Xx` BotDefinition) — VERIFIED live on sdb6c
|
|
58
|
+
|
|
59
|
+
ASA = an Agentforce Service Agent bot: `BotDefinition WHERE Type='ExternalCopilot' AND AgentType='EinsteinServiceAgent'`, routable only if it has a linked bot user AND an active version. The full precondition/enumeration/selection detail lives in `references/asa-routing.md` — load that. ASA additionally **requires a FallbackQueue** (resolve one as above), which the PATCH writes alongside the `0Xx` SessionHandler.
|
|
60
|
+
|
|
61
|
+
**Verified 2026-08-12 (sdb6c):** `Type='ExternalCopilot' AND AgentType='EinsteinServiceAgent'` returns two bots; one (`0XxSG000000Sv9p0AC`) has both `BotUserId` and an active `BotVersion` (routable), the other (`ASA2`) has no active version (listed but flagged not-live). Note: the Data-API `BotDefinition` sObject exposes only `Type` / `AgentType` / `AgentTemplate` (no version/rich-content columns) — the active-version check must go through the `BotVersions` child relationship / `BotUserId`, exactly as `references/asa-routing.md` does.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Digital Worker (`1iE` AgenticCtxtDecorDefinition) — NOT live-verifiable on sdb6c
|
|
66
|
+
|
|
67
|
+
The SessionHandler domain `AgenticCtxtDecorDefinition` (Digital Worker, added v262) is gated by the org permission `orgHasOmniChannelScrt2DigitalWorkerRouting` (per `LiveAgentPresenceUtilImpl.isActiveDigitalWorker`). On sdb6c that object is **not SOQL-addressable** (`INVALID_TYPE`), which means the perm/feature isn't enabled there — so this path could not be verified against a live org.
|
|
68
|
+
|
|
69
|
+
Intended locate (unverified — validate against an org that has the perm before relying on it):
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
sf data query --target-org '{ORG_ALIAS}' \
|
|
73
|
+
--query "SELECT Id, DeveloperName, MasterLabel FROM AgenticCtxtDecorDefinition ORDER BY MasterLabel" \
|
|
74
|
+
--json > /tmp/ccr-digital-workers.json
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`Id` (`1iE`-prefixed) is `{TARGET_ID}`. FallbackQueue is **required** (server rejects null with `MissingFallbackQueueForDigitalWorkerRouting`). If the object errors with `INVALID_TYPE`, emit `{ok:false, kind:"no-eligible-target", routingType:"digital_worker", hint:"this org doesn't have Digital Worker routing enabled (AgenticCtxtDecorDefinition not available) — use a different routing type or contact your Salesforce rep to enable it"}`.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## User (`005`) — PARTIALLY verified on sdb6c
|
|
82
|
+
|
|
83
|
+
Direct-to-user routing points SessionHandler at a `User` with FallbackQueue **null**. `validateSessionHandler` additionally requires the user to have a RoutingConfiguration (else `NoRoutingConfigDefined`) — but this is **not** a direct field on `User` (`User.RoutingConfigurationId` does not exist). The linkage runs through Omni-Channel presence configuration: `PresenceUserConfig` (the config, which references a routing/priority setup) joined to users via `PresenceUserConfigUser`.
|
|
84
|
+
|
|
85
|
+
Locate eligible users (those assigned to a presence config, which carries the routing configuration):
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# users assigned to an Omni-Channel presence config
|
|
89
|
+
sf data query --target-org '{ORG_ALIAS}' \
|
|
90
|
+
--query "SELECT UserId, User.Name, PresenceUserConfigId FROM PresenceUserConfigUser WHERE User.IsActive = true ORDER BY User.Name" \
|
|
91
|
+
--json > /tmp/ccr-users.json
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`UserId` (`005`-prefixed) is `{TARGET_ID}`; FallbackQueue stays null. Present, let the user pick, then Stage 5 PATCH (`SessionHandlerId={TARGET_ID}` only).
|
|
95
|
+
|
|
96
|
+
If 0 rows: `{ok:false, kind:"no-eligible-target", routingType:"user", hint:"no users are assigned to an Omni-Channel presence configuration with routing — set one up in Setup → Omni-Channel → Presence Configurations, then re-run this skill"}`.
|
|
97
|
+
|
|
98
|
+
**Verified 2026-08-12 (sdb6c):** the *persisted-state* rule is confirmed — Enhanced channel `Facebook_US_104218168883106` (`0MjSG0000000C7d0AE`) carries `SessionHandlerId=005SG00000051bNYAQ` with `FallbackQueueId=null`, so User-as-SessionHandler with a null FallbackQueue is a valid live configuration. The *locate query* (`PresenceUserConfigUser`) and the RoutingConfiguration precondition were not exercised end-to-end via a fresh PATCH; treat the enumeration query as best-effort and confirm the picked user actually has routing before relying on activation.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Worked examples: `service-de-channel-routing-configure`
|
|
2
|
+
|
|
3
|
+
Reference runs:
|
|
4
|
+
|
|
5
|
+
- Queue path: reuse an existing queue (fast path) and create a new queue via the Metadata API (slow path). Both validated against test1.
|
|
6
|
+
- Flow path: attach an active Omni-Channel RoutingFlow with a fallback queue. Validated live against sdb6c 2026-08-12.
|
|
7
|
+
- ASA path: pick an existing live ASA with a fallback queue. Enumeration/selection validated against sdb14-test; the ASA `Type/AgentType` filter and routable-vs-not-live split re-verified live on sdb6c 2026-08-12.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Worked example: reuse an existing Queue on test1
|
|
12
|
+
|
|
13
|
+
Verified by inspection on `messagingsdb6ccom.test1.my.pc-rnd.salesforce.com`, 2026-04-30. Input:
|
|
14
|
+
|
|
15
|
+
- `{CHANNEL_ID}` = `0MjSG000000Fc1l0AC` (the WhatsApp channel)
|
|
16
|
+
|
|
17
|
+
**Stage 1** read shows `SessionHandlerId = 00GSG0000000LSf2AM`, so this channel would short-circuit to the no-op path and report:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{"ok": true, "noop": true, "sessionHandlerId": "00GSG0000000LSf2AM", "queueName": "Messaging Queue", "message": "Routing already configured"}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
If the channel were freshly inserted with `SessionHandlerId = null`, the skill would:
|
|
24
|
+
- Stage 3: list existing queues (`Messaging Queue`, `MyQueue`, ...)
|
|
25
|
+
- User picks `Messaging Queue` → `{QUEUE_ID} = 00GSG0000000LSf2AM`
|
|
26
|
+
- Stage 5: PATCH
|
|
27
|
+
- Stage 6: verify
|
|
28
|
+
- Stage 7: report `Success — Routing configured — channel 0MjSG000000Fc1l0AC now routes to Queue 'Messaging Queue' (reused existing queue).`
|
|
29
|
+
|
|
30
|
+
## Worked example: create a new Queue
|
|
31
|
+
|
|
32
|
+
Input:
|
|
33
|
+
- `{CHANNEL_ID}` = `0MjSG000000NewChannel`
|
|
34
|
+
- User chooses "create new" with `Label="WhatsApp Demo Queue"`, `DevName="WhatsApp_Demo_Queue"`, `RoutingModel=MostAvailable`, `AddSelf=Y`
|
|
35
|
+
|
|
36
|
+
**Stages 1–3**: channel has null routing, user picks "create new".
|
|
37
|
+
|
|
38
|
+
**Stage 4**: skill writes to `/tmp/ccr-metadata-<ts>/`:
|
|
39
|
+
- `force-app/main/default/queues/WhatsApp_Demo_Queue.queue-meta.xml`
|
|
40
|
+
- `force-app/main/default/queueRoutingConfigs/WhatsApp_Demo_Queue_Routing.queueRoutingConfig-meta.xml`
|
|
41
|
+
- `sfdx-project.json`
|
|
42
|
+
|
|
43
|
+
`sf project deploy start` succeeds. Re-query returns `{Id: '00GSG00000NewQueue01'}`.
|
|
44
|
+
|
|
45
|
+
GroupMember insert adds the current user to the queue.
|
|
46
|
+
|
|
47
|
+
**Stage 5**: PATCH `MessagingChannel.SessionHandlerId = 00GSG00000NewQueue01`.
|
|
48
|
+
|
|
49
|
+
**Stage 6**: verify.
|
|
50
|
+
|
|
51
|
+
**Stage 7**: `Success — Routing configured — channel 0MjSG000000NewChannel now routes to Queue 'WhatsApp Demo Queue'.`
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Worked example: attach an Omni-Channel Flow (verified live on sdb6c)
|
|
56
|
+
|
|
57
|
+
Verified live on `messaging_sdb6c` 2026-08-12. Input:
|
|
58
|
+
|
|
59
|
+
- `{CHANNEL_ID}` = `0MjSG0000004rIf0AI` (Enhanced channel `Customer_Support`, `SessionHandlerId = null`)
|
|
60
|
+
|
|
61
|
+
**Stage 1**: read shows `SessionHandlerId = null, FallbackQueueId = null`. Continue.
|
|
62
|
+
|
|
63
|
+
**Stage 2**: `PlatformType = Enhanced` confirmed. User picks `2) flow`.
|
|
64
|
+
|
|
65
|
+
**Locate (references/target-locate.md)** — active, org-local RoutingFlows:
|
|
66
|
+
|
|
67
|
+
```soql
|
|
68
|
+
SELECT DurableId, Label, ApiName, NamespacePrefix, IsActive, ActiveVersionId
|
|
69
|
+
FROM FlowDefinitionView
|
|
70
|
+
WHERE ProcessType = 'RoutingFlow' AND IsActive = true AND NamespacePrefix = null
|
|
71
|
+
ORDER BY Label
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Returns org-local flows whose `DurableId` is the `300` FlowDefinition Id (e.g. `DirectToAgentFlow` → `300SG0000002gw1YAA`). User picks it → `{TARGET_ID} = 300SG0000002gw1YAA`.
|
|
75
|
+
|
|
76
|
+
**Resolve FallbackQueue** (required for Flow): eligible-queue query returns `Messaging_Queue` (`00GSG0000000LSf2AM`). User picks it → `{FALLBACK_QUEUE_ID} = 00GSG0000000LSf2AM`.
|
|
77
|
+
|
|
78
|
+
**Stage 5**: single PATCH writing both fields:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
$ sf data update record --sobject MessagingChannel --record-id 0MjSG0000004rIf0AI \
|
|
82
|
+
--values 'SessionHandlerId=300SG0000002gw1YAA FallbackQueueId=00GSG0000000LSf2AM'
|
|
83
|
+
# → success
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
(A PATCH that sets the Flow SessionHandler but leaves FallbackQueue null is rejected server-side: *"A Fallback Queue must be specified when selecting a Flow routing method."* — observed live.)
|
|
87
|
+
|
|
88
|
+
**Stage 6**: re-read returns `SessionHandlerId = 300SG0000002gw1YAA, FallbackQueueId = 00GSG0000000LSf2AM`. Verified.
|
|
89
|
+
|
|
90
|
+
**Stage 7**:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{"ok": true, "routingType": "flow", "sessionHandlerId": "300SG0000002gw1YAA",
|
|
94
|
+
"fallbackQueueId": "00GSG0000000LSf2AM", "flowName": "DirectToAgentFlow",
|
|
95
|
+
"flowDeveloperName": "DirectToAgentFlow", "created": false}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
User-facing: `Success — Routing configured — channel 0MjSG0000004rIf0AI now routes to Omni-Flow 'DirectToAgentFlow' (300SG0000002gw1YAA), fallback Queue 00GSG0000000LSf2AM.`
|
|
99
|
+
|
|
100
|
+
*(The test channel was restored to `SessionHandlerId=null, FallbackQueueId=null` afterward.)*
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Worked example: pick an existing live ASA on sdb14-test
|
|
105
|
+
|
|
106
|
+
Verified on `sdb14com-a8.test2.my.pc-rnd.salesforce.com` (`sdb14-test`), 2026-05-12. The fast path: an Agentforce-licensed org has ASAs already authored and we just need to attach one. Input:
|
|
107
|
+
|
|
108
|
+
- `{CHANNEL_ID}` = `0MjRZ00000004210AA` (a freshly-inserted WhatsApp channel)
|
|
109
|
+
|
|
110
|
+
**Stage 1**: channel has `SessionHandlerId = null, FallbackQueueId = null`. Continue.
|
|
111
|
+
|
|
112
|
+
**Stage 2**: user picks `2) asa`.
|
|
113
|
+
|
|
114
|
+
**Stage 3-ASA.0** precondition check:
|
|
115
|
+
```bash
|
|
116
|
+
$ sf sobject describe --target-org sdb14-test --sobject BotDefinition 2>&1 | grep -q "does not exist" && echo MISSING || echo PRESENT
|
|
117
|
+
PRESENT
|
|
118
|
+
```
|
|
119
|
+
Continue.
|
|
120
|
+
|
|
121
|
+
**Stage 3-ASA.1** enumerate active ASAs (one query, child-relationship form works on this org):
|
|
122
|
+
|
|
123
|
+
```soql
|
|
124
|
+
SELECT Id, DeveloperName, MasterLabel, BotUserId,
|
|
125
|
+
(SELECT Id, Status FROM BotVersions WHERE Status='Active' LIMIT 1)
|
|
126
|
+
FROM BotDefinition
|
|
127
|
+
WHERE Type='ExternalCopilot' AND AgentType='EinsteinServiceAgent'
|
|
128
|
+
ORDER BY MasterLabel
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Returns 25 rows. After post-processing (filter rows where `BotUserId != null` AND `BotVersions[0].Status == 'Active'`), 13 are routable.
|
|
132
|
+
|
|
133
|
+
**Stage 3-ASA.2** prompt:
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
Existing Agentforce Service Agents on sdb14-test:
|
|
137
|
+
|
|
138
|
+
1) Agentforce Service Agent KAFile (Agentforce_Service_Agent_KAFile) — 0XxRZ0000002ZWL0A2 [live]
|
|
139
|
+
2) Agentforce Service Agent Test (Agentforce_Service_Agent_Test) — 0XxRZ0000002kJh0AI [live]
|
|
140
|
+
3) BYO Service Agent (BYO_Service_Agent) — 0XxRZ0000002lAv0AI [live]
|
|
141
|
+
4) MON ASA Apex (MON_ASA_Apex) — 0XxRZ0000003APR0A2 [live]
|
|
142
|
+
...
|
|
143
|
+
|
|
144
|
+
Pick [1-13]: 4
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Records: `{ASA_ID} = 0XxRZ0000003APR0A2`, `{ASA_LABEL} = "MON ASA Apex"`, `{ASA_DEV_NAME} = "MON_ASA_Apex"`, `{BOT_USER_ID} = 005RZ000001wJ3JYAU`, `{BOT_VERSION_ID} = 0X9RZ0000002b8L0AQ`.
|
|
148
|
+
|
|
149
|
+
**Stage 3-ASA.3** resolve FallbackQueue (required for ASA): eligible-queue query returns a MessagingSession queue; user picks it → `{FALLBACK_QUEUE_ID} = 00GRZ0000000abc0AA`.
|
|
150
|
+
|
|
151
|
+
**Stage 5**: single PATCH writing both fields — `sf data update record --sobject MessagingChannel --record-id 0MjRZ00000004210AA --values 'SessionHandlerId=0XxRZ0000003APR0A2 FallbackQueueId=00GRZ0000000abc0AA'` succeeds. (Omitting the FallbackQueue would be rejected with `MissingFallbackQueueForAsaRouting`.)
|
|
152
|
+
|
|
153
|
+
**Stage 6**: re-read returns `SessionHandlerId = 0XxRZ0000003APR0A2, FallbackQueueId = 00GRZ0000000abc0AA`. Verified.
|
|
154
|
+
|
|
155
|
+
**Stage 7**:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"ok": true,
|
|
160
|
+
"routingType": "asa",
|
|
161
|
+
"sessionHandlerId": "0XxRZ0000003APR0A2",
|
|
162
|
+
"fallbackQueueId": "00GRZ0000000abc0AA",
|
|
163
|
+
"asaName": "MON ASA Apex",
|
|
164
|
+
"asaDeveloperName": "MON_ASA_Apex",
|
|
165
|
+
"botUserId": "005RZ000001wJ3JYAU",
|
|
166
|
+
"botVersionId": "0X9RZ0000002b8L0AQ",
|
|
167
|
+
"created": false
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
User-facing: `Success — Routing configured — channel 0MjRZ00000004210AA now routes to Agentforce Service Agent 'MON ASA Apex' (0XxRZ0000003APR0A2), fallback Queue 00GRZ0000000abc0AA. Bot user: 005RZ000001wJ3JYAU. Active version: 0X9RZ0000002b8L0AQ.`
|
|
172
|
+
|
|
173
|
+
Total elapsed: ~3s (SOQL + PATCH, no external callouts needed).
|
|
174
|
+
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: service-de-headless-channel-configure
|
|
3
|
+
description: "Top-level orchestrator: given a messaging channel type and its type-specific inputs, produces an activated Enhanced `MessagingChannel` in the target Salesforce org — without the Meta/LINE/Apple setup popups. Prompts for `{MESSAGE_TYPE}` if not supplied, then sequences insert → route → consent → activate via the type-agnostic dispatcher (`service-de-channel-create`) plus the shared routing/consent/activation leaves. Resumes from partial state on re-run. Use this skill when the user wants to set up an Enhanced messaging channel (WhatsApp, Facebook, LINE, Apple, or SMS/Text) end-to-end from the command line, bypassing the in-org setup popups."
|
|
4
|
+
metadata:
|
|
5
|
+
version: "1.0"
|
|
6
|
+
minApiVersion: "67.0"
|
|
7
|
+
domains: ["Service"]
|
|
8
|
+
cliTools:
|
|
9
|
+
- tool: ["sf"]
|
|
10
|
+
semver: ">=2.0.0"
|
|
11
|
+
relatedSkills:
|
|
12
|
+
- "service-de-channel-activate"
|
|
13
|
+
- "service-de-channel-consent-configure"
|
|
14
|
+
- "service-de-channel-create"
|
|
15
|
+
- "service-de-channel-routing-configure"
|
|
16
|
+
- "service-de-waba-integrate"
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Headless Channel Setup (type-agnostic)
|
|
20
|
+
|
|
21
|
+
## What this skill does
|
|
22
|
+
|
|
23
|
+
Takes a channel type (`WhatsApp` | `Line` | `AppleBusinessChat` | `Facebook` | `Text`) plus its type-specific inputs and drives it to an activated `MessagingChannel`. It first gates on the Enhanced Messaging Terms and Conditions, then runs four steps:
|
|
24
|
+
|
|
25
|
+
0. **Accept Terms and Conditions** — renders the Enhanced Messaging disclaimer and requires the user to certify they have authority to bind their org, mirroring the in-org "Add a Channel" wizard. Blocking — a decline ends the run before any org work. *(Stage 0.5, in this skill)*
|
|
26
|
+
1. **Insert the channel** — invokes `service-de-channel-create`, which handles the per-type third-party prereq internally (e.g. WhatsApp's `service-de-waba-integrate` runs inside `service-de-channel-create`). *(skill: `service-de-channel-create`)*
|
|
27
|
+
2. **Configure routing** — sets `SessionHandlerId` to an Omni-Channel Queue (pick existing or create new). Message-type-agnostic. *(skill: `service-de-channel-routing-configure`)*
|
|
28
|
+
3. **Configure consent** — ensures a valid `ConsentType` + matching `MsgChannelLanguageKeyword` record. The Connect insert auto-seeds a default `ConsentType=ImplicitOptIn` + opt-out keyword, so on a fresh channel this step is frequently a **no-op** — or an *upgrade* if the caller wants ExplicitOptIn/DoubleOptIn. Activation's readiness check requires both routing AND consent, so this runs before activation. *(skill: `service-de-channel-consent-configure`)*
|
|
29
|
+
4. **Activate** — PATCHes `MessagingChannelUsage.DeploymentStatus` to `Provisioning` via REST; the server-side save-hook drives the full observer chain synchronously and returns 204 once the MCU reaches `Active` and `MessagingChannel.IsActive=true`. Message-type-agnostic. *(skill: `service-de-channel-activate`)*
|
|
30
|
+
|
|
31
|
+
**Resume-by-default.** Each step is idempotent — if you re-run after a failure, the orchestrator detects existing state and skips steps that already succeeded.
|
|
32
|
+
|
|
33
|
+
**Prompt mid-flow.** If `{MESSAGE_TYPE}` isn't in the initial request, the orchestrator asks upfront. Routing choices (pick queue / create new) are prompted when step 2 runs, not upfront — keeps leaf skills self-contained.
|
|
34
|
+
|
|
35
|
+
## Reference File Index
|
|
36
|
+
|
|
37
|
+
| Reference file | Load when |
|
|
38
|
+
| --- | --- |
|
|
39
|
+
| `references/inputs.md` | You need the full input field list — MESSAGE_TYPE/ORG_ALIAS plus per-type fields for WhatsApp, LINE, AppleBusinessChat, Facebook, Text (SMS). |
|
|
40
|
+
| `references/terms-and-conditions.md` | Rendering the Stage 0.5 disclaimer and certification prompt — verbatim text and per-type label/third-party mappings. |
|
|
41
|
+
| `references/output-envelopes.md` | Wiring error handling or parsing the canonical success/failure/terms-declined JSON envelope shapes. |
|
|
42
|
+
| `references/partial-success.md` | The orchestrator fails mid-way and you need to render the partial-success/resume report. |
|
|
43
|
+
| `references/gotchas.md` | Debugging unexpected behavior — duplicate-key errors, resume/idempotency questions, preflight SOQL shape, unattended/CI usage. |
|
|
44
|
+
| `references/worked-examples.md` | You need a reference trace (fresh WhatsApp run, resume after failure, Apple dispatch, unsupported-type rejection) for exact envelope shapes. |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Critical execution rule
|
|
49
|
+
|
|
50
|
+
**This orchestrator MUST run all stages (0-5) in a SINGLE response without stopping between stages.**
|
|
51
|
+
|
|
52
|
+
When you invoke a leaf skill (service-de-channel-create, service-de-channel-routing-configure, service-de-channel-consent-configure, service-de-channel-activate) and it returns via function_results:
|
|
53
|
+
|
|
54
|
+
- **DO:** Immediately parse the function_results return value and continue to the next stage
|
|
55
|
+
- **DO:** Run Stage 0.5 → Stage 1 → Stage 2 → Stage 3 → Stage 3.5 → Stage 4 → Stage 5 consecutively in ONE response
|
|
56
|
+
- **DO NOT:** Stop and report back to the user between stages
|
|
57
|
+
- **DO NOT:** Wait for user confirmation between stages
|
|
58
|
+
- **DO NOT:** Treat each stage as a separate turn in the conversation
|
|
59
|
+
|
|
60
|
+
**Why this matters:** The user invoked THIS orchestrator skill to get an end-to-end activated channel. They did NOT invoke the individual leaf skills. Your job is to run the entire pipeline autonomously and report the final result. Stopping mid-flow breaks the orchestrator pattern and forces the user to manually resume each stage.
|
|
61
|
+
|
|
62
|
+
**Exception:** Only stop mid-flow if a leaf skill returns `ok: false` with a terminal error (not a recoverable prompt), or if the user declines the Stage 0.5 Terms and Conditions gate (emit `terms-not-accepted` and halt). Then report the failure immediately with context about which stage failed and what state was reached.
|
|
63
|
+
|
|
64
|
+
**Stage 0.5 is a required blocking prompt.** The Terms and Conditions gate is the one prompt that must be answered affirmatively before any org work. It is not optional and must not be auto-accepted. A `no`/decline ends the run per the exception above; a `yes` continues to Stage 1 in the same response.
|
|
65
|
+
|
|
66
|
+
**Leaf skill prompts:** Some leaf skills (like `service-de-waba-integrate` or `service-de-channel-routing-configure`) may prompt the user for input mid-execution. That's fine — answer those prompts as they come up, but then CONTINUE to the next stage immediately after the prompt is answered. Don't stop just because a prompt was involved.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## When NOT to use this skill
|
|
71
|
+
|
|
72
|
+
- **You only want one step.** Invoke the leaf skill directly (`service-de-channel-create`, `service-de-channel-routing-configure`, `service-de-channel-activate`). This orchestrator is for the full automated path from nothing → activated channel.
|
|
73
|
+
- **You want to run stages independently in separate conversation turns.** This orchestrator runs all stages consecutively in one response. If you need manual control between stages, invoke the leaf skills individually.
|
|
74
|
+
- **You want a message type outside `WhatsApp` / `Line` / `AppleBusinessChat` / `Facebook` / `Text`.** The dispatcher will return `unsupported-type`. WeChat / MsCopilot / Alexa would need their own leaves + a dispatcher update.
|
|
75
|
+
- **The prereq hasn't been met (WABA not shared, LINE channel not created, Apple account not registered, SMS number not provisioned).** The per-type insert skill's Stage 2-equivalent surfaces this clearly and returns; no orchestration fixes it. (For SMS/Text the number-provisioning prereq isn't checked at insert — an unprovisioned number surfaces later as an activation-time `provisioning-error`.)
|
|
76
|
+
|
|
77
|
+
## Inputs (from user)
|
|
78
|
+
|
|
79
|
+
`{MESSAGE_TYPE}` (prompted if omitted) and `{ORG_ALIAS}` (optional), plus type-specific fields for WhatsApp, LINE, AppleBusinessChat, Facebook, and Text (SMS) forwarded to the dispatcher. **Load `references/inputs.md` and follow it** for the full field list and the omitted-type prompt text.
|
|
80
|
+
|
|
81
|
+
## Output (to user)
|
|
82
|
+
|
|
83
|
+
Three top-level outcomes: success, step-annotated failure, and terms-declined. **Load `references/output-envelopes.md` and follow it** for the exact JSON shapes.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Stage 0: Resolve `{MESSAGE_TYPE}` and type-specific key
|
|
88
|
+
|
|
89
|
+
If `{MESSAGE_TYPE}` is omitted, prompt the user (see "Inputs" above). Refuse to proceed without one — there's no sensible default.
|
|
90
|
+
|
|
91
|
+
Once known, determine the **preflight key** — the field we'll filter the `MessagingChannel` SOQL on to detect existing state. It's always `MessagingPlatformKey`, but what that value *is* varies by type:
|
|
92
|
+
|
|
93
|
+
| `{MESSAGE_TYPE}` | Preflight key value `{PLATFORM_KEY}` | Notes |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| `WhatsApp` | `{PHONE_NUMBER_ID}` | Required upfront |
|
|
96
|
+
| `Line` | `{LINE_CHANNEL_ID}` | Required upfront |
|
|
97
|
+
| `AppleBusinessChat` | `{APPLE_BC_ID}` | Required upfront |
|
|
98
|
+
| `Facebook` | `{PAGE_ID}` | Optional - OAuth → fetch pages → prompt if not provided |
|
|
99
|
+
| `Text` | `{SMS_NUMBER}` | Required upfront (the phone number / short code itself) |
|
|
100
|
+
|
|
101
|
+
**Facebook is unique:** If `{PAGE_ID}` is not provided, the orchestrator cannot run its own Stage 1 preflight. Instead, skip Stage 1 and let `service-de-channel-create` handle the full OAuth → page selection → preflight → creation flow. The insertion skill has its own Stage 1 preflight that runs after page selection.
|
|
102
|
+
|
|
103
|
+
For non-Facebook types, validate that the caller provided the required type-specific inputs for `{MESSAGE_TYPE}` (see Inputs above). If missing, prompt or halt — don't call the dispatcher, it will re-validate and return `missing-input`, wasting a round trip.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Stage 0.5: Enhanced Messaging Terms and Conditions (blocking gate)
|
|
108
|
+
|
|
109
|
+
**Run this before any org query or channel work.** The in-org "Add a Channel" wizard requires the admin to accept the Enhanced Messaging Terms and Conditions before it will let them proceed to channel setup. The headless flow must enforce the same gate — do not skip it, do not accept on the user's behalf. This runs once per orchestrator invocation, after `{MESSAGE_TYPE}` is known (the disclaimer names the channel) and before Stage 1.
|
|
110
|
+
|
|
111
|
+
**Render the disclaimer and certification prompt from `references/terms-and-conditions.md` (verbatim, substituting the channel label) — load it and follow it for the exact wording and per-type label/third-party mappings.**
|
|
112
|
+
|
|
113
|
+
**Gate behavior:**
|
|
114
|
+
|
|
115
|
+
- If the user answers **yes** (affirmative acceptance), record `{TC_ACCEPTED} = true` and continue to Stage 1.
|
|
116
|
+
- If the user answers **no**, declines, or does not affirmatively accept, **halt immediately** — do not run Stage 1 or any subsequent stage. Emit:
|
|
117
|
+
```json
|
|
118
|
+
{"ok": false, "kind": "terms-not-accepted",
|
|
119
|
+
"hint": "user did not accept the Enhanced Messaging Terms and Conditions — channel setup cannot proceed. Re-run when ready to accept."}
|
|
120
|
+
```
|
|
121
|
+
- Acceptance is required on **every** orchestrator invocation, including resume runs. It is a per-session gate, not persisted — we don't have a place to durably record it, and the cost of re-confirming is one prompt.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Stage 1: Pre-flight state detection (resume support)
|
|
126
|
+
|
|
127
|
+
**Skip this stage entirely if `MESSAGE_TYPE=Facebook` and `{PAGE_ID}` was not provided.** The Facebook insertion skill needs to run OAuth first before we know which PAGE_ID to check for. Let the insertion skill handle its own preflight in Stage 1 after page selection.
|
|
128
|
+
|
|
129
|
+
For all other cases, query the org to see how far a prior run got. This enables skip-ahead on resume. **Two queries, not a subquery** — the `(SELECT ... FROM MessagingChannelUsages)` subquery fails on some orgs where the child relationship is unnameable. Use FK-keyed second query instead (see gotcha #9).
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
sf data query --target-org '{ORG_ALIAS}' \
|
|
133
|
+
--query "SELECT Id, DeveloperName, MessageType, IsActive, SessionHandlerId, FallbackQueueId FROM MessagingChannel WHERE MessagingPlatformKey = '{PLATFORM_KEY}' AND MessageType = '{MESSAGE_TYPE}'" \
|
|
134
|
+
--json > /tmp/hcs-preflight.json
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
If the channel query returns a row, fire a second query to resolve its MCU:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
sf data query --target-org '{ORG_ALIAS}' \
|
|
141
|
+
--query "SELECT Id, DeploymentStatus FROM MessagingChannelUsage WHERE MessagingChannelId = '{CHANNEL_ID}'" \
|
|
142
|
+
--json > /tmp/hcs-preflight-mcu.json
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Parse the combined result to figure out `{CURRENT_STATE}`:
|
|
146
|
+
|
|
147
|
+
| Preflight result | `CURRENT_STATE` | First step to run |
|
|
148
|
+
| --- | --- | --- |
|
|
149
|
+
| No records | `fresh` | Step 1 (insert) |
|
|
150
|
+
| Record exists, `IsActive=false`, `SessionHandlerId=null` and `FallbackQueueId=null` | `inserted-no-routing` | Step 2 (configure routing) |
|
|
151
|
+
| Record exists, `IsActive=false`, routing set | `routed-not-active` | Step 3 (configure consent), then Step 4 (activate) |
|
|
152
|
+
| Record exists, `IsActive=true` | `already-active` | Emit no-op success envelope; return. |
|
|
153
|
+
|
|
154
|
+
Record the existing `{CHANNEL_ID}` and `{MCU_ID}` if present — downstream steps need them.
|
|
155
|
+
|
|
156
|
+
Initialize `{STEPS_RUN} = []`, `{STEPS_SKIPPED} = []`, `{T0} = Date.now()`.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Stage 2: Insert the channel (step 1 of 4)
|
|
161
|
+
|
|
162
|
+
Skip this stage if `CURRENT_STATE` ∈ `{inserted-no-routing, routed-not-active, already-active}` — the channel already exists. Append `"insert"` to `STEPS_SKIPPED` in that case.
|
|
163
|
+
|
|
164
|
+
Otherwise invoke `service-de-channel-create` with:
|
|
165
|
+
|
|
166
|
+
- `{MESSAGE_TYPE}` = (from Stage 0)
|
|
167
|
+
- All type-specific inputs (forwarded verbatim — dispatcher routes to the right leaf)
|
|
168
|
+
- `{ORG_ALIAS}`
|
|
169
|
+
|
|
170
|
+
The insertion skill handles per-type prereqs internally (e.g., for WhatsApp, `service-de-channel-create` invokes `service-de-waba-integrate` as its Stage 2). This orchestrator doesn't need to know about WABA linking, LINE token verification, or Apple registration — `service-de-channel-create` owns the prereq semantics for whichever type it's running.
|
|
171
|
+
|
|
172
|
+
Handle the envelope:
|
|
173
|
+
|
|
174
|
+
| Leaf envelope | Orchestrator action |
|
|
175
|
+
| --- | --- |
|
|
176
|
+
| `{ok: true, channelId, mcuId, ...}` | Record `{CHANNEL_ID}` and `{MCU_ID}`. Append `"insert"` to `STEPS_RUN`. Continue. |
|
|
177
|
+
| `{ok: false, kind: "partnership-blocked" \| "user-declined" \| "apple-registration-pending" \| "line-prereq-missing"}` | These come from the per-type prereq stage. Pass through as `failedStep: "insert"`, `failedStepIndex: 1`. Return. |
|
|
178
|
+
| `{ok: false, kind: "missing-input" \| "unsupported-type"}` | Should have been caught in Stage 0 — emit failure with `failedStep: "insert"` and a note that the caller's inputs were incomplete. |
|
|
179
|
+
| `{ok: false, kind: <anything else>}` | Emit failure envelope with `failedStep: "insert"`, `failedStepIndex: 1`. Return. |
|
|
180
|
+
|
|
181
|
+
At this point we have `{CHANNEL_ID}` and `{MCU_ID}` regardless of whether step 1 ran or was skipped.
|
|
182
|
+
|
|
183
|
+
**→ Continue immediately to Stage 3 in this same response. DO NOT STOP.**
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## Stage 3: Configure routing (step 2 of 4)
|
|
188
|
+
|
|
189
|
+
Skip this stage if `CURRENT_STATE === "routed-not-active"` — routing is already set. Append `"route"` to `STEPS_SKIPPED`.
|
|
190
|
+
|
|
191
|
+
Otherwise invoke `service-de-channel-routing-configure`:
|
|
192
|
+
|
|
193
|
+
- `{CHANNEL_ID}` = recorded above
|
|
194
|
+
- `{ORG_ALIAS}`
|
|
195
|
+
|
|
196
|
+
This is the step that **prompts the user** for queue choice (pick existing / create new / escape hatch). Don't try to pre-empt the prompts — forward the user's answers as-is.
|
|
197
|
+
|
|
198
|
+
Handle the envelope:
|
|
199
|
+
|
|
200
|
+
| Leaf envelope | Orchestrator action |
|
|
201
|
+
| --- | --- |
|
|
202
|
+
| `{ok: true, sessionHandlerId, queueName, ...}` (including `noop: true`) | Record `{SESSION_HANDLER_ID}` and `{QUEUE_NAME}`. Append `"route"` to `STEPS_RUN`. Continue. |
|
|
203
|
+
| `{ok: false, kind: "unsupported-routing-type", ...}` | User chose flow/user/asa/aea. Emit partial-success with `failedStep: "route"` and a resume hint pointing at the UI. Return. |
|
|
204
|
+
| `{ok: false, kind: "metadata-deploy-failed" \| "patch-failed" \| "verify-failed"}` | Emit failure envelope with `failedStep: "route"`. Return. |
|
|
205
|
+
|
|
206
|
+
**→ Continue immediately to Stage 3.5 in this same response. DO NOT STOP.**
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Stage 3.5: Configure consent (before activation)
|
|
211
|
+
|
|
212
|
+
Activation's readiness check requires **consent AND routing** — a fully-routed channel still fails to activate if consent isn't configured. Invoke `service-de-channel-consent-configure`:
|
|
213
|
+
|
|
214
|
+
- `{CHANNEL_ID}` = recorded above
|
|
215
|
+
- `{CONSENT_TYPE}`, `{LANGUAGE}`, and the keyword/prompt values — forward whatever the user supplied; omit what they didn't
|
|
216
|
+
- `{ORG_ALIAS}`
|
|
217
|
+
|
|
218
|
+
This stage **ensures consent is activation-ready** — it doesn't always write. The Connect insert **auto-seeds** `ConsentType=ImplicitOptIn` plus a default opt-out `MsgChannelLanguageKeyword`, which already satisfies the readiness check. So the leaf's Stage 1 will frequently find the channel *already* ready and return `noop: true` — the expected outcome on a fresh `ImplicitOptIn` channel, not a bug. It performs a **real write only** to upgrade (ExplicitOptIn/DoubleOptIn) or override the seeded keywords/prompts. When the user pre-supplied inputs asking for an upgrade, expect a write and let the leaf prompt for missing values — don't suppress those prompts.
|
|
219
|
+
|
|
220
|
+
Handle the envelope:
|
|
221
|
+
|
|
222
|
+
| Leaf envelope | Orchestrator action |
|
|
223
|
+
| --- | --- |
|
|
224
|
+
| `{ok: true, ...}` (including `noop: true`) | Append `"consent"` to `STEPS_RUN` (or `STEPS_SKIPPED` if `noop`). Continue. |
|
|
225
|
+
| `{ok: false, kind: "not-enhanced"}` | Shouldn't happen — these skills only create Enhanced channels. Emit failure with `failedStep: "consent"`. Return. |
|
|
226
|
+
| `{ok: false, kind: "missing-consent-input", hint}` | The user didn't supply a required keyword/prompt for the chosen ConsentType. Emit failure with `failedStep: "consent"` and pass through the `hint`. Return. |
|
|
227
|
+
| `{ok: false, ...}` (any other kind — `channel-patch-failed`, `keyword-record-failed`, `verify-failed`, or an unrecognized envelope) | Emit failure with `failedStep: "consent"` and pass through the leaf's `kind` and message verbatim. Return. |
|
|
228
|
+
|
|
229
|
+
**→ Continue immediately to Stage 4 in this same response. DO NOT STOP.**
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Stage 4: Activate (step 4 of 4)
|
|
234
|
+
|
|
235
|
+
Always run (unless `CURRENT_STATE === "already-active"`, in which case Stage 1 returned early).
|
|
236
|
+
|
|
237
|
+
Invoke `service-de-channel-activate`:
|
|
238
|
+
|
|
239
|
+
- `{CHANNEL_ID}` = recorded above
|
|
240
|
+
- `{ORG_ALIAS}`
|
|
241
|
+
|
|
242
|
+
No timeout knobs — activation is a single synchronous PATCH. The leaf does a defensive poll if the server ever returns mid-transition, but the expected path is one round-trip.
|
|
243
|
+
|
|
244
|
+
Handle the envelope:
|
|
245
|
+
|
|
246
|
+
| Leaf envelope | Orchestrator action |
|
|
247
|
+
| --- | --- |
|
|
248
|
+
| `{ok: true, isActive: true, ...}` (including `noop: true`) | Record results. Append `"activate"` to `STEPS_RUN`. Continue to Stage 5. |
|
|
249
|
+
| `{ok: false, kind: "no-routing"}` | Unusual (we just set it) — probably a race or permission issue. Emit failure with a hint about the permissions check. Return. |
|
|
250
|
+
| `{ok: false, kind: "no-mcu" \| "channel-missing"}` | Shouldn't happen after successful insert. Emit failure with the leaf's envelope. Return. |
|
|
251
|
+
| `{ok: false, kind: "readiness-failed", errorMessage}` | `validateChannelReadinessOnProvisioning` rejected the PATCH — missing consent (STOP/HELP keyword record). Stage 3.5 should have caught this; if it re-appears, re-run `service-de-channel-consent-configure` for the channel. Emit failure and pass through the resume hint. Return. |
|
|
252
|
+
| `{ok: false, kind: "provisioning-error", errorReason, errorDetails}` | Third-party side rejected (Meta `/register` failed, etc.). MCU is now in `Error`. Emit failure and pass through `errorReason`/`errorDetails`. Return. |
|
|
253
|
+
| `{ok: false, kind: "auth" \| "transport"}` | REST call failed at the HTTP layer (401 from `sf` auth, 5xx from the instance). Pass through. Return. |
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Stage 5: Final report
|
|
258
|
+
|
|
259
|
+
Build the success envelope:
|
|
260
|
+
|
|
261
|
+
```json
|
|
262
|
+
{
|
|
263
|
+
"ok": true,
|
|
264
|
+
"messageType": "{MESSAGE_TYPE}",
|
|
265
|
+
"channelId": "{CHANNEL_ID}",
|
|
266
|
+
"mcuId": "{MCU_ID}",
|
|
267
|
+
"channelName": "{CHANNEL_NAME or inferred}",
|
|
268
|
+
"sessionHandlerId": "{SESSION_HANDLER_ID}",
|
|
269
|
+
"queueName": "{QUEUE_NAME}",
|
|
270
|
+
"isActive": true,
|
|
271
|
+
"stepsRun": [...],
|
|
272
|
+
"stepsSkipped": [...],
|
|
273
|
+
"totalDurationMs": Date.now() - T0
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Render to the user as:
|
|
278
|
+
|
|
279
|
+
```text
|
|
280
|
+
Success — {MESSAGE_TYPE} channel '{CHANNEL_NAME}' is live on {ORG_ALIAS}.
|
|
281
|
+
Channel ID: {CHANNEL_ID}
|
|
282
|
+
Routed to: {queueName} ({SESSION_HANDLER_ID})
|
|
283
|
+
Steps: ran {STEPS_RUN.join(", ")}{, skipped " + STEPS_SKIPPED.join(", ") if any}
|
|
284
|
+
Total time: {formatted from durationMs}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
If any step was skipped due to resume, the report should make that visible.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Partial-success and resume reporting
|
|
292
|
+
|
|
293
|
+
If the orchestrator fails mid-way, the envelope always includes `stateSoFar` describing what landed. **`stateSoFar` must always carry both `stepsRun` and `stepsSkipped`** (each an array, empty if nothing landed/skipped yet) alongside the fields that landed — the partial-success renderer reads both. **When rendering a failure, load `references/partial-success.md` and follow it** — it has the exact template for showing which steps already landed and how to retry.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Worked examples
|
|
298
|
+
|
|
299
|
+
For reference traces (fresh WhatsApp run, resume after routing failure, Apple dispatch, unsupported-type rejection), see `references/worked-examples.md`.
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Gotchas
|
|
304
|
+
|
|
305
|
+
Nine known gotchas covering prereq ownership, `MessagingPlatformKey` uniqueness, resume semantics, CSOT-only support, error-classification boundaries, prompt placement, platform-key mapping, wall-clock duration, and the two-query preflight workaround. **When debugging unexpected behavior, load `references/gotchas.md` and follow it.**
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: service-de-headless-channel-configure-gotchas
|
|
3
|
+
description: "Load when debugging unexpected orchestrator behavior — duplicate-key errors, resume/idempotency questions, preflight SOQL shape, or unattended/CI usage of the headless channel setup orchestrator. Covers the nine known gotchas: prereq ownership, MessagingPlatformKey uniqueness, resume-by-reinvocation, CSOT-only support, error-classification boundaries, prompt placement, platform-key mapping, wall-clock duration, and the two-query preflight. DO NOT load during a normal end-to-end run with no errors."
|
|
4
|
+
metadata:
|
|
5
|
+
version: "1.0"
|
|
6
|
+
related-skills: service-de-headless-channel-configure
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Gotchas
|
|
10
|
+
|
|
11
|
+
1. **Type-specific prereqs are owned by the insertion skill, not this orchestrator.** For WhatsApp, `service-de-channel-create` handles the WABA-linking prompt internally. For Line/Apple, `service-de-channel-create` is likewise responsible for its own credential-collection prereq, per the `MESSAGE_TYPE` it's given. This orchestrator stays type-agnostic — it doesn't know (or want to know) what a WABA is.
|
|
12
|
+
|
|
13
|
+
2. **Idempotency relies on `(MessagingPlatformKey, MessageType)` uniqueness.** The preflight query keys off the pair. If there are stale/deleted channels with the same key, SF should prevent duplicates on insert (DB uniqueness constraint on `(MessagePlatform, MessageType, MessagingPlatformKey)` for active rows). If insert fails with `DUPLICATE_VALUE` but preflight found no record, the backing MCU index is inconsistent — escalate to user.
|
|
14
|
+
|
|
15
|
+
3. **Resume is opt-in-by-reinvocation, not background.** The orchestrator doesn't store state files — it re-queries on each run. Keeps it simple.
|
|
16
|
+
|
|
17
|
+
4. **Step ordering assumes CSOT channels (Enhanced).** Legacy pre-CSOT channels used different activation paths (`activateWhatsAppNumber`, etc.). Not supported here.
|
|
18
|
+
|
|
19
|
+
5. **Don't catch transport/internal errors at this layer.** The leaf skills handle that — by the time a failure reaches this orchestrator, it's already classified into `ok:false, kind:"..."`. Just annotate which step failed.
|
|
20
|
+
|
|
21
|
+
6. **The orchestrator's prompts are limited to Stage 0 (type if omitted) and Stage 3 (routing choices).** Stages 2 and 4 are non-interactive. For fully-unattended mode (CI, cron), you need `{MESSAGE_TYPE}` supplied, and either (a) use an already-configured queue so Stage 3 no-ops, or (b) add a `--queue-id` override. Not built yet.
|
|
22
|
+
|
|
23
|
+
7. **Channel-agnostic preflight keys off `{PLATFORM_KEY}`, not the type-specific id name.** The SOQL filter is always `MessagingPlatformKey = '{PLATFORM_KEY}'`. Map the per-type input to `{PLATFORM_KEY}` once at Stage 0 rather than branching the SOQL — keeps Stage 1 one query, not three.
|
|
24
|
+
|
|
25
|
+
8. **Total duration is wall-clock, not sum-of-steps.** If the user pauses mid-prompt in Stage 0 or Stage 3, `totalDurationMs` includes think time. For perf analysis, care about the per-leaf `durationMs` values.
|
|
26
|
+
|
|
27
|
+
9. **Preflight uses two queries, not a subquery.** The `MessagingChannel` → `MessagingChannelUsage` child relationship is `MessagingChannelUsages` on some orgs (`test1`) but unnameable on others (`wadtesting` has `relationshipName: None` in `sf sobject describe`). Subqueries fail with `INVALID_TYPE` on the latter. FK-keyed second query (`MessagingChannelUsage WHERE MessagingChannelId = '{CHANNEL_ID}'`) works everywhere. Cost is one extra SOQL per preflight — negligible.
|