sourcecode 3.8.0__tar.gz → 4.0.1__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-3.8.0 → sourcecode-4.0.1}/CHANGELOG.md +180 -0
  2. {sourcecode-3.8.0 → sourcecode-4.0.1}/PKG-INFO +52 -5
  3. {sourcecode-3.8.0 → sourcecode-4.0.1}/README.md +51 -4
  4. {sourcecode-3.8.0 → sourcecode-4.0.1}/pyproject.toml +1 -1
  5. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/__init__.py +1 -1
  6. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/cache.py +48 -0
  7. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/cache_model.py +7 -0
  8. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/cli.py +162 -23
  9. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/confidence_analyzer.py +7 -2
  10. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/defect_identity.py +24 -0
  11. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/environment_resolution.py +1 -1
  12. sourcecode-4.0.1/src/sourcecode/filter_surface.py +404 -0
  13. sourcecode-4.0.1/src/sourcecode/identity_fallback.py +244 -0
  14. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/migrate_check.py +27 -5
  15. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/parse_cache.py +23 -0
  16. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/posture.py +57 -4
  17. sourcecode-4.0.1/src/sourcecode/remedies.py +104 -0
  18. sourcecode-4.0.1/src/sourcecode/risk.py +345 -0
  19. sourcecode-4.0.1/src/sourcecode/rule_catalog.py +107 -0
  20. sourcecode-4.0.1/src/sourcecode/security_config_scan.py +262 -0
  21. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/security_posture.py +216 -23
  22. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_findings.py +13 -3
  23. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_profiles.py +6 -2
  24. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_properties.py +1 -1
  25. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_security_audit.py +91 -0
  26. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_tx_analyzer.py +42 -0
  27. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/summarizer.py +7 -2
  28. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/verify_repo.py +8 -0
  29. sourcecode-3.8.0/src/sourcecode/filter_surface.py +0 -173
  30. {sourcecode-3.8.0 → sourcecode-4.0.1}/.github/workflows/build-windows.yml +0 -0
  31. {sourcecode-3.8.0 → sourcecode-4.0.1}/.gitignore +0 -0
  32. {sourcecode-3.8.0 → sourcecode-4.0.1}/.ruff.toml +0 -0
  33. {sourcecode-3.8.0 → sourcecode-4.0.1}/CONTRIBUTING.md +0 -0
  34. {sourcecode-3.8.0 → sourcecode-4.0.1}/LICENSE +0 -0
  35. {sourcecode-3.8.0 → sourcecode-4.0.1}/SECURITY.md +0 -0
  36. {sourcecode-3.8.0 → sourcecode-4.0.1}/raw +0 -0
  37. {sourcecode-3.8.0 → sourcecode-4.0.1}/scripts/compare_integration_engines.py +0 -0
  38. {sourcecode-3.8.0 → sourcecode-4.0.1}/scripts/customer_smoke_test.sh +0 -0
  39. {sourcecode-3.8.0 → sourcecode-4.0.1}/scripts/generate_jdk_exports.py +0 -0
  40. {sourcecode-3.8.0 → sourcecode-4.0.1}/scripts/perf_harness.py +0 -0
  41. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/adaptive_scanner.py +0 -0
  42. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/archetype.py +0 -0
  43. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/architectural_baseline.py +0 -0
  44. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/architectural_delta.py +0 -0
  45. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/architecture_analyzer.py +0 -0
  46. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/architecture_summary.py +0 -0
  47. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/ast_extractor.py +0 -0
  48. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/call_surface.py +0 -0
  49. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/caller_metrics.py +0 -0
  50. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/caller_reach.py +0 -0
  51. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/canonical_ir.py +0 -0
  52. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/chain_rules.py +0 -0
  53. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/change_plan.py +0 -0
  54. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/cir_graphs.py +0 -0
  55. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/classifier.py +0 -0
  56. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/code_notes_analyzer.py +0 -0
  57. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/compare.py +0 -0
  58. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/constraint_diff.py +0 -0
  59. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/context_cache.py +0 -0
  60. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/context_graph.py +0 -0
  61. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/context_scorer.py +0 -0
  62. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/context_summarizer.py +0 -0
  63. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/contract_diff.py +0 -0
  64. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/contract_init.py +0 -0
  65. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/contract_model.py +0 -0
  66. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/contract_pipeline.py +0 -0
  67. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/coverage_parser.py +0 -0
  68. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/degradation.py +0 -0
  69. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/dependency_analyzer.py +0 -0
  70. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/deployment_prefix.py +0 -0
  71. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/__init__.py +0 -0
  72. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/base.py +0 -0
  73. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/csproj_parser.py +0 -0
  74. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/dart.py +0 -0
  75. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/dotnet.py +0 -0
  76. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/elixir.py +0 -0
  77. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/go.py +0 -0
  78. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/heuristic.py +0 -0
  79. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/hybrid.py +0 -0
  80. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/java.py +0 -0
  81. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/jvm_ext.py +0 -0
  82. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/nodejs.py +0 -0
  83. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/parsers.py +0 -0
  84. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/php.py +0 -0
  85. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/project.py +0 -0
  86. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/python.py +0 -0
  87. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/ruby.py +0 -0
  88. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/rust.py +0 -0
  89. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/systems.py +0 -0
  90. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/terraform.py +0 -0
  91. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/tooling.py +0 -0
  92. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/doc_analyzer.py +0 -0
  93. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/dynamic_argument_surface.py +0 -0
  94. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/endpoint_literals.py +0 -0
  95. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/endpoint_metrics.py +0 -0
  96. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/entrypoint_classifier.py +0 -0
  97. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/env_analyzer.py +0 -0
  98. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/envelope.py +0 -0
  99. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/error_schema.py +0 -0
  100. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/evidence_provider.py +0 -0
  101. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/explain.py +0 -0
  102. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/facts/__init__.py +0 -0
  103. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/facts/registry.json +0 -0
  104. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/file_chunker.py +0 -0
  105. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/file_classifier.py +0 -0
  106. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/format_contract.py +0 -0
  107. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/fqn_utils.py +0 -0
  108. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/git_analyzer.py +0 -0
  109. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/git_checkout.py +0 -0
  110. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/graph_analyzer.py +0 -0
  111. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/graph_evidence.py +0 -0
  112. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/hibernate_strat.py +0 -0
  113. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/integration_coordinates.py +0 -0
  114. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/jdk_exports.py +0 -0
  115. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/license.py +0 -0
  116. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/__init__.py +0 -0
  117. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  118. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  119. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  120. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  121. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  122. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/orchestrator.py +0 -0
  123. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/registry.py +0 -0
  124. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/runner.py +0 -0
  125. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/server.py +0 -0
  126. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp_nudge.py +0 -0
  127. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/metrics_analyzer.py +0 -0
  128. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/migration_blast.py +0 -0
  129. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/non_coverage.py +0 -0
  130. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/openapi_surface.py +0 -0
  131. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/output_budget.py +0 -0
  132. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/path_admission.py +0 -0
  133. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/path_filters.py +0 -0
  134. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/perf.py +0 -0
  135. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/pipe_contract.py +0 -0
  136. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/pr_comment_renderer.py +0 -0
  137. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/pr_impact.py +0 -0
  138. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/prepare_context.py +0 -0
  139. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/progress.py +0 -0
  140. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/ranking_engine.py +0 -0
  141. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/readiness_timeline.py +0 -0
  142. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/reconciliation.py +0 -0
  143. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/redactor.py +0 -0
  144. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/reference_facts.py +0 -0
  145. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/relevance_scorer.py +0 -0
  146. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/rename_refactor.py +0 -0
  147. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/repo_classifier.py +0 -0
  148. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/repository_ir.py +0 -0
  149. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/__init__.py +0 -0
  150. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/context.py +0 -0
  151. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/errors.py +0 -0
  152. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/executor.py +0 -0
  153. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/planner.py +0 -0
  154. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/query.py +0 -0
  155. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/request.py +0 -0
  156. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/resolution.py +0 -0
  157. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/result.py +0 -0
  158. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/retriever.py +0 -0
  159. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/runtime.py +0 -0
  160. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/steps.py +0 -0
  161. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
  162. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/steps_graph.py +0 -0
  163. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/steps_impact.py +0 -0
  164. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/steps_intf.py +0 -0
  165. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/steps_struct.py +0 -0
  166. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/steps_txsec.py +0 -0
  167. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/ris.py +0 -0
  168. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/runtime_classifier.py +0 -0
  169. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/scanner.py +0 -0
  170. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/schema.py +0 -0
  171. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
  172. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/security_config.py +0 -0
  173. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/semantic_analyzer.py +0 -0
  174. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/semantic_impact_engine.py +0 -0
  175. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/semantic_integration_engine.py +0 -0
  176. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/semantic_services.py +0 -0
  177. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/serializer.py +0 -0
  178. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_event_topology.py +0 -0
  179. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_impact.py +0 -0
  180. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_model.py +0 -0
  181. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_semantic.py +0 -0
  182. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/target_admission.py +0 -0
  183. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/telemetry/__init__.py +0 -0
  184. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/telemetry/config.py +0 -0
  185. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/telemetry/consent.py +0 -0
  186. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/telemetry/events.py +0 -0
  187. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/telemetry/filters.py +0 -0
  188. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/telemetry/transport.py +0 -0
  189. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/test_gap_ranking.py +0 -0
  190. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/test_sources.py +0 -0
  191. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/token_estimate.py +0 -0
  192. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/tree_utils.py +0 -0
  193. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/type_usage_surface.py +0 -0
  194. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/validation_inference.py +0 -0
  195. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/validation_surface.py +0 -0
  196. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/verify_edit.py +0 -0
  197. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/verify_rules.py +0 -0
  198. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/version_check.py +0 -0
  199. {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/workspace.py +0 -0
  200. {sourcecode-3.8.0 → sourcecode-4.0.1}/supabase/functions/README.md +0 -0
  201. {sourcecode-3.8.0 → sourcecode-4.0.1}/supabase/functions/get-license/index.ts +0 -0
  202. {sourcecode-3.8.0 → sourcecode-4.0.1}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
  203. {sourcecode-3.8.0 → sourcecode-4.0.1}/supabase/functions/telemetry/index.ts +0 -0
  204. {sourcecode-3.8.0 → sourcecode-4.0.1}/supabase/sql/license_event_ordering.sql +0 -0
  205. {sourcecode-3.8.0 → sourcecode-4.0.1}/supabase/sql/licensing_schema.sql +0 -0
  206. {sourcecode-3.8.0 → sourcecode-4.0.1}/supabase/sql/telemetry_events.sql +0 -0
@@ -2,6 +2,186 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [4.0.1] — 2026-08-02
6
+
7
+ Patch, and the criterion is the one this project has used since 3.2.0: nothing here
8
+ moves a published field, an exit code or a default. Three surfaces stopped
9
+ misdescribing an engine that did not change — the release advertised half its own
10
+ security ruleset, the front page led to neither capability the field asked for by
11
+ name, and the document both of them call the full command reference covered fewer
12
+ than half the commands. All three were found in-house.
13
+
14
+ ### Fixed
15
+
16
+ - **`spring-audit --help` advertised three security rules and the build ships six**
17
+ (C4-9). The one-liner the root panel prints, and the command's own screen, said
18
+ `security surface (SEC-001..003)` two releases after CL-9 shipped SEC-004, SEC-005
19
+ and SEC-006; `docs/PRODUCT_TIERS.md` said `TX-001..005 + SEC-001..003` and
20
+ `docs/USER_GUIDE.md` said `TX-001..TX-005`. The engine was right in every case —
21
+ the product advertised half its ruleset, in the release that answered the field's
22
+ complaint about security recall. `sourcecode/rule_catalog.py` now holds one summary
23
+ line per rule and the help renders from it, while the id *set* is derived from the
24
+ shipped pattern registries by `tests/test_rule_catalog.py`: a seventh rule fails the
25
+ build until it is documented, and no surface may name a rule the build cannot emit.
26
+ The non-coverage block in the same help is rendered from `non_coverage` too, which
27
+ had a renderer with no consumer beside four rows restated by hand.
28
+ - **The front page did not lead to either remedy that C4-8 closed** (C4-10). The
29
+ pointer lived in the payload that states the limitation, which reaches an agent and
30
+ not a reader who has not run the command yet — the same reader who wrote
31
+ `ask posture --provenance` and `ask contracts init` by hand after a full session.
32
+ `ask --help` now renders a *Questions the repository alone does not answer* block
33
+ from `remedies.REMEDIES`, and lists `risk .` in Start here; the README carries
34
+ `--resolve-environments`, `verify --init` and `ask risk` in the Quickstart,
35
+ `--resolve-environments` in §5b beside the `--diff` it qualifies, and a §5c for
36
+ composed risk. `tests/test_remedies.py` fails when a remedy is absent from either
37
+ surface.
38
+ - **The "full command reference" documented 14 of 32 commands** (C4-11). `verify`,
39
+ `verify-edit` and `pr-impact` — the three gate commands — appeared only as names in
40
+ the tier table, and eight more had no occurrence in the file at all. Sections added
41
+ for the gate family (with the exit-code contract they share), for `plan`, `compare`,
42
+ `delta` and `contract-diff`, and a table for the rest.
43
+ `tests/test_user_guide_coverage.py` takes the command population from the CLI and
44
+ parses every invocation the guide prints against it.
45
+
46
+ ## [4.0.0] — 2026-08-02
47
+
48
+ Major because two published `gate_coverage` fields are removed, not because the
49
+ engine changed shape: `total_controller_handlers` / `gate_bearing` /
50
+ `not_carrying_gate` (C2-14, the announced end of their two-minor window) and
51
+ `possibly_filter_covered` (C1-20, which had no window — it counted the wrong thing).
52
+ `removed_fields` in the same block maps each retired name to its successor.
53
+
54
+ This release closes fourteen of the sixteen rows opened by the seventh field
55
+ evaluation, in the order that record argued for, and ships `ask risk` — the first
56
+ command that composes the other answers instead of adding one.
57
+
58
+ ### Added
59
+
60
+ - **`ask risk` — the composition layer** (M10 head; [EXPERIMENTAL]). The seventh
61
+ evaluation's thesis was *"ASK tiene todos los átomos y no forma moléculas"*: one
62
+ class was `medium` in `spring-audit`, `medium/5.0` in `impact-chain`,
63
+ `coverage_unknown → permit_all` in `posture`, and executed a stored procedure that
64
+ mutates the database. Composed, that is unauthenticated write access under the
65
+ release build; separately, it was two commands saying "medium" and a reader doing
66
+ the join by hand.
67
+ `severity_effective = defect_severity × reachability × auth_verdict × write_effect`,
68
+ emitted as an ordered list. No new analysis — every factor is read from the
69
+ authority that already publishes it, and every row carries its four factors with
70
+ their sources, so a reader can reject one and keep the rest. An axis that could
71
+ not be measured is `unknown`, multiplies by 1.0, and is named in `blind_axes`:
72
+ the composition may not invent what nobody measured. This is the item that
73
+ *"crea producto"* rather than correcting data, and the one nobody replicates by
74
+ combining three scanners, because none of them shares an endpoint id with the
75
+ others.
76
+
77
+ - **Three textbook security rules, because silence has to mean something** (CL-9).
78
+ The seventh evaluation got one security finding out of 3 342 files, then found
79
+ three more by hand in three files ASK had pointed it at. `SEC-004` (passwords
80
+ stored under a fast unsalted digest), `SEC-005` (CSRF disabled under
81
+ session-bearing authentication) and `SEC-006` (a cookie created without the Secure
82
+ attribute) ship in the `spring-audit` security surface, from one scan
83
+ (`sourcecode/security_config_scan.py`) with `file:line`. Each requires a
84
+ security-configuration context, so SHA-1 over a response body stays an ETag and a
85
+ stateless API that disables CSRF is not reported — a rule that cannot tell those
86
+ apart is one teams switch off, after which it protects nothing. These are table
87
+ stakes rather than differentiation: closing them avoids losing the sale.
88
+
89
+ - **A third verdict for a gate that authorises against an identity nobody proved**
90
+ (C1-21). 939 endpoints in the field were reported `protected_custom` for carrying a
91
+ real gate — whose aspect resolves the caller through a method that returns a
92
+ database user when the authentication is null. The check runs; what it decides on,
93
+ for a request carrying no credential, is an identity the application invented, and
94
+ the vocabulary had no way to say so.
95
+ - `sourcecode/identity_fallback.py` (extractor) reports a method that reads the
96
+ platform's identity and, in a branch guarded by that identity being absent,
97
+ returns one anyway. Throwing, denying and returning null are correct handling and
98
+ are never reported; nothing branches on a method or class name (VAI).
99
+ - `security_posture` follows the enforcement path — types carrying published AOP
100
+ advice vocabulary or implementing a request-chain SPI — over `calls` edges, and
101
+ emits `protected_custom_degraded` (confidence `RequiresManualReview`) with an
102
+ `identity_resolution` block naming the method, the absence test and what it
103
+ returns. A fallback the enforcement path does not reach is not charged to the
104
+ gate.
105
+
106
+ - **The remedy travels with the limitation** (C4-8, C3-37). The evaluation's requests
107
+ #1 and #5 — written by hand with invented syntax — are `posture
108
+ --resolve-environments` and `verify --init`, both shipped in the build it audited.
109
+ Four earlier rows say the same thing: discoverability cannot live in a document,
110
+ because a reader looking at an output does not go and read `--help`. One registry
111
+ (`sourcecode/remedies.py`), keyed by the question rather than by the flag, is read
112
+ by `posture.activation`, `posture --diff`, the `security_posture` limitation that is
113
+ conditional on the profile set, and `verify`'s exit-2 reason. A test refuses any
114
+ remedy naming a command or option the CLI does not accept, so a renamed flag breaks
115
+ the build instead of sending a reader to an invocation that no longer exists.
116
+
117
+ - **A filter that matches a path is not a filter that checks the caller** (C1-20).
118
+ `gate_coverage` published `possibly_filter_covered: 2635` over patterns `/*`,
119
+ `/api/*` and `/api/v1/*` — and those three filters were CORS, headers and logging,
120
+ while the only filter that authenticates covered two prefixes. The wording was
121
+ technically honest and the number was still *"falso consuelo"*: the corrected split
122
+ on that repository is 12 covered against 2 623 in the gap. Both halves of the join
123
+ were already in the same process, so the fix is an intersection **per filter**
124
+ rather than per pattern-set:
125
+ - `sourcecode/filter_surface.py` now records each declared filter (`@WebFilter`, and
126
+ `web.xml` mappings correlated with their `<filter-class>`) with a verdict —
127
+ `authenticates`, `does_not_authenticate`, `unknown` — decided structurally, never
128
+ by name (VAI): the filter establishes an identity, or it reads a credential *and*
129
+ refuses over it. A body that is not in this repository stays `unknown`, because
130
+ absence of evidence published as evidence of absence is the same defect mirrored.
131
+ - `gate_coverage` replaces the single count with four that partition the escape set:
132
+ `filter_covered_authenticating`, `filter_gap_non_authenticating`,
133
+ `filter_authentication_unknown`, `no_matching_filter_pattern`, plus a `filters`
134
+ list naming each filter, its patterns and the evidence behind its verdict.
135
+
136
+ - **Seven presentation rows, none of them an analysis error, two of which led a
137
+ reader to the inverse conclusion** (C2-15…C2-20, C1-19).
138
+ - `validation` printed *"0 body endpoints, 1179 gaps"* over a payload carrying
139
+ `body_endpoints_in_code: 1201` — the declared-constraint count under the
140
+ code-surface name. Both axes are named in their own units (C2-15).
141
+ - TX-006's witnesses all carried the callee's line, because that is where the
142
+ remedy goes, so several rows shared one number and read as duplicates. Each
143
+ finding now carries its `call_site` from the IR's span index, and the defect row
144
+ publishes the distinct sites with their count (C2-16).
145
+ - `limitations` merged across scopes repeated an entry verbatim; deduplicated once
146
+ in `finalize`, in first-seen order (C2-17).
147
+ - `spring_profiles.conditional_beans[].source_file` used the platform's native path
148
+ separator while the rest of the document used `/`; posix everywhere, including the
149
+ two other extractors that did the same (C2-18).
150
+ - `estimated_effort_range_days` published `{low: 60.7, high: 60.7}` — not a range,
151
+ at a precision the model does not have. The band declares `point_estimate` and
152
+ `precision_days`, and rounds to it (C2-19).
153
+ - `posture` cut four endpoint lists and its evidence map at 200 and declared
154
+ nothing, in the command whose declared caps the same evaluation calls a feature.
155
+ Each cut publishes total/shown/omitted and the registered cap effect; a list that
156
+ was not cut declares nothing (C2-20).
157
+ - Three commands published a file count for one repository — 3 337, 3 336, 3 342 —
158
+ and none said what it counted. Measured rather than equalised: all code-extension
159
+ files in any language, the non-test denominator of a test ratio, and the `.java`
160
+ files handed to the migration rules. Each names its population (C1-19).
161
+
162
+ - **`cache status` counts every store a warm fills** (C3-36). It printed `CAS blobs:
163
+ 0`, `Total size: 0.1 MB` immediately after an 89-second warm of 3 342 files: true of
164
+ the per-repository core store, and the warm's output mostly lands in the shared
165
+ Canonical IR and the content-addressed parse cache, which the command never counted.
166
+ The status now breaks down by store, says what each holds, and labels the parse
167
+ cache shared across repositories so its size is not read as this repository's.
168
+
169
+ ### Removed
170
+
171
+ - **BREAKING — `gate_coverage` no longer emits the three deprecated aliases** (C2-14).
172
+ `total_controller_handlers` counted *endpoints* under a name that says handlers,
173
+ `gate_bearing` counted *handler methods* while sitting beside an endpoint count, and
174
+ `not_carrying_gate` duplicated `endpoints_not_carrying_gate`. They were kept for a
175
+ two-minor window after C1-5 named the units; the seventh field evaluation read the
176
+ aliases anyway and quoted `total_controller_handlers: 3574` as handlers next to
177
+ `handler_methods_total: 913`. An alias that still ships is a live claim, and two of
178
+ these claimed the wrong unit. Read `endpoints_total`,
179
+ `handler_methods_carrying_gate` and `endpoints_not_carrying_gate`; the block now
180
+ carries `removed_fields` mapping each retired name to its successor, so a consumer
181
+ meets the answer rather than a `KeyError`. `possibly_filter_covered` is retired in
182
+ the same block and for the same reason (C1-20): it counted "a filter runs here" and
183
+ was read as "a filter checks here".
184
+
5
185
  ## [3.8.0] — 2026-08-02
6
186
 
7
187
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 3.8.0
3
+ Version: 4.0.1
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
@@ -129,6 +129,26 @@ ask spring-audit /path/to/repo
129
129
  ask migrate-check /path/to/repo --compact
130
130
  ```
131
131
 
132
+ **Then the three that finish the sentence the four above start.** A profile-set answer stays
133
+ conditional until you know which set the deployment starts with, a gate nobody can populate is
134
+ a gate nobody runs, and a defect ranked without its reach is a linter note:
135
+
136
+ ```bash
137
+ # Which profile set ACTUALLY runs? Reads every artefact that can set it — build,
138
+ # descriptors, Dockerfile, Compose, Kubernetes, launch scripts — with file:line, and
139
+ # says NOT DECIDED IN THIS REPOSITORY when nothing in the tree decides it. Then ranks
140
+ # every admissible set by what it leaves reachable without authentication.
141
+ ask posture /path/to/repo --resolve-environments
142
+
143
+ # Derive the contracts this repository already satisfies, execute each one before
144
+ # writing it, and populate .ask/contracts.yml from the measurement instead of by hand.
145
+ ask verify /path/to/repo --init
146
+
147
+ # What each defect actually costs once reach, access and write effect are in it:
148
+ # severity × reachability × auth_verdict × write_effect, ordered, every factor traceable.
149
+ ask risk /path/to/repo
150
+ ```
151
+
132
152
  Then the everyday loop:
133
153
 
134
154
  ```bash
@@ -145,13 +165,17 @@ ask onboard /path/to/repo
145
165
  ask review-pr /path/to/repo --since main
146
166
 
147
167
  # CI gate on NEW violations only, instead of on pre-existing debt
168
+ ask verify /path/to/repo --init # derive the contracts, don't hand-write them
148
169
  ask verify /path/to/repo --capture-baseline # accept today's debt, once
149
170
  ask verify /path/to/repo # then: only new violations block
150
171
  ```
151
172
 
152
- > **Adopting a gate on a real codebase.** A repository that starts declaring contracts already
153
- > violates them somewhere; `ask verify` is **baseline-relative by default** (`--fail-on new`)
154
- > so the gate survives contact with reality instead of being switched off on day one.
173
+ > **Adopting a gate on a real codebase.** Nobody hand-writes contracts for a 3 000-file
174
+ > monolith, so `ask verify --init` derives the ones the repository satisfies **today** and
175
+ > executes each before writing it init followed by verify passes by construction.
176
+ > A repository that starts declaring contracts already violates them somewhere; `ask verify`
177
+ > is **baseline-relative by default** (`--fail-on new`) so the gate survives contact with
178
+ > reality instead of being switched off on day one.
155
179
  > `ask baseline capture|diff|trend` is a different thing: versioned architectural metrics over
156
180
  > time, for trend reporting rather than blocking.
157
181
 
@@ -194,10 +218,32 @@ What a profile set **actually wires**: which conditional beans register, which d
194
218
  `ask posture` · `ask posture --diff dev:prod` · `ask posture --property k=v`
195
219
  → [posture.md](docs/posture.md)
196
220
 
221
+ **`--resolve-environments` carries it past the edge of the repository.** Every answer above
222
+ is conditional on a profile set, and which set runs is decided by the deployment. This flag
223
+ reads every artefact in the tree that can set `spring.profiles.active` — Maven/Gradle,
224
+ `web.xml`, `Dockerfile`, Compose, Kubernetes, launch scripts — with `file:line`, and returns
225
+ `decided_in_repository`, `artefacts_disagree` (two deployments, never resolved by picking
226
+ one) or **`NOT DECIDED IN THIS REPOSITORY`**. Then it resolves every admissible set over one
227
+ parse and publishes the worst. A field audit closed those five hops by hand with grep before
228
+ the flag existed.
229
+ `ask posture . --resolve-environments`
230
+
197
231
  Unresolved is a first-class outcome: a condition the resolver cannot decide is reported as a
198
232
  hole with the condition named, never folded into active or inactive. **A posture answer that
199
233
  guesses is a confident security falsehood — the worst failure mode this tool has.**
200
234
 
235
+ ### 5c · Composed Risk *(experimental)*
236
+ Every command above answers one axis, and a reader composes them by hand. `ask risk` does the
237
+ join over the endpoint and symbol ids these commands already share with each other:
238
+ `severity_effective = defect_severity × reachability × auth_verdict × write_effect`. The
239
+ product of the published factors **is** the published score — decomposable to the four
240
+ figures and the authority behind each — and an axis this build cannot measure is `unknown`,
241
+ weighted 1.0 and named in `blind_axes` rather than silently treated as safe. Measured on a
242
+ field case: a defect both `spring-audit` and `impact-chain` called *medium* composes to
243
+ **high (8.06)** once *reachable unauthenticated* and *writes to the database* are in it.
244
+ `ask risk .` · `ask risk . --min-band high` · `ask risk . --limit 10`
245
+ → [reference](docs/USER_GUIDE.md)
246
+
201
247
  ### 6 · Developer Workflows
202
248
  The everyday loop: diff-based PR review, symptom-driven bug triage, and delta context for continuous agent runs.
203
249
  `ask review-pr` · `ask fix-bug` · `ask prepare-context`
@@ -220,7 +266,7 @@ experimental: both are true, and they are two different facts.
220
266
  |---|---|---|
221
267
  | **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
222
268
  | **supported** | maintained; fields are added, never removed without a major | every command not named in another row |
223
- | **experimental** | shape may change in a minor — do not gate CI on it | `posture` · `archetype` |
269
+ | **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `posture` · `archetype` |
224
270
  | **parked** | kept working, no longer developed | `retrieve` |
225
271
 
226
272
  The same table is printed by `ask --help`, and both are generated from one authority
@@ -237,6 +283,7 @@ from it.
237
283
  | Command | Tier | Answers | Note |
238
284
  |---|---|---|---|
239
285
  | `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
286
+ | `risk` | experimental | what each defect actually costs, once reach, access and write effect are in it | `defect_severity × reachability × auth_verdict × write_effect`; every factor names its authority |
240
287
  | `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators) |
241
288
  | `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment` |
242
289
  | `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan |
@@ -91,6 +91,26 @@ ask spring-audit /path/to/repo
91
91
  ask migrate-check /path/to/repo --compact
92
92
  ```
93
93
 
94
+ **Then the three that finish the sentence the four above start.** A profile-set answer stays
95
+ conditional until you know which set the deployment starts with, a gate nobody can populate is
96
+ a gate nobody runs, and a defect ranked without its reach is a linter note:
97
+
98
+ ```bash
99
+ # Which profile set ACTUALLY runs? Reads every artefact that can set it — build,
100
+ # descriptors, Dockerfile, Compose, Kubernetes, launch scripts — with file:line, and
101
+ # says NOT DECIDED IN THIS REPOSITORY when nothing in the tree decides it. Then ranks
102
+ # every admissible set by what it leaves reachable without authentication.
103
+ ask posture /path/to/repo --resolve-environments
104
+
105
+ # Derive the contracts this repository already satisfies, execute each one before
106
+ # writing it, and populate .ask/contracts.yml from the measurement instead of by hand.
107
+ ask verify /path/to/repo --init
108
+
109
+ # What each defect actually costs once reach, access and write effect are in it:
110
+ # severity × reachability × auth_verdict × write_effect, ordered, every factor traceable.
111
+ ask risk /path/to/repo
112
+ ```
113
+
94
114
  Then the everyday loop:
95
115
 
96
116
  ```bash
@@ -107,13 +127,17 @@ ask onboard /path/to/repo
107
127
  ask review-pr /path/to/repo --since main
108
128
 
109
129
  # CI gate on NEW violations only, instead of on pre-existing debt
130
+ ask verify /path/to/repo --init # derive the contracts, don't hand-write them
110
131
  ask verify /path/to/repo --capture-baseline # accept today's debt, once
111
132
  ask verify /path/to/repo # then: only new violations block
112
133
  ```
113
134
 
114
- > **Adopting a gate on a real codebase.** A repository that starts declaring contracts already
115
- > violates them somewhere; `ask verify` is **baseline-relative by default** (`--fail-on new`)
116
- > so the gate survives contact with reality instead of being switched off on day one.
135
+ > **Adopting a gate on a real codebase.** Nobody hand-writes contracts for a 3 000-file
136
+ > monolith, so `ask verify --init` derives the ones the repository satisfies **today** and
137
+ > executes each before writing it init followed by verify passes by construction.
138
+ > A repository that starts declaring contracts already violates them somewhere; `ask verify`
139
+ > is **baseline-relative by default** (`--fail-on new`) so the gate survives contact with
140
+ > reality instead of being switched off on day one.
117
141
  > `ask baseline capture|diff|trend` is a different thing: versioned architectural metrics over
118
142
  > time, for trend reporting rather than blocking.
119
143
 
@@ -156,10 +180,32 @@ What a profile set **actually wires**: which conditional beans register, which d
156
180
  `ask posture` · `ask posture --diff dev:prod` · `ask posture --property k=v`
157
181
  → [posture.md](docs/posture.md)
158
182
 
183
+ **`--resolve-environments` carries it past the edge of the repository.** Every answer above
184
+ is conditional on a profile set, and which set runs is decided by the deployment. This flag
185
+ reads every artefact in the tree that can set `spring.profiles.active` — Maven/Gradle,
186
+ `web.xml`, `Dockerfile`, Compose, Kubernetes, launch scripts — with `file:line`, and returns
187
+ `decided_in_repository`, `artefacts_disagree` (two deployments, never resolved by picking
188
+ one) or **`NOT DECIDED IN THIS REPOSITORY`**. Then it resolves every admissible set over one
189
+ parse and publishes the worst. A field audit closed those five hops by hand with grep before
190
+ the flag existed.
191
+ `ask posture . --resolve-environments`
192
+
159
193
  Unresolved is a first-class outcome: a condition the resolver cannot decide is reported as a
160
194
  hole with the condition named, never folded into active or inactive. **A posture answer that
161
195
  guesses is a confident security falsehood — the worst failure mode this tool has.**
162
196
 
197
+ ### 5c · Composed Risk *(experimental)*
198
+ Every command above answers one axis, and a reader composes them by hand. `ask risk` does the
199
+ join over the endpoint and symbol ids these commands already share with each other:
200
+ `severity_effective = defect_severity × reachability × auth_verdict × write_effect`. The
201
+ product of the published factors **is** the published score — decomposable to the four
202
+ figures and the authority behind each — and an axis this build cannot measure is `unknown`,
203
+ weighted 1.0 and named in `blind_axes` rather than silently treated as safe. Measured on a
204
+ field case: a defect both `spring-audit` and `impact-chain` called *medium* composes to
205
+ **high (8.06)** once *reachable unauthenticated* and *writes to the database* are in it.
206
+ `ask risk .` · `ask risk . --min-band high` · `ask risk . --limit 10`
207
+ → [reference](docs/USER_GUIDE.md)
208
+
163
209
  ### 6 · Developer Workflows
164
210
  The everyday loop: diff-based PR review, symptom-driven bug triage, and delta context for continuous agent runs.
165
211
  `ask review-pr` · `ask fix-bug` · `ask prepare-context`
@@ -182,7 +228,7 @@ experimental: both are true, and they are two different facts.
182
228
  |---|---|---|
183
229
  | **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
184
230
  | **supported** | maintained; fields are added, never removed without a major | every command not named in another row |
185
- | **experimental** | shape may change in a minor — do not gate CI on it | `posture` · `archetype` |
231
+ | **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `posture` · `archetype` |
186
232
  | **parked** | kept working, no longer developed | `retrieve` |
187
233
 
188
234
  The same table is printed by `ask --help`, and both are generated from one authority
@@ -199,6 +245,7 @@ from it.
199
245
  | Command | Tier | Answers | Note |
200
246
  |---|---|---|---|
201
247
  | `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
248
+ | `risk` | experimental | what each defect actually costs, once reach, access and write effect are in it | `defect_severity × reachability × auth_verdict × write_effect`; every factor names its authority |
202
249
  | `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators) |
203
250
  | `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment` |
204
251
  | `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan |
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "3.8.0"
7
+ version = "4.0.1"
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__ = "3.8.0"
7
+ __version__ = "4.0.1"
@@ -354,6 +354,7 @@ def status(repo_root: Path) -> dict[str, Any]:
354
354
  "cores": 0, "snapshots": 0, "views": 0, "cas_blobs": 0,
355
355
  "total_size_bytes": 0, "total_size_mb": 0.0,
356
356
  "current_git_head": current_head,
357
+ "stores": _store_breakdown(repo_root, 0),
357
358
  **ris_fields,
358
359
  }
359
360
  cores = list(cache_d.glob("core-*.json.gz"))
@@ -371,10 +372,57 @@ def status(repo_root: Path) -> dict[str, Any]:
371
372
  "total_size_bytes": total_bytes,
372
373
  "total_size_mb": round(total_bytes / (1024 * 1024), 2),
373
374
  "current_git_head": current_head,
375
+ # C3-36: `CAS blobs: 0`, `Total size: 0.1 MB` immediately after an 89-second
376
+ # warm of 3 342 files. Every figure above was true and described one store
377
+ # of three — the warm's output mostly lands in the shared CIR and the parse
378
+ # cache, which this command never counted. A status that reports a third of
379
+ # the state reads as a warm that did nothing.
380
+ "stores": _store_breakdown(repo_root, total_bytes),
374
381
  **ris_fields,
375
382
  }
376
383
 
377
384
 
385
+ def _store_breakdown(repo_root: Path, core_bytes: int) -> "dict[str, Any]":
386
+ """What a warm actually populated, by store. Best-effort per store: a store
387
+ that cannot be inspected is reported as unavailable, never as empty."""
388
+ out: "dict[str, Any]" = {
389
+ "core": {
390
+ "cache_dir": str(cache_dir(repo_root)),
391
+ "bytes": core_bytes,
392
+ "scope": "this repository",
393
+ "holds": "core snapshots, rendered views and their CAS blobs",
394
+ },
395
+ }
396
+ try:
397
+ from sourcecode.context_cache import ContextCache # noqa: PLC0415
398
+
399
+ ctx = ContextCache.for_repo(repo_root).stats()
400
+ out["shared_cir"] = {
401
+ "cache_dir": ctx["cache_dir"],
402
+ "entries": ctx["contexts"],
403
+ "bytes": ctx["bytes_stored"],
404
+ "scope": "this repository",
405
+ "holds": "the shared Canonical IR that explain/impact/posture reuse",
406
+ }
407
+ except Exception:
408
+ out["shared_cir"] = {"available": False}
409
+ try:
410
+ from sourcecode import parse_cache as _pc # noqa: PLC0415
411
+
412
+ out["parse"] = {
413
+ **_pc.store_stats(),
414
+ "holds": "per-file parses, content-addressed across every repository",
415
+ }
416
+ except Exception:
417
+ out["parse"] = {"available": False}
418
+ out["note"] = (
419
+ "`cache warm` populates all of these; the core store alone is a third of "
420
+ "the answer, and reading it as the whole is how a completed warm looks like "
421
+ "an empty cache."
422
+ )
423
+ return out
424
+
425
+
378
426
  def clear(repo_root: Path, *, clear_ris: bool = False) -> int:
379
427
  """Delete cache files for *repo_root*. Returns the number of files removed.
380
428
 
@@ -131,6 +131,13 @@ COMMANDS: tuple[CommandCache, ...] = (
131
131
  "builds — the parse it used to repeat for itself. `--diff` compares two profile "
132
132
  "sets over that one IR, so the second side costs the resolution only.",
133
133
  "10.1 s → 1.6 s"),
134
+ CommandCache("risk", ("cir", "parse"), "shared", False,
135
+ "Composes what the audit, impact-chain and the posture already answer, so it "
136
+ "pays each of their costs once over the shared CIR a warm builds — one parse "
137
+ "for the whole composition, and the reachability query is cached per symbol "
138
+ "within the run.",
139
+ "not measured on the battery yet — the composition is bounded by the "
140
+ "`spring-audit` + `impact-chain` costs listed here, not by new analysis"),
134
141
  CommandCache("endpoints", ("ris", "parse"), "shared", False,
135
142
  "Recomputes the endpoint surface on every run, over a parse a warm has already "
136
143
  "paid for. Until 3.7.0 the extractor parsed every file itself instead of reading "