@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,651 @@
1
+ """P2.3-3: end-to-end fixture integration tests.
2
+
3
+ Drives `main.main(argv)` against synthetic fixtures — no real org, no
4
+ sf CLI spawn, no HTTP. Every REST/sf boundary is mocked at the
5
+ `main.fetch_*` / `main.run_sf` / `main.probe_channels` surface; all
6
+ layers below (join, parse, render, finalize) run as production code.
7
+
8
+ Tests (one per pipeline path):
9
+ 1. classic_react_end_to_end — STATUS=OK, tree + summary + architecture.md
10
+ 2. nga_orchestration_end_to_end — NGA reverse-lookup + `par/and` state diagram
11
+ 3. cache_hit_end_to_end — poisoned Wave A — must never be called
12
+ 4. probe_failed_end_to_end — STATUS=RETRIEVE_FAILED + schema-drift detail
13
+ 5. force_refresh_end_to_end — pre-populated fresh cache ignored
14
+ 6. render_failure_end_to_end — STATUS=PARTIAL_OK + RENDER_FAILED=true
15
+
16
+ Each test carves its own tempdir for work/cache/data so no cross-test
17
+ state leaks. Assertions focus on the observable surface (RESULT block
18
+ + on-disk artifacts) rather than on implementation details of
19
+ intermediate steps — the same tests survive a refactor of main.py's
20
+ internal phase ordering.
21
+ """
22
+ from __future__ import annotations
23
+
24
+ import json
25
+ import os
26
+ import subprocess
27
+ import sys
28
+ import tempfile
29
+ import unittest
30
+ from pathlib import Path
31
+ from unittest import mock
32
+
33
+ from . import _bootstrap # noqa: F401
34
+
35
+ import config # type: ignore
36
+ import soql_loader # type: ignore
37
+ import main # type: ignore
38
+ from tests.fixtures import genai_payloads as fx # type: ignore
39
+
40
+ # SKILL_ROOT is now file-relative in config.py, so config.SOQL_DIR auto-
41
+ # resolves to the repo's assets/soql/ under test. soql_loader still
42
+ # captures SOQL_DIR via `from config import SOQL_DIR` at module top, so
43
+ # we mirror its binding here defensively.
44
+ _REPO_SOQL_DIR = Path(__file__).resolve().parent.parent.parent / "assets" / "soql"
45
+ soql_loader.SOQL_DIR = _REPO_SOQL_DIR
46
+
47
+ # emit_result.py lives under tools/; tests invoke it via subprocess so the
48
+ # tool's RESULT-formatting logic is exercised under the same contract the
49
+ # SKILL.md Bash wrapper uses.
50
+ _TOOLS_DIR = Path(__file__).resolve().parent.parent.parent / "tools"
51
+
52
+
53
+ # ---------------------------------------------------------------------------
54
+ # Shared helpers (mirrored from test_main_pipeline — intentionally copied
55
+ # rather than imported, so a refactor of that file doesn't silently change
56
+ # the end-to-end test behavior.)
57
+ # ---------------------------------------------------------------------------
58
+
59
+
60
+ def _args(work_dir: Path, **overrides) -> list[str]:
61
+ base = [
62
+ "--org-alias", "test-org",
63
+ "--agent", overrides.pop("agent", "MyAgent"),
64
+ "--work-dir", str(work_dir),
65
+ "--parallelism", "2",
66
+ ]
67
+ for k, v in overrides.items():
68
+ flag = "--" + k.replace("_", "-")
69
+ if isinstance(v, bool):
70
+ if v:
71
+ base.append(flag)
72
+ else:
73
+ base.extend([flag, str(v)])
74
+ return base
75
+
76
+
77
+ def _mock_auth_probe(probe_result=None):
78
+ probe_result = probe_result or fx.probe_ok_payload()
79
+ org_display_payload = {
80
+ "status": 0,
81
+ "result": {
82
+ "instanceUrl": "https://example.my.salesforce.com",
83
+ "accessToken": "00Dxx0000000000!AQ_fake_token_value",
84
+ "id": "00Dxx0000000000AAA",
85
+ "apiVersion": "60.0",
86
+ },
87
+ }
88
+ return [
89
+ mock.patch.object(main, "run_sf", return_value=org_display_payload),
90
+ mock.patch.object(main, "probe_channels", return_value=probe_result),
91
+ ]
92
+
93
+
94
+ def _mock_bot_resolution(agent_api_name="MyAgent", bot_def=None,
95
+ versions=("v5",), active="v5"):
96
+ bot_def = bot_def or fx.BOT_DEFINITION_DETAIL_CLASSIC
97
+ return [
98
+ mock.patch.object(
99
+ main, "fetch_bot_versions",
100
+ return_value=fx.make_bot_versions(agent_api_name, versions, active),
101
+ ),
102
+ mock.patch.object(main, "fetch_bot_definition_details", return_value=bot_def),
103
+ ]
104
+
105
+
106
+ def _mock_wave_a_classic():
107
+ return [
108
+ mock.patch.object(main, "fetch_planner_definition", return_value=fx.CLASSIC_PLANNER),
109
+ mock.patch.object(main, "fetch_plugins_by_planner", return_value=fx.CLASSIC_PLUGINS),
110
+ mock.patch.object(main, "fetch_planner_bundle_functions", return_value=fx.CLASSIC_BUNDLE_FN_JOIN),
111
+ mock.patch.object(main, "fetch_functions_by_plugins", return_value=fx.CLASSIC_FUNCTIONS),
112
+ mock.patch.object(main, "fetch_plugin_instructions", return_value=fx.CLASSIC_INSTRUCTIONS),
113
+ mock.patch.object(main, "fetch_plugin_functions", return_value=fx.CLASSIC_PLUGIN_FUNCTIONS),
114
+ mock.patch.object(main, "fetch_planner_attrs", return_value=fx.CLASSIC_ATTRS),
115
+ ]
116
+
117
+
118
+ def _mock_wave_b_classic():
119
+ return [
120
+ mock.patch.object(main, "fetch_apex_bodies_by_names", return_value=fx.CLASSIC_APEX_ROWS),
121
+ mock.patch.object(main, "fetch_apex_bodies_by_ids", return_value=[]),
122
+ mock.patch.object(main, "fetch_flow_definition_ids_by_names", return_value=fx.CLASSIC_FLOW_DEFS),
123
+ mock.patch.object(main, "fetch_flow_definition_by_ids", return_value=[]),
124
+ mock.patch.object(
125
+ main, "fetch_flow_metadata",
126
+ side_effect=lambda vid, *a, **kw: fx.CLASSIC_FLOW_METADATA.get(vid),
127
+ ),
128
+ ]
129
+
130
+
131
+ def _mock_wave_a_nga():
132
+ return [
133
+ mock.patch.object(main, "fetch_planner_definition", return_value=fx.NGA_PLANNER),
134
+ mock.patch.object(main, "fetch_plugins_by_planner", return_value=fx.NGA_PLUGINS),
135
+ mock.patch.object(main, "fetch_planner_bundle_functions", return_value=[]),
136
+ mock.patch.object(main, "fetch_functions_by_plugins", return_value=fx.NGA_FUNCTIONS),
137
+ mock.patch.object(main, "fetch_plugin_instructions", return_value=[]),
138
+ mock.patch.object(main, "fetch_plugin_functions", return_value=fx.NGA_PLUGIN_FUNCTIONS),
139
+ mock.patch.object(main, "fetch_planner_attrs", return_value=[]),
140
+ ]
141
+
142
+
143
+ def _mock_wave_b_nga():
144
+ return [
145
+ mock.patch.object(main, "fetch_apex_bodies_by_names", return_value=[]),
146
+ mock.patch.object(main, "fetch_apex_bodies_by_ids", return_value=fx.NGA_APEX_BY_ID),
147
+ mock.patch.object(main, "fetch_flow_definition_ids_by_names", return_value=[]),
148
+ mock.patch.object(main, "fetch_flow_definition_by_ids", return_value=fx.NGA_FLOW_DEF_BY_ID),
149
+ mock.patch.object(main, "fetch_flow_metadata", return_value={
150
+ "Id": "301VF999NGAVER", "FullName": "NGAResolvedFlow-1", "Metadata": {},
151
+ }),
152
+ ]
153
+
154
+
155
+ def _apply(patches):
156
+ for p in patches:
157
+ p.start()
158
+
159
+
160
+ def _stop(patches):
161
+ for p in patches:
162
+ p.stop()
163
+
164
+
165
+ def _run_emit_result(work_dir: Path) -> subprocess.CompletedProcess:
166
+ """Drive emit_result.py against the ctx main.py wrote.
167
+
168
+ Exercises the same SKILL.md Bash-wrapper contract: main.py writes
169
+ .emit_ctx.json, emit_result.py reads + renders. Subprocess call so
170
+ the tool runs under a clean env (no leaked test-process state).
171
+ """
172
+ env = {**os.environ, "WORK_DIR": str(work_dir)}
173
+ return subprocess.run(
174
+ [sys.executable, str(_TOOLS_DIR / "emit_result.py")],
175
+ env=env, capture_output=True, text=True, timeout=30,
176
+ )
177
+
178
+
179
+ def _parse_result_block(stdout: str) -> dict:
180
+ """Pull KV pairs out of the `=== RESULT ===` block."""
181
+ lines = stdout.splitlines()
182
+ out: dict[str, str] = {}
183
+ in_block = False
184
+ for line in lines:
185
+ if line.strip() == "=== RESULT ===":
186
+ in_block = True
187
+ continue
188
+ if in_block and "=" in line:
189
+ k, _, v = line.partition("=")
190
+ out[k] = v
191
+ return out
192
+
193
+
194
+ # ---------------------------------------------------------------------------
195
+ # Test 1 — classic ReAct end-to-end
196
+ # ---------------------------------------------------------------------------
197
+
198
+
199
+ class ClassicReactEndToEndTests(unittest.TestCase):
200
+ """P2.3-3: classic ReAct pipeline on MyAgent-v5-shaped fixtures.
201
+
202
+ Asserts observable surface only: on-disk artifacts + RESULT block
203
+ KV pairs. Internal phase ordering can change without breaking this
204
+ test.
205
+ """
206
+
207
+ def test_classic_react_end_to_end_produces_full_artifact_set(self):
208
+ with tempfile.TemporaryDirectory() as tmp:
209
+ work_dir = Path(tmp) / "work"
210
+ data_root = Path(tmp) / "data"
211
+ cache_root = Path(tmp) / "cache"
212
+
213
+ patches = [
214
+ *_mock_auth_probe(),
215
+ *_mock_bot_resolution(),
216
+ *_mock_wave_a_classic(),
217
+ *_mock_wave_b_classic(),
218
+ mock.patch.object(
219
+ main, "build_agent_data_dir",
220
+ side_effect=lambda o, a, v: data_root / o / f"{a}__{v}",
221
+ ),
222
+ mock.patch.object(
223
+ main, "build_agent_cache_dir",
224
+ side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}",
225
+ ),
226
+ ]
227
+ _apply(patches)
228
+ try:
229
+ rc = main.main(_args(work_dir))
230
+ finally:
231
+ _stop(patches)
232
+
233
+ self.assertEqual(rc, 0)
234
+
235
+ # --- on-disk artifacts ---
236
+ data_dir = data_root / "00Dxx0000000000" / "MyAgent__v5"
237
+ tree_file = data_dir / "MyAgent_v5_metadata_tree.json"
238
+ arch_file = data_dir / "MyAgent_v5_architecture.md"
239
+
240
+ self.assertTrue(tree_file.is_file(), "metadata_tree.json missing")
241
+ self.assertTrue(arch_file.is_file(), "architecture.md missing")
242
+ # summary.md dropped from the output contract —
243
+ # confirm it is NOT written.
244
+ self.assertFalse(
245
+ (data_dir / "MyAgent_v5_metadata_tree.summary.md").exists(),
246
+ "summary.md should have been dropped from the output contract",
247
+ )
248
+ # rendered architecture filename embeds the agent
249
+ # api name (new convention — proves the rename is wired).
250
+ self.assertTrue(
251
+ arch_file.name.startswith("MyAgent"),
252
+ f"architecture filename should start with agent api name, got {arch_file.name}",
253
+ )
254
+
255
+ tree = json.loads(tree_file.read_text())
256
+ self.assertGreater(tree.get("node_count", 0), 0)
257
+ self.assertEqual(tree["agent"]["generation"], "classic")
258
+
259
+ # --- emit_result RESULT block ---
260
+ r = _run_emit_result(work_dir)
261
+ self.assertEqual(r.returncode, 0, msg=r.stderr)
262
+ block = _parse_result_block(r.stdout)
263
+ self.assertIn(block["STATUS"], ("OK", "PARTIAL_OK"))
264
+ self.assertEqual(block["OUTPUT_ARCHITECTURE_PATH"], str(arch_file))
265
+ self.assertEqual(block["RENDER_FAILED"], "false")
266
+ self.assertGreater(int(block["NODE_COUNT"]), 0)
267
+
268
+
269
+ # ---------------------------------------------------------------------------
270
+ # Test 2 — NGA end-to-end
271
+ # ---------------------------------------------------------------------------
272
+
273
+
274
+ class NgaEndToEndTests(unittest.TestCase):
275
+ """P2.3-3: NGA ConcurrentMultiAgentOrchestration end-to-end.
276
+
277
+ Exercises the NGA reverse-lookup path (InvocationTarget is a 15/18-
278
+ char Id, not a DeveloperName) and verifies the architecture.md
279
+ carries NGA-specific state-diagram content (`par/and dispatch`).
280
+ """
281
+
282
+ def test_nga_end_to_end_produces_par_state_diagram(self):
283
+ with tempfile.TemporaryDirectory() as tmp:
284
+ work_dir = Path(tmp) / "work"
285
+ data_root = Path(tmp) / "data"
286
+ cache_root = Path(tmp) / "cache"
287
+
288
+ patches = [
289
+ *_mock_auth_probe(),
290
+ *_mock_bot_resolution(
291
+ agent_api_name="MyAgent2",
292
+ bot_def=fx.BOT_DEFINITION_DETAIL_NGA,
293
+ ),
294
+ *_mock_wave_a_nga(),
295
+ *_mock_wave_b_nga(),
296
+ mock.patch.object(
297
+ main, "build_agent_data_dir",
298
+ side_effect=lambda o, a, v: data_root / o / f"{a}__{v}",
299
+ ),
300
+ mock.patch.object(
301
+ main, "build_agent_cache_dir",
302
+ side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}",
303
+ ),
304
+ ]
305
+ _apply(patches)
306
+ try:
307
+ rc = main.main(_args(work_dir, agent="MyAgent2"))
308
+ finally:
309
+ _stop(patches)
310
+
311
+ self.assertEqual(rc, 0)
312
+
313
+ data_dir = data_root / "00Dxx0000000000" / "MyAgent2__v5"
314
+ tree_file = data_dir / "MyAgent2_v5_metadata_tree.json"
315
+ arch_file = data_dir / "MyAgent2_v5_architecture.md"
316
+
317
+ self.assertTrue(tree_file.is_file())
318
+ self.assertTrue(arch_file.is_file())
319
+
320
+ tree = json.loads(tree_file.read_text())
321
+ self.assertEqual(tree["agent"]["generation"], "nga")
322
+ # NGA reverse-lookup worked — the tree built a TOPIC node for
323
+ # NGATopic1 with 2 GEN_AI_FUNCTION children (Flow + Apex).
324
+ counts = tree["_kind_counts"]
325
+ self.assertEqual(counts.get("TOPIC"), 1)
326
+ self.assertEqual(counts.get("GEN_AI_FUNCTION"), 2)
327
+
328
+ # Architecture.md renders — surface the NGA tell via the
329
+ # Data flow / Topic anatomy sections. The Planner state
330
+ # machine section (which previously carried `par/and
331
+ # dispatch`) was retired from the default pipeline in
332
+ # 2026-05; the NGA-specific state-diagram output is now
333
+ # exercised directly in RenderNgaTests.
334
+ arch_text = arch_file.read_text()
335
+ self.assertIn("NGATopic1", arch_text)
336
+ self.assertIn("NGAFlowAction", arch_text)
337
+ self.assertIn("NGAApexAction", arch_text)
338
+ # Retired section must not appear.
339
+ self.assertNotIn("Planner state machine", arch_text)
340
+
341
+ r = _run_emit_result(work_dir)
342
+ block = _parse_result_block(r.stdout)
343
+ self.assertIn(block["STATUS"], ("OK", "PARTIAL_OK"))
344
+ self.assertEqual(block["AGENT_GENERATION"], "nga")
345
+
346
+
347
+ # ---------------------------------------------------------------------------
348
+ # Test 3 — cache hit end-to-end
349
+ # ---------------------------------------------------------------------------
350
+
351
+
352
+ class CacheHitEndToEndTests(unittest.TestCase):
353
+ """P2.3-3: pre-populated fresh cache short-circuits the pipeline.
354
+
355
+ Wave A + Wave B fetchers are poisoned with AssertionError — the
356
+ test fails loudly if main.py attempts any fetch on a cache hit.
357
+ """
358
+
359
+ def test_cache_hit_end_to_end_skips_all_wave_calls(self):
360
+ import datetime as dt
361
+
362
+ with tempfile.TemporaryDirectory() as tmp:
363
+ work_dir = Path(tmp) / "work"
364
+ data_root = Path(tmp) / "data"
365
+ cache_root = Path(tmp) / "cache"
366
+ data_dir = data_root / "00Dxx0000000000" / "MyAgent__v5"
367
+ cache_dir = cache_root / "00Dxx0000000000" / "MyAgent__v5"
368
+ data_dir.mkdir(parents=True)
369
+ cache_dir.mkdir(parents=True)
370
+
371
+ tree_base = "MyAgent_v5_metadata_tree"
372
+ # Minimal tree + architecture.md so the cache-hit emit ctx
373
+ # surfaces an OUTPUT_ARCHITECTURE_PATH.
374
+ # architecture filename is self-identifying.
375
+ (data_dir / f"{tree_base}.json").write_text(json.dumps({
376
+ "_schema_version": "3.0",
377
+ "agent": {"generation": "classic"},
378
+ "root": {"children": []},
379
+ "node_count": 12, "depth": 3,
380
+ "_kind_counts": {}, "_unresolved": [],
381
+ }))
382
+ (data_dir / "MyAgent_v5_architecture.md").write_text("# cached arch\n")
383
+
384
+ from config import SCHEMA_VERSION
385
+ manifest = {
386
+ "built_at_utc": dt.datetime.now(dt.timezone.utc).isoformat().replace("+00:00", "Z"),
387
+ "schema_version": SCHEMA_VERSION,
388
+ "agent": {
389
+ "version": "v5", "bot_id": "0Xa000000000ABC",
390
+ "generation": "classic", "_version_auto_picked": True,
391
+ },
392
+ "node_count": 12, "depth": 3, "kind_counts": {},
393
+ "ttl_days": 7,
394
+ "data_path": str(data_dir / f"{tree_base}.json"),
395
+ "partial": False, "unresolved_count": 0,
396
+ }
397
+ (cache_dir / "manifest.json").write_text(json.dumps(manifest))
398
+
399
+ def _poison(*_a, **_kw):
400
+ raise AssertionError("cache hit MUST NOT invoke any Wave fetcher")
401
+
402
+ poisoned_fetchers = [
403
+ mock.patch.object(main, name, side_effect=_poison)
404
+ for name in (
405
+ "fetch_planner_definition",
406
+ "fetch_plugins_by_planner",
407
+ "fetch_planner_bundle_functions",
408
+ "fetch_functions_by_plugins",
409
+ "fetch_plugin_instructions",
410
+ "fetch_plugin_functions",
411
+ "fetch_planner_attrs",
412
+ "fetch_apex_bodies_by_names",
413
+ "fetch_apex_bodies_by_ids",
414
+ "fetch_flow_definition_ids_by_names",
415
+ "fetch_flow_definition_by_ids",
416
+ "fetch_flow_metadata",
417
+ )
418
+ ]
419
+
420
+ patches = [
421
+ *_mock_auth_probe(),
422
+ *_mock_bot_resolution(),
423
+ *poisoned_fetchers,
424
+ mock.patch.object(
425
+ main, "build_agent_data_dir",
426
+ side_effect=lambda o, a, v: data_dir,
427
+ ),
428
+ mock.patch.object(
429
+ main, "build_agent_cache_dir",
430
+ side_effect=lambda o, a, v: cache_dir,
431
+ ),
432
+ ]
433
+ _apply(patches)
434
+ try:
435
+ rc = main.main(_args(work_dir))
436
+ finally:
437
+ _stop(patches)
438
+
439
+ self.assertEqual(rc, 0)
440
+
441
+ r = _run_emit_result(work_dir)
442
+ block = _parse_result_block(r.stdout)
443
+ self.assertEqual(block["STATUS"], "OK")
444
+ self.assertEqual(block["CACHE_HIT"], "true")
445
+ self.assertEqual(int(block["NODE_COUNT"]), 12)
446
+ # Cached architecture.md surfaces as the OUTPUT path.
447
+ # filename embeds agent api name + version.
448
+ self.assertTrue(block["OUTPUT_ARCHITECTURE_PATH"].endswith("MyAgent_v5_architecture.md"))
449
+ self.assertEqual(block["RENDER_FAILED"], "false")
450
+
451
+
452
+ # ---------------------------------------------------------------------------
453
+ # Test 4 — probe-failed end-to-end
454
+ # ---------------------------------------------------------------------------
455
+
456
+
457
+ class ProbeFailedEndToEndTests(unittest.TestCase):
458
+ """P2.3-3: channel probe returns PROBE_FAILED -> RETRIEVE_FAILED.
459
+
460
+ Verifies Batch 2.1 remediation: schema-drift manifests as
461
+ STATUS=RETRIEVE_FAILED with ERROR_DETAIL containing `schema-drift`
462
+ rather than a fabricated SCHEMA_DRIFT enum value. The emit_result
463
+ STATUS enum doesn't include SCHEMA_DRIFT, so mapping to
464
+ RETRIEVE_FAILED preserves the existing contract while surfacing
465
+ the cause in ERROR_DETAIL.
466
+ """
467
+
468
+ def test_probe_failed_end_to_end_emits_retrieve_failed(self):
469
+ with tempfile.TemporaryDirectory() as tmp:
470
+ work_dir = Path(tmp) / "work"
471
+
472
+ patches = _mock_auth_probe(
473
+ probe_result=fx.probe_failed_payload(
474
+ sobject="GenAiPlannerDefinition",
475
+ missing=["PlannerType", "DeveloperName"],
476
+ ),
477
+ )
478
+ _apply(patches)
479
+ try:
480
+ rc = main.main(_args(work_dir))
481
+ finally:
482
+ _stop(patches)
483
+
484
+ # Pipeline returns nonzero on terminal failure — matches the
485
+ # SKILL.md Bash wrapper's set +e / capture _rc / exit _rc
486
+ # contract.
487
+ self.assertEqual(rc, 1)
488
+
489
+ r = _run_emit_result(work_dir)
490
+ self.assertEqual(r.returncode, 0, msg=r.stderr)
491
+ block = _parse_result_block(r.stdout)
492
+ self.assertEqual(block["STATUS"], "RETRIEVE_FAILED")
493
+ self.assertIn("schema-drift", block["ERROR_DETAIL"])
494
+ # The specific missing fields surface in the detail string
495
+ # (first 3 only per main.py's truncation).
496
+ self.assertIn("PlannerType", block["ERROR_DETAIL"])
497
+
498
+
499
+ # ---------------------------------------------------------------------------
500
+ # Test 5 — --force end-to-end
501
+ # ---------------------------------------------------------------------------
502
+
503
+
504
+ class ForceRefreshEndToEndTests(unittest.TestCase):
505
+ """P2.3-3: fresh cache + --force -> full pipeline runs, cache supersedes.
506
+
507
+ Asserts:
508
+ * Wave A fetcher was invoked exactly once (cache was NOT used).
509
+ * CACHE_HIT=false in the RESULT block.
510
+ * Post-run manifest differs from pre-run manifest (node_count
511
+ reflects the live-fetched tree, not the 999-node placeholder).
512
+ """
513
+
514
+ def test_force_refresh_bypasses_fresh_cache(self):
515
+ import datetime as dt
516
+
517
+ with tempfile.TemporaryDirectory() as tmp:
518
+ work_dir = Path(tmp) / "work"
519
+ data_root = Path(tmp) / "data"
520
+ cache_root = Path(tmp) / "cache"
521
+ data_dir = data_root / "00Dxx0000000000" / "MyAgent__v5"
522
+ cache_dir = cache_root / "00Dxx0000000000" / "MyAgent__v5"
523
+ data_dir.mkdir(parents=True)
524
+ cache_dir.mkdir(parents=True)
525
+ (data_dir / "MyAgent_v5_metadata_tree.json").write_text("{}")
526
+
527
+ from config import SCHEMA_VERSION
528
+ stale_manifest = {
529
+ "built_at_utc": dt.datetime.now(dt.timezone.utc).isoformat().replace("+00:00", "Z"),
530
+ "schema_version": SCHEMA_VERSION,
531
+ "agent": {"version": "v5"},
532
+ # Bogus node count to detect whether the cache path or
533
+ # the live-fetched tree won.
534
+ "node_count": 999, "depth": 99, "kind_counts": {},
535
+ "ttl_days": 7,
536
+ "data_path": str(data_dir / "MyAgent_v5_metadata_tree.json"),
537
+ "partial": False, "unresolved_count": 0,
538
+ }
539
+ (cache_dir / "manifest.json").write_text(json.dumps(stale_manifest))
540
+
541
+ patches = [
542
+ *_mock_auth_probe(),
543
+ *_mock_bot_resolution(),
544
+ *_mock_wave_a_classic(),
545
+ *_mock_wave_b_classic(),
546
+ mock.patch.object(
547
+ main, "build_agent_data_dir",
548
+ side_effect=lambda o, a, v: data_dir,
549
+ ),
550
+ mock.patch.object(
551
+ main, "build_agent_cache_dir",
552
+ side_effect=lambda o, a, v: cache_dir,
553
+ ),
554
+ ]
555
+ _apply(patches)
556
+ try:
557
+ rc = main.main(_args(work_dir, force=True))
558
+ planner_calls = main.fetch_planner_definition.call_count
559
+ finally:
560
+ _stop(patches)
561
+
562
+ self.assertEqual(rc, 0)
563
+ # Wave A actually fired — cache was NOT consulted.
564
+ self.assertEqual(planner_calls, 1)
565
+
566
+ # Manifest on disk post-run reflects the live fetch, not the
567
+ # 999-node placeholder.
568
+ post_manifest = json.loads((cache_dir / "manifest.json").read_text())
569
+ self.assertNotEqual(post_manifest.get("node_count"), 999)
570
+ self.assertGreater(post_manifest.get("node_count", 0), 0)
571
+
572
+ r = _run_emit_result(work_dir)
573
+ block = _parse_result_block(r.stdout)
574
+ self.assertIn(block["STATUS"], ("OK", "PARTIAL_OK"))
575
+ self.assertEqual(block["CACHE_HIT"], "false")
576
+
577
+
578
+ # ---------------------------------------------------------------------------
579
+ # Test 6 — render failure end-to-end
580
+ # ---------------------------------------------------------------------------
581
+
582
+
583
+ class RenderFailureEndToEndTests(unittest.TestCase):
584
+ """P2.3-3: renderer raises -> tree OK, architecture.md.error sidecar,
585
+ STATUS=PARTIAL_OK, RENDER_FAILED=true in RESULT block.
586
+
587
+ contract. The pipeline does NOT abort on render failure —
588
+ the tree JSON is the authoritative output; architecture.md is
589
+ derived. This test asserts the signalling: downstream consumers can
590
+ distinguish "headline diagram missing" from "pipeline succeeded
591
+ cleanly" via RENDER_FAILED + the sidecar.
592
+ """
593
+
594
+ def test_render_failure_end_to_end_surfaces_partial_ok(self):
595
+ import render_architecture # type: ignore
596
+
597
+ with tempfile.TemporaryDirectory() as tmp:
598
+ work_dir = Path(tmp) / "work"
599
+ data_root = Path(tmp) / "data"
600
+ cache_root = Path(tmp) / "cache"
601
+
602
+ def _boom(*_a, **_kw):
603
+ raise RuntimeError("render exploded for end-to-end test")
604
+
605
+ patches = [
606
+ *_mock_auth_probe(),
607
+ *_mock_bot_resolution(),
608
+ *_mock_wave_a_classic(),
609
+ *_mock_wave_b_classic(),
610
+ mock.patch.object(
611
+ main, "build_agent_data_dir",
612
+ side_effect=lambda o, a, v: data_root / o / f"{a}__{v}",
613
+ ),
614
+ mock.patch.object(
615
+ main, "build_agent_cache_dir",
616
+ side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}",
617
+ ),
618
+ mock.patch.object(render_architecture, "render", side_effect=_boom),
619
+ ]
620
+ _apply(patches)
621
+ try:
622
+ rc = main.main(_args(work_dir))
623
+ finally:
624
+ _stop(patches)
625
+
626
+ self.assertEqual(rc, 0)
627
+
628
+ data_dir = data_root / "00Dxx0000000000" / "MyAgent__v5"
629
+ # Sidecar landed, architecture.md did NOT.
630
+ # filenames are self-identifying.
631
+ self.assertTrue((data_dir / "MyAgent_v5_architecture.md.error").is_file())
632
+ self.assertFalse((data_dir / "MyAgent_v5_architecture.md").is_file())
633
+ # Tree JSON DID land — the render failure is isolated to the
634
+ # derived artifact.
635
+ self.assertTrue(
636
+ (data_dir / "MyAgent_v5_metadata_tree.json").is_file()
637
+ )
638
+
639
+ r = _run_emit_result(work_dir)
640
+ block = _parse_result_block(r.stdout)
641
+ # emit_result auto-promotes OK -> PARTIAL_OK on render failure
642
+ # (see build_block .2-R1).
643
+ self.assertEqual(block["STATUS"], "PARTIAL_OK")
644
+ self.assertEqual(block["RENDER_FAILED"], "true")
645
+ self.assertEqual(block["OUTPUT_ARCHITECTURE_PATH"], "")
646
+ self.assertIn("RENDER_ERROR_DETAIL", block)
647
+ self.assertTrue(block["RENDER_ERROR_DETAIL"]) # non-empty
648
+
649
+
650
+ if __name__ == "__main__":
651
+ unittest.main()