sourcecode 4.5.3__tar.gz → 4.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. {sourcecode-4.5.3 → sourcecode-4.7.0}/CHANGELOG.md +149 -0
  2. {sourcecode-4.5.3 → sourcecode-4.7.0}/PKG-INFO +4 -4
  3. {sourcecode-4.5.3 → sourcecode-4.7.0}/README.md +3 -3
  4. {sourcecode-4.5.3 → sourcecode-4.7.0}/pyproject.toml +1 -1
  5. {sourcecode-4.5.3 → sourcecode-4.7.0}/scripts/perf_harness.py +38 -1
  6. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/__init__.py +1 -1
  7. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/archetype.py +44 -0
  8. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/baseline_autocapture.py +13 -1
  9. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/cache.py +27 -1
  10. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/cli.py +18 -4
  11. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/java.py +4 -0
  12. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/explain.py +133 -40
  13. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/mcp/registry.py +9 -4
  14. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/mcp/server.py +13 -4
  15. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/migrate_check.py +24 -1
  16. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/path_filters.py +50 -40
  17. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/perf.py +112 -1
  18. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/posture.py +65 -5
  19. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/repository_ir.py +20 -13
  20. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/risk.py +119 -31
  21. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/rule_catalog.py +10 -3
  22. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/security_config_scan.py +172 -0
  23. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/source_text.py +2 -3
  24. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/spring_impact.py +107 -11
  25. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/spring_security_audit.py +20 -2
  26. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/test_sources.py +47 -4
  27. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/verify_rules.py +1 -1
  28. {sourcecode-4.5.3 → sourcecode-4.7.0}/.github/workflows/build-windows.yml +0 -0
  29. {sourcecode-4.5.3 → sourcecode-4.7.0}/.gitignore +0 -0
  30. {sourcecode-4.5.3 → sourcecode-4.7.0}/.ruff.toml +0 -0
  31. {sourcecode-4.5.3 → sourcecode-4.7.0}/CLAUDE.md +0 -0
  32. {sourcecode-4.5.3 → sourcecode-4.7.0}/CONTRIBUTING.md +0 -0
  33. {sourcecode-4.5.3 → sourcecode-4.7.0}/LICENSE +0 -0
  34. {sourcecode-4.5.3 → sourcecode-4.7.0}/SECURITY.md +0 -0
  35. {sourcecode-4.5.3 → sourcecode-4.7.0}/raw +0 -0
  36. {sourcecode-4.5.3 → sourcecode-4.7.0}/scripts/compare_integration_engines.py +0 -0
  37. {sourcecode-4.5.3 → sourcecode-4.7.0}/scripts/customer_smoke_test.sh +0 -0
  38. {sourcecode-4.5.3 → sourcecode-4.7.0}/scripts/generate_jdk_exports.py +0 -0
  39. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/adaptive_scanner.py +0 -0
  40. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/architectural_baseline.py +0 -0
  41. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/architectural_delta.py +0 -0
  42. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/architecture_analyzer.py +0 -0
  43. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/architecture_summary.py +0 -0
  44. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/ast_extractor.py +0 -0
  45. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/cache_model.py +0 -0
  46. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/call_surface.py +0 -0
  47. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/caller_metrics.py +0 -0
  48. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/caller_reach.py +0 -0
  49. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/canonical_ir.py +0 -0
  50. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/chain_rules.py +0 -0
  51. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/change_plan.py +0 -0
  52. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/cir_graphs.py +0 -0
  53. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/classifier.py +0 -0
  54. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/client_calls.py +0 -0
  55. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  56. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/compare.py +0 -0
  57. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/confidence_analyzer.py +0 -0
  58. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/constraint_diff.py +0 -0
  59. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/context_cache.py +0 -0
  60. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/context_graph.py +0 -0
  61. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/context_scorer.py +0 -0
  62. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/context_summarizer.py +0 -0
  63. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/contract_diff.py +0 -0
  64. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/contract_init.py +0 -0
  65. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/contract_model.py +0 -0
  66. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/contract_pipeline.py +0 -0
  67. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/coverage_parser.py +0 -0
  68. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/data_exposure.py +0 -0
  69. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/data_labels.py +0 -0
  70. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/defect_identity.py +0 -0
  71. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/degradation.py +0 -0
  72. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/dependency_analyzer.py +0 -0
  73. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/deployment_prefix.py +0 -0
  74. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/__init__.py +0 -0
  75. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/base.py +0 -0
  76. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  77. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/dart.py +0 -0
  78. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/dotnet.py +0 -0
  79. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/elixir.py +0 -0
  80. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/go.py +0 -0
  81. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/heuristic.py +0 -0
  82. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/hybrid.py +0 -0
  83. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  84. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/nodejs.py +0 -0
  85. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/parsers.py +0 -0
  86. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/php.py +0 -0
  87. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/project.py +0 -0
  88. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/python.py +0 -0
  89. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/ruby.py +0 -0
  90. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/rust.py +0 -0
  91. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/systems.py +0 -0
  92. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/terraform.py +0 -0
  93. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/detectors/tooling.py +0 -0
  94. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/doc_analyzer.py +0 -0
  95. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/dynamic_argument_surface.py +0 -0
  96. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/endpoint_literals.py +0 -0
  97. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/endpoint_metrics.py +0 -0
  98. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  99. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/env_analyzer.py +0 -0
  100. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/envelope.py +0 -0
  101. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/environment_resolution.py +0 -0
  102. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/error_schema.py +0 -0
  103. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/evidence_provider.py +0 -0
  104. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/facts/__init__.py +0 -0
  105. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/facts/registry.json +0 -0
  106. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/file_chunker.py +0 -0
  107. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/file_classifier.py +0 -0
  108. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/filter_surface.py +0 -0
  109. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/format_contract.py +0 -0
  110. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/fqn_utils.py +0 -0
  111. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/git_analyzer.py +0 -0
  112. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/git_checkout.py +0 -0
  113. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/graph_analyzer.py +0 -0
  114. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/graph_evidence.py +0 -0
  115. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/hibernate_strat.py +0 -0
  116. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/identity_fallback.py +0 -0
  117. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/integration_coordinates.py +0 -0
  118. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/jdk_exports.py +0 -0
  119. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/license.py +0 -0
  120. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/mcp/__init__.py +0 -0
  121. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  122. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  123. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  124. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  125. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  126. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/mcp/orchestrator.py +0 -0
  127. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/mcp/runner.py +0 -0
  128. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/mcp_nudge.py +0 -0
  129. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/metrics_analyzer.py +0 -0
  130. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/migration_blast.py +0 -0
  131. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/non_coverage.py +0 -0
  132. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/openapi_surface.py +0 -0
  133. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/openrewrite_recipe.py +0 -0
  134. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/output_budget.py +0 -0
  135. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/parse_cache.py +0 -0
  136. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/path_admission.py +0 -0
  137. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/pipe_contract.py +0 -0
  138. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/pr_comment_renderer.py +0 -0
  139. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/pr_impact.py +0 -0
  140. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/prepare_context.py +0 -0
  141. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/progress.py +0 -0
  142. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/ranking_engine.py +0 -0
  143. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/readiness_timeline.py +0 -0
  144. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/reconciliation.py +0 -0
  145. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/redactor.py +0 -0
  146. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/reference_facts.py +0 -0
  147. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/release_info.py +0 -0
  148. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/relevance_scorer.py +0 -0
  149. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/remedies.py +0 -0
  150. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/rename_refactor.py +0 -0
  151. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/repo_classifier.py +0 -0
  152. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/__init__.py +0 -0
  153. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/context.py +0 -0
  154. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/errors.py +0 -0
  155. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/executor.py +0 -0
  156. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/planner.py +0 -0
  157. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/query.py +0 -0
  158. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/request.py +0 -0
  159. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/resolution.py +0 -0
  160. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/result.py +0 -0
  161. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/retriever.py +0 -0
  162. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/runtime.py +0 -0
  163. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/steps.py +0 -0
  164. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
  165. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/steps_graph.py +0 -0
  166. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/steps_impact.py +0 -0
  167. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/steps_intf.py +0 -0
  168. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/steps_struct.py +0 -0
  169. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/retrieval/steps_txsec.py +0 -0
  170. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/ris.py +0 -0
  171. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/runtime_classifier.py +0 -0
  172. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/sarif.py +0 -0
  173. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/scanner.py +0 -0
  174. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/schema.py +0 -0
  175. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
  176. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/security_config.py +0 -0
  177. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/security_posture.py +0 -0
  178. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/semantic_analyzer.py +0 -0
  179. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/semantic_impact_engine.py +0 -0
  180. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/semantic_integration_engine.py +0 -0
  181. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/semantic_services.py +0 -0
  182. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/serializer.py +0 -0
  183. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/servlet_surface.py +0 -0
  184. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/spring_event_topology.py +0 -0
  185. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/spring_findings.py +0 -0
  186. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/spring_model.py +0 -0
  187. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/spring_profiles.py +0 -0
  188. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/spring_properties.py +0 -0
  189. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/spring_semantic.py +0 -0
  190. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/spring_tx_analyzer.py +0 -0
  191. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/summarizer.py +0 -0
  192. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/target_admission.py +0 -0
  193. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/telemetry/__init__.py +0 -0
  194. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/telemetry/config.py +0 -0
  195. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/telemetry/consent.py +0 -0
  196. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/telemetry/events.py +0 -0
  197. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/telemetry/filters.py +0 -0
  198. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/telemetry/transport.py +0 -0
  199. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/test_gap_ranking.py +0 -0
  200. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/token_estimate.py +0 -0
  201. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/tree_utils.py +0 -0
  202. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/type_usage_surface.py +0 -0
  203. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/validation_inference.py +0 -0
  204. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/validation_surface.py +0 -0
  205. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/verify_edit.py +0 -0
  206. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/verify_repo.py +0 -0
  207. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/version_check.py +0 -0
  208. {sourcecode-4.5.3 → sourcecode-4.7.0}/src/sourcecode/workspace.py +0 -0
  209. {sourcecode-4.5.3 → sourcecode-4.7.0}/supabase/functions/README.md +0 -0
  210. {sourcecode-4.5.3 → sourcecode-4.7.0}/supabase/functions/get-license/index.ts +0 -0
  211. {sourcecode-4.5.3 → sourcecode-4.7.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
  212. {sourcecode-4.5.3 → sourcecode-4.7.0}/supabase/functions/telemetry/index.ts +0 -0
  213. {sourcecode-4.5.3 → sourcecode-4.7.0}/supabase/sql/license_event_ordering.sql +0 -0
  214. {sourcecode-4.5.3 → sourcecode-4.7.0}/supabase/sql/licensing_schema.sql +0 -0
  215. {sourcecode-4.5.3 → sourcecode-4.7.0}/supabase/sql/telemetry_events.sql +0 -0
@@ -2,6 +2,155 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [4.7.0] — 2026-08-04
6
+
7
+ ### Fixed
8
+
9
+ - **`impact-chain` no longer pays a repository-wide TX + security audit by default.**
10
+ `impact_findings` is now opt-in with `--with-findings`, so the common query cost
11
+ follows the queried subgraph instead of the whole repository.
12
+ - **`migrate-check` now separates migration blockers from broad blockers.**
13
+ The payload publishes `migration_blocking_count` while keeping the legacy
14
+ `blocking_count` for compatibility.
15
+ - **Disabled security controls are reported explicitly.** Commented-out
16
+ framework security annotations now emit `DEAD-001`, and security catalog/help
17
+ output includes disabled-control findings.
18
+ - **MyBatis SQL interpolation is classified as SQL-injection risk.** Mapper
19
+ `${...}` interpolation emits `SEC-008` instead of being treated as a generic
20
+ raw SQL smell.
21
+ - **Performance claims now have endpoint-scale coverage.** The battery includes
22
+ a high-endpoint fixture, publishes scale dimensions, and gates unexplained
23
+ performance regressions against prior measurements.
24
+ - **Framework detection covers Jersey and Governator.** Migration/readiness
25
+ output no longer misses those stacks when scanning mixed Java repositories.
26
+
27
+ ## [4.6.0] — 2026-08-04
28
+
29
+ Field evaluation #11 (7,5/10), by the evaluator who measured 4.5.2 twelve hours
30
+ earlier, on the build that closed their previous list. **Eight complaints, eight
31
+ reproductions, eight fixes** — the first evaluation where every complaint
32
+ survives verification and none re-derives a closed row.
33
+
34
+ The headline is not in the list below and is worth stating: the four false
35
+ positives measured on 4.5.2 are **gone**, verified line by line in the field, and
36
+ the run reports **0 false positives across 19 findings** — precision 9/10,
37
+ epistemic honesty 10/10 (*"no he visto nada mejor en ninguna herramienta de
38
+ análisis, comercial o no"*). E-2 is closed in the field, not only in the battery.
39
+
40
+ Minor, not patch: `risk` publishes a sixth reachability value and three new
41
+ fields, `posture` publishes two, `impact-chain` publishes two, and the test/
42
+ production split moves published populations. **No field was removed and no exit
43
+ code moved.**
44
+
45
+ ### Fixed
46
+
47
+ - **`impact-chain` spent 2 300× longer answering than building the model it
48
+ answers from** (C3-42, **high**). The field published `query_time_ms: 1 187 063`
49
+ beside `model_build_time_ms: 516` and abandoned two more invocations past 25
50
+ minutes — the axis this evaluation scored **3/10**, with the verdict that
51
+ decides it: *"un gate de CI que tarda 45 min no es un gate"*. The seed
52
+ expansions (CH-001a/b) answered *"every symbol of this class"* by scanning the
53
+ whole symbol table once per subtype, with the seed set rebuilt for every symbol
54
+ tested. Both now read one class→symbols index memoized on the CIR, which
55
+ matters twice: `RiskComposer.reach` calls that path **once per defect**, and
56
+ that is where the field's ~45-minute `risk` comes from. Measured A/B on
57
+ keycloak (5 525 files, 59 410 symbols), identical results in all four queries:
58
+ `Provider` **8.15 s → 2.60 s**. Second half, and the reason the rest is flat:
59
+ `query_time_ms` was never the walk — it includes a repository-wide TX +
60
+ security audit, now published as `audit_time_ms` with a `query_time_basis`
61
+ stating that the walk is the difference between the two and that
62
+ `model_build_time_ms` is not comparable with either.
63
+ - **`risk` did not read the other authority that answered its own access axis**
64
+ (C1-26, **high**). It asked `posture` only when `--profile` was given, so the
65
+ default invocation weighed an endpoint at `unknown` (×1.4) that `posture`, in
66
+ the same process and over the same CIR, decided was reachable without
67
+ authentication (×2.0). The resolution is now read always; with no set named it
68
+ is the one Spring performs with none given — `default` alone, which CL-8
69
+ records as the permissive case, not a neutral one — and every row publishes
70
+ `profile_set`, `profile_set_basis` (*"a default, never a guarantee: the process
71
+ environment outranks every file"*) and `profile_decisions`. It cannot
72
+ manufacture a verdict: `no_rule_matched` stays unknown coverage, the
73
+ combination is per endpoint, and on a fixture where both chains are
74
+ profile-gated the answer stays `unknown`. Measured on the field's shape: **8.06
75
+ → 11.52**, exactly the ratio of the two access weights, every other factor
76
+ unmoved.
77
+ - **`risk` degraded a repository-wide control defect with a sentence that is
78
+ false in effect** (C1-25, configuration half; second field witness). *"No HTTP
79
+ endpoint in this repository reaches it"* — about the file that decides whether
80
+ any endpoint is reachable at all. Reach for such a defect is **declared, not
81
+ walked**: `posture` already knew which configuration file decided which
82
+ request and now publishes it as `chains.decides_endpoints`, `risk` reads it as
83
+ the reachability value `request_chain`, and the two units stay apart —
84
+ `endpoints_reached` remains the walk, `decides_requests` is the scope.
85
+ Evidence-bound both ways: only a file declaring readable chain rules qualifies,
86
+ and an unresolved servlet path clears the attribution entirely. Fixture: **low
87
+ 2.8 → medium 4.48**.
88
+ - **`posture --resolve-environments` truncated the open-endpoint list without
89
+ declaring the cap** (C2-25). 50 entries under a count of 2 635, with no
90
+ `total`, no `omitted`, no `direction: under_reports` — in the module that
91
+ defines the cap helper and applies it to four other lists. *"Rompe la garantía
92
+ que el resto del tool cumple escrupulosamente, y es precisamente en la lista
93
+ que un auditor necesita completa."* The helper grew the one parameter it was
94
+ missing (the limit that actually bit) and every other slice in the module was
95
+ checked.
96
+ - **`explain` answered a configuration class with every section empty**,
97
+ `found: true` and no warning (C3-41, **high**) — on the command the same
98
+ evaluation calls the product's best asset, for the class an auditor opens
99
+ first. One model error with three faces: a factory member is a method
100
+ (`symbol_kind: "bean"` was excluded by kind, so **every** `@Configuration` in
101
+ every repository published no methods); a configuration class wires through its
102
+ members' signatures and bodies, not through an injection graph (both are atoms
103
+ already published, read only when the class really declares factory members);
104
+ and its constraints are in a DSL, so the section now reads `chain_rules` — the
105
+ authority `posture` uses on that same file — with `file:line` per rule. Fourth,
106
+ and the reason the report was silent: every section was wrapped in a bare
107
+ `except: []`, so a crash and a measured emptiness were one output. A failed
108
+ section now says which one failed.
109
+ - **`cache freshness` called a snapshot STALE over a file no analyser reads**
110
+ (C1-27) — with `RIS HEAD == current HEAD` and `Delta: 0` beside it. C3-40
111
+ (4.5.3) replaced a false *fresh* with a false *stale* by counting any porcelain
112
+ line. One authority now decides which paths qualify
113
+ (`path_filters.analysis_reads`) and both consumers ask it: the freshness
114
+ boolean and the **tree signature**, which is what actually decides the verdict
115
+ and is also the cache key — so an agent writing its own settings file was
116
+ discarding every warm answer. The excused set is state nothing opens and is
117
+ **not** every dot directory: `.github` is read as tooling evidence and stays a
118
+ change. The default is inclusive, because a missed change is a false *fresh*.
119
+ - **The test/production split still had two authorities** (C1-28).
120
+ `path_filters.is_test_path` was never retired after C1-2 made `test_sources`
121
+ the authority in 3.2.1, and the two disagreed on five path shapes in both
122
+ directions. Field symptom: *"`--compact` counts 1 test file that is actually in
123
+ `src/main`"* — verdict right, numerator wrong. The second module is now a
124
+ passthrough, after absorbing everything it knew that the authority did not; and
125
+ a declared **main** source root now outranks a naming convention, the same rule
126
+ the directory half always applied, in the other direction. Fleet effect,
127
+ measured cold: keycloak 5 525 → 5 486 Java files with endpoints **676 → 678**,
128
+ openmrs-core 866 → 861, Broadleaf / alfresco / petclinic unchanged.
129
+ - **`archetype` never read the endpoint surface for the dimension the endpoint
130
+ surface decides** (C3-43). A 3 574-endpoint CRUD REST monolith was labelled
131
+ `engine` at medium confidence on a fan-in Gini, while the legacy classifier it
132
+ supersedes answered `api` and was right. The density `_primary_interface`
133
+ already reads is now positive evidence for `application` and **named negative
134
+ evidence** against `engine` — the shape the library de-bias uses — scaled by
135
+ the measured density, and emitted only when the surface was measured.
136
+ Measured: Broadleaf and keycloak `engine/high → application/low`, petclinic
137
+ `engine/low → application/medium`, jobrunr `engine/high → engine/low`,
138
+ openmrs-core unchanged (1 endpoint, no density, no discount — the negative
139
+ control).
140
+
141
+ ### Notes
142
+
143
+ Two rows from this evaluation are **not** fixed here, on purpose: **P-9** is a
144
+ pricing decision (a fifth pass, and the fourth to argue itself off the seat axis
145
+ — the ceiling is conditioned on this battery's performance work and on a tier
146
+ promotion, not on any missing capability), and **CL-13** is the narrow rule
147
+ catalogue (7 SEC + 6 TX), queued as **F-F** with the *test surface in
148
+ production* rule first, because C1-28 just gave it its admission surface for
149
+ free. Full record in `.planning/FIELD-EVAL-11-2026-08-04.md`; every row is in
150
+ `docs/DEFECT-LEDGER.md`.
151
+
152
+ Suite: 6 468 passed, 6 skipped.
153
+
5
154
  ## [4.5.3] — 2026-08-04
6
155
 
7
156
  Patch: the fixable half of field evaluation #10 (7,5/10, CI reliability **4/10**), in one
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 4.5.3
3
+ Version: 4.7.0
4
4
  Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
5
5
  License-File: LICENSE
6
6
  Keywords: agents,ai,codebase,context,developer-tools,llm
@@ -42,7 +42,7 @@ Description-Content-Type: text/markdown
42
42
 
43
43
  **Context · Impact · Migration · Architecture · Review — everything from one structural model.**
44
44
 
45
- ![Version](https://img.shields.io/badge/version-4.5.3-blue)
45
+ ![Version](https://img.shields.io/badge/version-4.7.0-blue)
46
46
  ![Python](https://img.shields.io/badge/python-3.9%2B-green)
47
47
 
48
48
  > **ASK Engine** is the product. The CLI command is **`ask`**. The legacy **`sourcecode`**
@@ -97,7 +97,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
97
97
  # pip / pipx
98
98
  pipx install sourcecode # or: pip install sourcecode
99
99
 
100
- ask version # ask 4.5.3 — and, on a build that has aged,
100
+ ask version # ask 4.7.0 — and, on a build that has aged,
101
101
  # how many releases have probably shipped since
102
102
  ```
103
103
 
@@ -211,7 +211,7 @@ Bounded, noise-free repo context designed to drop straight into an agent's conte
211
211
 
212
212
  ### 2 · Impact Analysis
213
213
  Blast radius from a class or interface — reverse dependencies, through Spring DI, to the HTTP endpoints a change reaches.
214
- `ask impact` · `ask impact-chain` (TX/SEC-enriched) · `ask pr-impact`
214
+ `ask impact` · `ask impact-chain` (blast radius; `--with-findings` for TX/SEC audit findings) · `ask pr-impact`
215
215
  → [reference](docs/USER_GUIDE.md#core-commands)
216
216
 
217
217
  ### 3 · Architecture Intelligence
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Context · Impact · Migration · Architecture · Review — everything from one structural model.**
6
6
 
7
- ![Version](https://img.shields.io/badge/version-4.5.3-blue)
7
+ ![Version](https://img.shields.io/badge/version-4.7.0-blue)
8
8
  ![Python](https://img.shields.io/badge/python-3.9%2B-green)
9
9
 
10
10
  > **ASK Engine** is the product. The CLI command is **`ask`**. The legacy **`sourcecode`**
@@ -59,7 +59,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
59
59
  # pip / pipx
60
60
  pipx install sourcecode # or: pip install sourcecode
61
61
 
62
- ask version # ask 4.5.3 — and, on a build that has aged,
62
+ ask version # ask 4.7.0 — and, on a build that has aged,
63
63
  # how many releases have probably shipped since
64
64
  ```
65
65
 
@@ -173,7 +173,7 @@ Bounded, noise-free repo context designed to drop straight into an agent's conte
173
173
 
174
174
  ### 2 · Impact Analysis
175
175
  Blast radius from a class or interface — reverse dependencies, through Spring DI, to the HTTP endpoints a change reaches.
176
- `ask impact` · `ask impact-chain` (TX/SEC-enriched) · `ask pr-impact`
176
+ `ask impact` · `ask impact-chain` (blast radius; `--with-findings` for TX/SEC audit findings) · `ask pr-impact`
177
177
  → [reference](docs/USER_GUIDE.md#core-commands)
178
178
 
179
179
  ### 3 · Architecture Intelligence
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "4.5.3"
7
+ version = "4.7.0"
8
8
  description = "Persistent structural context and ultra-fast repeated analysis for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -201,6 +201,12 @@ def main() -> int:
201
201
  ap.add_argument("--fleet-root", type=Path, default=DEFAULT_FLEET_ROOT)
202
202
  ap.add_argument("--out", type=Path, default=None,
203
203
  help="Output dir (default: docs/perf/baselines/<tool_version>).")
204
+ ap.add_argument("--compare-dir", type=Path, default=None,
205
+ help="Previous perf-baseline directory to gate against.")
206
+ ap.add_argument("--max-regression", type=float, default=0.25,
207
+ help="Allowed wall p50/p95 regression ratio before failing (default: 0.25).")
208
+ ap.add_argument("--allow-incomparable", action="store_true",
209
+ help="Do not fail when baseline/current cells are incomparable.")
204
210
  ap.add_argument("--quick", action="store_true", help="petclinic only, 2 runs — smoke test.")
205
211
  ap.add_argument("--dry-run", action="store_true", help="Print the plan, run nothing.")
206
212
  args = ap.parse_args()
@@ -227,6 +233,7 @@ def main() -> int:
227
233
  return 0
228
234
 
229
235
  out_dir.mkdir(parents=True, exist_ok=True)
236
+ failures: list[tuple[str, dict]] = []
230
237
  for cmd, name, mode in plan:
231
238
  subdir = FLEET.get(name, name)
232
239
  repo_path = args.fleet_root / subdir
@@ -242,9 +249,39 @@ def main() -> int:
242
249
  fname = f"{name}__{cmd or 'ask'}__{mode}.json"
243
250
  (out_dir / fname).write_text(json.dumps(cell, indent=2) + "\n", encoding="utf-8")
244
251
  w = cell["wall_ms"]
245
- print(f" p50={w['p50']}ms p95={w['p95']}ms -> {fname}")
252
+ gate = None
253
+ if args.compare_dir:
254
+ base_path = args.compare_dir / fname
255
+ if base_path.exists():
256
+ try:
257
+ baseline = json.loads(base_path.read_text(encoding="utf-8"))
258
+ gate = perf.regression_gate(
259
+ baseline,
260
+ cell,
261
+ max_regression=args.max_regression,
262
+ allow_incomparable=args.allow_incomparable,
263
+ )
264
+ (out_dir / f"{fname}.gate.json").write_text(
265
+ json.dumps(gate, indent=2) + "\n", encoding="utf-8"
266
+ )
267
+ if not gate.get("passed"):
268
+ failures.append((fname, gate))
269
+ except (OSError, ValueError) as exc:
270
+ failures.append((fname, {
271
+ "status": "incomparable",
272
+ "passed": False,
273
+ "reasons": [f"could not read baseline: {exc}"],
274
+ }))
275
+ _gate_text = f" gate={gate['status']}" if gate else ""
276
+ print(f" p50={w['p50']}ms p95={w['p95']}ms{_gate_text} -> {fname}")
246
277
 
247
278
  print(f"done. artifacts in {out_dir}")
279
+ if failures:
280
+ print("perf regression gate failed:", file=sys.stderr)
281
+ for fname, gate in failures:
282
+ detail = gate.get("failed_metrics") or gate.get("reasons")
283
+ print(f" {fname}: {gate.get('status')} {detail}", file=sys.stderr)
284
+ return 1
248
285
  return 0
249
286
 
250
287
 
@@ -4,4 +4,4 @@ ASK Engine is the product. ``ask`` is the canonical CLI command; ``sourcecode``
4
4
  the legacy compatibility alias and the Python/PyPI package name. See
5
5
  docs/PRODUCT_IDENTITY.md (normative)."""
6
6
 
7
- __version__ = "4.5.3"
7
+ __version__ = "4.7.0"
@@ -86,6 +86,14 @@ _MIN_CONFIDENT_SCORE = 0.5
86
86
  # discriminating. Tuned so a clear library (no app/server/servlet entry) is not confidently
87
87
  # labeled an engine, while runnable systems (which never trigger the gate) are untouched.
88
88
  _LIBRARY_ENGINE_DISCOUNT = 0.55
89
+ # The same shape for the opposite mistake (C3-43): a repository whose primary
90
+ # surface is HTTP owns storage/kernel packages and hub topology *because* it
91
+ # serves requests with them, so that evidence is not discriminating for "engine"
92
+ # either. Scaled by the measured density, so a repository with a marginal surface
93
+ # is barely discounted and one that is nothing but endpoints is discounted fully.
94
+ # Below the library figure on purpose: an application CAN be built around an
95
+ # engine, whereas a non-runnable artifact cannot be an engine product at all.
96
+ _HTTP_ENGINE_DISCOUNT = 0.45
89
97
  # Entry kinds that make a repo a runnable system (an app/server/servlet/daemon) rather
90
98
  # than a consumable library. Used to gate the library de-bias (P0).
91
99
  _RUNNABLE_ENTRY_KINDS = frozenset({
@@ -409,6 +417,42 @@ class ArchetypeClassifier:
409
417
  add("application", "runtime_entry_plus_services",
410
418
  f"bootstrap/server entry + service mass ≈ {cm['service']:.0%}",
411
419
  2.0, 1.0, max(cm["service"], 0.2))
420
+ # C3-43. The strongest MEASURED discriminator this build has for what a
421
+ # repository is — its HTTP surface — was read by `_primary_interface` and
422
+ # ignored here, so a 3 574-endpoint CRUD REST monolith was labelled
423
+ # `engine` on package-name masses and a fan-in Gini, while the legacy
424
+ # classifier it supersedes answered `api` and was right. Same ramp as the
425
+ # interface dimension, from the same features: one authority for the
426
+ # figure, two dimensions reading it.
427
+ if f.endpoint_share is None:
428
+ # Unmeasured is not zero: contribute nothing, and say so.
429
+ add("application", "http_surface_density",
430
+ "endpoint surface not measured — this dimension is scored without it",
431
+ 2.5, 0.0, 0.0)
432
+ else:
433
+ density = f.endpoint_share * 100
434
+ http_strength = (
435
+ max(0.0, min(1.0, (density - 0.5) / 1.5)) if f.endpoint_total else 0.0
436
+ )
437
+ add("application", "http_surface_density",
438
+ f"{f.endpoint_total} endpoints over {f.total_files} files "
439
+ f"({density:.2f}/100 files) — the repository's primary surface is HTTP",
440
+ 2.5, http_strength, 1.0)
441
+ # And the same fact as NAMED negative evidence for `engine`, the way
442
+ # the library de-bias below does it: a codebase whose product is a
443
+ # request surface owns storage and kernel packages *because* it is an
444
+ # application, so that mass is not, alone, evidence of an engine.
445
+ engine_positive_http = sum(max(0.0, e.contribution) for e in cands["engine"])
446
+ if http_strength > 0 and engine_positive_http > 0:
447
+ cands["engine"].append(Evidence(
448
+ "http_surface_discount",
449
+ f"{f.endpoint_total} endpoints over {f.total_files} files: the "
450
+ "primary surface of this repository is HTTP, and the storage/"
451
+ "kernel mass and hub topology an application needs to serve it "
452
+ "are not, alone, evidence of an engine product",
453
+ 1.0, 1.0, 1.0,
454
+ -engine_positive_http * _HTTP_ENGINE_DISCOUNT * http_strength,
455
+ ))
412
456
  # platform: many modules + multiple concept clusters + distribution
413
457
  multi = 1.0 if f.module_count >= 8 else f.module_count / 8
414
458
  add("platform", "many_modules_multi_concern",
@@ -210,7 +210,19 @@ def worktree_dirty(
210
210
  return None
211
211
  if out.returncode != 0:
212
212
  return None
213
- lines = [ln for ln in out.stdout.splitlines() if ln.strip()]
213
+ # C1-27. "Dirty" means the tree *the analysis reads* differs from HEAD. A
214
+ # change under an editor or agent state directory is not one — no analyser
215
+ # opens those files — and counting it reported STALE on a snapshot that
216
+ # described the tree exactly, with `Delta: 0` beside it. One authority answers
217
+ # which paths qualify (`path_filters.analysis_reads`) and its default is
218
+ # inclusive: anything not named there still counts, because a missed change
219
+ # is a false *fresh* and a spurious one only costs a rebuild.
220
+ from sourcecode.path_filters import analysis_reads
221
+
222
+ lines = [
223
+ ln for ln in out.stdout.splitlines()
224
+ if ln.strip() and analysis_reads(_porcelain_path(ln))
225
+ ]
214
226
  if ignore is None:
215
227
  return bool(lines)
216
228
  candidates = [ignore] if isinstance(ignore, (str, Path)) else list(ignore)
@@ -213,6 +213,14 @@ def _untracked_tree_fingerprint(target: Path) -> str:
213
213
  return f"ff{h.hexdigest()[:14]}"
214
214
 
215
215
 
216
+ def _porcelain_status_path(line: str) -> str:
217
+ """The path a `git status --porcelain` line refers to (destination on renames)."""
218
+ body = line[3:] if len(line) > 3 else ""
219
+ if " -> " in body:
220
+ body = body.split(" -> ", 1)[1]
221
+ return body.strip().strip('"')
222
+
223
+
216
224
  def worktree_signature(repo_root: Path, scope: Optional[Path] = None) -> str:
217
225
  """Hex fingerprint of the **exact tree state an analysis would read**.
218
226
 
@@ -252,12 +260,30 @@ def worktree_signature(repo_root: Path, scope: Optional[Path] = None) -> str:
252
260
  porcelain = st.stdout if st.returncode == 0 else ""
253
261
  except Exception:
254
262
  porcelain = ""
263
+ # C1-27. The signature describes *the tree an analysis would read*, so a line
264
+ # about a file no analyser opens does not belong in it — an editor settings
265
+ # file was invalidating every cached answer and publishing STALE beside
266
+ # `Delta: 0`. One authority decides which paths qualify, and its default is
267
+ # inclusive: anything not named there still invalidates.
268
+ from sourcecode.path_filters import analysis_reads
269
+
270
+ porcelain = "\n".join(
271
+ ln for ln in porcelain.splitlines()
272
+ if ln.strip() and analysis_reads(_porcelain_status_path(ln))
273
+ )
255
274
  if not porcelain.strip():
256
275
  return head # clean — HEAD fully describes the tree
257
276
 
258
277
  try:
278
+ from sourcecode.path_filters import _TOOL_STATE_DIRS
279
+
280
+ # The same exclusion, expressed to git for the half that is not a list of
281
+ # paths. A tracked editor-state file must not enter the signature through
282
+ # the diff after being kept out of the status.
283
+ _diff_spec = list(pathspec) or ["--", "."]
284
+ _diff_spec += [f":(exclude,glob)**/{d}/**" for d in sorted(_TOOL_STATE_DIRS)]
259
285
  df = subprocess.run(
260
- ["git", "-C", str(root), "diff", "HEAD", *pathspec],
286
+ ["git", "-C", str(root), "diff", "HEAD", *_diff_spec],
261
287
  capture_output=True, text=True, timeout=20,
262
288
  )
263
289
  diff_txt = df.stdout if df.returncode == 0 else ""
@@ -354,7 +354,7 @@ of files) in minutes. Semantic analysis itself is sub-second; repo indexing domi
354
354
  ask --agent [dim]# full structured JSON for AI agents[/dim]
355
355
 
356
356
  [bold]Change and risk:[/bold]
357
- impact-chain <Class> . [dim]# blast radius w/ TX + security per hop[/dim]
357
+ impact-chain <Class> . [dim]# blast radius; TX/SEC findings opt-in[/dim]
358
358
  impact <Class> . [dim]# reverse deps → endpoints reached[/dim]
359
359
  pr-impact . --files - [dim]# same, scoped to a diff on stdin; gating codes[/dim]
360
360
  posture . --since main [dim]# did this branch open an endpoint? (exp.)[/dim]
@@ -8419,8 +8419,16 @@ def impact_chain_cmd(
8419
8419
  "surfaces). Totals stay exact in metadata/truncated_lists. "
8420
8420
  "0 disables the cap.",
8421
8421
  ),
8422
+ with_findings: bool = typer.Option(
8423
+ False, "--with-findings",
8424
+ help=(
8425
+ "Also run the repository-wide TX + security audit and filter findings "
8426
+ "to this chain. Off by default so query cost follows the queried "
8427
+ "subgraph rather than the whole repository."
8428
+ ),
8429
+ ),
8422
8430
  ) -> None:
8423
- """Spring impact-chain: systemic blast radius of a symbol with TX/SEC enrichment.
8431
+ """Spring impact-chain: systemic blast radius of a symbol; TX/SEC findings are opt-in.
8424
8432
 
8425
8433
  \b
8426
8434
  Given a symbol (class or method), returns:
@@ -8431,6 +8439,7 @@ def impact_chain_cmd(
8431
8439
  - security_surfaces — per-endpoint security verdict + confidence
8432
8440
  (security_posture authority) + declared policy + SEC findings
8433
8441
  - impact_findings — TX/SEC audit findings touching the call chain
8442
+ (only with --with-findings)
8434
8443
  - risk_level — critical | high | medium | low
8435
8444
 
8436
8445
  \b
@@ -8537,7 +8546,10 @@ def impact_chain_cmd(
8537
8546
  )
8538
8547
  return
8539
8548
 
8540
- result = run_impact_chain(cir, symbol, depth=depth, root=target, model=_model)
8549
+ result = run_impact_chain(
8550
+ cir, symbol, depth=depth, root=target, model=_model,
8551
+ include_findings=with_findings,
8552
+ )
8541
8553
 
8542
8554
  data = result.to_dict()
8543
8555
  # Same rule as `impact`: a file is a request for the whole answer (C2-2). An
@@ -8853,7 +8865,9 @@ def explain_cmd(
8853
8865
  except Exception:
8854
8866
  cir = ContextGraph.build(file_list, target).cir # fallback: never break explain
8855
8867
  model = SpringSemanticModel.build(cir)
8856
- explanation = explain_class(class_name, cir, model).capped(limit)
8868
+ # `root` is what lets the security section read the request-chain rules a
8869
+ # configuration class declares in a DSL rather than in annotations (C3-41).
8870
+ explanation = explain_class(class_name, cir, model, root=target).capped(limit)
8857
8871
  finally:
8858
8872
  _prog.finish()
8859
8873
  if _cc_look is not None:
@@ -457,6 +457,10 @@ class JavaDetector(AbstractDetector):
457
457
  or "resteasy" in text # RESTEasy — a JAX-RS implementation
458
458
  ):
459
459
  frameworks.append(FrameworkDetection(name="JAX-RS", source=source))
460
+ if "com.sun.jersey" in text or "org.glassfish.jersey" in text:
461
+ frameworks.append(FrameworkDetection(name="Jersey", source=source))
462
+ if "com.netflix.governator" in text:
463
+ frameworks.append(FrameworkDetection(name="Governator", source=source))
460
464
  if "mybatis" in text:
461
465
  frameworks.append(FrameworkDetection(name="MyBatis", source=source))
462
466
  if "thymeleaf" in text: