@salesforce/afv-skills 1.63.0 → 1.65.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 (484) hide show
  1. package/package.json +1 -1
  2. package/skills/agentforce-gpt-email-generation-configure/SKILL.md +312 -0
  3. package/skills/agentforce-offline-experimentation-run/SKILL.md +253 -0
  4. package/skills/agentforce-offline-experimentation-run/scripts/build_report.py +796 -0
  5. package/skills/agentforce-offline-experimentation-run/scripts/resolve-token.sh +111 -0
  6. package/skills/agentforce-offline-experimentation-run/scripts/sfap_replay.py +1053 -0
  7. package/skills/agentforce-wizard-ui-forecasting-analytics-components-configure/SKILL.md +64 -0
  8. package/skills/agentforce-wizard-ui-sales-einstein-components-configure/SKILL.md +46 -0
  9. package/skills/automation-company-profile-info-query/SKILL.md +51 -0
  10. package/skills/automation-digital-wallet-configure/SKILL.md +689 -0
  11. package/skills/automation-flow-coordinate/SKILL.md +95 -0
  12. package/skills/automation-flow-coordinate/references/elements/action-call/action-call.md +1569 -0
  13. package/skills/automation-flow-coordinate/references/elements/action-call/conversation-messaging.md +96 -0
  14. package/skills/automation-flow-coordinate/references/elements/action-call/examples/send-sms-message.json +23 -0
  15. package/skills/automation-flow-coordinate/references/elements/action-call/examples/send-to-journey-no-fields.json +31 -0
  16. package/skills/automation-flow-coordinate/references/elements/action-call/send-to-journey.md +179 -0
  17. package/skills/automation-flow-coordinate/references/elements/exit-rule/examples/event-email-link-click.json +13 -0
  18. package/skills/automation-flow-coordinate/references/elements/exit-rule/exit-rule.md +83 -0
  19. package/skills/automation-flow-coordinate/references/elements/forward-to-bot-or-agent/examples/forward-to-bot-or-agent.json +69 -0
  20. package/skills/automation-flow-coordinate/references/elements/forward-to-bot-or-agent/forward-to-bot-or-agent.md +274 -0
  21. package/skills/automation-flow-coordinate/references/elements/start/audience-common.md +192 -0
  22. package/skills/automation-flow-coordinate/references/elements/start/automation-event-triggered.md +130 -0
  23. package/skills/automation-flow-coordinate/references/elements/start/data-cloud-data-change-triggered.md +92 -0
  24. package/skills/automation-flow-coordinate/references/elements/start/form-submission-triggered.md +88 -0
  25. package/skills/automation-flow-coordinate/references/elements/start/segment-triggered.md +152 -0
  26. package/skills/automation-flow-coordinate/references/elements/start/start.md +539 -0
  27. package/skills/automation-flow-coordinate/references/elements/subflow/subflow.md +152 -0
  28. package/skills/automation-flow-coordinate/references/elements/wait/wait.md +497 -0
  29. package/skills/automation-flow-coordinate/references/recipes/author/author.md +868 -0
  30. package/skills/automation-flow-coordinate/references/recipes/summarize/element-generic.md +300 -0
  31. package/skills/automation-flow-coordinate/references/recipes/summarize/reference-resolution.md +292 -0
  32. package/skills/automation-flow-coordinate/references/recipes/summarize/summarize.md +323 -0
  33. package/skills/automation-flow-coordinate/references/recipes/testing/examples/debug-output-template.md +109 -0
  34. package/skills/automation-flow-coordinate/references/recipes/testing/shape.md +219 -0
  35. package/skills/automation-flow-coordinate/references/recipes/testing/shared-stages/intent-analyzer.md +180 -0
  36. package/skills/automation-flow-coordinate/references/recipes/testing/workflows/debug.md +175 -0
  37. package/skills/automation-flow-coordinate/references/recipes/testing/workflows/promote.md +255 -0
  38. package/skills/automation-flow-coordinate/references/recipes/testing/workflows/save-debug.md +212 -0
  39. package/skills/automation-flow-coordinate/references/resources/variable/variable.md +171 -0
  40. package/skills/automation-flow-coordinate/references/shared/anti-patterns.md +786 -0
  41. package/skills/automation-flow-coordinate/references/shared/end/end.md +267 -0
  42. package/skills/automation-flow-coordinate/references/shared/flow-type-resolver/eval/README.md +69 -0
  43. package/skills/automation-flow-coordinate/references/shared/flow-type-resolver/eval/predictions.jsonl +80 -0
  44. package/skills/automation-flow-coordinate/references/shared/flow-type-resolver/eval/prompts.jsonl +116 -0
  45. package/skills/automation-flow-coordinate/references/shared/flow-type-resolver/flow-type-resolver.md +321 -0
  46. package/skills/automation-flow-coordinate/references/shared/flow-type-resolver/taxonomy.json +320 -0
  47. package/skills/automation-flow-coordinate/references/shared/server-functions.md +597 -0
  48. package/skills/automation-sandbox-post-copy-config-generate/SKILL.md +21 -11
  49. package/skills/automation-sandbox-post-copy-config-generate/assets/config_template.json +10 -0
  50. package/skills/automation-sandbox-post-copy-config-generate/assets/json_schema.json +33 -1
  51. package/skills/automation-sandbox-post-copy-config-generate/references/configuration_catalog.md +44 -1
  52. package/skills/automation-sandbox-post-copy-configure/SKILL.md +132 -124
  53. package/skills/automation-sandbox-post-copy-configure/references/flow_activation_path.md +151 -0
  54. package/skills/automation-sandbox-post-copy-configure/references/scheduled_apex_path.md +55 -9
  55. package/skills/automotive-cloud-appraisal-management-settings-configure/SKILL.md +69 -0
  56. package/skills/automotive-cloud-dealer-essentials-configure/SKILL.md +78 -0
  57. package/skills/automotive-cloud-ground-agent-data-pipelines-configure/SKILL.md +373 -0
  58. package/skills/automotive-cloud-ground-mfg-agent-data-pipelines-configure/SKILL.md +273 -0
  59. package/skills/automotive-cloud-mfg-agent-data-pipelines-configure/SKILL.md +259 -0
  60. package/skills/automotive-cloud-mfg-sales-concierge-agent-create/SKILL.md +369 -0
  61. package/skills/automotive-cloud-mfg-sales-concierge-foundation-configure/SKILL.md +542 -0
  62. package/skills/automotive-cloud-mfg-sales-concierge-foundation-coordinate/SKILL.md +159 -0
  63. package/skills/automotive-cloud-mfg-sales-concierge-orchestrator-agent-create/SKILL.md +349 -0
  64. package/skills/automotive-cloud-mfg-sales-concierge-orchestrator-configure/SKILL.md +505 -0
  65. package/skills/automotive-cloud-sales-concierge-agent-create/SKILL.md +380 -0
  66. package/skills/automotive-cloud-sales-concierge-foundation-configure/SKILL.md +567 -0
  67. package/skills/automotive-cloud-sales-concierge-foundation-coordinate/SKILL.md +159 -0
  68. package/skills/automotive-cloud-sales-concierge-orchestrator-agent-create/SKILL.md +360 -0
  69. package/skills/automotive-cloud-sales-concierge-orchestrator-configure/SKILL.md +539 -0
  70. package/skills/automotive-cloud-sales-concierge-search-grounding-configure/SKILL.md +358 -0
  71. package/skills/commerce-b2b-merchant-quote-configure/SKILL.md +602 -0
  72. package/skills/commerce-b2b-store-configure/SKILL.md +251 -0
  73. package/skills/commerce-credit-memo-create/SKILL.md +139 -0
  74. package/skills/commerce-delivery-business-hours-configure/SKILL.md +277 -0
  75. package/skills/commerce-delivery-estimation-apply/SKILL.md +155 -0
  76. package/skills/commerce-delivery-estimation-configure/SKILL.md +377 -0
  77. package/skills/commerce-delivery-routing-specs-integrate/SKILL.md +174 -0
  78. package/skills/commerce-estimate-bopis-query/SKILL.md +279 -0
  79. package/skills/commerce-estimate-delivery-date-query/SKILL.md +349 -0
  80. package/skills/commerce-fees-apply/SKILL.md +227 -0
  81. package/skills/commerce-fulfillment-routing-analyze/SKILL.md +200 -0
  82. package/skills/commerce-guest-buyer-create/SKILL.md +173 -0
  83. package/skills/commerce-location-bopis-configure/SKILL.md +378 -0
  84. package/skills/commerce-location-business-hours-configure/SKILL.md +235 -0
  85. package/skills/commerce-location-delivery-processing-time-configure/SKILL.md +309 -0
  86. package/skills/commerce-location-graph-integrate/SKILL.md +131 -0
  87. package/skills/commerce-location-shipping-carrier-method-configure/SKILL.md +755 -0
  88. package/skills/commerce-location-temporary-operating-hours-configure/SKILL.md +331 -0
  89. package/skills/commerce-merchant-buyer-groups-configure/SKILL.md +579 -0
  90. package/skills/commerce-merchant-buyer-user-onboarding-create/SKILL.md +626 -0
  91. package/skills/commerce-merchant-catalog-configure/SKILL.md +614 -0
  92. package/skills/commerce-merchant-extension-provider-configure/SKILL.md +368 -0
  93. package/skills/commerce-merchant-insights-account-health-churn-analyze/SKILL.md +118 -0
  94. package/skills/commerce-merchant-insights-inventory-returns-analyze/SKILL.md +65 -0
  95. package/skills/commerce-merchant-insights-order-shopper-get/SKILL.md +90 -0
  96. package/skills/commerce-merchant-insights-product-performance-analyze/SKILL.md +72 -0
  97. package/skills/commerce-merchant-insights-query/SKILL.md +279 -0
  98. package/skills/commerce-merchant-storefront-guest-access-configure/SKILL.md +656 -0
  99. package/skills/commerce-order-summary-change-apply/SKILL.md +375 -0
  100. package/skills/commerce-product-details-get/SKILL.md +363 -0
  101. package/skills/commerce-product-search/SKILL.md +563 -0
  102. package/skills/commerce-react-storefront-create/SKILL.md +350 -0
  103. package/skills/commerce-return-order-summary-create/SKILL.md +513 -0
  104. package/skills/commerce-search-relevance-analyze/SKILL.md +757 -0
  105. package/skills/commerce-temporary-processing-time-override-create/SKILL.md +274 -0
  106. package/skills/communications-initial-setup-configure/SKILL.md +630 -0
  107. package/skills/communications-multisite-configure/SKILL.md +571 -0
  108. package/skills/communications-revenue-cloud-settings-configure/SKILL.md +74 -0
  109. package/skills/communications-smb-fiber-catalog-create/SKILL.md +413 -0
  110. package/skills/communications-tmf-integrate/SKILL.md +1368 -0
  111. package/skills/consumer-goods-promotion-bo-api-deploy/SKILL.md +54 -107
  112. package/skills/consumer-goods-promotion-bo-api-deploy/assets/set-comment-value/payloads/copy.json +1 -1
  113. package/skills/consumer-goods-promotion-bo-api-deploy/references/conventions-and-payload-rules.md +82 -5
  114. package/skills/consumer-goods-promotion-bo-api-deploy/references/generate-and-wire.md +35 -2
  115. package/skills/consumer-goods-promotion-bo-api-deploy/references/preflight-and-seed-queries.md +149 -0
  116. package/skills/consumer-goods-promotion-bo-api-deploy/references/smoke-and-verify.md +17 -1
  117. package/skills/consumer-goods-visit-activity-act4-questions-assign/SKILL.md +448 -0
  118. package/skills/consumer-goods-visit-activity-act5-standard-create/SKILL.md +269 -0
  119. package/skills/consumer-goods-visit-activity-act6-assortment-configure/SKILL.md +271 -0
  120. package/skills/consumer-goods-visit-activity-act7-account-scoping-create/SKILL.md +382 -0
  121. package/skills/consumer-goods-visit-activity-act8-plan-attach-create/SKILL.md +373 -0
  122. package/skills/consumer-goods-visit-activity-act9-proof-validate/SKILL.md +389 -0
  123. package/skills/consumer-goods-visit-and-activity-act1-specification-create/SKILL.md +338 -0
  124. package/skills/consumer-goods-visit-and-activity-act2-template-create/SKILL.md +547 -0
  125. package/skills/consumer-goods-visit-and-activity-act3-definition-create/SKILL.md +346 -0
  126. package/skills/consumer-goods-visit-and-activity-configure/SKILL.md +1110 -0
  127. package/skills/crm-analytics-adoption-insights-configure/SKILL.md +224 -0
  128. package/skills/crm-analytics-custom-report-type-lightning-configure/SKILL.md +418 -0
  129. package/skills/crm-analytics-dashboards-configure/SKILL.md +731 -0
  130. package/skills/crm-analytics-operational-analytics-metadata-bridge-migrate/SKILL.md +233 -0
  131. package/skills/crm-analytics-report-notifications-ui-configure/SKILL.md +184 -0
  132. package/skills/crm-analytics-sharing-inheritance-coverage-analyze/SKILL.md +167 -0
  133. package/skills/crm-analytics-sonic-getting-started-configure/SKILL.md +55 -0
  134. package/skills/crm-analytics-tableau-next-app-deploy/SKILL.md +1350 -0
  135. package/skills/crm-analytics-tableau-next-c360-basemodel-validate/SKILL.md +1862 -0
  136. package/skills/crm-analytics-tableau-next-datacloud-validate/SKILL.md +83 -0
  137. package/skills/crm-analytics-tableau-next-provisioning-validate/SKILL.md +81 -0
  138. package/skills/data360-activation-create/SKILL.md +104 -0
  139. package/skills/data360-activation-external-platform-get/SKILL.md +49 -0
  140. package/skills/data360-activation-target-create/SKILL.md +93 -0
  141. package/skills/data360-activation-v2-create/SKILL.md +456 -0
  142. package/skills/data360-audience-dmo-get/SKILL.md +38 -0
  143. package/skills/data360-calculated-affinity-create/SKILL.md +82 -0
  144. package/skills/data360-calculated-insight-create/SKILL.md +148 -0
  145. package/skills/data360-catalog-metadata-create/SKILL.md +183 -0
  146. package/skills/data360-code-extension-create/SKILL.md +115 -0
  147. package/skills/data360-communication-capping-create/SKILL.md +227 -0
  148. package/skills/data360-connection-create/SKILL.md +491 -0
  149. package/skills/data360-content-lens-create/SKILL.md +181 -0
  150. package/skills/data360-data-action-create/SKILL.md +126 -0
  151. package/skills/data360-data-action-target-create/SKILL.md +181 -0
  152. package/skills/data360-data-clean-room-create/SKILL.md +238 -0
  153. package/skills/data360-data-governance-create/SKILL.md +746 -0
  154. package/skills/data360-data-graph-create/SKILL.md +82 -0
  155. package/skills/data360-data-harmonized-model-object-reference-create/SKILL.md +38 -0
  156. package/skills/data360-data-lake-object-create/SKILL.md +207 -0
  157. package/skills/data360-data-model-object-catalog-get/SKILL.md +49 -0
  158. package/skills/data360-data-model-object-create/SKILL.md +128 -0
  159. package/skills/data360-data-model-object-mapping-create/SKILL.md +106 -0
  160. package/skills/data360-data-space-create/SKILL.md +161 -0
  161. package/skills/data360-data-streams-create/SKILL.md +324 -0
  162. package/skills/data360-engagement-signal-get/SKILL.md +38 -0
  163. package/skills/data360-experiment-create/SKILL.md +82 -0
  164. package/skills/data360-goal-based-campaign-create/SKILL.md +192 -0
  165. package/skills/data360-harmonization-process-history-get/SKILL.md +38 -0
  166. package/skills/data360-harmonized-unstructured-dmo-create/SKILL.md +84 -0
  167. package/skills/data360-identity-resolution-create/SKILL.md +115 -0
  168. package/skills/data360-intelligent-document-processing-create/SKILL.md +148 -0
  169. package/skills/data360-knowledge-graph-construction-create/SKILL.md +93 -0
  170. package/skills/data360-knowledge-graph-create/SKILL.md +216 -0
  171. package/skills/data360-knowledge-space-mcp-configure/SKILL.md +475 -0
  172. package/skills/data360-machine-learning-mcp-configure/SKILL.md +697 -0
  173. package/skills/data360-multi-org-mcp-configure/SKILL.md +117 -0
  174. package/skills/data360-secondary-index-mcp-configure/SKILL.md +126 -0
  175. package/skills/data360-segment-mcp-configure/SKILL.md +159 -0
  176. package/skills/data360-semantic-calculated-dimension-mcp-configure/SKILL.md +93 -0
  177. package/skills/data360-semantic-calculated-measurement-mcp-configure/SKILL.md +93 -0
  178. package/skills/data360-semantic-data-object-mcp-configure/SKILL.md +93 -0
  179. package/skills/data360-semantic-dimension-mcp-configure/SKILL.md +38 -0
  180. package/skills/data360-semantic-engine-mcp-configure/SKILL.md +62 -0
  181. package/skills/data360-semantic-measurement-mcp-configure/SKILL.md +38 -0
  182. package/skills/data360-semantic-metric-mcp-configure/SKILL.md +93 -0
  183. package/skills/data360-semantic-model-mcp-configure/SKILL.md +115 -0
  184. package/skills/data360-standard-mapping-mcp-configure/SKILL.md +38 -0
  185. package/skills/data360-tenant-lifecycle-mcp-configure/SKILL.md +73 -0
  186. package/skills/dx-devops-conflict-resolve/SKILL.md +1 -5
  187. package/skills/dx-devops-pipeline-manage/SKILL.md +1 -5
  188. package/skills/dx-devops-project-manage/SKILL.md +1 -5
  189. package/skills/dx-devops-promote/SKILL.md +1 -5
  190. package/skills/dx-devops-request-status/SKILL.md +1 -5
  191. package/skills/dx-lifecycle-center/SKILL.md +120 -0
  192. package/skills/dx-lifecycle-center/examples/workflows.md +175 -0
  193. package/skills/dx-lifecycle-center/references/connect-api.md +123 -0
  194. package/skills/dx-lifecycle-center/references/connect-org.md +184 -0
  195. package/skills/dx-lifecycle-center/references/deploy.md +153 -0
  196. package/skills/dx-lifecycle-center/references/error-handling.md +21 -0
  197. package/skills/dx-lifecycle-center/references/hub-org.md +37 -0
  198. package/skills/dx-lifecycle-center/references/list-orgs.md +99 -0
  199. package/skills/dx-lifecycle-center/references/request-body.md +75 -0
  200. package/skills/dx-lifecycle-center/references/troubleshooting.md +31 -0
  201. package/skills/dx-lifecycle-center/scripts/poll-deploy-status.sh +200 -0
  202. package/skills/dx-lifecycle-center/scripts/resolve-environment.sh +120 -0
  203. package/skills/dx-org-devhub-configure/SKILL.md +1 -3
  204. package/skills/dx-org-shape-manage/SKILL.md +1 -5
  205. package/skills/dx-org-snapshot-manage/SKILL.md +1 -3
  206. package/skills/education-cloud-academic-calendar-generate/SKILL.md +1 -3
  207. package/skills/education-cloud-course-catalog-migrate/SKILL.md +1 -3
  208. package/skills/education-cloud-domain-configure/SKILL.md +1 -3
  209. package/skills/education-cloud-multi-campus-configure/SKILL.md +1 -3
  210. package/skills/education-cloud-student-recruitment-agent-configure/SKILL.md +1 -5
  211. package/skills/experience-afv-query/SKILL.md +234 -0
  212. package/skills/experience-agentforce-vibes-in-react-configure/SKILL.md +63 -0
  213. package/skills/experience-apex-components-configure/SKILL.md +69 -0
  214. package/skills/experience-apex-pages-configure/SKILL.md +107 -0
  215. package/skills/experience-app-home-configure/SKILL.md +76 -0
  216. package/skills/experience-aura-lightning-out-access-configure/SKILL.md +58 -0
  217. package/skills/experience-briefcase-configure/SKILL.md +287 -0
  218. package/skills/experience-community-flexi-page-list-create/SKILL.md +74 -0
  219. package/skills/experience-community-template-definition-list-query/SKILL.md +48 -0
  220. package/skills/experience-community-theme-definition-list-query/SKILL.md +38 -0
  221. package/skills/experience-content-assets-configure/SKILL.md +86 -0
  222. package/skills/experience-custom-domain-create/SKILL.md +727 -0
  223. package/skills/experience-defer-rendering-workspace-page-setup-configure/SKILL.md +41 -0
  224. package/skills/experience-field-service-app-builder-configure/SKILL.md +187 -0
  225. package/skills/experience-flow-category-configure/SKILL.md +117 -0
  226. package/skills/experience-formula-configure/SKILL.md +358 -0
  227. package/skills/experience-global-actions-configure/SKILL.md +69 -0
  228. package/skills/experience-global-publisher-layouts-configure/SKILL.md +79 -0
  229. package/skills/experience-instrumentation-configure/SKILL.md +64 -0
  230. package/skills/experience-lex-engagement-configure/SKILL.md +50 -0
  231. package/skills/experience-lightning-bolt-open/SKILL.md +12 -0
  232. package/skills/experience-lightning-out-configure/SKILL.md +129 -0
  233. package/skills/experience-lightning-preview-configure/SKILL.md +67 -0
  234. package/skills/experience-lightning-types-query/SKILL.md +98 -0
  235. package/skills/experience-malware-scan-configure/SKILL.md +71 -0
  236. package/skills/experience-my-salesforce-configure/SKILL.md +126 -0
  237. package/skills/experience-navigation-menus-configure/SKILL.md +235 -0
  238. package/skills/experience-notification-types-configure/SKILL.md +206 -0
  239. package/skills/experience-notifications-configure/SKILL.md +75 -0
  240. package/skills/experience-record-discovery-query/SKILL.md +227 -0
  241. package/skills/experience-regenerate-previews-open/SKILL.md +94 -0
  242. package/skills/experience-sales-cloud-mab-configure/SKILL.md +254 -0
  243. package/skills/experience-schema-builder-open/SKILL.md +38 -0
  244. package/skills/experience-simple-record-home-configure/SKILL.md +110 -0
  245. package/skills/experience-static-resources-configure/SKILL.md +74 -0
  246. package/skills/experience-ui-bundle-2gp-deploy/SKILL.md +1 -3
  247. package/skills/experience-ui-bundle-features-generate/SKILL.md +1 -5
  248. package/skills/experience-ui-bundle-mfa-configure/SKILL.md +1 -3
  249. package/skills/field-service-data-capture-form-deployer-configure/SKILL.md +23 -2
  250. package/skills/field-service-data-capture-form-designer-configure/SKILL.md +13 -3
  251. package/skills/field-service-data-capture-migrate/SKILL.md +1 -3
  252. package/skills/field-service-mobile-branding-configure/SKILL.md +17 -3
  253. package/skills/field-service-objective-designer-configure/SKILL.md +72 -379
  254. package/skills/field-service-prework-brief-deployer-configure/SKILL.md +10 -537
  255. package/skills/field-service-scheduling-policy-designer-query/SKILL.md +65 -1093
  256. package/skills/{field-service-setup-orchestrator-get → field-service-setup-coordinate}/SKILL.md +18 -3
  257. package/skills/field-service-sobject-create-configure/SKILL.md +13 -213
  258. package/skills/field-service-voice-to-form-configure/SKILL.md +40 -11
  259. package/skills/field-service-work-plan-configure/SKILL.md +253 -0
  260. package/skills/field-service-work-rule-designer-configure/SKILL.md +121 -95
  261. package/skills/fsc-actionable-segmentation-settings-configure/SKILL.md +180 -0
  262. package/skills/fsc-digital-origination-bre-decision-matrix-foundation-create/SKILL.md +196 -0
  263. package/skills/fsc-digital-origination-bre-disclosures-consent-configure/SKILL.md +106 -0
  264. package/skills/fsc-digital-origination-bre-document-upload-configure/SKILL.md +96 -0
  265. package/skills/fsc-digital-origination-bre-permissions-assign/SKILL.md +111 -0
  266. package/skills/fsc-digital-origination-bre-setup-coordinate/SKILL.md +250 -0
  267. package/skills/fsc-digital-origination-bre-stp-eligibility-configure/SKILL.md +122 -0
  268. package/skills/fsc-digital-origination-coordinate/SKILL.md +653 -0
  269. package/skills/fsc-digital-origination-demo-run/SKILL.md +225 -0
  270. package/skills/fsc-digital-origination-execution-guardrails-validate/SKILL.md +112 -0
  271. package/skills/fsc-digital-origination-initial-setup-configure/SKILL.md +396 -0
  272. package/skills/fsc-digital-origination-pricing-setup-coordinate/SKILL.md +336 -0
  273. package/skills/fsc-digital-origination-pricing-setup-data-foundation-create/SKILL.md +208 -0
  274. package/skills/fsc-digital-origination-pricing-setup-procedure-create/SKILL.md +375 -0
  275. package/skills/fsc-digital-origination-product-setup-act1-permissions-assign/SKILL.md +83 -0
  276. package/skills/fsc-digital-origination-product-setup-coordinate/SKILL.md +248 -0
  277. package/skills/fsc-digital-origination-sample-data-create/SKILL.md +206 -0
  278. package/skills/fsc-document-checklist-settings-configure/SKILL.md +57 -0
  279. package/skills/fsc-flexible-hierarchy-configure/SKILL.md +148 -0
  280. package/skills/fsc-flexible-hierarchy-foundation-configure/SKILL.md +1430 -0
  281. package/skills/fsc-flexible-hierarchy-graph-config-create/SKILL.md +471 -0
  282. package/skills/fsc-flexible-hierarchy-rule-based-graph-deploy/SKILL.md +429 -0
  283. package/skills/fsc-pricing-product-configurator-configure/SKILL.md +150 -0
  284. package/skills/fsc-pricing-salesforce-omnistudio-switch/SKILL.md +123 -0
  285. package/skills/fsc-product-act2-catalog-categories-create/SKILL.md +82 -0
  286. package/skills/fsc-product-act3-attributes-create/SKILL.md +249 -0
  287. package/skills/fsc-product-act4-classification-assignment-create/SKILL.md +196 -0
  288. package/skills/fsc-product-act5-considerations-get/SKILL.md +44 -0
  289. package/skills/fsc-stage-management-apex-flow-deploy/SKILL.md +384 -0
  290. package/skills/fsc-stage-management-compliant-data-sharing-configure/SKILL.md +144 -0
  291. package/skills/fsc-stage-management-decision-matrices-create/SKILL.md +107 -0
  292. package/skills/fsc-stage-management-definition-assignments-create/SKILL.md +189 -0
  293. package/skills/fsc-stage-management-definition-create/SKILL.md +108 -0
  294. package/skills/fsc-stage-management-permissions-assign/SKILL.md +143 -0
  295. package/skills/fsc-stage-management-transitions-configure/SKILL.md +139 -0
  296. package/skills/health-cloud-appt-booking-config-configure/SKILL.md +135 -0
  297. package/skills/health-cloud-appt-booking-url-config-configure/SKILL.md +134 -0
  298. package/skills/health-cloud-care-provider-affl-role-config-configure/SKILL.md +136 -0
  299. package/skills/health-cloud-care-provider-search-config-configure/SKILL.md +134 -0
  300. package/skills/health-cloud-care-requests-create/SKILL.md +178 -0
  301. package/skills/health-cloud-initial-configure/SKILL.md +511 -0
  302. package/skills/health-cloud-patient-appointment-scheduling-configure/SKILL.md +1374 -0
  303. package/skills/health-cloud-provider-search-settings-configure/SKILL.md +924 -0
  304. package/skills/health-cloud-referral-management-coordinate/SKILL.md +513 -0
  305. package/skills/health-cloud-timeline-configure/SKILL.md +622 -0
  306. package/skills/health-cloud-virtual-visit-config-configure/SKILL.md +135 -0
  307. package/skills/industries-account-score-settings-query/SKILL.md +78 -0
  308. package/skills/industries-actionable-list-data-sources-dmo-configure/SKILL.md +177 -0
  309. package/skills/industries-ad-product-availability-search/SKILL.md +399 -0
  310. package/skills/industries-advanced-account-forecast-settings-configure/SKILL.md +628 -0
  311. package/skills/industries-advanced-therapy-management-settings-configure/SKILL.md +73 -0
  312. package/skills/industries-atm-settings-starter-configure/SKILL.md +76 -0
  313. package/skills/industries-batch-document-ai-configure/SKILL.md +196 -0
  314. package/skills/industries-behavioral-health-app-settings-configure/SKILL.md +71 -0
  315. package/skills/industries-branch-management-settings-configure/SKILL.md +89 -0
  316. package/skills/industries-bre-decision-table-access-configure/SKILL.md +367 -0
  317. package/skills/industries-brokerage-settings-configure/SKILL.md +41 -0
  318. package/skills/industries-calendar-sync-settings-configure/SKILL.md +89 -0
  319. package/skills/industries-care-request-settings-configure/SKILL.md +218 -0
  320. package/skills/industries-case-management-intelligence-settings-configure/SKILL.md +54 -0
  321. package/skills/industries-catalog-process-attributes-products-configure/SKILL.md +380 -0
  322. package/skills/industries-catalog-process-fulfillment-configure/SKILL.md +216 -0
  323. package/skills/industries-catalog-process-intake-configure/SKILL.md +219 -0
  324. package/skills/industries-catalog-process-knowledge-configure/SKILL.md +153 -0
  325. package/skills/industries-catalog-process-preprocessor-configure/SKILL.md +168 -0
  326. package/skills/industries-cds-general-settings-configure/SKILL.md +69 -0
  327. package/skills/industries-claim-financial-settings-configure/SKILL.md +169 -0
  328. package/skills/industries-clinical-data-model-settings-configure/SKILL.md +136 -0
  329. package/skills/industries-clinical-data-model-settings-starter-configure/SKILL.md +105 -0
  330. package/skills/industries-collection-plan-settings-configure/SKILL.md +132 -0
  331. package/skills/industries-comms-service-console-settings-configure/SKILL.md +159 -0
  332. package/skills/industries-compliance-configure/SKILL.md +102 -0
  333. package/skills/industries-compliance-document-extraction-setup-configure/SKILL.md +76 -0
  334. package/skills/industries-contact-center-app-layout-configure/SKILL.md +88 -0
  335. package/skills/industries-contact-center-components-configure/SKILL.md +96 -0
  336. package/skills/industries-contact-center-path-knowledge-configure/SKILL.md +95 -0
  337. package/skills/industries-contact-center-user-access-assign/SKILL.md +96 -0
  338. package/skills/industries-course-waitlist-config-configure/SKILL.md +162 -0
  339. package/skills/industries-crisis-center-settings-configure/SKILL.md +84 -0
  340. package/skills/industries-custom-object-settings-configure/SKILL.md +94 -0
  341. package/skills/industries-data-cloud-integration-configure/SKILL.md +88 -0
  342. package/skills/industries-data-space-feature-mappings-configure/SKILL.md +245 -0
  343. package/skills/industries-decision-matrix-builder-configure/SKILL.md +78 -0
  344. package/skills/industries-decision-table-hbase-configure/SKILL.md +87 -0
  345. package/skills/industries-decision-table-version-configure/SKILL.md +74 -0
  346. package/skills/industries-decision-tables-builder-configure/SKILL.md +253 -0
  347. package/skills/industries-decision-tables-configure/SKILL.md +439 -0
  348. package/skills/industries-energy-utilities-configure/SKILL.md +251 -0
  349. package/skills/industries-eu-cloud-multisite-configure/SKILL.md +1008 -0
  350. package/skills/industries-eu-new-connections-configure/SKILL.md +30 -0
  351. package/skills/industries-explainability-msg-template-configure/SKILL.md +135 -0
  352. package/skills/industries-expression-set-message-token-configure/SKILL.md +135 -0
  353. package/skills/industries-field-service-settings-configure/SKILL.md +82 -0
  354. package/skills/industries-form-framework-settings-configure/SKILL.md +30 -0
  355. package/skills/industries-fsc-ai-settings-configure/SKILL.md +57 -0
  356. package/skills/industries-fsc-association-engine-settings-configure/SKILL.md +172 -0
  357. package/skills/industries-fsc-b2b-settings-configure/SKILL.md +61 -0
  358. package/skills/industries-fsc-insurance-settings-configure/SKILL.md +58 -0
  359. package/skills/industries-fsc-visa-fulfillment-setup-configure/SKILL.md +103 -0
  360. package/skills/industries-fsc-wealth-agent-settings-configure/SKILL.md +117 -0
  361. package/skills/industries-fsc-wealth-settings-configure/SKILL.md +99 -0
  362. package/skills/industries-fundraising-gift-entry-settings-configure/SKILL.md +120 -0
  363. package/skills/industries-fundraising-rfm-configure/SKILL.md +128 -0
  364. package/skills/industries-fundraising-settings-configure/SKILL.md +145 -0
  365. package/skills/industries-fundraising-source-code-gen-configure/SKILL.md +299 -0
  366. package/skills/industries-google-maps-api-key-settings-configure/SKILL.md +87 -0
  367. package/skills/industries-grantmaking-intelligence-settings-open/SKILL.md +58 -0
  368. package/skills/industries-hc-score-category-settings-configure/SKILL.md +167 -0
  369. package/skills/industries-health-engagement-settings-configure/SKILL.md +218 -0
  370. package/skills/industries-home-health-agentforce-setup-configure/SKILL.md +131 -0
  371. package/skills/industries-home-health-bundling-policy-create/SKILL.md +50 -0
  372. package/skills/industries-home-health-entity-labels-configure/SKILL.md +29 -0
  373. package/skills/industries-home-health-fsl-package-deploy/SKILL.md +71 -0
  374. package/skills/industries-home-health-fsl-settings-validate/SKILL.md +27 -0
  375. package/skills/industries-home-health-guided-setup-care-and-skill-get/SKILL.md +80 -0
  376. package/skills/industries-home-health-guided-setup-configure/SKILL.md +836 -0
  377. package/skills/industries-home-health-guided-setup-enable-org-fsl-get/SKILL.md +55 -0
  378. package/skills/industries-home-health-guided-setup-get-org-ready-get/SKILL.md +61 -0
  379. package/skills/industries-home-health-licenses-assign/SKILL.md +27 -0
  380. package/skills/industries-home-health-operating-hours-create/SKILL.md +40 -0
  381. package/skills/industries-home-health-scheduling-policy-create/SKILL.md +41 -0
  382. package/skills/industries-home-health-service-objective-create/SKILL.md +22 -0
  383. package/skills/industries-home-health-skills-create/SKILL.md +31 -0
  384. package/skills/industries-home-health-users-create/SKILL.md +29 -0
  385. package/skills/industries-icm-act3-toggles-configure/SKILL.md +198 -0
  386. package/skills/industries-icm-act5-genai-suggested-assessments-configure/SKILL.md +361 -0
  387. package/skills/industries-icm-act6-mcg-integration-configure/SKILL.md +550 -0
  388. package/skills/industries-integrated-care-management-configure/SKILL.md +168 -0
  389. package/skills/industries-object-enablement-configure/SKILL.md +86 -0
  390. package/skills/industries-tpm-system-processing-service-configure/SKILL.md +64 -0
  391. package/skills/insurance-brokerage-agency-billing-configure/SKILL.md +1 -3
  392. package/skills/integration-apex-settings-configure/SKILL.md +61 -0
  393. package/skills/marketing-e360-email-archiving-configure/SKILL.md +73 -0
  394. package/skills/marketing-message-test/SKILL.md +1 -3
  395. package/skills/nonprofit-fundraising-configure/SKILL.md +240 -0
  396. package/skills/nonprofit-fundraising-configure/references/gotchas.md +26 -0
  397. package/skills/nonprofit-fundraising-configure/references/mcp-invocation.md +678 -0
  398. package/skills/nonprofit-fundraising-configure/references/permission-targeting.md +35 -0
  399. package/skills/nonprofit-volunteer-management-model-get/SKILL.md +166 -0
  400. package/skills/nonprofit-volunteer-management-model-get/references/entities.md +315 -0
  401. package/skills/nonprofit-volunteer-management-model-get/references/relationships.md +175 -0
  402. package/skills/nonprofit-volunteer-management-model-get/references/themes.md +143 -0
  403. package/skills/nonprofit-volunteer-management-records-create/SKILL.md +121 -0
  404. package/skills/nonprofit-volunteer-management-records-create/references/field-guide.md +284 -0
  405. package/skills/nonprofit-volunteer-management-records-create/references/mcp-invocation.md +248 -0
  406. package/skills/nonprofit-volunteer-management-records-create/references/review-format.md +140 -0
  407. package/skills/nonprofit-volunteer-management-records-create/scripts/expand-series.py +632 -0
  408. package/skills/nonprofit-volunteer-management-records-create/scripts/render-review-table.py +419 -0
  409. package/skills/nonprofit-volunteer-management-records-create/scripts/tests/test_expand_series.py +690 -0
  410. package/skills/nonprofit-volunteer-management-records-create/scripts/tests/test_render_review_table.py +421 -0
  411. package/skills/nonprofit-volunteer-management-structure-generate/SKILL.md +119 -0
  412. package/skills/nonprofit-volunteer-management-structure-generate/references/configuration-decisions.md +159 -0
  413. package/skills/nonprofit-volunteer-management-structure-generate/references/discovery-interview.md +137 -0
  414. package/skills/nonprofit-volunteer-management-structure-generate/references/edge-cases.md +48 -0
  415. package/skills/nonprofit-volunteer-management-structure-generate/references/mcp-invocation.md +75 -0
  416. package/skills/nonprofit-volunteer-management-structure-generate/references/plan-output.md +141 -0
  417. package/skills/platform-custom-field-generate/SKILL.md +1 -0
  418. package/skills/platform-custom-field-generate/references/advanced-picklists.md +5 -5
  419. package/skills/platform-custom-metadata-type-generate/SKILL.md +3 -0
  420. package/skills/platform-custom-object-generate/SKILL.md +4 -0
  421. package/skills/platform-custom-permissions-configure/SKILL.md +687 -0
  422. package/skills/platform-custom-setting-generate/SKILL.md +3 -0
  423. package/skills/platform-datamask-run/SKILL.md +1 -5
  424. package/skills/platform-label-workbench-import-create/SKILL.md +67 -0
  425. package/skills/platform-permission-set-generate/SKILL.md +3 -0
  426. package/skills/platform-privacy-agent-settings-configure/SKILL.md +752 -0
  427. package/skills/platform-salesforce-connect-adapter-generate/SKILL.md +1 -3
  428. package/skills/platform-sandbox-configure/SKILL.md +1 -3
  429. package/skills/platform-value-set-generate/SKILL.md +3 -0
  430. package/skills/sales-call-scoring-configure/SKILL.md +1 -5
  431. package/skills/service-agentforce-channel-configure/SKILL.md +1 -3
  432. package/skills/service-agentforce-human-escalation-configure/SKILL.md +1 -3
  433. package/skills/service-catalog-template-coordinate/SKILL.md +1 -3
  434. package/skills/service-concierge-portal-generate/SKILL.md +1 -3
  435. package/skills/service-email-to-case-configure/SKILL.md +1 -5
  436. package/skills/service-itsm-agentic-setup-agent-runtime-access-assign/SKILL.md +1 -3
  437. package/skills/service-itsm-agentic-setup-agentforce-coordinate/SKILL.md +1 -3
  438. package/skills/service-itsm-agentic-setup-agentforce-studio-configure/SKILL.md +1 -3
  439. package/skills/service-itsm-agentic-setup-agentforce-studio-validate/SKILL.md +1 -3
  440. package/skills/service-itsm-agentic-setup-cmdb-access-assign/SKILL.md +1 -3
  441. package/skills/service-itsm-agentic-setup-cmdb-bundle-deploy/SKILL.md +1 -5
  442. package/skills/service-itsm-agentic-setup-cmdb-configure/SKILL.md +1 -3
  443. package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +1 -3
  444. package/skills/service-itsm-agentic-setup-cmdb-discovery-configure/SKILL.md +1 -3
  445. package/skills/service-itsm-agentic-setup-employee-agent-configure/SKILL.md +1 -3
  446. package/skills/service-itsm-agentic-setup-fulfiller-agent-configure/SKILL.md +1 -3
  447. package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +1 -0
  448. package/skills/service-itsm-agentic-setup-itsm-agentforce-permset-assign/SKILL.md +1 -3
  449. package/skills/service-itsm-agentic-setup-uel-user-create/SKILL.md +1 -9
  450. package/skills/service-itsm-incident-mgmt-configure/SKILL.md +1 -5
  451. package/skills/service-itsm-incident-priority-configure/SKILL.md +1 -3
  452. package/skills/service-itsm-slack-itservice-configure/SKILL.md +1 -3
  453. package/skills/service-itsm-swarming-configure/SKILL.md +1 -3
  454. package/skills/service-itsm-teams-configure/SKILL.md +1 -3
  455. package/skills/service-itsm-teams-debug/SKILL.md +1 -3
  456. package/skills/service-itsm-teams-employee-agent-configure/SKILL.md +1 -3
  457. package/skills/service-itsm-teams-itdesk-configure/SKILL.md +1 -3
  458. package/skills/service-itsm-teams-itservice-configure/SKILL.md +1 -3
  459. package/skills/service-native-voice-recording-transcription-configure/SKILL.md +1 -3
  460. package/skills/service-omni-agent-users-create/SKILL.md +1 -3
  461. package/skills/service-omni-agent-work-sharing-configure/SKILL.md +1 -3
  462. package/skills/service-omni-attribute-routing-configure/SKILL.md +1 -3
  463. package/skills/service-omni-base-settings-configure/SKILL.md +1 -3
  464. package/skills/service-omni-channel-inventory-analyze/SKILL.md +1 -3
  465. package/skills/service-omni-channel-limits-analyze/SKILL.md +1 -3
  466. package/skills/service-omni-channel-setup-coordinate/SKILL.md +1 -3
  467. package/skills/service-omni-command-center-analyze/SKILL.md +1 -3
  468. package/skills/service-omni-command-center-configure/SKILL.md +1 -3
  469. package/skills/service-omni-permission-set-assign/SKILL.md +1 -3
  470. package/skills/service-omni-presence-status-deploy/SKILL.md +1 -3
  471. package/skills/service-omni-presence-user-config-deploy/SKILL.md +1 -3
  472. package/skills/service-omni-queue-deploy/SKILL.md +1 -3
  473. package/skills/service-omni-queue-members-assign/SKILL.md +1 -3
  474. package/skills/service-omni-queue-routing-config-deploy/SKILL.md +1 -3
  475. package/skills/service-omni-routing-flow-deploy/SKILL.md +1 -3
  476. package/skills/service-omni-service-channel-configure/SKILL.md +1 -3
  477. package/skills/service-omni-sidebar-configure/SKILL.md +1 -3
  478. package/skills/service-omni-skills-based-routing-configure/SKILL.md +1 -3
  479. package/skills/service-omni-supervisor-config-deploy/SKILL.md +1 -3
  480. package/skills/service-omni-supervisor-permset-assign/SKILL.md +1 -3
  481. package/skills/service-omni-supervisor-surface-deploy/SKILL.md +1 -3
  482. package/skills/service-omni-supervisor-users-create/SKILL.md +1 -3
  483. package/skills/service-omni-work-skill-routing-configure/SKILL.md +1 -3
  484. package/skills/tableau-next-asset-create/README.md +0 -65
@@ -0,0 +1,796 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Generate a self-contained HTML offline-analysis report from replay results JSON.
4
+ Adapted from hawking/ai-agent-backtesting PR #53 (build_failure_report.py).
5
+
6
+ Usage:
7
+ python build_report.py [replay_results.json] [output.html]
8
+ """
9
+ import json, sys, html as _html, textwrap
10
+ from pathlib import Path
11
+ from collections import Counter
12
+
13
+ # ---------------------------------------------------------------------------
14
+ # Helpers
15
+ # ---------------------------------------------------------------------------
16
+
17
+ def _calls(ans_json):
18
+ """Extract [(name, args_dict), ...] from a structured answer JSON string."""
19
+ try:
20
+ ans = json.loads(ans_json) if isinstance(ans_json, str) else ans_json
21
+ except (json.JSONDecodeError, TypeError):
22
+ return []
23
+ tcs = ans.get("tool_calls") or []
24
+ out = []
25
+ for tc in tcs:
26
+ name = tc.get("name", "")
27
+ args = tc.get("arguments", {})
28
+ if isinstance(args, str):
29
+ try:
30
+ args = json.loads(args)
31
+ except Exception:
32
+ args = {"raw": args}
33
+ out.append((name, args))
34
+ return out
35
+
36
+
37
+ def _is_router(d):
38
+ golden = _calls(d.get("GoldenAnswer", "{}"))
39
+ if d.get("GoldenType") == "topic":
40
+ return True
41
+ for name, _ in golden:
42
+ if any(name.lower().startswith(p) for p in ("route_to", "go_to", "transfer_to")):
43
+ return True
44
+ return False
45
+
46
+
47
+ def _bucket(d, name_hit):
48
+ """Categorize a failing row into a failure bucket."""
49
+ if d.get("ScoringError"):
50
+ err = d["ScoringError"].lower()
51
+ if "expected tool call" in err and "got text" in err:
52
+ return "no tool call emitted"
53
+ if "expected text" in err and "got tool call" in err:
54
+ return "unexpected tool call"
55
+ return "infra error"
56
+ if d.get("ToolAltReason"):
57
+ return "used functionally similar tool"
58
+ if not name_hit:
59
+ return "called a different tool"
60
+ if d.get("SchemaViolationNotes"):
61
+ return "args violate tool schema"
62
+ return "args mismatch (values differ)"
63
+
64
+
65
+ def _score_topic(routers):
66
+ if not routers:
67
+ return None
68
+ hits = sum(1 for d in routers if d.get("FunctionNameAgreementLenient"))
69
+ return round(100 * hits / len(routers), 1)
70
+
71
+
72
+ def _score_action_strict(actions):
73
+ if not actions:
74
+ return None
75
+ hits = sum(1 for d in actions if d.get("PassStrict") or d.get("FunctionArgsAgreement"))
76
+ return round(100 * hits / len(actions), 1)
77
+
78
+
79
+ def _score_action_lenient(actions):
80
+ """Count a row as passing if it passes strict OR used a functionally equivalent tool."""
81
+ if not actions:
82
+ return None
83
+ hits = sum(1 for d in actions
84
+ if d.get("PassStrict") or d.get("FunctionArgsAgreement") or d.get("FunctionNameAgreementLenient"))
85
+ return round(100 * hits / len(actions), 1)
86
+
87
+
88
+ def _rating(score, safe_min=85, review_min=60):
89
+ if score is None:
90
+ return "N/A", "#64748b"
91
+ if score >= safe_min:
92
+ return "SAFE", "#15803d"
93
+ if score >= review_min:
94
+ return "REVIEW", "#b45309"
95
+ return "UNSAFE", "#dc2626"
96
+
97
+
98
+ def _esc(text):
99
+ return _html.escape(str(text)) if text else ""
100
+
101
+
102
+ def _json_pretty(obj):
103
+ if isinstance(obj, str):
104
+ try:
105
+ obj = json.loads(obj)
106
+ except Exception:
107
+ return _esc(obj)
108
+ return _esc(json.dumps(obj, indent=2))
109
+
110
+
111
+ # ---------------------------------------------------------------------------
112
+ # Card rendering
113
+ # ---------------------------------------------------------------------------
114
+
115
+ def _card(d, rec, idx):
116
+ """Render an expandable card for a single failing row."""
117
+ golden = _calls(d.get("GoldenAnswer", "{}"))
118
+ predicted = _calls(d.get("PredictedAnswer", "{}"))
119
+ g_names = [n for n, _ in golden]
120
+ p_names = [n for n, _ in predicted]
121
+
122
+ name_hit = d.get("FunctionNameAgreement", False)
123
+ bucket = _bucket(d, name_hit)
124
+
125
+ flags = []
126
+ if d.get("ScoringError"):
127
+ flags.append(f'<span class="flag flag-error">{_esc(d["ScoringError"][:80])}</span>')
128
+ if d.get("ToolAltReason"):
129
+ flags.append(f'<span class="flag flag-warn">{_esc(d["ToolAltReason"])}</span>')
130
+ if d.get("FunctionArgsScoreReason"):
131
+ flags.append(f'<span class="flag flag-info">Args: {_esc(str(d["FunctionArgsScoreReason"])[:120])}</span>')
132
+
133
+ # Status badge
134
+ if d.get("PassStrict") or d.get("FunctionArgsAgreement"):
135
+ status_cls = "badge-pass"
136
+ status_txt = "PASS"
137
+ elif d.get("FunctionNameAgreementLenient"):
138
+ status_cls = "badge-warn"
139
+ status_txt = "PARTIAL"
140
+ else:
141
+ status_cls = "badge-fail"
142
+ status_txt = "FAIL"
143
+
144
+ # Golden vs Predicted comparison
145
+ golden_html = ""
146
+ for name, args in golden:
147
+ golden_html += f'<div class="tool-call"><span class="tool-name">{_esc(name)}</span>'
148
+ golden_html += f'<pre class="tool-args">{_json_pretty(args)}</pre></div>'
149
+ if not golden:
150
+ try:
151
+ ga = json.loads(d.get("GoldenAnswer", "{}"))
152
+ if ga.get("content"):
153
+ golden_html = f'<div class="text-resp">{_esc(ga["content"][:300])}</div>'
154
+ except Exception:
155
+ pass
156
+
157
+ predicted_html = ""
158
+ for name, args in predicted:
159
+ predicted_html += f'<div class="tool-call"><span class="tool-name">{_esc(name)}</span>'
160
+ predicted_html += f'<pre class="tool-args">{_json_pretty(args)}</pre></div>'
161
+ if not predicted:
162
+ try:
163
+ pa = json.loads(d.get("PredictedAnswer", "{}"))
164
+ if pa.get("content"):
165
+ predicted_html = f'<div class="text-resp">{_esc(pa["content"][:300])}</div>'
166
+ except Exception:
167
+ pass
168
+
169
+ # Tools offered
170
+ tools_offered = rec.get("tools", []) if rec else []
171
+ tools_html = ", ".join(f'<code>{_esc(t)}</code>' for t in tools_offered) if tools_offered else "<em>none</em>"
172
+
173
+ # Transcript (all messages, full content)
174
+ messages = rec.get("messages", []) if rec else []
175
+ transcript_html = ""
176
+ for msg in messages:
177
+ role = msg.get("role", "unknown")
178
+ content = str(msg.get("content", ""))
179
+ transcript_html += f'<div class="msg msg-{_esc(role)}"><strong>{_esc(role)}</strong>: {_esc(content)}</div>'
180
+
181
+ return f'''
182
+ <details class="card">
183
+ <summary class="card-header">
184
+ <span class="card-idx">#{idx}</span>
185
+ <span class="{status_cls}">{status_txt}</span>
186
+ <span class="card-bucket">{_esc(bucket)}</span>
187
+ <span class="card-utterance">{_esc(d.get("Utterance", "")[:80])}</span>
188
+ <span class="card-session">{_esc(d.get("AiAgentSessionId", "")[:12])}...</span>
189
+ </summary>
190
+ <div class="card-body">
191
+ <div class="flags">{" ".join(flags)}</div>
192
+
193
+ <div class="comparison">
194
+ <div class="comp-col">
195
+ <h4>Golden (Expected)</h4>
196
+ {golden_html or "<em>none</em>"}
197
+ </div>
198
+ <div class="comp-col">
199
+ <h4>Predicted (Replay)</h4>
200
+ {predicted_html or "<em>none</em>"}
201
+ </div>
202
+ </div>
203
+
204
+ <div class="section">
205
+ <h4>Scores</h4>
206
+ <table class="score-table">
207
+ <tr><td>Function Name Match</td><td>{"Yes" if d.get("FunctionNameAgreement") else "No"}</td></tr>
208
+ <tr><td>Function Name Match (Lenient)</td><td>{"Yes" if d.get("FunctionNameAgreementLenient") else "No"}</td></tr>
209
+ <tr><td>Args Agreement</td><td>{"Yes" if d.get("FunctionArgsAgreement") else "No"}</td></tr>
210
+ <tr><td>Args Score</td><td>{d.get("FunctionArgsScore", "N/A")}</td></tr>
211
+ <tr><td>Pass Strict</td><td>{"Yes" if d.get("PassStrict") else "No"}</td></tr>
212
+ </table>
213
+ </div>
214
+
215
+ <div class="section">
216
+ <h4>Tools Offered</h4>
217
+ <div>{tools_html}</div>
218
+ </div>
219
+
220
+ <details class="transcript-toggle">
221
+ <summary>Transcript ({len(messages)} messages)</summary>
222
+ <div class="transcript">{transcript_html or "<em>no transcript captured</em>"}</div>
223
+ </details>
224
+ </div>
225
+ </details>'''
226
+
227
+
228
+ # ---------------------------------------------------------------------------
229
+ # Main HTML builder
230
+ # ---------------------------------------------------------------------------
231
+
232
+ CSS = '''
233
+ @import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600;700&family=Inter:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap');
234
+
235
+ :root {
236
+ --slate-50: #f8fafc; --slate-100: #f1f5f9; --slate-200: #e2e8f0;
237
+ --slate-300: #cbd5e1; --slate-400: #94a3b8; --slate-500: #64748b;
238
+ --slate-600: #475569; --slate-700: #334155; --slate-800: #1e293b;
239
+ --slate-900: #0f172a;
240
+ --safe: #15803d; --safe-bg: #f0fdf4; --safe-border: #bbf7d0;
241
+ --review: #b45309; --review-bg: #fffbeb; --review-border: #fde68a;
242
+ --unsafe: #dc2626; --unsafe-bg: #fef2f2; --unsafe-border: #fecaca;
243
+ --radius: 12px;
244
+ }
245
+
246
+ * { box-sizing: border-box; margin: 0; padding: 0; }
247
+
248
+ body {
249
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
250
+ background: linear-gradient(135deg, var(--slate-50) 0%, var(--slate-100) 100%);
251
+ color: var(--slate-800);
252
+ line-height: 1.6;
253
+ min-height: 100vh;
254
+ padding: 2rem;
255
+ }
256
+
257
+ .container { max-width: 1200px; margin: 0 auto; }
258
+
259
+ h1 {
260
+ font-family: 'Space Grotesk', sans-serif;
261
+ font-size: 2rem;
262
+ font-weight: 700;
263
+ color: var(--slate-900);
264
+ margin-bottom: 0.5rem;
265
+ }
266
+
267
+ h2 {
268
+ font-family: 'Space Grotesk', sans-serif;
269
+ font-size: 1.4rem;
270
+ font-weight: 600;
271
+ color: var(--slate-700);
272
+ margin: 2rem 0 1rem;
273
+ padding-bottom: 0.5rem;
274
+ border-bottom: 2px solid var(--slate-200);
275
+ }
276
+
277
+ h3 {
278
+ font-family: 'Space Grotesk', sans-serif;
279
+ font-size: 1.1rem;
280
+ font-weight: 600;
281
+ color: var(--slate-600);
282
+ margin-bottom: 0.5rem;
283
+ }
284
+
285
+ h4 {
286
+ font-family: 'Space Grotesk', sans-serif;
287
+ font-size: 0.9rem;
288
+ font-weight: 600;
289
+ color: var(--slate-500);
290
+ margin-bottom: 0.3rem;
291
+ text-transform: uppercase;
292
+ letter-spacing: 0.05em;
293
+ }
294
+
295
+ /* Header */
296
+ .header {
297
+ background: white;
298
+ border-radius: var(--radius);
299
+ padding: 2rem;
300
+ margin-bottom: 2rem;
301
+ box-shadow: 0 1px 3px rgba(0,0,0,0.08);
302
+ border: 1px solid var(--slate-200);
303
+ }
304
+
305
+ .header-meta {
306
+ display: flex;
307
+ flex-wrap: wrap;
308
+ gap: 1.5rem;
309
+ margin-top: 1rem;
310
+ font-size: 0.875rem;
311
+ color: var(--slate-500);
312
+ }
313
+
314
+ .header-meta dt { font-weight: 600; color: var(--slate-600); }
315
+ .header-meta dd { font-family: 'IBM Plex Mono', monospace; }
316
+
317
+ /* Verdict badge */
318
+ .verdict {
319
+ display: inline-block;
320
+ padding: 0.5rem 1.5rem;
321
+ border-radius: 999px;
322
+ font-family: 'Space Grotesk', sans-serif;
323
+ font-weight: 700;
324
+ font-size: 1.1rem;
325
+ letter-spacing: 0.05em;
326
+ color: white;
327
+ margin-top: 1rem;
328
+ }
329
+
330
+ /* Scorecards */
331
+ .scorecards {
332
+ display: grid;
333
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
334
+ gap: 1.5rem;
335
+ margin-bottom: 2rem;
336
+ }
337
+
338
+ .scorecard {
339
+ background: white;
340
+ border-radius: var(--radius);
341
+ padding: 1.5rem;
342
+ box-shadow: 0 1px 3px rgba(0,0,0,0.08);
343
+ border: 1px solid var(--slate-200);
344
+ }
345
+
346
+ .scorecard-value {
347
+ font-family: 'Space Grotesk', sans-serif;
348
+ font-size: 2.5rem;
349
+ font-weight: 700;
350
+ margin: 0.5rem 0;
351
+ }
352
+
353
+ .scorecard-label {
354
+ font-size: 0.875rem;
355
+ color: var(--slate-500);
356
+ }
357
+
358
+ .scorecard-detail {
359
+ font-size: 0.8rem;
360
+ color: var(--slate-500);
361
+ margin-top: 0.25rem;
362
+ }
363
+
364
+ /* Buckets */
365
+ .buckets {
366
+ background: white;
367
+ border-radius: var(--radius);
368
+ padding: 1.5rem;
369
+ margin-bottom: 2rem;
370
+ box-shadow: 0 1px 3px rgba(0,0,0,0.08);
371
+ border: 1px solid var(--slate-200);
372
+ }
373
+
374
+ .bucket-row {
375
+ display: flex;
376
+ align-items: center;
377
+ padding: 0.5rem 0;
378
+ border-bottom: 1px solid var(--slate-100);
379
+ }
380
+
381
+ .bucket-row:last-child { border-bottom: none; }
382
+
383
+ .bucket-name {
384
+ flex: 1;
385
+ font-size: 0.9rem;
386
+ color: var(--slate-700);
387
+ }
388
+
389
+ .bucket-bar-wrap {
390
+ flex: 2;
391
+ height: 24px;
392
+ background: var(--slate-100);
393
+ border-radius: 4px;
394
+ overflow: hidden;
395
+ margin: 0 1rem;
396
+ }
397
+
398
+ .bucket-bar {
399
+ height: 100%;
400
+ background: var(--slate-400);
401
+ border-radius: 4px;
402
+ transition: width 0.3s ease;
403
+ }
404
+
405
+ .bucket-count {
406
+ width: 3rem;
407
+ text-align: right;
408
+ font-family: 'IBM Plex Mono', monospace;
409
+ font-size: 0.875rem;
410
+ font-weight: 600;
411
+ color: var(--slate-600);
412
+ }
413
+
414
+ /* Cards */
415
+ .card {
416
+ background: white;
417
+ border-radius: var(--radius);
418
+ margin-bottom: 0.75rem;
419
+ box-shadow: 0 1px 3px rgba(0,0,0,0.08);
420
+ border: 1px solid var(--slate-200);
421
+ overflow: hidden;
422
+ }
423
+
424
+ .card-header {
425
+ display: flex;
426
+ align-items: center;
427
+ gap: 0.75rem;
428
+ padding: 1rem 1.5rem;
429
+ cursor: pointer;
430
+ font-size: 0.9rem;
431
+ list-style: none;
432
+ }
433
+
434
+ .card-header::-webkit-details-marker { display: none; }
435
+ .card-header::before {
436
+ content: '\\25B6';
437
+ font-size: 0.7rem;
438
+ color: var(--slate-400);
439
+ transition: transform 0.2s;
440
+ }
441
+ details[open] > .card-header::before { transform: rotate(90deg); }
442
+
443
+ .card-idx {
444
+ font-family: 'IBM Plex Mono', monospace;
445
+ font-weight: 600;
446
+ color: var(--slate-500);
447
+ min-width: 2.5rem;
448
+ }
449
+
450
+ .card-bucket {
451
+ font-size: 0.8rem;
452
+ color: var(--slate-500);
453
+ background: var(--slate-100);
454
+ padding: 0.15rem 0.5rem;
455
+ border-radius: 4px;
456
+ }
457
+
458
+ .card-utterance {
459
+ flex: 1;
460
+ color: var(--slate-700);
461
+ overflow: hidden;
462
+ text-overflow: ellipsis;
463
+ white-space: nowrap;
464
+ }
465
+
466
+ .card-session {
467
+ font-family: 'IBM Plex Mono', monospace;
468
+ font-size: 0.75rem;
469
+ color: var(--slate-500);
470
+ }
471
+
472
+ .card-body { padding: 0 1.5rem 1.5rem; }
473
+
474
+ .badge-pass {
475
+ background: var(--safe-bg); color: var(--safe); border: 1px solid var(--safe-border);
476
+ padding: 0.15rem 0.5rem; border-radius: 4px; font-size: 0.75rem; font-weight: 600;
477
+ }
478
+ .badge-warn {
479
+ background: var(--review-bg); color: var(--review); border: 1px solid var(--review-border);
480
+ padding: 0.15rem 0.5rem; border-radius: 4px; font-size: 0.75rem; font-weight: 600;
481
+ }
482
+ .badge-fail {
483
+ background: var(--unsafe-bg); color: var(--unsafe); border: 1px solid var(--unsafe-border);
484
+ padding: 0.15rem 0.5rem; border-radius: 4px; font-size: 0.75rem; font-weight: 600;
485
+ }
486
+
487
+ /* Flags */
488
+ .flags { margin-bottom: 1rem; display: flex; flex-wrap: wrap; gap: 0.5rem; }
489
+ .flag {
490
+ font-size: 0.8rem; padding: 0.25rem 0.75rem; border-radius: 6px;
491
+ font-family: 'IBM Plex Mono', monospace;
492
+ }
493
+ .flag-error { background: var(--unsafe-bg); color: var(--unsafe); border: 1px solid var(--unsafe-border); }
494
+ .flag-warn { background: var(--review-bg); color: var(--review); border: 1px solid var(--review-border); }
495
+ .flag-info { background: var(--slate-100); color: var(--slate-600); }
496
+
497
+ /* Comparison */
498
+ .comparison {
499
+ display: grid;
500
+ grid-template-columns: 1fr 1fr;
501
+ gap: 1rem;
502
+ margin-bottom: 1rem;
503
+ }
504
+
505
+ .comp-col {
506
+ background: var(--slate-50);
507
+ border-radius: 8px;
508
+ padding: 1rem;
509
+ border: 1px solid var(--slate-200);
510
+ }
511
+
512
+ .tool-call { margin-bottom: 0.5rem; }
513
+ .tool-name {
514
+ font-family: 'IBM Plex Mono', monospace;
515
+ font-weight: 600;
516
+ font-size: 0.9rem;
517
+ color: var(--slate-800);
518
+ }
519
+
520
+ .tool-args {
521
+ font-family: 'IBM Plex Mono', monospace;
522
+ font-size: 0.8rem;
523
+ background: var(--slate-100);
524
+ padding: 0.5rem;
525
+ border-radius: 4px;
526
+ margin-top: 0.25rem;
527
+ overflow-x: auto;
528
+ white-space: pre-wrap;
529
+ word-break: break-word;
530
+ }
531
+
532
+ .text-resp {
533
+ font-size: 0.85rem;
534
+ color: var(--slate-600);
535
+ font-style: italic;
536
+ }
537
+
538
+ /* Section */
539
+ .section { margin-bottom: 1rem; }
540
+
541
+ .score-table {
542
+ width: 100%;
543
+ font-size: 0.85rem;
544
+ border-collapse: collapse;
545
+ }
546
+ .score-table td {
547
+ padding: 0.3rem 0.5rem;
548
+ border-bottom: 1px solid var(--slate-100);
549
+ }
550
+ .score-table td:first-child { color: var(--slate-500); width: 60%; }
551
+ .score-table td:last-child { font-family: 'IBM Plex Mono', monospace; font-weight: 500; }
552
+
553
+ /* Transcript */
554
+ .transcript-toggle { margin-top: 1rem; }
555
+ .transcript-toggle > summary {
556
+ cursor: pointer;
557
+ font-size: 0.85rem;
558
+ font-weight: 600;
559
+ color: var(--slate-500);
560
+ padding: 0.5rem 0;
561
+ }
562
+
563
+ .transcript {
564
+ max-height: 300px;
565
+ overflow-y: auto;
566
+ margin-top: 0.5rem;
567
+ padding: 0.5rem;
568
+ background: var(--slate-50);
569
+ border-radius: 8px;
570
+ border: 1px solid var(--slate-200);
571
+ }
572
+
573
+ .msg {
574
+ padding: 0.4rem 0.6rem;
575
+ margin-bottom: 0.25rem;
576
+ font-size: 0.8rem;
577
+ border-radius: 4px;
578
+ word-break: break-word;
579
+ }
580
+
581
+ .msg strong { font-size: 0.75rem; text-transform: uppercase; }
582
+ .msg-system { background: #eff6ff; color: #1e40af; }
583
+ .msg-user { background: #f0fdf4; color: #166534; }
584
+ .msg-assistant { background: #fdf4ff; color: #86198f; }
585
+ .msg-info { background: var(--slate-100); color: var(--slate-500); }
586
+
587
+ code {
588
+ font-family: 'IBM Plex Mono', monospace;
589
+ font-size: 0.85em;
590
+ background: var(--slate-100);
591
+ padding: 0.1rem 0.3rem;
592
+ border-radius: 3px;
593
+ }
594
+
595
+ /* Pass rows section */
596
+ .pass-summary {
597
+ background: var(--safe-bg);
598
+ border: 1px solid var(--safe-border);
599
+ border-radius: var(--radius);
600
+ padding: 1rem 1.5rem;
601
+ margin-bottom: 1.5rem;
602
+ color: var(--safe);
603
+ font-weight: 500;
604
+ }
605
+ '''
606
+
607
+
608
+ def build(data):
609
+ """Build HTML report from replay results JSON data."""
610
+ meta = data.get("metadata", {})
611
+ rows = data.get("rows", [])
612
+ recs = data.get("recs", {})
613
+
614
+ routers = [d for d in rows if _is_router(d)]
615
+ actions = [d for d in rows if not _is_router(d)]
616
+
617
+ topic_score = _score_topic(routers)
618
+ action_strict = _score_action_strict(actions)
619
+ action_lenient = _score_action_lenient(actions)
620
+
621
+ # Overall verdict uses lenient action score (functionally equivalent tools count)
622
+ action_score = action_lenient
623
+ if topic_score is not None and action_score is not None:
624
+ overall = round(0.3 * topic_score + 0.7 * action_score, 1)
625
+ elif action_score is not None:
626
+ overall = action_score
627
+ elif topic_score is not None:
628
+ overall = topic_score
629
+ else:
630
+ overall = None
631
+
632
+ verdict_text, verdict_color = _rating(overall)
633
+
634
+ # A row passes if strict pass, args agreement, OR lenient name match (equivalent tool)
635
+ def _row_passes(d):
636
+ return d.get("PassStrict") or d.get("FunctionArgsAgreement") or d.get("FunctionNameAgreementLenient")
637
+
638
+ failing = [d for d in rows if not _row_passes(d)]
639
+ bucket_counts = Counter()
640
+ for d in failing:
641
+ name_hit = d.get("FunctionNameAgreement", False)
642
+ bucket_counts[_bucket(d, name_hit)] += 1
643
+ max_bucket = max(bucket_counts.values()) if bucket_counts else 1
644
+
645
+ passing = [d for d in rows if _row_passes(d)]
646
+
647
+ # Build HTML
648
+ parts = []
649
+ parts.append(f'''<!DOCTYPE html>
650
+ <html lang="en">
651
+ <head>
652
+ <meta charset="utf-8">
653
+ <meta name="viewport" content="width=device-width, initial-scale=1">
654
+ <title>Offline Analysis Report</title>
655
+ <style>{CSS}</style>
656
+ </head>
657
+ <body>
658
+ <div class="container">
659
+ ''')
660
+
661
+ # Header
662
+ parts.append(f'''
663
+ <div class="header">
664
+ <h1>Offline Analysis Report</h1>
665
+ <div class="verdict" style="background:{verdict_color}">{verdict_text}</div>
666
+ <dl class="header-meta">
667
+ <div><dt>Baseline Model</dt><dd>{_esc(meta.get("baseline_model", "N/A"))}</dd></div>
668
+ <div><dt>Replay Model</dt><dd>{_esc(meta.get("replay_model", "N/A"))}</dd></div>
669
+ <div><dt>Org ID</dt><dd>{_esc(meta.get("org_id", "N/A"))}</dd></div>
670
+ <div><dt>Agent</dt><dd>{_esc(meta.get("agent_api_name", "N/A") or "N/A")}</dd></div>
671
+ <div><dt>Total Rows</dt><dd>{meta.get("total_rows", len(rows))}</dd></div>
672
+ <div><dt>Timestamp</dt><dd>{_esc(meta.get("timestamp", ""))}</dd></div>
673
+ </dl>
674
+ </div>
675
+ ''')
676
+
677
+ # Scorecards
678
+ parts.append('<div class="scorecards">')
679
+
680
+ if routers:
681
+ t_verdict, t_color = _rating(topic_score)
682
+ parts.append(f'''
683
+ <div class="scorecard">
684
+ <h3>Routing</h3>
685
+ <div class="scorecard-value" style="color:{t_color}">{topic_score}%</div>
686
+ <div class="scorecard-label">Topic Agreement (Lenient)</div>
687
+ <div class="scorecard-detail">{len(routers)} routing rows &middot; {t_verdict}</div>
688
+ </div>''')
689
+
690
+ if actions:
691
+ a_verdict, a_color = _rating(action_lenient)
692
+ as_verdict, as_color = _rating(action_strict)
693
+ strict_pass = sum(1 for d in actions if d.get("PassStrict"))
694
+ args_agree = sum(1 for d in actions if d.get("FunctionArgsAgreement"))
695
+ name_exact = sum(1 for d in actions if d.get("FunctionNameAgreement"))
696
+ name_lenient = sum(1 for d in actions if d.get("FunctionNameAgreementLenient"))
697
+ parts.append(f'''
698
+ <div class="scorecard">
699
+ <h3>Action Tools (Lenient)</h3>
700
+ <div class="scorecard-value" style="color:{a_color}">{action_lenient}%</div>
701
+ <div class="scorecard-label">Includes functionally equivalent tools</div>
702
+ <div class="scorecard-detail">{len(actions)} action rows &middot; {a_verdict}</div>
703
+ <div class="scorecard-detail">{name_lenient}/{len(actions)} tool match (lenient) &middot; {name_exact}/{len(actions)} exact</div>
704
+ </div>''')
705
+ parts.append(f'''
706
+ <div class="scorecard">
707
+ <h3>Action Tools (Strict)</h3>
708
+ <div class="scorecard-value" style="color:{as_color}">{action_strict}%</div>
709
+ <div class="scorecard-label">Exact name + args agreement</div>
710
+ <div class="scorecard-detail">{strict_pass} strict pass &middot; {args_agree} args agree</div>
711
+ </div>''')
712
+
713
+ # Overall scorecard
714
+ o_verdict, o_color = _rating(overall)
715
+ parts.append(f'''
716
+ <div class="scorecard">
717
+ <h3>Overall</h3>
718
+ <div class="scorecard-value" style="color:{o_color}">{overall if overall is not None else "N/A"}%</div>
719
+ <div class="scorecard-label">Weighted Score</div>
720
+ <div class="scorecard-detail">{len(rows)} total rows &middot; {len(passing)} pass &middot; {len(failing)} fail</div>
721
+ </div>''')
722
+
723
+ parts.append('</div>') # end scorecards
724
+
725
+ # Failure buckets
726
+ if bucket_counts:
727
+ parts.append('<div class="buckets"><h3>Failure Breakdown</h3>')
728
+ for bucket_name, count in bucket_counts.most_common():
729
+ pct = round(100 * count / max_bucket)
730
+ parts.append(f'''
731
+ <div class="bucket-row">
732
+ <span class="bucket-name">{_esc(bucket_name)}</span>
733
+ <div class="bucket-bar-wrap"><div class="bucket-bar" style="width:{pct}%"></div></div>
734
+ <span class="bucket-count">{count}</span>
735
+ </div>''')
736
+ parts.append('</div>')
737
+
738
+ # Passing rows summary
739
+ if passing:
740
+ parts.append(f'<div class="pass-summary">{len(passing)} row(s) passed (strict pass or args agreement)</div>')
741
+
742
+ # Failing row cards
743
+ if failing:
744
+ parts.append(f'<h2>Failing Rows ({len(failing)})</h2>')
745
+ for d in failing:
746
+ idx = d.get("SessionRowIndex", "?")
747
+ rec = recs.get(str(idx), {})
748
+ parts.append(_card(d, rec, idx))
749
+
750
+ # All passing row cards (collapsed section)
751
+ if passing:
752
+ parts.append(f'''
753
+ <details style="margin-top:1.5rem">
754
+ <summary style="cursor:pointer;font-family:'Space Grotesk',sans-serif;font-weight:600;color:var(--slate-500);font-size:1.1rem;padding:0.5rem 0">
755
+ Passing Rows ({len(passing)})
756
+ </summary>
757
+ <div style="margin-top:0.5rem">''')
758
+ for d in passing:
759
+ idx = d.get("SessionRowIndex", "?")
760
+ rec = recs.get(str(idx), {})
761
+ parts.append(_card(d, rec, idx))
762
+ parts.append('</div></details>')
763
+
764
+ parts.append('''
765
+ </div>
766
+ </body>
767
+ </html>''')
768
+
769
+ return "\n".join(parts)
770
+
771
+
772
+ # ---------------------------------------------------------------------------
773
+ # CLI
774
+ # ---------------------------------------------------------------------------
775
+
776
+ def main():
777
+ input_path = sys.argv[1] if len(sys.argv) > 1 else "replay_results.json"
778
+ output_path = sys.argv[2] if len(sys.argv) > 2 else "offline_analysis_report.html"
779
+
780
+ with open(input_path) as f:
781
+ data = json.load(f)
782
+
783
+ html = build(data)
784
+
785
+ with open(output_path, "w") as f:
786
+ f.write(html)
787
+
788
+ rows = data.get("rows", [])
789
+ passing = sum(1 for d in rows
790
+ if d.get("PassStrict") or d.get("FunctionArgsAgreement") or d.get("FunctionNameAgreementLenient"))
791
+ print(f"Report generated: {output_path}")
792
+ print(f" {len(rows)} rows, {passing} passing, {len(rows) - passing} failing")
793
+
794
+
795
+ if __name__ == "__main__":
796
+ main()