sourcecode 2.7.0__tar.gz → 3.0.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 (180) hide show
  1. {sourcecode-2.7.0 → sourcecode-3.0.0}/CHANGELOG.md +79 -0
  2. {sourcecode-2.7.0 → sourcecode-3.0.0}/PKG-INFO +3 -1
  3. {sourcecode-2.7.0 → sourcecode-3.0.0}/README.md +2 -0
  4. {sourcecode-2.7.0 → sourcecode-3.0.0}/pyproject.toml +1 -1
  5. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/__init__.py +1 -1
  6. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/cache.py +44 -3
  7. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/cli.py +439 -33
  8. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/context_cache.py +9 -0
  9. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/contract_pipeline.py +14 -3
  10. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/java.py +7 -1
  11. sourcecode-3.0.0/src/sourcecode/envelope.py +193 -0
  12. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/format_contract.py +11 -5
  13. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/git_analyzer.py +74 -12
  14. sourcecode-3.0.0/src/sourcecode/posture.py +458 -0
  15. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/prepare_context.py +126 -35
  16. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/repository_ir.py +70 -1
  17. sourcecode-3.0.0/src/sourcecode/schemas/envelope-v1.schema.json +74 -0
  18. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/semantic_integration_engine.py +11 -0
  19. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/spring_impact.py +44 -10
  20. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/spring_profiles.py +11 -1
  21. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/spring_security_audit.py +5 -3
  22. sourcecode-3.0.0/src/sourcecode/verify_repo.py +252 -0
  23. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/verify_rules.py +135 -12
  24. {sourcecode-2.7.0 → sourcecode-3.0.0}/.github/workflows/build-windows.yml +0 -0
  25. {sourcecode-2.7.0 → sourcecode-3.0.0}/.gitignore +0 -0
  26. {sourcecode-2.7.0 → sourcecode-3.0.0}/.ruff.toml +0 -0
  27. {sourcecode-2.7.0 → sourcecode-3.0.0}/CONTRIBUTING.md +0 -0
  28. {sourcecode-2.7.0 → sourcecode-3.0.0}/LICENSE +0 -0
  29. {sourcecode-2.7.0 → sourcecode-3.0.0}/SECURITY.md +0 -0
  30. {sourcecode-2.7.0 → sourcecode-3.0.0}/raw +0 -0
  31. {sourcecode-2.7.0 → sourcecode-3.0.0}/scripts/compare_integration_engines.py +0 -0
  32. {sourcecode-2.7.0 → sourcecode-3.0.0}/scripts/customer_smoke_test.sh +0 -0
  33. {sourcecode-2.7.0 → sourcecode-3.0.0}/scripts/generate_jdk_exports.py +0 -0
  34. {sourcecode-2.7.0 → sourcecode-3.0.0}/scripts/perf_harness.py +0 -0
  35. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/adaptive_scanner.py +0 -0
  36. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/archetype.py +0 -0
  37. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/architectural_baseline.py +0 -0
  38. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/architectural_delta.py +0 -0
  39. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/architecture_analyzer.py +0 -0
  40. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/architecture_summary.py +0 -0
  41. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/ast_extractor.py +0 -0
  42. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/call_surface.py +0 -0
  43. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/caller_metrics.py +0 -0
  44. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/canonical_ir.py +0 -0
  45. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/change_plan.py +0 -0
  46. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/cir_graphs.py +0 -0
  47. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/classifier.py +0 -0
  48. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  49. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/compare.py +0 -0
  50. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/confidence_analyzer.py +0 -0
  51. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/constraint_diff.py +0 -0
  52. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/context_graph.py +0 -0
  53. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/context_scorer.py +0 -0
  54. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/context_summarizer.py +0 -0
  55. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/contract_diff.py +0 -0
  56. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/contract_model.py +0 -0
  57. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/coverage_parser.py +0 -0
  58. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/dependency_analyzer.py +0 -0
  59. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/deployment_prefix.py +0 -0
  60. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/__init__.py +0 -0
  61. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/base.py +0 -0
  62. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  63. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/dart.py +0 -0
  64. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/dotnet.py +0 -0
  65. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/elixir.py +0 -0
  66. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/go.py +0 -0
  67. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/heuristic.py +0 -0
  68. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/hybrid.py +0 -0
  69. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  70. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/nodejs.py +0 -0
  71. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/parsers.py +0 -0
  72. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/php.py +0 -0
  73. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/project.py +0 -0
  74. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/python.py +0 -0
  75. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/ruby.py +0 -0
  76. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/rust.py +0 -0
  77. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/systems.py +0 -0
  78. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/terraform.py +0 -0
  79. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/detectors/tooling.py +0 -0
  80. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/doc_analyzer.py +0 -0
  81. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/dynamic_argument_surface.py +0 -0
  82. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/endpoint_literals.py +0 -0
  83. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/endpoint_metrics.py +0 -0
  84. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  85. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/env_analyzer.py +0 -0
  86. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/error_schema.py +0 -0
  87. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/evidence_provider.py +0 -0
  88. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/explain.py +0 -0
  89. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/file_chunker.py +0 -0
  90. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/file_classifier.py +0 -0
  91. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/filter_surface.py +0 -0
  92. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/fqn_utils.py +0 -0
  93. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/graph_analyzer.py +0 -0
  94. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/graph_evidence.py +0 -0
  95. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/hibernate_strat.py +0 -0
  96. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/jdk_exports.py +0 -0
  97. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/license.py +0 -0
  98. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/mcp/__init__.py +0 -0
  99. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  100. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  101. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  102. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  103. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  104. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/mcp/orchestrator.py +0 -0
  105. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/mcp/registry.py +0 -0
  106. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/mcp/runner.py +0 -0
  107. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/mcp/server.py +0 -0
  108. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/mcp_nudge.py +0 -0
  109. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/metrics_analyzer.py +0 -0
  110. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/migrate_check.py +0 -0
  111. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/openapi_surface.py +0 -0
  112. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/output_budget.py +0 -0
  113. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/parse_cache.py +0 -0
  114. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/path_filters.py +0 -0
  115. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/perf.py +0 -0
  116. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/pr_comment_renderer.py +0 -0
  117. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/pr_impact.py +0 -0
  118. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/progress.py +0 -0
  119. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/ranking_engine.py +0 -0
  120. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/readiness_timeline.py +0 -0
  121. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/reconciliation.py +0 -0
  122. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/redactor.py +0 -0
  123. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/relevance_scorer.py +0 -0
  124. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/rename_refactor.py +0 -0
  125. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/repo_classifier.py +0 -0
  126. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/__init__.py +0 -0
  127. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/context.py +0 -0
  128. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/errors.py +0 -0
  129. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/executor.py +0 -0
  130. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/planner.py +0 -0
  131. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/query.py +0 -0
  132. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/request.py +0 -0
  133. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/resolution.py +0 -0
  134. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/result.py +0 -0
  135. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/retriever.py +0 -0
  136. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/runtime.py +0 -0
  137. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/steps.py +0 -0
  138. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
  139. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/steps_graph.py +0 -0
  140. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/steps_impact.py +0 -0
  141. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/steps_intf.py +0 -0
  142. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/steps_struct.py +0 -0
  143. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/retrieval/steps_txsec.py +0 -0
  144. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/ris.py +0 -0
  145. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/runtime_classifier.py +0 -0
  146. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/scanner.py +0 -0
  147. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/schema.py +0 -0
  148. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/security_config.py +0 -0
  149. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/security_posture.py +0 -0
  150. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/semantic_analyzer.py +0 -0
  151. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/semantic_impact_engine.py +0 -0
  152. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/semantic_services.py +0 -0
  153. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/serializer.py +0 -0
  154. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/spring_event_topology.py +0 -0
  155. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/spring_findings.py +0 -0
  156. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/spring_model.py +0 -0
  157. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/spring_semantic.py +0 -0
  158. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/spring_tx_analyzer.py +0 -0
  159. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/summarizer.py +0 -0
  160. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/telemetry/__init__.py +0 -0
  161. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/telemetry/config.py +0 -0
  162. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/telemetry/consent.py +0 -0
  163. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/telemetry/events.py +0 -0
  164. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/telemetry/filters.py +0 -0
  165. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/telemetry/transport.py +0 -0
  166. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/token_estimate.py +0 -0
  167. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/tree_utils.py +0 -0
  168. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/type_usage_surface.py +0 -0
  169. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/validation_inference.py +0 -0
  170. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/validation_surface.py +0 -0
  171. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/verify_edit.py +0 -0
  172. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/version_check.py +0 -0
  173. {sourcecode-2.7.0 → sourcecode-3.0.0}/src/sourcecode/workspace.py +0 -0
  174. {sourcecode-2.7.0 → sourcecode-3.0.0}/supabase/functions/README.md +0 -0
  175. {sourcecode-2.7.0 → sourcecode-3.0.0}/supabase/functions/get-license/index.ts +0 -0
  176. {sourcecode-2.7.0 → sourcecode-3.0.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
  177. {sourcecode-2.7.0 → sourcecode-3.0.0}/supabase/functions/telemetry/index.ts +0 -0
  178. {sourcecode-2.7.0 → sourcecode-3.0.0}/supabase/sql/license_event_ordering.sql +0 -0
  179. {sourcecode-2.7.0 → sourcecode-3.0.0}/supabase/sql/licensing_schema.sql +0 -0
  180. {sourcecode-2.7.0 → sourcecode-3.0.0}/supabase/sql/telemetry_events.sql +0 -0
@@ -1,5 +1,84 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.0.0] — 2026-07-28
4
+
5
+ **One answer per question, a contract around every answer, and a gate that can be
6
+ switched on.** Driven by the strategic re-triage of the 2.7.0 field audit: ten reported
7
+ defects collapsed into four root-cause kernels — scope & identity, evidence admission,
8
+ presentation contract, conditional resolution — and the flagship enforcement feature was
9
+ built on top of the kernels rather than beside them.
10
+
11
+ ### Breaking
12
+
13
+ - **`pr-impact` defaults to JSON.** It was the only machine-consumable command defaulting
14
+ to text, while being the one command a pipeline gates on (`--fail-on`, exit codes).
15
+ `--format text` restores the previous output.
16
+ - **`endpoints --by-controller` keys are controller FQNs, not simple class names.** The
17
+ function documented FQN grouping and grouped by simple name, so two controllers sharing
18
+ a name in different packages became one entry: keycloak reported 120 groups for 123
19
+ controller classes, and three of them listed another package's routes as their own.
20
+
21
+ ### Added
22
+
23
+ - **Executable contracts.** A repository declares its invariants in `.ask/contracts.yml`
24
+ — forbidden edges, endpoint-security requirements, and forbidden finding classes from
25
+ the transaction/security analyzers that already ship — and `ask verify` gates on them.
26
+ Baseline-relative by default (`--capture-baseline`, `--fail-on new|any|never`): a
27
+ codebase adopting contracts already violates them, and a gate that fails on all of it
28
+ is switched off the same afternoon. Exit codes match `verify-edit` (0 pass, 1 blocked,
29
+ 2 unverified). Violation identity excludes source position, so moving code is not a new
30
+ violation. GitHub Actions workflow and generic CI recipes in
31
+ [docs/contracts.md](docs/contracts.md); the older `.ask/verify-rules.json` keeps working.
32
+ - **`ask posture --profile` / `--diff`** *(experimental)*. Profile *detection* shipped in 2.7.0 with
33
+ nothing consuming it. This resolves which conditional beans a profile set actually
34
+ wires — full `@Profile` semantics including `!`, `&`, `|` and parentheses — and reports
35
+ what each side of a `--diff` wires that the other does not, including the
36
+ security-configuration slice ("prod configures the request chain; dev activates no
37
+ security configuration"). A bean gated by a condition the analyzer does not evaluate is
38
+ reported as **unresolved**, never assumed active and never assumed absent. On a
39
+ repository that gates beans on properties most of the answer will be "unresolved" —
40
+ that is the honest shape of what ships, and why the command is marked experimental.
41
+ See [docs/posture.md](docs/posture.md).
42
+ - **A response envelope on every JSON payload.** `_meta` carries
43
+ `envelope_version`, `tool_version`, `command`, `scope` (path, repo root, and the prefix
44
+ every path in the payload is relative to), `run_id`, and the `inputs` the id is computed
45
+ over. `run_id` carries no timestamp, so two runs on an unchanged tree are byte-identical
46
+ and any change to the analyzer, the commit, the working tree or the repository
47
+ configuration changes it. MCP inherits it.
48
+ - **A published output contract.** `ask schema envelope-v1` prints the JSON Schema the
49
+ installed version emits, with the compatibility policy stated inside it. A conformance
50
+ battery validates real command output against it.
51
+ - **`--base` as an alias for `--since`**, and `-f` for `--format` on `review-pr` and
52
+ `verify-edit`. Additive: every existing spelling still works.
53
+ - **Endpoint admission classes.** The endpoint surface publishes `by_source` and
54
+ `semantic_model_endpoints`, so the totals from `endpoints`, `spring-audit` and
55
+ `retrieve endpoint-inventory` reconcile instead of contradicting each other.
56
+
57
+ ### Fixed
58
+
59
+ - **`--changed-only` reported `file_paths: []` on every run.** It filtered a key the
60
+ compact view never emits, so the one file-level surface of the changed-only envelope was
61
+ always empty — next to a non-empty `changed_files` proving otherwise. Both the cold and
62
+ the warm-cache paths had the same dead filter. The warm path also claimed
63
+ `cache_source: L2_view` for content that came from the L1 rebuild.
64
+ - **Three commands answered "how many endpoints?" with three numbers.** Broadleaf
65
+ 225/220/220, openmrs 1/0/0, JobRunr 12/0/0. The difference is xml-mapped controllers and
66
+ router-DSL routes, which the semantic model does not index; `spring-audit` explained it
67
+ as "multi-prefix routes that collapse", which was measurably not the cause.
68
+ - **`impact` and `impact-chain` scored risk on incomparable scales.** `impact` bounds the
69
+ score to [0,100); `impact-chain` returned an unbounded total whose caller term was capped
70
+ at 20, flattening symbols whose caller counts differ by an order of magnitude (keycloak
71
+ printed 86.0 for two symbols and 1844.0 for a third). Both now use the same knee
72
+ compression, with the knee on the critical band edge — zero risk-level changes across a
73
+ 16-symbol A/B — and publish `risk_score_raw` for ranking.
74
+ - **`review-pr` announced roles its own evidence gate had rejected.** A repository whose
75
+ only change was a string helper named `NameMapper.java` reported "1 MyBatis mapper(s) —
76
+ risk areas: persistence" while the file's own record said `artifact_type: source`. One
77
+ admission seam now serves the summary, the risk areas, the review-order ranking and the
78
+ per-file records. Aligning them exposed the gate rejecting true positives too:
79
+ persistence evidence knew JPA but not MyBatis/JDBC, and controller evidence knew Spring
80
+ MVC but not JAX-RS — keycloak's entire 676-endpoint surface.
81
+
3
82
  ## [2.7.0] — 2026-07-26
4
83
 
5
84
  **The analyzer reads facts it had been walking past, and stops spending the context budget
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 2.7.0
3
+ Version: 3.0.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
@@ -232,6 +232,8 @@ Matching endpoints report `policy: "custom"` and drop out of the `no_security_si
232
232
  | Doc | What it covers |
233
233
  |-----|----------------|
234
234
  | [USER_GUIDE.md](docs/USER_GUIDE.md) | Full command reference, flags, output schema, workflows |
235
+ | [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml`, enforce them in the edit loop and in CI |
236
+ | [posture.md](docs/posture.md) | What a profile set actually wires, and what could not be decided (experimental) |
235
237
  | [migrate-check.md](docs/migrate-check.md) | Migration rule catalogue (MIG-001..043) + Hibernate stratification |
236
238
  | [MODERNIZATION.md](docs/MODERNIZATION.md) | The modernization product: assess → understand → plan → execute |
237
239
  | [PRODUCT_TIERS.md](docs/PRODUCT_TIERS.md) | Free vs Pro, pricing model |
@@ -194,6 +194,8 @@ Matching endpoints report `policy: "custom"` and drop out of the `no_security_si
194
194
  | Doc | What it covers |
195
195
  |-----|----------------|
196
196
  | [USER_GUIDE.md](docs/USER_GUIDE.md) | Full command reference, flags, output schema, workflows |
197
+ | [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml`, enforce them in the edit loop and in CI |
198
+ | [posture.md](docs/posture.md) | What a profile set actually wires, and what could not be decided (experimental) |
197
199
  | [migrate-check.md](docs/migrate-check.md) | Migration rule catalogue (MIG-001..043) + Hibernate stratification |
198
200
  | [MODERNIZATION.md](docs/MODERNIZATION.md) | The modernization product: assess → understand → plan → execute |
199
201
  | [PRODUCT_TIERS.md](docs/PRODUCT_TIERS.md) | Free vs Pro, pricing model |
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "2.7.0"
7
+ version = "3.0.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__ = "2.7.0"
7
+ __version__ = "3.0.0"
@@ -75,11 +75,52 @@ SCHEMA_VERSION: str = "2"
75
75
  #: Bump to invalidate all L1 core caches (independent of snapshot version).
76
76
  CORE_SCHEMA_VERSION: str = "1"
77
77
 
78
- #: Bump when analysis logic or output schema changes NOT on every package release.
79
- #: This is the stable part of the L1 core cache key. Package version bumps (patch,
80
- #: minor) must NOT bump this value unless the cached data format actually changed.
78
+ #: Manual override for invalidating all L1 core caches. Rarely needed now that the
79
+ #: key carries :func:`analyzer_fingerprint`; kept as an escape hatch for cases the
80
+ #: fingerprint cannot see (a changed dependency, a corrected cache format).
81
+ #: Package version bumps must NOT bump this value.
81
82
  ANALYZER_CACHE_VERSION: str = "1"
82
83
 
84
+
85
+ def analyzer_fingerprint() -> str:
86
+ """Content hash of the analysis code, memoised for the process.
87
+
88
+ A cache key built only from the repository state and a hand-maintained version
89
+ constant cannot notice that the analyzer itself changed. That discipline failed
90
+ exactly as designed-by-humans disciplines do: five consecutive fixes to analysis
91
+ logic shipped without anyone bumping ``ANALYZER_CACHE_VERSION``, so an upgraded
92
+ install kept serving pre-fix results from cache on an unchanged commit — the
93
+ fixes looked inert until the user cleared the cache by hand.
94
+
95
+ Hashing file *content* (not mtime) keeps the key stable across reinstalls and
96
+ identical checkouts on different machines, so caches stay shareable. Any edit to
97
+ any module invalidates every entry: over-invalidation costs a re-analysis,
98
+ under-invalidation reports facts the current code would not produce.
99
+
100
+ Falls back to the package version when the source is unreadable (zipimport,
101
+ frozen builds) — degraded, never wrong-by-silence.
102
+ """
103
+ global _ANALYZER_FINGERPRINT
104
+ if _ANALYZER_FINGERPRINT is not None:
105
+ return _ANALYZER_FINGERPRINT
106
+ digest = hashlib.sha256()
107
+ try:
108
+ pkg_root = Path(__file__).resolve().parent
109
+ sources = sorted(pkg_root.rglob("*.py"))
110
+ if not sources:
111
+ raise OSError("no analyzer sources found")
112
+ for src in sources:
113
+ digest.update(src.relative_to(pkg_root).as_posix().encode("utf-8"))
114
+ digest.update(src.read_bytes())
115
+ _ANALYZER_FINGERPRINT = digest.hexdigest()[:12]
116
+ except Exception:
117
+ from sourcecode import __version__ as _pkg_version
118
+ _ANALYZER_FINGERPRINT = f"pkg-{_pkg_version}"
119
+ return _ANALYZER_FINGERPRINT
120
+
121
+
122
+ _ANALYZER_FINGERPRINT: Optional[str] = None
123
+
83
124
  #: Fields eligible for CAS deduplication (applied to top-level JSON dict keys).
84
125
  _CAS_FIELDS: frozenset[str] = frozenset([
85
126
  "file_paths",