sourcecode 4.9.0__tar.gz → 4.10.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 (218) hide show
  1. {sourcecode-4.9.0 → sourcecode-4.10.0}/CHANGELOG.md +40 -0
  2. {sourcecode-4.9.0 → sourcecode-4.10.0}/PKG-INFO +23 -10
  3. {sourcecode-4.9.0 → sourcecode-4.10.0}/README.md +22 -9
  4. {sourcecode-4.9.0 → sourcecode-4.10.0}/pyproject.toml +1 -1
  5. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/__init__.py +1 -1
  6. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/audit_report.py +21 -2
  7. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/cache_model.py +6 -0
  8. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/canonical_ir.py +19 -0
  9. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/cli.py +148 -10
  10. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/migrate_check.py +307 -1
  11. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/progress.py +21 -6
  12. sourcecode-4.10.0/src/sourcecode/provenance.py +202 -0
  13. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/release_info.py +1 -1
  14. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/risk.py +11 -0
  15. sourcecode-4.10.0/src/sourcecode/runs.py +136 -0
  16. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/sarif.py +12 -0
  17. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/security_config_scan.py +55 -0
  18. {sourcecode-4.9.0 → sourcecode-4.10.0}/.github/workflows/build-windows.yml +0 -0
  19. {sourcecode-4.9.0 → sourcecode-4.10.0}/.gitignore +0 -0
  20. {sourcecode-4.9.0 → sourcecode-4.10.0}/.ruff.toml +0 -0
  21. {sourcecode-4.9.0 → sourcecode-4.10.0}/CLAUDE.md +0 -0
  22. {sourcecode-4.9.0 → sourcecode-4.10.0}/CONTRIBUTING.md +0 -0
  23. {sourcecode-4.9.0 → sourcecode-4.10.0}/LICENSE +0 -0
  24. {sourcecode-4.9.0 → sourcecode-4.10.0}/SECURITY.md +0 -0
  25. {sourcecode-4.9.0 → sourcecode-4.10.0}/raw +0 -0
  26. {sourcecode-4.9.0 → sourcecode-4.10.0}/scripts/compare_integration_engines.py +0 -0
  27. {sourcecode-4.9.0 → sourcecode-4.10.0}/scripts/customer_smoke_test.sh +0 -0
  28. {sourcecode-4.9.0 → sourcecode-4.10.0}/scripts/generate_jdk_exports.py +0 -0
  29. {sourcecode-4.9.0 → sourcecode-4.10.0}/scripts/perf_harness.py +0 -0
  30. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/adaptive_scanner.py +0 -0
  31. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/archetype.py +0 -0
  32. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/architectural_baseline.py +0 -0
  33. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/architectural_delta.py +0 -0
  34. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/architecture_analyzer.py +0 -0
  35. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/architecture_summary.py +0 -0
  36. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/ast_extractor.py +0 -0
  37. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/baseline_autocapture.py +0 -0
  38. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/cache.py +0 -0
  39. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/call_surface.py +0 -0
  40. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/caller_metrics.py +0 -0
  41. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/caller_reach.py +0 -0
  42. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/chain_rules.py +0 -0
  43. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/change_plan.py +0 -0
  44. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/cir_graphs.py +0 -0
  45. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/classifier.py +0 -0
  46. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/client_calls.py +0 -0
  47. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  48. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/compare.py +0 -0
  49. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/confidence_analyzer.py +0 -0
  50. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/constraint_diff.py +0 -0
  51. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/context_cache.py +0 -0
  52. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/context_graph.py +0 -0
  53. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/context_scorer.py +0 -0
  54. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/context_summarizer.py +0 -0
  55. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/contract_diff.py +0 -0
  56. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/contract_init.py +0 -0
  57. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/contract_model.py +0 -0
  58. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/contract_pipeline.py +0 -0
  59. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/coverage_parser.py +0 -0
  60. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/data_exposure.py +0 -0
  61. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/data_labels.py +0 -0
  62. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/defect_identity.py +0 -0
  63. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/degradation.py +0 -0
  64. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/dependency_analyzer.py +0 -0
  65. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/deployment_prefix.py +0 -0
  66. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/__init__.py +0 -0
  67. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/base.py +0 -0
  68. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  69. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/dart.py +0 -0
  70. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/dotnet.py +0 -0
  71. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/elixir.py +0 -0
  72. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/go.py +0 -0
  73. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/heuristic.py +0 -0
  74. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/hybrid.py +0 -0
  75. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/java.py +0 -0
  76. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  77. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/nodejs.py +0 -0
  78. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/parsers.py +0 -0
  79. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/php.py +0 -0
  80. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/project.py +0 -0
  81. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/python.py +0 -0
  82. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/ruby.py +0 -0
  83. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/rust.py +0 -0
  84. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/systems.py +0 -0
  85. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/terraform.py +0 -0
  86. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/detectors/tooling.py +0 -0
  87. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/doc_analyzer.py +0 -0
  88. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/dynamic_argument_surface.py +0 -0
  89. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/endpoint_literals.py +0 -0
  90. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/endpoint_metrics.py +0 -0
  91. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  92. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/env_analyzer.py +0 -0
  93. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/envelope.py +0 -0
  94. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/environment_resolution.py +0 -0
  95. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/error_schema.py +0 -0
  96. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/evidence_provider.py +0 -0
  97. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/explain.py +0 -0
  98. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/facts/__init__.py +0 -0
  99. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/facts/registry.json +0 -0
  100. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/file_chunker.py +0 -0
  101. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/file_classifier.py +0 -0
  102. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/filter_surface.py +0 -0
  103. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/format_contract.py +0 -0
  104. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/fqn_utils.py +0 -0
  105. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/git_analyzer.py +0 -0
  106. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/git_checkout.py +0 -0
  107. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/graph_analyzer.py +0 -0
  108. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/graph_evidence.py +0 -0
  109. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/hibernate_strat.py +0 -0
  110. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/identity_fallback.py +0 -0
  111. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/integration_coordinates.py +0 -0
  112. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/jdk_exports.py +0 -0
  113. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/license.py +0 -0
  114. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/__init__.py +0 -0
  115. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  116. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  117. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  118. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  119. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  120. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/orchestrator.py +0 -0
  121. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/registry.py +0 -0
  122. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/runner.py +0 -0
  123. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp/server.py +0 -0
  124. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/mcp_nudge.py +0 -0
  125. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/metrics_analyzer.py +0 -0
  126. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/migration_blast.py +0 -0
  127. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/non_coverage.py +0 -0
  128. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/openapi_surface.py +0 -0
  129. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/openrewrite_recipe.py +0 -0
  130. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/output_budget.py +0 -0
  131. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/parse_cache.py +0 -0
  132. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/path_admission.py +0 -0
  133. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/path_filters.py +0 -0
  134. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/perf.py +0 -0
  135. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/pipe_contract.py +0 -0
  136. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/posture.py +0 -0
  137. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/pr_comment_renderer.py +0 -0
  138. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/pr_impact.py +0 -0
  139. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/prepare_context.py +0 -0
  140. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/ranking_engine.py +0 -0
  141. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/readiness_timeline.py +0 -0
  142. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/reconciliation.py +0 -0
  143. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/redactor.py +0 -0
  144. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/reference_facts.py +0 -0
  145. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/relevance_scorer.py +0 -0
  146. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/remedies.py +0 -0
  147. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/rename_refactor.py +0 -0
  148. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/repo_classifier.py +0 -0
  149. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/repository_ir.py +0 -0
  150. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/__init__.py +0 -0
  151. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/context.py +0 -0
  152. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/errors.py +0 -0
  153. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/executor.py +0 -0
  154. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/planner.py +0 -0
  155. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/query.py +0 -0
  156. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/request.py +0 -0
  157. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/resolution.py +0 -0
  158. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/result.py +0 -0
  159. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/retriever.py +0 -0
  160. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/runtime.py +0 -0
  161. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/steps.py +0 -0
  162. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
  163. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/steps_graph.py +0 -0
  164. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/steps_impact.py +0 -0
  165. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/steps_intf.py +0 -0
  166. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/steps_struct.py +0 -0
  167. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/retrieval/steps_txsec.py +0 -0
  168. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/ris.py +0 -0
  169. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/rule_catalog.py +0 -0
  170. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/runtime_classifier.py +0 -0
  171. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/scanner.py +0 -0
  172. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/schema.py +0 -0
  173. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
  174. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/security_config.py +0 -0
  175. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/security_posture.py +0 -0
  176. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/semantic_analyzer.py +0 -0
  177. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/semantic_impact_engine.py +0 -0
  178. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/semantic_integration_engine.py +0 -0
  179. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/semantic_services.py +0 -0
  180. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/serializer.py +0 -0
  181. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/servlet_surface.py +0 -0
  182. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/source_text.py +0 -0
  183. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_event_topology.py +0 -0
  184. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_findings.py +0 -0
  185. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_impact.py +0 -0
  186. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_model.py +0 -0
  187. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_profiles.py +0 -0
  188. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_properties.py +0 -0
  189. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_security_audit.py +0 -0
  190. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_semantic.py +0 -0
  191. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/spring_tx_analyzer.py +0 -0
  192. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/summarizer.py +0 -0
  193. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/target_admission.py +0 -0
  194. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/telemetry/__init__.py +0 -0
  195. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/telemetry/config.py +0 -0
  196. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/telemetry/consent.py +0 -0
  197. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/telemetry/events.py +0 -0
  198. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/telemetry/filters.py +0 -0
  199. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/telemetry/transport.py +0 -0
  200. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/test_gap_ranking.py +0 -0
  201. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/test_sources.py +0 -0
  202. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/token_estimate.py +0 -0
  203. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/tree_utils.py +0 -0
  204. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/type_usage_surface.py +0 -0
  205. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/validation_inference.py +0 -0
  206. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/validation_surface.py +0 -0
  207. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/verify_edit.py +0 -0
  208. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/verify_repo.py +0 -0
  209. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/verify_rules.py +0 -0
  210. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/version_check.py +0 -0
  211. {sourcecode-4.9.0 → sourcecode-4.10.0}/src/sourcecode/workspace.py +0 -0
  212. {sourcecode-4.9.0 → sourcecode-4.10.0}/supabase/functions/README.md +0 -0
  213. {sourcecode-4.9.0 → sourcecode-4.10.0}/supabase/functions/get-license/index.ts +0 -0
  214. {sourcecode-4.9.0 → sourcecode-4.10.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
  215. {sourcecode-4.9.0 → sourcecode-4.10.0}/supabase/functions/telemetry/index.ts +0 -0
  216. {sourcecode-4.9.0 → sourcecode-4.10.0}/supabase/sql/license_event_ordering.sql +0 -0
  217. {sourcecode-4.9.0 → sourcecode-4.10.0}/supabase/sql/licensing_schema.sql +0 -0
  218. {sourcecode-4.9.0 → sourcecode-4.10.0}/supabase/sql/telemetry_events.sql +0 -0
@@ -2,6 +2,46 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [4.10.0] — 2026-08-05
6
+
7
+ ### Fixed
8
+
9
+ - **Canonical endpoint projection rejects parser-corrupt Java handler names.**
10
+ Reserved Java keywords such as `if` can no longer reach CIR/risk as synthetic
11
+ handler symbols.
12
+ - **`DEAD-001` reports commented Java security annotations.** Java comments that
13
+ contain Spring/Jakarta/custom security annotations are now treated as disabled
14
+ controls, while active annotations stay out of dead-code findings.
15
+ - **`SEC-007` reports JavaMelody descriptor credentials.** `authorized-users`
16
+ values in deployment descriptors are detected and redacted even when they are
17
+ not written as `{SHA-*}` digest literals.
18
+ - **`audit-report` can reuse existing risk evidence.** `--from-risk risk.json`
19
+ packages a previous `ask risk` payload instead of recomputing repo-wide risk.
20
+ - **Long analysis observability improved.** `ASK_PROGRESS=1` enables non-TTY
21
+ heartbeat lines, long commands write durable `.ask/runs` records, and file
22
+ outputs are written atomically.
23
+ - **Large-repo CI budgets are explicit.** `ASK_MAX_ANALYSIS_SECONDS` can fail a
24
+ repo-wide/deep command before work starts when the configured budget is below
25
+ the command's safe floor.
26
+
27
+ ### Documentation
28
+
29
+ - README, user guide and root `ask --help` now distinguish per-symbol,
30
+ inventory and repo-wide/deep command costs instead of treating cache
31
+ benchmarks as universal runtime promises.
32
+
33
+ ## [4.9.1] — 2026-08-04
34
+
35
+ ### Added
36
+
37
+ - **Java LTS/licensing inventory in `migrate-check`.** Reports Java 8/11/17/21/25
38
+ evidence from Maven/Gradle, local runtime hints and container files, target-LTS
39
+ blockers via `--target-jdk`, and explicit Oracle JDK licensing-review signals
40
+ without changing migration readiness scoring.
41
+ - **Claim provenance ledger.** `risk`, `enrich`, `migrate-check`, `audit-report`
42
+ and `prepare-context` now emit `evidence_manifest` with stable claim IDs,
43
+ source paths/lines, command inputs, ASK version, git HEAD and freshness metadata.
44
+
5
45
  ## [4.9.0] — 2026-08-04
6
46
 
7
47
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 4.9.0
3
+ Version: 4.10.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.9.0-blue)
45
+ ![Version](https://img.shields.io/badge/version-4.10.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`**
@@ -54,9 +54,9 @@ Description-Content-Type: text/markdown
54
54
 
55
55
  ## The problem
56
56
 
57
- Every time an AI coding agent starts a new session, it has to re-parse the repository from scratch. For a large Java or TypeScript monolith, that means 5–15 seconds per invocation. Multiply by dozens of agent turns per hour, and repo context acquisition becomes a real bottleneck — not just latency, but tokens, compute, and iteration velocity.
57
+ Every time an AI coding agent starts a new session, it has to re-parse the repository from scratch. On small and mid-sized repos that cost is seconds; on large Java/Spring monoliths, repo-wide semantic composition can be minutes. Multiply that by dozens of agent turns per hour, and repo context acquisition becomes a real bottleneck — not just latency, but tokens, compute, and iteration velocity.
58
58
 
59
- ASK Engine solves this with a persistent structural cache keyed on file content hashes. After the first scan, every subsequent invocation returns pre-built context in milliseconds. The repo doesn't change? The cache doesn't expire.
59
+ ASK Engine solves this with a persistent structural cache keyed on file content hashes. After the first scan, later invocations reuse pre-built context whenever their command can consume the warmed layers. The repo doesn't change? The cache doesn't expire.
60
60
 
61
61
  **The cache is not a performance optimization. It is what makes ASK Engine usable as infrastructure rather than a one-off tool.**
62
62
 
@@ -69,9 +69,11 @@ ASK Engine solves this with a persistent structural cache keyed on file content
69
69
  | Keycloak | 7,885 Java files | 10.5s | 0.6s | **~17x** |
70
70
  | BroadleafCommerce | 2,985 Java files | 2.7s | 0.3s | **~9x** |
71
71
 
72
- Cache keyed on content hashes invalidated only when source changes. On repeated agent sessions against the same codebase, nearly every invocation is a cache hit.
72
+ These numbers are cache-layer benchmarks, not a promise for every command. Per-symbol queries and compact context benefit most. Inventory commands scale with file count. Repo-wide/deep compositions such as `risk`, `audit-report` and large `spring-audit` runs can take minutes on multi-thousand-endpoint repositories and belong in a supervised or nightly job unless CI sets an explicit budget.
73
73
 
74
- At 0.3s per call, ASK Engine becomes **constant infrastructure** inside agent loops — call it before every edit, every PR review, every test run, without batching or caching manually.
74
+ With the right command class, ASK Engine becomes **constant infrastructure** inside agent loops — call the fast/context surfaces before edits and reserve deep compositions for the points where their evidence is worth the runtime.
75
+
76
+ **Large-repo controls.** Set `ASK_PROGRESS=1` to get line heartbeats in non-TTY supervised runs. Set `ASK_MAX_ANALYSIS_SECONDS=<seconds>` to fail before starting a repo-wide/deep command whose configured budget is below its safe floor. Use `ask audit-report --from-risk risk.json` to package an existing risk run instead of recomputing it.
75
77
 
76
78
  **What a warm actually covers.** `ask cache warm` runs the compact analysis: it rebuilds the
77
79
  shared structural layers (L1/L2 + the Repository Intelligence Snapshot + the shared Canonical
@@ -97,7 +99,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
97
99
  # pip / pipx
98
100
  pipx install sourcecode # or: pip install sourcecode
99
101
 
100
- ask version # ask 4.9.0 — and, on a build that has aged,
102
+ ask version # ask 4.10.0 — and, on a build that has aged,
101
103
  # how many releases have probably shipped since
102
104
  ```
103
105
 
@@ -137,8 +139,9 @@ ask endpoints /path/to/repo
137
139
  # CGLIB no-op), security surface, request-body validation.
138
140
  ask spring-audit /path/to/repo
139
141
 
140
- # Spring Boot 2→3 readiness: located blockers, per-dimension score, effort estimate.
142
+ # Spring Boot 2→3 readiness plus Java LTS/licensing inventory.
141
143
  ask migrate-check /path/to/repo --compact
144
+ # Add --target-jdk 25 to make the LTS route explicit.
142
145
  ```
143
146
 
144
147
  **Then the three that finish the sentence the four above start.** A profile-set answer stays
@@ -308,12 +311,12 @@ from it.
308
311
  | `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
309
312
  | `risk` | experimental | what each defect actually costs, once reach, access, write effect and the shape of the input path are in it | `defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`; every factor names its authority; `--table --rule SEC-008 --band high --top-n 20` gives audit triage without `jq` |
310
313
  | `enrich` | experimental | another scanner's SARIF findings, ranked by what this repository does with them | `--sarif <log>`; same composition as `risk`, with `--table --rule <id> --band high --top-n 20` for triage |
311
- | `audit-report` | experimental | human audit bundle over existing `risk` + `posture` evidence, optionally signed | `--format markdown`; `--sign-key <file>` signs canonical JSON with HMAC-SHA256 |
314
+ | `audit-report` | experimental | human audit bundle over existing `risk` + `posture` evidence, optionally signed | includes `evidence_manifest` claim provenance; `--format markdown`; `--sign-key <file>` signs canonical JSON with HMAC-SHA256 |
312
315
  | `migrate-recipe` | experimental | the migration report as the OpenRewrite recipe that applies it | only recipes a finding named; the manual remainder published beside them; writes nothing without `--write`, and never a runnable command for an empty recipe list |
313
316
  | `data-exposure` | experimental | which routes can carry the data you labelled, and who reaches them | labels declared in `sourcecode.config.json` — never inferred from a name; `signature` and `call_reach` evidence published apart, field-level flow out of scope (NC-008). With nothing declared, `ask data-exposure /path/to/repo` answers `answered: false` and hands back the file, the key and an example to declare — it never reports zero exposed routes |
314
317
  | `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators). `--compact` answers the exposure census without the rows; `--servlets` lists the servlet-mounted surface as its own population; `--client-usage` says which routes the TS/JS client in this repository actually calls |
315
318
  | `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment`; `--table --rule SEC-008 --top-n 20` for human-scale review |
316
- | `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan; `--table --rule MIG-001 --band critical --top-n 20` for blocker triage |
319
+ | `migrate-check` | core | Boot 2→3 readiness + Java LTS/licensing inventory: located blockers, per-dimension score, effort, detected Java 8/11/17/21/25 evidence and explicit licensing-review signals | `--target-jdk 25` sets the target LTS route; `--blast-radius` orders the re-test plan; `--table --rule MIG-001 --band critical --top-n 20` for blocker triage |
317
320
  | `impact` / `impact-chain` | core | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
318
321
  | `pr-impact` | core | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
319
322
  | `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
@@ -401,6 +404,16 @@ and that gap is the honest description, not a defect to argue with. `migrate-che
401
404
  the OpenRewrite recipe each finding carries so the executor that does apply changes has its
402
405
  input.
403
406
 
407
+ **Java LTS/licensing inventory.** `migrate-check` emits `java_lts_inventory` beside the migration
408
+ scores. It reads Maven/Gradle, local runtime hints and container files for Java 8/11/17/21/25
409
+ evidence, reports target-LTS blockers with `--target-jdk`, and marks explicit Oracle JDK evidence
410
+ as `licensing_review_needed`. This is inventory evidence, not legal advice.
411
+
412
+ **Claim provenance ledger.** JSON outputs from `risk`, `enrich`, `migrate-check`,
413
+ `audit-report` and `prepare-context` include `evidence_manifest`: stable claim IDs mapped to
414
+ source paths/lines, command inputs, ASK version, git HEAD and freshness metadata. The manifest
415
+ indexes claims already in the payload; it does not add analysis or certify compliance.
416
+
404
417
 
405
418
  ---
406
419
 
@@ -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.9.0-blue)
7
+ ![Version](https://img.shields.io/badge/version-4.10.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`**
@@ -16,9 +16,9 @@
16
16
 
17
17
  ## The problem
18
18
 
19
- Every time an AI coding agent starts a new session, it has to re-parse the repository from scratch. For a large Java or TypeScript monolith, that means 5–15 seconds per invocation. Multiply by dozens of agent turns per hour, and repo context acquisition becomes a real bottleneck — not just latency, but tokens, compute, and iteration velocity.
19
+ Every time an AI coding agent starts a new session, it has to re-parse the repository from scratch. On small and mid-sized repos that cost is seconds; on large Java/Spring monoliths, repo-wide semantic composition can be minutes. Multiply that by dozens of agent turns per hour, and repo context acquisition becomes a real bottleneck — not just latency, but tokens, compute, and iteration velocity.
20
20
 
21
- ASK Engine solves this with a persistent structural cache keyed on file content hashes. After the first scan, every subsequent invocation returns pre-built context in milliseconds. The repo doesn't change? The cache doesn't expire.
21
+ ASK Engine solves this with a persistent structural cache keyed on file content hashes. After the first scan, later invocations reuse pre-built context whenever their command can consume the warmed layers. The repo doesn't change? The cache doesn't expire.
22
22
 
23
23
  **The cache is not a performance optimization. It is what makes ASK Engine usable as infrastructure rather than a one-off tool.**
24
24
 
@@ -31,9 +31,11 @@ ASK Engine solves this with a persistent structural cache keyed on file content
31
31
  | Keycloak | 7,885 Java files | 10.5s | 0.6s | **~17x** |
32
32
  | BroadleafCommerce | 2,985 Java files | 2.7s | 0.3s | **~9x** |
33
33
 
34
- Cache keyed on content hashes invalidated only when source changes. On repeated agent sessions against the same codebase, nearly every invocation is a cache hit.
34
+ These numbers are cache-layer benchmarks, not a promise for every command. Per-symbol queries and compact context benefit most. Inventory commands scale with file count. Repo-wide/deep compositions such as `risk`, `audit-report` and large `spring-audit` runs can take minutes on multi-thousand-endpoint repositories and belong in a supervised or nightly job unless CI sets an explicit budget.
35
35
 
36
- At 0.3s per call, ASK Engine becomes **constant infrastructure** inside agent loops — call it before every edit, every PR review, every test run, without batching or caching manually.
36
+ With the right command class, ASK Engine becomes **constant infrastructure** inside agent loops — call the fast/context surfaces before edits and reserve deep compositions for the points where their evidence is worth the runtime.
37
+
38
+ **Large-repo controls.** Set `ASK_PROGRESS=1` to get line heartbeats in non-TTY supervised runs. Set `ASK_MAX_ANALYSIS_SECONDS=<seconds>` to fail before starting a repo-wide/deep command whose configured budget is below its safe floor. Use `ask audit-report --from-risk risk.json` to package an existing risk run instead of recomputing it.
37
39
 
38
40
  **What a warm actually covers.** `ask cache warm` runs the compact analysis: it rebuilds the
39
41
  shared structural layers (L1/L2 + the Repository Intelligence Snapshot + the shared Canonical
@@ -59,7 +61,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
59
61
  # pip / pipx
60
62
  pipx install sourcecode # or: pip install sourcecode
61
63
 
62
- ask version # ask 4.9.0 — and, on a build that has aged,
64
+ ask version # ask 4.10.0 — and, on a build that has aged,
63
65
  # how many releases have probably shipped since
64
66
  ```
65
67
 
@@ -99,8 +101,9 @@ ask endpoints /path/to/repo
99
101
  # CGLIB no-op), security surface, request-body validation.
100
102
  ask spring-audit /path/to/repo
101
103
 
102
- # Spring Boot 2→3 readiness: located blockers, per-dimension score, effort estimate.
104
+ # Spring Boot 2→3 readiness plus Java LTS/licensing inventory.
103
105
  ask migrate-check /path/to/repo --compact
106
+ # Add --target-jdk 25 to make the LTS route explicit.
104
107
  ```
105
108
 
106
109
  **Then the three that finish the sentence the four above start.** A profile-set answer stays
@@ -270,12 +273,12 @@ from it.
270
273
  | `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
271
274
  | `risk` | experimental | what each defect actually costs, once reach, access, write effect and the shape of the input path are in it | `defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`; every factor names its authority; `--table --rule SEC-008 --band high --top-n 20` gives audit triage without `jq` |
272
275
  | `enrich` | experimental | another scanner's SARIF findings, ranked by what this repository does with them | `--sarif <log>`; same composition as `risk`, with `--table --rule <id> --band high --top-n 20` for triage |
273
- | `audit-report` | experimental | human audit bundle over existing `risk` + `posture` evidence, optionally signed | `--format markdown`; `--sign-key <file>` signs canonical JSON with HMAC-SHA256 |
276
+ | `audit-report` | experimental | human audit bundle over existing `risk` + `posture` evidence, optionally signed | includes `evidence_manifest` claim provenance; `--format markdown`; `--sign-key <file>` signs canonical JSON with HMAC-SHA256 |
274
277
  | `migrate-recipe` | experimental | the migration report as the OpenRewrite recipe that applies it | only recipes a finding named; the manual remainder published beside them; writes nothing without `--write`, and never a runnable command for an empty recipe list |
275
278
  | `data-exposure` | experimental | which routes can carry the data you labelled, and who reaches them | labels declared in `sourcecode.config.json` — never inferred from a name; `signature` and `call_reach` evidence published apart, field-level flow out of scope (NC-008). With nothing declared, `ask data-exposure /path/to/repo` answers `answered: false` and hands back the file, the key and an example to declare — it never reports zero exposed routes |
276
279
  | `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators). `--compact` answers the exposure census without the rows; `--servlets` lists the servlet-mounted surface as its own population; `--client-usage` says which routes the TS/JS client in this repository actually calls |
277
280
  | `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment`; `--table --rule SEC-008 --top-n 20` for human-scale review |
278
- | `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan; `--table --rule MIG-001 --band critical --top-n 20` for blocker triage |
281
+ | `migrate-check` | core | Boot 2→3 readiness + Java LTS/licensing inventory: located blockers, per-dimension score, effort, detected Java 8/11/17/21/25 evidence and explicit licensing-review signals | `--target-jdk 25` sets the target LTS route; `--blast-radius` orders the re-test plan; `--table --rule MIG-001 --band critical --top-n 20` for blocker triage |
279
282
  | `impact` / `impact-chain` | core | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
280
283
  | `pr-impact` | core | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
281
284
  | `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
@@ -363,6 +366,16 @@ and that gap is the honest description, not a defect to argue with. `migrate-che
363
366
  the OpenRewrite recipe each finding carries so the executor that does apply changes has its
364
367
  input.
365
368
 
369
+ **Java LTS/licensing inventory.** `migrate-check` emits `java_lts_inventory` beside the migration
370
+ scores. It reads Maven/Gradle, local runtime hints and container files for Java 8/11/17/21/25
371
+ evidence, reports target-LTS blockers with `--target-jdk`, and marks explicit Oracle JDK evidence
372
+ as `licensing_review_needed`. This is inventory evidence, not legal advice.
373
+
374
+ **Claim provenance ledger.** JSON outputs from `risk`, `enrich`, `migrate-check`,
375
+ `audit-report` and `prepare-context` include `evidence_manifest`: stable claim IDs mapped to
376
+ source paths/lines, command inputs, ASK version, git HEAD and freshness metadata. The manifest
377
+ indexes claims already in the payload; it does not add analysis or certify compliance.
378
+
366
379
 
367
380
  ---
368
381
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "4.9.0"
7
+ version = "4.10.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"
@@ -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.9.0"
7
+ __version__ = "4.10.0"
@@ -39,13 +39,19 @@ def build_audit_report(
39
39
  profiles: Optional[set[str]] = None,
40
40
  sign_key: Optional[bytes] = None,
41
41
  risk_limit: int = 10,
42
+ risk_payload: Optional[dict[str, Any]] = None,
42
43
  ) -> dict[str, Any]:
43
44
  """Build the buyer-readable audit bundle from existing command payloads."""
44
45
  from sourcecode.posture import build_posture
45
- from sourcecode.risk import build_risk
46
46
 
47
47
  root = Path(root).resolve()
48
- risk = build_risk(root, limit=risk_limit, min_band="low", profiles=profiles)
48
+ if risk_payload is None:
49
+ from sourcecode.risk import build_risk
50
+ risk = build_risk(root, limit=risk_limit, min_band="low", profiles=profiles)
51
+ risk_source = "computed"
52
+ else:
53
+ risk = risk_payload
54
+ risk_source = "from-risk"
49
55
  posture = build_posture(root, profiles or set())
50
56
  top_risks = risk.get("risks", [])[:risk_limit]
51
57
  access = ((posture.get("endpoints") or {}).get("effective_access") or {})
@@ -58,6 +64,7 @@ def build_audit_report(
58
64
  **({"profile_set": sorted(profiles)} if profiles else {}),
59
65
  "summary": {
60
66
  "risk_model": risk.get("model"),
67
+ "risk_source": risk_source,
61
68
  "total_defects": risk.get("total_defects"),
62
69
  "total_findings": risk.get("total_findings"),
63
70
  "risk_bands": risk.get("by_band", {}),
@@ -78,6 +85,18 @@ def build_audit_report(
78
85
  "non_coverage": (risk.get("non_coverage") or {}).get("items", []),
79
86
  },
80
87
  }
88
+ from sourcecode.provenance import build_evidence_manifest
89
+ unsigned["evidence_manifest"] = build_evidence_manifest(
90
+ unsigned,
91
+ command="audit-report",
92
+ root=root,
93
+ inputs={
94
+ "profiles": sorted(profiles) if profiles else None,
95
+ "risk_limit": risk_limit,
96
+ "risk_source": risk_source,
97
+ "signed": bool(sign_key),
98
+ },
99
+ )
81
100
  # Sign and publish the same JSON-normalized material. Some embedded evidence
82
101
  # may contain tuples or other JSON-coercible values; normalizing before signing
83
102
  # avoids a signature over an in-memory shape the user never receives.
@@ -144,6 +144,12 @@ COMMANDS: tuple[CommandCache, ...] = (
144
144
  "repository side, so what it buys is what it buys `risk`.",
145
145
  "not measured on the battery yet — bounded by the `risk` composition, plus "
146
146
  "reading one JSON file"),
147
+ CommandCache("audit-report", ("cir", "parse"), "shared", False,
148
+ "Packages `risk` and `posture` evidence. A warm helps the repository side; "
149
+ "`--from-risk risk.json` skips risk recomputation entirely and only builds "
150
+ "the posture/report projection.",
151
+ "not measured on the battery yet — bounded by `risk` + `posture`, or by "
152
+ "`posture` when `--from-risk` is supplied"),
147
153
  CommandCache("migrate-recipe", ("parse",), "shared", False,
148
154
  "Runs the same scan as `migrate-check` and projects its findings into an "
149
155
  "OpenRewrite recipe, so it buys exactly what a warm buys `migrate-check`: "
@@ -43,6 +43,23 @@ _REVERSE_EXCLUDE: frozenset[str] = frozenset({"annotated_with", "mapped_to"})
43
43
  # the CIR endpoint count reconciles with the `endpoints` command). See BUG #7.
44
44
  _FQN_PATH_RE: re.Pattern = re.compile(r"/(org|com|net|io|edu)\.[a-z][a-z0-9]*\.[a-zA-Z]")
45
45
 
46
+ _JAVA_RESERVED_HANDLER_NAMES: frozenset[str] = frozenset({
47
+ "if", "else", "for", "while", "do", "switch", "case", "break", "continue",
48
+ "return", "new", "throw", "try", "catch", "finally", "instanceof",
49
+ "this", "super", "void", "class", "interface", "enum", "extends", "implements",
50
+ "import", "package", "static", "final", "abstract", "synchronized", "native",
51
+ "true", "false", "null",
52
+ })
53
+
54
+
55
+ def _route_has_reserved_handler(route: dict) -> bool:
56
+ """Reject parser-corrupt endpoint symbols such as ``pkg.Controller#if``."""
57
+ symbol = str(route.get("symbol") or "")
58
+ if "#" not in symbol:
59
+ return False
60
+ handler = symbol.rsplit("#", 1)[1].split("(", 1)[0].strip()
61
+ return handler in _JAVA_RESERVED_HANDLER_NAMES
62
+
46
63
 
47
64
  # ---------------------------------------------------------------------------
48
65
  # CanonicalSecurity
@@ -438,6 +455,8 @@ def ir_dict_to_canonical(
438
455
  for r in route_surface:
439
456
  if r.get("scope") == "test_util":
440
457
  continue
458
+ if _route_has_reserved_handler(r):
459
+ continue
441
460
  if _FQN_PATH_RE.search(r.get("path", "") or ""):
442
461
  continue
443
462
  ep = _route_to_canonical_endpoint(r)
@@ -338,14 +338,16 @@ def _build_help_text() -> str:
338
338
  Deterministic Java/Spring semantics and reusable structural context for AI coding agents.
339
339
 
340
340
  Cache warms on first scan; later calls reuse pre-built context instead of rescanning.
341
- Scan and warm time scale with repo size small repos in seconds, large repos (thousands
342
- of files) in minutes. Semantic analysis itself is sub-second; repo indexing dominates.
341
+ Performance depends on command class and repo size: per-symbol queries are the fast path,
342
+ inventory commands scale with files, and repo-wide/deep compositions can take
343
+ minutes on multi-thousand-endpoint repositories. Use deep jobs nightly or with
344
+ ASK_MAX_ANALYSIS_SECONDS/ASK_PROGRESS when CI needs an explicit budget.
343
345
 
344
346
  [bold]Start here — Java/Spring analysis:[/bold]
345
347
  posture . --diff dev:prod [dim]# effective access, two profile sets (exp.)[/dim]
346
348
  endpoints . [dim]# endpoints + effective path + policy[/dim]
347
349
  spring-audit . [dim]# TX anomalies + security surface[/dim]
348
- migrate-check . --compact [dim]# Boot 2→3: located blockers + effort[/dim]
350
+ migrate-check . --compact [dim]# Boot 2→3 + Java LTS/licensing inventory[/dim]
349
351
  risk . [dim]# defects ranked by reach × access (exp.)[/dim]
350
352
 
351
353
  {_remedy_help_block()}
@@ -881,9 +883,24 @@ def _enforce_format(command: str, fmt: str) -> None:
881
883
 
882
884
 
883
885
  def _safe_write_file(path: "Path", content: str) -> None:
884
- """Write content to path, emitting a clean JSON error on I/O failure."""
886
+ """Atomically write content to path, emitting a clean JSON error on I/O failure."""
885
887
  try:
886
- path.write_text(content, encoding="utf-8")
888
+ path = Path(path)
889
+ path.parent.mkdir(parents=True, exist_ok=True)
890
+ tmp = path.with_name(f".{path.name}.tmp-{os.getpid()}-{time.time_ns()}")
891
+ tmp.write_text(content, encoding="utf-8")
892
+ tmp.replace(path)
893
+ try:
894
+ from sourcecode.runs import active_run
895
+ run = active_run()
896
+ if run is not None:
897
+ run.write(
898
+ status="running",
899
+ output_path=path,
900
+ output_size=path.stat().st_size,
901
+ )
902
+ except Exception:
903
+ pass
887
904
  except OSError as _exc:
888
905
  _emit_error_json(
889
906
  INVALID_INPUT_CODE,
@@ -968,6 +985,50 @@ def _active_command_context() -> "tuple[str, Optional[Path]]":
968
985
 
969
986
 
970
987
  _EXPENSIVE_ANALYSIS_TTL_SECONDS = 6 * 60 * 60
988
+ _ANALYSIS_CLASSES: dict[str, tuple[str, int, str]] = {
989
+ "spring-audit": ("repo-wide", 600, "use nightly/deep tier on large repositories"),
990
+ "risk": ("deep", 1200, "run `ask spring-audit` or a saved `risk.json` first"),
991
+ "audit-report": ("deep", 1200, "reuse `--from-risk risk.json` or schedule nightly"),
992
+ "verify --init": ("repo-wide", 600, "derive contracts outside pre-commit"),
993
+ "verify": ("core", 60, "run with a larger CI budget or narrow the contract set"),
994
+ "migrate-check": ("repo-wide", 600, "run inventory in CI and deep migration checks nightly"),
995
+ }
996
+
997
+
998
+ def _analysis_budget(command: str) -> dict[str, Any]:
999
+ cls, recommended, fallback = _ANALYSIS_CLASSES.get(
1000
+ command, ("repo-wide", 600, "run this command in a supervised or nightly job")
1001
+ )
1002
+ configured: Optional[float] = None
1003
+ raw = os.environ.get("ASK_MAX_ANALYSIS_SECONDS")
1004
+ if raw:
1005
+ try:
1006
+ configured = float(raw)
1007
+ except ValueError:
1008
+ configured = None
1009
+ return {
1010
+ "class": cls,
1011
+ "recommended_min_seconds": recommended,
1012
+ "configured_max_seconds": configured,
1013
+ "fallback": fallback,
1014
+ }
1015
+
1016
+
1017
+ def _enforce_analysis_budget(command: str, budget: dict[str, Any]) -> None:
1018
+ configured = budget.get("configured_max_seconds")
1019
+ recommended = float(budget.get("recommended_min_seconds") or 0)
1020
+ if configured is None or float(configured) >= recommended:
1021
+ return
1022
+ _emit_error_json(
1023
+ INVALID_INPUT_CODE,
1024
+ (
1025
+ f"{command} is a {budget.get('class')} analysis and the configured "
1026
+ f"budget ({configured:g}s) is below its safe floor ({recommended:g}s)."
1027
+ ),
1028
+ hint=str(budget.get("fallback") or "raise ASK_MAX_ANALYSIS_SECONDS"),
1029
+ expected=f"ASK_MAX_ANALYSIS_SECONDS >= {recommended:g}",
1030
+ )
1031
+ raise typer.Exit(code=2)
971
1032
 
972
1033
 
973
1034
  def _analysis_lock_path(path: Path) -> Path:
@@ -1051,8 +1112,14 @@ def _emit_analysis_contention_warning(command: str, path: Path, phase: str) -> N
1051
1112
  @contextlib.contextmanager
1052
1113
  def _expensive_analysis_scope(command: str, path: Path, phase: str):
1053
1114
  """Register a long repository-wide analysis and warn on concurrent runs."""
1115
+ from sourcecode.runs import RunRecord, reset_active_run, set_active_run
1116
+
1054
1117
  lock_path = _analysis_lock_path(path)
1055
1118
  _emit_analysis_contention_warning(command, path, phase)
1119
+ budget = _analysis_budget(command)
1120
+ _enforce_analysis_budget(command, budget)
1121
+ run_record = RunRecord.start(path, command, phase, budget=budget)
1122
+ run_token = set_active_run(run_record)
1056
1123
  token = f"{os.getpid()}:{time.time_ns()}"
1057
1124
  owns_lock = False
1058
1125
  if _active_analysis_record(lock_path) is None:
@@ -1077,6 +1144,12 @@ def _expensive_analysis_scope(command: str, path: Path, phase: str):
1077
1144
  owns_lock = False
1078
1145
  try:
1079
1146
  yield
1147
+ if run_record is not None:
1148
+ run_record.write(status="complete", exit_code=0)
1149
+ except BaseException as exc:
1150
+ if run_record is not None:
1151
+ run_record.write(status="failed", exit_code=1, error=str(exc))
1152
+ raise
1080
1153
  finally:
1081
1154
  if owns_lock:
1082
1155
  try:
@@ -1088,6 +1161,7 @@ def _expensive_analysis_scope(command: str, path: Path, phase: str):
1088
1161
  lock_path.unlink()
1089
1162
  except OSError:
1090
1163
  pass
1164
+ reset_active_run(run_token)
1091
1165
 
1092
1166
 
1093
1167
  def _emit_command_output(
@@ -3875,6 +3949,11 @@ def prepare_context_cmd(
3875
3949
  ask prepare-context review-pr . --since main --output review.json
3876
3950
  ask prepare-context onboard --llm-prompt
3877
3951
  ask prepare-context --task-help
3952
+
3953
+ \b
3954
+ Provenance:
3955
+ JSON output includes evidence_manifest: claim IDs for context files and
3956
+ source-backed rows, plus command inputs, ASK version, git HEAD and freshness.
3878
3957
  """
3879
3958
  from sourcecode.prepare_context import TASKS, TaskContextBuilder
3880
3959
 
@@ -4419,6 +4498,20 @@ def prepare_context_cmd(
4419
4498
  _skipped.append("test_gap_discovery")
4420
4499
  out["skipped_analyzers"] = _skipped
4421
4500
 
4501
+ from sourcecode.provenance import build_evidence_manifest as _build_evidence_manifest
4502
+ out["evidence_manifest"] = _build_evidence_manifest(
4503
+ out,
4504
+ command="prepare-context",
4505
+ root=target,
4506
+ inputs={
4507
+ "task": task,
4508
+ "since": since,
4509
+ "format": format or "json",
4510
+ "fast": fast,
4511
+ "llm_prompt": llm_prompt,
4512
+ },
4513
+ )
4514
+
4422
4515
  # P0-1: Apply output budget per task — safety net for large repos.
4423
4516
  _pc_budget = _prepare_context_budget(task)
4424
4517
 
@@ -8007,6 +8100,11 @@ def audit_report_cmd(
8007
8100
  format: str = typer.Option(
8008
8101
  "json", "--format", "-f", help="Output format: json, yaml or markdown."
8009
8102
  ),
8103
+ from_risk: Optional[Path] = typer.Option(
8104
+ None,
8105
+ "--from-risk",
8106
+ help="Reuse an existing `ask risk -o risk.json` payload instead of recomputing risk.",
8107
+ ),
8010
8108
  copy: bool = _copy_option(),
8011
8109
  ) -> None:
8012
8110
  """[EXPERIMENTAL] Human audit bundle over existing ASK evidence, optionally signed.
@@ -8015,7 +8113,8 @@ def audit_report_cmd(
8015
8113
  This packages the same evidence `risk` and `posture` already publish into a
8016
8114
  report a buyer can read: top risks, effective runtime posture, source-linked
8017
8115
  evidence and non-coverage. It does not certify compliance, choose fixes or
8018
- assign ROI.
8116
+ assign ROI. JSON includes evidence_manifest: claim IDs mapped to source spans,
8117
+ command inputs, ASK version and freshness.
8019
8118
 
8020
8119
  \b
8021
8120
  `--sign-key` adds an HMAC-SHA256 signature over the canonical JSON payload.
@@ -8024,6 +8123,7 @@ def audit_report_cmd(
8024
8123
  \b
8025
8124
  Examples:
8026
8125
  ask audit-report .
8126
+ ask risk . -o risk.json && ask audit-report . --from-risk risk.json
8027
8127
  ask audit-report . --profile prod --format markdown
8028
8128
  ask audit-report . --sign-key audit.key -o audit-report.json
8029
8129
  """
@@ -8059,12 +8159,42 @@ def audit_report_cmd(
8059
8159
  expected="a non-empty key file",
8060
8160
  )
8061
8161
  raise typer.Exit(code=1)
8162
+ risk_payload = None
8163
+ if from_risk is not None:
8164
+ risk_path = Path(from_risk).expanduser()
8165
+ if not risk_path.is_file():
8166
+ _emit_error_json(
8167
+ INVALID_INPUT_CODE,
8168
+ f"--from-risk must name a readable risk JSON file (got {str(from_risk)!r}).",
8169
+ hint="Example: ask risk . -o risk.json && ask audit-report . --from-risk risk.json",
8170
+ expected="an existing JSON file produced by `ask risk`",
8171
+ )
8172
+ raise typer.Exit(code=1)
8173
+ try:
8174
+ risk_payload = json.loads(risk_path.read_text(encoding="utf-8"))
8175
+ except Exception as exc:
8176
+ _emit_error_json(
8177
+ INVALID_INPUT_CODE,
8178
+ f"--from-risk is not valid JSON: {exc}",
8179
+ hint="Regenerate it with: ask risk . -o risk.json",
8180
+ expected="a JSON object produced by `ask risk`",
8181
+ )
8182
+ raise typer.Exit(code=1)
8183
+ if not isinstance(risk_payload, dict) or "risks" not in risk_payload:
8184
+ _emit_error_json(
8185
+ INVALID_INPUT_CODE,
8186
+ "--from-risk does not look like an `ask risk` payload.",
8187
+ hint="Regenerate it with: ask risk . -o risk.json",
8188
+ expected="a JSON object with a `risks` array",
8189
+ )
8190
+ raise typer.Exit(code=1)
8062
8191
 
8063
8192
  _prog = Progress()
8064
8193
  _prog.start("packaging audit evidence")
8065
8194
  try:
8066
8195
  data = build_audit_report(
8067
8196
  path, profiles=_profile_set(profile), sign_key=key_bytes,
8197
+ risk_payload=risk_payload,
8068
8198
  )
8069
8199
  finally:
8070
8200
  _prog.stop()
@@ -8724,9 +8854,9 @@ def migrate_check_cmd(
8724
8854
  None,
8725
8855
  "--target-jdk",
8726
8856
  help=(
8727
- "The JDK you are actually moving to (e.g. 11, 17, 21). Rules for a "
8728
- "later JDK are not your blockers and are not reported. Without it, "
8729
- "every JDK axis is reported at once."
8857
+ "The JDK you are actually moving to (e.g. 11, 17, 21, 25). Rules "
8858
+ "for a later JDK are not your blockers and are not reported. Also "
8859
+ "sets java_lts_inventory.target_lts."
8730
8860
  ),
8731
8861
  ),
8732
8862
  keep_boot: bool = typer.Option(
@@ -8786,7 +8916,7 @@ def migrate_check_cmd(
8786
8916
  help="Caller BFS depth for --blast-radius (1-8, default: 4).",
8787
8917
  ),
8788
8918
  ) -> None:
8789
- """Spring Boot 2→3 migration readiness: detect javax→jakarta namespace blockers.
8919
+ """Spring Boot 2→3 migration readiness + Java LTS/licensing inventory.
8790
8920
 
8791
8921
  \b
8792
8922
  Detects:
@@ -8815,6 +8945,7 @@ def migrate_check_cmd(
8815
8945
  ask migrate-check . --compact bounded decision summary
8816
8946
  ask migrate-check /path/to/repo --format text
8817
8947
  ask migrate-check . --min-severity high
8948
+ ask migrate-check . --target-jdk 25 Java LTS target inventory
8818
8949
  ask migrate-check . --table --rule MIG-001 --band critical --top-n 20
8819
8950
  ask migrate-check . --output migration.json
8820
8951
  ask migrate-check . --snapshot --ref sprint-12 persist a readiness point
@@ -8837,6 +8968,13 @@ def migrate_check_cmd(
8837
8968
  <repo>/.ask/readiness-history). --trend reads that series and reports
8838
8969
  first→last movement — no improving/degrading label, and readiness_score is
8839
8970
  flagged not-comparable when the applicable dimension set changed.
8971
+
8972
+ \b
8973
+ Java LTS/licensing inventory:
8974
+ The JSON report includes java_lts_inventory: Java 8/11/17/21/25 evidence
8975
+ from Maven/Gradle, local runtime hints and container files; target-LTS
8976
+ blockers; and explicit Oracle JDK/licensing-review signals. This is
8977
+ inventory evidence, not legal advice, and it never changes readiness_score.
8840
8978
  """
8841
8979
  from sourcecode.repository_ir import find_java_files
8842
8980
  from sourcecode.migrate_check import run_migrate_check