sourcecode 5.2.0__tar.gz → 5.3.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 (239) hide show
  1. {sourcecode-5.2.0 → sourcecode-5.3.0}/CHANGELOG.md +107 -0
  2. {sourcecode-5.2.0 → sourcecode-5.3.0}/PKG-INFO +52 -14
  3. {sourcecode-5.2.0 → sourcecode-5.3.0}/README.md +51 -13
  4. {sourcecode-5.2.0 → sourcecode-5.3.0}/pyproject.toml +1 -1
  5. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/__init__.py +1 -1
  6. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/cache_model.py +1 -0
  7. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/cli.py +257 -5
  8. sourcecode-5.3.0/src/sourcecode/consumer_join.py +357 -0
  9. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/environment_resolution.py +200 -12
  10. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/format_contract.py +1 -0
  11. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/non_coverage.py +12 -8
  12. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/perf.py +15 -1
  13. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/remedies.py +51 -1
  14. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/risk.py +92 -2
  15. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/spring_findings.py +39 -0
  16. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/spring_impact.py +10 -0
  17. sourcecode-5.3.0/src/sourcecode/sql_taint.py +362 -0
  18. sourcecode-5.3.0/src/sourcecode/timeline.py +459 -0
  19. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/verify_rules.py +9 -0
  20. sourcecode-5.3.0/src/sourcecode/waivers.py +384 -0
  21. {sourcecode-5.2.0 → sourcecode-5.3.0}/.github/workflows/build-windows.yml +0 -0
  22. {sourcecode-5.2.0 → sourcecode-5.3.0}/.github/workflows/perf-gate.yml +0 -0
  23. {sourcecode-5.2.0 → sourcecode-5.3.0}/.gitignore +0 -0
  24. {sourcecode-5.2.0 → sourcecode-5.3.0}/.ruff.toml +0 -0
  25. {sourcecode-5.2.0 → sourcecode-5.3.0}/CLAUDE.md +0 -0
  26. {sourcecode-5.2.0 → sourcecode-5.3.0}/CONTRIBUTING.md +0 -0
  27. {sourcecode-5.2.0 → sourcecode-5.3.0}/LICENSE +0 -0
  28. {sourcecode-5.2.0 → sourcecode-5.3.0}/SECURITY.md +0 -0
  29. {sourcecode-5.2.0 → sourcecode-5.3.0}/raw +0 -0
  30. {sourcecode-5.2.0 → sourcecode-5.3.0}/scripts/compare_integration_engines.py +0 -0
  31. {sourcecode-5.2.0 → sourcecode-5.3.0}/scripts/customer_smoke_test.sh +0 -0
  32. {sourcecode-5.2.0 → sourcecode-5.3.0}/scripts/generate_jdk_exports.py +0 -0
  33. {sourcecode-5.2.0 → sourcecode-5.3.0}/scripts/perf_gate.py +0 -0
  34. {sourcecode-5.2.0 → sourcecode-5.3.0}/scripts/perf_harness.py +0 -0
  35. {sourcecode-5.2.0 → sourcecode-5.3.0}/scripts/sync_gate_anchors.py +0 -0
  36. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/adaptive_scanner.py +0 -0
  37. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/archetype.py +0 -0
  38. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/architectural_baseline.py +0 -0
  39. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/architectural_delta.py +0 -0
  40. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/architecture_analyzer.py +0 -0
  41. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/architecture_summary.py +0 -0
  42. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/ast_extractor.py +0 -0
  43. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/audit_report.py +0 -0
  44. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/baseline_autocapture.py +0 -0
  45. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/cache.py +0 -0
  46. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/call_surface.py +0 -0
  47. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/caller_metrics.py +0 -0
  48. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/caller_reach.py +0 -0
  49. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/canonical_ir.py +0 -0
  50. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/chain_rules.py +0 -0
  51. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/change_plan.py +0 -0
  52. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/cir_graphs.py +0 -0
  53. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/classifier.py +0 -0
  54. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/client_calls.py +0 -0
  55. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  56. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/compare.py +0 -0
  57. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/confidence_analyzer.py +0 -0
  58. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/constraint_diff.py +0 -0
  59. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/container_wiring.py +0 -0
  60. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/context_cache.py +0 -0
  61. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/context_graph.py +0 -0
  62. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/context_scorer.py +0 -0
  63. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/context_summarizer.py +0 -0
  64. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/contract_diff.py +0 -0
  65. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/contract_init.py +0 -0
  66. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/contract_model.py +0 -0
  67. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/contract_pipeline.py +0 -0
  68. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/coverage_parser.py +0 -0
  69. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/data_exposure.py +0 -0
  70. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/data_labels.py +0 -0
  71. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/declarations.py +0 -0
  72. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/defect_identity.py +0 -0
  73. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/degradation.py +0 -0
  74. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/dependency_analyzer.py +0 -0
  75. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/deployment_prefix.py +0 -0
  76. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detach.py +0 -0
  77. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/__init__.py +0 -0
  78. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/base.py +0 -0
  79. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  80. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/dart.py +0 -0
  81. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/dotnet.py +0 -0
  82. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/elixir.py +0 -0
  83. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/go.py +0 -0
  84. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/heuristic.py +0 -0
  85. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/hybrid.py +0 -0
  86. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/java.py +0 -0
  87. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  88. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/nodejs.py +0 -0
  89. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/parsers.py +0 -0
  90. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/php.py +0 -0
  91. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/project.py +0 -0
  92. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/python.py +0 -0
  93. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/ruby.py +0 -0
  94. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/rust.py +0 -0
  95. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/systems.py +0 -0
  96. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/terraform.py +0 -0
  97. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/detectors/tooling.py +0 -0
  98. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/doc_analyzer.py +0 -0
  99. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/dynamic_argument_surface.py +0 -0
  100. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/endpoint_literals.py +0 -0
  101. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/endpoint_metrics.py +0 -0
  102. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  103. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/env_analyzer.py +0 -0
  104. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/envelope.py +0 -0
  105. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/error_schema.py +0 -0
  106. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/evidence_provider.py +0 -0
  107. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/execution_plan.py +0 -0
  108. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/explain.py +0 -0
  109. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/facts/__init__.py +0 -0
  110. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/facts/registry.json +0 -0
  111. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/file_chunker.py +0 -0
  112. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/file_classifier.py +0 -0
  113. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/filter_surface.py +0 -0
  114. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/fqn_utils.py +0 -0
  115. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/gate_anchors.py +0 -0
  116. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/git_analyzer.py +0 -0
  117. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/git_checkout.py +0 -0
  118. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/graph_analyzer.py +0 -0
  119. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/graph_evidence.py +0 -0
  120. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/hibernate_strat.py +0 -0
  121. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/identity_fallback.py +0 -0
  122. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/integration_coordinates.py +0 -0
  123. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/jdk_exports.py +0 -0
  124. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/license.py +0 -0
  125. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/mcp/__init__.py +0 -0
  126. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/mcp/dependency_import.py +0 -0
  127. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  128. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  129. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  130. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  131. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  132. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/mcp/orchestrator.py +0 -0
  133. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/mcp/registry.py +0 -0
  134. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/mcp/runner.py +0 -0
  135. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/mcp/server.py +0 -0
  136. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/mcp_nudge.py +0 -0
  137. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/metrics_analyzer.py +0 -0
  138. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/migrate_check.py +0 -0
  139. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/migration_blast.py +0 -0
  140. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/openapi_surface.py +0 -0
  141. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/openrewrite_recipe.py +0 -0
  142. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/output_budget.py +0 -0
  143. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/output_encoding.py +0 -0
  144. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/parallel.py +0 -0
  145. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/parse_cache.py +0 -0
  146. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/partial_contract.py +0 -0
  147. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/path_admission.py +0 -0
  148. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/path_filters.py +0 -0
  149. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/phased_run.py +0 -0
  150. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/pipe_contract.py +0 -0
  151. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/posture.py +0 -0
  152. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/pr_comment_renderer.py +0 -0
  153. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/pr_impact.py +0 -0
  154. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/prepare_context.py +0 -0
  155. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/progress.py +0 -0
  156. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/provenance.py +0 -0
  157. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/ranking_engine.py +0 -0
  158. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/readiness_timeline.py +0 -0
  159. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/readonly.py +0 -0
  160. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/reconciliation.py +0 -0
  161. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/redactor.py +0 -0
  162. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/reference_facts.py +0 -0
  163. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/release_info.py +0 -0
  164. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/relevance_scorer.py +0 -0
  165. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/rename_refactor.py +0 -0
  166. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/repo_classifier.py +0 -0
  167. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/repository_ir.py +0 -0
  168. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/__init__.py +0 -0
  169. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/context.py +0 -0
  170. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/errors.py +0 -0
  171. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/executor.py +0 -0
  172. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/planner.py +0 -0
  173. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/query.py +0 -0
  174. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/request.py +0 -0
  175. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/resolution.py +0 -0
  176. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/result.py +0 -0
  177. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/retriever.py +0 -0
  178. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/runtime.py +0 -0
  179. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/steps.py +0 -0
  180. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
  181. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/steps_graph.py +0 -0
  182. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/steps_impact.py +0 -0
  183. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/steps_intf.py +0 -0
  184. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/steps_struct.py +0 -0
  185. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/retrieval/steps_txsec.py +0 -0
  186. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/ris.py +0 -0
  187. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/rule_catalog.py +0 -0
  188. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/rule_pass.py +0 -0
  189. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/runs.py +0 -0
  190. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/runtime_classifier.py +0 -0
  191. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/sarif.py +0 -0
  192. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/scanner.py +0 -0
  193. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/schema.py +0 -0
  194. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
  195. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/security_chain.py +0 -0
  196. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/security_config.py +0 -0
  197. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/security_config_scan.py +0 -0
  198. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/security_posture.py +0 -0
  199. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/semantic_analyzer.py +0 -0
  200. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/semantic_impact_engine.py +0 -0
  201. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/semantic_integration_engine.py +0 -0
  202. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/semantic_services.py +0 -0
  203. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/serializer.py +0 -0
  204. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/servlet_surface.py +0 -0
  205. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/source_text.py +0 -0
  206. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/spring_event_topology.py +0 -0
  207. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/spring_model.py +0 -0
  208. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/spring_profiles.py +0 -0
  209. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/spring_properties.py +0 -0
  210. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/spring_security_audit.py +0 -0
  211. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/spring_semantic.py +0 -0
  212. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/spring_tx_analyzer.py +0 -0
  213. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/summarizer.py +0 -0
  214. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/target_admission.py +0 -0
  215. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/telemetry/__init__.py +0 -0
  216. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/telemetry/config.py +0 -0
  217. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/telemetry/consent.py +0 -0
  218. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/telemetry/events.py +0 -0
  219. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/telemetry/filters.py +0 -0
  220. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/telemetry/transport.py +0 -0
  221. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/test_gap_ranking.py +0 -0
  222. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/test_sources.py +0 -0
  223. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/text_input.py +0 -0
  224. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/token_estimate.py +0 -0
  225. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/tree_utils.py +0 -0
  226. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/type_usage_surface.py +0 -0
  227. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/validation_inference.py +0 -0
  228. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/validation_surface.py +0 -0
  229. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/verify_edit.py +0 -0
  230. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/verify_repo.py +0 -0
  231. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/version_check.py +0 -0
  232. {sourcecode-5.2.0 → sourcecode-5.3.0}/src/sourcecode/workspace.py +0 -0
  233. {sourcecode-5.2.0 → sourcecode-5.3.0}/supabase/functions/README.md +0 -0
  234. {sourcecode-5.2.0 → sourcecode-5.3.0}/supabase/functions/get-license/index.ts +0 -0
  235. {sourcecode-5.2.0 → sourcecode-5.3.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
  236. {sourcecode-5.2.0 → sourcecode-5.3.0}/supabase/functions/telemetry/index.ts +0 -0
  237. {sourcecode-5.2.0 → sourcecode-5.3.0}/supabase/sql/license_event_ordering.sql +0 -0
  238. {sourcecode-5.2.0 → sourcecode-5.3.0}/supabase/sql/licensing_schema.sql +0 -0
  239. {sourcecode-5.2.0 → sourcecode-5.3.0}/supabase/sql/telemetry_events.sql +0 -0
@@ -2,6 +2,113 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.3.0] — 2026-08-11
6
+
7
+ **The capability queue, built on the stable point.** 5.2.0 was the highest-scored
8
+ build of twelve rounds and left three defect rows open, none of which blocks a
9
+ capability — so the queue that had been accumulating across four field
10
+ evaluations was built instead. Five features, one commit each, and **not one of
11
+ them is a new analysis**: each joins two things this product already measures.
12
+ The three defect rows stay open on purpose (C3-112, C3-113, C3-103) and are named
13
+ in the roadmap rather than quietly deferred.
14
+
15
+ Every one of the five keeps the rule the series is built on — an answer that
16
+ cannot be decided says so. `--profile-from` on an artefact that decides nothing
17
+ leaves the previous verdict byte-for-byte; a waiver that expired does not apply
18
+ and is published as expired; a timeline sample that could not be analysed is
19
+ `null` with a reason; the spliced-SQL verdict has a third state; the
20
+ surface-reduction plan calls its delete list *candidates* and publishes what
21
+ bounds it.
22
+
23
+ ### Added
24
+ - **`endpoints --consumer <repo>` — the surface-reduction plan (F-BH).** One
25
+ repository is analysed; the system is four, and the consumers live in
26
+ repositories nobody analyses together — so the census answers *what is exposed*
27
+ and every plan started with "protect 2 635 routes". Name the consumers
28
+ (repeatable) and `consumer_join` (`consumer-join-v1`) crosses each route's
29
+ access verdict, read from `posture`, with whether anybody calls it:
30
+ **`fix_now`** (open and consumed), **`delete_candidates`** (open and consumed by
31
+ nobody — remove the surface instead of guarding it), **`broken_integrations`**
32
+ (a consumer calls a route this server does not serve, the one direction needing
33
+ no coverage assumption). Java consumers are read too — `RestTemplate`/exchange
34
+ calls and declarative client interfaces — under the same admission rule as the
35
+ TypeScript side: the verb and path must be written at the call site, and a type
36
+ that does not declare itself an HTTP client is never read as one. The plan is
37
+ bounded and says so: per-consumer file counts and unresolved call sites are
38
+ published, `direction: under_reports` stands, `delete_candidates` carries the
39
+ sentence to read before acting, and a match through a neutralised path variable
40
+ is reported as `normalised` rather than exact. It also adjudicates
41
+ duplicate-looking routes (`/v1/agrupadorGfh` beside `/v1/agrupador-gfh`) by who
42
+ calls them: live aliases, or one live route plus debris.
43
+ - **Bounded HTTP-input → spliced-SQL taint, three-state (F-BF).** SEC-008 reports
44
+ every MyBatis `${}`; which of them request input actually reaches was the
45
+ question nobody could answer — *"la diferencia entre 16 sitios que revisar y 2
46
+ sitios que arreglar hoy"* — and `risk`'s `query_construction` axis answered
47
+ `not_observed` (×1,0) on **all 98 rows** of the field's repository, because its
48
+ propagation ends at Java query-builder calls while that repository's SQL lives
49
+ in mapper XML. `sql_taint` (`sql-taint-v1`) joins the two ends the product
50
+ already resolves: the annotated `@RequestParam`/`@PathVariable`/`@RequestBody`
51
+ seeds `risk` walks from, and the `${}` population SEC-008 indexes, keyed by
52
+ namespace and statement id. Verdict lattice **`reaches`** (with the trace) /
53
+ **`does_not_reach`** (stated only where the call sites were found) /
54
+ **`undecidable`** (no resolvable call site, no statement id, an undeclared
55
+ namespace) — only the first moves the axis, to a new
56
+ `http_input_reaches_sql_interpolation` value weighted the same as the
57
+ concatenation case, because the distinction is the evidence and not the
58
+ severity. `risk` publishes the three-state census beside the rows. This is not
59
+ interprocedural taint and does not claim to be: NC-001 stands for everything
60
+ outside the pair.
61
+ - **`ask timeline` — since when, and in which commit window (F-BJ).**
62
+ `data-exposure` answers *"2 453 routes reach labelled data and nothing decides
63
+ access to them"*; nobody could answer *since when*, which is the question that
64
+ turns a finding into an owner, a date and a work item — and the first question
65
+ asked after a breach. `ask timeline . --since v1.0 --watch
66
+ posture,data-exposure` walks the commit series, runs the analyses that already
67
+ ship on a read-only materialisation of each sampled tree (the repository is
68
+ never written to), and publishes **transitions** rather than a per-commit
69
+ dump. Four watchable metrics (`posture`, `data-exposure`, `endpoints`,
70
+ `spring-audit`), each declaring the command it projects, so every point is
71
+ re-derivable by running that command at that commit. Only buildable now
72
+ because the analyses cost seconds and eleven rounds of byte-identical payloads
73
+ mean a difference between two samples is a difference in the code. Honest by
74
+ construction: a sample that could not be analysed is `null` with a reason and
75
+ never 0; a transition names the commit it was **observed** at and publishes
76
+ the window it could have happened in rather than attributing it to a commit it
77
+ was not measured at (raise `--max-commits` to close the window to one commit);
78
+ the first sample is a baseline, never a transition; and the per-sample cost is
79
+ measured and published, because a hundred-commit series is a nightly job.
80
+ - **`.ask/waivers.yml` — adjudication that survives the next run (F-BI).** The
81
+ `verify` baseline records accepted *debt*; a waiver makes the other claim —
82
+ *this row was never a defect here* — which is the only thing that lets a team
83
+ gate on a family with any false-positive rate at all (field evaluation #24: 9
84
+ of 9 `high` findings false on a greenfield module, and *"do not gate CI on
85
+ this"*). Keyed on the stable `finding_id`/`defect_id`, `reason` required,
86
+ optional `by` and `expires`. `spring-audit` publishes what left — `waived[]`
87
+ with the reason and the declaring file, `summary.waived_findings`, and a
88
+ `waivers` block listing what was declared, applied, **expired** and matched
89
+ nothing — and `verify`, `verify-edit`, `risk` and `pr-impact` honour the same
90
+ file, so an adjudicated row stops holding the gate red. A rule family cannot
91
+ be waived (a silenced family is indistinguishable from one that found
92
+ nothing), and a malformed file stops the command instead of reading as
93
+ "nothing waived". A repository that declares no waivers gets a byte-identical
94
+ payload.
95
+ - **`posture --profile-from <deployment artefact>` (F-BG) — the last hop of the
96
+ flagship.** `posture` resolved the conditional bean graph completely and then
97
+ stopped where the answer is actually decided: *"SPRING_PROFILES_ACTIVE in the
98
+ process environment outranks every artefact below it, and this analysis cannot
99
+ see the process environment"* — three field evaluations named this as their
100
+ first choice. Name the artefact that decides it (Kubernetes manifest, compose
101
+ file, WebLogic deployment plan, `Dockerfile`, dotenv, launch script;
102
+ repeatable) and the whole command answers under that profile set, publishing a
103
+ `profile_from` block (`profile-from-v1`) with the artefacts read, the
104
+ `file:line` that decided it and the caveat that the process environment
105
+ outranks the file too. Undecidable-first, so the flag is safe to point
106
+ anywhere: a placeholder, an entry with no value, a file that never mentions the
107
+ setting, or two artefacts that disagree all decide **nothing**, and the
108
+ repository's own verdict survives byte-for-byte. `--env-file` now shares this
109
+ reader, so a dotenv is one shape among six instead of the only one the product
110
+ could be handed.
111
+
5
112
  ## [5.2.0] — 2026-08-11
6
113
 
7
114
  **The queue field evaluation #26 opened, and the row underneath the other rows.**
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 5.2.0
3
+ Version: 5.3.0
4
4
  Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
5
5
  License-File: LICENSE
6
6
  Keywords: agents,ai,codebase,context,developer-tools,llm
@@ -42,7 +42,7 @@ Description-Content-Type: text/markdown
42
42
 
43
43
  **Context · Impact · Migration · Architecture · Review — everything from one structural model.**
44
44
 
45
- ![Version](https://img.shields.io/badge/version-5.2.0-blue)
45
+ ![Version](https://img.shields.io/badge/version-5.3.0-blue)
46
46
  ![Python](https://img.shields.io/badge/python-3.9%2B-green)
47
47
 
48
48
  > **ASK Engine** is the product. The CLI command is **`ask`**. The legacy **`sourcecode`**
@@ -126,7 +126,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
126
126
  # pip / pipx
127
127
  pipx install sourcecode # or: pip install sourcecode
128
128
 
129
- ask version # ask 5.2.0 — and, on a build that has aged,
129
+ ask version # ask 5.3.0 — and, on a build that has aged,
130
130
  # how many releases have probably shipped since
131
131
  ```
132
132
 
@@ -195,6 +195,29 @@ ask verify /path/to/repo --init --dry-run
195
195
  ask risk /path/to/repo
196
196
  ```
197
197
 
198
+ **And the three that answer questions this repository does not contain the answer to.**
199
+ The profile set is decided by a deployment artefact, the consumers are other repositories,
200
+ and *since when* is a fact about history — each one is a join of things already measured,
201
+ and each one leaves the previous answer untouched when it cannot decide:
202
+
203
+ ```bash
204
+ # The artefact that decides the profile set — Kubernetes manifest, compose file, WebLogic
205
+ # deployment plan, Dockerfile, dotenv, launch script. Every answer is then given under the
206
+ # set it names, with the file:line that decided it. An artefact that decides nothing (a
207
+ # placeholder, two artefacts that disagree) leaves the repository's own verdict as it was.
208
+ ask posture /path/to/repo --profile-from k8s/deployment-prod.yaml
209
+
210
+ # Of the routes a readable rule leaves open: which ones a consumer actually calls (work),
211
+ # and which ones nobody calls (surface to delete instead of guard). Reads TypeScript/JS and
212
+ # Java consumers, only where the verb and the path are written at the call site.
213
+ ask endpoints /path/to/repo --consumer ../web-client --consumer ../partner-api
214
+
215
+ # Since when. Walks the commit series, runs the analyses that already ship on a read-only
216
+ # materialisation of each sampled tree, and publishes where a number MOVED — with the commit
217
+ # it was observed at and the window it could have happened in.
218
+ ask timeline /path/to/repo --since v1.0 --watch posture,data-exposure
219
+ ```
220
+
198
221
  Then the everyday loop:
199
222
 
200
223
  ```bash
@@ -249,7 +272,7 @@ Blast radius from a class or interface — reverse dependencies, through Spring
249
272
 
250
273
  ### 3 · Architecture Intelligence
251
274
  The system map: module graph, dependency views, REST surface, per-class summaries, and a symbol-level IR for downstream tooling.
252
- `ask export` · `ask repo-ir` · `ask endpoints` · `ask explain`
275
+ `ask export` · `ask repo-ir` · `ask endpoints` · `ask explain` · `ask timeline` (*experimental* — the same views over the commit series: when a number moved, and in which window)
253
276
  → [reference](docs/USER_GUIDE.md#core-commands)
254
277
 
255
278
  ### 4 · Migration & Modernization
@@ -280,6 +303,16 @@ parse and publishes the worst. A field audit closed those five hops by hand with
280
303
  the flag existed.
281
304
  `ask posture . --resolve-environments`
282
305
 
306
+ **`--profile-from` closes the loop.** `--resolve-environments` reads what the *repository*
307
+ says; the artefact that actually decides the profile set usually lives outside it. Name it —
308
+ Kubernetes manifest, compose file, WebLogic deployment plan, `Dockerfile`, dotenv, launch
309
+ script — and every answer is given under the set it sets, with the `file:line` that decided
310
+ it. Undecidable-first, so pointing it at the wrong file costs nothing: a placeholder, an entry
311
+ with no value, or two artefacts that disagree decide **nothing** and leave the repository's
312
+ own verdict byte-for-byte as it was. The process environment still outranks the file, and the
313
+ payload says so.
314
+ `ask posture . --profile-from k8s/deployment-prod.yaml`
315
+
283
316
  Unresolved is a first-class outcome: a condition the resolver cannot decide is reported as a
284
317
  hole with the condition named, never folded into active or inactive. **A posture answer that
285
318
  guesses is a confident security falsehood — the worst failure mode this tool has.**
@@ -295,8 +328,12 @@ field case: a defect both `spring-audit` and `impact-chain` called *medium* comp
295
328
  **high (8.06)** once *reachable unauthenticated* and *writes to the database* are in it.
296
329
  The last two factors describe the input path: a query assembled by concatenation, a bounded
297
330
  HTTP-input-to-query-sink path when ASK can prove one, and a route accepting a body with no
298
- declared constraint. General taint remains `NC-001` and is published in the payload's own
299
- `non_coverage` block.
331
+ declared constraint. **The sink family a MyBatis codebase actually uses is covered too**: an
332
+ annotated HTTP input reaching a statement that splices it into the SQL with `${...}` is a
333
+ three-state verdict — `reaches` (with the trace), `does_not_reach` (stated only where the call
334
+ sites were found) or `undecidable` — and only the first moves the factor. The census is
335
+ published beside the rows, so the multiplier is auditable rather than asserted. General taint
336
+ remains `NC-001` and is published in the payload's own `non_coverage` block.
300
337
  `ask risk .` · `ask risk . --min-band high` · `ask risk . --limit 10`
301
338
  → [reference](docs/USER_GUIDE.md)
302
339
 
@@ -322,7 +359,7 @@ experimental: both are true, and they are two different facts.
322
359
  |---|---|---|
323
360
  | **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
324
361
  | **supported** | maintained; fields are added, never removed without a major | every command not named in another row |
325
- | **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `enrich` · `audit-report` · `data-exposure` · `migrate-recipe` · `archetype` |
362
+ | **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `enrich` · `audit-report` · `data-exposure` · `migrate-recipe` · `archetype` · `timeline` |
326
363
  | **parked** | kept working, no longer developed | `retrieve` |
327
364
 
328
365
  The same table is printed by `ask --help`, and both are generated from one authority
@@ -338,18 +375,18 @@ from it.
338
375
 
339
376
  | Command | Tier | Answers | Note |
340
377
  |---|---|---|---|
341
- | `posture` | supported | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
342
- | `risk` | experimental | what each defect actually costs, once reach, access, write effect and the shape of the input path are in it | `defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`; every factor names its authority; `--table --rule SEC-008 --band high --top-n 20` gives audit triage without `jq` |
378
+ | `posture` | supported | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here. `--resolve-environments` says which set the repository decides; `--profile-from <file>` reads the artefact that actually decides it (Kubernetes manifest, compose file, deployment plan, `Dockerfile`, dotenv) and answers under that set, with the `file:line` — deciding nothing leaves the verdict untouched |
379
+ | `risk` | experimental | what each defect actually costs, once reach, access, write effect and the shape of the input path are in it | `defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`; every factor names its authority; the `query_construction` factor covers MyBatis `${}` splicing with a three-state verdict (`reaches` / `does_not_reach` / `undecidable`) and publishes the census; `--table --rule SEC-008 --band high --top-n 20` gives audit triage without `jq` |
343
380
  | `enrich` | experimental | another scanner's SARIF findings, ranked by what this repository does with them | `--sarif <log>`; same composition as `risk`, with `--table --rule <id> --band high --top-n 20` for triage |
344
381
  | `audit-report` | experimental | human audit bundle over existing `risk` + `posture` evidence, optionally signed | includes `evidence_manifest` claim provenance; `--format markdown`; `--sign-key <file>` signs canonical JSON with HMAC-SHA256 |
345
382
  | `migrate-recipe` | experimental | the migration report as the OpenRewrite recipe that applies it | only recipes a finding named; the manual remainder published beside them; writes nothing without `--write`, and never a runnable command for an empty recipe list |
346
383
  | `data-exposure` | experimental | which routes can carry the data you labelled, and who reaches them | labels declared in `sourcecode.config.json` — never inferred from a name; `signature` and `call_reach` evidence published apart, field-level flow out of scope (NC-008). With nothing declared, `ask data-exposure /path/to/repo` answers `answered: false` and hands back the file, the key and an example to declare — it never reports zero exposed routes |
347
- | `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators). `--compact` answers the exposure census without the rows; `--servlets` lists the servlet-mounted surface as its own population; `--client-usage` says which routes the TS/JS client in this repository actually calls |
384
+ | `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators). `--compact` answers the exposure census without the rows; `--servlets` lists the servlet-mounted surface as its own population; `--client-usage` says which routes the TS/JS client in this repository actually calls; `--consumer <repo>` (repeatable) joins the routes against consumers in **other** repositories — TypeScript/JS and Java — and turns the census into a surface-reduction plan: open and called (fix now), open and called by nobody (delete rather than guard), and calls this server serves no route for |
348
385
  | `spring-audit` | core | transactional anomalies + security configuration/exposure + validation gaps | `--ci`, `-f github-comment`; `--table --rule SEC-008 --top-n 20` for human-scale review. Every run inventories its own rules — `rules_run`, `rules_not_run`, `rules_partially_run`, `rules_run_count`/`rules_total` — so "all of them" is a fact, not an assumption |
349
386
  | `migrate-check` | core | Boot 2→3 readiness + Java LTS/licensing inventory: located blockers, per-dimension score, effort, detected Java 8/11/17/21/25 evidence and explicit licensing-review signals | `--target-jdk 25` sets the target LTS route; `--blast-radius` orders the re-test plan; `--table --rule MIG-001 --band critical --top-n 20` for blocker triage |
350
387
  | `impact` / `impact-chain` | core | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
351
388
  | `pr-impact` | core | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
352
- | `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
389
+ | `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2. `.ask/waivers.yml` adjudicates a finding as *not a defect here* (stable id + required reason, optional expiry) so a reviewed row stops holding the gate red — a baseline records accepted debt, a waiver says it was never a defect |
353
390
  | `verify-edit` | supported | did the working-tree edits change runtime behaviour | semantic diff gate for the edit loop |
354
391
  | `--compact` / `--agent` | — | bounded structural context for an agent | flags of the root command, not commands: not tiered |
355
392
  | `onboard` / `explain` / `cold-start` | supported | orientation in an unfamiliar repo; per-class summary; bootstrap snapshot | |
@@ -360,6 +397,7 @@ from it.
360
397
  | `validation` | supported | request-body validation coverage and gaps | |
361
398
  | `baseline capture\|diff` · `trend` | supported | versioned architectural metrics over time; `ask trend .` reads the series (a repository path or a baselines directory), `ask baseline diff .` compares the tree against its newest point | trend reporting, not gating. Baselines land in `.ask/baselines` **inside the repository** — the history travels with the code, not with a vendor; an audit that must not write passes `--dir`. `capture --auto` is the unattended form (one baseline per commit, never rewrites one, never fails the build) — automate it: [baseline-ci.yml](docs/baseline-ci.yml) |
362
399
  | `retrieve` | parked | typed knowledge queries over the model | |
400
+ | `timeline` | experimental | since when a number moved, and in which commit window | walks the commit series and re-runs the shipped analyses (`posture`, `data-exposure`, `endpoints`, `spring-audit`) on a read-only materialisation of each sampled tree; publishes transitions, not a per-commit dump. A sample that could not be analysed is `null` with a reason, never 0, and a transition under sampling carries the window it could have happened in |
363
401
  | `archetype` | experimental | evidence-based architectural archetype | |
364
402
  | `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
365
403
  | `cache status\|warm\|model\|clear` · `auth` · `telemetry` · `mcp` · `config` · `version` | supported | housekeeping | `cache model [path]` explains what a warm buys per command; `activate` too |
@@ -404,7 +442,7 @@ reading JSON sees the same boundary a buyer reads here.
404
442
 
405
443
  | Not covered | Why | What answers it |
406
444
  |---|---|---|
407
- | **General request-input-to-sink taint analysis.** | `ask risk` includes a bounded slice for annotated HTTP parameters, positional calls in repository Java sources and known query sinks. Anything broader 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) for complete taint. What this product adds on top is reachability and, for the bounded slice, whether an annotated HTTP input reaches a known concatenated query sink. |
445
+ | **General request-input-to-sink taint analysis.** | `ask risk` includes two bounded slices for annotated HTTP parameters and positional calls in repository Java sources: known query sinks, and MyBatis statements that splice a value into their SQL. Anything broader 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) for complete taint. What this product adds on top is reachability and, for the two bounded slices, whether an annotated HTTP input reaches a known concatenated query sink or a spliced SQL statement — the latter with a three-state verdict that says `undecidable` rather than clearing a route it could not follow. |
408
446
  | **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). |
409
447
  | **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. |
410
448
  | **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. |
@@ -414,7 +452,7 @@ Two more boundaries worth stating in the same voice:
414
452
  | Not covered | Why | What answers it |
415
453
  |---|---|---|
416
454
  | **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. |
417
- | **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. |
455
+ | **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. `--profile-from <file>` goes one step further and reads the deployment artefact itself, which is where that decision is actually written — still a file, so the process environment still outranks it, and the payload says so. |
418
456
 
419
457
 
420
458
  And one about the endpoint surface itself:
@@ -560,7 +598,7 @@ Matching endpoints report `policy: "custom"` and drop out of the `no_security_si
560
598
  | Doc | What it covers |
561
599
  |-----|----------------|
562
600
  | [USER_GUIDE.md](docs/USER_GUIDE.md) | Full command reference, flags, output schema, workflows |
563
- | [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml` (or derive them with `ask verify --init`), enforce them in the edit loop and in CI |
601
+ | [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml` (or derive them with `ask verify --init`), enforce them in the edit loop and in CI — and adjudicate a finding as *not a defect here* in `.ask/waivers.yml` |
564
602
  | [baseline-ci.yml](docs/baseline-ci.yml) | Capture an architectural baseline per release, so the series exists when you want to read it |
565
603
  | [posture.md](docs/posture.md) | What a profile set actually wires — down to which endpoints its filter chain permits — and what could not be decided |
566
604
  | [migrate-check.md](docs/migrate-check.md) | Migration rule catalogue (MIG-001..043) + Hibernate stratification |
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Context · Impact · Migration · Architecture · Review — everything from one structural model.**
6
6
 
7
- ![Version](https://img.shields.io/badge/version-5.2.0-blue)
7
+ ![Version](https://img.shields.io/badge/version-5.3.0-blue)
8
8
  ![Python](https://img.shields.io/badge/python-3.9%2B-green)
9
9
 
10
10
  > **ASK Engine** is the product. The CLI command is **`ask`**. The legacy **`sourcecode`**
@@ -88,7 +88,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
88
88
  # pip / pipx
89
89
  pipx install sourcecode # or: pip install sourcecode
90
90
 
91
- ask version # ask 5.2.0 — and, on a build that has aged,
91
+ ask version # ask 5.3.0 — and, on a build that has aged,
92
92
  # how many releases have probably shipped since
93
93
  ```
94
94
 
@@ -157,6 +157,29 @@ ask verify /path/to/repo --init --dry-run
157
157
  ask risk /path/to/repo
158
158
  ```
159
159
 
160
+ **And the three that answer questions this repository does not contain the answer to.**
161
+ The profile set is decided by a deployment artefact, the consumers are other repositories,
162
+ and *since when* is a fact about history — each one is a join of things already measured,
163
+ and each one leaves the previous answer untouched when it cannot decide:
164
+
165
+ ```bash
166
+ # The artefact that decides the profile set — Kubernetes manifest, compose file, WebLogic
167
+ # deployment plan, Dockerfile, dotenv, launch script. Every answer is then given under the
168
+ # set it names, with the file:line that decided it. An artefact that decides nothing (a
169
+ # placeholder, two artefacts that disagree) leaves the repository's own verdict as it was.
170
+ ask posture /path/to/repo --profile-from k8s/deployment-prod.yaml
171
+
172
+ # Of the routes a readable rule leaves open: which ones a consumer actually calls (work),
173
+ # and which ones nobody calls (surface to delete instead of guard). Reads TypeScript/JS and
174
+ # Java consumers, only where the verb and the path are written at the call site.
175
+ ask endpoints /path/to/repo --consumer ../web-client --consumer ../partner-api
176
+
177
+ # Since when. Walks the commit series, runs the analyses that already ship on a read-only
178
+ # materialisation of each sampled tree, and publishes where a number MOVED — with the commit
179
+ # it was observed at and the window it could have happened in.
180
+ ask timeline /path/to/repo --since v1.0 --watch posture,data-exposure
181
+ ```
182
+
160
183
  Then the everyday loop:
161
184
 
162
185
  ```bash
@@ -211,7 +234,7 @@ Blast radius from a class or interface — reverse dependencies, through Spring
211
234
 
212
235
  ### 3 · Architecture Intelligence
213
236
  The system map: module graph, dependency views, REST surface, per-class summaries, and a symbol-level IR for downstream tooling.
214
- `ask export` · `ask repo-ir` · `ask endpoints` · `ask explain`
237
+ `ask export` · `ask repo-ir` · `ask endpoints` · `ask explain` · `ask timeline` (*experimental* — the same views over the commit series: when a number moved, and in which window)
215
238
  → [reference](docs/USER_GUIDE.md#core-commands)
216
239
 
217
240
  ### 4 · Migration & Modernization
@@ -242,6 +265,16 @@ parse and publishes the worst. A field audit closed those five hops by hand with
242
265
  the flag existed.
243
266
  `ask posture . --resolve-environments`
244
267
 
268
+ **`--profile-from` closes the loop.** `--resolve-environments` reads what the *repository*
269
+ says; the artefact that actually decides the profile set usually lives outside it. Name it —
270
+ Kubernetes manifest, compose file, WebLogic deployment plan, `Dockerfile`, dotenv, launch
271
+ script — and every answer is given under the set it sets, with the `file:line` that decided
272
+ it. Undecidable-first, so pointing it at the wrong file costs nothing: a placeholder, an entry
273
+ with no value, or two artefacts that disagree decide **nothing** and leave the repository's
274
+ own verdict byte-for-byte as it was. The process environment still outranks the file, and the
275
+ payload says so.
276
+ `ask posture . --profile-from k8s/deployment-prod.yaml`
277
+
245
278
  Unresolved is a first-class outcome: a condition the resolver cannot decide is reported as a
246
279
  hole with the condition named, never folded into active or inactive. **A posture answer that
247
280
  guesses is a confident security falsehood — the worst failure mode this tool has.**
@@ -257,8 +290,12 @@ field case: a defect both `spring-audit` and `impact-chain` called *medium* comp
257
290
  **high (8.06)** once *reachable unauthenticated* and *writes to the database* are in it.
258
291
  The last two factors describe the input path: a query assembled by concatenation, a bounded
259
292
  HTTP-input-to-query-sink path when ASK can prove one, and a route accepting a body with no
260
- declared constraint. General taint remains `NC-001` and is published in the payload's own
261
- `non_coverage` block.
293
+ declared constraint. **The sink family a MyBatis codebase actually uses is covered too**: an
294
+ annotated HTTP input reaching a statement that splices it into the SQL with `${...}` is a
295
+ three-state verdict — `reaches` (with the trace), `does_not_reach` (stated only where the call
296
+ sites were found) or `undecidable` — and only the first moves the factor. The census is
297
+ published beside the rows, so the multiplier is auditable rather than asserted. General taint
298
+ remains `NC-001` and is published in the payload's own `non_coverage` block.
262
299
  `ask risk .` · `ask risk . --min-band high` · `ask risk . --limit 10`
263
300
  → [reference](docs/USER_GUIDE.md)
264
301
 
@@ -284,7 +321,7 @@ experimental: both are true, and they are two different facts.
284
321
  |---|---|---|
285
322
  | **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
286
323
  | **supported** | maintained; fields are added, never removed without a major | every command not named in another row |
287
- | **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `enrich` · `audit-report` · `data-exposure` · `migrate-recipe` · `archetype` |
324
+ | **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `enrich` · `audit-report` · `data-exposure` · `migrate-recipe` · `archetype` · `timeline` |
288
325
  | **parked** | kept working, no longer developed | `retrieve` |
289
326
 
290
327
  The same table is printed by `ask --help`, and both are generated from one authority
@@ -300,18 +337,18 @@ from it.
300
337
 
301
338
  | Command | Tier | Answers | Note |
302
339
  |---|---|---|---|
303
- | `posture` | supported | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
304
- | `risk` | experimental | what each defect actually costs, once reach, access, write effect and the shape of the input path are in it | `defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`; every factor names its authority; `--table --rule SEC-008 --band high --top-n 20` gives audit triage without `jq` |
340
+ | `posture` | supported | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here. `--resolve-environments` says which set the repository decides; `--profile-from <file>` reads the artefact that actually decides it (Kubernetes manifest, compose file, deployment plan, `Dockerfile`, dotenv) and answers under that set, with the `file:line` — deciding nothing leaves the verdict untouched |
341
+ | `risk` | experimental | what each defect actually costs, once reach, access, write effect and the shape of the input path are in it | `defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`; every factor names its authority; the `query_construction` factor covers MyBatis `${}` splicing with a three-state verdict (`reaches` / `does_not_reach` / `undecidable`) and publishes the census; `--table --rule SEC-008 --band high --top-n 20` gives audit triage without `jq` |
305
342
  | `enrich` | experimental | another scanner's SARIF findings, ranked by what this repository does with them | `--sarif <log>`; same composition as `risk`, with `--table --rule <id> --band high --top-n 20` for triage |
306
343
  | `audit-report` | experimental | human audit bundle over existing `risk` + `posture` evidence, optionally signed | includes `evidence_manifest` claim provenance; `--format markdown`; `--sign-key <file>` signs canonical JSON with HMAC-SHA256 |
307
344
  | `migrate-recipe` | experimental | the migration report as the OpenRewrite recipe that applies it | only recipes a finding named; the manual remainder published beside them; writes nothing without `--write`, and never a runnable command for an empty recipe list |
308
345
  | `data-exposure` | experimental | which routes can carry the data you labelled, and who reaches them | labels declared in `sourcecode.config.json` — never inferred from a name; `signature` and `call_reach` evidence published apart, field-level flow out of scope (NC-008). With nothing declared, `ask data-exposure /path/to/repo` answers `answered: false` and hands back the file, the key and an example to declare — it never reports zero exposed routes |
309
- | `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators). `--compact` answers the exposure census without the rows; `--servlets` lists the servlet-mounted surface as its own population; `--client-usage` says which routes the TS/JS client in this repository actually calls |
346
+ | `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators). `--compact` answers the exposure census without the rows; `--servlets` lists the servlet-mounted surface as its own population; `--client-usage` says which routes the TS/JS client in this repository actually calls; `--consumer <repo>` (repeatable) joins the routes against consumers in **other** repositories — TypeScript/JS and Java — and turns the census into a surface-reduction plan: open and called (fix now), open and called by nobody (delete rather than guard), and calls this server serves no route for |
310
347
  | `spring-audit` | core | transactional anomalies + security configuration/exposure + validation gaps | `--ci`, `-f github-comment`; `--table --rule SEC-008 --top-n 20` for human-scale review. Every run inventories its own rules — `rules_run`, `rules_not_run`, `rules_partially_run`, `rules_run_count`/`rules_total` — so "all of them" is a fact, not an assumption |
311
348
  | `migrate-check` | core | Boot 2→3 readiness + Java LTS/licensing inventory: located blockers, per-dimension score, effort, detected Java 8/11/17/21/25 evidence and explicit licensing-review signals | `--target-jdk 25` sets the target LTS route; `--blast-radius` orders the re-test plan; `--table --rule MIG-001 --band critical --top-n 20` for blocker triage |
312
349
  | `impact` / `impact-chain` | core | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
313
350
  | `pr-impact` | core | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
314
- | `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
351
+ | `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2. `.ask/waivers.yml` adjudicates a finding as *not a defect here* (stable id + required reason, optional expiry) so a reviewed row stops holding the gate red — a baseline records accepted debt, a waiver says it was never a defect |
315
352
  | `verify-edit` | supported | did the working-tree edits change runtime behaviour | semantic diff gate for the edit loop |
316
353
  | `--compact` / `--agent` | — | bounded structural context for an agent | flags of the root command, not commands: not tiered |
317
354
  | `onboard` / `explain` / `cold-start` | supported | orientation in an unfamiliar repo; per-class summary; bootstrap snapshot | |
@@ -322,6 +359,7 @@ from it.
322
359
  | `validation` | supported | request-body validation coverage and gaps | |
323
360
  | `baseline capture\|diff` · `trend` | supported | versioned architectural metrics over time; `ask trend .` reads the series (a repository path or a baselines directory), `ask baseline diff .` compares the tree against its newest point | trend reporting, not gating. Baselines land in `.ask/baselines` **inside the repository** — the history travels with the code, not with a vendor; an audit that must not write passes `--dir`. `capture --auto` is the unattended form (one baseline per commit, never rewrites one, never fails the build) — automate it: [baseline-ci.yml](docs/baseline-ci.yml) |
324
361
  | `retrieve` | parked | typed knowledge queries over the model | |
362
+ | `timeline` | experimental | since when a number moved, and in which commit window | walks the commit series and re-runs the shipped analyses (`posture`, `data-exposure`, `endpoints`, `spring-audit`) on a read-only materialisation of each sampled tree; publishes transitions, not a per-commit dump. A sample that could not be analysed is `null` with a reason, never 0, and a transition under sampling carries the window it could have happened in |
325
363
  | `archetype` | experimental | evidence-based architectural archetype | |
326
364
  | `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
327
365
  | `cache status\|warm\|model\|clear` · `auth` · `telemetry` · `mcp` · `config` · `version` | supported | housekeeping | `cache model [path]` explains what a warm buys per command; `activate` too |
@@ -366,7 +404,7 @@ reading JSON sees the same boundary a buyer reads here.
366
404
 
367
405
  | Not covered | Why | What answers it |
368
406
  |---|---|---|
369
- | **General request-input-to-sink taint analysis.** | `ask risk` includes a bounded slice for annotated HTTP parameters, positional calls in repository Java sources and known query sinks. Anything broader 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) for complete taint. What this product adds on top is reachability and, for the bounded slice, whether an annotated HTTP input reaches a known concatenated query sink. |
407
+ | **General request-input-to-sink taint analysis.** | `ask risk` includes two bounded slices for annotated HTTP parameters and positional calls in repository Java sources: known query sinks, and MyBatis statements that splice a value into their SQL. Anything broader 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) for complete taint. What this product adds on top is reachability and, for the two bounded slices, whether an annotated HTTP input reaches a known concatenated query sink or a spliced SQL statement — the latter with a three-state verdict that says `undecidable` rather than clearing a route it could not follow. |
370
408
  | **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). |
371
409
  | **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. |
372
410
  | **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. |
@@ -376,7 +414,7 @@ Two more boundaries worth stating in the same voice:
376
414
  | Not covered | Why | What answers it |
377
415
  |---|---|---|
378
416
  | **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. |
379
- | **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. |
417
+ | **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. `--profile-from <file>` goes one step further and reads the deployment artefact itself, which is where that decision is actually written — still a file, so the process environment still outranks it, and the payload says so. |
380
418
 
381
419
 
382
420
  And one about the endpoint surface itself:
@@ -522,7 +560,7 @@ Matching endpoints report `policy: "custom"` and drop out of the `no_security_si
522
560
  | Doc | What it covers |
523
561
  |-----|----------------|
524
562
  | [USER_GUIDE.md](docs/USER_GUIDE.md) | Full command reference, flags, output schema, workflows |
525
- | [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml` (or derive them with `ask verify --init`), enforce them in the edit loop and in CI |
563
+ | [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml` (or derive them with `ask verify --init`), enforce them in the edit loop and in CI — and adjudicate a finding as *not a defect here* in `.ask/waivers.yml` |
526
564
  | [baseline-ci.yml](docs/baseline-ci.yml) | Capture an architectural baseline per release, so the series exists when you want to read it |
527
565
  | [posture.md](docs/posture.md) | What a profile set actually wires — down to which endpoints its filter chain permits — and what could not be decided |
528
566
  | [migrate-check.md](docs/migrate-check.md) | Migration rule catalogue (MIG-001..043) + Hibernate stratification |
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "5.2.0"
7
+ version = "5.3.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__ = "5.2.0"
7
+ __version__ = "5.3.0"
@@ -368,6 +368,7 @@ COMMANDS: tuple[CommandCache, ...] = (
368
368
  "`no_ris` instead of a snapshot.",
369
369
  "0.2 s either way", analysis_class="core", cold_seconds=0.2, warm_seconds=0.2,
370
370
  field_seconds=0.4, field_cache_state="mixed", field_measured_version="5.1.0"),
371
+ CommandCache("timeline", (), "none", False, "Each sample is a fresh materialisation of a different commit, so nothing is shared between samples: two commits are two trees, and a cache keyed on a tree state can only ever serve one of them. The per-sample cost is measured and published in the payload.", analysis_class="ir"),
371
372
  CommandCache("trend", (), "none", False, "Reads stored baseline artifacts from disk; analyses no source, so no cache layer applies. Same command as `baseline trend`.", analysis_class="none"),
372
373
  CommandCache("baseline", ("parse",), "shared", False,
373
374
  "`capture`/`diff`/`trend` over architectural metrics. The field figure is `capture`, "