@salesforce/afv-skills 1.14.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (365) hide show
  1. package/package.json +1 -1
  2. package/skills/activating-datacloud/SKILL.md +0 -1
  3. package/skills/analyzing-omnistudio-dependencies/SKILL.md +0 -1
  4. package/skills/applying-slds/SKILL.md +322 -0
  5. package/skills/applying-slds/checklists.md +83 -0
  6. package/skills/applying-slds/examples.md +283 -0
  7. package/skills/applying-slds/guidance/README.md +83 -0
  8. package/skills/applying-slds/guidance/blueprints-index.md +213 -0
  9. package/skills/applying-slds/guidance/icons-guidance.md +186 -0
  10. package/skills/applying-slds/guidance/overviews/borders.md +236 -0
  11. package/skills/applying-slds/guidance/overviews/color.md +266 -0
  12. package/skills/applying-slds/guidance/overviews/display-density.md +366 -0
  13. package/skills/applying-slds/guidance/overviews/icons.md +240 -0
  14. package/skills/applying-slds/guidance/overviews/illustrations.md +235 -0
  15. package/skills/applying-slds/guidance/overviews/shadows.md +176 -0
  16. package/skills/applying-slds/guidance/overviews/spacing.md +216 -0
  17. package/skills/applying-slds/guidance/overviews/typography.md +323 -0
  18. package/skills/applying-slds/guidance/overviews/utilities.md +542 -0
  19. package/skills/applying-slds/guidance/slds-development-guide.md +288 -0
  20. package/skills/applying-slds/guidance/styling-hooks/borders.md +202 -0
  21. package/skills/applying-slds/guidance/styling-hooks/color/expressive-palette-hooks.md +153 -0
  22. package/skills/applying-slds/guidance/styling-hooks/color/index.md +171 -0
  23. package/skills/applying-slds/guidance/styling-hooks/color/semantic/accent-hooks.md +204 -0
  24. package/skills/applying-slds/guidance/styling-hooks/color/semantic/feedback-hooks.md +768 -0
  25. package/skills/applying-slds/guidance/styling-hooks/color/semantic/surface-hooks.md +337 -0
  26. package/skills/applying-slds/guidance/styling-hooks/color/system-hooks.md +132 -0
  27. package/skills/applying-slds/guidance/styling-hooks/index.md +327 -0
  28. package/skills/applying-slds/guidance/styling-hooks/shadows.md +238 -0
  29. package/skills/applying-slds/guidance/styling-hooks/spacing.md +254 -0
  30. package/skills/applying-slds/guidance/styling-hooks/typography.md +448 -0
  31. package/skills/applying-slds/guidance/utilities/alignment.md +119 -0
  32. package/skills/applying-slds/guidance/utilities/borders.md +131 -0
  33. package/skills/applying-slds/guidance/utilities/box.md +125 -0
  34. package/skills/applying-slds/guidance/utilities/color.md +165 -0
  35. package/skills/applying-slds/guidance/utilities/dark-mode.md +111 -0
  36. package/skills/applying-slds/guidance/utilities/description-list.md +168 -0
  37. package/skills/applying-slds/guidance/utilities/floats.md +117 -0
  38. package/skills/applying-slds/guidance/utilities/grid.md +264 -0
  39. package/skills/applying-slds/guidance/utilities/horizontal-list.md +110 -0
  40. package/skills/applying-slds/guidance/utilities/hyphenation.md +84 -0
  41. package/skills/applying-slds/guidance/utilities/index.md +205 -0
  42. package/skills/applying-slds/guidance/utilities/interactions.md +89 -0
  43. package/skills/applying-slds/guidance/utilities/layout.md +109 -0
  44. package/skills/applying-slds/guidance/utilities/line-clamp.md +131 -0
  45. package/skills/applying-slds/guidance/utilities/margin.md +155 -0
  46. package/skills/applying-slds/guidance/utilities/media-object.md +161 -0
  47. package/skills/applying-slds/guidance/utilities/name-value-list.md +152 -0
  48. package/skills/applying-slds/guidance/utilities/padding.md +155 -0
  49. package/skills/applying-slds/guidance/utilities/position.md +177 -0
  50. package/skills/applying-slds/guidance/utilities/print.md +114 -0
  51. package/skills/applying-slds/guidance/utilities/scrollable.md +126 -0
  52. package/skills/applying-slds/guidance/utilities/sizing.md +190 -0
  53. package/skills/applying-slds/guidance/utilities/themes.md +121 -0
  54. package/skills/applying-slds/guidance/utilities/truncate.md +127 -0
  55. package/skills/applying-slds/guidance/utilities/typography.md +166 -0
  56. package/skills/applying-slds/guidance/utilities/vertical-list.md +166 -0
  57. package/skills/applying-slds/guidance/utilities/visibility.md +228 -0
  58. package/skills/applying-slds/metadata/README.md +84 -0
  59. package/skills/applying-slds/metadata/blueprints/components/accordion.yaml +304 -0
  60. package/skills/applying-slds/metadata/blueprints/components/activity-timeline.yaml +92 -0
  61. package/skills/applying-slds/metadata/blueprints/components/alert.yaml +103 -0
  62. package/skills/applying-slds/metadata/blueprints/components/app-launcher.yaml +94 -0
  63. package/skills/applying-slds/metadata/blueprints/components/avatar-group.yaml +81 -0
  64. package/skills/applying-slds/metadata/blueprints/components/avatar.yaml +97 -0
  65. package/skills/applying-slds/metadata/blueprints/components/badges.yaml +102 -0
  66. package/skills/applying-slds/metadata/blueprints/components/brand-band.yaml +198 -0
  67. package/skills/applying-slds/metadata/blueprints/components/breadcrumbs.yaml +95 -0
  68. package/skills/applying-slds/metadata/blueprints/components/builder-header.yaml +192 -0
  69. package/skills/applying-slds/metadata/blueprints/components/button-groups.yaml +82 -0
  70. package/skills/applying-slds/metadata/blueprints/components/button-icons.yaml +295 -0
  71. package/skills/applying-slds/metadata/blueprints/components/buttons.yaml +230 -0
  72. package/skills/applying-slds/metadata/blueprints/components/cards.yaml +124 -0
  73. package/skills/applying-slds/metadata/blueprints/components/carousel.yaml +140 -0
  74. package/skills/applying-slds/metadata/blueprints/components/chat.yaml +179 -0
  75. package/skills/applying-slds/metadata/blueprints/components/checkbox-button-group.yaml +192 -0
  76. package/skills/applying-slds/metadata/blueprints/components/checkbox-button.yaml +204 -0
  77. package/skills/applying-slds/metadata/blueprints/components/checkbox-toggle.yaml +177 -0
  78. package/skills/applying-slds/metadata/blueprints/components/checkbox.yaml +108 -0
  79. package/skills/applying-slds/metadata/blueprints/components/color-picker.yaml +172 -0
  80. package/skills/applying-slds/metadata/blueprints/components/combobox.yaml +136 -0
  81. package/skills/applying-slds/metadata/blueprints/components/counter.yaml +147 -0
  82. package/skills/applying-slds/metadata/blueprints/components/data-tables.yaml +157 -0
  83. package/skills/applying-slds/metadata/blueprints/components/datepickers.yaml +130 -0
  84. package/skills/applying-slds/metadata/blueprints/components/datetime-picker.yaml +155 -0
  85. package/skills/applying-slds/metadata/blueprints/components/docked-composer.yaml +201 -0
  86. package/skills/applying-slds/metadata/blueprints/components/docked-form-footer.yaml +161 -0
  87. package/skills/applying-slds/metadata/blueprints/components/docked-utility-bar.yaml +175 -0
  88. package/skills/applying-slds/metadata/blueprints/components/drop-zone.yaml +115 -0
  89. package/skills/applying-slds/metadata/blueprints/components/dueling-picklist.yaml +196 -0
  90. package/skills/applying-slds/metadata/blueprints/components/dynamic-icons.yaml +128 -0
  91. package/skills/applying-slds/metadata/blueprints/components/dynamic-menu.yaml +141 -0
  92. package/skills/applying-slds/metadata/blueprints/components/expandable-section.yaml +115 -0
  93. package/skills/applying-slds/metadata/blueprints/components/expression.yaml +143 -0
  94. package/skills/applying-slds/metadata/blueprints/components/feeds.yaml +125 -0
  95. package/skills/applying-slds/metadata/blueprints/components/file-selector.yaml +154 -0
  96. package/skills/applying-slds/metadata/blueprints/components/files.yaml +119 -0
  97. package/skills/applying-slds/metadata/blueprints/components/form-element.yaml +145 -0
  98. package/skills/applying-slds/metadata/blueprints/components/global-header.yaml +120 -0
  99. package/skills/applying-slds/metadata/blueprints/components/global-navigation.yaml +100 -0
  100. package/skills/applying-slds/metadata/blueprints/components/icons.yaml +138 -0
  101. package/skills/applying-slds/metadata/blueprints/components/illustration.yaml +205 -0
  102. package/skills/applying-slds/metadata/blueprints/components/input.yaml +151 -0
  103. package/skills/applying-slds/metadata/blueprints/components/list-builder.yaml +127 -0
  104. package/skills/applying-slds/metadata/blueprints/components/lookups.yaml +132 -0
  105. package/skills/applying-slds/metadata/blueprints/components/map.yaml +118 -0
  106. package/skills/applying-slds/metadata/blueprints/components/menus.yaml +134 -0
  107. package/skills/applying-slds/metadata/blueprints/components/modals.yaml +152 -0
  108. package/skills/applying-slds/metadata/blueprints/components/notifications.yaml +88 -0
  109. package/skills/applying-slds/metadata/blueprints/components/page-headers.yaml +135 -0
  110. package/skills/applying-slds/metadata/blueprints/components/panels.yaml +149 -0
  111. package/skills/applying-slds/metadata/blueprints/components/path.yaml +154 -0
  112. package/skills/applying-slds/metadata/blueprints/components/picklist.yaml +125 -0
  113. package/skills/applying-slds/metadata/blueprints/components/pills.yaml +154 -0
  114. package/skills/applying-slds/metadata/blueprints/components/popovers.yaml +120 -0
  115. package/skills/applying-slds/metadata/blueprints/components/progress-bar.yaml +110 -0
  116. package/skills/applying-slds/metadata/blueprints/components/progress-indicator.yaml +133 -0
  117. package/skills/applying-slds/metadata/blueprints/components/progress-ring.yaml +102 -0
  118. package/skills/applying-slds/metadata/blueprints/components/prompt.yaml +126 -0
  119. package/skills/applying-slds/metadata/blueprints/components/publishers.yaml +178 -0
  120. package/skills/applying-slds/metadata/blueprints/components/radio-button-group.yaml +172 -0
  121. package/skills/applying-slds/metadata/blueprints/components/radio-group.yaml +112 -0
  122. package/skills/applying-slds/metadata/blueprints/components/rich-text-editor.yaml +135 -0
  123. package/skills/applying-slds/metadata/blueprints/components/scoped-notifications.yaml +188 -0
  124. package/skills/applying-slds/metadata/blueprints/components/scoped-tabs.yaml +97 -0
  125. package/skills/applying-slds/metadata/blueprints/components/select.yaml +127 -0
  126. package/skills/applying-slds/metadata/blueprints/components/setup-assistant.yaml +152 -0
  127. package/skills/applying-slds/metadata/blueprints/components/slider.yaml +111 -0
  128. package/skills/applying-slds/metadata/blueprints/components/spinners.yaml +135 -0
  129. package/skills/applying-slds/metadata/blueprints/components/split-view.yaml +112 -0
  130. package/skills/applying-slds/metadata/blueprints/components/summary-detail.yaml +103 -0
  131. package/skills/applying-slds/metadata/blueprints/components/tabs.yaml +138 -0
  132. package/skills/applying-slds/metadata/blueprints/components/textarea.yaml +116 -0
  133. package/skills/applying-slds/metadata/blueprints/components/tiles.yaml +108 -0
  134. package/skills/applying-slds/metadata/blueprints/components/timepicker.yaml +111 -0
  135. package/skills/applying-slds/metadata/blueprints/components/toast.yaml +154 -0
  136. package/skills/applying-slds/metadata/blueprints/components/tooltips.yaml +107 -0
  137. package/skills/applying-slds/metadata/blueprints/components/tree-grid.yaml +116 -0
  138. package/skills/applying-slds/metadata/blueprints/components/trees.yaml +116 -0
  139. package/skills/applying-slds/metadata/blueprints/components/trial-bar.yaml +112 -0
  140. package/skills/applying-slds/metadata/blueprints/components/vertical-navigation.yaml +130 -0
  141. package/skills/applying-slds/metadata/blueprints/components/vertical-tabs.yaml +140 -0
  142. package/skills/applying-slds/metadata/blueprints/components/visual-picker.yaml +150 -0
  143. package/skills/applying-slds/metadata/blueprints/components/welcome-mat.yaml +136 -0
  144. package/skills/applying-slds/metadata/hooks-index.json +6272 -0
  145. package/skills/applying-slds/metadata/icon-metadata.json +38466 -0
  146. package/skills/applying-slds/metadata/utilities-index.json +21912 -0
  147. package/skills/applying-slds/references/component-selection.md +112 -0
  148. package/skills/applying-slds/references/icons-decision-guide.md +124 -0
  149. package/skills/applying-slds/references/styling-decision-guide.md +228 -0
  150. package/skills/applying-slds/references/utilities-quick-ref.md +125 -0
  151. package/skills/applying-slds/scripts/search-blueprints.cjs +117 -0
  152. package/skills/applying-slds/scripts/search-hooks.cjs +139 -0
  153. package/skills/applying-slds/scripts/search-icons.cjs +174 -0
  154. package/skills/applying-slds/scripts/search-utilities.cjs +161 -0
  155. package/skills/building-mobile-apps/SKILL.md +0 -1
  156. package/skills/building-omnistudio-callable-apex/SKILL.md +0 -1
  157. package/skills/building-omnistudio-datamapper/SKILL.md +0 -1
  158. package/skills/building-omnistudio-flexcard/SKILL.md +0 -1
  159. package/skills/building-omnistudio-integration-procedure/SKILL.md +0 -1
  160. package/skills/building-omnistudio-omniscript/SKILL.md +0 -1
  161. package/skills/building-sf-integrations/SKILL.md +0 -1
  162. package/skills/configuring-connected-apps/SKILL.md +0 -1
  163. package/skills/connecting-datacloud/SKILL.md +0 -1
  164. package/skills/creating-b2b-commerce-store/SKILL.md +0 -1
  165. package/skills/debugging-apex-logs/SKILL.md +0 -1
  166. package/skills/deploying-metadata/SKILL.md +0 -1
  167. package/skills/deploying-omnistudio-datapacks/SKILL.md +0 -1
  168. package/skills/developing-agentforce/SKILL.md +0 -1
  169. package/skills/fetching-salesforce-docs/SKILL.md +0 -1
  170. package/skills/generating-custom-lightning-type/SKILL.md +17 -39
  171. package/skills/generating-custom-lightning-type/assets/primitive-types-and-constraints.md +41 -0
  172. package/skills/generating-custom-lightning-type/references/widget-rendition.md +124 -0
  173. package/skills/generating-lwc-components/SKILL.md +0 -1
  174. package/skills/generating-mermaid-diagrams/SKILL.md +0 -1
  175. package/skills/generating-visual-diagrams/SKILL.md +0 -1
  176. package/skills/handling-sf-data/SKILL.md +0 -1
  177. package/skills/harmonizing-datacloud/SKILL.md +0 -1
  178. package/skills/integrating-b2b-commerce-open-code-components/SKILL.md +0 -1
  179. package/skills/investigating-agentforce-architecture/README.md +156 -0
  180. package/skills/investigating-agentforce-architecture/SKILL.md +230 -0
  181. package/skills/investigating-agentforce-architecture/assets/cli/describe_sobject.yaml +16 -0
  182. package/skills/investigating-agentforce-architecture/assets/cli/describe_tooling_sobject.yaml +17 -0
  183. package/skills/investigating-agentforce-architecture/assets/cli/list_metadata_genaiprompttemplate.yaml +17 -0
  184. package/skills/investigating-agentforce-architecture/assets/cli/org_display.yaml +15 -0
  185. package/skills/investigating-agentforce-architecture/assets/cli/retrieve_genai_plugin.yaml +18 -0
  186. package/skills/investigating-agentforce-architecture/assets/cli/show_access_token.yaml +27 -0
  187. package/skills/investigating-agentforce-architecture/assets/mermaid/action_tree.mmd +20 -0
  188. package/skills/investigating-agentforce-architecture/assets/mermaid/data_flow.mmd +19 -0
  189. package/skills/investigating-agentforce-architecture/assets/mermaid/dependency_graph.mmd +19 -0
  190. package/skills/investigating-agentforce-architecture/assets/mermaid/invocation_sequence.mmd +20 -0
  191. package/skills/investigating-agentforce-architecture/assets/mermaid/planner_state.mmd +18 -0
  192. package/skills/investigating-agentforce-architecture/assets/soql/apex_class_bodies_by_ids.soql +3 -0
  193. package/skills/investigating-agentforce-architecture/assets/soql/apex_class_bodies_by_names.soql +3 -0
  194. package/skills/investigating-agentforce-architecture/assets/soql/bot_definition_details.soql +3 -0
  195. package/skills/investigating-agentforce-architecture/assets/soql/bot_version_lookup.soql +4 -0
  196. package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_by_ids.soql +3 -0
  197. package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_ids_by_names.soql +3 -0
  198. package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_view_by_durable_ids.soql +4 -0
  199. package/skills/investigating-agentforce-architecture/assets/soql/flow_metadata_by_id.soql +3 -0
  200. package/skills/investigating-agentforce-architecture/assets/soql/functions_by_plugins.soql +5 -0
  201. package/skills/investigating-agentforce-architecture/assets/soql/planner_attrs_by_parent_ids.soql +3 -0
  202. package/skills/investigating-agentforce-architecture/assets/soql/planner_bundle_functions.soql +3 -0
  203. package/skills/investigating-agentforce-architecture/assets/soql/planner_definition_by_agent_chain.soql +3 -0
  204. package/skills/investigating-agentforce-architecture/assets/soql/plugin_functions_by_plugin_ids.soql +3 -0
  205. package/skills/investigating-agentforce-architecture/assets/soql/plugin_instructions_by_plugin_ids.soql +3 -0
  206. package/skills/investigating-agentforce-architecture/assets/soql/plugins_by_planner.soql +4 -0
  207. package/skills/investigating-agentforce-architecture/references/architecture_sections.md +243 -0
  208. package/skills/investigating-agentforce-architecture/references/contract.json +244 -0
  209. package/skills/investigating-agentforce-architecture/references/soql_fields.md +512 -0
  210. package/skills/investigating-agentforce-architecture/scripts/_shared/__init__.py +1 -0
  211. package/skills/investigating-agentforce-architecture/scripts/_shared/fs_guard.py +329 -0
  212. package/skills/investigating-agentforce-architecture/scripts/_shared/paths.py +110 -0
  213. package/skills/investigating-agentforce-architecture/scripts/_shared/runtime.py +59 -0
  214. package/skills/investigating-agentforce-architecture/scripts/_shared/sql.py +10 -0
  215. package/skills/investigating-agentforce-architecture/scripts/cache_check.py +234 -0
  216. package/skills/investigating-agentforce-architecture/scripts/config.py +131 -0
  217. package/skills/investigating-agentforce-architecture/scripts/fetch_soql.py +689 -0
  218. package/skills/investigating-agentforce-architecture/scripts/finalize.py +295 -0
  219. package/skills/investigating-agentforce-architecture/scripts/main.py +2835 -0
  220. package/skills/investigating-agentforce-architecture/scripts/metadata_listing.py +265 -0
  221. package/skills/investigating-agentforce-architecture/scripts/parallel_retrieve.py +69 -0
  222. package/skills/investigating-agentforce-architecture/scripts/parse_bundle.py +215 -0
  223. package/skills/investigating-agentforce-architecture/scripts/parse_wave.py +845 -0
  224. package/skills/investigating-agentforce-architecture/scripts/probe_channels.py +302 -0
  225. package/skills/investigating-agentforce-architecture/scripts/render_architecture.py +1043 -0
  226. package/skills/investigating-agentforce-architecture/scripts/resolve_bot.py +255 -0
  227. package/skills/investigating-agentforce-architecture/scripts/resolve_invocation_target.py +130 -0
  228. package/skills/investigating-agentforce-architecture/scripts/rest_client.py +763 -0
  229. package/skills/investigating-agentforce-architecture/scripts/retrieve_planner.py +13 -0
  230. package/skills/investigating-agentforce-architecture/scripts/sf_cli.py +242 -0
  231. package/skills/investigating-agentforce-architecture/scripts/soql_loader.py +253 -0
  232. package/skills/investigating-agentforce-architecture/scripts/summarize_tree.py +143 -0
  233. package/skills/investigating-agentforce-architecture/scripts/tests/__init__.py +0 -0
  234. package/skills/investigating-agentforce-architecture/scripts/tests/_bootstrap.py +23 -0
  235. package/skills/investigating-agentforce-architecture/scripts/tests/fixtures/__init__.py +0 -0
  236. package/skills/investigating-agentforce-architecture/scripts/tests/fixtures/genai_payloads.py +400 -0
  237. package/skills/investigating-agentforce-architecture/scripts/tests/test_cache_check.py +307 -0
  238. package/skills/investigating-agentforce-architecture/scripts/tests/test_cache_check_main.py +283 -0
  239. package/skills/investigating-agentforce-architecture/scripts/tests/test_config.py +115 -0
  240. package/skills/investigating-agentforce-architecture/scripts/tests/test_end_to_end_fixture.py +651 -0
  241. package/skills/investigating-agentforce-architecture/scripts/tests/test_finalize.py +278 -0
  242. package/skills/investigating-agentforce-architecture/scripts/tests/test_flow_children_inflation.py +582 -0
  243. package/skills/investigating-agentforce-architecture/scripts/tests/test_fs_guard.py +113 -0
  244. package/skills/investigating-agentforce-architecture/scripts/tests/test_iterative_wave_b.py +478 -0
  245. package/skills/investigating-agentforce-architecture/scripts/tests/test_main_pipeline.py +3359 -0
  246. package/skills/investigating-agentforce-architecture/scripts/tests/test_parallel_retrieve.py +131 -0
  247. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_bundle.py +400 -0
  248. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave.py +644 -0
  249. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_classifiers.py +224 -0
  250. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_helpers.py +380 -0
  251. package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_main.py +397 -0
  252. package/skills/investigating-agentforce-architecture/scripts/tests/test_per_branch_visited.py +244 -0
  253. package/skills/investigating-agentforce-architecture/scripts/tests/test_probe_channels.py +359 -0
  254. package/skills/investigating-agentforce-architecture/scripts/tests/test_probe_cli_recipes.py +185 -0
  255. package/skills/investigating-agentforce-architecture/scripts/tests/test_render_architecture.py +810 -0
  256. package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_bot.py +203 -0
  257. package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_creds.py +157 -0
  258. package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_invocation_target.py +145 -0
  259. package/skills/investigating-agentforce-architecture/scripts/tests/test_rest_client.py +1253 -0
  260. package/skills/investigating-agentforce-architecture/scripts/tests/test_runtime_override.py +100 -0
  261. package/skills/investigating-agentforce-architecture/scripts/tests/test_sf_cli.py +261 -0
  262. package/skills/investigating-agentforce-architecture/scripts/tests/test_signature_stamping.py +466 -0
  263. package/skills/investigating-agentforce-architecture/scripts/tests/test_soql_loader.py +501 -0
  264. package/skills/investigating-agentforce-architecture/scripts/tests/test_summarize_tree.py +241 -0
  265. package/skills/investigating-agentforce-architecture/scripts/tests/test_write_emit_ctx.py +480 -0
  266. package/skills/investigating-agentforce-architecture/tools/emit_env.py +157 -0
  267. package/skills/investigating-agentforce-architecture/tools/emit_result.py +262 -0
  268. package/skills/investigating-agentforce-architecture/tools/sanitize.py +33 -0
  269. package/skills/investigating-agentforce-architecture/tools/write_emit_ctx.py +332 -0
  270. package/skills/investigating-agentforce-d360/README.md +123 -0
  271. package/skills/investigating-agentforce-d360/SKILL.md +163 -0
  272. package/skills/investigating-agentforce-d360/assets/dc/app_generation.sql +51 -0
  273. package/skills/investigating-agentforce-d360/assets/dc/content_category.sql +44 -0
  274. package/skills/investigating-agentforce-d360/assets/dc/content_quality.sql +41 -0
  275. package/skills/investigating-agentforce-d360/assets/dc/discover_sessions.sql +36 -0
  276. package/skills/investigating-agentforce-d360/assets/dc/feedback.sql +47 -0
  277. package/skills/investigating-agentforce-d360/assets/dc/feedback_details.sql +38 -0
  278. package/skills/investigating-agentforce-d360/assets/dc/gateway_records.sql +45 -0
  279. package/skills/investigating-agentforce-d360/assets/dc/gateway_request_llm.sql +50 -0
  280. package/skills/investigating-agentforce-d360/assets/dc/gateway_request_metadata.sql +44 -0
  281. package/skills/investigating-agentforce-d360/assets/dc/gateway_request_tags.sql +42 -0
  282. package/skills/investigating-agentforce-d360/assets/dc/gateway_requests.sql +89 -0
  283. package/skills/investigating-agentforce-d360/assets/dc/gateway_responses.sql +43 -0
  284. package/skills/investigating-agentforce-d360/assets/dc/generations.sql +52 -0
  285. package/skills/investigating-agentforce-d360/assets/dc/interactions.sql +53 -0
  286. package/skills/investigating-agentforce-d360/assets/dc/messages.sql +53 -0
  287. package/skills/investigating-agentforce-d360/assets/dc/messaging_session.sql +37 -0
  288. package/skills/investigating-agentforce-d360/assets/dc/moment_interactions.sql +34 -0
  289. package/skills/investigating-agentforce-d360/assets/dc/moments.sql +39 -0
  290. package/skills/investigating-agentforce-d360/assets/dc/participants.sql +48 -0
  291. package/skills/investigating-agentforce-d360/assets/dc/sessions.sql +78 -0
  292. package/skills/investigating-agentforce-d360/assets/dc/steps.sql +64 -0
  293. package/skills/investigating-agentforce-d360/assets/dc/tag_associations.sql +46 -0
  294. package/skills/investigating-agentforce-d360/assets/dc/tag_definition_associations.sql +37 -0
  295. package/skills/investigating-agentforce-d360/assets/dc/tag_definitions.sql +50 -0
  296. package/skills/investigating-agentforce-d360/assets/dc/tags.sql +37 -0
  297. package/skills/investigating-agentforce-d360/assets/dc/telemetry_spans.sql +55 -0
  298. package/skills/investigating-agentforce-d360/references/artifacts.md +50 -0
  299. package/skills/investigating-agentforce-d360/references/dc_dmo_fields.md +823 -0
  300. package/skills/investigating-agentforce-d360/references/dc_pipeline_contract.md +608 -0
  301. package/skills/investigating-agentforce-d360/scripts/_shared/__init__.py +2 -0
  302. package/skills/investigating-agentforce-d360/scripts/_shared/cli_override.py +98 -0
  303. package/skills/investigating-agentforce-d360/scripts/_shared/fs_guard.py +334 -0
  304. package/skills/investigating-agentforce-d360/scripts/_shared/paths.py +155 -0
  305. package/skills/investigating-agentforce-d360/scripts/_shared/runtime.py +59 -0
  306. package/skills/investigating-agentforce-d360/scripts/_shared/sql.py +14 -0
  307. package/skills/investigating-agentforce-d360/scripts/assemble_dc.py +1624 -0
  308. package/skills/investigating-agentforce-d360/scripts/config.py +45 -0
  309. package/skills/investigating-agentforce-d360/scripts/dc.py +188 -0
  310. package/skills/investigating-agentforce-d360/scripts/discover_sessions.py +556 -0
  311. package/skills/investigating-agentforce-d360/scripts/fetch_dc.py +1045 -0
  312. package/skills/investigating-agentforce-d360/scripts/render_dc.py +1750 -0
  313. package/skills/investigating-agentforce-d360/scripts/resolve_session.py +264 -0
  314. package/skills/investigating-agentforce-d360/scripts/storage.py +92 -0
  315. package/skills/investigating-agentforce-d360/scripts/tests/__init__.py +0 -0
  316. package/skills/investigating-agentforce-d360/scripts/tests/_bootstrap.py +15 -0
  317. package/skills/investigating-agentforce-d360/scripts/tests/fixtures/__init__.py +0 -0
  318. package/skills/investigating-agentforce-d360/scripts/tests/fixtures/synthetic_session.py +424 -0
  319. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_bootstrap_and_mode.py +115 -0
  320. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_gateway_direct.py +220 -0
  321. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_gateway_direct_integration.py +158 -0
  322. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_helpers.py +287 -0
  323. package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_integration.py +247 -0
  324. package/skills/investigating-agentforce-d360/scripts/tests/test_dc_and_resolve_session.py +433 -0
  325. package/skills/investigating-agentforce-d360/scripts/tests/test_discover_sessions.py +458 -0
  326. package/skills/investigating-agentforce-d360/scripts/tests/test_discover_sessions_grep_ci.py +193 -0
  327. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_helpers.py +266 -0
  328. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_identity.py +528 -0
  329. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_main.py +251 -0
  330. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_waterfall.py +229 -0
  331. package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_waterfall_full.py +283 -0
  332. package/skills/investigating-agentforce-d360/scripts/tests/test_identity_coherence.py +327 -0
  333. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_branches.py +256 -0
  334. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_gateway_direct.py +130 -0
  335. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_helpers.py +291 -0
  336. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_integration.py +220 -0
  337. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_planner_llm_calls.py +284 -0
  338. package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_show_prompts_gating.py +215 -0
  339. package/skills/investigating-agentforce-d360/scripts/tests/test_resolve_from_disk.py +100 -0
  340. package/skills/investigating-agentforce-d360/scripts/tests/test_resolve_session_main.py +149 -0
  341. package/skills/investigating-agentforce-d360/scripts/tests/test_runtime_override.py +104 -0
  342. package/skills/investigating-agentforce-d360/scripts/tests/test_session_shape.py +95 -0
  343. package/skills/investigating-agentforce-d360/scripts/tests/test_session_shape_dropped_by_stdm.py +85 -0
  344. package/skills/managing-managed-event-subscription/SKILL.md +152 -0
  345. package/skills/managing-managed-event-subscription/assets/managed-event-subscription-template.xml +20 -0
  346. package/skills/managing-managed-event-subscription/references/delete-guide.md +57 -0
  347. package/skills/managing-managed-event-subscription/references/topic-name-formats.md +26 -0
  348. package/skills/managing-managed-event-subscription/references/update-constraints.md +30 -0
  349. package/skills/modeling-omnistudio-epc-catalog/SKILL.md +0 -1
  350. package/skills/observing-agentforce/SKILL.md +0 -1
  351. package/skills/orchestrating-datacloud/SKILL.md +0 -1
  352. package/skills/preparing-datacloud/SKILL.md +0 -1
  353. package/skills/querying-soql/SKILL.md +0 -1
  354. package/skills/retrieving-datacloud/SKILL.md +0 -1
  355. package/skills/running-apex-tests/SKILL.md +0 -1
  356. package/skills/running-code-analyzer/SKILL.md +0 -1
  357. package/skills/segmenting-datacloud/SKILL.md +0 -1
  358. package/skills/testing-agentforce/SKILL.md +0 -1
  359. package/skills/uplifting-components-to-slds2/SKILL.md +3 -2
  360. package/skills/uplifting-components-to-slds2/references/color-hooks-decision-guide.md +30 -9
  361. package/skills/uplifting-components-to-slds2/references/examples.md +24 -6
  362. package/skills/validating-slds/SKILL.md +262 -0
  363. package/skills/validating-slds/references/quality-checks.md +308 -0
  364. package/skills/validating-slds/references/report-format.md +302 -0
  365. package/skills/validating-slds/scripts/analyze-quality.cjs +521 -0
@@ -0,0 +1,528 @@
1
+ """Tests for ``fetch_dc._resolve_identity`` + ``sf org display`` fallback.
2
+
3
+ Closes a real-world failure mode: ``sessions[0].ssot__InternalOrganizationId__c``
4
+ is occasionally null in SSOT materialization despite every other field
5
+ being populated (e.g. session ``019dface-0000-7000-8000-000000000001`` in
6
+ ``my-org-alias``). The authenticated ``sf`` alias knows the org id
7
+ regardless, so we fall back to ``sf org display --target-org <alias> --json``
8
+ and parse ``.result.id``. If that also fails, a unified diagnostic
9
+ surfaces both failure modes.
10
+
11
+ Every test patches ``subprocess.run`` at the ``fetch_dc`` module level so
12
+ no real CLI is ever invoked.
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import json
17
+ import subprocess
18
+ import unittest
19
+ from types import SimpleNamespace
20
+ from unittest import mock
21
+
22
+ from . import _bootstrap # noqa: F401 — sys.path setup
23
+
24
+ import fetch_dc # type: ignore
25
+
26
+
27
+ _ORG_ALIAS = "my-org-alias"
28
+ _FULL_ORG_ID_18 = "00D0000000000000EA"
29
+ _EXPECTED_ORG_ID_15 = "00D000000000000"
30
+ _AGENT_API = "DemoAgent"
31
+ _AGENT_VER = "v5"
32
+
33
+
34
+ def _agent_participant() -> dict:
35
+ return {
36
+ "ssot__AiAgentSessionParticipantRole__c": "AGENT",
37
+ "ssot__AiAgentApiName__c": _AGENT_API,
38
+ "ssot__AiAgentVersionApiName__c": _AGENT_VER,
39
+ }
40
+
41
+
42
+ def _sf_cli_success_stdout(org_id: str = _FULL_ORG_ID_18) -> str:
43
+ """Shape mirrors the real ``sf org display --json`` payload."""
44
+ return json.dumps({
45
+ "status": 0,
46
+ "result": {
47
+ "id": org_id,
48
+ "instanceUrl": "https://example.my.salesforce.com",
49
+ "accessToken": "REDACTED",
50
+ },
51
+ })
52
+
53
+
54
+ class ResolveIdentityDmoPopulatedTests(unittest.TestCase):
55
+ """Happy path — DMO field carries a valid 18-char id, no subprocess spawn."""
56
+
57
+ def test_resolve_identity_uses_dmo_when_populated(self):
58
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
59
+ participants = [_agent_participant()]
60
+
61
+ with mock.patch.object(fetch_dc.subprocess, "run") as m_run:
62
+ org_id_15, agent, ver = fetch_dc._resolve_identity(
63
+ sessions, participants, _ORG_ALIAS,
64
+ )
65
+
66
+ self.assertEqual(org_id_15, _EXPECTED_ORG_ID_15)
67
+ self.assertEqual(agent, _AGENT_API)
68
+ self.assertEqual(ver, _AGENT_VER)
69
+ m_run.assert_not_called()
70
+
71
+
72
+ class ResolveIdentityDmoFallbackTests(unittest.TestCase):
73
+ """DMO field null/empty/short — fall back to ``sf org display``."""
74
+
75
+ def _patch_sf_cli_ok(self, org_id: str = _FULL_ORG_ID_18):
76
+ return mock.patch.object(
77
+ fetch_dc.subprocess, "run",
78
+ return_value=SimpleNamespace(
79
+ stdout=_sf_cli_success_stdout(org_id),
80
+ stderr="",
81
+ returncode=0,
82
+ ),
83
+ )
84
+
85
+ def test_resolve_identity_falls_back_to_sf_cli_when_dmo_null(self):
86
+ sessions = [{"ssot__InternalOrganizationId__c": None}]
87
+ participants = [_agent_participant()]
88
+
89
+ with self._patch_sf_cli_ok() as m_run:
90
+ org_id_15, agent, ver = fetch_dc._resolve_identity(
91
+ sessions, participants, _ORG_ALIAS,
92
+ )
93
+
94
+ self.assertEqual(org_id_15, _EXPECTED_ORG_ID_15)
95
+ self.assertEqual(agent, _AGENT_API)
96
+ self.assertEqual(ver, _AGENT_VER)
97
+ # Exact argv shape matters — it's the public contract with the sf CLI.
98
+ args, kwargs = m_run.call_args
99
+ self.assertEqual(
100
+ args[0],
101
+ ["sf", "org", "display", "--target-org", _ORG_ALIAS, "--json"],
102
+ )
103
+ self.assertTrue(kwargs.get("check"))
104
+ self.assertTrue(kwargs.get("capture_output"))
105
+ self.assertTrue(kwargs.get("text"))
106
+
107
+ def test_resolve_identity_falls_back_when_dmo_empty_string(self):
108
+ sessions = [{"ssot__InternalOrganizationId__c": ""}]
109
+ participants = [_agent_participant()]
110
+
111
+ with self._patch_sf_cli_ok():
112
+ org_id_15, _, _ = fetch_dc._resolve_identity(
113
+ sessions, participants, _ORG_ALIAS,
114
+ )
115
+ self.assertEqual(org_id_15, _EXPECTED_ORG_ID_15)
116
+
117
+ def test_resolve_identity_falls_back_when_dmo_shorter_than_15(self):
118
+ sessions = [{"ssot__InternalOrganizationId__c": "shortid"}]
119
+ participants = [_agent_participant()]
120
+
121
+ with self._patch_sf_cli_ok():
122
+ org_id_15, _, _ = fetch_dc._resolve_identity(
123
+ sessions, participants, _ORG_ALIAS,
124
+ )
125
+ self.assertEqual(org_id_15, _EXPECTED_ORG_ID_15)
126
+
127
+
128
+ class ResolveIdentityBothSourcesFailTests(unittest.TestCase):
129
+ """When both the DMO field AND the CLI fallback fail, surface both."""
130
+
131
+ def test_resolve_identity_raises_when_both_sources_fail(self):
132
+ sessions = [{"ssot__InternalOrganizationId__c": None}]
133
+ participants = [_agent_participant()]
134
+
135
+ err = subprocess.CalledProcessError(
136
+ returncode=1,
137
+ cmd=["sf", "org", "display", "--target-org", _ORG_ALIAS, "--json"],
138
+ stderr="No AuthInfo found for name " + _ORG_ALIAS,
139
+ )
140
+ with mock.patch.object(fetch_dc.subprocess, "run", side_effect=err):
141
+ with self.assertRaises(SystemExit) as ctx:
142
+ fetch_dc._resolve_identity(
143
+ sessions, participants, _ORG_ALIAS,
144
+ )
145
+
146
+ msg = str(ctx.exception)
147
+ # Must mention both failure modes so users know which to fix.
148
+ self.assertIn("both DMO field and sf org display failed", msg)
149
+ self.assertIn(_ORG_ALIAS, msg)
150
+ self.assertIn("CalledProcessError", msg)
151
+
152
+
153
+ class ResolveIdentityNoAgentParticipantsTests(unittest.TestCase):
154
+ """Recently-created sessions can land here while STDM is still
155
+ materializing — the AGENT participant rows haven't been written yet.
156
+ The error must hint at retry rather than implying a malformed session.
157
+ """
158
+
159
+ def test_resolve_identity_raises_with_retry_hint_when_no_agent_participants(self):
160
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
161
+ # No AGENT-role participants; only a USER row.
162
+ participants = [{
163
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
164
+ "ssot__AiAgentApiName__c": "",
165
+ "ssot__AiAgentVersionApiName__c": "",
166
+ }]
167
+
168
+ with self.assertRaises(SystemExit) as ctx:
169
+ fetch_dc._resolve_identity(sessions, participants, _ORG_ALIAS)
170
+
171
+ msg = str(ctx.exception)
172
+ # Identifying string for the error class.
173
+ self.assertIn("no AGENT participants", msg)
174
+ # New (Fix #6) wording — leads with retry, then falls back to malformed.
175
+ self.assertIn("retry in a few minutes", msg)
176
+ self.assertIn("STDM materialization", msg)
177
+
178
+ def test_resolve_identity_raises_when_only_empty_field_participants(self):
179
+ # AGENT-role row exists but agent_api_name + agent_version are blank.
180
+ # Same outcome — no usable identity, same retry-hint error.
181
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
182
+ participants = [{
183
+ "ssot__AiAgentSessionParticipantRole__c": "AGENT",
184
+ "ssot__AiAgentApiName__c": "",
185
+ "ssot__AiAgentVersionApiName__c": "",
186
+ }]
187
+
188
+ with self.assertRaises(SystemExit) as ctx:
189
+ fetch_dc._resolve_identity(sessions, participants, _ORG_ALIAS)
190
+
191
+ self.assertIn("no AGENT participants", str(ctx.exception))
192
+
193
+
194
+ class ResolveIdentityUserRowFallbackTests(unittest.TestCase):
195
+ """Some agent shapes (e.g. the OOTB ``MyAgent`` template) leave
196
+ AGENT-row ``ssot__AiAgentApiName__c`` / ``ssot__AiAgentVersionApiName__c``
197
+ as ``NOT_SET`` indefinitely, while USER-role rows correctly carry the
198
+ api_name. The downstream session is otherwise complete (interactions,
199
+ steps, generations all materialize), so refusing to run wastes signal.
200
+
201
+ The fallback promotes the api_name from any participant row, stamps
202
+ version=``v0`` (placeholder satisfying ``^v[0-9]+$`` per fs_guard), and
203
+ proceeds. Tests guard against regression — a future "tighten this back
204
+ up" refactor would re-break the MyAgent case silently.
205
+ """
206
+
207
+ def test_falls_back_to_user_row_api_name_when_agent_rows_not_set(self):
208
+ # Mirrors a real session shape observed in production:
209
+ # USER rows carry the api_name, AGENT rows are 'NOT_SET'.
210
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
211
+ participants = [
212
+ {
213
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
214
+ "ssot__AiAgentApiName__c": "MyAgent",
215
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
216
+ },
217
+ {
218
+ "ssot__AiAgentSessionParticipantRole__c": "AGENT",
219
+ "ssot__AiAgentApiName__c": "NOT_SET",
220
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
221
+ },
222
+ ]
223
+
224
+ org_id_15, agent, ver = fetch_dc._resolve_identity(
225
+ sessions, participants, _ORG_ALIAS,
226
+ )
227
+
228
+ self.assertEqual(org_id_15, _EXPECTED_ORG_ID_15)
229
+ self.assertEqual(agent, "MyAgent")
230
+ # Placeholder must satisfy the AGENT_VERSION_RE used by paths.session_dir.
231
+ self.assertEqual(ver, "v0")
232
+
233
+ def test_fallback_handles_blank_api_name_on_agent_row(self):
234
+ # AGENT row api_name is empty string (rather than the literal
235
+ # 'NOT_SET'). Both shapes mean the same thing per _NOT_SET.
236
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
237
+ participants = [
238
+ {
239
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
240
+ "ssot__AiAgentApiName__c": "MyAgent",
241
+ "ssot__AiAgentVersionApiName__c": "",
242
+ },
243
+ {
244
+ "ssot__AiAgentSessionParticipantRole__c": "AGENT",
245
+ "ssot__AiAgentApiName__c": "",
246
+ "ssot__AiAgentVersionApiName__c": "",
247
+ },
248
+ ]
249
+
250
+ _, agent, ver = fetch_dc._resolve_identity(
251
+ sessions, participants, _ORG_ALIAS,
252
+ )
253
+ self.assertEqual(agent, "MyAgent")
254
+ self.assertEqual(ver, "v0")
255
+
256
+ def test_fallback_picks_lexicographic_first_when_multiple_user_names(self):
257
+ # Multi-agent handoff session where USER rows mention both agents.
258
+ # The fallback uses sorted({...})[0] to match the dominant-agent
259
+ # policy used elsewhere in the pipeline.
260
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
261
+ participants = [
262
+ {
263
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
264
+ "ssot__AiAgentApiName__c": "ZAgent",
265
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
266
+ },
267
+ {
268
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
269
+ "ssot__AiAgentApiName__c": "AAgent",
270
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
271
+ },
272
+ {
273
+ "ssot__AiAgentSessionParticipantRole__c": "AGENT",
274
+ "ssot__AiAgentApiName__c": "NOT_SET",
275
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
276
+ },
277
+ ]
278
+
279
+ _, agent, ver = fetch_dc._resolve_identity(
280
+ sessions, participants, _ORG_ALIAS,
281
+ )
282
+ self.assertEqual(agent, "AAgent")
283
+ self.assertEqual(ver, "v0")
284
+
285
+ def test_agent_row_with_only_version_not_set_still_uses_strict_path(self):
286
+ # Defensive: AGENT row has a real api_name but version=NOT_SET. The
287
+ # strict candidate filter rejects it, but the fallback should still
288
+ # promote the api_name (avoiding a needless raise just because version
289
+ # was missing on the AGENT row).
290
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
291
+ participants = [{
292
+ "ssot__AiAgentSessionParticipantRole__c": "AGENT",
293
+ "ssot__AiAgentApiName__c": "RealAgent",
294
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
295
+ }]
296
+
297
+ _, agent, ver = fetch_dc._resolve_identity(
298
+ sessions, participants, _ORG_ALIAS,
299
+ )
300
+ self.assertEqual(agent, "RealAgent")
301
+ self.assertEqual(ver, "v0")
302
+
303
+ def test_fallback_rejects_api_name_with_invalid_shape(self):
304
+ # Even though a non-empty api_name is present on a USER row, if it
305
+ # doesn't satisfy ^[A-Za-z0-9_]+$ (fs_guard.API_NAME_RE) the fallback
306
+ # MUST fall through to the original SystemExit. Without this guard,
307
+ # paths.session_dir would later reject the dir with an opaque
308
+ # ValidationError far from where the bad value originated.
309
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
310
+ for bad_name in ("Service Agent", "agent-v1", "agent.v1", "héllo"):
311
+ with self.subTest(bad_name=bad_name):
312
+ participants = [{
313
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
314
+ "ssot__AiAgentApiName__c": bad_name,
315
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
316
+ }]
317
+ with self.assertRaises(SystemExit) as ctx:
318
+ fetch_dc._resolve_identity(
319
+ sessions, participants, _ORG_ALIAS,
320
+ )
321
+ # Falls through to the strict-path SystemExit, NOT a path-
322
+ # validation traceback from fs_guard.
323
+ self.assertIn("no AGENT participants", str(ctx.exception))
324
+
325
+ def test_fallback_skips_invalid_picks_valid_when_both_present(self):
326
+ # If multiple api_names are seen, the regex filter should drop the
327
+ # invalid ones and the fallback should still succeed with a valid one.
328
+ # Defense against a real session that mixes a malformed display-name
329
+ # row (e.g. legacy data) with a clean USER row.
330
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
331
+ participants = [
332
+ {
333
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
334
+ "ssot__AiAgentApiName__c": "Service Agent", # invalid
335
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
336
+ },
337
+ {
338
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
339
+ "ssot__AiAgentApiName__c": "MyAgent", # valid
340
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
341
+ },
342
+ ]
343
+ _, agent, ver = fetch_dc._resolve_identity(
344
+ sessions, participants, _ORG_ALIAS,
345
+ )
346
+ self.assertEqual(agent, "MyAgent")
347
+ self.assertEqual(ver, "v0")
348
+
349
+ def test_fallback_returned_version_matches_agent_version_regex(self):
350
+ # Belt-and-braces: the placeholder version we return MUST match
351
+ # the ^v[0-9]+$ shape enforced by paths.session_dir / fs_guard
352
+ # (see scripts/_shared/paths.py:_validate_agent_triple). If a
353
+ # future change picks a different placeholder ('NOT_SET',
354
+ # 'unknown', 'v0.0', etc.) directory creation downstream will
355
+ # blow up. Test the exact contract here without taking a
356
+ # cross-skill import dependency.
357
+ import re
358
+
359
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
360
+ participants = [{
361
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
362
+ "ssot__AiAgentApiName__c": "MyAgent",
363
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
364
+ }]
365
+ _, _, ver = fetch_dc._resolve_identity(
366
+ sessions, participants, _ORG_ALIAS,
367
+ )
368
+ self.assertRegex(ver, r"^v[0-9]+$")
369
+
370
+
371
+ class ResolveIdentityCrossRoleVersionHarvestTests(unittest.TestCase):
372
+ """Real-data shape: AGENT participant rows had api_name + version both
373
+ NOT_SET, but the USER rows carried the real (api_name, version) pair.
374
+ The prior fallback only harvested api_name from non-AGENT rows and
375
+ stamped version=``v0``, so the dir landed at ``<agent>__v0/`` while
376
+ ``assemble_dc`` reconciled the real version into the tree from
377
+ ``session.identity`` — dir + tree out of sync.
378
+
379
+ The cross-role harvest closes that gap: when the strict AGENT-only
380
+ candidate list is empty, scan ALL participant rows for a valid
381
+ (api_name, version) pair before falling back to the v0 placeholder.
382
+ Real version wins; placeholder is genuinely a last resort.
383
+ """
384
+
385
+ def test_user_row_carries_real_version_dir_lands_correctly(self):
386
+ # The exact shape found on a live session. AGENT rows: NOT_SET on
387
+ # both fields. USER rows: real pair.
388
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
389
+ participants = [
390
+ {
391
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
392
+ "ssot__AiAgentApiName__c": "MyAgent",
393
+ "ssot__AiAgentVersionApiName__c": "v24",
394
+ },
395
+ {
396
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
397
+ "ssot__AiAgentApiName__c": "MyAgent",
398
+ "ssot__AiAgentVersionApiName__c": "v24",
399
+ },
400
+ {
401
+ "ssot__AiAgentSessionParticipantRole__c": "AGENT",
402
+ "ssot__AiAgentApiName__c": "NOT_SET",
403
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
404
+ },
405
+ ]
406
+
407
+ _, agent, ver = fetch_dc._resolve_identity(
408
+ sessions, participants, _ORG_ALIAS,
409
+ )
410
+ self.assertEqual(agent, "MyAgent")
411
+ # MUST be the real version, NOT the v0 placeholder — that's the
412
+ # whole point of the cross-role harvest.
413
+ self.assertEqual(ver, "v24")
414
+
415
+ def test_falls_through_to_v0_placeholder_when_no_role_carries_version(self):
416
+ # Builder Previewer shape: api_name lands on a USER row but no
417
+ # participant row carries a real version. Must drop through to
418
+ # the v0 placeholder branch (which keeps the pipeline runnable
419
+ # for that legitimate session shape).
420
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
421
+ participants = [
422
+ {
423
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
424
+ "ssot__AiAgentApiName__c": "MyAgent",
425
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
426
+ },
427
+ {
428
+ "ssot__AiAgentSessionParticipantRole__c": "AGENT",
429
+ "ssot__AiAgentApiName__c": "NOT_SET",
430
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
431
+ },
432
+ ]
433
+
434
+ _, agent, ver = fetch_dc._resolve_identity(
435
+ sessions, participants, _ORG_ALIAS,
436
+ )
437
+ self.assertEqual(agent, "MyAgent")
438
+ self.assertEqual(ver, "v0")
439
+
440
+ def test_cross_role_rejects_malformed_version(self):
441
+ # Someone wrote a malformed version into a USER row (e.g.
442
+ # 'v1.0', '1', '24'). Must NOT adopt it — fs_guard will reject
443
+ # the dir later. Fall through to v0 placeholder so the pipeline
444
+ # still runs and the assemble_dc reconcile can promote later
445
+ # if a real version shows up elsewhere in the tree.
446
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
447
+ for bad_version in ("v1.0", "1", "24", "version-24", ""):
448
+ with self.subTest(bad_version=bad_version):
449
+ participants = [
450
+ {
451
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
452
+ "ssot__AiAgentApiName__c": "MyAgent",
453
+ "ssot__AiAgentVersionApiName__c": bad_version,
454
+ },
455
+ {
456
+ "ssot__AiAgentSessionParticipantRole__c": "AGENT",
457
+ "ssot__AiAgentApiName__c": "NOT_SET",
458
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
459
+ },
460
+ ]
461
+ _, agent, ver = fetch_dc._resolve_identity(
462
+ sessions, participants, _ORG_ALIAS,
463
+ )
464
+ self.assertEqual(agent, "MyAgent")
465
+ # Bad version rejected; placeholder kicks in.
466
+ self.assertEqual(ver, "v0")
467
+
468
+ def test_strict_agent_row_precedence_beats_user_row(self):
469
+ # When BOTH AGENT and USER rows carry valid (api_name, version)
470
+ # pairs, the strict-AGENT path runs first and the cross-role
471
+ # branch is unreachable. Pin this precedence so a future
472
+ # refactor can't accidentally reorder the resolution. If the
473
+ # AGENT row's pair were ever shadowed by a USER row's pair, the
474
+ # dominant-agent invariant on handoff sessions breaks.
475
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
476
+ participants = [
477
+ {
478
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
479
+ "ssot__AiAgentApiName__c": "AAgent", # lex-first across both rows
480
+ "ssot__AiAgentVersionApiName__c": "v1",
481
+ },
482
+ {
483
+ "ssot__AiAgentSessionParticipantRole__c": "AGENT",
484
+ "ssot__AiAgentApiName__c": "ZAgent", # lex-LAST overall
485
+ "ssot__AiAgentVersionApiName__c": "v9",
486
+ },
487
+ ]
488
+
489
+ _, agent, ver = fetch_dc._resolve_identity(
490
+ sessions, participants, _ORG_ALIAS,
491
+ )
492
+ # AGENT-row precedence: ZAgent/v9 wins, NOT AAgent/v1.
493
+ self.assertEqual(agent, "ZAgent")
494
+ self.assertEqual(ver, "v9")
495
+
496
+ def test_cross_role_picks_lex_first_when_multiple_valid_pairs(self):
497
+ # Handoff with two valid (api_name, version) pairs across USER
498
+ # rows. The strict-path dominant-agent rule applies: lex-first
499
+ # wins. This keeps the cross-role harvest aligned with the
500
+ # AGENT-only path's selection policy.
501
+ sessions = [{"ssot__InternalOrganizationId__c": _FULL_ORG_ID_18}]
502
+ participants = [
503
+ {
504
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
505
+ "ssot__AiAgentApiName__c": "ZAgent",
506
+ "ssot__AiAgentVersionApiName__c": "v9",
507
+ },
508
+ {
509
+ "ssot__AiAgentSessionParticipantRole__c": "USER",
510
+ "ssot__AiAgentApiName__c": "AAgent",
511
+ "ssot__AiAgentVersionApiName__c": "v3",
512
+ },
513
+ {
514
+ "ssot__AiAgentSessionParticipantRole__c": "AGENT",
515
+ "ssot__AiAgentApiName__c": "NOT_SET",
516
+ "ssot__AiAgentVersionApiName__c": "NOT_SET",
517
+ },
518
+ ]
519
+
520
+ _, agent, ver = fetch_dc._resolve_identity(
521
+ sessions, participants, _ORG_ALIAS,
522
+ )
523
+ self.assertEqual(agent, "AAgent")
524
+ self.assertEqual(ver, "v3")
525
+
526
+
527
+ if __name__ == "__main__":
528
+ unittest.main()