sourcecode 4.0.1__tar.gz → 4.2.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 (206) hide show
  1. {sourcecode-4.0.1 → sourcecode-4.2.0}/CHANGELOG.md +217 -0
  2. {sourcecode-4.0.1 → sourcecode-4.2.0}/PKG-INFO +29 -3
  3. {sourcecode-4.0.1 → sourcecode-4.2.0}/README.md +28 -2
  4. {sourcecode-4.0.1 → sourcecode-4.2.0}/pyproject.toml +1 -1
  5. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/__init__.py +1 -1
  6. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/caller_reach.py +16 -7
  7. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/canonical_ir.py +29 -0
  8. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/cli.py +247 -3
  9. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/contract_diff.py +5 -4
  10. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/envelope.py +10 -0
  11. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/environment_resolution.py +100 -6
  12. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/facts/registry.json +15 -0
  13. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/git_checkout.py +5 -2
  14. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/non_coverage.py +33 -5
  15. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/posture.py +483 -7
  16. sourcecode-4.2.0/src/sourcecode/release_info.py +123 -0
  17. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/remedies.py +18 -1
  18. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/risk.py +73 -15
  19. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/rule_catalog.py +1 -0
  20. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/schemas/envelope-v1.schema.json +8 -1
  21. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/security_config_scan.py +132 -1
  22. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/spring_impact.py +14 -3
  23. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/spring_security_audit.py +16 -2
  24. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/verify_repo.py +5 -0
  25. {sourcecode-4.0.1 → sourcecode-4.2.0}/.github/workflows/build-windows.yml +0 -0
  26. {sourcecode-4.0.1 → sourcecode-4.2.0}/.gitignore +0 -0
  27. {sourcecode-4.0.1 → sourcecode-4.2.0}/.ruff.toml +0 -0
  28. {sourcecode-4.0.1 → sourcecode-4.2.0}/CONTRIBUTING.md +0 -0
  29. {sourcecode-4.0.1 → sourcecode-4.2.0}/LICENSE +0 -0
  30. {sourcecode-4.0.1 → sourcecode-4.2.0}/SECURITY.md +0 -0
  31. {sourcecode-4.0.1 → sourcecode-4.2.0}/raw +0 -0
  32. {sourcecode-4.0.1 → sourcecode-4.2.0}/scripts/compare_integration_engines.py +0 -0
  33. {sourcecode-4.0.1 → sourcecode-4.2.0}/scripts/customer_smoke_test.sh +0 -0
  34. {sourcecode-4.0.1 → sourcecode-4.2.0}/scripts/generate_jdk_exports.py +0 -0
  35. {sourcecode-4.0.1 → sourcecode-4.2.0}/scripts/perf_harness.py +0 -0
  36. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/adaptive_scanner.py +0 -0
  37. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/archetype.py +0 -0
  38. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/architectural_baseline.py +0 -0
  39. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/architectural_delta.py +0 -0
  40. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/architecture_analyzer.py +0 -0
  41. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/architecture_summary.py +0 -0
  42. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/ast_extractor.py +0 -0
  43. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/cache.py +0 -0
  44. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/cache_model.py +0 -0
  45. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/call_surface.py +0 -0
  46. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/caller_metrics.py +0 -0
  47. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/chain_rules.py +0 -0
  48. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/change_plan.py +0 -0
  49. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/cir_graphs.py +0 -0
  50. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/classifier.py +0 -0
  51. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  52. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/compare.py +0 -0
  53. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/confidence_analyzer.py +0 -0
  54. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/constraint_diff.py +0 -0
  55. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/context_cache.py +0 -0
  56. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/context_graph.py +0 -0
  57. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/context_scorer.py +0 -0
  58. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/context_summarizer.py +0 -0
  59. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/contract_init.py +0 -0
  60. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/contract_model.py +0 -0
  61. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/contract_pipeline.py +0 -0
  62. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/coverage_parser.py +0 -0
  63. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/defect_identity.py +0 -0
  64. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/degradation.py +0 -0
  65. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/dependency_analyzer.py +0 -0
  66. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/deployment_prefix.py +0 -0
  67. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/__init__.py +0 -0
  68. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/base.py +0 -0
  69. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  70. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/dart.py +0 -0
  71. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/dotnet.py +0 -0
  72. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/elixir.py +0 -0
  73. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/go.py +0 -0
  74. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/heuristic.py +0 -0
  75. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/hybrid.py +0 -0
  76. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/java.py +0 -0
  77. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  78. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/nodejs.py +0 -0
  79. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/parsers.py +0 -0
  80. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/php.py +0 -0
  81. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/project.py +0 -0
  82. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/python.py +0 -0
  83. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/ruby.py +0 -0
  84. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/rust.py +0 -0
  85. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/systems.py +0 -0
  86. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/terraform.py +0 -0
  87. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/detectors/tooling.py +0 -0
  88. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/doc_analyzer.py +0 -0
  89. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/dynamic_argument_surface.py +0 -0
  90. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/endpoint_literals.py +0 -0
  91. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/endpoint_metrics.py +0 -0
  92. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  93. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/env_analyzer.py +0 -0
  94. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/error_schema.py +0 -0
  95. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/evidence_provider.py +0 -0
  96. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/explain.py +0 -0
  97. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/facts/__init__.py +0 -0
  98. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/file_chunker.py +0 -0
  99. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/file_classifier.py +0 -0
  100. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/filter_surface.py +0 -0
  101. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/format_contract.py +0 -0
  102. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/fqn_utils.py +0 -0
  103. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/git_analyzer.py +0 -0
  104. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/graph_analyzer.py +0 -0
  105. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/graph_evidence.py +0 -0
  106. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/hibernate_strat.py +0 -0
  107. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/identity_fallback.py +0 -0
  108. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/integration_coordinates.py +0 -0
  109. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/jdk_exports.py +0 -0
  110. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/license.py +0 -0
  111. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/mcp/__init__.py +0 -0
  112. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  113. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  114. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  115. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  116. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  117. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/mcp/orchestrator.py +0 -0
  118. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/mcp/registry.py +0 -0
  119. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/mcp/runner.py +0 -0
  120. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/mcp/server.py +0 -0
  121. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/mcp_nudge.py +0 -0
  122. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/metrics_analyzer.py +0 -0
  123. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/migrate_check.py +0 -0
  124. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/migration_blast.py +0 -0
  125. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/openapi_surface.py +0 -0
  126. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/output_budget.py +0 -0
  127. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/parse_cache.py +0 -0
  128. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/path_admission.py +0 -0
  129. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/path_filters.py +0 -0
  130. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/perf.py +0 -0
  131. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/pipe_contract.py +0 -0
  132. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/pr_comment_renderer.py +0 -0
  133. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/pr_impact.py +0 -0
  134. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/prepare_context.py +0 -0
  135. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/progress.py +0 -0
  136. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/ranking_engine.py +0 -0
  137. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/readiness_timeline.py +0 -0
  138. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/reconciliation.py +0 -0
  139. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/redactor.py +0 -0
  140. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/reference_facts.py +0 -0
  141. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/relevance_scorer.py +0 -0
  142. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/rename_refactor.py +0 -0
  143. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/repo_classifier.py +0 -0
  144. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/repository_ir.py +0 -0
  145. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/__init__.py +0 -0
  146. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/context.py +0 -0
  147. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/errors.py +0 -0
  148. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/executor.py +0 -0
  149. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/planner.py +0 -0
  150. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/query.py +0 -0
  151. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/request.py +0 -0
  152. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/resolution.py +0 -0
  153. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/result.py +0 -0
  154. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/retriever.py +0 -0
  155. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/runtime.py +0 -0
  156. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/steps.py +0 -0
  157. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
  158. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/steps_graph.py +0 -0
  159. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/steps_impact.py +0 -0
  160. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/steps_intf.py +0 -0
  161. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/steps_struct.py +0 -0
  162. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/retrieval/steps_txsec.py +0 -0
  163. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/ris.py +0 -0
  164. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/runtime_classifier.py +0 -0
  165. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/scanner.py +0 -0
  166. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/schema.py +0 -0
  167. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/security_config.py +0 -0
  168. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/security_posture.py +0 -0
  169. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/semantic_analyzer.py +0 -0
  170. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/semantic_impact_engine.py +0 -0
  171. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/semantic_integration_engine.py +0 -0
  172. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/semantic_services.py +0 -0
  173. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/serializer.py +0 -0
  174. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/spring_event_topology.py +0 -0
  175. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/spring_findings.py +0 -0
  176. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/spring_model.py +0 -0
  177. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/spring_profiles.py +0 -0
  178. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/spring_properties.py +0 -0
  179. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/spring_semantic.py +0 -0
  180. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/spring_tx_analyzer.py +0 -0
  181. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/summarizer.py +0 -0
  182. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/target_admission.py +0 -0
  183. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/telemetry/__init__.py +0 -0
  184. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/telemetry/config.py +0 -0
  185. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/telemetry/consent.py +0 -0
  186. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/telemetry/events.py +0 -0
  187. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/telemetry/filters.py +0 -0
  188. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/telemetry/transport.py +0 -0
  189. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/test_gap_ranking.py +0 -0
  190. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/test_sources.py +0 -0
  191. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/token_estimate.py +0 -0
  192. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/tree_utils.py +0 -0
  193. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/type_usage_surface.py +0 -0
  194. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/validation_inference.py +0 -0
  195. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/validation_surface.py +0 -0
  196. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/verify_edit.py +0 -0
  197. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/verify_rules.py +0 -0
  198. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/version_check.py +0 -0
  199. {sourcecode-4.0.1 → sourcecode-4.2.0}/src/sourcecode/workspace.py +0 -0
  200. {sourcecode-4.0.1 → sourcecode-4.2.0}/supabase/functions/README.md +0 -0
  201. {sourcecode-4.0.1 → sourcecode-4.2.0}/supabase/functions/get-license/index.ts +0 -0
  202. {sourcecode-4.0.1 → sourcecode-4.2.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
  203. {sourcecode-4.0.1 → sourcecode-4.2.0}/supabase/functions/telemetry/index.ts +0 -0
  204. {sourcecode-4.0.1 → sourcecode-4.2.0}/supabase/sql/license_event_ordering.sql +0 -0
  205. {sourcecode-4.0.1 → sourcecode-4.2.0}/supabase/sql/licensing_schema.sql +0 -0
  206. {sourcecode-4.0.1 → sourcecode-4.2.0}/supabase/sql/telemetry_events.sql +0 -0
@@ -2,6 +2,223 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [4.2.0] — 2026-08-03
6
+
7
+ Minor, not a patch, by this project's own criterion: two published figures move
8
+ and a verdict changes, so a pipeline reading either can change colour.
9
+ `posture --resolve-environments` answers `NOT DECIDED IN THIS REPOSITORY` where
10
+ it answered `artefacts_disagree` on a repository whose build properties nothing
11
+ consumes (C1-22), and `ask risk` publishes defects where it published findings,
12
+ so `total_defects` and `by_band` move (C1-23) — 20 → 15 on BroadleafCommerce.
13
+ `risk` also drops `rule_id` for `rule_ids`: it is in the `experimental` tier,
14
+ whose published promise is exactly that its shape may change in a minor.
15
+
16
+ Field evaluation #9 (8/10, same 3 337-file monolith as #6–#8) opened nine rows
17
+ and this release closes seven of them. The two left open are open on purpose:
18
+ `C3-39` needs a Windows runner before it needs a fix, and `P-7` is a pricing
19
+ decision. Every complaint was re-measured against HEAD before a row was written
20
+ — five reproduced, one was half false, one was not reproducible here, and one
21
+ was a capability that already shipped.
22
+
23
+ ### Added
24
+
25
+ - **`ask posture --diff-ref <base>:<head>` and `--since <ref>` — one profile set,
26
+ two git refs** (roadmap M10.5 item 1). `--diff` holds the tree fixed and moves
27
+ the profile set; this holds the profile set fixed and moves the tree, which is
28
+ the question a pull request asks: *does this change what a client can reach
29
+ without authenticating?* `--since` compares a ref with the working tree,
30
+ uncommitted edits included. Both refs are read with `git archive`: nothing is
31
+ written to the repository, no worktree is created and the index is not touched.
32
+ `docs/posture.md` had declared this as the one requested extension with no
33
+ feature behind it.
34
+ - **`--fail-on opened|any|never` — the gate half.** Default `never`, so no
35
+ invocation that worked yesterday changes colour today; `opened` exits 1 when a
36
+ request a readable rule leaves reachable unauthenticated was not one before.
37
+ The payload is emitted before the exit code, because a red pipeline with no
38
+ statement of what opened is a gate nobody keeps. It requires a ref comparison —
39
+ gating a single run would gate on pre-existing debt, which is `spring-audit --ci`.
40
+ - **`endpoint_request_identity` registered as a fact** (ADR-0008 R11,
41
+ `sourcecode.canonical_ir:request_identity`). The comparison unit is the request
42
+ (`METHOD path`), not the endpoint id, which carries the controller FQN and the
43
+ handler symbol and therefore changes when a handler moves between classes
44
+ without the URL changing. `contract_diff` re-derived the same identity and now
45
+ binds to the authority. Path-variable patterns are deliberately **not**
46
+ normalised: `{id:.*}` and `{id:[^0-9].*}` are different URLs to a caller, and
47
+ one field repository moved 93 requests with exactly that edit in a single commit.
48
+
49
+ ### Added
50
+
51
+ - **`ask endpoints --compact` — the census instead of the rows** (C2-22, field
52
+ evaluation #9). Asked how exposed a repository was, the command answered with
53
+ 1.9 MB of JSON for 3 574 endpoints and no summary mode, and the evaluator
54
+ aggregated it by hand. Every answer now carries an `exposure` block — counts by
55
+ method, by security policy, by controller and by first path area — and
56
+ `--compact` returns it without the rows, declaring what it dropped. Two rules
57
+ it obeys against itself: the census is measured over the population the filters
58
+ chose and never over what `--limit` left rendered, and every ranked rollup
59
+ states its own total when it cuts. Measured on BroadleafCommerce: 95 KB → 11 KB,
60
+ every count unchanged. (The other half of the complaint is recorded as false:
61
+ `spring-audit` has shipped `--compact`, `--min-severity` and `--scope` for
62
+ releases.)
63
+
64
+ - **NC-007 — the endpoint population is declared** (CL-12, field evaluation #9).
65
+ `endpoints` projects Spring handler mappings; a servlet declared in `web.xml`
66
+ or registered as a `ServletRegistrationBean` is reachable over HTTP and is in
67
+ no part of that model. Six published non-coverage rows are exactly what let a
68
+ reader treat the list as the whole HTTP surface, and the evaluation lost a
69
+ monitoring console that way — at a path behind the credential the same run
70
+ reported as SEC-007. The row is published in the `endpoints` payload and inside
71
+ `posture.endpoints`, because the reader who counts open requests is reading
72
+ `posture`. Admission of a servlet surface is deliberately **not** in this
73
+ change: it is a second population and merging it into `endpoints.total` would
74
+ move a published count and every ratio keyed on it.
75
+
76
+ ### Fixed
77
+
78
+ - **A reach figure that did not name its scope** (C2-23, field evaluation #9).
79
+ `risk` reported `endpoints_reached: 1` for a symbol whose class `impact-chain`
80
+ said reached 8 — both correct, both documented, in two payloads, so reconciling
81
+ them cost the reader three unit notes. Each row now carries
82
+ `endpoints_reached_basis`: what the figure is a reach *of* (a defect sits at the
83
+ symbol that carries the remedy, so a method-level defect walks from the method)
84
+ and, where that is narrower than a class, the command that answers the wider
85
+ question. The relationship is asserted by measurement rather than stated in
86
+ prose.
87
+
88
+ - **The remedy registry now follows the status, not only the limitation** (C4-13,
89
+ field evaluation #9 — the sixth appearance of the C4 shape). The evaluation met
90
+ `verify`'s `contract_count: 0` → `unverified` → exit 2 under a read-only
91
+ constraint, concluded the command was unusable and asked for a `--dry-run` that
92
+ shipped in 3.7.0. The state named one next move and the reader could not take
93
+ it. `Remedy` gained `also` (the further options an answer needs — a remedy is an
94
+ invocation, not a flag), the new entry is `ask verify . --init --dry-run`, and
95
+ the `unverified` reason names both forms. The guard grew with it: every option
96
+ of an invocation must be accepted by the command it names, and the README check
97
+ matches a line carrying the command with all of its options, so a front page
98
+ that lists `--init` and omits `--dry-run` fails the build.
99
+
100
+ - **The hub-class guard contradicted the payload beside it** (C2-21, field
101
+ evaluation #9). It printed *"symbol has > 500 direct callers"* while the same
102
+ run published 215 of them on openmrs-core's `Context`: the guard trips on
103
+ caller **reference sites** (method-level keys included) and the payload
104
+ publishes caller **classes**, so the stated reason was checkably false while
105
+ the decision was right. `caller_reach.bfs_callers` now returns the population it
106
+ read, and the warning names it with its unit next to the class count it takes
107
+ from `caller_metrics.caller_classes` — *"792 caller reference sites … exceed the
108
+ cap of 500 … The 215 direct caller classes this run publishes stay exact"*.
109
+
110
+ - **`ask risk` ranked findings under the label `spring-audit` deduplicates**
111
+ (C1-23, field evaluation #9). One SEC-004 appeared three times for three call
112
+ sites in one class and `by_band` was an observation census under a defect
113
+ label — measured on BroadleafCommerce, 20 rows over 15 distinct `defect_id`
114
+ beside `spring-audit`'s own 15 defects / 20 findings. `build_risk` now iterates
115
+ `defect_identity.group_by_defect`, so one row is one thing to fix and both
116
+ commands report the same count (asserted against each other, not against a
117
+ literal). Nothing is dropped: `witness_count` and `witness_sites` carry where
118
+ each observation was seen, `total_findings` publishes the census under its own
119
+ name, and `rule_id` becomes **`rule_ids`** because one defect can be witnessed
120
+ by TX-001 and TX-006 at once and a singular field would have to pick one.
121
+ `severity` is the strongest across the witnesses, and
122
+ `factors.defect_severity.basis` says so.
123
+
124
+ - **A Maven build property was published as a runtime activation** (C1-22, field
125
+ evaluation #9 — the row it called the most expensive in its report). Two
126
+ `<properties>` entries setting `spring.profiles.active` made
127
+ `posture --resolve-environments` answer `artefacts_disagree` — *"different
128
+ deployments, pick one"* — on a repository where **nothing activates a profile at
129
+ run time**. The honest verdict, which the command already implements, is
130
+ `NOT DECIDED IN THIS REPOSITORY`: the default set applies and the permissive
131
+ profile wins, which is exactly where that audit's most severe finding lived. The
132
+ command turned a fail-open into a deployment ambiguity, in the scenario it is
133
+ sold for. A build property is now admitted as an activation only when a resource
134
+ in the repository consumes it (`@spring.profiles.active@`, or
135
+ `${spring.profiles.active}` where the build declares its resources filtered).
136
+ Unconsumed, the value is kept — it is still the profile set a build of it would
137
+ produce, so the worst case keeps ranking it — and carries the reason it decides
138
+ nothing, beside a `build_properties_not_consumed` count. The positive control is
139
+ half the battery: before this, the case where the property genuinely does decide
140
+ produced the identical verdict, which is how the defect stayed invisible. No
141
+ movement on the field repositories.
142
+
143
+ - **A rule that disappeared was reported as protection gained.** Found by the
144
+ negative control, not in the field: delete a security configuration and every
145
+ request it decided goes `permit_all` → undecided, which a two-bucket
146
+ opened/closed split published as *"2 requests no longer reachable
147
+ unauthenticated"*. Four buckets now: `opened` and `closed` (attributable to the
148
+ change), `no_longer_decided` (coverage lost) and `now_open_previously_undecided`
149
+ (our reading moved, not necessarily the system — it never turns a gate red on
150
+ its own). Requests undecided on either side are counted in
151
+ `access_not_decided_either_side`, the delta publishes `direction`, and
152
+ `gate.reading` states the floor (I-8).
153
+ - **`git_checkout` no longer offers a remedy half its callers do not have.** The
154
+ not-a-repository message told every caller to "pass two checkouts positionally";
155
+ `posture` takes none. The message states the fact and each command supplies its
156
+ own hint.
157
+
158
+ ## [4.1.0] — 2026-08-03
159
+
160
+ Minor, not a patch, and the criterion is this project's own: a new rule can trip
161
+ a gate that was green yesterday. `spring-audit --ci` and `verify --fail-on any`
162
+ will fail on a repository that stores a credential in a deployment descriptor —
163
+ correctly, and for the first time. Nothing is removed, no default moves, and no
164
+ exit code changes meaning.
165
+
166
+ Field audit #8 (deep read-only audit of the eval #6/#7 repository, by a new
167
+ evaluator, 100 % catalogue coverage) ran a build self-reporting **3.5.0** while
168
+ 4.0.1 was shipping, and re-derived twelve of its fourteen product complaints from
169
+ rows already closed — one of them the answer to its own critical finding. The
170
+ first entry below is that defect; the rest are the three findings that survived
171
+ verification against 4.0.1.
172
+
173
+ ### Added
174
+
175
+ - **SEC-007 — a credential stored in a deployment descriptor** (CL-10). The audit
176
+ found `monitor:{SHA-256}dc20b820…` in
177
+ `src/main/options/{DPA,M3,M3DEV}/WEB-INF/web.xml`: unsalted, the same hash in all
178
+ three per-environment overlays, and found by hand because *"los overlays
179
+ `src/main/options/**` son punto ciego"*. The gap was admission surface, not
180
+ detection — those descriptors are files `environment_resolution`,
181
+ `filter_surface` and `path_filters` already open, and SEC-004 already names a
182
+ fast unsalted digest. The rule fires on the **shape of the value**
183
+ (`{ALGO}<hex>`), never on the parameter's name (VAI), with `${placeholder}` as
184
+ the negative control; the digest is truncated in the finding, because a report
185
+ about a credential must not be a place to read one from; and identical digests
186
+ across descriptors are composed into the statement the audit actually made —
187
+ three environments share one credential, so the least protected decides the
188
+ strength of all three. NC-002 is **narrowed, not deleted**: Helm values, CI
189
+ variable files and shell scripts stay declared out of scope. Zero findings across
190
+ six field repositories.
191
+ - **`ask version` says how old the build is** (C4-12). Age in days alone would not
192
+ have caught the audit's case — that build was three days old. On this project's
193
+ cadence three days is six releases (eight, in fact). So the block publishes the
194
+ release date, the measured release rate (2.07/day over the last 30 releases), an
195
+ **estimate** of releases since with its basis, and an advisory naming the upgrade
196
+ command and the defect ledger. It never claims a newer release exists: offline,
197
+ that would be the confident-wrong answer the ledger exists to prevent. `_meta`
198
+ carries `tool_release_date` only — the date is a constant of the build, the age
199
+ changes daily, and the envelope is byte-identical by contract.
200
+
201
+ ### Fixed
202
+
203
+ - **`posture` now says when the container would not contradict its own resolution**
204
+ (CL-11). `allow-bean-definition-overriding: true` and
205
+ `allow-circular-references: true`, in the repository whose entire security verdict
206
+ turns on which `SecurityConfig` bean wins: with overriding enabled a second
207
+ definition replaces the first silently, so the startup failure that would have
208
+ caught a filter-chain override never happens. The block only ever **lowers**
209
+ confidence, so it sits beside the verdict and is repeated inside
210
+ `security.resolution_is_a_default` — the C1-20 lesson runs the other way here, and
211
+ a caveat a reader has to go and find does not reach the conclusion it was written
212
+ for. An undecidable setting is not read as off.
213
+ - **The platform claim matches what the battery can check** (C3-38). Third field
214
+ report of console mojibake on Windows/PowerShell; C3-3 and C3-12 are both recorded
215
+ *does not reproduce*, both scoped macOS-only. Patching a codec that was never
216
+ reproduced is what C3-27's rule forbids, so the README states instead that
217
+ Windows is a target the battery cannot verify, names what the CLI does do for it,
218
+ and cites the three rows. A documented limit is not a fix: C3-38 stays open until
219
+ a Windows runner exists.
220
+
221
+
5
222
  ## [4.0.1] — 2026-08-02
6
223
 
7
224
  Patch, and the criterion is the one this project has used since 3.2.0: nothing here
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 4.0.1
3
+ Version: 4.2.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
@@ -97,13 +97,25 @@ 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 2.5.1
100
+ ask version # ask 4.1.0 — and, on a build that has aged,
101
+ # how many releases have probably shipped since
101
102
  ```
102
103
 
103
104
  > **Package vs. command.** The install package is named `sourcecode` this release
104
105
  > (renaming the distribution is a separate, breaking change). Installing it gives you the
105
106
  > canonical **`ask`** command plus the deprecated **`sourcecode`** alias.
106
107
 
108
+ > **Platforms.** Developed and tested on macOS and Linux; every release runs its full
109
+ > battery there. **Windows/PowerShell is a target we cannot verify:** the CLI is written
110
+ > for it — UTF-8 streams are forced at both console entry points, a successful run writes
111
+ > nothing to stderr (PowerShell 5.1 raises `NativeCommandError` on any stderr write), and
112
+ > the MCP server strips the BOM PowerShell puts on stdin — but no Windows runner exists in
113
+ > the battery. Three separate field reports of console mojibake (`—` rendering as `â€"`)
114
+ > have never reproduced under measurement, and the only variable those reports share is the
115
+ > platform we cannot exercise (C3-3, C3-12, C3-38 in the
116
+ > [defect ledger](docs/DEFECT-LEDGER.md)). On Windows, prefer `--output <file>` over shell
117
+ > redirection, and report a rendering problem rather than assuming it is known.
118
+
107
119
  ---
108
120
 
109
121
  ## Quickstart
@@ -144,6 +156,10 @@ ask posture /path/to/repo --resolve-environments
144
156
  # writing it, and populate .ask/contracts.yml from the measurement instead of by hand.
145
157
  ask verify /path/to/repo --init
146
158
 
159
+ # Same derivation under a read-only constraint: prints what it would declare and
160
+ # writes nothing — the form an audit of somebody else's repository can run.
161
+ ask verify /path/to/repo --init --dry-run
162
+
147
163
  # What each defect actually costs once reach, access and write effect are in it:
148
164
  # severity × reachability × auth_verdict × write_effect, ordered, every factor traceable.
149
165
  ask risk /path/to/repo
@@ -218,6 +234,9 @@ What a profile set **actually wires**: which conditional beans register, which d
218
234
  `ask posture` · `ask posture --diff dev:prod` · `ask posture --property k=v`
219
235
  → [posture.md](docs/posture.md)
220
236
 
237
+ **`--diff-ref` makes it a gate instead of a report.** `--diff` moves the profile set; `--diff-ref origin/main:HEAD` (or `--since origin/main`, which compares a ref with the working tree) moves the *tree* under one profile set and answers *did this branch open an endpoint*. `--fail-on opened` exits 1 when it did. Both refs are read with `git archive` — nothing is written to the repository. The comparison is keyed on the request (`METHOD path`), counts requests only one side serves, and never reports a rule that disappeared as protection gained.
238
+ `ask posture . --since origin/main --fail-on opened`
239
+
221
240
  **`--resolve-environments` carries it past the edge of the repository.** Every answer above
222
241
  is conditional on a profile set, and which set runs is decided by the deployment. This flag
223
242
  reads every artefact in the tree that can set `spring.profiles.active` — Maven/Gradle,
@@ -331,7 +350,7 @@ reading JSON sees the same boundary a buyer reads here.
331
350
  | Not covered | Why | What answers it |
332
351
  |---|---|---|
333
352
  | **Whether request input reaches a sink — no dataflow or taint analysis.** | This engine resolves structure and wiring without compiling. Taint needs value flow through a program, which is a different analysis with a different failure mode: an unsound one produces confident findings that are wrong, and every claim here is meant to be checkable against the line that produced it. | A dataflow scanner (Semgrep, CodeQL). What this product adds on top is reachability: which of that tool's findings sit behind an endpoint that is reachable unauthenticated. |
334
- | **Secrets outside Java and Spring configuration a credential in a deployment descriptor, a Helm value, a CI variable file.** | The file population this analyzer reads is the Java source and the Spring configuration convention. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
353
+ | **Secrets outside Java, Spring configuration and the deployment descriptors a Helm value, a CI variable file, a shell script.** | The file population this analyzer reads is the Java source, the Spring configuration convention and the descriptors it already parses to resolve an environment. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. Narrowed by CL-10: a credential stored in `web.xml` or a Spring XML context IS reported (SEC-007), because those files were already being read. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
335
354
  | **Filter-chain order and per-filter URL patterns — the presence of a custom filter is structural only.** | Which filter runs first is decided by bean ordering this analyzer does not resolve. Where two active configurations both match a request, the answer published is `undecided` rather than a guess. | `ask posture --profile <set>` states per endpoint what the readable rules decide and what they leave undecided. |
336
355
  | **Known vulnerabilities in dependencies — no CVE database, no version advisory matching.** | Enriching a vulnerability feed is a different product with a different update cadence; a stale embedded database is worse than no database, because it reads as a clean bill of health. | A dependency scanner (Trivy, OWASP Dependency-Check). `impact-chain` then answers which of its findings anything actually reaches. |
337
356
 
@@ -342,6 +361,13 @@ Two more boundaries worth stating in the same voice:
342
361
  | **Applying a migration — nothing here edits source.** | This is the diagnosis layer: it measures what must change and what each change would reach. Rewriting code is an execution problem with an established executor, and duplicating it would mean maintaining a second, worse one. | OpenRewrite. `migrate-check` publishes the recipe each finding carries (`recipes[]`), which is the input that executor takes. |
343
362
  | **What the process environment sets at start-up — the profile set, properties and secrets a container is given.** | Nothing in a repository can observe the environment of a process that has not started. A value read from a file here is the default the repository ships, never a guarantee of what runs. | `ask posture --resolve-environments` reads every artefact in the repository that names the profile set, says when none of them decides it, and ranks the admissible sets by what each leaves open. |
344
363
 
364
+
365
+ And one about the endpoint surface itself:
366
+
367
+ | Not covered | Why | What answers it |
368
+ |---|---|---|
369
+ | **HTTP surface that is not a Spring handler mapping — a servlet declared in `web.xml` or registered as a `ServletRegistrationBean`, a container-level mapping, a static console mounted by a library.** | The endpoint population is projected from the Spring route model: one entry per handler mapping. A servlet is reachable over HTTP and is not in that model, so it is absent from `endpoints`, from the access verdicts derived from it, and from every ratio keyed on the total. Merging a second population into that count would move a published figure and every ratio with it, so the population is declared before it is widened. | Read the deployment descriptors for `<servlet-mapping>` entries and the Spring configuration for `ServletRegistrationBean` beans. Field evaluation #9 found a monitoring console mounted this way, behind a credential `ask spring-audit` did report (SEC-007) at a path nothing here listed. |
370
+
345
371
  **Positioning.** Until an executor ships, this is the **diagnosis layer**: it measures what
346
372
  must change, what each change reaches, and what a gate should block — and it removes none of
347
373
  it. Field evaluation scored it 7/10 as a report generator and 5.5/10 as a development tool,
@@ -59,13 +59,25 @@ 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 2.5.1
62
+ ask version # ask 4.1.0 — and, on a build that has aged,
63
+ # how many releases have probably shipped since
63
64
  ```
64
65
 
65
66
  > **Package vs. command.** The install package is named `sourcecode` this release
66
67
  > (renaming the distribution is a separate, breaking change). Installing it gives you the
67
68
  > canonical **`ask`** command plus the deprecated **`sourcecode`** alias.
68
69
 
70
+ > **Platforms.** Developed and tested on macOS and Linux; every release runs its full
71
+ > battery there. **Windows/PowerShell is a target we cannot verify:** the CLI is written
72
+ > for it — UTF-8 streams are forced at both console entry points, a successful run writes
73
+ > nothing to stderr (PowerShell 5.1 raises `NativeCommandError` on any stderr write), and
74
+ > the MCP server strips the BOM PowerShell puts on stdin — but no Windows runner exists in
75
+ > the battery. Three separate field reports of console mojibake (`—` rendering as `â€"`)
76
+ > have never reproduced under measurement, and the only variable those reports share is the
77
+ > platform we cannot exercise (C3-3, C3-12, C3-38 in the
78
+ > [defect ledger](docs/DEFECT-LEDGER.md)). On Windows, prefer `--output <file>` over shell
79
+ > redirection, and report a rendering problem rather than assuming it is known.
80
+
69
81
  ---
70
82
 
71
83
  ## Quickstart
@@ -106,6 +118,10 @@ ask posture /path/to/repo --resolve-environments
106
118
  # writing it, and populate .ask/contracts.yml from the measurement instead of by hand.
107
119
  ask verify /path/to/repo --init
108
120
 
121
+ # Same derivation under a read-only constraint: prints what it would declare and
122
+ # writes nothing — the form an audit of somebody else's repository can run.
123
+ ask verify /path/to/repo --init --dry-run
124
+
109
125
  # What each defect actually costs once reach, access and write effect are in it:
110
126
  # severity × reachability × auth_verdict × write_effect, ordered, every factor traceable.
111
127
  ask risk /path/to/repo
@@ -180,6 +196,9 @@ What a profile set **actually wires**: which conditional beans register, which d
180
196
  `ask posture` · `ask posture --diff dev:prod` · `ask posture --property k=v`
181
197
  → [posture.md](docs/posture.md)
182
198
 
199
+ **`--diff-ref` makes it a gate instead of a report.** `--diff` moves the profile set; `--diff-ref origin/main:HEAD` (or `--since origin/main`, which compares a ref with the working tree) moves the *tree* under one profile set and answers *did this branch open an endpoint*. `--fail-on opened` exits 1 when it did. Both refs are read with `git archive` — nothing is written to the repository. The comparison is keyed on the request (`METHOD path`), counts requests only one side serves, and never reports a rule that disappeared as protection gained.
200
+ `ask posture . --since origin/main --fail-on opened`
201
+
183
202
  **`--resolve-environments` carries it past the edge of the repository.** Every answer above
184
203
  is conditional on a profile set, and which set runs is decided by the deployment. This flag
185
204
  reads every artefact in the tree that can set `spring.profiles.active` — Maven/Gradle,
@@ -293,7 +312,7 @@ reading JSON sees the same boundary a buyer reads here.
293
312
  | Not covered | Why | What answers it |
294
313
  |---|---|---|
295
314
  | **Whether request input reaches a sink — no dataflow or taint analysis.** | This engine resolves structure and wiring without compiling. Taint needs value flow through a program, which is a different analysis with a different failure mode: an unsound one produces confident findings that are wrong, and every claim here is meant to be checkable against the line that produced it. | A dataflow scanner (Semgrep, CodeQL). What this product adds on top is reachability: which of that tool's findings sit behind an endpoint that is reachable unauthenticated. |
296
- | **Secrets outside Java and Spring configuration a credential in a deployment descriptor, a Helm value, a CI variable file.** | The file population this analyzer reads is the Java source and the Spring configuration convention. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
315
+ | **Secrets outside Java, Spring configuration and the deployment descriptors a Helm value, a CI variable file, a shell script.** | The file population this analyzer reads is the Java source, the Spring configuration convention and the descriptors it already parses to resolve an environment. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. Narrowed by CL-10: a credential stored in `web.xml` or a Spring XML context IS reported (SEC-007), because those files were already being read. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
297
316
  | **Filter-chain order and per-filter URL patterns — the presence of a custom filter is structural only.** | Which filter runs first is decided by bean ordering this analyzer does not resolve. Where two active configurations both match a request, the answer published is `undecided` rather than a guess. | `ask posture --profile <set>` states per endpoint what the readable rules decide and what they leave undecided. |
298
317
  | **Known vulnerabilities in dependencies — no CVE database, no version advisory matching.** | Enriching a vulnerability feed is a different product with a different update cadence; a stale embedded database is worse than no database, because it reads as a clean bill of health. | A dependency scanner (Trivy, OWASP Dependency-Check). `impact-chain` then answers which of its findings anything actually reaches. |
299
318
 
@@ -304,6 +323,13 @@ Two more boundaries worth stating in the same voice:
304
323
  | **Applying a migration — nothing here edits source.** | This is the diagnosis layer: it measures what must change and what each change would reach. Rewriting code is an execution problem with an established executor, and duplicating it would mean maintaining a second, worse one. | OpenRewrite. `migrate-check` publishes the recipe each finding carries (`recipes[]`), which is the input that executor takes. |
305
324
  | **What the process environment sets at start-up — the profile set, properties and secrets a container is given.** | Nothing in a repository can observe the environment of a process that has not started. A value read from a file here is the default the repository ships, never a guarantee of what runs. | `ask posture --resolve-environments` reads every artefact in the repository that names the profile set, says when none of them decides it, and ranks the admissible sets by what each leaves open. |
306
325
 
326
+
327
+ And one about the endpoint surface itself:
328
+
329
+ | Not covered | Why | What answers it |
330
+ |---|---|---|
331
+ | **HTTP surface that is not a Spring handler mapping — a servlet declared in `web.xml` or registered as a `ServletRegistrationBean`, a container-level mapping, a static console mounted by a library.** | The endpoint population is projected from the Spring route model: one entry per handler mapping. A servlet is reachable over HTTP and is not in that model, so it is absent from `endpoints`, from the access verdicts derived from it, and from every ratio keyed on the total. Merging a second population into that count would move a published figure and every ratio with it, so the population is declared before it is widened. | Read the deployment descriptors for `<servlet-mapping>` entries and the Spring configuration for `ServletRegistrationBean` beans. Field evaluation #9 found a monitoring console mounted this way, behind a credential `ask spring-audit` did report (SEC-007) at a path nothing here listed. |
332
+
307
333
  **Positioning.** Until an executor ships, this is the **diagnosis layer**: it measures what
308
334
  must change, what each change reaches, and what a gate should block — and it removes none of
309
335
  it. Field evaluation scored it 7/10 as a report generator and 5.5/10 as a development tool,
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "4.0.1"
7
+ version = "4.2.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.0.1"
7
+ __version__ = "4.2.0"
@@ -127,13 +127,21 @@ def bfs_callers(
127
127
  max_depth: int,
128
128
  impl_graph: object | None = None,
129
129
  method_scoped: bool = False,
130
- ) -> tuple[list[str], list[str], bool, int]:
130
+ ) -> tuple[list[str], list[str], bool, int, int]:
131
131
  """Walk the reverse graph from *seed_fqns*.
132
132
 
133
- Returns ``(direct, indirect, was_truncated, self_excluded)``. ``direct`` is
134
- depth 1 — the callers of the seeds themselves; ``indirect`` is depth 2 and
135
- beyond, up to *max_depth*. ``was_truncated`` says the hub-class guard capped
136
- the walk, which makes the result a floor.
133
+ Returns ``(direct, indirect, was_truncated, self_excluded, guard_population)``.
134
+ ``direct`` is depth 1 — the callers of the seeds themselves; ``indirect`` is
135
+ depth 2 and beyond, up to *max_depth*. ``was_truncated`` says the hub-class
136
+ guard capped the walk, which makes the result a floor.
137
+
138
+ ``guard_population`` is the number the guard actually read: unique caller
139
+ **reference sites**, method-level keys included, before anything is
140
+ normalised to a class. It is returned rather than left implicit because the
141
+ figure the payload publishes is the class count, and a message that names
142
+ the cap without naming its own population contradicts the payload beside it —
143
+ measured on openmrs-core, *"symbol has > 500 direct callers"* printed next to
144
+ `direct_caller_count: 215` (C2-21).
137
145
 
138
146
  A class's own members are members, not external callers, so they are dropped
139
147
  and counted (BUG #2 — leaving them in inflated a blast radius ~12×). For a
@@ -170,7 +178,8 @@ def bfs_callers(
170
178
  if etype not in SKIP_EDGE_TYPES:
171
179
  unique_direct.update(c for c in fqn_list if not _is_self_reference(c))
172
180
 
173
- effective_depth = 1 if len(unique_direct) > CALLER_CAP else max_depth
181
+ guard_population = len(unique_direct)
182
+ effective_depth = 1 if guard_population > CALLER_CAP else max_depth
174
183
  if effective_depth < max_depth:
175
184
  was_truncated = True
176
185
 
@@ -202,4 +211,4 @@ def bfs_callers(
202
211
  else:
203
212
  _add_caller(caller, depth)
204
213
 
205
- return direct, indirect, was_truncated, self_excluded
214
+ return direct, indirect, was_truncated, self_excluded, guard_population
@@ -115,6 +115,30 @@ class CanonicalSecurity:
115
115
  # CanonicalEndpoint
116
116
  # ---------------------------------------------------------------------------
117
117
 
118
+ def request_identity(method: str, path: str) -> str:
119
+ """The identity of the **request**, not of the handler that serves it.
120
+
121
+ An endpoint `id` identifies a handler: it carries the controller FQN and the
122
+ handler symbol, so moving a mapping to another class produces a different
123
+ `id` for the same URL. That is the right identity inside one tree and the
124
+ wrong one across two — a comparison keyed on it reports every refactored
125
+ handler as one endpoint removed and another added, and the reader asking
126
+ "did this change what a caller can reach" has to subtract the noise by hand.
127
+
128
+ Two states of one repository — `contract-diff` between refs, `posture
129
+ --diff-ref` — compare what a client can call, which is METHOD + path. One
130
+ authority for it, because two spellings of one identity is how two commands
131
+ come to disagree about the same endpoint (ADR-0008 R11).
132
+
133
+ Note what this deliberately does *not* do: it does not normalise path
134
+ variable names or inline regexes. `/{id:.*}` and `/{id:[^0-9].*}` are
135
+ different URLs to a client, and equating them would hide a real change in
136
+ the surface — measured on a fleet repository where exactly that edit moved
137
+ 93 requests.
138
+ """
139
+ return f"{str(method).upper()} {path}"
140
+
141
+
118
142
  @dataclass
119
143
  class CanonicalEndpoint:
120
144
  """Canonical endpoint entity — single source of truth for REST endpoint data.
@@ -159,6 +183,11 @@ class CanonicalEndpoint:
159
183
  """Deterministic endpoint ID — stable across formatting/body changes."""
160
184
  return f"{method}:{path}:{controller_class}:{handler_symbol}"
161
185
 
186
+ @property
187
+ def request_key(self) -> str:
188
+ """This endpoint's request identity — see `request_identity`."""
189
+ return request_identity(self.method, self.path)
190
+
162
191
 
163
192
  # ---------------------------------------------------------------------------
164
193
  # CanonicalRepositoryIR