@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,256 @@
1
+ """Additional ``render_dc`` tests targeting branches not covered by
2
+ ``test_render_dc_integration.py``:
3
+
4
+ - ``main_for_session`` reads tree + manifest from disk; emits markdown
5
+ - ``main`` argparse → main_for_session
6
+ - ``_parse_finish_reason`` HTML-escaped JSON parsing
7
+ - ``_decoded_line`` tool-call JSON detection
8
+ - mermaid sequence diagram (requires ≥2 ACTION_STEPs OR an error_text)
9
+ - mermaid topic flowchart (requires repeating topics across turns)
10
+ - schema-version refusal on unsupported _schema_version
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import unittest
16
+ from pathlib import Path
17
+ from tempfile import TemporaryDirectory
18
+ from unittest import mock
19
+
20
+ from . import _bootstrap # noqa: F401 — sys.path setup
21
+
22
+ import assemble_dc # type: ignore
23
+ import render_dc # type: ignore
24
+ from config import paths # type: ignore
25
+ from .fixtures.synthetic_session import IDS, write_to_disk # type: ignore
26
+
27
+
28
+ # -----------------------------------------------------------------------------
29
+ # main_for_session — disk-backed entry point
30
+ # -----------------------------------------------------------------------------
31
+
32
+
33
+ class MainForSessionTests(unittest.TestCase):
34
+
35
+ def test_reads_tree_writes_summary_md(self):
36
+ with TemporaryDirectory() as t:
37
+ tmp = Path(t)
38
+ sdir = write_to_disk(tmp)
39
+ with mock.patch.object(paths, "DATA_ROOT", tmp):
40
+ tree, _ = assemble_dc.assemble(IDS.SID)
41
+ (sdir / "dc._session_tree.json").write_text(
42
+ json.dumps(tree, default=str)
43
+ )
44
+ rc = render_dc.main_for_session(IDS.SID)
45
+ self.assertEqual(rc, 0)
46
+ summary_path = sdir / "dc._session_summary.md"
47
+ self.assertTrue(summary_path.is_file())
48
+ self.assertGreater(len(summary_path.read_text()), 1000)
49
+
50
+ def test_raises_when_tree_missing(self):
51
+ with TemporaryDirectory() as t:
52
+ tmp = Path(t)
53
+ write_to_disk(tmp) # creates session dir but not tree
54
+ with mock.patch.object(paths, "DATA_ROOT", tmp):
55
+ with self.assertRaises(SystemExit) as ctx:
56
+ render_dc.main_for_session(IDS.SID)
57
+ self.assertIn("tree not found", str(ctx.exception))
58
+
59
+ def test_tolerates_missing_manifest_with_warning(self):
60
+ with TemporaryDirectory() as t:
61
+ tmp = Path(t)
62
+ sdir = write_to_disk(tmp)
63
+ with mock.patch.object(paths, "DATA_ROOT", tmp):
64
+ tree, _ = assemble_dc.assemble(IDS.SID)
65
+ (sdir / "dc._session_tree.json").write_text(
66
+ json.dumps(tree, default=str)
67
+ )
68
+ # Wipe the manifest. main_for_session should still succeed
69
+ # (manifest is optional; missing → no manifest-driven sections).
70
+ (sdir / "dc._session_manifest.json").unlink()
71
+ rc = render_dc.main_for_session(IDS.SID)
72
+ self.assertEqual(rc, 0)
73
+
74
+
75
+ # -----------------------------------------------------------------------------
76
+ # main — argparse + resolve
77
+ # -----------------------------------------------------------------------------
78
+
79
+
80
+ class MainTests(unittest.TestCase):
81
+
82
+ def test_main_invokes_main_for_session_with_resolved_sid(self):
83
+ with TemporaryDirectory() as t:
84
+ tmp = Path(t)
85
+ sdir = write_to_disk(tmp)
86
+ with mock.patch.object(paths, "DATA_ROOT", tmp):
87
+ tree, _ = assemble_dc.assemble(IDS.SID)
88
+ (sdir / "dc._session_tree.json").write_text(
89
+ json.dumps(tree, default=str)
90
+ )
91
+ with mock.patch.object(
92
+ render_dc.sys, "argv",
93
+ ["render_dc.py", "--session", IDS.SID],
94
+ ):
95
+ rc = render_dc.main()
96
+ self.assertEqual(rc, 0)
97
+
98
+
99
+ # -----------------------------------------------------------------------------
100
+ # _parse_finish_reason — HTML-escaped JSON
101
+ # -----------------------------------------------------------------------------
102
+
103
+
104
+ class ParseFinishReasonTests(unittest.TestCase):
105
+
106
+ def test_extracts_stop_from_double_escaped_json(self):
107
+ # Real wire format: `{"finish_reason":"\"stop\""}`
108
+ params = '{"finish_reason":"\\"stop\\""}'
109
+ self.assertEqual(render_dc._parse_finish_reason(params), "stop")
110
+
111
+ def test_returns_none_for_empty(self):
112
+ self.assertIsNone(render_dc._parse_finish_reason(None))
113
+ self.assertIsNone(render_dc._parse_finish_reason(""))
114
+
115
+ def test_returns_none_for_unparseable_json(self):
116
+ self.assertIsNone(render_dc._parse_finish_reason("<<<not json>>>"))
117
+
118
+ def test_returns_none_when_finish_reason_not_string(self):
119
+ params = '{&quot;finish_reason&quot;: 42}'
120
+ self.assertIsNone(render_dc._parse_finish_reason(params))
121
+
122
+
123
+ # -----------------------------------------------------------------------------
124
+ # _decoded_line — tool-call JSON detection
125
+ # -----------------------------------------------------------------------------
126
+
127
+
128
+ class DecodedLineTests(unittest.TestCase):
129
+
130
+ def test_returns_dash_for_empty(self):
131
+ self.assertEqual(render_dc._decoded_line(None), "—")
132
+ self.assertEqual(render_dc._decoded_line(""), "—")
133
+
134
+ def test_renders_quoted_truncated_text_for_plain_string(self):
135
+ out = render_dc._decoded_line("Hello world")
136
+ self.assertEqual(out, '"Hello world"')
137
+
138
+ def test_summarizes_tool_call_json(self):
139
+ # Real wire shape: HTML-escaped JSON with toolInvocations array.
140
+ body = (
141
+ '{"toolInvocations":[{'
142
+ '"function":{"name":"search_orders",'
143
+ '"arguments":"{\\"query\\":\\"refund\\"}"}}],'
144
+ '"content":"I will search for orders."}'
145
+ )
146
+ out = render_dc._decoded_line(body)
147
+ self.assertIn("1 tool call", out)
148
+ self.assertIn("search_orders", out)
149
+ self.assertIn("query=", out)
150
+
151
+
152
+ # -----------------------------------------------------------------------------
153
+ # Multi-turn fixture for mermaid branches
154
+ # -----------------------------------------------------------------------------
155
+
156
+
157
+ def _add_extra_turn_to_tree(tree: dict) -> None:
158
+ """Mutate the assembled tree to have a 2nd TURN with a topic that
159
+ repeats — triggers both the sequence diagram and the topic flowchart.
160
+ """
161
+ # Tag the existing turn with a topic
162
+ sess = tree["session"]
163
+ for iv in sess["interactions"]:
164
+ if iv["type"] == "TURN":
165
+ iv["topic"] = "Refunds"
166
+ # Inject a 2nd action step so sequence diagram passes its
167
+ # has_error/len(actions)>=2 gate.
168
+ iv["steps"].append({
169
+ "id": "step-extra-action",
170
+ "type": "ACTION_STEP",
171
+ "name": "ExtraAction",
172
+ "start_ts": "2026-04-22T10:00:42.000Z",
173
+ "end_ts": "2026-04-22T10:00:48.000Z",
174
+ "error_text": None,
175
+ "generation": None,
176
+ "gateway_request": None,
177
+ })
178
+ break
179
+ # Append a 2nd TURN that uses the same topic — triggers flowchart edges.
180
+ sess["interactions"].append({
181
+ "id": "ixn-turn-002b",
182
+ "type": "TURN",
183
+ "topic": "Refunds",
184
+ "trace_id": "trace-2nd",
185
+ "start_ts": "2026-04-22T10:01:05.000Z",
186
+ "end_ts": "2026-04-22T10:01:25.000Z",
187
+ "steps": [
188
+ {"id": "step-2a", "type": "ACTION_STEP",
189
+ "name": "ActionA",
190
+ "start_ts": "2026-04-22T10:01:08.000Z",
191
+ "end_ts": "2026-04-22T10:01:12.000Z",
192
+ "error_text": None,
193
+ "generation": None,
194
+ "gateway_request": None},
195
+ {"id": "step-2b", "type": "ACTION_STEP",
196
+ "name": "ActionB",
197
+ "start_ts": "2026-04-22T10:01:13.000Z",
198
+ "end_ts": "2026-04-22T10:01:18.000Z",
199
+ "error_text": "Action B failed: timeout",
200
+ "generation": None,
201
+ "gateway_request": None},
202
+ ],
203
+ "messages": [
204
+ {"role": "USER", "text": "I want to escalate.", "ts": None},
205
+ {"role": "AGENT", "text": "Connecting you to a human.", "ts": None},
206
+ ],
207
+ "tag_associations": [], "telemetry_spans": [],
208
+ "timestamp_bound_gateway_calls": [],
209
+ })
210
+
211
+
212
+ class MultiTurnRenderTests(unittest.TestCase):
213
+
214
+ def _assemble_and_render(self, tree_mutator):
215
+ with TemporaryDirectory() as t:
216
+ tmp = Path(t)
217
+ sdir = write_to_disk(tmp)
218
+ with mock.patch.object(paths, "DATA_ROOT", tmp):
219
+ tree, _ = assemble_dc.assemble(IDS.SID)
220
+ tree_mutator(tree)
221
+ manifest = json.loads(
222
+ (sdir / "dc._session_manifest.json").read_text()
223
+ )
224
+ return render_dc.render(tree, manifest=manifest, session_dir=sdir)
225
+
226
+ def test_sequence_diagram_emitted_when_turn_has_two_actions(self):
227
+ md = self._assemble_and_render(_add_extra_turn_to_tree)
228
+ self.assertIn("sequenceDiagram", md)
229
+ self.assertIn("participant U as USER", md)
230
+ self.assertIn("participant P as Planner", md)
231
+
232
+ def test_topic_flowchart_emitted_when_topics_repeat(self):
233
+ md = self._assemble_and_render(_add_extra_turn_to_tree)
234
+ self.assertIn("flowchart LR", md)
235
+ self.assertIn("Refunds", md)
236
+
237
+
238
+ # -----------------------------------------------------------------------------
239
+ # Schema-version guard
240
+ # -----------------------------------------------------------------------------
241
+
242
+
243
+ class SchemaVersionGuardTests(unittest.TestCase):
244
+
245
+ def test_render_refuses_unsupported_schema_version(self):
246
+ # _assert_schema_version reads session._schema_version (per impl).
247
+ bad_tree = {
248
+ "session": {"id": IDS.SID, "interactions": [], "_schema_version": 999},
249
+ }
250
+ with self.assertRaises(SystemExit) as ctx:
251
+ render_dc.render(bad_tree)
252
+ self.assertIn("unsupported tree _schema_version", str(ctx.exception))
253
+
254
+
255
+ if __name__ == "__main__":
256
+ unittest.main()
@@ -0,0 +1,130 @@
1
+ """Tests for ``render_dc._render_gateway_direct``.
2
+
3
+ Feeds a gateway-direct tree (built by ``_assemble_gateway_direct``)
4
+ through the public ``render()`` entry point and asserts on the emitted
5
+ markdown. The intent is to pin the section contract without coupling to
6
+ exact whitespace:
7
+
8
+ - lag banner appears
9
+ - gateway chain table has the expected header
10
+ - one H4 per gateway_request_id in per-call detail
11
+ - per-call detail includes a fenced code block for the prompt
12
+ - Interaction-dependent sections are ABSENT (Hierarchical trace,
13
+ Per-turn summary, Transcript, Session counts)
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import unittest
18
+
19
+ from . import _bootstrap # noqa: F401 — sys.path setup
20
+
21
+ from assemble_dc import _assemble_gateway_direct # type: ignore
22
+ from render_dc import render # type: ignore
23
+
24
+ from .test_assemble_dc_gateway_direct import (
25
+ _SID,
26
+ _make_manifest,
27
+ _make_rows,
28
+ )
29
+
30
+
31
+ class RenderGatewayDirectTests(unittest.TestCase):
32
+
33
+ def setUp(self):
34
+ rows = _make_rows()
35
+ manifest = _make_manifest()
36
+ self.tree = _assemble_gateway_direct(_SID, rows, manifest, parse_warnings=[])
37
+ # Opt into prompt rendering — these tests exercise the *content* of
38
+ # the per-call detail block, not the default-gating contract. The
39
+ # default-gating tests live in test_render_dc_show_prompts_gating.py.
40
+ self.md = render(self.tree, manifest, show_prompts=True)
41
+
42
+ def test_starts_with_session_heading(self):
43
+ self.assertTrue(self.md.startswith(f"# Session {_SID}"))
44
+
45
+ def test_lag_banner_present(self):
46
+ self.assertIn("STDM Interaction/Step/Message DMOs have not yet "
47
+ "materialized", self.md)
48
+ self.assertIn("Re-run in 24–72h", self.md)
49
+
50
+ def test_gateway_chain_table_header(self):
51
+ self.assertIn("| Model | Provider", self.md)
52
+ self.assertIn("Prompt tok", self.md)
53
+ self.assertIn("Response ts", self.md)
54
+
55
+ def test_h4_per_gateway_call(self):
56
+ """3 fixture gateway_requests → 3 `#### LLM call N` headings."""
57
+ h4_count = self.md.count("#### LLM call ")
58
+ self.assertGreaterEqual(h4_count, 3)
59
+
60
+ def test_prompt_fenced_code_block(self):
61
+ """Per-call detail wraps the prompt in a fenced code block."""
62
+ self.assertIn("```", self.md)
63
+ self.assertIn("This is the prompt body for gw-1.", self.md)
64
+
65
+ def test_no_hierarchical_trace_section(self):
66
+ self.assertNotIn("Hierarchical trace", self.md)
67
+ self.assertNotIn("Complete hierarchical trace", self.md)
68
+
69
+ def test_no_per_turn_summary_section(self):
70
+ self.assertNotIn("Per-turn summary", self.md)
71
+
72
+ def test_no_transcript_section(self):
73
+ self.assertNotIn("## Transcript", self.md)
74
+
75
+ def test_session_identity_section_present(self):
76
+ self.assertIn("## Session identity", self.md)
77
+
78
+ def test_prompt_with_triple_backticks_uses_longer_fence(self):
79
+ """Prompts containing ``` must get a 4+-backtick fence.
80
+
81
+ LLM prompt templates commonly embed triple-backtick tool-use
82
+ examples. A hardcoded ``` fence would close early and corrupt
83
+ every section after the first such prompt.
84
+ """
85
+ rows = _make_rows()
86
+ rows["gateway_requests"][0]["prompt__c"] = (
87
+ "See this example:\n"
88
+ "```python\n"
89
+ "print('hi')\n"
90
+ "```\n"
91
+ "End of example."
92
+ )
93
+ manifest = _make_manifest()
94
+ tree = _assemble_gateway_direct(_SID, rows, manifest, parse_warnings=[])
95
+ md = render(tree, manifest, show_prompts=True)
96
+ self.assertIn("````", md) # 4-backtick fence
97
+ self.assertIn("print('hi')", md)
98
+ # The inner triple-backticks survive intact.
99
+ self.assertIn("```python", md)
100
+
101
+ def test_prompt_with_four_backticks_uses_five_backtick_fence(self):
102
+ """Fence length scales with the longest inner run of backticks."""
103
+ rows = _make_rows()
104
+ rows["gateway_requests"][0]["prompt__c"] = (
105
+ "Edge case:\n````\nnested\n````\nDone."
106
+ )
107
+ manifest = _make_manifest()
108
+ tree = _assemble_gateway_direct(_SID, rows, manifest, parse_warnings=[])
109
+ md = render(tree, manifest, show_prompts=True)
110
+ self.assertIn("`````", md) # 5-backtick fence
111
+
112
+ def test_prompt_truncation_marker_for_oversized_prompt(self):
113
+ """Display-only 64 KB cap: prompts over the limit carry a truncation marker.
114
+
115
+ Raw JSON on disk is untouched — the cap only applies to markdown.
116
+ """
117
+ rows = _make_rows()
118
+ # Inflate the first prompt to 80 KB of ASCII.
119
+ rows["gateway_requests"][0]["prompt__c"] = "x" * 80_000
120
+ manifest = _make_manifest()
121
+ tree = _assemble_gateway_direct(_SID, rows, manifest, parse_warnings=[])
122
+ md = render(tree, manifest, show_prompts=True)
123
+ self.assertIn("[truncated; full prompt in dc.gateway_requests.json]", md)
124
+ # The on-tree prompt_text is still the full 80 KB — the cap is render-only.
125
+ self.assertEqual(len(tree["session"]["gateway_chain"][0]["prompt_text"]),
126
+ 80_000)
127
+
128
+
129
+ if __name__ == "__main__":
130
+ unittest.main()
@@ -0,0 +1,291 @@
1
+ """Tests for ``render_dc`` pure-function helpers.
2
+
3
+ The renderer is large (863 stmts); covering its end-to-end markdown
4
+ output requires a complex tree fixture. These tests target the small,
5
+ pure helpers — they're cheap to test and account for ~150 stmts of the
6
+ gap.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import unittest
11
+ from datetime import datetime, timezone
12
+
13
+ from . import _bootstrap # noqa: F401 — sys.path setup
14
+
15
+ import render_dc # type: ignore
16
+
17
+
18
+ # -----------------------------------------------------------------------------
19
+ # _parse_iso
20
+ # -----------------------------------------------------------------------------
21
+
22
+
23
+ class ParseIsoTests(unittest.TestCase):
24
+
25
+ def test_returns_none_for_falsy_input(self):
26
+ self.assertIsNone(render_dc._parse_iso(None))
27
+ self.assertIsNone(render_dc._parse_iso(""))
28
+
29
+ def test_parses_z_terminated(self):
30
+ self.assertEqual(
31
+ render_dc._parse_iso("2026-04-22T10:00:00Z"),
32
+ datetime(2026, 4, 22, 10, 0, 0, tzinfo=timezone.utc),
33
+ )
34
+
35
+ def test_returns_none_for_unparseable(self):
36
+ self.assertIsNone(render_dc._parse_iso("not-a-timestamp"))
37
+
38
+
39
+ # -----------------------------------------------------------------------------
40
+ # _fmt_offset
41
+ # -----------------------------------------------------------------------------
42
+
43
+
44
+ class FmtOffsetTests(unittest.TestCase):
45
+
46
+ def test_returns_dash_when_timestamp_or_start_missing(self):
47
+ anchor = datetime(2026, 4, 22, 10, 0, 0, tzinfo=timezone.utc)
48
+ self.assertEqual(render_dc._fmt_offset(None, anchor), "—")
49
+ self.assertEqual(render_dc._fmt_offset("2026-04-22T10:00:00Z", None), "—")
50
+
51
+ def test_formats_offset_with_3_decimals(self):
52
+ anchor = datetime(2026, 4, 22, 10, 0, 0, tzinfo=timezone.utc)
53
+ out = render_dc._fmt_offset("2026-04-22T10:00:01.234Z", anchor)
54
+ self.assertEqual(out, "+1.234s")
55
+
56
+
57
+ # -----------------------------------------------------------------------------
58
+ # _fmt_duration_ms
59
+ # -----------------------------------------------------------------------------
60
+
61
+
62
+ class FmtDurationMsTests(unittest.TestCase):
63
+
64
+ def test_dash_when_either_side_missing(self):
65
+ self.assertEqual(render_dc._fmt_duration_ms(None, "2026-04-22T10:00:00Z"), "—")
66
+ self.assertEqual(render_dc._fmt_duration_ms("2026-04-22T10:00:00Z", None), "—")
67
+
68
+ def test_returns_int_ms_with_unit(self):
69
+ out = render_dc._fmt_duration_ms(
70
+ "2026-04-22T10:00:00.000Z", "2026-04-22T10:00:00.123Z",
71
+ )
72
+ self.assertEqual(out, "123ms")
73
+
74
+
75
+ # -----------------------------------------------------------------------------
76
+ # _decode + _truncate
77
+ # -----------------------------------------------------------------------------
78
+
79
+
80
+ class DecodeTruncateTests(unittest.TestCase):
81
+
82
+ def test_decode_unescapes_html_and_collapses_newlines(self):
83
+ self.assertEqual(render_dc._decode("&quot;hi&quot;\nthere"), '"hi" there')
84
+
85
+ def test_decode_returns_empty_for_falsy(self):
86
+ self.assertEqual(render_dc._decode(None), "")
87
+ self.assertEqual(render_dc._decode(""), "")
88
+
89
+ def test_truncate_pads_with_ellipsis_when_over_n(self):
90
+ long = "a" * 100
91
+ out = render_dc._truncate(long, n=10)
92
+ self.assertEqual(len(out), 10)
93
+ self.assertTrue(out.endswith("…"))
94
+
95
+ def test_truncate_returns_input_when_under_or_equal_n(self):
96
+ self.assertEqual(render_dc._truncate("short", n=10), "short")
97
+
98
+ def test_truncate_returns_dash_for_falsy(self):
99
+ self.assertEqual(render_dc._truncate(None), "—")
100
+ self.assertEqual(render_dc._truncate(""), "—")
101
+
102
+
103
+ # -----------------------------------------------------------------------------
104
+ # _short
105
+ # -----------------------------------------------------------------------------
106
+
107
+
108
+ class ShortTests(unittest.TestCase):
109
+
110
+ def test_returns_dash_for_falsy(self):
111
+ self.assertEqual(render_dc._short(None), "—")
112
+ self.assertEqual(render_dc._short(""), "—")
113
+
114
+ def test_truncates_long_uuid_with_ellipsis(self):
115
+ out = render_dc._short("019dface-0000-7000-8000-000000000001", keep=8)
116
+ self.assertEqual(out, "019dface…")
117
+
118
+ def test_returns_input_when_short(self):
119
+ self.assertEqual(render_dc._short("abc"), "abc")
120
+
121
+
122
+ # -----------------------------------------------------------------------------
123
+ # _fmt_total_duration — h / m / s rollover
124
+ # -----------------------------------------------------------------------------
125
+
126
+
127
+ class FmtTotalDurationTests(unittest.TestCase):
128
+
129
+ def test_returns_none_when_either_side_missing(self):
130
+ self.assertIsNone(render_dc._fmt_total_duration(None, "2026-04-22T10:00:00Z"))
131
+
132
+ def test_seconds_only(self):
133
+ self.assertEqual(
134
+ render_dc._fmt_total_duration(
135
+ "2026-04-22T10:00:00.000Z", "2026-04-22T10:00:42.500Z",
136
+ ),
137
+ "42.500s",
138
+ )
139
+
140
+ def test_minutes_and_seconds(self):
141
+ self.assertEqual(
142
+ render_dc._fmt_total_duration(
143
+ "2026-04-22T10:00:00Z", "2026-04-22T10:02:30Z",
144
+ ),
145
+ "2m 30.000s",
146
+ )
147
+
148
+ def test_hours_minutes_seconds(self):
149
+ out = render_dc._fmt_total_duration(
150
+ "2026-04-22T10:00:00Z", "2026-04-22T11:30:45Z",
151
+ )
152
+ self.assertEqual(out, "1h 30m 45.000s")
153
+
154
+
155
+ # -----------------------------------------------------------------------------
156
+ # _derive_session_end
157
+ # -----------------------------------------------------------------------------
158
+
159
+
160
+ class DeriveSessionEndTests(unittest.TestCase):
161
+
162
+ def test_returns_session_end_ts_verbatim_when_present(self):
163
+ end, source = render_dc._derive_session_end(
164
+ {"end_ts": "2026-04-22T11:00:00Z", "interactions": []},
165
+ )
166
+ self.assertEqual(end, "2026-04-22T11:00:00Z")
167
+ self.assertIsNone(source)
168
+
169
+ def test_uses_session_end_interaction_start_ts(self):
170
+ sess = {
171
+ "end_ts": None,
172
+ "interactions": [
173
+ {"type": "TURN", "start_ts": "10:00", "end_ts": "10:01"},
174
+ {"type": "SESSION_END", "start_ts": "11:00:00Z"},
175
+ ],
176
+ }
177
+ end, source = render_dc._derive_session_end(sess)
178
+ self.assertEqual(end, "11:00:00Z")
179
+ self.assertEqual(source, "from SESSION_END interaction")
180
+
181
+ def test_falls_back_to_last_turn_end_ts(self):
182
+ sess = {
183
+ "end_ts": None,
184
+ "interactions": [
185
+ {"type": "TURN", "start_ts": "10:00", "end_ts": "10:01"},
186
+ {"type": "TURN", "start_ts": "10:02", "end_ts": "10:03"},
187
+ ],
188
+ }
189
+ end, source = render_dc._derive_session_end(sess)
190
+ self.assertEqual(end, "10:03")
191
+ self.assertEqual(source, "session still open (last TURN)")
192
+
193
+ def test_returns_none_pair_when_no_data(self):
194
+ end, source = render_dc._derive_session_end({"interactions": []})
195
+ self.assertIsNone(end)
196
+ self.assertIsNone(source)
197
+
198
+
199
+ # -----------------------------------------------------------------------------
200
+ # _compose_agent_cell
201
+ # -----------------------------------------------------------------------------
202
+
203
+
204
+ class ComposeAgentCellTests(unittest.TestCase):
205
+
206
+ def test_full_identity_concatenated(self):
207
+ out = render_dc._compose_agent_cell({
208
+ "agent_api_name": "MyAgent",
209
+ "agent_version": "v3",
210
+ "agent_label": "My Agent",
211
+ "agent_type": "Internal",
212
+ })
213
+ self.assertEqual(out, "MyAgent v3 — My Agent (Internal)")
214
+
215
+ def test_only_api_name(self):
216
+ out = render_dc._compose_agent_cell({"agent_api_name": "MyAgent"})
217
+ self.assertEqual(out, "MyAgent")
218
+
219
+ def test_only_label(self):
220
+ out = render_dc._compose_agent_cell({"agent_label": "Display Only"})
221
+ self.assertEqual(out, "Display Only")
222
+
223
+ def test_returns_none_for_empty_identity(self):
224
+ self.assertIsNone(render_dc._compose_agent_cell({}))
225
+
226
+
227
+ # -----------------------------------------------------------------------------
228
+ # _section_session_bootstrap — channel-aware NOT_SET wording
229
+ # -----------------------------------------------------------------------------
230
+
231
+
232
+ class SectionSessionBootstrapNotSetWordingTests(unittest.TestCase):
233
+ """`VariableText__c == NOT_SET` is a "no bootstrap variables" signal,
234
+ not a messaging-channel signal. Several non-messaging shapes (E&O
235
+ headless API, Atlas planner, generic API/integration) legitimately
236
+ produce NOT_SET — the rendered line must not call those "production
237
+ messaging path".
238
+ """
239
+
240
+ def _identity_with_no_bootstrap(self) -> dict:
241
+ # Sentinel: bootstrap_variables key is present and explicitly None
242
+ # (the assembler stamps None when VariableText__c is NOT_SET).
243
+ return {"bootstrap_variables": None}
244
+
245
+ def test_messaging_channel_keeps_messaging_path_addendum(self):
246
+ out = "\n".join(render_dc._section_session_bootstrap(
247
+ self._identity_with_no_bootstrap(),
248
+ channel="SCRT2 - EmbeddedMessaging",
249
+ ))
250
+ self.assertIn("no bootstrap variables", out)
251
+ self.assertIn("production messaging path", out)
252
+ # Alias.
253
+ out2 = "\n".join(render_dc._section_session_bootstrap(
254
+ self._identity_with_no_bootstrap(),
255
+ channel="Messaging",
256
+ ))
257
+ self.assertIn("production messaging path", out2)
258
+
259
+ def test_non_messaging_channel_omits_messaging_path(self):
260
+ # E&O is the wheelz that surfaced this bug — Atlas-planner
261
+ # session on the "E & O" channel was being mislabeled
262
+ # "production messaging path".
263
+ out = "\n".join(render_dc._section_session_bootstrap(
264
+ self._identity_with_no_bootstrap(),
265
+ channel="E & O",
266
+ ))
267
+ self.assertIn("no bootstrap variables", out)
268
+ self.assertNotIn("production messaging path", out)
269
+ self.assertNotIn("messaging", out.lower())
270
+
271
+ def test_null_channel_uses_neutral_wording(self):
272
+ # No channel info at all — must not assume messaging.
273
+ out = "\n".join(render_dc._section_session_bootstrap(
274
+ self._identity_with_no_bootstrap(),
275
+ channel=None,
276
+ ))
277
+ self.assertIn("no bootstrap variables", out)
278
+ self.assertNotIn("production messaging path", out)
279
+
280
+ def test_default_channel_kwarg_is_neutral(self):
281
+ # Backward-compat: callers that don't pass channel get the
282
+ # neutral wording, never the messaging-path label.
283
+ out = "\n".join(render_dc._section_session_bootstrap(
284
+ self._identity_with_no_bootstrap(),
285
+ ))
286
+ self.assertIn("no bootstrap variables", out)
287
+ self.assertNotIn("production messaging path", out)
288
+
289
+
290
+ if __name__ == "__main__":
291
+ unittest.main()