llm-sca-tooling 0.1.0__py3-none-any.whl
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.
- llm_sca_tooling/__init__.py +5 -0
- llm_sca_tooling/blast_radius/__init__.py +42 -0
- llm_sca_tooling/blast_radius/abi_impact.py +74 -0
- llm_sca_tooling/blast_radius/ambiguous_links.py +46 -0
- llm_sca_tooling/blast_radius/change_type.py +99 -0
- llm_sca_tooling/blast_radius/cross_repo.py +117 -0
- llm_sca_tooling/blast_radius/doc_spec_impact.py +70 -0
- llm_sca_tooling/blast_radius/generated_stub.py +60 -0
- llm_sca_tooling/blast_radius/graph_traversal.py +263 -0
- llm_sca_tooling/blast_radius/impact_groups.py +33 -0
- llm_sca_tooling/blast_radius/models.py +152 -0
- llm_sca_tooling/blast_radius/report.py +125 -0
- llm_sca_tooling/blast_radius/sarif_reachability.py +59 -0
- llm_sca_tooling/blast_radius/service.py +222 -0
- llm_sca_tooling/blast_radius/traversal_policy.py +192 -0
- llm_sca_tooling/cli/__init__.py +1 -0
- llm_sca_tooling/cli/indexing.py +67 -0
- llm_sca_tooling/cli/main.py +594 -0
- llm_sca_tooling/cli/setup_cmd.py +310 -0
- llm_sca_tooling/config.py +212 -0
- llm_sca_tooling/errors.py +31 -0
- llm_sca_tooling/evaluation/__init__.py +75 -0
- llm_sca_tooling/evaluation/ai_readiness.py +116 -0
- llm_sca_tooling/evaluation/artefact_writer.py +110 -0
- llm_sca_tooling/evaluation/benchmark_adapter.py +122 -0
- llm_sca_tooling/evaluation/contamination.py +22 -0
- llm_sca_tooling/evaluation/fl_metrics.py +118 -0
- llm_sca_tooling/evaluation/flaky_detector.py +43 -0
- llm_sca_tooling/evaluation/harness_condition.py +115 -0
- llm_sca_tooling/evaluation/maintainability_oracle.py +61 -0
- llm_sca_tooling/evaluation/models.py +244 -0
- llm_sca_tooling/evaluation/operational_metrics.py +66 -0
- llm_sca_tooling/evaluation/perturbation_runner.py +12 -0
- llm_sca_tooling/evaluation/rds_features.py +105 -0
- llm_sca_tooling/evaluation/regression_adapter.py +54 -0
- llm_sca_tooling/evaluation/replay.py +18 -0
- llm_sca_tooling/evaluation/smoke_adapter.py +177 -0
- llm_sca_tooling/evaluation/store.py +69 -0
- llm_sca_tooling/evaluation/t1_runner.py +213 -0
- llm_sca_tooling/evaluation/t2_runner.py +18 -0
- llm_sca_tooling/evaluation/t3_runner.py +99 -0
- llm_sca_tooling/evaluation/t4_runner.py +93 -0
- llm_sca_tooling/fl/__init__.py +28 -0
- llm_sca_tooling/fl/blame_prior.py +155 -0
- llm_sca_tooling/fl/context_assembler.py +216 -0
- llm_sca_tooling/fl/embedding_adapters/__init__.py +5 -0
- llm_sca_tooling/fl/embedding_adapters/local_adapter.py +60 -0
- llm_sca_tooling/fl/embedding_adapters/null_adapter.py +26 -0
- llm_sca_tooling/fl/embedding_adapters/openai_adapter.py +27 -0
- llm_sca_tooling/fl/embedding_interface.py +100 -0
- llm_sca_tooling/fl/graph_expansion.py +139 -0
- llm_sca_tooling/fl/investigate.py +167 -0
- llm_sca_tooling/fl/issue.py +355 -0
- llm_sca_tooling/fl/keyword_retrieval.py +324 -0
- llm_sca_tooling/fl/localisation.py +318 -0
- llm_sca_tooling/fl/memory_stub.py +42 -0
- llm_sca_tooling/fl/models.py +172 -0
- llm_sca_tooling/fl/ranking.py +157 -0
- llm_sca_tooling/fl/reasoning.py +97 -0
- llm_sca_tooling/fl/sarif_prior.py +182 -0
- llm_sca_tooling/fl/sbfl.py +214 -0
- llm_sca_tooling/fl/uncertainty.py +88 -0
- llm_sca_tooling/fl/vector_cache.py +215 -0
- llm_sca_tooling/governance/__init__.py +14 -0
- llm_sca_tooling/governance/permissions.py +73 -0
- llm_sca_tooling/governance/policy.py +97 -0
- llm_sca_tooling/graph/__init__.py +1 -0
- llm_sca_tooling/hardening/__init__.py +21 -0
- llm_sca_tooling/hardening/cache_invalidation.py +55 -0
- llm_sca_tooling/hardening/cumulative_risk.py +84 -0
- llm_sca_tooling/hardening/file_watcher.py +22 -0
- llm_sca_tooling/hardening/git_hooks.py +48 -0
- llm_sca_tooling/hardening/graph_chunker.py +37 -0
- llm_sca_tooling/hardening/harness_drift.py +78 -0
- llm_sca_tooling/hardening/manifest_regression_runner.py +28 -0
- llm_sca_tooling/hardening/models.py +155 -0
- llm_sca_tooling/hardening/permission_profiles.py +78 -0
- llm_sca_tooling/hardening/subscription_recovery.py +29 -0
- llm_sca_tooling/hardening/task_authorization.py +28 -0
- llm_sca_tooling/hardening/trace_redaction_audit.py +17 -0
- llm_sca_tooling/harness/__init__.py +5 -0
- llm_sca_tooling/harness/condition.py +169 -0
- llm_sca_tooling/indexing/__init__.py +15 -0
- llm_sca_tooling/indexing/backends/__init__.py +1 -0
- llm_sca_tooling/indexing/backends/base.py +104 -0
- llm_sca_tooling/indexing/backends/capability.py +9 -0
- llm_sca_tooling/indexing/backends/cpp/__init__.py +5 -0
- llm_sca_tooling/indexing/backends/cpp/abi_edge_builder.py +23 -0
- llm_sca_tooling/indexing/backends/cpp/clangd_adapter.py +238 -0
- llm_sca_tooling/indexing/backends/cpp/cmake_backend.py +26 -0
- llm_sca_tooling/indexing/backends/cpp/compile_commands.py +55 -0
- llm_sca_tooling/indexing/backends/cpp/cpp_backend.py +131 -0
- llm_sca_tooling/indexing/backends/cpp/ctest_detection.py +30 -0
- llm_sca_tooling/indexing/backends/cpp/libclang_adapter.py +272 -0
- llm_sca_tooling/indexing/backends/cross_check.py +77 -0
- llm_sca_tooling/indexing/backends/ctags.py +166 -0
- llm_sca_tooling/indexing/backends/fact_reconciler.py +109 -0
- llm_sca_tooling/indexing/backends/java/__init__.py +5 -0
- llm_sca_tooling/indexing/backends/java/capability.py +3 -0
- llm_sca_tooling/indexing/backends/java/java_backend.py +63 -0
- llm_sca_tooling/indexing/backends/java/jdt_adapter.py +17 -0
- llm_sca_tooling/indexing/backends/python/__init__.py +5 -0
- llm_sca_tooling/indexing/backends/python/import_resolver.py +14 -0
- llm_sca_tooling/indexing/backends/python/pyan3_adapter.py +172 -0
- llm_sca_tooling/indexing/backends/python/pyright_adapter.py +236 -0
- llm_sca_tooling/indexing/backends/python/python_backend.py +120 -0
- llm_sca_tooling/indexing/backends/python_ast.py +535 -0
- llm_sca_tooling/indexing/backends/registry.py +43 -0
- llm_sca_tooling/indexing/backends/tree_sitter.py +60 -0
- llm_sca_tooling/indexing/backends/typescript/__init__.py +5 -0
- llm_sca_tooling/indexing/backends/typescript/madge_adapter.py +82 -0
- llm_sca_tooling/indexing/backends/typescript/module_resolver.py +123 -0
- llm_sca_tooling/indexing/backends/typescript/package_meta.py +27 -0
- llm_sca_tooling/indexing/backends/typescript/ts_backend.py +120 -0
- llm_sca_tooling/indexing/backends/typescript/ts_test_detection.py +36 -0
- llm_sca_tooling/indexing/backends/typescript/tsmorph_adapter.py +282 -0
- llm_sca_tooling/indexing/backends/utils.py +118 -0
- llm_sca_tooling/indexing/blame.py +158 -0
- llm_sca_tooling/indexing/build_evidence.py +216 -0
- llm_sca_tooling/indexing/config.py +22 -0
- llm_sca_tooling/indexing/diagnostics.py +65 -0
- llm_sca_tooling/indexing/git_metadata.py +137 -0
- llm_sca_tooling/indexing/graph_slices.py +44 -0
- llm_sca_tooling/indexing/hashing.py +18 -0
- llm_sca_tooling/indexing/ignore.py +108 -0
- llm_sca_tooling/indexing/lsp/__init__.py +6 -0
- llm_sca_tooling/indexing/lsp/capabilities.py +27 -0
- llm_sca_tooling/indexing/lsp/client.py +90 -0
- llm_sca_tooling/indexing/lsp/errors.py +13 -0
- llm_sca_tooling/indexing/lsp/lifecycle.py +38 -0
- llm_sca_tooling/indexing/lsp/protocol.py +17 -0
- llm_sca_tooling/indexing/lsp/request_dispatcher.py +96 -0
- llm_sca_tooling/indexing/manifests.py +100 -0
- llm_sca_tooling/indexing/pipeline.py +5 -0
- llm_sca_tooling/indexing/provenance.py +11 -0
- llm_sca_tooling/indexing/result.py +47 -0
- llm_sca_tooling/indexing/scanner.py +321 -0
- llm_sca_tooling/indexing/service.py +696 -0
- llm_sca_tooling/indexing/snapshots.py +31 -0
- llm_sca_tooling/indexing/summaries.py +82 -0
- llm_sca_tooling/mcp_server/__init__.py +6 -0
- llm_sca_tooling/mcp_server/capabilities.py +42 -0
- llm_sca_tooling/mcp_server/config.py +36 -0
- llm_sca_tooling/mcp_server/context.py +22 -0
- llm_sca_tooling/mcp_server/dev_server.py +60 -0
- llm_sca_tooling/mcp_server/errors.py +86 -0
- llm_sca_tooling/mcp_server/notifications.py +47 -0
- llm_sca_tooling/mcp_server/prompt_registry.py +181 -0
- llm_sca_tooling/mcp_server/prompts/bug_resolve.md +67 -0
- llm_sca_tooling/mcp_server/prompts/evaluate.md +10 -0
- llm_sca_tooling/mcp_server/prompts/implementation_check.md +56 -0
- llm_sca_tooling/mcp_server/prompts/investigate.md +27 -0
- llm_sca_tooling/mcp_server/prompts/operational_review.md +18 -0
- llm_sca_tooling/mcp_server/prompts/patch_review.md +5 -0
- llm_sca_tooling/mcp_server/prompts/readiness_audit.md +17 -0
- llm_sca_tooling/mcp_server/prompts.py +12 -0
- llm_sca_tooling/mcp_server/resource_registry.py +101 -0
- llm_sca_tooling/mcp_server/resource_uris.py +41 -0
- llm_sca_tooling/mcp_server/resources/__init__.py +5 -0
- llm_sca_tooling/mcp_server/resources/blame.py +48 -0
- llm_sca_tooling/mcp_server/resources/core.py +440 -0
- llm_sca_tooling/mcp_server/resources/eval.py +94 -0
- llm_sca_tooling/mcp_server/resources/interfaces.py +104 -0
- llm_sca_tooling/mcp_server/resources/memory.py +101 -0
- llm_sca_tooling/mcp_server/resources/sarif.py +96 -0
- llm_sca_tooling/mcp_server/sampling.py +28 -0
- llm_sca_tooling/mcp_server/serialization.py +24 -0
- llm_sca_tooling/mcp_server/server.py +192 -0
- llm_sca_tooling/mcp_server/subscriptions.py +57 -0
- llm_sca_tooling/mcp_server/task_ids.py +9 -0
- llm_sca_tooling/mcp_server/task_runner.py +115 -0
- llm_sca_tooling/mcp_server/task_store.py +204 -0
- llm_sca_tooling/mcp_server/tasks.py +57 -0
- llm_sca_tooling/mcp_server/telemetry.py +79 -0
- llm_sca_tooling/mcp_server/tool_permissions.py +20 -0
- llm_sca_tooling/mcp_server/tool_registry.py +72 -0
- llm_sca_tooling/mcp_server/tools/__init__.py +5 -0
- llm_sca_tooling/mcp_server/tools/blame.py +90 -0
- llm_sca_tooling/mcp_server/tools/core.py +519 -0
- llm_sca_tooling/mcp_server/tools/eval.py +335 -0
- llm_sca_tooling/mcp_server/tools/fl.py +142 -0
- llm_sca_tooling/mcp_server/tools/impl_check.py +120 -0
- llm_sca_tooling/mcp_server/tools/interface.py +297 -0
- llm_sca_tooling/mcp_server/tools/issue_resolution.py +153 -0
- llm_sca_tooling/mcp_server/tools/memory.py +398 -0
- llm_sca_tooling/mcp_server/tools/operational_review.py +89 -0
- llm_sca_tooling/mcp_server/tools/patch_review.py +300 -0
- llm_sca_tooling/mcp_server/tools/qa.py +178 -0
- llm_sca_tooling/mcp_server/tools/readiness_audit.py +88 -0
- llm_sca_tooling/mcp_server/tools/sarif.py +157 -0
- llm_sca_tooling/mcp_server/tools/sast_repair.py +340 -0
- llm_sca_tooling/mcp_server/tools/traces.py +202 -0
- llm_sca_tooling/memory/__init__.py +31 -0
- llm_sca_tooling/memory/errors.py +19 -0
- llm_sca_tooling/memory/eviction/__init__.py +5 -0
- llm_sca_tooling/memory/eviction/compactor.py +140 -0
- llm_sca_tooling/memory/models.py +286 -0
- llm_sca_tooling/memory/promotion/__init__.py +5 -0
- llm_sca_tooling/memory/promotion/pipeline.py +77 -0
- llm_sca_tooling/memory/redaction.py +46 -0
- llm_sca_tooling/memory/relabelling/__init__.py +6 -0
- llm_sca_tooling/memory/relabelling/interface.py +18 -0
- llm_sca_tooling/memory/relabelling/null_relabeller.py +32 -0
- llm_sca_tooling/memory/retrieval/__init__.py +13 -0
- llm_sca_tooling/memory/retrieval/coarse.py +48 -0
- llm_sca_tooling/memory/retrieval/fine.py +65 -0
- llm_sca_tooling/memory/retrieval/interface.py +27 -0
- llm_sca_tooling/memory/retrieval/misalignment_guard.py +33 -0
- llm_sca_tooling/memory/ship_gate.py +31 -0
- llm_sca_tooling/memory/store.py +236 -0
- llm_sca_tooling/memory/write_path.py +97 -0
- llm_sca_tooling/operations/__init__.py +29 -0
- llm_sca_tooling/operations/budget.py +88 -0
- llm_sca_tooling/operations/ledger_delete.py +112 -0
- llm_sca_tooling/operations/ledger_export.py +84 -0
- llm_sca_tooling/operations/ledger_retention.py +37 -0
- llm_sca_tooling/operations/run_records.py +175 -0
- llm_sca_tooling/patch_review/__init__.py +46 -0
- llm_sca_tooling/patch_review/ast_diff.py +142 -0
- llm_sca_tooling/patch_review/diff_parser.py +129 -0
- llm_sca_tooling/patch_review/dryrun.py +189 -0
- llm_sca_tooling/patch_review/four_agent_audit.py +56 -0
- llm_sca_tooling/patch_review/graph_context.py +101 -0
- llm_sca_tooling/patch_review/interface_compat.py +109 -0
- llm_sca_tooling/patch_review/maintainability_gate.py +53 -0
- llm_sca_tooling/patch_review/merge_policy.py +48 -0
- llm_sca_tooling/patch_review/models.py +369 -0
- llm_sca_tooling/patch_review/operational_integration.py +74 -0
- llm_sca_tooling/patch_review/report.py +337 -0
- llm_sca_tooling/patch_review/risk_classifier.py +122 -0
- llm_sca_tooling/patch_review/risk_features.py +55 -0
- llm_sca_tooling/patch_review/risk_policy.py +158 -0
- llm_sca_tooling/patch_review/sampling_integration.py +100 -0
- llm_sca_tooling/patch_review/sarif_delta.py +99 -0
- llm_sca_tooling/patch_review/scope_audit.py +113 -0
- llm_sca_tooling/patch_review/symbol_detector.py +138 -0
- llm_sca_tooling/patch_review/test_delta.py +97 -0
- llm_sca_tooling/plugins/__init__.py +9 -0
- llm_sca_tooling/plugins/backlog/__init__.py +128 -0
- llm_sca_tooling/plugins/backlog/dbus_stub.py +3 -0
- llm_sca_tooling/plugins/backlog/grpc_stub.py +3 -0
- llm_sca_tooling/plugins/backlog/mqtt_stub.py +3 -0
- llm_sca_tooling/plugins/backlog/protobuf_stub.py +3 -0
- llm_sca_tooling/plugins/backlog/zeromq_stub.py +3 -0
- llm_sca_tooling/plugins/base.py +165 -0
- llm_sca_tooling/plugins/capability.py +77 -0
- llm_sca_tooling/plugins/errors.py +19 -0
- llm_sca_tooling/plugins/graph_utils.py +190 -0
- llm_sca_tooling/plugins/http_rest/__init__.py +5 -0
- llm_sca_tooling/plugins/http_rest/client_detector.py +41 -0
- llm_sca_tooling/plugins/http_rest/django_detector.py +28 -0
- llm_sca_tooling/plugins/http_rest/fastapi_detector.py +13 -0
- llm_sca_tooling/plugins/http_rest/flask_detector.py +13 -0
- llm_sca_tooling/plugins/http_rest/framework_detector.py +97 -0
- llm_sca_tooling/plugins/http_rest/openapi_parser.py +131 -0
- llm_sca_tooling/plugins/http_rest/plugin.py +395 -0
- llm_sca_tooling/plugins/http_rest/schema_extractor.py +12 -0
- llm_sca_tooling/plugins/http_rest/url_normalizer.py +57 -0
- llm_sca_tooling/plugins/interface_record.py +105 -0
- llm_sca_tooling/plugins/omniorb_idl/__init__.py +5 -0
- llm_sca_tooling/plugins/omniorb_idl/caller_finder.py +29 -0
- llm_sca_tooling/plugins/omniorb_idl/cpp_servant_linker.py +36 -0
- llm_sca_tooling/plugins/omniorb_idl/generated_artifact_tracker.py +19 -0
- llm_sca_tooling/plugins/omniorb_idl/idl_parser.py +39 -0
- llm_sca_tooling/plugins/omniorb_idl/plugin.py +329 -0
- llm_sca_tooling/plugins/omniorb_idl/python_stub_linker.py +26 -0
- llm_sca_tooling/plugins/registry.py +172 -0
- llm_sca_tooling/plugins/runner.py +76 -0
- llm_sca_tooling/plugins/store.py +57 -0
- llm_sca_tooling/plugins/traversal.py +155 -0
- llm_sca_tooling/plugins/traverse_edges.py +109 -0
- llm_sca_tooling/plugins/websocket/__init__.py +5 -0
- llm_sca_tooling/plugins/websocket/client_detector.py +33 -0
- llm_sca_tooling/plugins/websocket/event_extractor.py +21 -0
- llm_sca_tooling/plugins/websocket/namespace_resolver.py +16 -0
- llm_sca_tooling/plugins/websocket/plugin.py +321 -0
- llm_sca_tooling/plugins/websocket/server_detector.py +71 -0
- llm_sca_tooling/privacy/__init__.py +35 -0
- llm_sca_tooling/privacy/export_delete.py +69 -0
- llm_sca_tooling/privacy/redaction.py +69 -0
- llm_sca_tooling/privacy/retention_policy.py +95 -0
- llm_sca_tooling/qa/__init__.py +14 -0
- llm_sca_tooling/qa/answer.py +54 -0
- llm_sca_tooling/qa/behaviour_trace.py +204 -0
- llm_sca_tooling/qa/blame.py +265 -0
- llm_sca_tooling/qa/classifier.py +148 -0
- llm_sca_tooling/qa/confidence.py +63 -0
- llm_sca_tooling/qa/evidence_assembler.py +144 -0
- llm_sca_tooling/qa/graph_query.py +183 -0
- llm_sca_tooling/qa/interface_lookup.py +137 -0
- llm_sca_tooling/qa/lookup.py +386 -0
- llm_sca_tooling/qa/question.py +120 -0
- llm_sca_tooling/qa/service.py +282 -0
- llm_sca_tooling/qa/ship_gate.py +89 -0
- llm_sca_tooling/qa/synthesis.py +90 -0
- llm_sca_tooling/release/__init__.py +27 -0
- llm_sca_tooling/release/ablation.py +43 -0
- llm_sca_tooling/release/adversarial.py +34 -0
- llm_sca_tooling/release/calibration.py +101 -0
- llm_sca_tooling/release/models.py +171 -0
- llm_sca_tooling/release/operational_gates.py +71 -0
- llm_sca_tooling/release/production_refresh.py +42 -0
- llm_sca_tooling/release/release_gate.py +72 -0
- llm_sca_tooling/release/report_templates.py +41 -0
- llm_sca_tooling/sarif/__init__.py +31 -0
- llm_sca_tooling/sarif/adapters/__init__.py +20 -0
- llm_sca_tooling/sarif/adapters/bandit.py +160 -0
- llm_sca_tooling/sarif/adapters/base.py +41 -0
- llm_sca_tooling/sarif/adapters/codeql.py +46 -0
- llm_sca_tooling/sarif/adapters/external_import.py +52 -0
- llm_sca_tooling/sarif/adapters/ruleset.py +44 -0
- llm_sca_tooling/sarif/adapters/semgrep.py +100 -0
- llm_sca_tooling/sarif/adapters/sonarqube.py +71 -0
- llm_sca_tooling/sarif/binding.py +160 -0
- llm_sca_tooling/sarif/delta.py +110 -0
- llm_sca_tooling/sarif/errors.py +19 -0
- llm_sca_tooling/sarif/fingerprint.py +44 -0
- llm_sca_tooling/sarif/models.py +363 -0
- llm_sca_tooling/sarif/normalizer.py +485 -0
- llm_sca_tooling/sarif/parser.py +392 -0
- llm_sca_tooling/sarif/pipeline.py +135 -0
- llm_sca_tooling/sarif/resource.py +66 -0
- llm_sca_tooling/sarif/rulesets/__init__.py +0 -0
- llm_sca_tooling/sarif/rulesets/cpp_security.yaml +11 -0
- llm_sca_tooling/sarif/rulesets/python_security.yaml +20 -0
- llm_sca_tooling/sarif/rulesets/typescript_security.yaml +10 -0
- llm_sca_tooling/sarif/store.py +270 -0
- llm_sca_tooling/sarif/warned_by.py +190 -0
- llm_sca_tooling/sast_repair/__init__.py +91 -0
- llm_sca_tooling/sast_repair/alert_binding.py +122 -0
- llm_sca_tooling/sast_repair/alert_classification.py +92 -0
- llm_sca_tooling/sast_repair/analyser_rerun.py +89 -0
- llm_sca_tooling/sast_repair/build_test_runner.py +91 -0
- llm_sca_tooling/sast_repair/corpus_adapter.py +149 -0
- llm_sca_tooling/sast_repair/models.py +262 -0
- llm_sca_tooling/sast_repair/patch_generator.py +59 -0
- llm_sca_tooling/sast_repair/predicate_examples.py +64 -0
- llm_sca_tooling/sast_repair/predicate_metadata.py +132 -0
- llm_sca_tooling/sast_repair/remaining_risk.py +115 -0
- llm_sca_tooling/sast_repair/repair_context.py +101 -0
- llm_sca_tooling/sast_repair/report.py +286 -0
- llm_sca_tooling/sast_repair/rule_evolution.py +33 -0
- llm_sca_tooling/sast_repair/sandbox.py +134 -0
- llm_sca_tooling/sast_repair/sarif_delta_verifier.py +95 -0
- llm_sca_tooling/sast_repair/suppression.py +68 -0
- llm_sca_tooling/schemas/__init__.py +5 -0
- llm_sca_tooling/schemas/base.py +88 -0
- llm_sca_tooling/schemas/contracts.py +53 -0
- llm_sca_tooling/schemas/enums.py +254 -0
- llm_sca_tooling/schemas/evidence.py +69 -0
- llm_sca_tooling/schemas/governance.py +201 -0
- llm_sca_tooling/schemas/graph.py +292 -0
- llm_sca_tooling/schemas/harness.py +62 -0
- llm_sca_tooling/schemas/incidents.py +108 -0
- llm_sca_tooling/schemas/json_schema.py +100 -0
- llm_sca_tooling/schemas/memory.py +36 -0
- llm_sca_tooling/schemas/operations.py +190 -0
- llm_sca_tooling/schemas/patches.py +64 -0
- llm_sca_tooling/schemas/provenance.py +173 -0
- llm_sca_tooling/schemas/readiness.py +122 -0
- llm_sca_tooling/schemas/run_records.py +154 -0
- llm_sca_tooling/schemas/sarif.py +39 -0
- llm_sca_tooling/schemas/supply_chain.py +37 -0
- llm_sca_tooling/schemas/validation.py +90 -0
- llm_sca_tooling/schemas/verdicts.py +81 -0
- llm_sca_tooling/storage/__init__.py +9 -0
- llm_sca_tooling/storage/artifacts.py +140 -0
- llm_sca_tooling/storage/diagnostics.py +14 -0
- llm_sca_tooling/storage/errors.py +57 -0
- llm_sca_tooling/storage/export_import.py +382 -0
- llm_sca_tooling/storage/graph_queries.py +30 -0
- llm_sca_tooling/storage/graph_store.py +633 -0
- llm_sca_tooling/storage/harness_store.py +150 -0
- llm_sca_tooling/storage/ids.py +48 -0
- llm_sca_tooling/storage/migrations/0001_initial.sql +297 -0
- llm_sca_tooling/storage/migrations/0002_sarif.sql +88 -0
- llm_sca_tooling/storage/migrations/0003_embedding_vectors.sql +19 -0
- llm_sca_tooling/storage/migrations/0004_eval_runs.sql +14 -0
- llm_sca_tooling/storage/migrations/0005_memory.sql +58 -0
- llm_sca_tooling/storage/migrations/__init__.py +88 -0
- llm_sca_tooling/storage/operations.py +514 -0
- llm_sca_tooling/storage/paths.py +74 -0
- llm_sca_tooling/storage/registry.py +193 -0
- llm_sca_tooling/storage/snapshots.py +197 -0
- llm_sca_tooling/storage/sqlite.py +16 -0
- llm_sca_tooling/storage/transactions.py +19 -0
- llm_sca_tooling/storage/workspace.py +135 -0
- llm_sca_tooling/telemetry/__init__.py +6 -0
- llm_sca_tooling/telemetry/logging.py +41 -0
- llm_sca_tooling/telemetry/trace_writer.py +85 -0
- llm_sca_tooling/traces/__init__.py +35 -0
- llm_sca_tooling/traces/adapters/__init__.py +16 -0
- llm_sca_tooling/traces/adapters/base.py +38 -0
- llm_sca_tooling/traces/adapters/cpp_adapter.py +30 -0
- llm_sca_tooling/traces/adapters/js_adapter.py +30 -0
- llm_sca_tooling/traces/adapters/python_adapter.py +157 -0
- llm_sca_tooling/traces/adapters/python_runner.py +243 -0
- llm_sca_tooling/traces/adapters/registry.py +32 -0
- llm_sca_tooling/traces/artefact_store.py +63 -0
- llm_sca_tooling/traces/compression/__init__.py +17 -0
- llm_sca_tooling/traces/compression/divergence.py +45 -0
- llm_sca_tooling/traces/compression/interface.py +21 -0
- llm_sca_tooling/traces/compression/null_summarizer.py +84 -0
- llm_sca_tooling/traces/compression/state_diff.py +177 -0
- llm_sca_tooling/traces/contract.py +86 -0
- llm_sca_tooling/traces/integration/__init__.py +17 -0
- llm_sca_tooling/traces/integration/bug_resolve_hook.py +18 -0
- llm_sca_tooling/traces/integration/fl_hook.py +65 -0
- llm_sca_tooling/traces/integration/impl_check_hook.py +26 -0
- llm_sca_tooling/traces/integration/patch_review_hook.py +11 -0
- llm_sca_tooling/traces/models.py +213 -0
- llm_sca_tooling/traces/redaction.py +49 -0
- llm_sca_tooling/traces/scope_filter.py +96 -0
- llm_sca_tooling/traces/service.py +286 -0
- llm_sca_tooling/transport/__init__.py +13 -0
- llm_sca_tooling/transport/http_transport.py +58 -0
- llm_sca_tooling/workflows/__init__.py +1 -0
- llm_sca_tooling/workflows/bug_resolve/__init__.py +57 -0
- llm_sca_tooling/workflows/bug_resolve/blast_radius_stub.py +51 -0
- llm_sca_tooling/workflows/bug_resolve/candidate_patch.py +77 -0
- llm_sca_tooling/workflows/bug_resolve/certificate.py +60 -0
- llm_sca_tooling/workflows/bug_resolve/config.py +34 -0
- llm_sca_tooling/workflows/bug_resolve/gate_runner.py +153 -0
- llm_sca_tooling/workflows/bug_resolve/investigate.py +121 -0
- llm_sca_tooling/workflows/bug_resolve/models.py +307 -0
- llm_sca_tooling/workflows/bug_resolve/monitor_hooks.py +162 -0
- llm_sca_tooling/workflows/bug_resolve/patch_selection.py +102 -0
- llm_sca_tooling/workflows/bug_resolve/preconditions.py +42 -0
- llm_sca_tooling/workflows/bug_resolve/repair_context.py +69 -0
- llm_sca_tooling/workflows/bug_resolve/report.py +155 -0
- llm_sca_tooling/workflows/bug_resolve/reproduction_test.py +64 -0
- llm_sca_tooling/workflows/bug_resolve/state_machine.py +482 -0
- llm_sca_tooling/workflows/impl_check/__init__.py +37 -0
- llm_sca_tooling/workflows/impl_check/aggregator.py +159 -0
- llm_sca_tooling/workflows/impl_check/clause_extractor.py +118 -0
- llm_sca_tooling/workflows/impl_check/contract_generator.py +137 -0
- llm_sca_tooling/workflows/impl_check/dynamic_verdict.py +71 -0
- llm_sca_tooling/workflows/impl_check/grounding.py +56 -0
- llm_sca_tooling/workflows/impl_check/harness_policy.py +55 -0
- llm_sca_tooling/workflows/impl_check/ingestion.py +44 -0
- llm_sca_tooling/workflows/impl_check/intent_graph.py +56 -0
- llm_sca_tooling/workflows/impl_check/models.py +272 -0
- llm_sca_tooling/workflows/impl_check/operational_binding.py +33 -0
- llm_sca_tooling/workflows/impl_check/report.py +254 -0
- llm_sca_tooling/workflows/impl_check/static_verdict.py +155 -0
- llm_sca_tooling/workflows/impl_check/verdict_matrix.py +70 -0
- llm_sca_tooling-0.1.0.dist-info/METADATA +108 -0
- llm_sca_tooling-0.1.0.dist-info/RECORD +450 -0
- llm_sca_tooling-0.1.0.dist-info/WHEEL +4 -0
- llm_sca_tooling-0.1.0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Phase 15 blast-radius service — cross-language and cross-repository impact analysis."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from llm_sca_tooling.blast_radius.change_type import ChangeType, classify_change_type
|
|
6
|
+
from llm_sca_tooling.blast_radius.models import (
|
|
7
|
+
ABIChangeType,
|
|
8
|
+
ABIImpactNote,
|
|
9
|
+
AmbiguousLinkRecord,
|
|
10
|
+
BlastRadiusConfig,
|
|
11
|
+
BlastRadiusReport,
|
|
12
|
+
CrossRepoImpactRecord,
|
|
13
|
+
GeneratedStubImpactNote,
|
|
14
|
+
GeneratedStubImpactType,
|
|
15
|
+
ImpactGroup,
|
|
16
|
+
ImpactRecord,
|
|
17
|
+
MatchMethod,
|
|
18
|
+
)
|
|
19
|
+
from llm_sca_tooling.blast_radius.service import BlastRadiusService
|
|
20
|
+
from llm_sca_tooling.blast_radius.traversal_policy import (
|
|
21
|
+
TraversalPolicy,
|
|
22
|
+
default_policy_for,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"ABIChangeType",
|
|
27
|
+
"ABIImpactNote",
|
|
28
|
+
"AmbiguousLinkRecord",
|
|
29
|
+
"BlastRadiusConfig",
|
|
30
|
+
"BlastRadiusReport",
|
|
31
|
+
"BlastRadiusService",
|
|
32
|
+
"ChangeType",
|
|
33
|
+
"CrossRepoImpactRecord",
|
|
34
|
+
"GeneratedStubImpactNote",
|
|
35
|
+
"GeneratedStubImpactType",
|
|
36
|
+
"ImpactGroup",
|
|
37
|
+
"ImpactRecord",
|
|
38
|
+
"MatchMethod",
|
|
39
|
+
"TraversalPolicy",
|
|
40
|
+
"classify_change_type",
|
|
41
|
+
"default_policy_for",
|
|
42
|
+
]
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Phase 15 C/C++ ABI impact detection (with fallback when backend absent)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
from llm_sca_tooling.blast_radius.models import ABIChangeType, ABIImpactNote
|
|
8
|
+
from llm_sca_tooling.patch_review.models import ChangedSymbolRecord
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
_CPP_EXTENSIONS = {".cpp", ".cc", ".cxx", ".c", ".h", ".hpp", ".hxx"}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _is_cpp_file(file_path: str) -> bool:
|
|
16
|
+
lower = file_path.lower()
|
|
17
|
+
return any(lower.endswith(ext) for ext in _CPP_EXTENSIONS)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def build_abi_impact_notes(
|
|
21
|
+
changed_records: list[ChangedSymbolRecord],
|
|
22
|
+
*,
|
|
23
|
+
clangd_available: bool = False,
|
|
24
|
+
) -> list[ABIImpactNote]:
|
|
25
|
+
"""Produce ABIImpactNotes for C/C++ symbol changes.
|
|
26
|
+
|
|
27
|
+
When clangd/libclang backend is unavailable, always produce a note with
|
|
28
|
+
abi_change_type=UNKNOWN and an explanatory diagnostic — never silently skip.
|
|
29
|
+
"""
|
|
30
|
+
notes: list[ABIImpactNote] = []
|
|
31
|
+
|
|
32
|
+
for rec in changed_records:
|
|
33
|
+
if not _is_cpp_file(rec.file_path):
|
|
34
|
+
continue
|
|
35
|
+
|
|
36
|
+
if not clangd_available:
|
|
37
|
+
notes.append(
|
|
38
|
+
ABIImpactNote(
|
|
39
|
+
symbol_node_id=rec.graph_node_id or rec.symbol_path,
|
|
40
|
+
symbol_path=rec.symbol_path,
|
|
41
|
+
abi_change_type=ABIChangeType.UNKNOWN,
|
|
42
|
+
diagnostics=[
|
|
43
|
+
"libclang/clangd backend unavailable; ABI analysis skipped. "
|
|
44
|
+
"Manual ABI review required for this C/C++ change."
|
|
45
|
+
],
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
logger.warning(
|
|
49
|
+
"ABI analysis unavailable for %s (clangd not present)", rec.file_path
|
|
50
|
+
)
|
|
51
|
+
continue
|
|
52
|
+
|
|
53
|
+
# When clangd is available, determine ABI change type from record metadata
|
|
54
|
+
from llm_sca_tooling.patch_review.models import ChangeKind # noqa: PLC0415
|
|
55
|
+
|
|
56
|
+
if rec.change_kind == ChangeKind.MODIFIED_SIGNATURE:
|
|
57
|
+
abi_type = ABIChangeType.SIGNATURE_CHANGED
|
|
58
|
+
else:
|
|
59
|
+
abi_type = ABIChangeType.NO_ABI_IMPACT
|
|
60
|
+
|
|
61
|
+
notes.append(
|
|
62
|
+
ABIImpactNote(
|
|
63
|
+
symbol_node_id=rec.graph_node_id or rec.symbol_path,
|
|
64
|
+
symbol_path=rec.symbol_path,
|
|
65
|
+
abi_change_type=abi_type,
|
|
66
|
+
confidence=0.75,
|
|
67
|
+
diagnostics=[],
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
return notes
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
__all__ = ["build_abi_impact_notes"]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Phase 15 ambiguous-link bucket helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from llm_sca_tooling.blast_radius.models import AmbiguousLinkRecord, MatchMethod
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def make_unresolved_cross_repo_link(
|
|
9
|
+
source_node_id: str,
|
|
10
|
+
target_node_id: str,
|
|
11
|
+
edge_type: str,
|
|
12
|
+
confidence: float,
|
|
13
|
+
reason: str = "",
|
|
14
|
+
) -> AmbiguousLinkRecord:
|
|
15
|
+
return AmbiguousLinkRecord(
|
|
16
|
+
source_node_id=source_node_id,
|
|
17
|
+
target_node_id=target_node_id,
|
|
18
|
+
edge_type=edge_type,
|
|
19
|
+
confidence=confidence,
|
|
20
|
+
match_method=MatchMethod.CROSS_REPO_UNRESOLVED,
|
|
21
|
+
reason_ambiguous=reason or "Cross-repo target unresolved.",
|
|
22
|
+
recommended_followup="Register target repo and re-index.",
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def make_candidate_link(
|
|
27
|
+
source_node_id: str,
|
|
28
|
+
target_node_id: str,
|
|
29
|
+
edge_type: str,
|
|
30
|
+
confidence: float,
|
|
31
|
+
analyser_threshold: float,
|
|
32
|
+
) -> AmbiguousLinkRecord:
|
|
33
|
+
return AmbiguousLinkRecord(
|
|
34
|
+
source_node_id=source_node_id,
|
|
35
|
+
target_node_id=target_node_id,
|
|
36
|
+
edge_type=edge_type,
|
|
37
|
+
confidence=confidence,
|
|
38
|
+
match_method=MatchMethod.CANDIDATE_EDGE,
|
|
39
|
+
reason_ambiguous=(
|
|
40
|
+
f"Edge confidence {confidence:.2f} below analyser threshold {analyser_threshold:.2f}."
|
|
41
|
+
),
|
|
42
|
+
recommended_followup="Run analyser-level pass to confirm or reject.",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
__all__ = ["make_candidate_link", "make_unresolved_cross_repo_link"]
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""Phase 15 change-type classification."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from enum import StrEnum
|
|
6
|
+
|
|
7
|
+
from llm_sca_tooling.patch_review.models import ChangedSymbolRecord
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ChangeType(StrEnum):
|
|
11
|
+
INTERNAL_IMPLEMENTATION = "internal_implementation"
|
|
12
|
+
PUBLIC_API_CHANGE = "public_api_change"
|
|
13
|
+
IDL_SCHEMA_CONTRACT_CHANGE = "idl_schema_contract_change"
|
|
14
|
+
SECURITY_SENSITIVE_CHANGE = "security_sensitive_change"
|
|
15
|
+
GENERATED_FILE_CHANGE = "generated_file_change"
|
|
16
|
+
MIXED = "mixed"
|
|
17
|
+
UNKNOWN = "unknown"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
_IDL_PATTERNS = (
|
|
21
|
+
".proto",
|
|
22
|
+
".thrift",
|
|
23
|
+
".idl",
|
|
24
|
+
".wsdl",
|
|
25
|
+
".avsc",
|
|
26
|
+
".avro",
|
|
27
|
+
"openapi",
|
|
28
|
+
"swagger",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
_SECURITY_KEYWORDS = (
|
|
32
|
+
"auth",
|
|
33
|
+
"crypt",
|
|
34
|
+
"perm",
|
|
35
|
+
"secret",
|
|
36
|
+
"token",
|
|
37
|
+
"password",
|
|
38
|
+
"passwd",
|
|
39
|
+
"credential",
|
|
40
|
+
"cwe",
|
|
41
|
+
"sanitize",
|
|
42
|
+
"escape",
|
|
43
|
+
"jwt",
|
|
44
|
+
"oauth",
|
|
45
|
+
"acl",
|
|
46
|
+
"rbac",
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _is_idl_path(file_path: str) -> bool:
|
|
51
|
+
lower = file_path.lower()
|
|
52
|
+
return any(pat in lower for pat in _IDL_PATTERNS)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _is_security_sensitive(record: ChangedSymbolRecord) -> bool:
|
|
56
|
+
lower = record.file_path.lower() + " " + record.symbol_path.lower()
|
|
57
|
+
return any(kw in lower for kw in _SECURITY_KEYWORDS)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def classify_change_type(
|
|
61
|
+
records: list[ChangedSymbolRecord],
|
|
62
|
+
*,
|
|
63
|
+
security_node_ids: set[str] | None = None,
|
|
64
|
+
) -> tuple[ChangeType, list[ChangeType]]:
|
|
65
|
+
"""Classify the change type from a list of ChangedSymbolRecord.
|
|
66
|
+
|
|
67
|
+
Returns a tuple of (primary_type, applicable_types).
|
|
68
|
+
If multiple change types apply, primary_type is MIXED.
|
|
69
|
+
"""
|
|
70
|
+
if not records:
|
|
71
|
+
return ChangeType.UNKNOWN, []
|
|
72
|
+
|
|
73
|
+
applicable: set[ChangeType] = set()
|
|
74
|
+
|
|
75
|
+
for rec in records:
|
|
76
|
+
if rec.is_generated:
|
|
77
|
+
applicable.add(ChangeType.GENERATED_FILE_CHANGE)
|
|
78
|
+
if rec.is_public_api:
|
|
79
|
+
applicable.add(ChangeType.PUBLIC_API_CHANGE)
|
|
80
|
+
if _is_idl_path(rec.file_path):
|
|
81
|
+
applicable.add(ChangeType.IDL_SCHEMA_CONTRACT_CHANGE)
|
|
82
|
+
if _is_security_sensitive(rec) or (
|
|
83
|
+
security_node_ids
|
|
84
|
+
and rec.graph_node_id
|
|
85
|
+
and rec.graph_node_id in security_node_ids
|
|
86
|
+
):
|
|
87
|
+
applicable.add(ChangeType.SECURITY_SENSITIVE_CHANGE)
|
|
88
|
+
|
|
89
|
+
if not applicable:
|
|
90
|
+
return ChangeType.INTERNAL_IMPLEMENTATION, [ChangeType.INTERNAL_IMPLEMENTATION]
|
|
91
|
+
|
|
92
|
+
if len(applicable) > 1:
|
|
93
|
+
return ChangeType.MIXED, sorted(applicable)
|
|
94
|
+
|
|
95
|
+
only = next(iter(applicable))
|
|
96
|
+
return only, [only]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
__all__ = ["ChangeType", "classify_change_type"]
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""Phase 15 cross-repository traversal with is_partial fallback."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from llm_sca_tooling.blast_radius.models import (
|
|
9
|
+
AmbiguousLinkRecord,
|
|
10
|
+
CrossRepoImpactRecord,
|
|
11
|
+
MatchMethod,
|
|
12
|
+
)
|
|
13
|
+
from llm_sca_tooling.schemas.enums import GraphEdgeType
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from llm_sca_tooling.storage.graph_store import GraphStore
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
_CROSS_REPO_EDGE_TYPES = {
|
|
21
|
+
GraphEdgeType.CONSUMES.value,
|
|
22
|
+
GraphEdgeType.EXPOSES.value,
|
|
23
|
+
GraphEdgeType.FFI.value,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def traverse_cross_repo(
|
|
28
|
+
changed_node_ids: list[str],
|
|
29
|
+
graph_store: GraphStore,
|
|
30
|
+
*,
|
|
31
|
+
registered_repo_ids: list[str] | None = None,
|
|
32
|
+
max_hops: int = 2,
|
|
33
|
+
analyser_threshold: float = 0.75,
|
|
34
|
+
) -> tuple[list[CrossRepoImpactRecord], list[AmbiguousLinkRecord]]:
|
|
35
|
+
"""Traverse cross-repo graph overlay to find consuming repos.
|
|
36
|
+
|
|
37
|
+
When the overlay is unavailable or incomplete, returns CrossRepoImpactRecord
|
|
38
|
+
with is_partial=True — never silently skips.
|
|
39
|
+
|
|
40
|
+
Returns (cross_repo_records, ambiguous_link_records).
|
|
41
|
+
"""
|
|
42
|
+
if not registered_repo_ids:
|
|
43
|
+
logger.info("No registered repos provided; cross-repo traversal skipped.")
|
|
44
|
+
ambiguous = [
|
|
45
|
+
AmbiguousLinkRecord(
|
|
46
|
+
source_node_id=nid,
|
|
47
|
+
target_node_id="<unknown>",
|
|
48
|
+
edge_type=GraphEdgeType.CONSUMES.value,
|
|
49
|
+
confidence=0.0,
|
|
50
|
+
match_method=MatchMethod.CROSS_REPO_UNRESOLVED,
|
|
51
|
+
reason_ambiguous="No registered repos available for cross-repo traversal.",
|
|
52
|
+
recommended_followup="Register consuming repos and re-run blast radius.",
|
|
53
|
+
)
|
|
54
|
+
for nid in changed_node_ids
|
|
55
|
+
]
|
|
56
|
+
return [], ambiguous
|
|
57
|
+
|
|
58
|
+
edge_types = [GraphEdgeType(et) for et in _CROSS_REPO_EDGE_TYPES]
|
|
59
|
+
cross_records: list[CrossRepoImpactRecord] = []
|
|
60
|
+
cross_ambiguous: list[AmbiguousLinkRecord] = []
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
slice_ = graph_store.fetch_ego_graph(
|
|
64
|
+
changed_node_ids,
|
|
65
|
+
depth=max_hops,
|
|
66
|
+
edge_types=edge_types,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Group consuming nodes by repo_id
|
|
70
|
+
repo_consumers: dict[str, list[str]] = {}
|
|
71
|
+
for node in slice_.nodes:
|
|
72
|
+
if node.node_id in set(changed_node_ids):
|
|
73
|
+
continue
|
|
74
|
+
repo_id = node.repo.repo_id
|
|
75
|
+
if repo_id not in registered_repo_ids:
|
|
76
|
+
cross_ambiguous.append(
|
|
77
|
+
AmbiguousLinkRecord(
|
|
78
|
+
source_node_id=changed_node_ids[0] if changed_node_ids else "?",
|
|
79
|
+
target_node_id=node.node_id,
|
|
80
|
+
edge_type=GraphEdgeType.CONSUMES.value,
|
|
81
|
+
confidence=0.0,
|
|
82
|
+
match_method=MatchMethod.CROSS_REPO_UNRESOLVED,
|
|
83
|
+
reason_ambiguous=f"Repo {repo_id!r} not in registered repo list.",
|
|
84
|
+
recommended_followup="Register this repo to enable full cross-repo impact.",
|
|
85
|
+
)
|
|
86
|
+
)
|
|
87
|
+
continue
|
|
88
|
+
repo_consumers.setdefault(repo_id, []).append(node.node_id)
|
|
89
|
+
|
|
90
|
+
for repo_id, consumers in repo_consumers.items():
|
|
91
|
+
cross_records.append(
|
|
92
|
+
CrossRepoImpactRecord(
|
|
93
|
+
repo_id=repo_id,
|
|
94
|
+
consuming_node_ids=consumers,
|
|
95
|
+
hop_distance=1,
|
|
96
|
+
is_partial=False,
|
|
97
|
+
confidence=analyser_threshold,
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
except Exception as exc: # noqa: BLE001
|
|
102
|
+
logger.warning("Cross-repo traversal failed: %s", exc)
|
|
103
|
+
cross_records.append(
|
|
104
|
+
CrossRepoImpactRecord(
|
|
105
|
+
repo_id="<unknown>",
|
|
106
|
+
consuming_node_ids=[],
|
|
107
|
+
hop_distance=0,
|
|
108
|
+
is_partial=True,
|
|
109
|
+
partial_reason=f"Graph overlay traversal failed: {exc}",
|
|
110
|
+
confidence=0.0,
|
|
111
|
+
)
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
return cross_records, cross_ambiguous
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
__all__ = ["traverse_cross_repo"]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Phase 15 linked docs/specs impact — flag stale design clauses."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from llm_sca_tooling.schemas.enums import GraphEdgeType, GraphNodeType
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from llm_sca_tooling.storage.graph_store import GraphStore
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
_DOC_NODE_TYPES = {
|
|
16
|
+
GraphNodeType.DOCUMENT,
|
|
17
|
+
GraphNodeType.DESIGN_CLAUSE,
|
|
18
|
+
GraphNodeType.INTENT_NODE,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
_DOC_EDGE_TYPES = [
|
|
22
|
+
GraphEdgeType.SATISFIES,
|
|
23
|
+
GraphEdgeType.VIOLATES,
|
|
24
|
+
GraphEdgeType.DOCUMENTS,
|
|
25
|
+
GraphEdgeType.DECOMPOSES_TO,
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def collect_linked_docs(
|
|
30
|
+
changed_node_ids: list[str],
|
|
31
|
+
graph_store: GraphStore,
|
|
32
|
+
*,
|
|
33
|
+
max_hops: int = 3,
|
|
34
|
+
) -> tuple[list[dict[str, object]], str]:
|
|
35
|
+
"""Collect design_clause / intent_node / document nodes linked to changed symbols.
|
|
36
|
+
|
|
37
|
+
Returns (doc_node_dicts, summary_string).
|
|
38
|
+
"""
|
|
39
|
+
docs: list[dict[str, object]] = []
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
slice_ = graph_store.fetch_ego_graph(
|
|
43
|
+
changed_node_ids,
|
|
44
|
+
depth=max_hops,
|
|
45
|
+
edge_types=_DOC_EDGE_TYPES,
|
|
46
|
+
)
|
|
47
|
+
for node in slice_.nodes:
|
|
48
|
+
if node.node_id in set(changed_node_ids):
|
|
49
|
+
continue
|
|
50
|
+
if node.node_type in _DOC_NODE_TYPES:
|
|
51
|
+
docs.append(
|
|
52
|
+
{
|
|
53
|
+
"node_id": node.node_id,
|
|
54
|
+
"node_type": node.node_type.value,
|
|
55
|
+
"label": node.label,
|
|
56
|
+
"potentially_stale": True,
|
|
57
|
+
}
|
|
58
|
+
)
|
|
59
|
+
except Exception as exc: # noqa: BLE001
|
|
60
|
+
logger.warning("Linked docs collection failed: %s", exc)
|
|
61
|
+
|
|
62
|
+
summary = (
|
|
63
|
+
f"{len(docs)} linked doc/spec node(s) may be stale after this change."
|
|
64
|
+
if docs
|
|
65
|
+
else "No linked docs/specs affected."
|
|
66
|
+
)
|
|
67
|
+
return docs, summary
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
__all__ = ["collect_linked_docs"]
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Phase 15 generated-stub impact detection and reporting."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
from llm_sca_tooling.blast_radius.models import (
|
|
8
|
+
GeneratedStubImpactNote,
|
|
9
|
+
GeneratedStubImpactType,
|
|
10
|
+
)
|
|
11
|
+
from llm_sca_tooling.patch_review.models import ChangedSymbolRecord
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def build_generated_stub_notes(
|
|
17
|
+
diff_id: str,
|
|
18
|
+
changed_records: list[ChangedSymbolRecord],
|
|
19
|
+
*,
|
|
20
|
+
generated_file_allowlist: set[str] | None = None,
|
|
21
|
+
) -> list[GeneratedStubImpactNote]:
|
|
22
|
+
"""Produce GeneratedStubImpactNotes for generated files touched by this diff.
|
|
23
|
+
|
|
24
|
+
Rules:
|
|
25
|
+
- Every generated file produces a note.
|
|
26
|
+
- Direct edits to generated files set manual_edit_policy_flag=True unless in allowlist.
|
|
27
|
+
"""
|
|
28
|
+
allowlist = generated_file_allowlist or set()
|
|
29
|
+
notes: list[GeneratedStubImpactNote] = []
|
|
30
|
+
|
|
31
|
+
for rec in changed_records:
|
|
32
|
+
if not rec.is_generated:
|
|
33
|
+
continue
|
|
34
|
+
is_manual_violation = rec.file_path not in allowlist
|
|
35
|
+
notes.append(
|
|
36
|
+
GeneratedStubImpactNote(
|
|
37
|
+
diff_id=diff_id,
|
|
38
|
+
generated_file_path=rec.file_path,
|
|
39
|
+
generator_source="",
|
|
40
|
+
source_contract_node_id=rec.graph_node_id,
|
|
41
|
+
impact_type=GeneratedStubImpactType.GENERATED_FILE_DIRECTLY_CHANGED,
|
|
42
|
+
manual_edit_policy_flag=is_manual_violation,
|
|
43
|
+
recommended_action=(
|
|
44
|
+
"Check policy allowlist before merging."
|
|
45
|
+
if is_manual_violation
|
|
46
|
+
else "Verify regeneration is idempotent."
|
|
47
|
+
),
|
|
48
|
+
)
|
|
49
|
+
)
|
|
50
|
+
if is_manual_violation:
|
|
51
|
+
logger.warning(
|
|
52
|
+
"Manual edit detected on generated file %s (diff=%s)",
|
|
53
|
+
rec.file_path,
|
|
54
|
+
diff_id,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
return notes
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
__all__ = ["build_generated_stub_notes"]
|