@salesforce/afv-skills 1.14.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/applying-slds/SKILL.md +322 -0
- package/skills/applying-slds/checklists.md +83 -0
- package/skills/applying-slds/examples.md +283 -0
- package/skills/applying-slds/guidance/README.md +83 -0
- package/skills/applying-slds/guidance/blueprints-index.md +213 -0
- package/skills/applying-slds/guidance/icons-guidance.md +186 -0
- package/skills/applying-slds/guidance/overviews/borders.md +236 -0
- package/skills/applying-slds/guidance/overviews/color.md +266 -0
- package/skills/applying-slds/guidance/overviews/display-density.md +366 -0
- package/skills/applying-slds/guidance/overviews/icons.md +240 -0
- package/skills/applying-slds/guidance/overviews/illustrations.md +235 -0
- package/skills/applying-slds/guidance/overviews/shadows.md +176 -0
- package/skills/applying-slds/guidance/overviews/spacing.md +216 -0
- package/skills/applying-slds/guidance/overviews/typography.md +323 -0
- package/skills/applying-slds/guidance/overviews/utilities.md +542 -0
- package/skills/applying-slds/guidance/slds-development-guide.md +288 -0
- package/skills/applying-slds/guidance/styling-hooks/borders.md +202 -0
- package/skills/applying-slds/guidance/styling-hooks/color/expressive-palette-hooks.md +153 -0
- package/skills/applying-slds/guidance/styling-hooks/color/index.md +171 -0
- package/skills/applying-slds/guidance/styling-hooks/color/semantic/accent-hooks.md +204 -0
- package/skills/applying-slds/guidance/styling-hooks/color/semantic/feedback-hooks.md +768 -0
- package/skills/applying-slds/guidance/styling-hooks/color/semantic/surface-hooks.md +337 -0
- package/skills/applying-slds/guidance/styling-hooks/color/system-hooks.md +132 -0
- package/skills/applying-slds/guidance/styling-hooks/index.md +327 -0
- package/skills/applying-slds/guidance/styling-hooks/shadows.md +238 -0
- package/skills/applying-slds/guidance/styling-hooks/spacing.md +254 -0
- package/skills/applying-slds/guidance/styling-hooks/typography.md +448 -0
- package/skills/applying-slds/guidance/utilities/alignment.md +119 -0
- package/skills/applying-slds/guidance/utilities/borders.md +131 -0
- package/skills/applying-slds/guidance/utilities/box.md +125 -0
- package/skills/applying-slds/guidance/utilities/color.md +165 -0
- package/skills/applying-slds/guidance/utilities/dark-mode.md +111 -0
- package/skills/applying-slds/guidance/utilities/description-list.md +168 -0
- package/skills/applying-slds/guidance/utilities/floats.md +117 -0
- package/skills/applying-slds/guidance/utilities/grid.md +264 -0
- package/skills/applying-slds/guidance/utilities/horizontal-list.md +110 -0
- package/skills/applying-slds/guidance/utilities/hyphenation.md +84 -0
- package/skills/applying-slds/guidance/utilities/index.md +205 -0
- package/skills/applying-slds/guidance/utilities/interactions.md +89 -0
- package/skills/applying-slds/guidance/utilities/layout.md +109 -0
- package/skills/applying-slds/guidance/utilities/line-clamp.md +131 -0
- package/skills/applying-slds/guidance/utilities/margin.md +155 -0
- package/skills/applying-slds/guidance/utilities/media-object.md +161 -0
- package/skills/applying-slds/guidance/utilities/name-value-list.md +152 -0
- package/skills/applying-slds/guidance/utilities/padding.md +155 -0
- package/skills/applying-slds/guidance/utilities/position.md +177 -0
- package/skills/applying-slds/guidance/utilities/print.md +114 -0
- package/skills/applying-slds/guidance/utilities/scrollable.md +126 -0
- package/skills/applying-slds/guidance/utilities/sizing.md +190 -0
- package/skills/applying-slds/guidance/utilities/themes.md +121 -0
- package/skills/applying-slds/guidance/utilities/truncate.md +127 -0
- package/skills/applying-slds/guidance/utilities/typography.md +166 -0
- package/skills/applying-slds/guidance/utilities/vertical-list.md +166 -0
- package/skills/applying-slds/guidance/utilities/visibility.md +228 -0
- package/skills/applying-slds/metadata/README.md +84 -0
- package/skills/applying-slds/metadata/blueprints/components/accordion.yaml +304 -0
- package/skills/applying-slds/metadata/blueprints/components/activity-timeline.yaml +92 -0
- package/skills/applying-slds/metadata/blueprints/components/alert.yaml +103 -0
- package/skills/applying-slds/metadata/blueprints/components/app-launcher.yaml +94 -0
- package/skills/applying-slds/metadata/blueprints/components/avatar-group.yaml +81 -0
- package/skills/applying-slds/metadata/blueprints/components/avatar.yaml +97 -0
- package/skills/applying-slds/metadata/blueprints/components/badges.yaml +102 -0
- package/skills/applying-slds/metadata/blueprints/components/brand-band.yaml +198 -0
- package/skills/applying-slds/metadata/blueprints/components/breadcrumbs.yaml +95 -0
- package/skills/applying-slds/metadata/blueprints/components/builder-header.yaml +192 -0
- package/skills/applying-slds/metadata/blueprints/components/button-groups.yaml +82 -0
- package/skills/applying-slds/metadata/blueprints/components/button-icons.yaml +295 -0
- package/skills/applying-slds/metadata/blueprints/components/buttons.yaml +230 -0
- package/skills/applying-slds/metadata/blueprints/components/cards.yaml +124 -0
- package/skills/applying-slds/metadata/blueprints/components/carousel.yaml +140 -0
- package/skills/applying-slds/metadata/blueprints/components/chat.yaml +179 -0
- package/skills/applying-slds/metadata/blueprints/components/checkbox-button-group.yaml +192 -0
- package/skills/applying-slds/metadata/blueprints/components/checkbox-button.yaml +204 -0
- package/skills/applying-slds/metadata/blueprints/components/checkbox-toggle.yaml +177 -0
- package/skills/applying-slds/metadata/blueprints/components/checkbox.yaml +108 -0
- package/skills/applying-slds/metadata/blueprints/components/color-picker.yaml +172 -0
- package/skills/applying-slds/metadata/blueprints/components/combobox.yaml +136 -0
- package/skills/applying-slds/metadata/blueprints/components/counter.yaml +147 -0
- package/skills/applying-slds/metadata/blueprints/components/data-tables.yaml +157 -0
- package/skills/applying-slds/metadata/blueprints/components/datepickers.yaml +130 -0
- package/skills/applying-slds/metadata/blueprints/components/datetime-picker.yaml +155 -0
- package/skills/applying-slds/metadata/blueprints/components/docked-composer.yaml +201 -0
- package/skills/applying-slds/metadata/blueprints/components/docked-form-footer.yaml +161 -0
- package/skills/applying-slds/metadata/blueprints/components/docked-utility-bar.yaml +175 -0
- package/skills/applying-slds/metadata/blueprints/components/drop-zone.yaml +115 -0
- package/skills/applying-slds/metadata/blueprints/components/dueling-picklist.yaml +196 -0
- package/skills/applying-slds/metadata/blueprints/components/dynamic-icons.yaml +128 -0
- package/skills/applying-slds/metadata/blueprints/components/dynamic-menu.yaml +141 -0
- package/skills/applying-slds/metadata/blueprints/components/expandable-section.yaml +115 -0
- package/skills/applying-slds/metadata/blueprints/components/expression.yaml +143 -0
- package/skills/applying-slds/metadata/blueprints/components/feeds.yaml +125 -0
- package/skills/applying-slds/metadata/blueprints/components/file-selector.yaml +154 -0
- package/skills/applying-slds/metadata/blueprints/components/files.yaml +119 -0
- package/skills/applying-slds/metadata/blueprints/components/form-element.yaml +145 -0
- package/skills/applying-slds/metadata/blueprints/components/global-header.yaml +120 -0
- package/skills/applying-slds/metadata/blueprints/components/global-navigation.yaml +100 -0
- package/skills/applying-slds/metadata/blueprints/components/icons.yaml +138 -0
- package/skills/applying-slds/metadata/blueprints/components/illustration.yaml +205 -0
- package/skills/applying-slds/metadata/blueprints/components/input.yaml +151 -0
- package/skills/applying-slds/metadata/blueprints/components/list-builder.yaml +127 -0
- package/skills/applying-slds/metadata/blueprints/components/lookups.yaml +132 -0
- package/skills/applying-slds/metadata/blueprints/components/map.yaml +118 -0
- package/skills/applying-slds/metadata/blueprints/components/menus.yaml +134 -0
- package/skills/applying-slds/metadata/blueprints/components/modals.yaml +152 -0
- package/skills/applying-slds/metadata/blueprints/components/notifications.yaml +88 -0
- package/skills/applying-slds/metadata/blueprints/components/page-headers.yaml +135 -0
- package/skills/applying-slds/metadata/blueprints/components/panels.yaml +149 -0
- package/skills/applying-slds/metadata/blueprints/components/path.yaml +154 -0
- package/skills/applying-slds/metadata/blueprints/components/picklist.yaml +125 -0
- package/skills/applying-slds/metadata/blueprints/components/pills.yaml +154 -0
- package/skills/applying-slds/metadata/blueprints/components/popovers.yaml +120 -0
- package/skills/applying-slds/metadata/blueprints/components/progress-bar.yaml +110 -0
- package/skills/applying-slds/metadata/blueprints/components/progress-indicator.yaml +133 -0
- package/skills/applying-slds/metadata/blueprints/components/progress-ring.yaml +102 -0
- package/skills/applying-slds/metadata/blueprints/components/prompt.yaml +126 -0
- package/skills/applying-slds/metadata/blueprints/components/publishers.yaml +178 -0
- package/skills/applying-slds/metadata/blueprints/components/radio-button-group.yaml +172 -0
- package/skills/applying-slds/metadata/blueprints/components/radio-group.yaml +112 -0
- package/skills/applying-slds/metadata/blueprints/components/rich-text-editor.yaml +135 -0
- package/skills/applying-slds/metadata/blueprints/components/scoped-notifications.yaml +188 -0
- package/skills/applying-slds/metadata/blueprints/components/scoped-tabs.yaml +97 -0
- package/skills/applying-slds/metadata/blueprints/components/select.yaml +127 -0
- package/skills/applying-slds/metadata/blueprints/components/setup-assistant.yaml +152 -0
- package/skills/applying-slds/metadata/blueprints/components/slider.yaml +111 -0
- package/skills/applying-slds/metadata/blueprints/components/spinners.yaml +135 -0
- package/skills/applying-slds/metadata/blueprints/components/split-view.yaml +112 -0
- package/skills/applying-slds/metadata/blueprints/components/summary-detail.yaml +103 -0
- package/skills/applying-slds/metadata/blueprints/components/tabs.yaml +138 -0
- package/skills/applying-slds/metadata/blueprints/components/textarea.yaml +116 -0
- package/skills/applying-slds/metadata/blueprints/components/tiles.yaml +108 -0
- package/skills/applying-slds/metadata/blueprints/components/timepicker.yaml +111 -0
- package/skills/applying-slds/metadata/blueprints/components/toast.yaml +154 -0
- package/skills/applying-slds/metadata/blueprints/components/tooltips.yaml +107 -0
- package/skills/applying-slds/metadata/blueprints/components/tree-grid.yaml +116 -0
- package/skills/applying-slds/metadata/blueprints/components/trees.yaml +116 -0
- package/skills/applying-slds/metadata/blueprints/components/trial-bar.yaml +112 -0
- package/skills/applying-slds/metadata/blueprints/components/vertical-navigation.yaml +130 -0
- package/skills/applying-slds/metadata/blueprints/components/vertical-tabs.yaml +140 -0
- package/skills/applying-slds/metadata/blueprints/components/visual-picker.yaml +150 -0
- package/skills/applying-slds/metadata/blueprints/components/welcome-mat.yaml +136 -0
- package/skills/applying-slds/metadata/hooks-index.json +6272 -0
- package/skills/applying-slds/metadata/icon-metadata.json +38466 -0
- package/skills/applying-slds/metadata/utilities-index.json +21912 -0
- package/skills/applying-slds/references/component-selection.md +112 -0
- package/skills/applying-slds/references/icons-decision-guide.md +124 -0
- package/skills/applying-slds/references/styling-decision-guide.md +228 -0
- package/skills/applying-slds/references/utilities-quick-ref.md +125 -0
- package/skills/applying-slds/scripts/search-blueprints.cjs +117 -0
- package/skills/applying-slds/scripts/search-hooks.cjs +139 -0
- package/skills/applying-slds/scripts/search-icons.cjs +174 -0
- package/skills/applying-slds/scripts/search-utilities.cjs +161 -0
- package/skills/generating-custom-lightning-type/SKILL.md +17 -39
- package/skills/generating-custom-lightning-type/assets/primitive-types-and-constraints.md +41 -0
- package/skills/generating-custom-lightning-type/references/widget-rendition.md +124 -0
- package/skills/investigating-agentforce-architecture/README.md +156 -0
- package/skills/investigating-agentforce-architecture/SKILL.md +230 -0
- package/skills/investigating-agentforce-architecture/assets/cli/describe_sobject.yaml +16 -0
- package/skills/investigating-agentforce-architecture/assets/cli/describe_tooling_sobject.yaml +17 -0
- package/skills/investigating-agentforce-architecture/assets/cli/list_metadata_genaiprompttemplate.yaml +17 -0
- package/skills/investigating-agentforce-architecture/assets/cli/org_display.yaml +15 -0
- package/skills/investigating-agentforce-architecture/assets/cli/retrieve_genai_plugin.yaml +18 -0
- package/skills/investigating-agentforce-architecture/assets/cli/show_access_token.yaml +27 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/action_tree.mmd +20 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/data_flow.mmd +19 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/dependency_graph.mmd +19 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/invocation_sequence.mmd +20 -0
- package/skills/investigating-agentforce-architecture/assets/mermaid/planner_state.mmd +18 -0
- package/skills/investigating-agentforce-architecture/assets/soql/apex_class_bodies_by_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/apex_class_bodies_by_names.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/bot_definition_details.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/bot_version_lookup.soql +4 -0
- package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_by_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_ids_by_names.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/flow_definition_view_by_durable_ids.soql +4 -0
- package/skills/investigating-agentforce-architecture/assets/soql/flow_metadata_by_id.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/functions_by_plugins.soql +5 -0
- package/skills/investigating-agentforce-architecture/assets/soql/planner_attrs_by_parent_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/planner_bundle_functions.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/planner_definition_by_agent_chain.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/plugin_functions_by_plugin_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/plugin_instructions_by_plugin_ids.soql +3 -0
- package/skills/investigating-agentforce-architecture/assets/soql/plugins_by_planner.soql +4 -0
- package/skills/investigating-agentforce-architecture/references/architecture_sections.md +243 -0
- package/skills/investigating-agentforce-architecture/references/contract.json +244 -0
- package/skills/investigating-agentforce-architecture/references/soql_fields.md +512 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/__init__.py +1 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/fs_guard.py +329 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/paths.py +110 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/runtime.py +59 -0
- package/skills/investigating-agentforce-architecture/scripts/_shared/sql.py +10 -0
- package/skills/investigating-agentforce-architecture/scripts/cache_check.py +234 -0
- package/skills/investigating-agentforce-architecture/scripts/config.py +131 -0
- package/skills/investigating-agentforce-architecture/scripts/fetch_soql.py +689 -0
- package/skills/investigating-agentforce-architecture/scripts/finalize.py +295 -0
- package/skills/investigating-agentforce-architecture/scripts/main.py +2835 -0
- package/skills/investigating-agentforce-architecture/scripts/metadata_listing.py +265 -0
- package/skills/investigating-agentforce-architecture/scripts/parallel_retrieve.py +69 -0
- package/skills/investigating-agentforce-architecture/scripts/parse_bundle.py +215 -0
- package/skills/investigating-agentforce-architecture/scripts/parse_wave.py +845 -0
- package/skills/investigating-agentforce-architecture/scripts/probe_channels.py +302 -0
- package/skills/investigating-agentforce-architecture/scripts/render_architecture.py +1043 -0
- package/skills/investigating-agentforce-architecture/scripts/resolve_bot.py +255 -0
- package/skills/investigating-agentforce-architecture/scripts/resolve_invocation_target.py +130 -0
- package/skills/investigating-agentforce-architecture/scripts/rest_client.py +763 -0
- package/skills/investigating-agentforce-architecture/scripts/retrieve_planner.py +13 -0
- package/skills/investigating-agentforce-architecture/scripts/sf_cli.py +242 -0
- package/skills/investigating-agentforce-architecture/scripts/soql_loader.py +253 -0
- package/skills/investigating-agentforce-architecture/scripts/summarize_tree.py +143 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/__init__.py +0 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/_bootstrap.py +23 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/fixtures/__init__.py +0 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/fixtures/genai_payloads.py +400 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_cache_check.py +307 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_cache_check_main.py +283 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_config.py +115 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_end_to_end_fixture.py +651 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_finalize.py +278 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_flow_children_inflation.py +582 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_fs_guard.py +113 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_iterative_wave_b.py +478 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_main_pipeline.py +3359 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parallel_retrieve.py +131 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_bundle.py +400 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave.py +644 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_classifiers.py +224 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_helpers.py +380 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_parse_wave_main.py +397 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_per_branch_visited.py +244 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_probe_channels.py +359 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_probe_cli_recipes.py +185 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_render_architecture.py +810 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_bot.py +203 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_creds.py +157 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_resolve_invocation_target.py +145 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_rest_client.py +1253 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_runtime_override.py +100 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_sf_cli.py +261 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_signature_stamping.py +466 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_soql_loader.py +501 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_summarize_tree.py +241 -0
- package/skills/investigating-agentforce-architecture/scripts/tests/test_write_emit_ctx.py +480 -0
- package/skills/investigating-agentforce-architecture/tools/emit_env.py +157 -0
- package/skills/investigating-agentforce-architecture/tools/emit_result.py +262 -0
- package/skills/investigating-agentforce-architecture/tools/sanitize.py +33 -0
- package/skills/investigating-agentforce-architecture/tools/write_emit_ctx.py +332 -0
- package/skills/investigating-agentforce-d360/README.md +123 -0
- package/skills/investigating-agentforce-d360/SKILL.md +163 -0
- package/skills/investigating-agentforce-d360/assets/dc/app_generation.sql +51 -0
- package/skills/investigating-agentforce-d360/assets/dc/content_category.sql +44 -0
- package/skills/investigating-agentforce-d360/assets/dc/content_quality.sql +41 -0
- package/skills/investigating-agentforce-d360/assets/dc/discover_sessions.sql +36 -0
- package/skills/investigating-agentforce-d360/assets/dc/feedback.sql +47 -0
- package/skills/investigating-agentforce-d360/assets/dc/feedback_details.sql +38 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_records.sql +45 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_request_llm.sql +50 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_request_metadata.sql +44 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_request_tags.sql +42 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_requests.sql +89 -0
- package/skills/investigating-agentforce-d360/assets/dc/gateway_responses.sql +43 -0
- package/skills/investigating-agentforce-d360/assets/dc/generations.sql +52 -0
- package/skills/investigating-agentforce-d360/assets/dc/interactions.sql +53 -0
- package/skills/investigating-agentforce-d360/assets/dc/messages.sql +53 -0
- package/skills/investigating-agentforce-d360/assets/dc/messaging_session.sql +37 -0
- package/skills/investigating-agentforce-d360/assets/dc/moment_interactions.sql +34 -0
- package/skills/investigating-agentforce-d360/assets/dc/moments.sql +39 -0
- package/skills/investigating-agentforce-d360/assets/dc/participants.sql +48 -0
- package/skills/investigating-agentforce-d360/assets/dc/sessions.sql +78 -0
- package/skills/investigating-agentforce-d360/assets/dc/steps.sql +64 -0
- package/skills/investigating-agentforce-d360/assets/dc/tag_associations.sql +46 -0
- package/skills/investigating-agentforce-d360/assets/dc/tag_definition_associations.sql +37 -0
- package/skills/investigating-agentforce-d360/assets/dc/tag_definitions.sql +50 -0
- package/skills/investigating-agentforce-d360/assets/dc/tags.sql +37 -0
- package/skills/investigating-agentforce-d360/assets/dc/telemetry_spans.sql +55 -0
- package/skills/investigating-agentforce-d360/references/artifacts.md +50 -0
- package/skills/investigating-agentforce-d360/references/dc_dmo_fields.md +823 -0
- package/skills/investigating-agentforce-d360/references/dc_pipeline_contract.md +608 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/__init__.py +2 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/cli_override.py +98 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/fs_guard.py +334 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/paths.py +155 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/runtime.py +59 -0
- package/skills/investigating-agentforce-d360/scripts/_shared/sql.py +14 -0
- package/skills/investigating-agentforce-d360/scripts/assemble_dc.py +1624 -0
- package/skills/investigating-agentforce-d360/scripts/config.py +45 -0
- package/skills/investigating-agentforce-d360/scripts/dc.py +188 -0
- package/skills/investigating-agentforce-d360/scripts/discover_sessions.py +556 -0
- package/skills/investigating-agentforce-d360/scripts/fetch_dc.py +1045 -0
- package/skills/investigating-agentforce-d360/scripts/render_dc.py +1750 -0
- package/skills/investigating-agentforce-d360/scripts/resolve_session.py +264 -0
- package/skills/investigating-agentforce-d360/scripts/storage.py +92 -0
- package/skills/investigating-agentforce-d360/scripts/tests/__init__.py +0 -0
- package/skills/investigating-agentforce-d360/scripts/tests/_bootstrap.py +15 -0
- package/skills/investigating-agentforce-d360/scripts/tests/fixtures/__init__.py +0 -0
- package/skills/investigating-agentforce-d360/scripts/tests/fixtures/synthetic_session.py +424 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_bootstrap_and_mode.py +115 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_gateway_direct.py +220 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_gateway_direct_integration.py +158 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_helpers.py +287 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_assemble_dc_integration.py +247 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_dc_and_resolve_session.py +433 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_discover_sessions.py +458 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_discover_sessions_grep_ci.py +193 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_helpers.py +266 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_identity.py +528 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_main.py +251 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_waterfall.py +229 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_fetch_dc_waterfall_full.py +283 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_identity_coherence.py +327 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_branches.py +256 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_gateway_direct.py +130 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_helpers.py +291 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_integration.py +220 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_planner_llm_calls.py +284 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_render_dc_show_prompts_gating.py +215 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_resolve_from_disk.py +100 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_resolve_session_main.py +149 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_runtime_override.py +104 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_session_shape.py +95 -0
- package/skills/investigating-agentforce-d360/scripts/tests/test_session_shape_dropped_by_stdm.py +85 -0
- package/skills/managing-managed-event-subscription/SKILL.md +152 -0
- package/skills/managing-managed-event-subscription/assets/managed-event-subscription-template.xml +20 -0
- package/skills/managing-managed-event-subscription/references/delete-guide.md +57 -0
- package/skills/managing-managed-event-subscription/references/topic-name-formats.md +26 -0
- package/skills/managing-managed-event-subscription/references/update-constraints.md +30 -0
- package/skills/uplifting-components-to-slds2/SKILL.md +3 -2
- package/skills/uplifting-components-to-slds2/references/color-hooks-decision-guide.md +30 -9
- package/skills/uplifting-components-to-slds2/references/examples.md +24 -6
- package/skills/validating-slds/SKILL.md +262 -0
- package/skills/validating-slds/references/quality-checks.md +308 -0
- package/skills/validating-slds/references/report-format.md +302 -0
- package/skills/validating-slds/scripts/analyze-quality.cjs +521 -0
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
"""P2.3-3: end-to-end fixture integration tests.
|
|
2
|
+
|
|
3
|
+
Drives `main.main(argv)` against synthetic fixtures — no real org, no
|
|
4
|
+
sf CLI spawn, no HTTP. Every REST/sf boundary is mocked at the
|
|
5
|
+
`main.fetch_*` / `main.run_sf` / `main.probe_channels` surface; all
|
|
6
|
+
layers below (join, parse, render, finalize) run as production code.
|
|
7
|
+
|
|
8
|
+
Tests (one per pipeline path):
|
|
9
|
+
1. classic_react_end_to_end — STATUS=OK, tree + summary + architecture.md
|
|
10
|
+
2. nga_orchestration_end_to_end — NGA reverse-lookup + `par/and` state diagram
|
|
11
|
+
3. cache_hit_end_to_end — poisoned Wave A — must never be called
|
|
12
|
+
4. probe_failed_end_to_end — STATUS=RETRIEVE_FAILED + schema-drift detail
|
|
13
|
+
5. force_refresh_end_to_end — pre-populated fresh cache ignored
|
|
14
|
+
6. render_failure_end_to_end — STATUS=PARTIAL_OK + RENDER_FAILED=true
|
|
15
|
+
|
|
16
|
+
Each test carves its own tempdir for work/cache/data so no cross-test
|
|
17
|
+
state leaks. Assertions focus on the observable surface (RESULT block
|
|
18
|
+
+ on-disk artifacts) rather than on implementation details of
|
|
19
|
+
intermediate steps — the same tests survive a refactor of main.py's
|
|
20
|
+
internal phase ordering.
|
|
21
|
+
"""
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
import os
|
|
26
|
+
import subprocess
|
|
27
|
+
import sys
|
|
28
|
+
import tempfile
|
|
29
|
+
import unittest
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
from unittest import mock
|
|
32
|
+
|
|
33
|
+
from . import _bootstrap # noqa: F401
|
|
34
|
+
|
|
35
|
+
import config # type: ignore
|
|
36
|
+
import soql_loader # type: ignore
|
|
37
|
+
import main # type: ignore
|
|
38
|
+
from tests.fixtures import genai_payloads as fx # type: ignore
|
|
39
|
+
|
|
40
|
+
# SKILL_ROOT is now file-relative in config.py, so config.SOQL_DIR auto-
|
|
41
|
+
# resolves to the repo's assets/soql/ under test. soql_loader still
|
|
42
|
+
# captures SOQL_DIR via `from config import SOQL_DIR` at module top, so
|
|
43
|
+
# we mirror its binding here defensively.
|
|
44
|
+
_REPO_SOQL_DIR = Path(__file__).resolve().parent.parent.parent / "assets" / "soql"
|
|
45
|
+
soql_loader.SOQL_DIR = _REPO_SOQL_DIR
|
|
46
|
+
|
|
47
|
+
# emit_result.py lives under tools/; tests invoke it via subprocess so the
|
|
48
|
+
# tool's RESULT-formatting logic is exercised under the same contract the
|
|
49
|
+
# SKILL.md Bash wrapper uses.
|
|
50
|
+
_TOOLS_DIR = Path(__file__).resolve().parent.parent.parent / "tools"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
# Shared helpers (mirrored from test_main_pipeline — intentionally copied
|
|
55
|
+
# rather than imported, so a refactor of that file doesn't silently change
|
|
56
|
+
# the end-to-end test behavior.)
|
|
57
|
+
# ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _args(work_dir: Path, **overrides) -> list[str]:
|
|
61
|
+
base = [
|
|
62
|
+
"--org-alias", "test-org",
|
|
63
|
+
"--agent", overrides.pop("agent", "MyAgent"),
|
|
64
|
+
"--work-dir", str(work_dir),
|
|
65
|
+
"--parallelism", "2",
|
|
66
|
+
]
|
|
67
|
+
for k, v in overrides.items():
|
|
68
|
+
flag = "--" + k.replace("_", "-")
|
|
69
|
+
if isinstance(v, bool):
|
|
70
|
+
if v:
|
|
71
|
+
base.append(flag)
|
|
72
|
+
else:
|
|
73
|
+
base.extend([flag, str(v)])
|
|
74
|
+
return base
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _mock_auth_probe(probe_result=None):
|
|
78
|
+
probe_result = probe_result or fx.probe_ok_payload()
|
|
79
|
+
org_display_payload = {
|
|
80
|
+
"status": 0,
|
|
81
|
+
"result": {
|
|
82
|
+
"instanceUrl": "https://example.my.salesforce.com",
|
|
83
|
+
"accessToken": "00Dxx0000000000!AQ_fake_token_value",
|
|
84
|
+
"id": "00Dxx0000000000AAA",
|
|
85
|
+
"apiVersion": "60.0",
|
|
86
|
+
},
|
|
87
|
+
}
|
|
88
|
+
return [
|
|
89
|
+
mock.patch.object(main, "run_sf", return_value=org_display_payload),
|
|
90
|
+
mock.patch.object(main, "probe_channels", return_value=probe_result),
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _mock_bot_resolution(agent_api_name="MyAgent", bot_def=None,
|
|
95
|
+
versions=("v5",), active="v5"):
|
|
96
|
+
bot_def = bot_def or fx.BOT_DEFINITION_DETAIL_CLASSIC
|
|
97
|
+
return [
|
|
98
|
+
mock.patch.object(
|
|
99
|
+
main, "fetch_bot_versions",
|
|
100
|
+
return_value=fx.make_bot_versions(agent_api_name, versions, active),
|
|
101
|
+
),
|
|
102
|
+
mock.patch.object(main, "fetch_bot_definition_details", return_value=bot_def),
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _mock_wave_a_classic():
|
|
107
|
+
return [
|
|
108
|
+
mock.patch.object(main, "fetch_planner_definition", return_value=fx.CLASSIC_PLANNER),
|
|
109
|
+
mock.patch.object(main, "fetch_plugins_by_planner", return_value=fx.CLASSIC_PLUGINS),
|
|
110
|
+
mock.patch.object(main, "fetch_planner_bundle_functions", return_value=fx.CLASSIC_BUNDLE_FN_JOIN),
|
|
111
|
+
mock.patch.object(main, "fetch_functions_by_plugins", return_value=fx.CLASSIC_FUNCTIONS),
|
|
112
|
+
mock.patch.object(main, "fetch_plugin_instructions", return_value=fx.CLASSIC_INSTRUCTIONS),
|
|
113
|
+
mock.patch.object(main, "fetch_plugin_functions", return_value=fx.CLASSIC_PLUGIN_FUNCTIONS),
|
|
114
|
+
mock.patch.object(main, "fetch_planner_attrs", return_value=fx.CLASSIC_ATTRS),
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _mock_wave_b_classic():
|
|
119
|
+
return [
|
|
120
|
+
mock.patch.object(main, "fetch_apex_bodies_by_names", return_value=fx.CLASSIC_APEX_ROWS),
|
|
121
|
+
mock.patch.object(main, "fetch_apex_bodies_by_ids", return_value=[]),
|
|
122
|
+
mock.patch.object(main, "fetch_flow_definition_ids_by_names", return_value=fx.CLASSIC_FLOW_DEFS),
|
|
123
|
+
mock.patch.object(main, "fetch_flow_definition_by_ids", return_value=[]),
|
|
124
|
+
mock.patch.object(
|
|
125
|
+
main, "fetch_flow_metadata",
|
|
126
|
+
side_effect=lambda vid, *a, **kw: fx.CLASSIC_FLOW_METADATA.get(vid),
|
|
127
|
+
),
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _mock_wave_a_nga():
|
|
132
|
+
return [
|
|
133
|
+
mock.patch.object(main, "fetch_planner_definition", return_value=fx.NGA_PLANNER),
|
|
134
|
+
mock.patch.object(main, "fetch_plugins_by_planner", return_value=fx.NGA_PLUGINS),
|
|
135
|
+
mock.patch.object(main, "fetch_planner_bundle_functions", return_value=[]),
|
|
136
|
+
mock.patch.object(main, "fetch_functions_by_plugins", return_value=fx.NGA_FUNCTIONS),
|
|
137
|
+
mock.patch.object(main, "fetch_plugin_instructions", return_value=[]),
|
|
138
|
+
mock.patch.object(main, "fetch_plugin_functions", return_value=fx.NGA_PLUGIN_FUNCTIONS),
|
|
139
|
+
mock.patch.object(main, "fetch_planner_attrs", return_value=[]),
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _mock_wave_b_nga():
|
|
144
|
+
return [
|
|
145
|
+
mock.patch.object(main, "fetch_apex_bodies_by_names", return_value=[]),
|
|
146
|
+
mock.patch.object(main, "fetch_apex_bodies_by_ids", return_value=fx.NGA_APEX_BY_ID),
|
|
147
|
+
mock.patch.object(main, "fetch_flow_definition_ids_by_names", return_value=[]),
|
|
148
|
+
mock.patch.object(main, "fetch_flow_definition_by_ids", return_value=fx.NGA_FLOW_DEF_BY_ID),
|
|
149
|
+
mock.patch.object(main, "fetch_flow_metadata", return_value={
|
|
150
|
+
"Id": "301VF999NGAVER", "FullName": "NGAResolvedFlow-1", "Metadata": {},
|
|
151
|
+
}),
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _apply(patches):
|
|
156
|
+
for p in patches:
|
|
157
|
+
p.start()
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _stop(patches):
|
|
161
|
+
for p in patches:
|
|
162
|
+
p.stop()
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _run_emit_result(work_dir: Path) -> subprocess.CompletedProcess:
|
|
166
|
+
"""Drive emit_result.py against the ctx main.py wrote.
|
|
167
|
+
|
|
168
|
+
Exercises the same SKILL.md Bash-wrapper contract: main.py writes
|
|
169
|
+
.emit_ctx.json, emit_result.py reads + renders. Subprocess call so
|
|
170
|
+
the tool runs under a clean env (no leaked test-process state).
|
|
171
|
+
"""
|
|
172
|
+
env = {**os.environ, "WORK_DIR": str(work_dir)}
|
|
173
|
+
return subprocess.run(
|
|
174
|
+
[sys.executable, str(_TOOLS_DIR / "emit_result.py")],
|
|
175
|
+
env=env, capture_output=True, text=True, timeout=30,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _parse_result_block(stdout: str) -> dict:
|
|
180
|
+
"""Pull KV pairs out of the `=== RESULT ===` block."""
|
|
181
|
+
lines = stdout.splitlines()
|
|
182
|
+
out: dict[str, str] = {}
|
|
183
|
+
in_block = False
|
|
184
|
+
for line in lines:
|
|
185
|
+
if line.strip() == "=== RESULT ===":
|
|
186
|
+
in_block = True
|
|
187
|
+
continue
|
|
188
|
+
if in_block and "=" in line:
|
|
189
|
+
k, _, v = line.partition("=")
|
|
190
|
+
out[k] = v
|
|
191
|
+
return out
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
# ---------------------------------------------------------------------------
|
|
195
|
+
# Test 1 — classic ReAct end-to-end
|
|
196
|
+
# ---------------------------------------------------------------------------
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
class ClassicReactEndToEndTests(unittest.TestCase):
|
|
200
|
+
"""P2.3-3: classic ReAct pipeline on MyAgent-v5-shaped fixtures.
|
|
201
|
+
|
|
202
|
+
Asserts observable surface only: on-disk artifacts + RESULT block
|
|
203
|
+
KV pairs. Internal phase ordering can change without breaking this
|
|
204
|
+
test.
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
def test_classic_react_end_to_end_produces_full_artifact_set(self):
|
|
208
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
209
|
+
work_dir = Path(tmp) / "work"
|
|
210
|
+
data_root = Path(tmp) / "data"
|
|
211
|
+
cache_root = Path(tmp) / "cache"
|
|
212
|
+
|
|
213
|
+
patches = [
|
|
214
|
+
*_mock_auth_probe(),
|
|
215
|
+
*_mock_bot_resolution(),
|
|
216
|
+
*_mock_wave_a_classic(),
|
|
217
|
+
*_mock_wave_b_classic(),
|
|
218
|
+
mock.patch.object(
|
|
219
|
+
main, "build_agent_data_dir",
|
|
220
|
+
side_effect=lambda o, a, v: data_root / o / f"{a}__{v}",
|
|
221
|
+
),
|
|
222
|
+
mock.patch.object(
|
|
223
|
+
main, "build_agent_cache_dir",
|
|
224
|
+
side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}",
|
|
225
|
+
),
|
|
226
|
+
]
|
|
227
|
+
_apply(patches)
|
|
228
|
+
try:
|
|
229
|
+
rc = main.main(_args(work_dir))
|
|
230
|
+
finally:
|
|
231
|
+
_stop(patches)
|
|
232
|
+
|
|
233
|
+
self.assertEqual(rc, 0)
|
|
234
|
+
|
|
235
|
+
# --- on-disk artifacts ---
|
|
236
|
+
data_dir = data_root / "00Dxx0000000000" / "MyAgent__v5"
|
|
237
|
+
tree_file = data_dir / "MyAgent_v5_metadata_tree.json"
|
|
238
|
+
arch_file = data_dir / "MyAgent_v5_architecture.md"
|
|
239
|
+
|
|
240
|
+
self.assertTrue(tree_file.is_file(), "metadata_tree.json missing")
|
|
241
|
+
self.assertTrue(arch_file.is_file(), "architecture.md missing")
|
|
242
|
+
# summary.md dropped from the output contract —
|
|
243
|
+
# confirm it is NOT written.
|
|
244
|
+
self.assertFalse(
|
|
245
|
+
(data_dir / "MyAgent_v5_metadata_tree.summary.md").exists(),
|
|
246
|
+
"summary.md should have been dropped from the output contract",
|
|
247
|
+
)
|
|
248
|
+
# rendered architecture filename embeds the agent
|
|
249
|
+
# api name (new convention — proves the rename is wired).
|
|
250
|
+
self.assertTrue(
|
|
251
|
+
arch_file.name.startswith("MyAgent"),
|
|
252
|
+
f"architecture filename should start with agent api name, got {arch_file.name}",
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
tree = json.loads(tree_file.read_text())
|
|
256
|
+
self.assertGreater(tree.get("node_count", 0), 0)
|
|
257
|
+
self.assertEqual(tree["agent"]["generation"], "classic")
|
|
258
|
+
|
|
259
|
+
# --- emit_result RESULT block ---
|
|
260
|
+
r = _run_emit_result(work_dir)
|
|
261
|
+
self.assertEqual(r.returncode, 0, msg=r.stderr)
|
|
262
|
+
block = _parse_result_block(r.stdout)
|
|
263
|
+
self.assertIn(block["STATUS"], ("OK", "PARTIAL_OK"))
|
|
264
|
+
self.assertEqual(block["OUTPUT_ARCHITECTURE_PATH"], str(arch_file))
|
|
265
|
+
self.assertEqual(block["RENDER_FAILED"], "false")
|
|
266
|
+
self.assertGreater(int(block["NODE_COUNT"]), 0)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
# ---------------------------------------------------------------------------
|
|
270
|
+
# Test 2 — NGA end-to-end
|
|
271
|
+
# ---------------------------------------------------------------------------
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
class NgaEndToEndTests(unittest.TestCase):
|
|
275
|
+
"""P2.3-3: NGA ConcurrentMultiAgentOrchestration end-to-end.
|
|
276
|
+
|
|
277
|
+
Exercises the NGA reverse-lookup path (InvocationTarget is a 15/18-
|
|
278
|
+
char Id, not a DeveloperName) and verifies the architecture.md
|
|
279
|
+
carries NGA-specific state-diagram content (`par/and dispatch`).
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
def test_nga_end_to_end_produces_par_state_diagram(self):
|
|
283
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
284
|
+
work_dir = Path(tmp) / "work"
|
|
285
|
+
data_root = Path(tmp) / "data"
|
|
286
|
+
cache_root = Path(tmp) / "cache"
|
|
287
|
+
|
|
288
|
+
patches = [
|
|
289
|
+
*_mock_auth_probe(),
|
|
290
|
+
*_mock_bot_resolution(
|
|
291
|
+
agent_api_name="MyAgent2",
|
|
292
|
+
bot_def=fx.BOT_DEFINITION_DETAIL_NGA,
|
|
293
|
+
),
|
|
294
|
+
*_mock_wave_a_nga(),
|
|
295
|
+
*_mock_wave_b_nga(),
|
|
296
|
+
mock.patch.object(
|
|
297
|
+
main, "build_agent_data_dir",
|
|
298
|
+
side_effect=lambda o, a, v: data_root / o / f"{a}__{v}",
|
|
299
|
+
),
|
|
300
|
+
mock.patch.object(
|
|
301
|
+
main, "build_agent_cache_dir",
|
|
302
|
+
side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}",
|
|
303
|
+
),
|
|
304
|
+
]
|
|
305
|
+
_apply(patches)
|
|
306
|
+
try:
|
|
307
|
+
rc = main.main(_args(work_dir, agent="MyAgent2"))
|
|
308
|
+
finally:
|
|
309
|
+
_stop(patches)
|
|
310
|
+
|
|
311
|
+
self.assertEqual(rc, 0)
|
|
312
|
+
|
|
313
|
+
data_dir = data_root / "00Dxx0000000000" / "MyAgent2__v5"
|
|
314
|
+
tree_file = data_dir / "MyAgent2_v5_metadata_tree.json"
|
|
315
|
+
arch_file = data_dir / "MyAgent2_v5_architecture.md"
|
|
316
|
+
|
|
317
|
+
self.assertTrue(tree_file.is_file())
|
|
318
|
+
self.assertTrue(arch_file.is_file())
|
|
319
|
+
|
|
320
|
+
tree = json.loads(tree_file.read_text())
|
|
321
|
+
self.assertEqual(tree["agent"]["generation"], "nga")
|
|
322
|
+
# NGA reverse-lookup worked — the tree built a TOPIC node for
|
|
323
|
+
# NGATopic1 with 2 GEN_AI_FUNCTION children (Flow + Apex).
|
|
324
|
+
counts = tree["_kind_counts"]
|
|
325
|
+
self.assertEqual(counts.get("TOPIC"), 1)
|
|
326
|
+
self.assertEqual(counts.get("GEN_AI_FUNCTION"), 2)
|
|
327
|
+
|
|
328
|
+
# Architecture.md renders — surface the NGA tell via the
|
|
329
|
+
# Data flow / Topic anatomy sections. The Planner state
|
|
330
|
+
# machine section (which previously carried `par/and
|
|
331
|
+
# dispatch`) was retired from the default pipeline in
|
|
332
|
+
# 2026-05; the NGA-specific state-diagram output is now
|
|
333
|
+
# exercised directly in RenderNgaTests.
|
|
334
|
+
arch_text = arch_file.read_text()
|
|
335
|
+
self.assertIn("NGATopic1", arch_text)
|
|
336
|
+
self.assertIn("NGAFlowAction", arch_text)
|
|
337
|
+
self.assertIn("NGAApexAction", arch_text)
|
|
338
|
+
# Retired section must not appear.
|
|
339
|
+
self.assertNotIn("Planner state machine", arch_text)
|
|
340
|
+
|
|
341
|
+
r = _run_emit_result(work_dir)
|
|
342
|
+
block = _parse_result_block(r.stdout)
|
|
343
|
+
self.assertIn(block["STATUS"], ("OK", "PARTIAL_OK"))
|
|
344
|
+
self.assertEqual(block["AGENT_GENERATION"], "nga")
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
# ---------------------------------------------------------------------------
|
|
348
|
+
# Test 3 — cache hit end-to-end
|
|
349
|
+
# ---------------------------------------------------------------------------
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
class CacheHitEndToEndTests(unittest.TestCase):
|
|
353
|
+
"""P2.3-3: pre-populated fresh cache short-circuits the pipeline.
|
|
354
|
+
|
|
355
|
+
Wave A + Wave B fetchers are poisoned with AssertionError — the
|
|
356
|
+
test fails loudly if main.py attempts any fetch on a cache hit.
|
|
357
|
+
"""
|
|
358
|
+
|
|
359
|
+
def test_cache_hit_end_to_end_skips_all_wave_calls(self):
|
|
360
|
+
import datetime as dt
|
|
361
|
+
|
|
362
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
363
|
+
work_dir = Path(tmp) / "work"
|
|
364
|
+
data_root = Path(tmp) / "data"
|
|
365
|
+
cache_root = Path(tmp) / "cache"
|
|
366
|
+
data_dir = data_root / "00Dxx0000000000" / "MyAgent__v5"
|
|
367
|
+
cache_dir = cache_root / "00Dxx0000000000" / "MyAgent__v5"
|
|
368
|
+
data_dir.mkdir(parents=True)
|
|
369
|
+
cache_dir.mkdir(parents=True)
|
|
370
|
+
|
|
371
|
+
tree_base = "MyAgent_v5_metadata_tree"
|
|
372
|
+
# Minimal tree + architecture.md so the cache-hit emit ctx
|
|
373
|
+
# surfaces an OUTPUT_ARCHITECTURE_PATH.
|
|
374
|
+
# architecture filename is self-identifying.
|
|
375
|
+
(data_dir / f"{tree_base}.json").write_text(json.dumps({
|
|
376
|
+
"_schema_version": "3.0",
|
|
377
|
+
"agent": {"generation": "classic"},
|
|
378
|
+
"root": {"children": []},
|
|
379
|
+
"node_count": 12, "depth": 3,
|
|
380
|
+
"_kind_counts": {}, "_unresolved": [],
|
|
381
|
+
}))
|
|
382
|
+
(data_dir / "MyAgent_v5_architecture.md").write_text("# cached arch\n")
|
|
383
|
+
|
|
384
|
+
from config import SCHEMA_VERSION
|
|
385
|
+
manifest = {
|
|
386
|
+
"built_at_utc": dt.datetime.now(dt.timezone.utc).isoformat().replace("+00:00", "Z"),
|
|
387
|
+
"schema_version": SCHEMA_VERSION,
|
|
388
|
+
"agent": {
|
|
389
|
+
"version": "v5", "bot_id": "0Xa000000000ABC",
|
|
390
|
+
"generation": "classic", "_version_auto_picked": True,
|
|
391
|
+
},
|
|
392
|
+
"node_count": 12, "depth": 3, "kind_counts": {},
|
|
393
|
+
"ttl_days": 7,
|
|
394
|
+
"data_path": str(data_dir / f"{tree_base}.json"),
|
|
395
|
+
"partial": False, "unresolved_count": 0,
|
|
396
|
+
}
|
|
397
|
+
(cache_dir / "manifest.json").write_text(json.dumps(manifest))
|
|
398
|
+
|
|
399
|
+
def _poison(*_a, **_kw):
|
|
400
|
+
raise AssertionError("cache hit MUST NOT invoke any Wave fetcher")
|
|
401
|
+
|
|
402
|
+
poisoned_fetchers = [
|
|
403
|
+
mock.patch.object(main, name, side_effect=_poison)
|
|
404
|
+
for name in (
|
|
405
|
+
"fetch_planner_definition",
|
|
406
|
+
"fetch_plugins_by_planner",
|
|
407
|
+
"fetch_planner_bundle_functions",
|
|
408
|
+
"fetch_functions_by_plugins",
|
|
409
|
+
"fetch_plugin_instructions",
|
|
410
|
+
"fetch_plugin_functions",
|
|
411
|
+
"fetch_planner_attrs",
|
|
412
|
+
"fetch_apex_bodies_by_names",
|
|
413
|
+
"fetch_apex_bodies_by_ids",
|
|
414
|
+
"fetch_flow_definition_ids_by_names",
|
|
415
|
+
"fetch_flow_definition_by_ids",
|
|
416
|
+
"fetch_flow_metadata",
|
|
417
|
+
)
|
|
418
|
+
]
|
|
419
|
+
|
|
420
|
+
patches = [
|
|
421
|
+
*_mock_auth_probe(),
|
|
422
|
+
*_mock_bot_resolution(),
|
|
423
|
+
*poisoned_fetchers,
|
|
424
|
+
mock.patch.object(
|
|
425
|
+
main, "build_agent_data_dir",
|
|
426
|
+
side_effect=lambda o, a, v: data_dir,
|
|
427
|
+
),
|
|
428
|
+
mock.patch.object(
|
|
429
|
+
main, "build_agent_cache_dir",
|
|
430
|
+
side_effect=lambda o, a, v: cache_dir,
|
|
431
|
+
),
|
|
432
|
+
]
|
|
433
|
+
_apply(patches)
|
|
434
|
+
try:
|
|
435
|
+
rc = main.main(_args(work_dir))
|
|
436
|
+
finally:
|
|
437
|
+
_stop(patches)
|
|
438
|
+
|
|
439
|
+
self.assertEqual(rc, 0)
|
|
440
|
+
|
|
441
|
+
r = _run_emit_result(work_dir)
|
|
442
|
+
block = _parse_result_block(r.stdout)
|
|
443
|
+
self.assertEqual(block["STATUS"], "OK")
|
|
444
|
+
self.assertEqual(block["CACHE_HIT"], "true")
|
|
445
|
+
self.assertEqual(int(block["NODE_COUNT"]), 12)
|
|
446
|
+
# Cached architecture.md surfaces as the OUTPUT path.
|
|
447
|
+
# filename embeds agent api name + version.
|
|
448
|
+
self.assertTrue(block["OUTPUT_ARCHITECTURE_PATH"].endswith("MyAgent_v5_architecture.md"))
|
|
449
|
+
self.assertEqual(block["RENDER_FAILED"], "false")
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
# ---------------------------------------------------------------------------
|
|
453
|
+
# Test 4 — probe-failed end-to-end
|
|
454
|
+
# ---------------------------------------------------------------------------
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
class ProbeFailedEndToEndTests(unittest.TestCase):
|
|
458
|
+
"""P2.3-3: channel probe returns PROBE_FAILED -> RETRIEVE_FAILED.
|
|
459
|
+
|
|
460
|
+
Verifies Batch 2.1 remediation: schema-drift manifests as
|
|
461
|
+
STATUS=RETRIEVE_FAILED with ERROR_DETAIL containing `schema-drift`
|
|
462
|
+
rather than a fabricated SCHEMA_DRIFT enum value. The emit_result
|
|
463
|
+
STATUS enum doesn't include SCHEMA_DRIFT, so mapping to
|
|
464
|
+
RETRIEVE_FAILED preserves the existing contract while surfacing
|
|
465
|
+
the cause in ERROR_DETAIL.
|
|
466
|
+
"""
|
|
467
|
+
|
|
468
|
+
def test_probe_failed_end_to_end_emits_retrieve_failed(self):
|
|
469
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
470
|
+
work_dir = Path(tmp) / "work"
|
|
471
|
+
|
|
472
|
+
patches = _mock_auth_probe(
|
|
473
|
+
probe_result=fx.probe_failed_payload(
|
|
474
|
+
sobject="GenAiPlannerDefinition",
|
|
475
|
+
missing=["PlannerType", "DeveloperName"],
|
|
476
|
+
),
|
|
477
|
+
)
|
|
478
|
+
_apply(patches)
|
|
479
|
+
try:
|
|
480
|
+
rc = main.main(_args(work_dir))
|
|
481
|
+
finally:
|
|
482
|
+
_stop(patches)
|
|
483
|
+
|
|
484
|
+
# Pipeline returns nonzero on terminal failure — matches the
|
|
485
|
+
# SKILL.md Bash wrapper's set +e / capture _rc / exit _rc
|
|
486
|
+
# contract.
|
|
487
|
+
self.assertEqual(rc, 1)
|
|
488
|
+
|
|
489
|
+
r = _run_emit_result(work_dir)
|
|
490
|
+
self.assertEqual(r.returncode, 0, msg=r.stderr)
|
|
491
|
+
block = _parse_result_block(r.stdout)
|
|
492
|
+
self.assertEqual(block["STATUS"], "RETRIEVE_FAILED")
|
|
493
|
+
self.assertIn("schema-drift", block["ERROR_DETAIL"])
|
|
494
|
+
# The specific missing fields surface in the detail string
|
|
495
|
+
# (first 3 only per main.py's truncation).
|
|
496
|
+
self.assertIn("PlannerType", block["ERROR_DETAIL"])
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
# ---------------------------------------------------------------------------
|
|
500
|
+
# Test 5 — --force end-to-end
|
|
501
|
+
# ---------------------------------------------------------------------------
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
class ForceRefreshEndToEndTests(unittest.TestCase):
|
|
505
|
+
"""P2.3-3: fresh cache + --force -> full pipeline runs, cache supersedes.
|
|
506
|
+
|
|
507
|
+
Asserts:
|
|
508
|
+
* Wave A fetcher was invoked exactly once (cache was NOT used).
|
|
509
|
+
* CACHE_HIT=false in the RESULT block.
|
|
510
|
+
* Post-run manifest differs from pre-run manifest (node_count
|
|
511
|
+
reflects the live-fetched tree, not the 999-node placeholder).
|
|
512
|
+
"""
|
|
513
|
+
|
|
514
|
+
def test_force_refresh_bypasses_fresh_cache(self):
|
|
515
|
+
import datetime as dt
|
|
516
|
+
|
|
517
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
518
|
+
work_dir = Path(tmp) / "work"
|
|
519
|
+
data_root = Path(tmp) / "data"
|
|
520
|
+
cache_root = Path(tmp) / "cache"
|
|
521
|
+
data_dir = data_root / "00Dxx0000000000" / "MyAgent__v5"
|
|
522
|
+
cache_dir = cache_root / "00Dxx0000000000" / "MyAgent__v5"
|
|
523
|
+
data_dir.mkdir(parents=True)
|
|
524
|
+
cache_dir.mkdir(parents=True)
|
|
525
|
+
(data_dir / "MyAgent_v5_metadata_tree.json").write_text("{}")
|
|
526
|
+
|
|
527
|
+
from config import SCHEMA_VERSION
|
|
528
|
+
stale_manifest = {
|
|
529
|
+
"built_at_utc": dt.datetime.now(dt.timezone.utc).isoformat().replace("+00:00", "Z"),
|
|
530
|
+
"schema_version": SCHEMA_VERSION,
|
|
531
|
+
"agent": {"version": "v5"},
|
|
532
|
+
# Bogus node count to detect whether the cache path or
|
|
533
|
+
# the live-fetched tree won.
|
|
534
|
+
"node_count": 999, "depth": 99, "kind_counts": {},
|
|
535
|
+
"ttl_days": 7,
|
|
536
|
+
"data_path": str(data_dir / "MyAgent_v5_metadata_tree.json"),
|
|
537
|
+
"partial": False, "unresolved_count": 0,
|
|
538
|
+
}
|
|
539
|
+
(cache_dir / "manifest.json").write_text(json.dumps(stale_manifest))
|
|
540
|
+
|
|
541
|
+
patches = [
|
|
542
|
+
*_mock_auth_probe(),
|
|
543
|
+
*_mock_bot_resolution(),
|
|
544
|
+
*_mock_wave_a_classic(),
|
|
545
|
+
*_mock_wave_b_classic(),
|
|
546
|
+
mock.patch.object(
|
|
547
|
+
main, "build_agent_data_dir",
|
|
548
|
+
side_effect=lambda o, a, v: data_dir,
|
|
549
|
+
),
|
|
550
|
+
mock.patch.object(
|
|
551
|
+
main, "build_agent_cache_dir",
|
|
552
|
+
side_effect=lambda o, a, v: cache_dir,
|
|
553
|
+
),
|
|
554
|
+
]
|
|
555
|
+
_apply(patches)
|
|
556
|
+
try:
|
|
557
|
+
rc = main.main(_args(work_dir, force=True))
|
|
558
|
+
planner_calls = main.fetch_planner_definition.call_count
|
|
559
|
+
finally:
|
|
560
|
+
_stop(patches)
|
|
561
|
+
|
|
562
|
+
self.assertEqual(rc, 0)
|
|
563
|
+
# Wave A actually fired — cache was NOT consulted.
|
|
564
|
+
self.assertEqual(planner_calls, 1)
|
|
565
|
+
|
|
566
|
+
# Manifest on disk post-run reflects the live fetch, not the
|
|
567
|
+
# 999-node placeholder.
|
|
568
|
+
post_manifest = json.loads((cache_dir / "manifest.json").read_text())
|
|
569
|
+
self.assertNotEqual(post_manifest.get("node_count"), 999)
|
|
570
|
+
self.assertGreater(post_manifest.get("node_count", 0), 0)
|
|
571
|
+
|
|
572
|
+
r = _run_emit_result(work_dir)
|
|
573
|
+
block = _parse_result_block(r.stdout)
|
|
574
|
+
self.assertIn(block["STATUS"], ("OK", "PARTIAL_OK"))
|
|
575
|
+
self.assertEqual(block["CACHE_HIT"], "false")
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
# ---------------------------------------------------------------------------
|
|
579
|
+
# Test 6 — render failure end-to-end
|
|
580
|
+
# ---------------------------------------------------------------------------
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
class RenderFailureEndToEndTests(unittest.TestCase):
|
|
584
|
+
"""P2.3-3: renderer raises -> tree OK, architecture.md.error sidecar,
|
|
585
|
+
STATUS=PARTIAL_OK, RENDER_FAILED=true in RESULT block.
|
|
586
|
+
|
|
587
|
+
contract. The pipeline does NOT abort on render failure —
|
|
588
|
+
the tree JSON is the authoritative output; architecture.md is
|
|
589
|
+
derived. This test asserts the signalling: downstream consumers can
|
|
590
|
+
distinguish "headline diagram missing" from "pipeline succeeded
|
|
591
|
+
cleanly" via RENDER_FAILED + the sidecar.
|
|
592
|
+
"""
|
|
593
|
+
|
|
594
|
+
def test_render_failure_end_to_end_surfaces_partial_ok(self):
|
|
595
|
+
import render_architecture # type: ignore
|
|
596
|
+
|
|
597
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
598
|
+
work_dir = Path(tmp) / "work"
|
|
599
|
+
data_root = Path(tmp) / "data"
|
|
600
|
+
cache_root = Path(tmp) / "cache"
|
|
601
|
+
|
|
602
|
+
def _boom(*_a, **_kw):
|
|
603
|
+
raise RuntimeError("render exploded for end-to-end test")
|
|
604
|
+
|
|
605
|
+
patches = [
|
|
606
|
+
*_mock_auth_probe(),
|
|
607
|
+
*_mock_bot_resolution(),
|
|
608
|
+
*_mock_wave_a_classic(),
|
|
609
|
+
*_mock_wave_b_classic(),
|
|
610
|
+
mock.patch.object(
|
|
611
|
+
main, "build_agent_data_dir",
|
|
612
|
+
side_effect=lambda o, a, v: data_root / o / f"{a}__{v}",
|
|
613
|
+
),
|
|
614
|
+
mock.patch.object(
|
|
615
|
+
main, "build_agent_cache_dir",
|
|
616
|
+
side_effect=lambda o, a, v: cache_root / o / f"{a}__{v}",
|
|
617
|
+
),
|
|
618
|
+
mock.patch.object(render_architecture, "render", side_effect=_boom),
|
|
619
|
+
]
|
|
620
|
+
_apply(patches)
|
|
621
|
+
try:
|
|
622
|
+
rc = main.main(_args(work_dir))
|
|
623
|
+
finally:
|
|
624
|
+
_stop(patches)
|
|
625
|
+
|
|
626
|
+
self.assertEqual(rc, 0)
|
|
627
|
+
|
|
628
|
+
data_dir = data_root / "00Dxx0000000000" / "MyAgent__v5"
|
|
629
|
+
# Sidecar landed, architecture.md did NOT.
|
|
630
|
+
# filenames are self-identifying.
|
|
631
|
+
self.assertTrue((data_dir / "MyAgent_v5_architecture.md.error").is_file())
|
|
632
|
+
self.assertFalse((data_dir / "MyAgent_v5_architecture.md").is_file())
|
|
633
|
+
# Tree JSON DID land — the render failure is isolated to the
|
|
634
|
+
# derived artifact.
|
|
635
|
+
self.assertTrue(
|
|
636
|
+
(data_dir / "MyAgent_v5_metadata_tree.json").is_file()
|
|
637
|
+
)
|
|
638
|
+
|
|
639
|
+
r = _run_emit_result(work_dir)
|
|
640
|
+
block = _parse_result_block(r.stdout)
|
|
641
|
+
# emit_result auto-promotes OK -> PARTIAL_OK on render failure
|
|
642
|
+
# (see build_block .2-R1).
|
|
643
|
+
self.assertEqual(block["STATUS"], "PARTIAL_OK")
|
|
644
|
+
self.assertEqual(block["RENDER_FAILED"], "true")
|
|
645
|
+
self.assertEqual(block["OUTPUT_ARCHITECTURE_PATH"], "")
|
|
646
|
+
self.assertIn("RENDER_ERROR_DETAIL", block)
|
|
647
|
+
self.assertTrue(block["RENDER_ERROR_DETAIL"]) # non-empty
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
if __name__ == "__main__":
|
|
651
|
+
unittest.main()
|