sourcecode 3.7.0__tar.gz → 3.8.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 (200) hide show
  1. {sourcecode-3.7.0 → sourcecode-3.8.0}/CHANGELOG.md +313 -0
  2. {sourcecode-3.7.0 → sourcecode-3.8.0}/PKG-INFO +32 -3
  3. {sourcecode-3.7.0 → sourcecode-3.8.0}/README.md +31 -2
  4. {sourcecode-3.7.0 → sourcecode-3.8.0}/pyproject.toml +1 -1
  5. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/__init__.py +1 -1
  6. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/archetype.py +43 -16
  7. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/cache_model.py +10 -7
  8. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/cli.py +451 -118
  9. sourcecode-3.8.0/src/sourcecode/contract_init.py +419 -0
  10. sourcecode-3.8.0/src/sourcecode/defect_identity.py +142 -0
  11. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/degradation.py +52 -0
  12. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/java.py +15 -31
  13. sourcecode-3.8.0/src/sourcecode/environment_resolution.py +361 -0
  14. sourcecode-3.8.0/src/sourcecode/git_checkout.py +149 -0
  15. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/migrate_check.py +52 -2
  16. sourcecode-3.8.0/src/sourcecode/non_coverage.py +198 -0
  17. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/posture.py +144 -2
  18. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/pr_comment_renderer.py +13 -0
  19. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/prepare_context.py +110 -3
  20. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/repository_ir.py +43 -4
  21. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/result.py +24 -9
  22. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/steps.py +3 -0
  23. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/steps_endpoint.py +5 -5
  24. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/steps_graph.py +5 -5
  25. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/steps_impact.py +19 -7
  26. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/steps_intf.py +4 -4
  27. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/steps_struct.py +5 -5
  28. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/steps_txsec.py +5 -5
  29. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/serializer.py +39 -5
  30. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/spring_findings.py +54 -1
  31. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/spring_profiles.py +193 -1
  32. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/spring_tx_analyzer.py +10 -0
  33. sourcecode-3.8.0/src/sourcecode/test_gap_ranking.py +363 -0
  34. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/token_estimate.py +36 -0
  35. {sourcecode-3.7.0 → sourcecode-3.8.0}/.github/workflows/build-windows.yml +0 -0
  36. {sourcecode-3.7.0 → sourcecode-3.8.0}/.gitignore +0 -0
  37. {sourcecode-3.7.0 → sourcecode-3.8.0}/.ruff.toml +0 -0
  38. {sourcecode-3.7.0 → sourcecode-3.8.0}/CONTRIBUTING.md +0 -0
  39. {sourcecode-3.7.0 → sourcecode-3.8.0}/LICENSE +0 -0
  40. {sourcecode-3.7.0 → sourcecode-3.8.0}/SECURITY.md +0 -0
  41. {sourcecode-3.7.0 → sourcecode-3.8.0}/raw +0 -0
  42. {sourcecode-3.7.0 → sourcecode-3.8.0}/scripts/compare_integration_engines.py +0 -0
  43. {sourcecode-3.7.0 → sourcecode-3.8.0}/scripts/customer_smoke_test.sh +0 -0
  44. {sourcecode-3.7.0 → sourcecode-3.8.0}/scripts/generate_jdk_exports.py +0 -0
  45. {sourcecode-3.7.0 → sourcecode-3.8.0}/scripts/perf_harness.py +0 -0
  46. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/adaptive_scanner.py +0 -0
  47. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/architectural_baseline.py +0 -0
  48. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/architectural_delta.py +0 -0
  49. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/architecture_analyzer.py +0 -0
  50. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/architecture_summary.py +0 -0
  51. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/ast_extractor.py +0 -0
  52. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/cache.py +0 -0
  53. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/call_surface.py +0 -0
  54. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/caller_metrics.py +0 -0
  55. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/caller_reach.py +0 -0
  56. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/canonical_ir.py +0 -0
  57. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/chain_rules.py +0 -0
  58. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/change_plan.py +0 -0
  59. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/cir_graphs.py +0 -0
  60. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/classifier.py +0 -0
  61. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  62. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/compare.py +0 -0
  63. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/confidence_analyzer.py +0 -0
  64. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/constraint_diff.py +0 -0
  65. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/context_cache.py +0 -0
  66. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/context_graph.py +0 -0
  67. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/context_scorer.py +0 -0
  68. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/context_summarizer.py +0 -0
  69. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/contract_diff.py +0 -0
  70. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/contract_model.py +0 -0
  71. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/contract_pipeline.py +0 -0
  72. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/coverage_parser.py +0 -0
  73. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/dependency_analyzer.py +0 -0
  74. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/deployment_prefix.py +0 -0
  75. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/__init__.py +0 -0
  76. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/base.py +0 -0
  77. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  78. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/dart.py +0 -0
  79. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/dotnet.py +0 -0
  80. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/elixir.py +0 -0
  81. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/go.py +0 -0
  82. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/heuristic.py +0 -0
  83. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/hybrid.py +0 -0
  84. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  85. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/nodejs.py +0 -0
  86. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/parsers.py +0 -0
  87. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/php.py +0 -0
  88. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/project.py +0 -0
  89. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/python.py +0 -0
  90. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/ruby.py +0 -0
  91. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/rust.py +0 -0
  92. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/systems.py +0 -0
  93. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/terraform.py +0 -0
  94. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/detectors/tooling.py +0 -0
  95. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/doc_analyzer.py +0 -0
  96. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/dynamic_argument_surface.py +0 -0
  97. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/endpoint_literals.py +0 -0
  98. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/endpoint_metrics.py +0 -0
  99. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  100. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/env_analyzer.py +0 -0
  101. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/envelope.py +0 -0
  102. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/error_schema.py +0 -0
  103. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/evidence_provider.py +0 -0
  104. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/explain.py +0 -0
  105. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/facts/__init__.py +0 -0
  106. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/facts/registry.json +0 -0
  107. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/file_chunker.py +0 -0
  108. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/file_classifier.py +0 -0
  109. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/filter_surface.py +0 -0
  110. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/format_contract.py +0 -0
  111. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/fqn_utils.py +0 -0
  112. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/git_analyzer.py +0 -0
  113. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/graph_analyzer.py +0 -0
  114. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/graph_evidence.py +0 -0
  115. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/hibernate_strat.py +0 -0
  116. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/integration_coordinates.py +0 -0
  117. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/jdk_exports.py +0 -0
  118. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/license.py +0 -0
  119. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/mcp/__init__.py +0 -0
  120. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  121. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  122. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  123. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  124. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  125. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/mcp/orchestrator.py +0 -0
  126. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/mcp/registry.py +0 -0
  127. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/mcp/runner.py +0 -0
  128. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/mcp/server.py +0 -0
  129. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/mcp_nudge.py +0 -0
  130. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/metrics_analyzer.py +0 -0
  131. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/migration_blast.py +0 -0
  132. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/openapi_surface.py +0 -0
  133. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/output_budget.py +0 -0
  134. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/parse_cache.py +0 -0
  135. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/path_admission.py +0 -0
  136. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/path_filters.py +0 -0
  137. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/perf.py +0 -0
  138. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/pipe_contract.py +0 -0
  139. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/pr_impact.py +0 -0
  140. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/progress.py +0 -0
  141. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/ranking_engine.py +0 -0
  142. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/readiness_timeline.py +0 -0
  143. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/reconciliation.py +0 -0
  144. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/redactor.py +0 -0
  145. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/reference_facts.py +0 -0
  146. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/relevance_scorer.py +0 -0
  147. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/rename_refactor.py +0 -0
  148. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/repo_classifier.py +0 -0
  149. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/__init__.py +0 -0
  150. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/context.py +0 -0
  151. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/errors.py +0 -0
  152. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/executor.py +0 -0
  153. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/planner.py +0 -0
  154. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/query.py +0 -0
  155. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/request.py +0 -0
  156. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/resolution.py +0 -0
  157. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/retriever.py +0 -0
  158. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/retrieval/runtime.py +0 -0
  159. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/ris.py +0 -0
  160. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/runtime_classifier.py +0 -0
  161. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/scanner.py +0 -0
  162. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/schema.py +0 -0
  163. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
  164. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/security_config.py +0 -0
  165. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/security_posture.py +0 -0
  166. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/semantic_analyzer.py +0 -0
  167. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/semantic_impact_engine.py +0 -0
  168. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/semantic_integration_engine.py +0 -0
  169. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/semantic_services.py +0 -0
  170. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/spring_event_topology.py +0 -0
  171. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/spring_impact.py +0 -0
  172. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/spring_model.py +0 -0
  173. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/spring_properties.py +0 -0
  174. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/spring_security_audit.py +0 -0
  175. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/spring_semantic.py +0 -0
  176. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/summarizer.py +0 -0
  177. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/target_admission.py +0 -0
  178. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/telemetry/__init__.py +0 -0
  179. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/telemetry/config.py +0 -0
  180. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/telemetry/consent.py +0 -0
  181. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/telemetry/events.py +0 -0
  182. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/telemetry/filters.py +0 -0
  183. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/telemetry/transport.py +0 -0
  184. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/test_sources.py +0 -0
  185. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/tree_utils.py +0 -0
  186. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/type_usage_surface.py +0 -0
  187. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/validation_inference.py +0 -0
  188. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/validation_surface.py +0 -0
  189. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/verify_edit.py +0 -0
  190. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/verify_repo.py +0 -0
  191. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/verify_rules.py +0 -0
  192. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/version_check.py +0 -0
  193. {sourcecode-3.7.0 → sourcecode-3.8.0}/src/sourcecode/workspace.py +0 -0
  194. {sourcecode-3.7.0 → sourcecode-3.8.0}/supabase/functions/README.md +0 -0
  195. {sourcecode-3.7.0 → sourcecode-3.8.0}/supabase/functions/get-license/index.ts +0 -0
  196. {sourcecode-3.7.0 → sourcecode-3.8.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
  197. {sourcecode-3.7.0 → sourcecode-3.8.0}/supabase/functions/telemetry/index.ts +0 -0
  198. {sourcecode-3.7.0 → sourcecode-3.8.0}/supabase/sql/license_event_ordering.sql +0 -0
  199. {sourcecode-3.7.0 → sourcecode-3.8.0}/supabase/sql/licensing_schema.sql +0 -0
  200. {sourcecode-3.7.0 → sourcecode-3.8.0}/supabase/sql/telemetry_events.sql +0 -0
@@ -1,5 +1,318 @@
1
1
  # Changelog
2
2
 
3
+ ## [Unreleased]
4
+
5
+ ## [3.8.0] — 2026-08-02
6
+
7
+ ### Added
8
+
9
+ - **The security surface publishes what it does not answer** (CL-2, CL-7, and the framing half
10
+ of CL-5). A report that lists what it found and says nothing about what it never looks at
11
+ invites silence to be read as absence — and the audit that raised this found a credential
12
+ versioned in three deployment descriptors *by hand*, because nothing here reads outside Java
13
+ and Spring configuration.
14
+ - One authority, `sourcecode/non_coverage.py`, read by three surfaces: the `non_coverage`
15
+ block in the `spring-audit` payload, the command's own `--help`, and the README section —
16
+ all rendered from the same table, because a curated list beside a generated one is how
17
+ `endpoints` went missing from every help list.
18
+ - Four rows for the security surface: no dataflow or taint (NC-001), no secrets outside Java
19
+ and Spring configuration (NC-002), filter-chain order not reconstructed (NC-003), no CVE
20
+ matching (NC-004). Each states why it is out of scope rather than unimplemented, and what
21
+ does answer it. Two more state the migration boundary (NC-005, OpenRewrite takes the
22
+ recipes this publishes) and the environment boundary (NC-006, answered as far as a
23
+ repository can by `posture --resolve-environments`).
24
+ - The evaluator's argument for publishing it is commercial, not ethical: *"un producto que
25
+ publica sus límites no se compara por amplitud; se compara por profundidad, que es donde
26
+ gana."*
27
+
28
+ ### Changed
29
+
30
+ - **Two claims corrected with measured figures.** `--compact` is documented as the smallest
31
+ answer, **not the cheapest run** — 13.3 s cold on BroadleafCommerce against `spring-audit`
32
+ 3.6 s and `posture` 1.9 s, 0.3 s warm — with the reason to warm before a session stated where
33
+ the claim is made (CL-3). And the product is positioned as the **diagnosis layer** until an
34
+ executor ships, in the field's own numbers (7/10 as a report generator, 5.5/10 as a
35
+ development tool) rather than argued with (CL-5).
36
+
37
+ - **`ask trend` is a top-level command, and capture is automatable** (P-4). The *series* is the
38
+ asset — a repository that captured a baseline at each release has a history nobody can
39
+ reconstruct afterwards, and one that did not never will — so reading it is no longer two words
40
+ deep, and [`docs/baseline-ci.yml`](docs/baseline-ci.yml) captures one per tag and publishes the
41
+ trend as a build artifact. `ask baseline trend` is the same command.
42
+ - The read-only half was a **documentation** gap and is closed where the auditor meets it:
43
+ `--dir` already existed, and the default now says *why* it is inside the repository (the
44
+ history travels with the code, not with a vendor) and that an audit which must leave the tree
45
+ untouched writes elsewhere. README and the user guide say the same.
46
+ - ⚠Adding the command surfaced the **C4-1 shape a sixth time**: `ask trend` was registered,
47
+ working and documented, and the CLI answered *"'trend' does not exist"* — because the
48
+ dispatcher matched against a **hand-written set of subcommand names**. It is derived from the
49
+ registry now, and the battery asserts every registered command is dispatchable.
50
+
51
+ - **`ask posture --resolve-environments` — which profile set actually runs, and the worst one
52
+ that could** (CL-8 / M9.5). `posture --diff` was called the strongest thing this product does
53
+ and it stopped at the repository boundary: which profile set runs is decided by the
54
+ deployment, so the answer was conditional and a field evaluator closed the last hops by hand
55
+ with `grep` (build profile → the property the build filters → a placeholder present in no
56
+ config file → no `context-param` in any descriptor → therefore nothing decides it).
57
+ - Those hops are now mechanical. Every artefact that can set `spring.profiles.active` is read
58
+ — config files, Maven/Gradle properties, `web.xml` context parameters, `Dockerfile` `ENV`
59
+ and `-D` arguments, Compose and Kubernetes manifests, launch scripts — each publishing what
60
+ it says with `file:line`. The verdict is `decided_in_repository`, `artefacts_disagree` (two
61
+ deployments, never a contradiction to resolve by picking one), or **`NOT DECIDED IN THIS
62
+ REPOSITORY`**.
63
+ - Every admissible profile set is then resolved over one parse and ranked by what it leaves
64
+ open, so the payload names the worst case and, where the repository does decide, how far the
65
+ shipped set is from it: *"one environment variable away from dev"*.
66
+ - **`open_by_rule` and `access_not_decided` are counted separately.** A readable rule that
67
+ permits a request unauthenticated is not the same fact as no readable rule matching it, and
68
+ folding them together would publish the confident security falsehood this command exists to
69
+ prevent. The reading says which is which.
70
+ - A value found in the repository is published as a default, never a guarantee:
71
+ `SPRING_PROFILES_ACTIVE` in the process environment outranks every artefact, and this
72
+ analysis cannot see the process environment.
73
+
74
+ - **`ask verify --init` derives the contracts a repository already satisfies** (C3-30). The gate
75
+ had no way to acquire what it gates on: nobody hand-writes contracts for a 3 300-file
76
+ monolith, so the honest gate (zero contracts is `unverified`, closed as C3-15) stayed empty —
77
+ and the gate is the recurring half of the value story, where an audit is bought once.
78
+ - Three shapes, each written with the measurement behind it: a path prefix whose endpoints all
79
+ carry the same policy today (`require_endpoint_security`), an audit pattern that fires
80
+ nowhere (`forbid_finding`), and an injection edge between two annotated populations that
81
+ does not occur, both populations large enough that the absence is a pattern rather than an
82
+ accident (`forbidden_edge`).
83
+ - **Every rule is executed before it is written.** The derived set runs through the same engine
84
+ `verify` runs, and anything that fails on the tree it came from is dropped and reported —
85
+ `verify --init` followed by `verify` passes by construction, asserted as a round trip in the
86
+ battery, together with the proof that the populated gate goes red when the invariant breaks.
87
+ - Violations that exist today are deliberately not proposed: that is debt for
88
+ `--capture-baseline`, a different claim from an invariant, and the payload says so per
89
+ rejected candidate.
90
+ - `--dry-run` prints without writing; an existing contracts file is never replaced without
91
+ `--force`.
92
+
93
+ - **`delta` and `contract-diff` take git refs** (C3-33). Both compared two *checkouts* while
94
+ `review-pr` in the same CLI already took `--since`, so comparing two commits meant
95
+ orchestrating worktrees first. In the evaluation that recorded this, that cost coverage rather
96
+ than convenience: the evaluator ran the full catalogue against a client monolith under a
97
+ promise to leave the environment byte-identical and **omitted both commands** rather than
98
+ create worktrees in someone else's repository.
99
+ - `ask delta --base-ref origin/main --head-ref HEAD [--repo <path>]`, same for
100
+ `contract-diff`. Two checkouts positionally still work, and the payload publishes a
101
+ `comparison` block saying which basis it used — with both refs and their resolved commits.
102
+ - **Reading a ref writes nothing to the repository.** `git archive` streams the tree into a
103
+ temporary directory that is removed on the way out: no `git worktree add` (which registers
104
+ administrative state under `.git/worktrees` and leaves it behind if the process dies), no
105
+ checkout, no stash, no index read. The battery asserts `git status` and `git worktree list`
106
+ are identical before and after.
107
+ - A ref this repository does not have is refused by name (`git_ref_not_found`, exit 1) and
108
+ never substituted with something nearby.
109
+
110
+ ### Fixed
111
+
112
+ - **`retrieve` stopped publishing scores nothing computed** (C3-19, **`entities[].score` and
113
+ `explanation.score` are nullable**). `retrieve blast-radius` returned eighty dependents each
114
+ carrying `"score": 0.0`, beside an explanation whose own score was 92.43 — and the step that
115
+ orders those entities says in its own docstring that no score is computed. The same default put
116
+ a zero on every entity of every intent, and an `explanation` block with `winner: null,
117
+ score: 0.0` on the intents that return what they found rather than choose a winner: the shape
118
+ the field called *a ranking block that never ran*.
119
+ - Both fields are `None` when nothing wrote them. The order is real and structural, so the
120
+ payload states it: `entities_ranked_by` — *"reach from the target (direct before indirect),
121
+ then identity — a structural order, not a per-entity score"*.
122
+ - `retrieve` remains `[PARKED]`; this is the honesty fix the tier does not excuse.
123
+
124
+ - **`archetype` no longer scores an unmeasured HTTP surface as an absent one** (C3-7). The
125
+ command declares `endpoints` as a missing signal on runs with no root to read — and then
126
+ scored as if the answer were **0**, which is a measured statement. Inside the scorer that zero
127
+ did two things at once: it refuted `api-first` and it fired `worker`'s `event_no_http`
128
+ evidence, so a repository nobody measured came back classified as an event worker with the
129
+ reason published as if it were a finding (I-3/R9, inside a score).
130
+ - The count is nullable now. Unmeasured contributes nothing and says so in its own evidence
131
+ row; `event_no_http` requires the absence of HTTP as a *measured* fact. A measured zero
132
+ behaves exactly as before, which the battery asserts alongside the unmeasured case.
133
+ - Measured while closing it, and recorded rather than acted on: `archetype` on
134
+ BroadleafCommerce takes **9.3 s** (the field reported 22 s) and returns two high-confidence
135
+ dimensions of four, so the tier stays `[EXPERIMENTAL]` — the cost complaint does not
136
+ reproduce at that magnitude, and a command with two high-confidence answers is not a
137
+ candidate for `parked`.
138
+
139
+ - **The summary stopped costing more than the analyses it summarises** (C3-6, C3-21). Measured on
140
+ BroadleafCommerce with nothing warm: `--compact` **19.3 s → 13.3 s**, and with the parse cache
141
+ warm **14.0 s → 7.9 s**; `endpoints` **3.3 s → 1.4 s**. Two duplications inside one process, both
142
+ removed:
143
+ - The **core view was built twice on every cold run** — once for the L1 cache write and once for
144
+ the RIS update — and building it rebuilds the CIR. One repository state has one core view; both
145
+ writers now read it.
146
+ - The **endpoint extractor parsed every file itself** while `build_repo_ir` read the
147
+ content-addressed parse cache for the same bytes. A run that does both paid for the same parse
148
+ twice, and a warm cache measurably bought `endpoints` nothing — a fact this product published
149
+ in its own cache model. Same key, same extractor, same capture signature: the entry either side
150
+ writes is the entry the other reads. The cache-model rows for `endpoints` and the root command
151
+ are re-measured accordingly.
152
+ - The inversion is **narrowed, not gone**: `--compact` is still slower than `spring-audit`
153
+ (3.6 s) or `posture` (1.9 s), because it builds the summary *and* the core view where those
154
+ build one analysis each.
155
+ - **C3-21 does not reproduce on 3.7.0**: the cache hit that cost 2 647 ms now costs 1.6 s for
156
+ `explain` against a 1.6 s cold run, and the snapshot hit for `--compact` is 0.29 s. Recorded as
157
+ measured, not assumed closed.
158
+ - The battery pins the two mechanisms rather than wall-clock figures: a second extraction must
159
+ re-parse nothing, the cached and uncached answers must be identical, and one root run must
160
+ build the core view once.
161
+
162
+ - **A comment can no longer take a whole file out of the graph** (E-1). The declaration joiner
163
+ decided whether a line *starts* a type declaration by scanning raw text, so a comment carrying
164
+ `class` or `interface` followed by an identifier looked like a declaration head with its brace
165
+ on a later line — `/** Implements the interface only for the legacy path. */`, or a trailing
166
+ `// starter class is not an utility class` on an annotation. The join then swallowed the
167
+ annotation and the real declaration into one entry beginning with `@`, which the parser reads
168
+ as a pending annotation and never examines: the file contributed **zero symbols** — no type,
169
+ no endpoint, no transaction boundary — and a file that contributes nothing looks exactly like
170
+ a file with nothing in it, which is why no field report could ever name this.
171
+ - Comments are stripped before the keyword scan (block state carried across lines, string
172
+ literal aware), and the brace that ends a join must also be code, so a commented `{` no
173
+ longer cuts a real multi-line declaration in half.
174
+ - Measured A/B over six repositories: **open-banking-gateway recovers 6 types, three of them
175
+ Spring Boot application classes**; petclinic, eureka, openmrs-core, BroadleafCommerce and
176
+ keycloak are unchanged, and **no repository loses a symbol**.
177
+
178
+ - **`generate-tests` ranks by what depends on the file, not by how the file is named**
179
+ (C3-13, **`untested_sources[]` entries change shape**). Two rules, both name matching, both
180
+ measured on openmrs-core: admission kept only files whose name ends in one of five suffixes
181
+ (`Service.java`, `Controller.java`, `Repository.java`, `Mapper.java`, `RestController.java`),
182
+ reducing **866 production files to 11 candidates**; and coverage was a filename pair, so
183
+ `PersonServiceImpl` was a gap for want of a `PersonServiceImplTest`. What remained was ordered
184
+ by how often the substring `"public "` appears in the first 16 KB — while `blast_radius`,
185
+ transaction boundaries and endpoint exposure were already computed elsewhere in the same
186
+ product and never consulted.
187
+ - **Coverage is now a reach fact**: a type is covered when a test source reaches it — named
188
+ directly, or reached along the call, instantiation and injection edges a blast radius
189
+ already walks, through the interface the container wires it behind, or as a supertype of
190
+ something a test exercises. One forward traversal from every test type: 0.01 s on
191
+ BroadleafCommerce. Reaching is not asserting, so the coverage figure is a floor and the gap
192
+ list is a ceiling, and `notes` says so.
193
+ - **Admission is the population**, not a naming convention: openmrs-core 866 production files
194
+ → **161 untested**, BroadleafCommerce 2 765 → **1 494**, published as `population` beside
195
+ the list.
196
+ - **Order is the measured axes** — endpoints reached, transaction boundaries declared, classes
197
+ that depend on it — reusing `caller_reach`, `spring_impact._collect_endpoints` and
198
+ `spring_semantic.boundaries_declared_within` rather than deriving them again. The weights
199
+ that fold the three into `score` are published with `rank_weights_basis: "assumption, not a
200
+ measurement"`, and the order is reproducible from the axes without accepting them.
201
+ - `untested_sources[]`/`test_gaps[]` rows drop `rank_score`, `public_method_count` and
202
+ `has_framework_annotations` — measurements of the replaced basis — and carry
203
+ `endpoints_reached`, `transaction_boundaries` and `caller_classes` instead. `path`, `score`
204
+ and `reason` are unchanged. The new `test_gap_ranking` block publishes the basis, the
205
+ population and the caps.
206
+ - Cost, measured cold: BroadleafCommerce 11.1 s → **15.3 s**, openmrs-core 5.1 s → 10.2 s. A
207
+ run whose IR cannot be built keeps the filename algorithm and publishes the
208
+ `test_reach_graph` signal with what taking it costs the answer (I-8).
209
+
210
+ - **`generate-tests` publishes its time budget, and a cache no longer defeats it** (C3-1). The
211
+ 30 s cap was reachable only through `SOURCECODE_TESTS_TIMEOUT_MS`, a name in no help text —
212
+ the one knob that turns an empty answer into an answer was invisible to whoever was holding
213
+ the empty answer. `--timeout <seconds>` is now a documented flag (the variable still works;
214
+ the flag wins), and an exhausted budget publishes `analysis_budget` carrying the new
215
+ `time_budget` cap: *"an empty list here means the walk stopped, NOT that the repository has
216
+ nothing"*, with the budget, its source, and how to raise it.
217
+ - Closing it surfaced a sharper defect, measured: **the cache key ignored the budget**, so a
218
+ run that exhausted 2 s answered the re-run at 30 s from cache — the remedy the payload
219
+ names did nothing at all. The budget is now part of the cache identity, and an exhausted
220
+ result is never stored: an unfinished walk is worth re-running.
221
+ - Measured while closing it: the full scan on openmrs-core (3 300 files, cold cache) takes
222
+ **3.35 s** and returns 13 untested sources, so the field's empty payload does not reproduce
223
+ and the default budget is not the constraint it was taken for. The ranking half of C3-13
224
+ stays open — the command still matches file names while `blast_radius`, transactional
225
+ writes and endpoint exposure are already computed.
226
+
227
+ - **`review-pr` no longer counts documentation as a runtime change** (C3-11b). The field
228
+ reported a diff of 227 `.md` files as `runtime_changes: 228` — while every one of those
229
+ entries carried `artifact_type: "documentation"` and `change_effect: "documentation file (no
230
+ runtime impact)"`. The list contradicted its own members. Reproduced on a real git repository
231
+ (12 `.md` files + one touched controller): **13 → 1**. The classifier was never wrong;
232
+ membership was "not noise and not a build manifest", which admits everything else, and the
233
+ admission seam (K2) now asks whether the admitted type can carry runtime behaviour at all.
234
+ - Nothing is dropped: the twelve are reported under `non_runtime_changes` with the same
235
+ evidence and effect statement, and the GitHub comment names them by count so it cannot look
236
+ like it missed part of the diff.
237
+ - The split is asserted **against the effect statements themselves** — a type whose published
238
+ statement disclaims impact must be in the non-runtime set — so it cannot drift from the
239
+ prose it is derived from (C4-1).
240
+
241
+ - **One profile population, whatever surface is asked** (C1-18, **`spring_profiles` changes on
242
+ repositories with resource bundles or resource folders**). Reproduced on a fixture first: the
243
+ same repository in one session answered `["qa","dev"]` in the default view, `["dev","prod",
244
+ "staging"]` in `posture` and `["dev","prod","qa","staging"]` under `--agent`. Three
245
+ populations under one name — and every conditional-security finding is keyed on that set, so
246
+ the default agent surface was answering the profile question with the population that had
247
+ lost the environments.
248
+ - Authority `spring_profiles.profile_population`: four named signals — the
249
+ `application-{profile}` filename, the per-environment overlay directory,
250
+ `spring.config.activate.on-profile` / `spring.profiles` inside config documents, and
251
+ `@Profile` on a bean — unioned once, with `by_signal` published so each name's provenance
252
+ is auditable. The Java stack detector, `posture` and the serializer's profile section all
253
+ read it, asserted per surface.
254
+ - Closing it exposed two false positives in the signals it inherited, both fixed
255
+ structurally rather than by name (VAI): an `application-{x}` file counts only **beside its
256
+ base config** — alfresco-community-repo's `alfresco/messages/application-model_de.properties`
257
+ and 19 siblings were reported as twenty environments, now none — and an overlay directory
258
+ counts only when it **holds a config file** — spring-petclinic's `db/`, `messages/`,
259
+ `static/` and `templates/` were reported as four environments, now `mysql, postgres`, its
260
+ real profiles.
261
+
262
+ - **The token-saving ratio is published, and published as a ceiling** (CL-1). `token_economy`
263
+ emitted `emitted`, `baseline_raw_read` and `saved` — three numbers a reader divides into a
264
+ multiple and then quotes. The multiple travelled without the label the block put on the
265
+ inputs, which is how "up to 55×" ends up in a room. `ratio_upper_bound` is now emitted with
266
+ a `ratio_basis` that states the counterfactual making it a ceiling — every cited file and
267
+ build manifest read **in full and once** — the band we measured for the ceiling itself
268
+ (**3.8×–37.6×** over `--compact` and `--agent` on spring-petclinic, BroadleafCommerce,
269
+ openmrs-core and keycloak; nothing near 55×), and the field's 10×–20× read of the saving an
270
+ agent actually realizes.
271
+ - `realized_saving` is `null` with its reason rather than a number: which files an agent would
272
+ truly have read is not observable from this process, and a `0` there would read as "no
273
+ saving" (I-3).
274
+
275
+ - **`spring-audit` counts defects as well as observations** (C2-5). A rule fires per
276
+ observation; a reader counts repairs. The audit published only the first number and let it
277
+ stand for the second: on openmrs-core `ConceptServiceImpl#checkIfLocked` carried **six
278
+ TX-006 findings, one per call site, for one annotated method with one fix**, and the
279
+ ledger's original witness is a private `@Transactional` method that draws TX-001 *and*
280
+ TX-006 for the same repair. Measured on the fleet: **openmrs-core 38 findings → 29
281
+ defects, BroadleafCommerce 19 → 14**.
282
+ - A defect is `(category, defect_kind, symbol)` — the thing you edit, and what is wrong
283
+ with it. `defect_kind` is **declared by the rule itself** (TX-001 and TX-006 both
284
+ declare `proxy_bypass`) and defaults to the rule's own id, so a rule that declares
285
+ nothing is never merged into another by omission, and there is no rule table maintained
286
+ beside the rules to drift out of date (C4-1).
287
+ - Nothing is filtered. `findings[]` keeps every observation and each one now names its
288
+ `defect_id`; the new `defects[]` rows carry `rule_ids`, `witness_count` and the witness
289
+ ids, so the grouping is auditable in both directions. `summary` publishes
290
+ `total_findings`, `total_defects`, `defects_by_severity` and a `counts_note` stating
291
+ which is which — `by_severity` and `by_category` keep counting observations, because a
292
+ count that changes basis under an unchanged name is the same defect wearing a new suit.
293
+ - A defect takes the **strongest** severity and confidence among its witnesses, and its id
294
+ is keyed on the identity, not the witnesses — acquiring a second witness next run does
295
+ not rename it, so a baseline keeps matching it.
296
+
297
+ - **`migrate-check` lists the blockers; hygiene is counted, not listed** (C2-6, **default
298
+ payload changes**). On openmrs-core the default report carried 310 findings of which **184
299
+ were `java_8_best_practice` advisory hygiene** — findings that block no version and that
300
+ every readiness score already excludes. A reader scanning the array met three advisory
301
+ entries for every two blockers. The emitted list now carries the blockers, ordered
302
+ most-severe first (**310 → 126 listed, 912 KB → 717 KB**), and `--include-hygiene` restores
303
+ the entries.
304
+ - **The floor cuts the list, never a figure.** `summary.by_severity`, `by_rule`,
305
+ `by_migration_target`, `total_findings`, `hygiene_findings`, `blocking_count` and every
306
+ dimension score are byte-identical to the unfloored run and still cover the whole
307
+ population — verified as an equality, not a claim.
308
+ - It is published as a cap, not applied in silence: `findings_floor` (the `severity_floor`
309
+ row of `CAP_EFFECTS`, I-8) states what was removed, what stayed exact, and the flag that
310
+ restores it, so `len(findings)` is never read as the total.
311
+ - The other half of the ledger row — "headline score reads 0/100 while real blockers are
312
+ 481" — was already closed and re-measured here: hygiene is out of the aggregate, and
313
+ openmrs's 0 is `min(jakarta 0, hibernate 0)` with `jdk_modernization` (58) excluded by
314
+ design. The score was honest; the finding list was the noise.
315
+
3
316
  ## [3.7.0] — 2026-08-01
4
317
 
5
318
  **The exit-code contract and the C3 surface block.** Seven rows closed: the two the field named
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 3.7.0
3
+ Version: 3.8.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
@@ -251,7 +251,7 @@ from it.
251
251
  | `review-pr` / `fix-bug` / `prepare-context` | supported | diff review, symptom triage, task-shaped context | |
252
252
  | `plan` / `compare` / `delta` / `contract-diff` | supported | what to review for a change; candidates by measured cost; outcome of a change; public-contract break | no verdicts, measured cost only |
253
253
  | `validation` | supported | request-body validation coverage and gaps | |
254
- | `baseline capture\|diff\|trend` | supported | versioned architectural metrics over time | trend reporting, not gating |
254
+ | `baseline capture\|diff` · `trend` | supported | versioned architectural metrics over time; `ask trend <dir>` reads the series | 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`. Automate it: [baseline-ci.yml](docs/baseline-ci.yml) |
255
255
  | `retrieve` | parked | typed knowledge queries over the model | |
256
256
  | `archetype` | experimental | evidence-based architectural archetype | |
257
257
  | `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
@@ -275,6 +275,34 @@ Honest limits worth knowing before you rely on it:
275
275
  - Architecture classification is tuned for Spring MVC layered apps; SPI/plugin models (e.g. Quarkus extensions) may be misclassified. JAX-RS subresource-locator endpoint recall is ~65%.
276
276
  - Self-invocation `@Transactional` bypass (same-class call skipping the proxy) is not detected.
277
277
 
278
+ ### What the security surface does not answer
279
+
280
+ Published because a product that states its limits is not compared on breadth — it is
281
+ compared on depth. Each row is emitted in the payload too (`non_coverage`), so an agent
282
+ reading JSON sees the same boundary a buyer reads here.
283
+
284
+ | Not covered | Why | What answers it |
285
+ |---|---|---|
286
+ | **Whether request input reaches a sink — no dataflow or taint analysis.** | This engine resolves structure and wiring without compiling. Taint needs value flow through a program, which is a different analysis with a different failure mode: an unsound one produces confident findings that are wrong, and every claim here is meant to be checkable against the line that produced it. | A dataflow scanner (Semgrep, CodeQL). What this product adds on top is reachability: which of that tool's findings sit behind an endpoint that is reachable unauthenticated. |
287
+ | **Secrets outside Java and Spring configuration — a credential in a deployment descriptor, a Helm value, a CI variable file.** | The file population this analyzer reads is the Java source and the Spring configuration convention. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
288
+ | **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. |
289
+ | **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. |
290
+
291
+ Two more boundaries worth stating in the same voice:
292
+
293
+ | Not covered | Why | What answers it |
294
+ |---|---|---|
295
+ | **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. |
296
+ | **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. |
297
+
298
+ **Positioning.** Until an executor ships, this is the **diagnosis layer**: it measures what
299
+ must change, what each change reaches, and what a gate should block — and it removes none of
300
+ it. Field evaluation scored it 7/10 as a report generator and 5.5/10 as a development tool,
301
+ and that gap is the honest description, not a defect to argue with. `migrate-check` publishes
302
+ the OpenRewrite recipe each finding carries so the executor that does apply changes has its
303
+ input.
304
+
305
+
278
306
  ---
279
307
 
280
308
  ## Pricing
@@ -348,7 +376,8 @@ Matching endpoints report `policy: "custom"` and drop out of the `no_security_si
348
376
  | Doc | What it covers |
349
377
  |-----|----------------|
350
378
  | [USER_GUIDE.md](docs/USER_GUIDE.md) | Full command reference, flags, output schema, workflows |
351
- | [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml`, enforce them in the edit loop and in CI |
379
+ | [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 |
380
+ | [baseline-ci.yml](docs/baseline-ci.yml) | Capture an architectural baseline per release, so the series exists when you want to read it |
352
381
  | [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 (experimental) |
353
382
  | [migrate-check.md](docs/migrate-check.md) | Migration rule catalogue (MIG-001..043) + Hibernate stratification |
354
383
  | [MODERNIZATION.md](docs/MODERNIZATION.md) | The modernization product: assess → understand → plan → execute |
@@ -213,7 +213,7 @@ from it.
213
213
  | `review-pr` / `fix-bug` / `prepare-context` | supported | diff review, symptom triage, task-shaped context | |
214
214
  | `plan` / `compare` / `delta` / `contract-diff` | supported | what to review for a change; candidates by measured cost; outcome of a change; public-contract break | no verdicts, measured cost only |
215
215
  | `validation` | supported | request-body validation coverage and gaps | |
216
- | `baseline capture\|diff\|trend` | supported | versioned architectural metrics over time | trend reporting, not gating |
216
+ | `baseline capture\|diff` · `trend` | supported | versioned architectural metrics over time; `ask trend <dir>` reads the series | 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`. Automate it: [baseline-ci.yml](docs/baseline-ci.yml) |
217
217
  | `retrieve` | parked | typed knowledge queries over the model | |
218
218
  | `archetype` | experimental | evidence-based architectural archetype | |
219
219
  | `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
@@ -237,6 +237,34 @@ Honest limits worth knowing before you rely on it:
237
237
  - Architecture classification is tuned for Spring MVC layered apps; SPI/plugin models (e.g. Quarkus extensions) may be misclassified. JAX-RS subresource-locator endpoint recall is ~65%.
238
238
  - Self-invocation `@Transactional` bypass (same-class call skipping the proxy) is not detected.
239
239
 
240
+ ### What the security surface does not answer
241
+
242
+ Published because a product that states its limits is not compared on breadth — it is
243
+ compared on depth. Each row is emitted in the payload too (`non_coverage`), so an agent
244
+ reading JSON sees the same boundary a buyer reads here.
245
+
246
+ | Not covered | Why | What answers it |
247
+ |---|---|---|
248
+ | **Whether request input reaches a sink — no dataflow or taint analysis.** | This engine resolves structure and wiring without compiling. Taint needs value flow through a program, which is a different analysis with a different failure mode: an unsound one produces confident findings that are wrong, and every claim here is meant to be checkable against the line that produced it. | A dataflow scanner (Semgrep, CodeQL). What this product adds on top is reachability: which of that tool's findings sit behind an endpoint that is reachable unauthenticated. |
249
+ | **Secrets outside Java and Spring configuration — a credential in a deployment descriptor, a Helm value, a CI variable file.** | The file population this analyzer reads is the Java source and the Spring configuration convention. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
250
+ | **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. |
251
+ | **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. |
252
+
253
+ Two more boundaries worth stating in the same voice:
254
+
255
+ | Not covered | Why | What answers it |
256
+ |---|---|---|
257
+ | **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. |
258
+ | **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. |
259
+
260
+ **Positioning.** Until an executor ships, this is the **diagnosis layer**: it measures what
261
+ must change, what each change reaches, and what a gate should block — and it removes none of
262
+ it. Field evaluation scored it 7/10 as a report generator and 5.5/10 as a development tool,
263
+ and that gap is the honest description, not a defect to argue with. `migrate-check` publishes
264
+ the OpenRewrite recipe each finding carries so the executor that does apply changes has its
265
+ input.
266
+
267
+
240
268
  ---
241
269
 
242
270
  ## Pricing
@@ -310,7 +338,8 @@ Matching endpoints report `policy: "custom"` and drop out of the `no_security_si
310
338
  | Doc | What it covers |
311
339
  |-----|----------------|
312
340
  | [USER_GUIDE.md](docs/USER_GUIDE.md) | Full command reference, flags, output schema, workflows |
313
- | [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml`, enforce them in the edit loop and in CI |
341
+ | [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 |
342
+ | [baseline-ci.yml](docs/baseline-ci.yml) | Capture an architectural baseline per release, so the series exists when you want to read it |
314
343
  | [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 (experimental) |
315
344
  | [migrate-check.md](docs/migrate-check.md) | Migration rule catalogue (MIG-001..043) + Hibernate stratification |
316
345
  | [MODERNIZATION.md](docs/MODERNIZATION.md) | The modernization product: assess → understand → plan → execute |
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "3.7.0"
7
+ version = "3.8.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__ = "3.7.0"
7
+ __version__ = "3.8.0"
@@ -175,8 +175,13 @@ class _Features:
175
175
  module_count: int
176
176
  concept_mass: dict[str, float] # concept → fraction of source files
177
177
  entry_kinds: dict[str, int]
178
- endpoint_total: int
179
- endpoint_share: float # endpoints per source file
178
+ # `None` when the endpoint surface was NOT measured (no root to read, or the
179
+ # extraction failed). It used to be 0, which is a different claim: a score
180
+ # that reads "no HTTP surface" off an unknown one refutes `api-first` and
181
+ # actively supports `worker`, so an unmeasured repository was classified as
182
+ # if it exposed nothing (I-3/R9, inside a score).
183
+ endpoint_total: "Optional[int]"
184
+ endpoint_share: "Optional[float]" # endpoints per source file
180
185
  packaging: Optional[str]
181
186
  frameworks: set[str]
182
187
  graph_hubs: list[str]
@@ -250,7 +255,11 @@ class ArchetypeClassifier:
250
255
  signals_missing=f.signals_missing,
251
256
  generated_from=(
252
257
  f"{f.total_files} source files, {f.module_count} modules, "
253
- f"{f.endpoint_total} endpoints"
258
+ + (
259
+ f"{f.endpoint_total} endpoints"
260
+ if f.endpoint_total is not None
261
+ else "endpoint surface not measured"
262
+ )
254
263
  ),
255
264
  graph_metrics=f.graph_metrics,
256
265
  )
@@ -299,8 +308,10 @@ class ArchetypeClassifier:
299
308
  missing.append("entry_points")
300
309
 
301
310
  endpoint_total = self._endpoint_count(root)
302
- endpoint_share = (endpoint_total / total) if total else 0.0
303
- if root is not None:
311
+ endpoint_share = (
312
+ (endpoint_total / total) if (endpoint_total is not None and total) else None
313
+ )
314
+ if endpoint_total is not None:
304
315
  used.append("endpoints")
305
316
  else:
306
317
  missing.append("endpoints")
@@ -519,21 +530,31 @@ class ArchetypeClassifier:
519
530
  # api-first: HTTP surface must be significant relative to size. Ramp so a
520
531
  # rounding-error surface cannot win: 0 below 0.5 endpoints/100 files, linear
521
532
  # to full strength at >=2/100 files. (neo4j: 18/5600 = 0.32/100 -> 0.)
522
- density = f.endpoint_share * 100
523
- api_strength = max(0.0, min(1.0, (density - 0.5) / 1.5)) if f.endpoint_total else 0.0
524
- add("api-first", "endpoint_density",
525
- f"{f.endpoint_total} endpoints over {f.total_files} files "
526
- f"({density:.2f}/100 files)",
527
- 3.0, api_strength, 1.0)
533
+ if f.endpoint_share is None:
534
+ # Unmeasured, not zero: contribute nothing and say which axis is blind.
535
+ add("api-first", "endpoint_density",
536
+ "endpoint surface not measured this dimension is scored without it",
537
+ 3.0, 0.0, 0.0)
538
+ else:
539
+ density = f.endpoint_share * 100
540
+ api_strength = max(0.0, min(1.0, (density - 0.5) / 1.5)) if f.endpoint_total else 0.0
541
+ add("api-first", "endpoint_density",
542
+ f"{f.endpoint_total} endpoints over {f.total_files} files "
543
+ f"({density:.2f}/100 files)",
544
+ 3.0, api_strength, 1.0)
528
545
  cli_entries = f.entry_kinds.get("cli", 0)
529
546
  add("cli", "cli_entry_points", f"{cli_entries} CLI entry point(s); cli mass ≈ {cm['cli']:.0%}",
530
547
  2.5, 1.0 if cli_entries else (1.0 if cm["cli"] > 0.05 else 0.0), max(cm["cli"], 0.2))
531
548
  add("daemon", "server_bootstrap",
532
549
  f"server/bootstrap entries: {f.entry_kinds.get('server',0)+f.entry_kinds.get('bootstrap',0)}",
533
550
  2.0, 1.0 if ("server" in f.entry_kinds or "bootstrap" in f.entry_kinds) else 0.0, 0.5)
551
+ # `event_no_http` needs the absence of HTTP as a MEASURED fact: firing it
552
+ # on an unmeasured surface is how an unknown became evidence for `worker`.
553
+ _no_http_known = f.endpoint_total == 0
534
554
  add("worker", "event_no_http",
535
- f"event mass ≈ {cm['event']:.0%}, endpoints={f.endpoint_total}",
536
- 1.5, 1.0 if (cm["event"] > 0.05 and f.endpoint_total == 0) else 0.0, max(cm["event"], 0.1))
555
+ f"event mass ≈ {cm['event']:.0%}, endpoints="
556
+ + (str(f.endpoint_total) if f.endpoint_total is not None else "not measured"),
557
+ 1.5, 1.0 if (cm["event"] > 0.05 and _no_http_known) else 0.0, max(cm["event"], 0.1))
537
558
  lib_strength = 1.0 if (f.packaging == "jar" and not f.entry_kinds) else 0.3
538
559
  add("library", "consumed_as_dependency",
539
560
  f"packaging={f.packaging}, entry kinds={list(f.entry_kinds) or 'none'}",
@@ -666,12 +687,18 @@ class ArchetypeClassifier:
666
687
  return head if tail else ""
667
688
 
668
689
  @staticmethod
669
- def _endpoint_count(root: Optional[Path]) -> int:
690
+ def _endpoint_count(root: Optional[Path]) -> "Optional[int]":
691
+ """The measured endpoint count, or None when it was not measured.
692
+
693
+ Both failure modes — no root to read, and an extraction that raised —
694
+ return None rather than 0, because every consumer below treats 0 as the
695
+ measured statement "this repository exposes no HTTP surface".
696
+ """
670
697
  if root is None:
671
- return 0
698
+ return None
672
699
  try:
673
700
  from sourcecode.repository_ir import extract_java_endpoints
674
701
  data = extract_java_endpoints(root)
675
702
  return int(data.get("total", len(data.get("endpoints", []))))
676
703
  except Exception:
677
- return 0
704
+ return None
@@ -124,16 +124,18 @@ COMMANDS: tuple[CommandCache, ...] = (
124
124
  "`--compact` is what a warm stores by default; `--agent` needs `cache warm --agent`. "
125
125
  "`--env-map`, `--depth N` and `--exclude` change the *analysis*, so they miss the "
126
126
  "warmed core and rescan — this is the 171 s the field measured after a 103 s warm.",
127
- "--compact 17.7 s → 0.3 s; --agent --full --env-map --depth 20 34.7 s → 33.9 s (no gain)"),
127
+ "--compact 13.3 s cold → 0.3 s warm (cold re-measured on 3.7.0: was 19.3 s, C3-6); "
128
+ "--agent --full --env-map --depth 20 34.7 s → 33.9 s (no gain)"),
128
129
  CommandCache("posture", ("cir", "parse"), "shared", False,
129
130
  "Resolves the conditional bean graph on every run, over the shared CIR a warm "
130
131
  "builds — the parse it used to repeat for itself. `--diff` compares two profile "
131
132
  "sets over that one IR, so the second side costs the resolution only.",
132
133
  "10.1 s → 1.6 s"),
133
- CommandCache("endpoints", ("ris", "parse"), "none", False,
134
- "Recomputes the endpoint surface on every run and refreshes the RIS endpoint index. "
135
- "Measured: a warm buys it nothing.",
136
- "2.8 s 2.9 s"),
134
+ CommandCache("endpoints", ("ris", "parse"), "shared", False,
135
+ "Recomputes the endpoint surface on every run, over a parse a warm has already "
136
+ "paid for. Until 3.7.0 the extractor parsed every file itself instead of reading "
137
+ "the shared parse cache, and a warm measurably bought it nothing (C3-6).",
138
+ "3.3 s → 1.4 s (re-measured on 3.7.0; was 2.8 s → 2.9 s)"),
137
139
  CommandCache("spring-audit", ("ris", "parse"), "shared", False,
138
140
  "Recomputes every run, but over a parse a warm has already paid for.",
139
141
  "8.8 s → 3.7 s"),
@@ -158,8 +160,8 @@ COMMANDS: tuple[CommandCache, ...] = (
158
160
  "1.1 s → 2.3 s (slower)"),
159
161
  CommandCache("plan", ("parse",), "shared", False, "", "9.3 s → 3.8 s"),
160
162
  CommandCache("compare", ("parse",), "shared", False, ""),
161
- CommandCache("delta", (), "none", False, "Analyses two checkouts; neither is the tree the cache describes."),
162
- CommandCache("contract-diff", (), "none", False, "Analyses two checkouts."),
163
+ CommandCache("delta", (), "none", False, "Analyses two states — two checkouts, or two refs materialised into temporary trees; neither is the tree the cache describes."),
164
+ CommandCache("contract-diff", (), "none", False, "Analyses two states (checkouts or refs); neither is the tree the cache describes."),
163
165
  CommandCache("fix-bug", ("task",), "none", True,
164
166
  "Shorthand for `prepare-context fix-bug`; caches its own answer, which a warm never runs."),
165
167
  CommandCache("rename-class", (), "none", False, ""),
@@ -183,6 +185,7 @@ COMMANDS: tuple[CommandCache, ...] = (
183
185
  "Reads the RIS a warm rebuilds — that is all it does. Without one it answers "
184
186
  "`no_ris` instead of a snapshot.",
185
187
  "0.2 s either way"),
188
+ CommandCache("trend", (), "none", False, "Reads stored baseline artifacts from disk; analyses no source, so no cache layer applies. Same command as `baseline trend`."),
186
189
  CommandCache("baseline", ("parse",), "shared", False, "`capture`/`diff`/`trend` over architectural metrics.",
187
190
  "capture 8.7 s → 3.6 s"),
188
191
  CommandCache("retrieve", ("cir", "parse"), "shared", False,