sourcecode 5.0.1__tar.gz → 5.1.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 (235) hide show
  1. {sourcecode-5.0.1 → sourcecode-5.1.0}/.github/workflows/perf-gate.yml +2 -2
  2. {sourcecode-5.0.1 → sourcecode-5.1.0}/CHANGELOG.md +95 -0
  3. {sourcecode-5.0.1 → sourcecode-5.1.0}/PKG-INFO +3 -3
  4. {sourcecode-5.0.1 → sourcecode-5.1.0}/README.md +2 -2
  5. {sourcecode-5.0.1 → sourcecode-5.1.0}/pyproject.toml +1 -1
  6. {sourcecode-5.0.1 → sourcecode-5.1.0}/scripts/perf_gate.py +4 -0
  7. sourcecode-5.1.0/scripts/sync_gate_anchors.py +144 -0
  8. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/__init__.py +1 -1
  9. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/cache_model.py +120 -0
  10. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/cli.py +291 -37
  11. sourcecode-5.1.0/src/sourcecode/gate_anchors.py +42 -0
  12. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/parse_cache.py +43 -0
  13. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/perf.py +66 -11
  14. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/verify_edit.py +77 -16
  15. {sourcecode-5.0.1 → sourcecode-5.1.0}/.github/workflows/build-windows.yml +0 -0
  16. {sourcecode-5.0.1 → sourcecode-5.1.0}/.gitignore +0 -0
  17. {sourcecode-5.0.1 → sourcecode-5.1.0}/.ruff.toml +0 -0
  18. {sourcecode-5.0.1 → sourcecode-5.1.0}/CLAUDE.md +0 -0
  19. {sourcecode-5.0.1 → sourcecode-5.1.0}/CONTRIBUTING.md +0 -0
  20. {sourcecode-5.0.1 → sourcecode-5.1.0}/LICENSE +0 -0
  21. {sourcecode-5.0.1 → sourcecode-5.1.0}/SECURITY.md +0 -0
  22. {sourcecode-5.0.1 → sourcecode-5.1.0}/raw +0 -0
  23. {sourcecode-5.0.1 → sourcecode-5.1.0}/scripts/compare_integration_engines.py +0 -0
  24. {sourcecode-5.0.1 → sourcecode-5.1.0}/scripts/customer_smoke_test.sh +0 -0
  25. {sourcecode-5.0.1 → sourcecode-5.1.0}/scripts/generate_jdk_exports.py +0 -0
  26. {sourcecode-5.0.1 → sourcecode-5.1.0}/scripts/perf_harness.py +0 -0
  27. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/adaptive_scanner.py +0 -0
  28. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/archetype.py +0 -0
  29. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/architectural_baseline.py +0 -0
  30. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/architectural_delta.py +0 -0
  31. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/architecture_analyzer.py +0 -0
  32. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/architecture_summary.py +0 -0
  33. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/ast_extractor.py +0 -0
  34. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/audit_report.py +0 -0
  35. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/baseline_autocapture.py +0 -0
  36. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/cache.py +0 -0
  37. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/call_surface.py +0 -0
  38. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/caller_metrics.py +0 -0
  39. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/caller_reach.py +0 -0
  40. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/canonical_ir.py +0 -0
  41. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/chain_rules.py +0 -0
  42. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/change_plan.py +0 -0
  43. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/cir_graphs.py +0 -0
  44. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/classifier.py +0 -0
  45. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/client_calls.py +0 -0
  46. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  47. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/compare.py +0 -0
  48. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/confidence_analyzer.py +0 -0
  49. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/constraint_diff.py +0 -0
  50. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/container_wiring.py +0 -0
  51. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/context_cache.py +0 -0
  52. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/context_graph.py +0 -0
  53. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/context_scorer.py +0 -0
  54. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/context_summarizer.py +0 -0
  55. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/contract_diff.py +0 -0
  56. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/contract_init.py +0 -0
  57. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/contract_model.py +0 -0
  58. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/contract_pipeline.py +0 -0
  59. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/coverage_parser.py +0 -0
  60. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/data_exposure.py +0 -0
  61. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/data_labels.py +0 -0
  62. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/declarations.py +0 -0
  63. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/defect_identity.py +0 -0
  64. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/degradation.py +0 -0
  65. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/dependency_analyzer.py +0 -0
  66. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/deployment_prefix.py +0 -0
  67. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detach.py +0 -0
  68. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/__init__.py +0 -0
  69. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/base.py +0 -0
  70. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  71. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/dart.py +0 -0
  72. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/dotnet.py +0 -0
  73. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/elixir.py +0 -0
  74. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/go.py +0 -0
  75. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/heuristic.py +0 -0
  76. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/hybrid.py +0 -0
  77. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/java.py +0 -0
  78. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  79. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/nodejs.py +0 -0
  80. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/parsers.py +0 -0
  81. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/php.py +0 -0
  82. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/project.py +0 -0
  83. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/python.py +0 -0
  84. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/ruby.py +0 -0
  85. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/rust.py +0 -0
  86. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/systems.py +0 -0
  87. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/terraform.py +0 -0
  88. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/detectors/tooling.py +0 -0
  89. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/doc_analyzer.py +0 -0
  90. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/dynamic_argument_surface.py +0 -0
  91. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/endpoint_literals.py +0 -0
  92. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/endpoint_metrics.py +0 -0
  93. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  94. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/env_analyzer.py +0 -0
  95. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/envelope.py +0 -0
  96. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/environment_resolution.py +0 -0
  97. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/error_schema.py +0 -0
  98. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/evidence_provider.py +0 -0
  99. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/execution_plan.py +0 -0
  100. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/explain.py +0 -0
  101. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/facts/__init__.py +0 -0
  102. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/facts/registry.json +0 -0
  103. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/file_chunker.py +0 -0
  104. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/file_classifier.py +0 -0
  105. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/filter_surface.py +0 -0
  106. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/format_contract.py +0 -0
  107. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/fqn_utils.py +0 -0
  108. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/git_analyzer.py +0 -0
  109. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/git_checkout.py +0 -0
  110. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/graph_analyzer.py +0 -0
  111. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/graph_evidence.py +0 -0
  112. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/hibernate_strat.py +0 -0
  113. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/identity_fallback.py +0 -0
  114. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/integration_coordinates.py +0 -0
  115. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/jdk_exports.py +0 -0
  116. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/license.py +0 -0
  117. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/mcp/__init__.py +0 -0
  118. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/mcp/dependency_import.py +0 -0
  119. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  120. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  121. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  122. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  123. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  124. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/mcp/orchestrator.py +0 -0
  125. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/mcp/registry.py +0 -0
  126. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/mcp/runner.py +0 -0
  127. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/mcp/server.py +0 -0
  128. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/mcp_nudge.py +0 -0
  129. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/metrics_analyzer.py +0 -0
  130. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/migrate_check.py +0 -0
  131. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/migration_blast.py +0 -0
  132. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/non_coverage.py +0 -0
  133. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/openapi_surface.py +0 -0
  134. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/openrewrite_recipe.py +0 -0
  135. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/output_budget.py +0 -0
  136. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/output_encoding.py +0 -0
  137. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/parallel.py +0 -0
  138. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/partial_contract.py +0 -0
  139. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/path_admission.py +0 -0
  140. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/path_filters.py +0 -0
  141. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/phased_run.py +0 -0
  142. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/pipe_contract.py +0 -0
  143. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/posture.py +0 -0
  144. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/pr_comment_renderer.py +0 -0
  145. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/pr_impact.py +0 -0
  146. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/prepare_context.py +0 -0
  147. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/progress.py +0 -0
  148. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/provenance.py +0 -0
  149. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/ranking_engine.py +0 -0
  150. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/readiness_timeline.py +0 -0
  151. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/readonly.py +0 -0
  152. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/reconciliation.py +0 -0
  153. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/redactor.py +0 -0
  154. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/reference_facts.py +0 -0
  155. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/release_info.py +0 -0
  156. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/relevance_scorer.py +0 -0
  157. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/remedies.py +0 -0
  158. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/rename_refactor.py +0 -0
  159. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/repo_classifier.py +0 -0
  160. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/repository_ir.py +0 -0
  161. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/__init__.py +0 -0
  162. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/context.py +0 -0
  163. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/errors.py +0 -0
  164. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/executor.py +0 -0
  165. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/planner.py +0 -0
  166. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/query.py +0 -0
  167. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/request.py +0 -0
  168. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/resolution.py +0 -0
  169. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/result.py +0 -0
  170. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/retriever.py +0 -0
  171. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/runtime.py +0 -0
  172. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/steps.py +0 -0
  173. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
  174. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/steps_graph.py +0 -0
  175. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/steps_impact.py +0 -0
  176. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/steps_intf.py +0 -0
  177. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/steps_struct.py +0 -0
  178. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/retrieval/steps_txsec.py +0 -0
  179. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/ris.py +0 -0
  180. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/risk.py +0 -0
  181. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/rule_catalog.py +0 -0
  182. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/rule_pass.py +0 -0
  183. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/runs.py +0 -0
  184. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/runtime_classifier.py +0 -0
  185. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/sarif.py +0 -0
  186. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/scanner.py +0 -0
  187. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/schema.py +0 -0
  188. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
  189. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/security_chain.py +0 -0
  190. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/security_config.py +0 -0
  191. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/security_config_scan.py +0 -0
  192. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/security_posture.py +0 -0
  193. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/semantic_analyzer.py +0 -0
  194. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/semantic_impact_engine.py +0 -0
  195. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/semantic_integration_engine.py +0 -0
  196. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/semantic_services.py +0 -0
  197. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/serializer.py +0 -0
  198. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/servlet_surface.py +0 -0
  199. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/source_text.py +0 -0
  200. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/spring_event_topology.py +0 -0
  201. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/spring_findings.py +0 -0
  202. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/spring_impact.py +0 -0
  203. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/spring_model.py +0 -0
  204. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/spring_profiles.py +0 -0
  205. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/spring_properties.py +0 -0
  206. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/spring_security_audit.py +0 -0
  207. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/spring_semantic.py +0 -0
  208. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/spring_tx_analyzer.py +0 -0
  209. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/summarizer.py +0 -0
  210. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/target_admission.py +0 -0
  211. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/telemetry/__init__.py +0 -0
  212. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/telemetry/config.py +0 -0
  213. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/telemetry/consent.py +0 -0
  214. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/telemetry/events.py +0 -0
  215. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/telemetry/filters.py +0 -0
  216. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/telemetry/transport.py +0 -0
  217. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/test_gap_ranking.py +0 -0
  218. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/test_sources.py +0 -0
  219. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/text_input.py +0 -0
  220. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/token_estimate.py +0 -0
  221. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/tree_utils.py +0 -0
  222. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/type_usage_surface.py +0 -0
  223. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/validation_inference.py +0 -0
  224. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/validation_surface.py +0 -0
  225. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/verify_repo.py +0 -0
  226. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/verify_rules.py +0 -0
  227. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/version_check.py +0 -0
  228. {sourcecode-5.0.1 → sourcecode-5.1.0}/src/sourcecode/workspace.py +0 -0
  229. {sourcecode-5.0.1 → sourcecode-5.1.0}/supabase/functions/README.md +0 -0
  230. {sourcecode-5.0.1 → sourcecode-5.1.0}/supabase/functions/get-license/index.ts +0 -0
  231. {sourcecode-5.0.1 → sourcecode-5.1.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
  232. {sourcecode-5.0.1 → sourcecode-5.1.0}/supabase/functions/telemetry/index.ts +0 -0
  233. {sourcecode-5.0.1 → sourcecode-5.1.0}/supabase/sql/license_event_ordering.sql +0 -0
  234. {sourcecode-5.0.1 → sourcecode-5.1.0}/supabase/sql/licensing_schema.sql +0 -0
  235. {sourcecode-5.0.1 → sourcecode-5.1.0}/supabase/sql/telemetry_events.sql +0 -0
@@ -60,7 +60,7 @@ jobs:
60
60
  echo "repo_url=$(python3 -c "import json;print(json.load(open('gate-config.json'))['repository_url'])")" >> "$GITHUB_OUTPUT"
61
61
  echo "repo=$(python3 -c "import json;print(json.load(open('gate-config.json'))['repository'])")" >> "$GITHUB_OUTPUT"
62
62
  echo "fleet_subdir=$(python3 -c "import json;print(json.load(open('gate-config.json'))['fleet_subdir'])")" >> "$GITHUB_OUTPUT"
63
- echo "mode=$(python3 -c "import json;print(json.load(open('gate-config.json'))['mode'])")" >> "$GITHUB_OUTPUT"
63
+ echo "modes=$(python3 -c "import json;print(' '.join(json.load(open('gate-config.json'))['modes']))")" >> "$GITHUB_OUTPUT"
64
64
  echo "runs=$(python3 -c "import json;print(json.load(open('gate-config.json'))['min_runs'])")" >> "$GITHUB_OUTPUT"
65
65
  echo "commands=$(python3 -c "import json;print(' '.join(repr(c) for c in json.load(open('gate-config.json'))['commands']))")" >> "$GITHUB_OUTPUT"
66
66
 
@@ -79,7 +79,7 @@ jobs:
79
79
  python3 scripts/perf_harness.py \
80
80
  --repos "${{ steps.cfg.outputs.repo }}" \
81
81
  --commands ${{ steps.cfg.outputs.commands }} \
82
- --modes "${{ steps.cfg.outputs.mode }}" \
82
+ --modes ${{ steps.cfg.outputs.modes }} \
83
83
  --runs "${{ steps.cfg.outputs.runs }}" \
84
84
  --fleet-root fleet \
85
85
  --out perf-run
@@ -2,6 +2,101 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.1.0] — 2026-08-11
6
+
7
+ **The operational queue field evaluation #25 left open, and the one row it opened
8
+ that this project can act on.** No analysis changes: `endpoints`, `validation`,
9
+ `posture`, `spring-audit` and `migrate-check` were re-run on spring-petclinic,
10
+ jobrunr and BroadleafCommerce against 5.0.1 from a purged cache, and every
11
+ payload matches byte for byte except the fields that are clocks by definition
12
+ (`generated_at`, `analysis_time_ms`). What moves is what the product does when
13
+ you clear a cache, compare a tree with itself, ask it whether you have edited
14
+ anything, or read what a command costs — and `delta` / `contract-diff` gain one
15
+ declared key, `comparison.identical_states`.
16
+
17
+ ### Fixed
18
+
19
+ - **A confirmation prompt that cannot be answered is diagnosed, not raised
20
+ (C3-106).** v1.45.0 guarded the case it knew about — stdin that is not a
21
+ terminal — and the field found the one it does not cover: a PowerShell 5.1
22
+ session driven by a harness where `isatty()` answers true and the read hits
23
+ end-of-input at once, producing a Python traceback under a half-printed prompt.
24
+ All four prompts (`cache clear`, `cache context-clear`, `mcp init`,
25
+ `mcp remove` — the last two had no guard at all) now emit the product's own
26
+ envelope: `INVALID_INPUT`, the command that asked, `reason:
27
+ unanswerable_prompt`, and the `--yes` flag that removes the question. Exit 2,
28
+ because nothing was done. A plain "no" is still an answer: exit 1.
29
+ - **The shared parse store can be cleared, and says so (C3-104).** `cache status`
30
+ publishes three layers and `cache clear` emptied two; the third — the per-file
31
+ parse store — had no eviction surface at all, so a from-scratch audit meant
32
+ `rm -rf ~/.sourcecode/parse-cache-v1`, a path the field had to learn from our
33
+ documentation. `ask cache clear --global` empties it and reports what it
34
+ removed; the default run names the layer, its size and the flag. Global on
35
+ purpose: the store is content-addressed across repositories, so "this
36
+ repository's entries" is not a set it can produce.
37
+ - **One tree state is read once (C3-107).** `delta` and `contract-diff` built both
38
+ sides and then asked whether they differ. Identity is decided first — the
39
+ commit on the ref path, `cache.worktree_signature` on the checkout path, and
40
+ only when both sides produced a signature — so identical refs are materialised
41
+ once and the head IR is the base one. `comparison.identical_states` is always
42
+ present, with its basis, so a consumer can tell a degenerate comparison from a
43
+ real one. Wall time does not move on macOS (9,28 → 9,21 s on BroadleafCommerce):
44
+ the caches already served the second side, and what this removes is work whose
45
+ result the product already held.
46
+ - **A clean tree is not checked out a second time (C3-102).** `verify-edit` reads
47
+ the shared entry instead of materialising HEAD in a throwaway worktree when git
48
+ reports the tree unmodified, and writes what it builds into both the shared and
49
+ the HEAD-sha lanes, so the first edit after a clean run is still warm. The
50
+ measured gain is small (10,32 → 10,03 s cold on BroadleafCommerce): the field's
51
+ 76,6 s is one build of a 3 342-file repository, not a duplicated one. What
52
+ changes is that the build is no longer written where only `verify-edit` can
53
+ read it, and a clean-tree run no longer writes `.git/worktrees` in your
54
+ repository.
55
+ - **The `repo-ir` size band contains the largest repository ever measured
56
+ (C3-105).** The band was 10,8-27,9 KB/file and the field measured 30,3
57
+ (101 254 852 B over 3 342 files) — the one number offered for planning excluded
58
+ the measurement a reader would take. The fifth sample is admitted, and the band
59
+ now publishes its sample size and its direction: the top under-states, because
60
+ the sample that set it counted tests among its files and the estimate does not.
61
+
62
+ ### Added
63
+
64
+ - **A cached core richer than the requested view now serves it (C3-103).** The
65
+ overlay lookup already reused a *poorer* base and re-attached what it flipped;
66
+ the reverse was never tried, so asking for less than what was on disk paid for
67
+ a full analysis. The candidate set is symmetric now, with the dropped blocks
68
+ removed from the view so a caller never receives something it did not ask for.
69
+ On jobrunr: `--compact --git-context` then `--compact`, 1,15 s → **0,32 s**,
70
+ payload equal to a cold run block for block.
71
+ - **Every build carries an in-house measurement of itself (C3-109).** The field
72
+ anchors are the field's, on their repository and their machine, so this project
73
+ can never refresh them — which is why B17 reopened one release after it closed:
74
+ labelling a figure does not re-measure it. `ask cache model` now prints the
75
+ release gate's own figure beside the field's (`gate:`, `gate_measurement`,
76
+ `gate_currency()`), with its scale, cache state, host class and build. Beside,
77
+ never instead — and when the in-house one is behind there is a command to fix
78
+ it rather than an evaluation to wait for. Generated from the committed baseline
79
+ by `scripts/sync_gate_anchors.py`; the suite fails if the two disagree.
80
+ - **The gate measures the cold regime (C3-108).** Four consecutive in-house A/Bs
81
+ have failed to reproduce a field-reported regression, and the gate measured
82
+ warm only — while every field round since #23 purges every layer first. Cold
83
+ cells are captured and published (`observed_not_gated`, `decides: false` per
84
+ cell) and still may not block a release, because a cold median on an ephemeral
85
+ runner carries a cold page cache as well as a cold parse store.
86
+
87
+ ### Not fixed, and why
88
+
89
+ - **The 2-2,6x regression across sixteen commands reported between 4.18.0 and
90
+ 5.0.1 (C3-108) is open and unattributed.** Measured here on the field's own
91
+ method — every layer purged before each run — three builds on BroadleafCommerce
92
+ land within 2 % (`endpoints` 4,96 / 4,19 / 4,19 s · `spring-audit` 9,87 / 9,76 /
93
+ 9,75 s · `repo-ir` 4,20 / 4,12 / 4,21 s · `validation` 9,39 / 9,26 / 9,33 s for
94
+ 5.0.0 / 4.18.0 / 5.0.1), and the ADR-0006 harness on openmrs-core lands between
95
+ -0,6 % and +1,8 %, inside the ±5 % noise floor. The 4.18.0→5.0.1 diff is 13
96
+ files and 702 insertions, two of them on an analysis path and neither adding a
97
+ pass. A 2x a customer can measure is high whatever its cause, so the row stays
98
+ open: what it needs is a same-session A/B on the machine that sees it.
99
+
5
100
  ## [5.0.1] — 2026-08-11
6
101
 
7
102
  **A patch on the release that made the product's own cost figures honest, for the
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 5.0.1
3
+ Version: 5.1.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.0.1-blue)
45
+ ![Version](https://img.shields.io/badge/version-5.1.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.0.1 — and, on a build that has aged,
129
+ ask version # ask 5.1.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.0.1-blue)
7
+ ![Version](https://img.shields.io/badge/version-5.1.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.0.1 — and, on a build that has aged,
91
+ ask version # ask 5.1.0 — and, on a build that has aged,
92
92
  # how many releases have probably shipped since
93
93
  ```
94
94
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "5.0.1"
7
+ version = "5.1.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"
@@ -108,6 +108,10 @@ def _print_config() -> int:
108
108
  "fleet_subdir": FLEET.get(perf.RELEASE_GATE_REPO, perf.RELEASE_GATE_REPO),
109
109
  "repository_scale": perf.RELEASE_GATE_REPO_SCALE,
110
110
  "mode": perf.RELEASE_GATE_MODE,
111
+ # C3-108: what is measured and what decides are two lists now. The
112
+ # workflow reads `modes` for the harness; the gate reads the other.
113
+ "modes": list(perf.RELEASE_GATE_MEASURED_MODES),
114
+ "deciding_modes": list(perf.RELEASE_GATE_DECIDING_MODES),
111
115
  "min_runs": perf.RELEASE_GATE_MIN_RUNS,
112
116
  "commands": list(perf.RELEASE_GATE_COMMANDS),
113
117
  "exclusions": [
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env python3
2
+ """Regenerate `sourcecode.gate_anchors` from the committed gate baseline (C3-109).
3
+
4
+ The field anchors in `cache_model` are the **field's** measurements, taken on a
5
+ private repository and a Windows machine. This repository can never refresh
6
+ them, which is why B17 reopened one release after it closed: the mechanism that
7
+ labels an anchor with its build works, and nothing can re-measure the number it
8
+ labels.
9
+
10
+ What this repository *can* measure every release is the gate — `perf-gate.yml`
11
+ runs a declared command population on a 2 985-file repository under a declared
12
+ host class, and commits the cells. This script copies those cells into the
13
+ package, so a build can publish an in-house figure for **itself** beside a field
14
+ anchor that belongs to an older one.
15
+
16
+ One authority: the baseline JSON. The module is a derived artifact and
17
+ `tests/test_gate_anchor_currency.py` fails when the two disagree, so a refreshed
18
+ baseline that never reached the package is a red suite rather than a silent
19
+ lie — which is the failure mode the whole row is about.
20
+
21
+ Usage:
22
+ python3 scripts/sync_gate_anchors.py # rewrite the module
23
+ python3 scripts/sync_gate_anchors.py --check # exit 1 if it is out of date
24
+ """
25
+ from __future__ import annotations
26
+
27
+ import argparse
28
+ import json
29
+ import sys
30
+ from pathlib import Path
31
+
32
+ REPO_ROOT = Path(__file__).resolve().parent.parent
33
+ BASELINE_DIR = REPO_ROOT / "docs" / "perf" / "baselines" / "gate-latest"
34
+ MODULE_PATH = REPO_ROOT / "src" / "sourcecode" / "gate_anchors.py"
35
+
36
+ _HEADER = '''"""gate_anchors.py — what the release gate measured, on the build that ran it.
37
+
38
+ **Generated by `scripts/sync_gate_anchors.py` from `docs/perf/baselines/gate-latest/`.
39
+ Do not edit by hand.** The baseline is the authority; this module is how a build
40
+ carries it.
41
+
42
+ C3-109. `cache_model`'s field anchors are the field's own measurements, on their
43
+ repository and their machine — the reason they are trustworthy is the reason they
44
+ cannot be refreshed here, and B17 reopened one release after closing because a
45
+ refreshed anchor expires the moment the next release ships. This is the figure
46
+ this project *can* re-measure every release: the gate's own population on a
47
+ 2 985-file repository, under a declared host class, with the build that produced
48
+ it recorded beside it.
49
+
50
+ It does not replace a field anchor and never overrides one. It is the second
51
+ figure a reader gets — one measured at field scale on another build, one measured
52
+ on this build on a repository we control — and the pair is honest in a way
53
+ neither is alone.
54
+ """
55
+ from __future__ import annotations
56
+
57
+ '''
58
+
59
+
60
+ def _cells() -> "dict[str, dict]":
61
+ out: "dict[str, dict]" = {}
62
+ for path in sorted(BASELINE_DIR.glob("*.json")):
63
+ cell = json.loads(path.read_text(encoding="utf-8"))
64
+ command = cell.get("command") or "ask"
65
+ out[command] = {
66
+ "seconds": round(float(cell["wall_ms"]["p50"]) / 1000.0, 2),
67
+ "mode": cell.get("mode", "unknown"),
68
+ "runs": int(cell.get("runs", 0) or 0),
69
+ }
70
+ return out
71
+
72
+
73
+ def _meta() -> dict:
74
+ first = next(iter(sorted(BASELINE_DIR.glob("*.json"))), None)
75
+ if first is None:
76
+ return {}
77
+ cell = json.loads(first.read_text(encoding="utf-8"))
78
+ return {
79
+ "version": cell.get("tool_version", ""),
80
+ "captured_at": cell.get("captured_at", ""),
81
+ "repository": (cell.get("repo") or {}).get("name", ""),
82
+ "java_files": int((cell.get("repo") or {}).get("files", 0) or 0),
83
+ "host_class": (cell.get("env") or {}).get("host_id", "") or "github-ubuntu-latest",
84
+ }
85
+
86
+
87
+ def render() -> str:
88
+ meta = _meta()
89
+ cells = _cells()
90
+ lines = [_HEADER]
91
+ lines.append("#: The build the gate cells below were captured on.\n")
92
+ lines.append(f'GATE_MEASURED_VERSION = {meta.get("version", "")!r}\n')
93
+ lines.append("#: When, so a reader can tell a stale capture from a missing one.\n")
94
+ lines.append(f'GATE_CAPTURED_AT = {meta.get("captured_at", "")!r}\n')
95
+ lines.append("#: The repository the gate measures, and its size axis.\n")
96
+ lines.append(f'GATE_REPOSITORY = {meta.get("repository", "")!r}\n')
97
+ lines.append(f'GATE_JAVA_FILES = {meta.get("java_files", 0)!r}\n')
98
+ lines.append(
99
+ "#: The host class the runs are comparable within. Cross-machine numbers\n"
100
+ "#: are recorded, never diffed (ADR-0006).\n"
101
+ )
102
+ lines.append(f'GATE_HOST_CLASS = {meta.get("host_class", "")!r}\n')
103
+ lines.append(
104
+ "\n#: command → measured wall time (p50 seconds), the cache mode it was\n"
105
+ "#: taken in, and how many runs the median is over.\n"
106
+ )
107
+ lines.append("GATE_ANCHORS: \"dict[str, dict]\" = {\n")
108
+ for command, cell in cells.items():
109
+ lines.append(
110
+ f" {command!r}: {{\"seconds\": {cell['seconds']!r}, "
111
+ f"\"mode\": {cell['mode']!r}, \"runs\": {cell['runs']!r}}},\n"
112
+ )
113
+ lines.append("}\n")
114
+ return "".join(lines)
115
+
116
+
117
+ def main() -> int:
118
+ ap = argparse.ArgumentParser(description=__doc__)
119
+ ap.add_argument("--check", action="store_true",
120
+ help="Do not write; exit 1 when the module is out of date.")
121
+ args = ap.parse_args()
122
+
123
+ if not BASELINE_DIR.exists():
124
+ print(f"no baseline directory at {BASELINE_DIR}", file=sys.stderr)
125
+ return 1
126
+ rendered = render()
127
+ current = MODULE_PATH.read_text(encoding="utf-8") if MODULE_PATH.exists() else ""
128
+ if args.check:
129
+ if current != rendered:
130
+ print(
131
+ "sourcecode/gate_anchors.py is out of date with "
132
+ "docs/perf/baselines/gate-latest — run scripts/sync_gate_anchors.py",
133
+ file=sys.stderr,
134
+ )
135
+ return 1
136
+ print("gate anchors are in sync")
137
+ return 0
138
+ MODULE_PATH.write_text(rendered, encoding="utf-8")
139
+ print(f"wrote {MODULE_PATH.relative_to(REPO_ROOT)}")
140
+ return 0
141
+
142
+
143
+ if __name__ == "__main__":
144
+ raise SystemExit(main())
@@ -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.0.1"
7
+ __version__ = "5.1.0"
@@ -616,6 +616,103 @@ def field_currency() -> dict:
616
616
  }
617
617
 
618
618
 
619
+ def gate_anchor(command: str) -> "Optional[dict]":
620
+ """What the release gate measured for *command*, or ``None`` (C3-109).
621
+
622
+ The third figure in this module, and the only one this repository can refresh
623
+ by itself. `REFERENCE_*` is a 3.2.2 measurement on a 2 000-file tree;
624
+ `field_seconds` is the field's, at 3 342 files, on their machine and their
625
+ build. Both age, and neither can be re-measured from here — which is exactly
626
+ how B17 reopened one release after it was closed: the labelling worked and
627
+ the number still expired.
628
+
629
+ The gate measures a 2 985-file repository under a declared host class every
630
+ release and commits its cells, so this figure carries the build that produced
631
+ it and can be brought current by running the gate. It never overrides a field
632
+ anchor — a measurement at field scale outranks one at gate scale — it is
633
+ published *beside* it, so an anchor from an older build is no longer the only
634
+ number a reader has.
635
+ """
636
+ try:
637
+ from sourcecode.gate_anchors import (
638
+ GATE_ANCHORS,
639
+ GATE_HOST_CLASS,
640
+ GATE_JAVA_FILES,
641
+ GATE_MEASURED_VERSION,
642
+ GATE_REPOSITORY,
643
+ )
644
+ except Exception:
645
+ return None
646
+ cell = GATE_ANCHORS.get(command)
647
+ if not cell:
648
+ return None
649
+ return {
650
+ "seconds": cell["seconds"],
651
+ "cache_state": cell["mode"],
652
+ "runs": cell["runs"],
653
+ "measured_on_version": GATE_MEASURED_VERSION,
654
+ "repository": GATE_REPOSITORY,
655
+ "java_files": GATE_JAVA_FILES,
656
+ "host_class": GATE_HOST_CLASS,
657
+ }
658
+
659
+
660
+ def gate_currency() -> dict:
661
+ """Whether the in-house gate figures describe the build in hand (C3-109).
662
+
663
+ Same shape and same purpose as `field_currency`, for the anchor set that can
664
+ actually be refreshed. When this says `current: false`, the remedy is a
665
+ command rather than a hope: re-run the gate on the tag and commit the cells.
666
+ """
667
+ from sourcecode import __version__
668
+
669
+ current = __version__
670
+ try:
671
+ from sourcecode.gate_anchors import (
672
+ GATE_ANCHORS,
673
+ GATE_CAPTURED_AT,
674
+ GATE_HOST_CLASS,
675
+ GATE_JAVA_FILES,
676
+ GATE_MEASURED_VERSION,
677
+ GATE_REPOSITORY,
678
+ )
679
+ except Exception:
680
+ return {
681
+ "available": False,
682
+ "running_version": current,
683
+ "statement": (
684
+ "This build carries no gate measurement of its own. The gate "
685
+ "publishes one per release (docs/perf/REGRESSION-GATE.md); until "
686
+ "it runs, the field anchors are the only measured figures here."
687
+ ),
688
+ }
689
+ return {
690
+ "available": True,
691
+ "measured_on_version": GATE_MEASURED_VERSION,
692
+ "running_version": current,
693
+ "current": GATE_MEASURED_VERSION == current,
694
+ "captured_at": GATE_CAPTURED_AT,
695
+ "repository": GATE_REPOSITORY,
696
+ "java_files": GATE_JAVA_FILES,
697
+ "host_class": GATE_HOST_CLASS,
698
+ "commands": sorted(GATE_ANCHORS),
699
+ "statement": (
700
+ f"The release gate measured {len(GATE_ANCHORS)} commands on "
701
+ f"{GATE_REPOSITORY} ({GATE_JAVA_FILES} Java files, {GATE_HOST_CLASS}) "
702
+ + (
703
+ f"on {current}, the build you are running."
704
+ if GATE_MEASURED_VERSION == current
705
+ else (
706
+ f"on {GATE_MEASURED_VERSION}; you are running {current}, which "
707
+ f"the gate has not measured. Re-run it on this build "
708
+ f"(docs/perf/REGRESSION-GATE.md) — unlike the field anchors, "
709
+ f"this is a figure this project can refresh."
710
+ )
711
+ )
712
+ ),
713
+ }
714
+
715
+
619
716
  def reference_currency() -> dict:
620
717
  """How old the reference figures are, in releases the reader can name (F-AP).
621
718
 
@@ -680,6 +777,11 @@ def as_dict(here: "Optional[Conditioning]" = None) -> dict:
680
777
  # measured 2 351 s and 8,4 s on two of our own builds (C4-19, C3-97).
681
778
  "field_anchor": FIELD_ANCHOR,
682
779
  "field_currency": field_currency(),
780
+ # C3-109: and the figure this project can refresh by itself. A field
781
+ # anchor belongs to the build the field ran; this one belongs to the
782
+ # build the gate ran, which is a release away at worst instead of
783
+ # unreachable. Published beside, never instead.
784
+ "gate_currency": gate_currency(),
683
785
  "commands": [
684
786
  {
685
787
  "command": cmd.command,
@@ -716,6 +818,12 @@ def as_dict(here: "Optional[Conditioning]" = None) -> dict:
716
818
  "note": field_anchor_note(cmd),
717
819
  }
718
820
  ),
821
+ # C3-109: the in-house measurement of this command, on the build
822
+ # the gate last ran. Absent for commands the gate does not cover —
823
+ # its population is declared in `sourcecode.perf`, with the
824
+ # exclusions and their reasons, and an axis nobody measured is
825
+ # never a number here.
826
+ "gate_measurement": gate_anchor(cmd.command),
719
827
  }
720
828
  for cmd in COMMANDS
721
829
  ],
@@ -827,6 +935,7 @@ def render_text(here: "Optional[Conditioning]" = None) -> str:
827
935
  lines.append(f" Timings: {REFERENCE_REPOSITORY}, each command measured in isolation.")
828
936
  lines.append(f" {reference_currency()['statement']}")
829
937
  lines.append(f" {field_currency()['statement']}")
938
+ lines.append(f" {gate_currency()['statement']}")
830
939
  width = max(len(c.command) for c in COMMANDS)
831
940
  for cmd in COMMANDS:
832
941
  repeat = "repeat cached" if cmd.repeat else "recomputes"
@@ -848,6 +957,17 @@ def render_text(here: "Optional[Conditioning]" = None) -> str:
848
957
  f" {' ' * width} field: {shown} at "
849
958
  f"{_thousands(FIELD_ANCHOR_JAVA_FILES)} Java files{suffix}"
850
959
  )
960
+ _gate = gate_anchor(cmd.command)
961
+ if _gate:
962
+ # C3-109: the in-house figure, beside the field's rather than instead
963
+ # of it — one is at field scale on another build, one is on a build
964
+ # this project can bring current.
965
+ lines.append(
966
+ f" {' ' * width} gate: {_gate['seconds']:g} s at "
967
+ f"{_thousands(_gate['java_files'])} Java files "
968
+ f"({_gate['cache_state']} cache, on {_gate['measured_on_version']}, "
969
+ f"{_gate['host_class']})"
970
+ )
851
971
  if cmd.note:
852
972
  lines.append(f" {' ' * width} {cmd.note}")
853
973
  if here is not None and cmd.command in here.per_command: