sourcecode 5.4.1__tar.gz → 5.5.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 (356) hide show
  1. {sourcecode-5.4.1 → sourcecode-5.5.0}/CHANGELOG.md +53 -0
  2. {sourcecode-5.4.1 → sourcecode-5.5.0}/PKG-INFO +3 -3
  3. {sourcecode-5.4.1 → sourcecode-5.5.0}/README.md +2 -2
  4. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/DEFECT-LEDGER.md +3 -3
  5. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/USER_GUIDE.md +1 -1
  6. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/semantic-ir-roadmap.md +40 -0
  7. {sourcecode-5.4.1 → sourcecode-5.5.0}/pyproject.toml +1 -1
  8. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/__init__.py +1 -1
  9. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/cache_model.py +9 -0
  10. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/cli.py +26 -1
  11. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/non_coverage.py +21 -0
  12. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/reference_facts.py +39 -11
  13. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/repository_ir.py +12 -1
  14. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/risk.py +2 -1
  15. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/validation_surface.py +89 -0
  16. {sourcecode-5.4.1 → sourcecode-5.5.0}/.github/workflows/build-windows.yml +0 -0
  17. {sourcecode-5.4.1 → sourcecode-5.5.0}/.github/workflows/perf-gate.yml +0 -0
  18. {sourcecode-5.4.1 → sourcecode-5.5.0}/.gitignore +0 -0
  19. {sourcecode-5.4.1 → sourcecode-5.5.0}/.ruff.toml +0 -0
  20. {sourcecode-5.4.1 → sourcecode-5.5.0}/CLAUDE.md +0 -0
  21. {sourcecode-5.4.1 → sourcecode-5.5.0}/CONTRIBUTING.md +0 -0
  22. {sourcecode-5.4.1 → sourcecode-5.5.0}/LICENSE +0 -0
  23. {sourcecode-5.4.1 → sourcecode-5.5.0}/SECURITY.md +0 -0
  24. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/CACHE.md +0 -0
  25. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/COMMERCIAL-OFFER.md +0 -0
  26. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/CUSTOMER-VALIDATION.md +0 -0
  27. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/DEMO-5MIN.md +0 -0
  28. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/DEVELOPMENT-ROADMAP.md +0 -0
  29. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/EXECUTION-PLAN-12MO.md +0 -0
  30. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/EXECUTIVE-ROADMAP.md +0 -0
  31. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/MANUAL-USUARIO.md +0 -0
  32. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/MODERNIZATION.md +0 -0
  33. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/PRODUCT_AUDIT.md +0 -0
  34. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/PRODUCT_IDENTITY.md +0 -0
  35. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/PRODUCT_TIERS.md +0 -0
  36. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/RC1-CHECKLIST.md +0 -0
  37. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/RELEASE-CHECKLIST.md +0 -0
  38. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/CATALOG-retrieval-intents.md +0 -0
  39. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/DESIGN-knowledge-provider-integration.md +0 -0
  40. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/DESIGN-p5.3b-statement-surface.md +0 -0
  41. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/DESIGN-p5.5-span-index.md +0 -0
  42. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/DESIGN-p6-semantic-impact-engine.md +0 -0
  43. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/DESIGN-p6-semantic-integration-engine.md +0 -0
  44. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/DESIGN-p7-semantic-services.md +0 -0
  45. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/DESIGN-robustness-security-inference.md +0 -0
  46. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/DESIGN-semantic-retrieval.md +0 -0
  47. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/EPV-p6-class-typeref.md +0 -0
  48. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/REPORT-p6-flow-analyzer-comparison.md +0 -0
  49. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/REPORT-p6-integration-detector-comparison.md +0 -0
  50. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/REPORT-p8-flow-analyzer-migration.md +0 -0
  51. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/REPORT-p9-integration-detector-migration.md +0 -0
  52. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/adr/0001-semantic-ir.md +0 -0
  53. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/adr/0002-source-evidence-boundary.md +0 -0
  54. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/adr/0003-architectural-characterization.md +0 -0
  55. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/adr/0004-semantic-retrieval.md +0 -0
  56. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/adr/0005-evidence-reconciliation.md +0 -0
  57. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/adr/0006-performance-harness.md +0 -0
  58. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/adr/0007-composition-semantics.md +0 -0
  59. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/adr/0008-answer-coherence.md +0 -0
  60. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/consumer-disposition-inventory.md +0 -0
  61. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/overview.md +0 -0
  62. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/product-architecture-review.md +0 -0
  63. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/product-strategy-layering.md +0 -0
  64. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/architecture/semantic-ir-consumer-matrix.md +0 -0
  65. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/baseline-ci.yml +0 -0
  66. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/commercial-pipeline-audit.md +0 -0
  67. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/contracts-ci.yml +0 -0
  68. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/contracts.md +0 -0
  69. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/eval/2026-06-15-petclinic-rest-issue11-vets-pagination.md +0 -0
  70. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/eval/2026-06-15-petclinic-rest-issue147-validation.md +0 -0
  71. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/eval/2026-06-15-petclinic-rest-workflow.md +0 -0
  72. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/eval/2026-06-15-phase18-openapi-surface.md +0 -0
  73. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/eval/2026-06-15-phase20-validation-surface.md +0 -0
  74. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/eval/2026-06-16-broadleaf-checkout-impact-fieldtest.md +0 -0
  75. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/eval/2026-06-16-petclinic-rest-issue11-weakness2-closed.md +0 -0
  76. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/eval/2026-06-16-spring-petclinic-issue2333-dead-vets.md +0 -0
  77. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/licensing-schema.md +0 -0
  78. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/migrate-check.md +0 -0
  79. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/README.md +0 -0
  80. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/REGRESSION-GATE.md +0 -0
  81. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/SUMMARY.md +0 -0
  82. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/alfresco__ask__cold.json +0 -0
  83. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/alfresco__ask__warm.json +0 -0
  84. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/broadleaf__ask__cold.json +0 -0
  85. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/broadleaf__ask__warm.json +0 -0
  86. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/eureka__ask__cold.json +0 -0
  87. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/eureka__ask__warm.json +0 -0
  88. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/jenkins__ask__cold.json +0 -0
  89. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/jenkins__ask__warm.json +0 -0
  90. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/jobrunr__ask__cold.json +0 -0
  91. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/jobrunr__ask__warm.json +0 -0
  92. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/keycloak__ask__cold.json +0 -0
  93. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/keycloak__ask__warm.json +0 -0
  94. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/neo4j__ask__cold.json +0 -0
  95. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/neo4j__ask__warm.json +0 -0
  96. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/ofbiz__ask__cold.json +0 -0
  97. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/ofbiz__ask__warm.json +0 -0
  98. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/openmrs__ask__cold.json +0 -0
  99. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/openmrs__ask__warm.json +0 -0
  100. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/petclinic__ask__cold.json +0 -0
  101. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.15/petclinic__ask__warm.json +0 -0
  102. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/SUMMARY.md +0 -0
  103. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/alfresco__ask__cold.json +0 -0
  104. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/alfresco__ask__warm.json +0 -0
  105. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/broadleaf__ask__cold.json +0 -0
  106. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/broadleaf__ask__warm.json +0 -0
  107. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/eureka__ask__cold.json +0 -0
  108. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/eureka__ask__warm.json +0 -0
  109. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/jenkins__ask__cold.json +0 -0
  110. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/jenkins__ask__warm.json +0 -0
  111. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/jobrunr__ask__cold.json +0 -0
  112. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/jobrunr__ask__warm.json +0 -0
  113. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/keycloak__ask__cold.json +0 -0
  114. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/keycloak__ask__warm.json +0 -0
  115. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/neo4j__ask__cold.json +0 -0
  116. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/neo4j__ask__warm.json +0 -0
  117. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/ofbiz__ask__cold.json +0 -0
  118. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/ofbiz__ask__warm.json +0 -0
  119. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/openmrs__ask__cold.json +0 -0
  120. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/openmrs__ask__warm.json +0 -0
  121. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/petclinic__ask__cold.json +0 -0
  122. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/2.5.16/petclinic__ask__warm.json +0 -0
  123. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/gate-latest/README.md +0 -0
  124. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/gate-latest/broadleaf__ask__warm.json +0 -0
  125. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/gate-latest/broadleaf__endpoints__warm.json +0 -0
  126. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/gate-latest/broadleaf__migrate-check__warm.json +0 -0
  127. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/gate-latest/broadleaf__posture__warm.json +0 -0
  128. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/gate-latest/broadleaf__spring-audit__warm.json +0 -0
  129. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/gate-latest/broadleaf__validation__warm.json +0 -0
  130. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/perf/baselines/reference-best/README.md +0 -0
  131. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/posture.md +0 -0
  132. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/privacy.md +0 -0
  133. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/pro-experience-audit.md +0 -0
  134. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/schema.md +0 -0
  135. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/spec/envelope-v1.md +0 -0
  136. {sourcecode-5.4.1 → sourcecode-5.5.0}/docs/spring-audit-ci.yml +0 -0
  137. {sourcecode-5.4.1 → sourcecode-5.5.0}/raw +0 -0
  138. {sourcecode-5.4.1 → sourcecode-5.5.0}/scripts/compare_integration_engines.py +0 -0
  139. {sourcecode-5.4.1 → sourcecode-5.5.0}/scripts/customer_smoke_test.sh +0 -0
  140. {sourcecode-5.4.1 → sourcecode-5.5.0}/scripts/generate_jdk_exports.py +0 -0
  141. {sourcecode-5.4.1 → sourcecode-5.5.0}/scripts/perf_gate.py +0 -0
  142. {sourcecode-5.4.1 → sourcecode-5.5.0}/scripts/perf_harness.py +0 -0
  143. {sourcecode-5.4.1 → sourcecode-5.5.0}/scripts/sync_gate_anchors.py +0 -0
  144. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/adaptive_scanner.py +0 -0
  145. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/archetype.py +0 -0
  146. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/architectural_baseline.py +0 -0
  147. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/architectural_delta.py +0 -0
  148. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/architecture_analyzer.py +0 -0
  149. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/architecture_summary.py +0 -0
  150. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/ast_extractor.py +0 -0
  151. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/audit_report.py +0 -0
  152. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/baseline_autocapture.py +0 -0
  153. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/bundled_docs.py +0 -0
  154. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/cache.py +0 -0
  155. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/call_surface.py +0 -0
  156. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/caller_metrics.py +0 -0
  157. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/caller_reach.py +0 -0
  158. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/canonical_ir.py +0 -0
  159. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/chain_rules.py +0 -0
  160. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/change_plan.py +0 -0
  161. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/cir_graphs.py +0 -0
  162. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/classifier.py +0 -0
  163. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/client_calls.py +0 -0
  164. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  165. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/compare.py +0 -0
  166. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/confidence_analyzer.py +0 -0
  167. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/constraint_diff.py +0 -0
  168. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/consumer_join.py +0 -0
  169. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/container_wiring.py +0 -0
  170. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/context_cache.py +0 -0
  171. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/context_graph.py +0 -0
  172. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/context_scorer.py +0 -0
  173. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/context_summarizer.py +0 -0
  174. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/contract_diff.py +0 -0
  175. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/contract_init.py +0 -0
  176. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/contract_model.py +0 -0
  177. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/contract_pipeline.py +0 -0
  178. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/coverage_parser.py +0 -0
  179. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/data_exposure.py +0 -0
  180. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/data_labels.py +0 -0
  181. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/declarations.py +0 -0
  182. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/defect_identity.py +0 -0
  183. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/degradation.py +0 -0
  184. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/dependency_analyzer.py +0 -0
  185. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/deployment_prefix.py +0 -0
  186. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detach.py +0 -0
  187. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/__init__.py +0 -0
  188. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/base.py +0 -0
  189. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  190. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/dart.py +0 -0
  191. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/dotnet.py +0 -0
  192. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/elixir.py +0 -0
  193. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/go.py +0 -0
  194. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/heuristic.py +0 -0
  195. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/hybrid.py +0 -0
  196. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/java.py +0 -0
  197. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  198. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/nodejs.py +0 -0
  199. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/parsers.py +0 -0
  200. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/php.py +0 -0
  201. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/project.py +0 -0
  202. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/python.py +0 -0
  203. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/ruby.py +0 -0
  204. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/rust.py +0 -0
  205. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/systems.py +0 -0
  206. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/terraform.py +0 -0
  207. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/detectors/tooling.py +0 -0
  208. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/doc_analyzer.py +0 -0
  209. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/dynamic_argument_surface.py +0 -0
  210. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/endpoint_literals.py +0 -0
  211. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/endpoint_metrics.py +0 -0
  212. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  213. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/env_analyzer.py +0 -0
  214. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/envelope.py +0 -0
  215. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/environment_resolution.py +0 -0
  216. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/error_schema.py +0 -0
  217. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/evidence_provider.py +0 -0
  218. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/execution_plan.py +0 -0
  219. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/explain.py +0 -0
  220. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/facts/__init__.py +0 -0
  221. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/facts/registry.json +0 -0
  222. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/file_chunker.py +0 -0
  223. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/file_classifier.py +0 -0
  224. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/filter_surface.py +0 -0
  225. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/format_contract.py +0 -0
  226. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/fqn_utils.py +0 -0
  227. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/gate_anchors.py +0 -0
  228. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/git_analyzer.py +0 -0
  229. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/git_checkout.py +0 -0
  230. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/graph_analyzer.py +0 -0
  231. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/graph_evidence.py +0 -0
  232. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/hibernate_strat.py +0 -0
  233. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/identity_fallback.py +0 -0
  234. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/integration_coordinates.py +0 -0
  235. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/jdk_exports.py +0 -0
  236. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/license.py +0 -0
  237. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/mcp/__init__.py +0 -0
  238. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/mcp/dependency_import.py +0 -0
  239. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  240. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  241. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  242. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  243. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  244. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/mcp/orchestrator.py +0 -0
  245. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/mcp/registry.py +0 -0
  246. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/mcp/runner.py +0 -0
  247. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/mcp/server.py +0 -0
  248. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/mcp_nudge.py +0 -0
  249. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/metrics_analyzer.py +0 -0
  250. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/migrate_check.py +0 -0
  251. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/migration_blast.py +0 -0
  252. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/openapi_surface.py +0 -0
  253. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/openrewrite_recipe.py +0 -0
  254. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/output_budget.py +0 -0
  255. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/output_encoding.py +0 -0
  256. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/parallel.py +0 -0
  257. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/parse_cache.py +0 -0
  258. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/partial_contract.py +0 -0
  259. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/path_admission.py +0 -0
  260. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/path_filters.py +0 -0
  261. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/perf.py +0 -0
  262. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/phased_run.py +0 -0
  263. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/pipe_contract.py +0 -0
  264. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/posture.py +0 -0
  265. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/pr_comment_renderer.py +0 -0
  266. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/pr_impact.py +0 -0
  267. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/prepare_context.py +0 -0
  268. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/progress.py +0 -0
  269. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/provenance.py +0 -0
  270. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/ranking_engine.py +0 -0
  271. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/readiness_timeline.py +0 -0
  272. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/readonly.py +0 -0
  273. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/reconciliation.py +0 -0
  274. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/redactor.py +0 -0
  275. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/release_info.py +0 -0
  276. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/relevance_scorer.py +0 -0
  277. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/remedies.py +0 -0
  278. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/rename_refactor.py +0 -0
  279. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/repo_classifier.py +0 -0
  280. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/__init__.py +0 -0
  281. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/context.py +0 -0
  282. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/errors.py +0 -0
  283. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/executor.py +0 -0
  284. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/planner.py +0 -0
  285. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/query.py +0 -0
  286. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/request.py +0 -0
  287. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/resolution.py +0 -0
  288. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/result.py +0 -0
  289. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/retriever.py +0 -0
  290. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/runtime.py +0 -0
  291. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/steps.py +0 -0
  292. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
  293. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/steps_graph.py +0 -0
  294. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/steps_impact.py +0 -0
  295. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/steps_intf.py +0 -0
  296. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/steps_struct.py +0 -0
  297. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/retrieval/steps_txsec.py +0 -0
  298. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/ris.py +0 -0
  299. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/rule_catalog.py +0 -0
  300. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/rule_pass.py +0 -0
  301. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/runs.py +0 -0
  302. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/runtime_classifier.py +0 -0
  303. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/sarif.py +0 -0
  304. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/scanner.py +0 -0
  305. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/schema.py +0 -0
  306. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
  307. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/security_chain.py +0 -0
  308. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/security_config.py +0 -0
  309. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/security_config_scan.py +0 -0
  310. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/security_posture.py +0 -0
  311. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/semantic_analyzer.py +0 -0
  312. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/semantic_impact_engine.py +0 -0
  313. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/semantic_integration_engine.py +0 -0
  314. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/semantic_services.py +0 -0
  315. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/serializer.py +0 -0
  316. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/servlet_surface.py +0 -0
  317. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/source_text.py +0 -0
  318. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/spring_event_topology.py +0 -0
  319. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/spring_findings.py +0 -0
  320. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/spring_impact.py +0 -0
  321. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/spring_model.py +0 -0
  322. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/spring_profiles.py +0 -0
  323. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/spring_properties.py +0 -0
  324. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/spring_security_audit.py +0 -0
  325. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/spring_semantic.py +0 -0
  326. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/spring_tx_analyzer.py +0 -0
  327. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/sql_taint.py +0 -0
  328. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/summarizer.py +0 -0
  329. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/target_admission.py +0 -0
  330. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/telemetry/__init__.py +0 -0
  331. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/telemetry/config.py +0 -0
  332. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/telemetry/consent.py +0 -0
  333. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/telemetry/events.py +0 -0
  334. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/telemetry/filters.py +0 -0
  335. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/telemetry/transport.py +0 -0
  336. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/test_gap_ranking.py +0 -0
  337. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/test_sources.py +0 -0
  338. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/text_input.py +0 -0
  339. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/timeline.py +0 -0
  340. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/token_estimate.py +0 -0
  341. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/tree_utils.py +0 -0
  342. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/type_usage_surface.py +0 -0
  343. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/validation_inference.py +0 -0
  344. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/verify_edit.py +0 -0
  345. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/verify_repo.py +0 -0
  346. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/verify_rules.py +0 -0
  347. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/version_check.py +0 -0
  348. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/waivers.py +0 -0
  349. {sourcecode-5.4.1 → sourcecode-5.5.0}/src/sourcecode/workspace.py +0 -0
  350. {sourcecode-5.4.1 → sourcecode-5.5.0}/supabase/functions/README.md +0 -0
  351. {sourcecode-5.4.1 → sourcecode-5.5.0}/supabase/functions/get-license/index.ts +0 -0
  352. {sourcecode-5.4.1 → sourcecode-5.5.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
  353. {sourcecode-5.4.1 → sourcecode-5.5.0}/supabase/functions/telemetry/index.ts +0 -0
  354. {sourcecode-5.4.1 → sourcecode-5.5.0}/supabase/sql/license_event_ordering.sql +0 -0
  355. {sourcecode-5.4.1 → sourcecode-5.5.0}/supabase/sql/licensing_schema.sql +0 -0
  356. {sourcecode-5.4.1 → sourcecode-5.5.0}/supabase/sql/telemetry_events.sql +0 -0
@@ -2,6 +2,59 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.5.0] — 2026-08-12
6
+
7
+ **Audit backlog resolved and performance signals made explicit.**
8
+ This release folds in the latest external audit queue: programmatic Spring
9
+ validation now contributes to `validation` gaps and confidence, servlet and
10
+ endpoint publishing preserve extension mappings and `ANY` methods, reference
11
+ classification distinguishes class literals from config wires, and the cache
12
+ model now warns about large repositories against the correct scale. The roadmap
13
+ also records the audit backlog, including the command-execution timing
14
+ regression called out in the report.
15
+
16
+ ### Fixed
17
+ - **Programmatic validation is now surfaced.** `Validator` and `@InitBinder`
18
+ evidence now affect `validation` gaps and overall confidence, and the payload
19
+ carries the non-coverage note for that limit.
20
+ - **Servlet extension mappings stay visible.** Patterns such as `*.ftl` and
21
+ `*.vm` are preserved in the servlet surface instead of being dropped.
22
+ - **Methodless request mappings publish as `ANY`.** `@RequestMapping` without a
23
+ declared method is no longer narrowed to `GET`.
24
+ - **Class literals count as references.** `Foo.class` hits now promote the
25
+ type to `referenced` instead of `unknown_framework_dispatch`.
26
+ - **Large-repository cache advice compares against the right scale.** The size
27
+ warning now tells the operator when the repository exceeds the measured
28
+ reference population.
29
+
30
+ ### Documentation
31
+ - Added the external 2026-08-12 audit queue and its performance backlog to the
32
+ roadmap.
33
+
34
+ ## [5.4.2] — 2026-08-12
35
+
36
+ **External audit fixes and roadmap alignment.**
37
+ This release preserves bounded SQL interpolation evidence in composed risk
38
+ payloads, declares the population of existing test counts, and removes routes
39
+ declared only by abstract controller classes. The external audit queue and
40
+ defect ledger are synchronized with the shipped behavior.
41
+
42
+ ### Fixed
43
+ - **Bounded SQL interpolations remain auditable in `risk` and `enrich`.** The
44
+ `sql_taint.bounded_interpolations` rows now survive composition serialization
45
+ beside `sinks_total`.
46
+ - **`existing_test_count` declares its population.** The payload now identifies
47
+ the all-path, multi-language `prepare-context` population and distinguishes it
48
+ from the Java IR test-gap population.
49
+ - **Abstract controller declarations no longer emit phantom routes.** Their
50
+ endpoints remain available for projection onto concrete subtypes, but the
51
+ abstract class itself is not treated as a registered handler bean.
52
+
53
+ ### Documentation
54
+ - Added the external 5.4.2 audit queue and recommended capability work to the
55
+ semantic IR roadmap.
56
+ - Synchronized the distributed defect ledger with the 5.4.1/5.4.2 build state.
57
+
5
58
  ## [5.4.1] — 2026-08-12
6
59
 
7
60
  **Two correctness fixes and a release bump.**
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 5.4.1
3
+ Version: 5.5.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.4.1-blue)
45
+ ![Version](https://img.shields.io/badge/version-5.5.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.4.1 — and, on a build that has aged,
129
+ ask version # ask 5.5.0 — and, on a build that has aged,
130
130
  # how many releases have probably shipped since
131
131
  ```
132
132
 
@@ -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.4.1-blue)
7
+ ![Version](https://img.shields.io/badge/version-5.5.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.4.1 — and, on a build that has aged,
91
+ ask version # ask 5.5.0 — and, on a build that has aged,
92
92
  # how many releases have probably shipped since
93
93
  ```
94
94
 
@@ -59,7 +59,7 @@ The facts these rows are keyed to are published: `ask schema facts-v1` prints th
59
59
  | C1-40 | **`cache model` promises `onboard` an answer-level cache hit and the second run recomputes.** `ask cache model .` publishes `onboard` → *"the answer (repeat cached)"* `[task, ris]`. Measured: first run 56 s (cold, expected), **second run on a warm cache 23,5 s** — not an answer hit, a partial recomputation. Corroborated by `cache context-stats .`: `Contexts: 1 · Hits: 1 · Misses: 1 · Hit ratio: 0.5 · Avg lookup 1029,1 ms (p95 1955,2 ms) · Avg build 18332,5 ms · Bytes stored 9 969 057`. A **full second to decide whether there is a hit**, over a single 10 MB entry, is the signature of deserialising the whole payload to read its key | 4.10.4 (eval #14) | **Medium** — `cache model` exists so a user can plan instead of guess; a row that overstates what a warm buys is the one defect that command cannot afford. The lookup half is the second field measurement of C3-47 | **closed (4.10.6), and the claim was the false half.** Reproduced at home on keycloak (5 486 sources): **with** a `cache warm`, `onboard` costs 0,7 s — the row's promise holds. **Without** one, a second identical run costs 9,4 s against 10,2 s cold: the warm is what stores the answer, and the command does not store its own. The row said `repeat cached`, the field ran it twice with no warm, and got 56 s → 23,5 s. `repeat` is now `false` for `onboard` and the measured figures are published at two scales, with and without a warm, so the reader can tell which run they are about to make. Half (b) shipped too: the validity keys (`ev`/`kl`/`sig`) live in an uncompressed sidecar beside the blob, so deciding *is this entry still valid?* is a small file read instead of decompressing and parsing a 10 MB envelope — the case that matters most, an entry invalidated by a changed signature, used to pay all of it and then discard the result. A genuine hit still pays for the payload it returns; that is the answer, not overhead. Entries written before the sidecar existed fall back to the old full read. Original remedy note: two halves. (a) Reconcile the claim: either `onboard` really caches its answer, or its row says `shared work`, not `the answer`. (b) Split key metadata (hash + validity) from the payload into a sidecar index so a hit is decided without deserialising the blob; target < 5 ms against the ~1 029 ms measured. Related F-AA |
60
60
  | C1-43 | **"Does this repository configure a request filter chain?" has two authorities, and the one that decides whether a `high` finding family runs is the older, weaker one.** `posture._security_config_types` reads the question off the IR's own edges — a type that `extends`/`implements` a chain SPI type, **or a member that `returns` one**, i.e. the `@Bean SecurityFilterChain` shape — and the docstring beside it records why: *"a repository that wires its chain with a `@Bean SecurityFilterChain` and no `@EnableWebSecurity` reported `security.active: 0` — a false zero on the axis this command exists for."* `repository_ir._filter_based`, which decides `security_model` and therefore whether **SEC-001 runs at all**, still tests only `@EnableWebSecurity` (`_FILTER_SECURITY_ANNOTATIONS`, deliberately one entry) and `extends WebSecurityConfigurerAdapter`. A Spring Security 6 repository that declares its chain as a bean is therefore classified `annotation_based`, and SEC-001 then asserts, per unannotated handler, *"In an annotation_based security model there is no centralized filter — any caller can reach this endpoint without authentication"* | 4.18.0 (eval #24) | **High** — a confident falsehood on the strongest axis, and the only one of the series: measured on a greenfield Boot 3 module, the single SEC-001 finding is `POST /api/v1/auth/login`, which the repository's `SecurityConfig` lists in `PUBLIC_ENDPOINTS` with `permitAll()` under a closing `anyRequest().authenticated()` — the chain the model says does not exist both admits that route *and* protects the other 24. The evaluator adjudicated it by reading the source: *"la herramienta lo marca `high` porque solo lee la anotación del método, no la cadena de filtros"* | **in-progress** — the premise half shipped on `fix/sec-001-chain-authority`. One authority, `security_chain`, holds the request-chain SPI vocabulary, the member rule (*a member returning the SPI type makes its declaring class the configuration*) and the name normalisation; `posture` and both `repository_ir` sites read it, so the mechanism can no longer differ. **Two questions are named apart there rather than merged, because only one of them may silence a finding:** `declares_request_chain` (is there a chain at all — the annotation, the pre-5.7 adapter, or a member producing a `SecurityFilterChain`) is SEC-001's premise and is deliberately narrow, while `chain_participant_types` (what takes part in configuring it, filters included) is `posture`'s question. Widening the first to the second would silence SEC-001 on repositories with no centralized authorization — the P1-A failure mode, and the one with no symptom. Measured end-to-end on a fixture of the reported shape: `security_model` `annotation_based` → `mixed`, and the SEC-001 finding on `POST /api/v1/auth/login` disappears; recall asserted in the same battery (no chain → still reported; `@EnableMethodSecurity` alone → still reported). Fleet A/B over 5 repositories × 3 commands: 15/15 payloads identical in content, which is the expected result and the point of running it — no fleet repository declares a chain in either shape, so nothing could move. **Open: the verdict half.** Where the chain resolves, the per-endpoint answer should come from the resolved chain rather than from the model classification (C1-8's `matched_path` machinery already exists), and where it does not resolve, SEC-001 abstains — never *"any caller can reach this endpoint"* over a chain the run did not read |
61
61
  | C1-44 | **`has_uncommitted_changes: false` sits in the same document as `git_context.uncommitted_files: 1`, and it is the field cache freshness is decided on.** `ask <repo> --compact --git-context` publishes both, one run, one payload: `git_context.uncommitted_files` counts the file, `_cache.has_uncommitted_changes` says there is none, and `git status --porcelain` on the same tree prints `?? .claude/settings.json`. The third authority in the build agrees with the first — `--changed-only` reports `changed_files_count: 1` for that file and its `--help` defines the set it counts as *"staged, unstaged, untracked"* — so two of three surfaces admit the file and the one a consumer trusts for staleness does not. Under that published definition the boolean is simply false | 5.3.1 (audit #28) | Medium | **closed 5.4.0** — one predicate (`baseline_autocapture.counts_as_dirty`), extracted from `worktree_dirty` and read by the count in both the fresh path and the cache-hit patch, so the boolean cannot drift from the function that defines it. What it excludes is published (`uncommitted_files_not_read`, `uncommitted_files_basis`) rather than subtracted in silence, and only when something was actually excluded. Original remedy note: one predicate over one definition of *the working set*, read by both fields; the boolean is derived from the count rather than measured a second time, and where the two cannot be derived from one another the document may not publish both |
62
- | C1-46 | **`existing_test_count: 6` sits beside `test_files: 0` and `has_test_sources: false` in one `prepare-context generate-tests` payload, and the 6 are five production files in a business package.** C3-115 closed the half that was reported — `test_gaps` now declares its population — and left a second authority for *"how many tests are there"* answering a different number in the same document. Re-measured in the field: 0 Java tests, 1 `.spec.ts`, 3 karma/jest configs; no population is worth 6. Root cause is in `test_sources.declared_test_root`: `_TEST_DIR_NAMES` carries the bare segment `it`, the final loop accepts it **at any depth**, and the only disarm — `_under_main_root` — knows `src/main` alone, which is a Maven layout. An Angular app lives under `src/app`, so `saint-client/src/app/shared/akita/it/` — *Incapacidad Temporal*, a business entity whose `it.model.ts` declares `ENFERMEDAD COMÚN` and `ACCIDENTE DE TRABAJO` — is read as a test source root and contributes 5 files; the 6th is the one real `.spec.ts`, and the reconciliation is exact. **It generalizes off this repository:** `it` is also the ISO 639-1 code for Italian, so `web/src/assets/i18n/it/messages.json` and `app/locales/it/common.ts` both answer `is_test_path: true` on the shipped build. Sibling of C1-28, in the direction C1-28 was written to prevent | 5.4.0 (audit #29) | **Medium** — the number is small and the shape is the one the maintenance rule exists for: an authority closed on a narrower restatement than the one reported | **open** |
62
+ | C1-46 | **`existing_test_count: 6` sits beside `test_files: 0` and `has_test_sources: false` in one `prepare-context generate-tests` payload, and the 6 are five production files in a business package.** C3-115 closed the half that was reported — `test_gaps` now declares its population — and left a second authority for *"how many tests are there"* answering a different number in the same document. Re-measured in the field: 0 Java tests, 1 `.spec.ts`, 3 karma/jest configs; no population is worth 6. Root cause is in `test_sources.declared_test_root`: `_TEST_DIR_NAMES` carries the bare segment `it`, the final loop accepts it **at any depth**, and the only disarm — `_under_main_root` — knows `src/main` alone, which is a Maven layout. An Angular app lives under `src/app`, so `saint-client/src/app/shared/akita/it/` — *Incapacidad Temporal*, a business entity whose `it.model.ts` declares `ENFERMEDAD COMÚN` and `ACCIDENTE DE TRABAJO` — is read as a test source root and contributes 5 files; the 6th is the one real `.spec.ts`, and the reconciliation is exact. **It generalizes off this repository:** `it` is also the ISO 639-1 code for Italian, so `web/src/assets/i18n/it/messages.json` and `app/locales/it/common.ts` both answer `is_test_path: true` on the shipped build. Sibling of C1-28, in the direction C1-28 was written to prevent | 5.4.0 (audit #29) | **Medium** — the path-classification half is closed in 5.4.1; `existing_test_count_unit` now declares its all-path, multi-language task population in 5.4.2, distinct from the Java IR population | **closed 5.4.2** |
63
63
  | C1-45 | **The SQL taint join keys a sink on a bare statement id, so a mapper method in one namespace is joined to a call site that resolves to another — and the result is published as the repository's #1 critical risk with a call trace that does not exist.** `risk`'s top row on a 3 342-file monolith is `severity_effective: 29.57` at `ProcesosGerenciaMapper.xml:74`, `factors.query_construction = http_input_reaches_sql_interpolation`, with evidence naming `AutocoberturasRestController#actualizar(id, obj)` *calls* `actualizar(…)` in `ProcesosGerenciaMapper`. The controller calls its own service's `actualizar`; the join matched on the method name alone. **The correct key already exists in the code and is not used** — `sql_taint` line 76 returns `f"{self.namespace}#{self.statement_id}" if self.namespace else self.statement_id`, and `namespace` is captured (141, 151) and then spent only on an explanatory sentence (313-314), while the published basis claims the sinks are *"keyed by namespace and statement id"*. **Accompanying defect, same row:** the interpolated expression is stored (72, 144) and emitted (86) and never inspected, so `bloqueada = ${dto.bloqueada ? "'S'" : "'N'"}` — an OGNL ternary whose two branches are string literals, a closed allowlist by construction and precisely the mitigation SEC-008's own `fix_hint` recommends — is ranked as a text-controllable sink | 5.3.1 (audit #28) | **High** — F-BF's whole argument is that this axis fires on evidence rather than on multiplication by 1,0; a name-collision join inverts the first row of the ranking, which is the product | **closed 5.4.0** — both sides keyed on `namespace#statement_id`: a call carries the type its receiver resolves to and is that statement's only when the receiver resolves to the mapper it lives in; an unresolved receiver is not the same answer as any type name, so the sink stays `undecidable` rather than `reaches`. `does_not_reach` carries the same qualification, because it is a confident no. `splices_free_text` reads the interpolation at last — anything it cannot prove closed is free text, and what it closes leaves the population into a published `bounded_interpolations` list. The regression fixture this row specified is in the suite. Original remedy note: key both sides on `namespace#statement_id` (the property is already written, the call sites read the wrong half), and give the interpolation a three-state read: an expression whose reachable values are all literals is `does_not_reach`, an unresolvable one stays `undecidable`, never `reaches` by default. Regression fixture: two mappers in different namespaces sharing a `statement_id`, one reached by HTTP input and one not — expected one `reaches`, one `undecidable`; today, two `reaches` |
64
64
 
65
65
 
@@ -231,8 +231,8 @@ The facts these rows are keyed to are published: `ask schema facts-v1` prints th
231
231
  | C3-120 | **The composition engine became unusable at 3 342 files, and one line of C1-45's fix is why.** Measured against 5.3.1 artefacts on the same subject: `risk` 38,37 s → **601,74 s** under a 300 s budget, returning `partial: true` with **0 of 98** defects composed; `risk` under a 3 000 s budget → 444 s complete (×11,6); `enrich` 36,30 s → **>600 s**, stopped without completing; `audit-report` not run at all after two hangs. Median ratio over 48 comparable pairs is **1,00x** — the regression is confined to this family. Root cause is `sql_taint._receiver_type`: `_RECEIVER_RE` is anchored `…\s*$` and is applied as `search(method.body[:body_index])`, which copies an O(body_index) prefix **and** makes the regex engine try every start position in it before concluding. `_called_names` pays that for **every call of every method in the repository**, unfiltered and unbounded, where 5.3.1 did `names.add(call.group(1))` at O(1); a service body of 1 650+ lines makes the pass quadratic. Auditor's microbenchmark on the shipped regex, results byte-identical to a windowed `search(body, start, endpos)`: 8,6 KB/200 calls **36,9×**, 43 KB/1 000 calls **186,9×**, 215 KB/5 000 calls **916,5×** — 5× the calls, 25× the time | 5.4.0 (audit #29) | **Critical** — three of the seven experimental commands, and the ones that carry the price premium, do not return on the repository this product is sold for | **closed 5.4.1** — the read is windowed (`search(body, start, body_index)`: the `$` still ends at the call, no prefix is copied and the engine is offered a bounded number of start positions), and the window start retreats over any identifier it lands inside so a receiver wider than 128 characters is resolved whole rather than by its suffix — `""` is *unresolved* here and must never be reached by truncation. Second half: `_called_names` takes the statement ids being decided as its scope, because the only question asked of that set is `(mapper, statement id) in called`, so a name no statement carries can change no verdict. Re-measured on the shipped regex: 5 000 calls over a 159 KB body, **18 079 ms → 28 ms**, results identical at every call site. Four regression assertions, including a wall-clock gate on the pass |
232
232
  | C3-121 | **The budget does not bind in the composition family, and one invocation froze the process.** `ASK_MAX_ANALYSIS_SECONDS=300 ask risk .` ran **601,74 s** of wall clock and wrote `elapsed_seconds: 600.92` into its own `_partial`; `ASK_MAX_ANALYSIS_SECONDS=150 ask enrich . --sarif` passed 600 s and was stopped by hand; a third `risk` invocation stopped responding until the working session was killed. This is the failure mode C3-82/C3-118 closed for `generate-tests` — *the budget must be checked where the walk can be cut, not only between phases* — reappearing in another family, and the lesson did not travel. Second half, independent of the overrun: a **respected** budget yields no answer — at 300 s the payload is `phases_completed: ["audit"]`, `phases_pending: ["compose"]`, `composition_stopped_after.defects_composed: 0`, which in CI is an empty envelope after ten minutes. The degradation shape itself is exemplary and is not what this row is against: `_partial` names the completed and pending phases, `why_stopped`, the repo-wide walks it skipped and the axes left `unknown`. ⚠ Re-measure after C3-120 before investigating separately — same subsystem, same triage C3-114 got against E-3 | 5.4.0 (audit #29) | **High** — a budget that does not cut is worse than no budget: it sells CI a guarantee it does not keep, and a hard freeze consumes the runner | **closed 5.4.1** — the deadline is asked *inside* the two repository-wide walks that hold the wall time, not only at their doors: the method parse samples the clock every 16 files and the two propagation walks sample it on their own units. A walk cut while running raises rather than returning what it had — every verdict these walks publish below `reaches` is a statement about the **whole** repository, and a negative over a partial universe is a confident no built on an unfinished read — so the measurement is dropped, the axis reads `unknown`, and the walk is named in `_partial.composition_walks_not_run` exactly as a walk that never started is. Nothing partial is cached on the CIR, so a later caller cannot be served a repository with files missing. Two assertions, both non-vacuous: the walk cut inside, and the composer naming it. ⚠ The residue this row does not close: the walks that are still gated only at the door (`inferring the security posture`, `indexing the validation surface`, `resolving the conditional bean graph`) — none of them was measured holding the overrun, and giving each a sampling seam is its own increment |
233
233
  | C3-122 | **`ask risk <repo> -o <path>` spent 444 s, exited 0, printed nothing and wrote no file.** One occurrence, from bash with a Windows path in forward slashes; a later recursive search found the file nowhere in the user tree. The same path shapes worked in the same session for `ask endpoints -o`, `ask config` and `ask baseline capture --dir`. Not reproduced — the auditor stopped invoking `risk` after the freeze in C3-121 — and recorded with that limitation. An analysis command that consumes 444 s and reports success without producing its output owes the reader a line on stderr at minimum | 5.4.0 (audit #29) | **Low** (unreproduced) — but it is a C5 shape: the exit code is the published fact and it is wrong | **open** |
234
- | C3-123 | **A static asset reaches `broken_integrations`, the one verdict this command presents as unconditional.** C3-119 did the main work — 19 → 1, with 14 relocated to `partial_client_calls` and the `meaning` stating its condition. The survivor is `GET /assets/i18n/{}.json` from `transloco-root.module.ts:18`: a translation bundle served by the container, not a Spring route. True under the published definition and not a broken integration in any sense a reader means. Remedy: exclude paths under known asset roots (`/assets/`, `/static/`, `/public/`) or ending in a static file extension, and say so in the `meaning` | 5.4.0 (audit #29) | **Low** | **open** |
235
- | C3-124 | **`risk` renamed three published keys inside a minor with no alias.** 5.3.1 emitted `total_defects`, `total_findings` and `risks_cap`; 5.4.0 emits `total_defects_floor`, `total_findings_floor` (plus `counts_basis`, `counts_are_floor`, `partial`, `_partial`) and dropped `risks_cap`. Permitted by the command's own experimental tier — *shape may change in a minor* — and the new names are better; the payload still carries no notice, so a consumer bound to the old keys reads `None` with nothing telling it why. `auth status` already publishes a `deprecated_fields` block: the channel exists and this command did not use it | 5.4.0 (audit #29) | **Informative** | **open** |
234
+ | C3-123 | **A static asset reaches `broken_integrations`, the one verdict this command presents as unconditional.** C3-119 did the main work — 19 → 1, with 14 relocated to `partial_client_calls` and the `meaning` stating its condition. The survivor is `GET /assets/i18n/{}.json` from `transloco-root.module.ts:18`: a translation bundle served by the container, not a Spring route. True under the published definition and not a broken integration in any sense a reader means. Remedy: exclude paths under known asset roots (`/assets/`, `/static/`, `/public/`) or ending in a static file extension, and say so in the `meaning` | 5.4.0 (audit #29) | **Low** | **closed 5.4.1** — static asset roots and file extensions are excluded and the meaning names the exclusion |
235
+ | C3-124 | **`risk` renamed three published keys inside a minor with no alias.** 5.3.1 emitted `total_defects`, `total_findings` and `risks_cap`; 5.4.0 emits `total_defects_floor`, `total_findings_floor` (plus `counts_basis`, `counts_are_floor`, `partial`, `_partial`) and dropped `risks_cap`. Permitted by the command's own experimental tier — *shape may change in a minor* — and the new names are better; the payload still carries no notice, so a consumer bound to the old keys reads `None` with nothing telling it why. `auth status` already publishes a `deprecated_fields` block: the channel exists and this command did not use it | 5.4.0 (audit #29) | **Informative** | **closed 5.4.1 as not a defect** — a complete 5.4.1 run retains the legacy keys; the renamed floor fields are emitted only for budget-cut payloads and are explicitly marked as floors |
236
236
 
237
237
  ## Class C4 — Discoverability (the ceiling as of 3.2.0)
238
238
 
@@ -136,7 +136,7 @@ pipx install sourcecode # isolated install, no venv needed
136
136
 
137
137
  # Verify
138
138
  ask version
139
- # ask 5.4.1
139
+ # ask 5.5.0
140
140
  ```
141
141
 
142
142
  Requires Python 3.9+.
@@ -297,3 +297,43 @@ milestone; hash-neutral; suite green.
297
297
  > completion), then `integration_detector` migration (Move 3). Both are named here
298
298
  > only to show the arc — neither is begun until P6.0's evidence is in hand and the
299
299
  > user selects it.
300
+
301
+ ---
302
+
303
+ ## Part V — External re-audit queue (5.4.1 → 5.4.2)
304
+
305
+ The latest external re-audit was run against the installed `5.4.1` build using
306
+ the same read-only harness and repository as the previous rounds. This section
307
+ records only findings that are not already represented elsewhere in this
308
+ roadmap; previously closed findings remain historical evidence, not duplicate
309
+ work items.
310
+
311
+ ### Bugs to fix
312
+
313
+ | ID | Finding | Severity | Resolution / acceptance criterion |
314
+ |----|---------|----------|------------------------------------|
315
+ | D-01 | `risk` drops `bounded_interpolations` while serializing the `sql_taint` block, so `sinks_total` is not auditable. | Medium | Preserve the bounded rows in the published payload. A fixture with one bounded and one free interpolation must report `sinks_total == 1` and one `bounded_interpolations` entry in both `risk` and `enrich`. |
316
+ | D-02 | `existing_test_count` has no population/unit declaration and is confused with the IR's `test_gap_ranking.population.test_files`. | Medium | Publish an explicit unit naming the all-paths, multi-language task population, or remove the redundant field. The chosen authority must be covered end to end. |
317
+ | D-03 | Route projection emits endpoints declared by abstract controller classes, creating phantom routes and inflating the unprotected census. | Low | Carry class modifiers into route-surface metadata and exclude abstract declarers from emitted routes; concrete subtype projection remains unchanged. |
318
+ | D-04 | The distributed defect ledger can claim `C3-123` is open although the `5.4.1` build already excludes static assets. | Informational | Synchronize ledger status with the shipped build and close the stale row. Documentation artifacts must describe the wheel they accompany. |
319
+ | D-05 | `risk -o` once exited successfully without writing a file; the four current invocations did write correctly. | Unreproduced | Keep as an observation only. Do not implement or mark it closed without a reproducible fixture. |
320
+
321
+ The audit explicitly retracted the apparent `N-01` global performance regression
322
+ after cache-settled, consecutive measurements, and retracted `REG-07` schema
323
+ breakage after a complete run preserved the legacy keys. Neither is a bug queue
324
+ item. The already closed `REG-01` through `REG-06` findings are likewise not
325
+ reopened here.
326
+
327
+ ### Recommended capabilities and engineering work
328
+
329
+ These are recommendations from the audit, not fixes to mix into the bug commits:
330
+
331
+ | Item | Recommendation | Product rationale |
332
+ |------|----------------|-------------------|
333
+ | Performance budget gate | Add a release-time assertion for IR construction and keep comparable cold/warm measurements. | Two consecutive releases had performance concerns before the cache-settled protocol separated real regressions from first-build cost. |
334
+ | Cache measurement protocol | Require an established cache and two concordant runs before publishing a performance claim; retain cold/warm values separately. | A single measurement inside a warming batch is not a stable comparison. |
335
+ | CLI grammar closure | Finish the unresolved CLI grammar/command-surface work tracked by `C4-25`. | The audit still identifies inconsistent or incomplete command syntax as an open usability risk. |
336
+
337
+ The existing P6.0 semantic-IR milestone is intentionally not repeated here;
338
+ its class-level type usage and semantic impact work remains the roadmap's
339
+ architectural feature track.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "5.4.1"
7
+ version = "5.5.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.4.1"
7
+ __version__ = "5.5.0"
@@ -492,6 +492,7 @@ class Conditioning:
492
492
  scope: str # "3 342 Java files, cache cold"
493
493
  transfers: "Optional[bool]" # do the reference figures apply here?
494
494
  per_command: "dict[str, str]" # command → how it can be run here
495
+ java_files: "Optional[int]" = None # measured scope size, if available
495
496
 
496
497
  def statement(self) -> str:
497
498
  """One sentence about whether the figures below transfer to this scope."""
@@ -500,6 +501,14 @@ class Conditioning:
500
501
  f"This repository ({self.scope}) was not measured, so nothing below "
501
502
  f"is claimed about it: the figures are the reference repository's."
502
503
  )
504
+ if self.java_files is not None and self.java_files > REFERENCE_JAVA_FILES:
505
+ return (
506
+ f"This repository ({self.scope}) is larger than the repository the "
507
+ f"figures below were measured on ({REFERENCE_JAVA_FILES} Java files), "
508
+ f"and what cost tracks here is the build rather than the file count: "
509
+ f"{FIELD_ANCHOR}. Read each figure as the reference's, not as yours; "
510
+ f"the `here:` lines say how each command can be run on this one."
511
+ )
503
512
  if self.transfers:
504
513
  return (
505
514
  f"This repository ({self.scope}) is within the size the figures "
@@ -27,6 +27,7 @@ from sourcecode.phased_run import PhasedRun
27
27
  from sourcecode.partial_contract import PARTIAL_EXIT_CODE as _PARTIAL_EXIT
28
28
  from sourcecode.partial_contract import read_count as _read_count
29
29
  from sourcecode import perf
30
+ from sourcecode.non_coverage import block as _non_coverage_block
30
31
  from sourcecode.caller_metrics import (
31
32
  CALLER_METRIC_RECONCILIATION,
32
33
  CYCLE_METRIC_RECONCILIATION,
@@ -5461,6 +5462,12 @@ def prepare_context_cmd(
5461
5462
  _et_count = getattr(output, "existing_test_count", None)
5462
5463
  if _et_count is not None:
5463
5464
  out["existing_test_count"] = _et_count
5465
+ out["existing_test_count_unit"] = (
5466
+ "test source files present in the complete prepare-context path "
5467
+ "universe, across all detected languages; this is a task-scope "
5468
+ "count and is not the Java IR population in "
5469
+ "`test_gap_ranking.population.test_files`"
5470
+ )
5464
5471
  # C3-13: the basis of the ranked list travels with it — emitted even when the
5465
5472
  # list is empty, because "no gaps" and "no measurement" are different answers.
5466
5473
  if task == "generate-tests":
@@ -7281,6 +7288,23 @@ def validation_cmd(
7281
7288
  except Exception:
7282
7289
  pass
7283
7290
 
7291
+ if data.get("programmatic_validation", {}).get("detected"):
7292
+ data.setdefault("non_coverage", _non_coverage_block("validation"))
7293
+ _vc = data.get("validation_confidence")
7294
+ if isinstance(_vc, dict):
7295
+ _vc["overall"] = "Likely"
7296
+ _vc["claim"] = (
7297
+ "Declared constraints are present, but programmatic Spring "
7298
+ "Validator wiring was detected outside this surface's model"
7299
+ )
7300
+ limits = _vc.setdefault("known_precision_limits", [])
7301
+ note = (
7302
+ "Programmatic Spring Validator / @InitBinder wiring is outside the "
7303
+ "declared-constraint surface."
7304
+ )
7305
+ if note not in limits:
7306
+ limits.append(note)
7307
+
7284
7308
  if path_prefix:
7285
7309
  data["endpoints"] = [
7286
7310
  e for e in data.get("endpoints", [])
@@ -14381,7 +14405,8 @@ def _cache_model_conditioning(path: Path) -> Any:
14381
14405
  line += f" ({found.reference})"
14382
14406
  per_command[row.command] = line
14383
14407
  return _cmodel.Conditioning(
14384
- scope=scope.describe(), transfers=transfers, per_command=per_command
14408
+ scope=scope.describe(), transfers=transfers, per_command=per_command,
14409
+ java_files=scope.java_files,
14385
14410
  )
14386
14411
  except Exception:
14387
14412
  # A cost note is never worth failing a command that answers.
@@ -321,6 +321,27 @@ NON_COVERAGE: tuple[NonCoverage, ...] = (
321
321
  "routes) is a measurement this command does not yet make."
322
322
  ),
323
323
  ),
324
+ NonCoverage(
325
+ id="NC-011",
326
+ surface="validation",
327
+ not_covered=(
328
+ "Programmatic Spring request-body validation wired with "
329
+ "`org.springframework.validation.Validator` or `@InitBinder`."
330
+ ),
331
+ why=(
332
+ "This surface reads declared bean-validation constraints recovered from "
333
+ "OpenAPI or DTO annotations. A validator registered in controller code "
334
+ "can enforce body rules without any declarative constraint on the "
335
+ "payload, so treating the result as fully verified would overstate what "
336
+ "the declared-constraint scan proves."
337
+ ),
338
+ instead=(
339
+ "`@InitBinder` / `setValidator(...)` wiring, or a Spring `Validator` "
340
+ "implementation, which this surface reports only as a coverage "
341
+ "boundary. `validation` still shows the declared rules; the programmatic "
342
+ "validator remains outside that model."
343
+ ),
344
+ ),
324
345
  )
325
346
 
326
347
 
@@ -162,7 +162,7 @@ _QUALIFIED_TYPE_RE = re.compile(r"\b[A-Z][A-Za-z0-9_$]*\.[A-Z][A-Za-z0-9_$]*")
162
162
 
163
163
  def _scan_repository(
164
164
  root: Path, simple_names: "set[str]", nested: "dict[str, tuple[str, str]]"
165
- ) -> "tuple[dict[str, str], dict[str, str]]":
165
+ ) -> "tuple[dict[str, str], dict[str, str], dict[str, str]]":
166
166
  """One walk, two questions — `(config-wired names, nested types other code names)`.
167
167
 
168
168
  Both scans need the whole tree, and walking it twice doubled the cost of the
@@ -175,6 +175,7 @@ def _scan_repository(
175
175
  """
176
176
  config_hits: dict[str, str] = {}
177
177
  nested_hits: dict[str, str] = {}
178
+ literal_hits: dict[str, str] = {}
178
179
  pending = set(simple_names)
179
180
  by_qualified: dict[str, list[str]] = {}
180
181
  for fqn, (qualified, _own) in nested.items():
@@ -183,7 +184,7 @@ def _scan_repository(
183
184
  scan_config = bool(pending)
184
185
  scan_java = bool(by_qualified)
185
186
  if not scan_config and not scan_java:
186
- return config_hits, nested_hits
187
+ return config_hits, nested_hits, literal_hits
187
188
 
188
189
  scanned = 0
189
190
  for dirpath, dirnames, filenames in os.walk(root):
@@ -191,7 +192,7 @@ def _scan_repository(
191
192
  for filename in filenames:
192
193
  is_java = filename.endswith(".java")
193
194
  is_config = os.path.splitext(filename)[1].lower() in _CONFIG_REF_EXTS
194
- if not ((is_java and scan_java) or (is_config and scan_config)):
195
+ if not ((is_java and (scan_java or scan_config)) or (is_config and scan_config)):
195
196
  continue
196
197
  if scanned >= _SCAN_MAX_FILES:
197
198
  break
@@ -206,6 +207,17 @@ def _scan_repository(
206
207
  pending.discard(hit)
207
208
  config_hits[hit] = rel
208
209
  scan_config = bool(pending)
210
+ if is_java and scan_config:
211
+ # A `Foo.class` literal is a real static reference, and the
212
+ # field audit found one of these on the annotation-dispatch path.
213
+ class_hits = {
214
+ hit for hit in pending
215
+ if f"{hit}.class" in text
216
+ }
217
+ for hit in class_hits:
218
+ pending.discard(hit)
219
+ literal_hits[hit] = rel
220
+ scan_config = bool(pending)
209
221
  if is_java and scan_java:
210
222
  for hit in set(_QUALIFIED_TYPE_RE.findall(text)) & set(by_qualified):
211
223
  for fqn in by_qualified[hit]:
@@ -213,10 +225,10 @@ def _scan_repository(
213
225
  nested_hits[fqn] = rel
214
226
  scan_java = len(nested_hits) < len(nested)
215
227
  if not scan_config and not scan_java:
216
- return config_hits, nested_hits
228
+ return config_hits, nested_hits, literal_hits
217
229
  if scanned >= _SCAN_MAX_FILES:
218
230
  break
219
- return config_hits, nested_hits
231
+ return config_hits, nested_hits, literal_hits
220
232
 
221
233
 
222
234
  def analyze_type_references(nodes: "list[dict]", root: Path) -> ReferenceFacts:
@@ -226,7 +238,15 @@ def analyze_type_references(nodes: "list[dict]", root: Path) -> ReferenceFacts:
226
238
  examined, because a method with no callers is a different question.
227
239
  """
228
240
  root = Path(root)
229
- types = [n for n in nodes or [] if n.get("type") in ("class", "interface") and n.get("fqn")]
241
+ def _node_kind(node: dict) -> str:
242
+ kind = str(node.get("symbol_kind") or node.get("kind") or node.get("type") or "")
243
+ if kind in ("class", "interface", "enum", "annotation", "record"):
244
+ return kind
245
+ if kind == "@interface":
246
+ return "annotation"
247
+ return str(node.get("type") or "")
248
+
249
+ types = [n for n in nodes or [] if _node_kind(n) in ("class", "interface", "enum", "annotation", "record") and n.get("fqn")]
230
250
  if not types:
231
251
  return ReferenceFacts(0, {s: 0 for s in STATUSES}, ())
232
252
 
@@ -237,7 +257,7 @@ def analyze_type_references(nodes: "list[dict]", root: Path) -> ReferenceFacts:
237
257
  entries.append(TypeReference(
238
258
  fqn=str(node["fqn"]), status=REFERENCED,
239
259
  basis="incoming edge in the call-graph",
240
- type=str(node.get("type") or ""), role=str(node.get("role") or "other"),
260
+ type=_node_kind(node), role=str(node.get("role") or "other"),
241
261
  ))
242
262
  else:
243
263
  candidates.append(node)
@@ -271,22 +291,30 @@ def analyze_type_references(nodes: "list[dict]", root: Path) -> ReferenceFacts:
271
291
  f"{parts[-2]}.{parts[-1]}",
272
292
  str(node.get("source_file") or "").replace("\\", "/"),
273
293
  )
274
- config_hits, nested_hits = _scan_repository(root, set(by_simple), nested_candidates)
294
+ config_hits, nested_hits, literal_hits = _scan_repository(root, set(by_simple), nested_candidates)
295
+ literal_refs: dict[str, str] = {}
275
296
  for simple, config_file in config_hits.items():
276
297
  for node in by_simple.get(simple, []):
277
298
  dispatch_basis[str(node["fqn"])] = f"named in {config_file}"
299
+ for simple, literal_file in literal_hits.items():
300
+ for node in by_simple.get(simple, []):
301
+ literal_refs[str(node["fqn"])] = literal_file
278
302
 
279
303
  for node in candidates:
280
304
  fqn = str(node["fqn"])
281
305
  common = {
282
306
  "fqn": fqn,
283
- "type": str(node.get("type") or ""),
307
+ "type": _node_kind(node),
284
308
  "role": str(node.get("role") or "other"),
285
309
  }
286
- if fqn in nested_hits:
310
+ if fqn in nested_hits or fqn in literal_refs:
287
311
  entries.append(TypeReference(
288
312
  status=REFERENCED,
289
- basis=f"named as a qualified nested type in {nested_hits[fqn]}",
313
+ basis=(
314
+ f"named as a qualified nested type in {nested_hits[fqn]}"
315
+ if fqn in nested_hits
316
+ else f"referenced by a class literal in {literal_refs[fqn]}"
317
+ ),
290
318
  **common,
291
319
  ))
292
320
  elif fqn in dispatch_basis:
@@ -3778,7 +3778,11 @@ def _parse_route_http_method(ann_name: str, args_str: str) -> str:
3778
3778
  if explicit:
3779
3779
  return explicit
3780
3780
  m = re.search(r'method\s*=\s*(?:RequestMethod\.)?(\w+)', args_str or "")
3781
- return m.group(1).upper() if m else ""
3781
+ if m:
3782
+ return m.group(1).upper()
3783
+ if ann_name == "@RequestMapping":
3784
+ return "ANY"
3785
+ return ""
3782
3786
 
3783
3787
 
3784
3788
  def _parse_route_extras(args_str: str) -> dict:
@@ -4959,6 +4963,7 @@ def _build_route_surface(
4959
4963
  "fqn": sym.symbol,
4960
4964
  "prefixes": prefixes,
4961
4965
  "own_endpoints": [],
4966
+ "abstract": "abstract" in (sym.modifiers or []),
4962
4967
  "has_path_ann": "@Path" in sym.annotations or "@RequestMapping" in sym.annotations,
4963
4968
  }
4964
4969
 
@@ -5016,6 +5021,12 @@ def _build_route_surface(
5016
5021
  (method, suffix, sym.symbol, sym.stable_id)
5017
5022
  )
5018
5023
 
5024
+ # Abstract controllers contribute declarations for concrete subtype
5025
+ # projection, but Spring does not register the abstract class itself as
5026
+ # a handler bean.
5027
+ if class_info.get(cls_simple, {}).get("abstract"):
5028
+ continue
5029
+
5019
5030
  # P1 FIX: extract security annotations (method-level first, class fallback)
5020
5031
  _cls_sym_for_sec = class_sym_by_simple.get(cls_simple)
5021
5032
  _sec = _route_security_from_sym(sym, _cls_sym_for_sec, custom_security)
@@ -1555,7 +1555,8 @@ def _assemble_payload(
1555
1555
  payload["sql_taint"] = {
1556
1556
  key: _taint[key]
1557
1557
  for key in ("schema_version", "answered", "sinks_total", "summary",
1558
- "statement", "verdict_lattice", "basis")
1558
+ "statement", "verdict_lattice", "basis",
1559
+ "bounded_interpolations")
1559
1560
  if key in _taint
1560
1561
  }
1561
1562
  # F-AY: three of this command's six axes are Spring-shaped (access, the
@@ -34,6 +34,7 @@ from pathlib import Path
34
34
  from typing import TYPE_CHECKING, Any, Optional
35
35
 
36
36
  from sourcecode.path_filters import is_test_path
37
+ from sourcecode.non_coverage import block as non_coverage_block
37
38
 
38
39
  if TYPE_CHECKING:
39
40
  from sourcecode.context_graph import ContextGraph
@@ -471,6 +472,47 @@ def _is_body_endpoint(ep: "dict[str, Any]") -> bool:
471
472
  return method in ("POST", "PUT", "PATCH")
472
473
 
473
474
 
475
+ def _programmatic_validation_signals(graph: "ContextGraph") -> "list[str]":
476
+ """Presence-only evidence for Spring Validator / InitBinder wiring.
477
+
478
+ The validation surface does not model these flows, but the command still
479
+ needs to say when a repo is using them so the declared-constraint summary is
480
+ not read as a full proof."""
481
+ evidence: list[str] = []
482
+
483
+ for t in graph.types():
484
+ if _is_excluded(t.source_file):
485
+ continue
486
+ sig = (t.signature or "")
487
+ if "org.springframework.validation.Validator" not in sig:
488
+ continue
489
+ if "ConstraintValidator" in sig:
490
+ continue
491
+ evidence.append(f"{t.fqn} implements org.springframework.validation.Validator")
492
+
493
+ for m in graph.symbols(kind="method"):
494
+ if _is_excluded(m.source_file):
495
+ continue
496
+ if m.has_annotation("InitBinder"):
497
+ evidence.append(f"{m.fqn} is annotated with @InitBinder")
498
+
499
+ if evidence:
500
+ return sorted(dict.fromkeys(evidence))
501
+
502
+ try:
503
+ for edge in graph.cir.call_graph:
504
+ target = str(edge.get("to") or edge.get("to_symbol") or "")
505
+ if target.endswith("setValidator"):
506
+ source = str(edge.get("from") or edge.get("from_symbol") or "")
507
+ if source:
508
+ evidence.append(f"{source} calls {target}")
509
+ break
510
+ except Exception:
511
+ pass
512
+
513
+ return sorted(dict.fromkeys(evidence))
514
+
515
+
474
516
  def build_validation_surface(
475
517
  root: Path,
476
518
  endpoints_data: "Optional[dict[str, Any]]" = None,
@@ -494,6 +536,7 @@ def build_validation_surface(
494
536
  graph = _build_graph(root)
495
537
 
496
538
  catalog = discover_custom_validators(root, graph)
539
+ programmatic_evidence = _programmatic_validation_signals(graph)
497
540
 
498
541
  out_endpoints: "list[dict[str, Any]]" = []
499
542
  gaps: "list[dict[str, Any]]" = []
@@ -579,6 +622,11 @@ def build_validation_surface(
579
622
  "gaps": len(gaps),
580
623
  },
581
624
  }
625
+ if programmatic_evidence:
626
+ result["programmatic_validation"] = {
627
+ "detected": True,
628
+ "evidence": programmatic_evidence,
629
+ }
582
630
  spec_path = endpoints_data.get("openapi_spec")
583
631
  if spec_path:
584
632
  result["openapi_spec"] = spec_path
@@ -661,7 +709,48 @@ def build_validation_surface(
661
709
  "expected for such repos, not a missing-validation finding."
662
710
  )
663
711
 
712
+ if programmatic_evidence:
713
+ result["non_coverage"] = non_coverage_block("validation")
714
+ result["note"] = (
715
+ result.get("note", "")
716
+ + " Programmatic Spring Validator wiring was detected, which is "
717
+ "outside the declared-constraint surface this command models."
718
+ ).strip()
719
+ if not result.get("gaps"):
720
+ result["gaps"] = [
721
+ {
722
+ "method": "",
723
+ "path": "",
724
+ "controller": "",
725
+ "reason": "programmatic_validator_wiring_unmodeled",
726
+ "basis": "programmatic_validation",
727
+ "confidence": "Likely",
728
+ }
729
+ ]
730
+ result["summary"]["gaps"] = 1
731
+
664
732
  _reconcile_with_code_axis(result, graph, root)
733
+ if programmatic_evidence:
734
+ result["non_coverage"] = non_coverage_block("validation")
735
+ note = result.get("note", "")
736
+ programmatic_note = (
737
+ " Programmatic Spring Validator wiring was detected, which is "
738
+ "outside the declared-constraint surface this command models."
739
+ )
740
+ if programmatic_note.strip() not in note:
741
+ result["note"] = (note + programmatic_note).strip()
742
+ if not result.get("gaps"):
743
+ result["gaps"] = [
744
+ {
745
+ "method": "",
746
+ "path": "",
747
+ "controller": "",
748
+ "reason": "programmatic_validator_wiring_unmodeled",
749
+ "basis": "programmatic_validation",
750
+ "confidence": "Likely",
751
+ }
752
+ ]
753
+ result["summary"]["gaps"] = 1
665
754
  return result
666
755
 
667
756