sourcecode 3.2.0__tar.gz → 3.2.2__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 (189) hide show
  1. {sourcecode-3.2.0 → sourcecode-3.2.2}/CHANGELOG.md +300 -0
  2. {sourcecode-3.2.0 → sourcecode-3.2.2}/PKG-INFO +128 -14
  3. {sourcecode-3.2.0 → sourcecode-3.2.2}/README.md +127 -13
  4. {sourcecode-3.2.0 → sourcecode-3.2.2}/pyproject.toml +1 -1
  5. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/__init__.py +1 -1
  6. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/cache.py +104 -0
  7. sourcecode-3.2.2/src/sourcecode/cache_model.py +295 -0
  8. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/chain_rules.py +49 -8
  9. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/cli.py +419 -205
  10. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/confidence_analyzer.py +10 -6
  11. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/context_cache.py +7 -27
  12. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/deployment_prefix.py +85 -0
  13. sourcecode-3.2.2/src/sourcecode/facts/__init__.py +71 -0
  14. sourcecode-3.2.2/src/sourcecode/facts/registry.json +158 -0
  15. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/license.py +1 -1
  16. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/mcp/registry.py +1 -1
  17. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/mcp/server.py +3 -3
  18. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/metrics_analyzer.py +8 -5
  19. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/posture.py +78 -6
  20. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/prepare_context.py +51 -26
  21. sourcecode-3.2.2/src/sourcecode/reference_facts.py +307 -0
  22. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/ris.py +27 -1
  23. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/serializer.py +36 -9
  24. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/spring_profiles.py +93 -13
  25. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/telemetry/__init__.py +4 -3
  26. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/telemetry/config.py +31 -23
  27. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/telemetry/consent.py +20 -16
  28. sourcecode-3.2.2/src/sourcecode/test_sources.py +178 -0
  29. {sourcecode-3.2.0 → sourcecode-3.2.2}/.github/workflows/build-windows.yml +0 -0
  30. {sourcecode-3.2.0 → sourcecode-3.2.2}/.gitignore +0 -0
  31. {sourcecode-3.2.0 → sourcecode-3.2.2}/.ruff.toml +0 -0
  32. {sourcecode-3.2.0 → sourcecode-3.2.2}/CONTRIBUTING.md +0 -0
  33. {sourcecode-3.2.0 → sourcecode-3.2.2}/LICENSE +0 -0
  34. {sourcecode-3.2.0 → sourcecode-3.2.2}/SECURITY.md +0 -0
  35. {sourcecode-3.2.0 → sourcecode-3.2.2}/raw +0 -0
  36. {sourcecode-3.2.0 → sourcecode-3.2.2}/scripts/compare_integration_engines.py +0 -0
  37. {sourcecode-3.2.0 → sourcecode-3.2.2}/scripts/customer_smoke_test.sh +0 -0
  38. {sourcecode-3.2.0 → sourcecode-3.2.2}/scripts/generate_jdk_exports.py +0 -0
  39. {sourcecode-3.2.0 → sourcecode-3.2.2}/scripts/perf_harness.py +0 -0
  40. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/adaptive_scanner.py +0 -0
  41. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/archetype.py +0 -0
  42. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/architectural_baseline.py +0 -0
  43. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/architectural_delta.py +0 -0
  44. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/architecture_analyzer.py +0 -0
  45. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/architecture_summary.py +0 -0
  46. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/ast_extractor.py +0 -0
  47. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/call_surface.py +0 -0
  48. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/caller_metrics.py +0 -0
  49. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/canonical_ir.py +0 -0
  50. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/change_plan.py +0 -0
  51. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/cir_graphs.py +0 -0
  52. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/classifier.py +0 -0
  53. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/code_notes_analyzer.py +0 -0
  54. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/compare.py +0 -0
  55. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/constraint_diff.py +0 -0
  56. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/context_graph.py +0 -0
  57. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/context_scorer.py +0 -0
  58. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/context_summarizer.py +0 -0
  59. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/contract_diff.py +0 -0
  60. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/contract_model.py +0 -0
  61. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/contract_pipeline.py +0 -0
  62. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/coverage_parser.py +0 -0
  63. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/dependency_analyzer.py +0 -0
  64. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/__init__.py +0 -0
  65. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/base.py +0 -0
  66. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/csproj_parser.py +0 -0
  67. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/dart.py +0 -0
  68. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/dotnet.py +0 -0
  69. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/elixir.py +0 -0
  70. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/go.py +0 -0
  71. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/heuristic.py +0 -0
  72. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/hybrid.py +0 -0
  73. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/java.py +0 -0
  74. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/jvm_ext.py +0 -0
  75. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/nodejs.py +0 -0
  76. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/parsers.py +0 -0
  77. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/php.py +0 -0
  78. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/project.py +0 -0
  79. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/python.py +0 -0
  80. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/ruby.py +0 -0
  81. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/rust.py +0 -0
  82. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/systems.py +0 -0
  83. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/terraform.py +0 -0
  84. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/detectors/tooling.py +0 -0
  85. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/doc_analyzer.py +0 -0
  86. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/dynamic_argument_surface.py +0 -0
  87. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/endpoint_literals.py +0 -0
  88. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/endpoint_metrics.py +0 -0
  89. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/entrypoint_classifier.py +0 -0
  90. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/env_analyzer.py +0 -0
  91. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/envelope.py +0 -0
  92. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/error_schema.py +0 -0
  93. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/evidence_provider.py +0 -0
  94. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/explain.py +0 -0
  95. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/file_chunker.py +0 -0
  96. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/file_classifier.py +0 -0
  97. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/filter_surface.py +0 -0
  98. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/format_contract.py +0 -0
  99. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/fqn_utils.py +0 -0
  100. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/git_analyzer.py +0 -0
  101. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/graph_analyzer.py +0 -0
  102. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/graph_evidence.py +0 -0
  103. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/hibernate_strat.py +0 -0
  104. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/integration_coordinates.py +0 -0
  105. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/jdk_exports.py +0 -0
  106. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/mcp/__init__.py +0 -0
  107. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  108. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  109. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  110. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  111. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  112. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/mcp/orchestrator.py +0 -0
  113. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/mcp/runner.py +0 -0
  114. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/mcp_nudge.py +0 -0
  115. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/migrate_check.py +0 -0
  116. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/migration_blast.py +0 -0
  117. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/openapi_surface.py +0 -0
  118. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/output_budget.py +0 -0
  119. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/parse_cache.py +0 -0
  120. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/path_filters.py +0 -0
  121. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/perf.py +0 -0
  122. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/pr_comment_renderer.py +0 -0
  123. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/pr_impact.py +0 -0
  124. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/progress.py +0 -0
  125. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/ranking_engine.py +0 -0
  126. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/readiness_timeline.py +0 -0
  127. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/reconciliation.py +0 -0
  128. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/redactor.py +0 -0
  129. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/relevance_scorer.py +0 -0
  130. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/rename_refactor.py +0 -0
  131. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/repo_classifier.py +0 -0
  132. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/repository_ir.py +0 -0
  133. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/__init__.py +0 -0
  134. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/context.py +0 -0
  135. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/errors.py +0 -0
  136. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/executor.py +0 -0
  137. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/planner.py +0 -0
  138. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/query.py +0 -0
  139. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/request.py +0 -0
  140. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/resolution.py +0 -0
  141. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/result.py +0 -0
  142. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/retriever.py +0 -0
  143. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/runtime.py +0 -0
  144. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/steps.py +0 -0
  145. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
  146. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/steps_graph.py +0 -0
  147. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/steps_impact.py +0 -0
  148. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/steps_intf.py +0 -0
  149. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/steps_struct.py +0 -0
  150. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/retrieval/steps_txsec.py +0 -0
  151. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/runtime_classifier.py +0 -0
  152. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/scanner.py +0 -0
  153. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/schema.py +0 -0
  154. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
  155. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/security_config.py +0 -0
  156. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/security_posture.py +0 -0
  157. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/semantic_analyzer.py +0 -0
  158. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/semantic_impact_engine.py +0 -0
  159. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/semantic_integration_engine.py +0 -0
  160. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/semantic_services.py +0 -0
  161. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/spring_event_topology.py +0 -0
  162. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/spring_findings.py +0 -0
  163. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/spring_impact.py +0 -0
  164. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/spring_model.py +0 -0
  165. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/spring_properties.py +0 -0
  166. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/spring_security_audit.py +0 -0
  167. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/spring_semantic.py +0 -0
  168. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/spring_tx_analyzer.py +0 -0
  169. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/summarizer.py +0 -0
  170. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/telemetry/events.py +0 -0
  171. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/telemetry/filters.py +0 -0
  172. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/telemetry/transport.py +0 -0
  173. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/token_estimate.py +0 -0
  174. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/tree_utils.py +0 -0
  175. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/type_usage_surface.py +0 -0
  176. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/validation_inference.py +0 -0
  177. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/validation_surface.py +0 -0
  178. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/verify_edit.py +0 -0
  179. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/verify_repo.py +0 -0
  180. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/verify_rules.py +0 -0
  181. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/version_check.py +0 -0
  182. {sourcecode-3.2.0 → sourcecode-3.2.2}/src/sourcecode/workspace.py +0 -0
  183. {sourcecode-3.2.0 → sourcecode-3.2.2}/supabase/functions/README.md +0 -0
  184. {sourcecode-3.2.0 → sourcecode-3.2.2}/supabase/functions/get-license/index.ts +0 -0
  185. {sourcecode-3.2.0 → sourcecode-3.2.2}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
  186. {sourcecode-3.2.0 → sourcecode-3.2.2}/supabase/functions/telemetry/index.ts +0 -0
  187. {sourcecode-3.2.0 → sourcecode-3.2.2}/supabase/sql/license_event_ordering.sql +0 -0
  188. {sourcecode-3.2.0 → sourcecode-3.2.2}/supabase/sql/licensing_schema.sql +0 -0
  189. {sourcecode-3.2.0 → sourcecode-3.2.2}/supabase/sql/telemetry_events.sql +0 -0
@@ -1,5 +1,305 @@
1
1
  # Changelog
2
2
 
3
+ ## [Unreleased]
4
+
5
+ ### Changed
6
+
7
+ - **Telemetry is opt-in** (P-1). It was opt-out; with no explicit choice on record, nothing is
8
+ now collected or transmitted — not on the first run, not in CI, nowhere. **An explicit choice
9
+ you made before is honoured unchanged**; if you never chose, telemetry is off.
10
+ - The default was not a preference. Field evaluation #3 was the first audit of regulated
11
+ third-party code (public-sector health data), where the reviewer must be able to state that
12
+ nothing left the machine — and *"disable it after the first run"* cannot give that
13
+ guarantee. It was recorded as a **procurement** blocker, not an analysis defect.
14
+ - The CI special case is gone along with the default it existed to override. CI is still
15
+ detected for exactly one purpose: skipping a first-run notice that has no terminal to
16
+ appear on.
17
+ - The first-run notice is now an **invitation**: it says telemetry is off, states what *would*
18
+ be collected if you enabled it, and names `ask telemetry enable`. It changes no setting.
19
+ - `ask telemetry status` distinguishes **"no choice recorded"** from **"you chose disabled"**
20
+ (`stored_choice()` returns `None`, never a silent `False`) — a buyer auditing this needs to
21
+ know which of the two they have.
22
+
23
+ ## [3.2.2] — 2026-07-29
24
+
25
+ **M7.5 complete — the product now says what it promises.** Three things a user could only
26
+ infer are written down and enforced: which of their commands a warm cache actually helps, what
27
+ a cold run costs where they meet it, and **what each command's output is worth relying on**.
28
+ Documenting the first of those found the cache had two freshness authorities and was answering
29
+ for trees it had not read — the pattern of this cycle, where writing down the promise is what
30
+ exposes where we do not keep it.
31
+
32
+ ### Added
33
+
34
+ - **Command tiers, named and published** (C4-6). Every command now carries one of four tiers —
35
+ `core`, `supported`, `experimental`, `parked` — from a single authority (`cli.COMMAND_TIERS`),
36
+ rendered by `ask --help`, the README command table and the user guide.
37
+ - A tier is a **stability promise**: `core` is safe to gate CI on, `experimental` may change
38
+ shape in a minor, `parked` still works but is no longer developed (empty today, and the help
39
+ says so rather than leaving the row blank).
40
+ - It is **not a value ranking** — `posture` is experimental *and* the first command the help
41
+ recommends — and it is **not the pricing tier**, which gates repository size and never
42
+ capability. Both distinctions are printed, not implied.
43
+ - The battery fails if a registered command sits in no tier, if a tier names a command that
44
+ does not exist, if a command calls itself `[EXPERIMENTAL]` while published in another tier,
45
+ or if either document drifts from the table.
46
+ - Which commands *move* between tiers, and whether `parked` disappears from the default help,
47
+ is the tiering work in M9. This release names the vocabulary before it is used against a
48
+ command.
49
+ - **The cache model is published, per command, and measured.** `ask cache model` (`--json`,
50
+ `--markdown`) and [docs/CACHE.md](docs/CACHE.md) answer the question field evaluation #3 could
51
+ not: *which of my commands does a warm actually help?* One rule for invalidation — every layer
52
+ keys on the exact tree state — then, per command, whether a warm gives it **the answer**, only
53
+ **the shared work**, or **nothing**, with the layers it reads and a measured figure.
54
+ - Which layers each command reads was derived by instrumenting the layers, not by reading the
55
+ code and hoping. What a warm is worth was then timed **per command in isolation**: cleared
56
+ caches, `cache warm`, then the command. Timed in a batch instead, one command warms the next
57
+ and the table lies — `impact-chain` looked unaffected by a warm in a batch and goes 9.9 s →
58
+ 1.7 s in isolation.
59
+ - Two measured results contradict the obvious assumption and are published as such: a warm
60
+ buys **`endpoints` nothing** (2.8 s → 2.9 s) and **`migrate-check` nothing** (4.8 s → 4.8 s),
61
+ and on a small diff it makes `review-pr` *slower* (1.1 s → 2.3 s) because loading the warmed
62
+ IR costs more than the work it saves.
63
+ - The battery fails if a registered command has no row, if the model names a command that does
64
+ not exist, if a row claims a warm helps while reading no layer a warm builds, or if
65
+ `docs/CACHE.md` has drifted from the registry. This is the `--help` lesson (C4-1) applied: a
66
+ curated list beside a generated one drifts.
67
+ - **`cache warm` states its cost and its limits when it finishes** (C4-5): elapsed time, what it
68
+ warmed, what it did **not** — `prepare-context` task answers, runs whose analysis flags differ,
69
+ and the two commands measured to gain nothing — plus the line that matters in CI: without a
70
+ persisted `~/.sourcecode`, every pipeline pays that time again. `cache warm --help` says it
71
+ before the run, not after.
72
+
73
+ ### Fixed
74
+
75
+ - **One authority for cache freshness: the tree state, never the committed HEAD.** The
76
+ snapshot cache behind the root command keyed on the HEAD sha alone, so it answered for a
77
+ tree it had not read. Reproduced on spring-petclinic: add `spring-boot-starter-data-ldap`
78
+ to a tracked `pom.xml`, do not commit, run `ask --compact` again — the pre-edit analysis
79
+ comes back from `L2_view` with `is_stale: false`, the new dependency invisible. The context
80
+ cache sitting next to it keyed on the exact tree and invalidated correctly, which is why
81
+ field evaluation #3 could only describe the behaviour as *"el modelo de invalidación no
82
+ está documentado y no es predecible"*: there were two models.
83
+ - `cache.worktree_signature` is now the single authority every layer keys on — the root
84
+ command's L1/L2 snapshots, the `prepare-context` task cache, the shared Canonical IR, and
85
+ the RIS bootstrap. One rule describes all of them: **any change to the analysed files
86
+ invalidates, committed or not.** A clean tree keys on the sha, so the ordinary repeat run
87
+ still hits (BroadleafCommerce: 18.1 s cold → 0.3 s warm, unchanged; the signature itself
88
+ costs ~50 ms on that tree, ~140 ms on keycloak).
89
+ - Untracked files are covered by size and mtime: they appear in no diff, so a new file — or
90
+ an edit to one — was invisible to a signature built from `git diff` alone.
91
+ - A tree git cannot describe (no repository, no commit) gets a fingerprint over the size and
92
+ mtime of every non-ignored file. Before, such trees used a **constant** key, so the cache
93
+ answered forever with the first analysis it ever ran; the context cache disabled itself
94
+ instead. Both now cache and both now invalidate.
95
+ - `--scope`-style subdirectory runs sign only their own subtree: an edit in a sibling module
96
+ no longer invalidates the module actually analysed.
97
+ - **RIS staleness answers the question it is asked.** `get_cold_start_context` reported
98
+ `stale: false` for any tree sharing the commit the snapshot was taken at, while carrying
99
+ `has_uncommitted_changes: true` in the same object — two facts about one thing, disagreeing.
100
+ The snapshot now records the tree it describes (`metadata.tree_signature`), and the
101
+ `prepare-context` RIS fast path serves `onboard`/`explain` only when that tree is still the
102
+ one on disk. Snapshots written before this release fall back to the old pair of facts.
103
+ - **`prepare-context --all` and `--include-config` are in the cache key.** They changed the
104
+ answer and were not keyed; the collision could not surface only because the key demanded a
105
+ git sha, and non-git trees cached nothing at all. Now that every tree has a signature, an
106
+ unkeyed flag would be served the other flag's answer.
107
+
108
+ ## [3.2.1] — 2026-07-29
109
+
110
+ **M7 complete — the last four seams, the fact registry, and a `--help` that leads with the
111
+ product.** Every fact ADR-0008 named now has one authority, a registered consumer list and an
112
+ assertion that keeps its emitters agreeing. Two of the four seams closed here were found by
113
+ field evaluation #3 *between the two commands it valued most*, and reproducing them showed
114
+ both were worse than reported.
115
+
116
+ **Upgrade note.** Three published numbers change value. None is a schema break; all are
117
+ corrections, and a pinned threshold may move:
118
+
119
+ - `modernize.summary.statically_unreferenced` grows sharply — the population it is measured
120
+ over never matched its own definition (keycloak 14 → 108, BroadleafCommerce 10 → 36,
121
+ alfresco 13 → 88). `summary.high_coupling_nodes` likewise stops reporting the display cap
122
+ of 20 and reports the measured count.
123
+ - `endpoints --limit N` no longer reports `total: N`. `total` and the security counters
124
+ describe the endpoints the *filters* selected; the new `shown` says how many are listed.
125
+ - `posture` verdicts change on repositories that declare `spring.mvc.servlet.path`: rules are
126
+ matched against the URL the filter chain actually receives, so endpoints previously reported
127
+ `no_rule_matched` — or, with a catch-all behind the rule, `permit_all` — now carry the
128
+ decision the matcher makes. Repositories without a declared servlet path are byte-identical.
129
+
130
+ New keys (`summary.reference_status`, `effective_access.path_basis`, `matched_path`, `shown`,
131
+ and `registries` in both `ask schema` and `ask version`) are additive.
132
+
133
+ ### Changed
134
+
135
+ - **`--help` no longer introduces the product with its weakest 20 %.** The command table was
136
+ ordered by the order commands are registered in the source, so a reader met
137
+ `prepare-context` and `repo-ir` — the two surfaces field evaluation #3 scored lowest —
138
+ before `posture` and `endpoints`, which the same evaluation called "the product". Commands
139
+ are now grouped into ordered panels, led by **Java/Spring analysis — start here**
140
+ (`posture`, `endpoints`, `spring-audit`, `migrate-check`), then *Change and risk*, *Context
141
+ for AI agents*, *Setup and inspection*, and *Experimental*. Nothing is hidden and nothing is
142
+ removed; the ordering is one table (`cli.HELP_PANELS`) and the battery fails if a registered
143
+ command is missing from it, if the table names a command that does not exist, or if the core
144
+ four stop leading the rendering.
145
+ - **The hand-written "Also available:" catalogue is gone.** A curated list beside a generated
146
+ one drifts, and it did: it is how `endpoints` shipped while appearing in no `--help` list at
147
+ all, leaving an evaluator to find the command they valued most inside another command's JSON.
148
+ - **`ask spring-audit --help` now says which gate it is.** `--ci` fails on *any* finding,
149
+ including debt that was already there — the field read it as baseline-relative and concluded
150
+ the gate was unusable on a legacy repository. The help now states the gate is absolute and
151
+ names the baseline-relative one (`ask verify --fail-on new`, `ask pr-impact --fail-on`) and
152
+ `ask baseline` for tracking the debt. A test asserts those commands and flags exist.
153
+
154
+ ### Added
155
+
156
+ - **Invariant I-3 in the battery: every registered fact declares what it says when it cannot
157
+ decide.** ADR-0008 R9 is easy to state and easy to lose — `statically_unreferenced: 0` over
158
+ 3 374 classes is what losing it costs. Each registry entry now carries `unresolved_answer`
159
+ (the outcome the fact emits when undecidable) plus the reason, or `null` with an explanation
160
+ of why the fact is total. A declared outcome must exist in the authority that derives it, so
161
+ the registry cannot document an `unknown` nothing emits — a check that immediately corrected
162
+ two entries where the unresolved answer belongs to the consumer, not the authority.
163
+
164
+ - **Invariant I-2 in the battery: a published count may not come from a truncated list.**
165
+ A static audit over every module (`tests/test_invariant_counts_from_measurement.py`): inside
166
+ one function, a name bound to a slice and then measured with `len()` in a payload position
167
+ fails the suite. Display sizes stay legal under an explicit key (`shown`, `omitted`, …),
168
+ because "how many did you show me" is a different question from "how many are there". The
169
+ audit is itself guarded against being vacuous.
170
+ - It found two live ones. `modernize.summary.high_coupling_nodes` reported the display cap
171
+ (20) as the number of high-coupling classes — a repository with 300 of them said 20; the
172
+ exact count now ships alongside `high_coupling_nodes_shown`. And `endpoints --limit N`
173
+ reported `total: N`: `--limit` cuts the rendering, not the population.
174
+ - **Value change:** with `--limit`, `endpoints` now reports `total` (and the security
175
+ counters) for the endpoints the *filters* selected, plus a new `shown` for how many are
176
+ listed. Before, all of them collapsed to the limit. Filters (`--path-prefix`,
177
+ `--controller`) genuinely change the population and still move `total`.
178
+
179
+ - **The fact registry ADR-0008 asks for (R11), shipped inside the package and enforced.**
180
+ `src/sourcecode/facts/registry.json` names every fact that has a single authority: what it
181
+ means, which `module:symbol` derives it, which modules may emit it, and the parity assertion
182
+ that keeps those emitters agreeing. Read it from an installed version with
183
+ `ask schema facts-v1` — a release states its own contract instead of pointing at
184
+ documentation that can drift from it. No new command: `ask schema` lists it under
185
+ `registries`, beside the output `schemas`.
186
+ - The registry is checked, not asserted: the battery fails if an authority does not exist,
187
+ if a registered consumer does not bind to it (R13 — the LDAP defect survived two releases
188
+ exactly because a consumer was never rebound), or if a fact carries no parity test (R12).
189
+ Writing it found two claims of mine that were untrue and one surface — the endpoint
190
+ security verdict — whose only real consumer is `impact`.
191
+ - Eleven facts registered, one per M7 seam plus the two each seam split apart.
192
+
193
+ ### Fixed
194
+
195
+ - **A repository with no tests at all reported `has_tests: true` and "N test files".** Third
196
+ field evaluation: a Spring monolith whose `src/test` does not exist was described as having
197
+ 4 test files, because production classes living in a package named `test` matched a
198
+ substring rule. The same document's `analysis_gaps` contradicted it — one document, two
199
+ derivations of one fact.
200
+ - New authority `test_sources`: a file is a test source when it sits under a **declared
201
+ test source root** (`src/test`, `src/it`, `src/androidTest`, `src/testFixtures`, or a
202
+ repository-level `tests/`, `spec/`, `__tests__/`) or matches an ecosystem **naming
203
+ convention** (`FooTest.java`, `test_foo.py`, `foo.spec.ts`, `foo_test.go`). A `test`
204
+ package **inside a main source root is production code** — the build tool's own layout
205
+ outranks any name.
206
+ - Five consumers now bind to it instead of re-deriving: `signals.has_tests`, the
207
+ `analysis_gaps` backend-coverage check (which now also states its basis),
208
+ `metrics_analyzer.is_test_file`, `prepare-context`'s test/source split, and the review-pr
209
+ coverage risk.
210
+ - **Value change:** files under a *main* source root in a directory named `test`/`tests`
211
+ stop counting as tests. Measured on the fleet: keycloak 2 220 → 1 777 Java test files
212
+ (443 files under `testsuite/…/src/main/java/…`), BroadleafCommerce 201 → 197,
213
+ spring-petclinic and openmrs-core unchanged.
214
+ - **`review-pr` reported `test_coverage_risk: "low"` for a diff containing no source files.**
215
+ In a repository with no tests, a documentation-only PR read as "covered" — the traffic light
216
+ inverted exactly where a reviewer relies on it. The surface now emits `unknown` with the
217
+ reason (`no source files changed in this diff`, or `repository declares no test sources`),
218
+ plus `changed_source_files` and `repository_has_test_sources`. `low` is now reachable only
219
+ when changed source files were checked and matched (ADR-0008 R9).
220
+
221
+ - **A class was reported as conditional on a profile *and* on its negation, contradicting
222
+ `ask posture` in the same run.** Found in the third field evaluation (3.2.0): a
223
+ configuration class declaring `@Profile("!m3")` — active exactly when `m3` is **absent** —
224
+ appeared in `signals.spring_profiles.profile_conditional_beans` under `m3` as well. Read as
225
+ a security fact, it inverts the answer.
226
+ - Root cause, reproduced: the source scan attributed every `@Profile` to *the next type
227
+ declaration ahead of it*, falling back to the file name when there was none. A
228
+ `@Profile("m3")` on a `@Bean` **method** inside that class was therefore attributed to the
229
+ class itself, next to the class-level `@Profile("!m3")`.
230
+ - Attribution is now the declaration the annotation actually annotates: only annotations
231
+ and modifiers may stand between it and a type declaration; a member-level annotation is
232
+ reported as `Type#member`, and an annotation whose target cannot be read is **not
233
+ reported at all** rather than attributed to a guess (ADR-0008 R9).
234
+ - **Value change:** member-level declarations move from the enclosing type to the member.
235
+ On the reference fleet this affects one symbol (`spring-petclinic`:
236
+ `MysqlTestApplication` → `MysqlTestApplication#container`); on repositories that put
237
+ `@Profile` on `@Bean` methods it affects each such method.
238
+ - New in the payload: `signals.spring_profiles.conditional_beans[]` with `symbol`,
239
+ `profiles`, `expression` (as written) and `source_file`. The token map
240
+ (`profile_conditional_beans`) buckets `@Profile("a & !b")` under `a` and `!b` with the
241
+ operator lost; the list keeps the expression, and both are now projections of **one**
242
+ derivation, so they cannot disagree.
243
+ - Parity assertion added: no symbol may be reported as conditional on a profile that
244
+ `posture` resolves it inactive under (invariant I-1).
245
+
246
+ - **`ask modernize` reported `statically_unreferenced: 0` across a 3 374-class monolith.**
247
+ Read as "there is no unreferenced code here", when what it meant was "a check that cannot
248
+ see framework dispatch found nothing" — the one place the product broke its own rule about
249
+ never publishing a number where the honest answer is `unknown` (ADR-0008 R9). Two causes:
250
+ - The population never matched the published definition. The note said "zero static
251
+ callers", the code examined only types with **no edges in either direction** — so a type
252
+ that calls something but is called by nothing was never a candidate at all.
253
+ - The surface had two buckets and the question has three answers.
254
+ - One authority now derives it, `reference_facts`, as a partition that sums to the classes
255
+ examined: `referenced` (an incoming edge, or another source naming it) /
256
+ `unknown_framework_dispatch` (no static caller, but a published annotation, an entry-point
257
+ signature, or the name wired from a configuration file) / `no_static_callers` (neither —
258
+ **absence of evidence, never "dead code"**). `summary.reference_status` carries the exact
259
+ counts and a `statement` that explains a zero instead of publishing it bare.
260
+ - Counts come from the measurement, not from `len()` of the lists, which are cut to 20 for
261
+ display (R5). Every listed type carries the `basis` for being there.
262
+ - Dispatch detection extended with published stereotype, persistence and entry-point
263
+ vocabulary (`@Component`/`@Service`/`@Repository`/`@Controller`/`@RestController`/
264
+ `@Configuration`/`@Entity`/`@Embeddable`/`@MappedSuperclass`/`@Aspect`/`@WebServlet`/
265
+ `@WebFilter`/`@WebListener`/`@SpringBootApplication`, `public static void main`), and the
266
+ configuration-name scan now matches whole names — `Order` inside `OrderItemImpl` was
267
+ marking live-looking classes dispatched.
268
+ - **Value change:** the candidate population is much larger, so the counts move.
269
+ keycloak 14 → 108 `no_static_callers`, BroadleafCommerce 10 → 36, alfresco 13 → 88;
270
+ spring-petclinic stays 0 and now says why (its one callerless type is an `@Entity`, so
271
+ the answer is `unknown`). The scan is also faster than the one it replaces: one repository
272
+ walk instead of two, and fixed patterns intersected with the candidate set rather than an
273
+ alternation over it (keycloak 2.5 s → 1.2 s).
274
+
275
+ - **`ask posture` decided endpoint access against a URL the application never serves.** A
276
+ repository declaring `spring.mvc.servlet.path=/api` is served at `/api/orders`, and that is
277
+ the URL its filter chain matches — but the chain rules were compared against the
278
+ mapping-relative `/orders`. A rule reading `.antMatchers("/api/**").authenticated()`
279
+ therefore covered nothing. Reported from the field as 2 632 endpoints falsely
280
+ `no_rule_matched`; reproduced in a fixture, it is worse than that — where a catch-all
281
+ `anyRequest().permitAll()` follows the rule, those endpoints were reported **`permit_all`**,
282
+ which states a protected endpoint is open.
283
+ - One authority for the prefix: `deployment_prefix`, the same module `ask endpoints` reads
284
+ for `effective_path`. `posture` asks it for the part a matcher actually sees — the
285
+ **servlet path**, resolved for the profile set you asked about, so a servlet path declared
286
+ only under `prod` applies exactly when `prod` does. The servlet **context** path is
287
+ excluded on purpose: the container strips it before the filter chain runs.
288
+ - Matcher semantics are honoured rather than averaged: `antMatchers`/`regexMatchers` match
289
+ the servlet-path-prefixed URL, `mvcMatchers` matches relative to the servlet mapping, and
290
+ `requestMatchers` is either one depending on the Spring Security version and classpath —
291
+ unreadable from source, so a rule covering the request under either reading is honoured.
292
+ - New in the payload: `effective_access.path_basis` states the servlet path used and where
293
+ it came from, and each stated endpoint carries `matched_path` in its evidence when the
294
+ matched URL differs from the endpoint's mapping-relative path.
295
+ - **Never a guessed URL** (ADR-0008 R9): where a servlet path is declared but cannot be
296
+ resolved (a `${PLACEHOLDER}`, or documents that disagree), every verdict that depends on a
297
+ path pattern is reported `undecided` with `decision_if_unprefixed`, instead of computed
298
+ against an assumed empty prefix.
299
+ - **Value change:** none on a repository that declares no servlet path — the two readings
300
+ coincide and the matching is unchanged. Verified byte-identical on spring-petclinic,
301
+ keycloak, BroadleafCommerce and spaghetti-api, none of which declare one.
302
+
3
303
  ## [3.2.0] — 2026-07-28
4
304
 
5
305
  **Answer coherence (M7, first four seams).** One fact, one authority (ADR-0008). Four
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 3.2.0
3
+ Version: 3.2.2
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
@@ -73,6 +73,19 @@ Cache keyed on content hashes — invalidated only when source changes. On repea
73
73
 
74
74
  At 0.3s per call, ASK Engine becomes **constant infrastructure** inside agent loops — call it before every edit, every PR review, every test run, without batching or caching manually.
75
75
 
76
+ **What a warm actually covers.** `ask cache warm` runs the compact analysis: it rebuilds the
77
+ shared structural layers (L1/L2 + the Repository Intelligence Snapshot + the shared Canonical
78
+ IR) and the **compact view**. Pass `--agent` to warm the agent view as well. Deeper projections
79
+ are separate keys and are *not* covered by either — `--full`, `--env-map` and a raised `--depth`
80
+ recompute on first use, as do most `prepare-context` tasks. Measured on a 3,342-file Spring
81
+ monolith: `cache warm` 103s → `--compact --git-context` 1s (hit), but `--agent --full --env-map
82
+ --depth 20` still 171s (miss).
83
+
84
+ **One rule for invalidation, and a table that names every command.** Every layer keys on the
85
+ exact tree state: any change to the analysed files invalidates it, committed or not. Which of
86
+ *your* commands a warm helps — the answer, only the shared work, or nothing — is published per
87
+ command: `ask cache model`, or [docs/CACHE.md](docs/CACHE.md).
88
+
76
89
  ---
77
90
 
78
91
  ## Install
@@ -95,27 +108,55 @@ ask version # ask 2.5.1
95
108
 
96
109
  ## Quickstart
97
110
 
111
+ **Start with these four.** In three independent field evaluations they carried most of the
112
+ measured value, and `posture --diff` is the one no evaluator found an equivalent for —
113
+ commercial or open source.
114
+
98
115
  ```bash
99
- # High-signal structural summarywarm cache ~0.3s, cold 2–10s
100
- ask --compact
116
+ # What does each profile set ACTUALLY wire and what changes between them?
117
+ # Resolves conditional beans and the filter chain, then diffs effective endpoint access.
118
+ ask posture /path/to/repo --diff dev:prod
101
119
 
102
- # Blast radius: what breaks if this class changes?
103
- ask impact OrderService /path/to/repo
120
+ # Every REST endpoint with its effective path (context-path + servlet path resolved),
121
+ # its inferred security policy and a confidence per endpoint.
122
+ ask endpoints /path/to/repo
123
+
124
+ # Spring semantic audit: transactional anomalies (private @Transactional = silent
125
+ # CGLIB no-op), security surface, request-body validation.
126
+ ask spring-audit /path/to/repo
104
127
 
105
- # Spring Boot 2→3 migration readiness (bounded decision summary)
128
+ # Spring Boot 2→3 readiness: located blockers, per-dimension score, effort estimate.
106
129
  ask migrate-check /path/to/repo --compact
130
+ ```
107
131
 
108
- # Spring semantic audit: TX anomalies + security surface
109
- ask spring-audit /path/to/repo
132
+ Then the everyday loop:
133
+
134
+ ```bash
135
+ # High-signal structural summary — warm cache ~0.3s, cold 2–10s
136
+ ask --compact
137
+
138
+ # Blast radius: what breaks if this class changes? (target the INTERFACE, not the Impl)
139
+ ask impact OrderService /path/to/repo
110
140
 
111
141
  # Onboard to an unfamiliar codebase
112
142
  ask onboard /path/to/repo
113
143
 
114
144
  # PR review: risk, test gaps, changed modules
115
145
  ask review-pr /path/to/repo --since main
146
+
147
+ # CI gate on NEW violations only, instead of on pre-existing debt
148
+ ask verify /path/to/repo --capture-baseline # accept today's debt, once
149
+ ask verify /path/to/repo # then: only new violations block
116
150
  ```
117
151
 
118
- Full command reference: **[docs/USER_GUIDE.md](docs/USER_GUIDE.md)**.
152
+ > **Adopting a gate on a real codebase.** A repository that starts declaring contracts already
153
+ > violates them somewhere; `ask verify` is **baseline-relative by default** (`--fail-on new`)
154
+ > so the gate survives contact with reality instead of being switched off on day one.
155
+ > `ask baseline capture|diff|trend` is a different thing: versioned architectural metrics over
156
+ > time, for trend reporting rather than blocking.
157
+
158
+ Full command reference: **[docs/USER_GUIDE.md](docs/USER_GUIDE.md)** · posture in depth:
159
+ **[docs/posture.md](docs/posture.md)**.
119
160
 
120
161
  ---
121
162
 
@@ -148,17 +189,76 @@ Deterministic Spring semantics: transactional anomalies (e.g. `@Transactional` o
148
189
  `ask spring-audit` · `ask validation`
149
190
  → [reference](docs/USER_GUIDE.md#core-commands)
150
191
 
192
+ ### 5b · Runtime Posture *(experimental — and the most differentiated thing here)*
193
+ What a profile set **actually wires**: which conditional beans register, which do not, and which conditions could not be decided at all — then the effective endpoint access that follows from the filter chain. `--diff` answers the question nobody else answers in one command: *what changes between `dev` and `prod`, across every endpoint at once.*
194
+ `ask posture` · `ask posture --diff dev:prod` · `ask posture --property k=v`
195
+ → [posture.md](docs/posture.md)
196
+
197
+ Unresolved is a first-class outcome: a condition the resolver cannot decide is reported as a
198
+ hole with the condition named, never folded into active or inactive. **A posture answer that
199
+ guesses is a confident security falsehood — the worst failure mode this tool has.**
200
+
151
201
  ### 6 · Developer Workflows
152
202
  The everyday loop: diff-based PR review, symptom-driven bug triage, and delta context for continuous agent runs.
153
203
  `ask review-pr` · `ask fix-bug` · `ask prepare-context`
154
204
  → [reference](docs/USER_GUIDE.md#typical-workflows)
155
205
 
156
206
  ### 7 · Utilities
157
- `ask rename-class` (word-boundary Java rename) · `ask chunk-file` (split large files for agents) · `ask cache` (status / warm / clear / freshness)
207
+ `ask rename-class` (word-boundary Java rename) · `ask chunk-file` (split large files for agents) · `ask cache` (status / warm / model / clear / freshness)
158
208
  → [reference](docs/USER_GUIDE.md)
159
209
 
160
210
  ---
161
211
 
212
+ ## Command tiers
213
+
214
+ A tier says **what an output is worth relying on** — it is a stability promise, not a value
215
+ ranking, and not the [pricing tier](docs/PRODUCT_TIERS.md) (Free/Pro gates repository size,
216
+ never capability). `posture` is the most differentiated command in the product *and* it is
217
+ experimental: both are true, and they are two different facts.
218
+
219
+ | Tier | Promise | Commands |
220
+ |---|---|---|
221
+ | **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
222
+ | **supported** | maintained; fields are added, never removed without a major | every command not named in another row |
223
+ | **experimental** | shape may change in a minor — do not gate CI on it | `posture` · `archetype` · `retrieve` |
224
+ | **parked** | kept working, no longer developed | none today |
225
+
226
+ The same table is printed by `ask --help`, and both are generated from one authority
227
+ (`cli.COMMAND_TIERS`) — the battery fails if a command is in no tier, or if this file drifts
228
+ from it.
229
+
230
+ ---
231
+
232
+ ## Every command, in one table
233
+
234
+ *`ask --help` shows a short header; this is the full surface. If you only read one row, read
235
+ `posture`.*
236
+
237
+ | Command | Tier | Answers | Note |
238
+ |---|---|---|---|
239
+ | `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
240
+ | `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators) |
241
+ | `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment` |
242
+ | `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan |
243
+ | `impact` / `impact-chain` | core | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
244
+ | `pr-impact` | core | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
245
+ | `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
246
+ | `verify-edit` | supported | did the working-tree edits change runtime behaviour | semantic diff gate for the edit loop |
247
+ | `--compact` / `--agent` | — | bounded structural context for an agent | flags of the root command, not commands: not tiered |
248
+ | `onboard` / `explain` / `cold-start` | supported | orientation in an unfamiliar repo; per-class summary; bootstrap snapshot | |
249
+ | `export` / `repo-ir` / `schema` | supported | tool-agnostic views (C4, module graph, integrations); symbol-level IR; published JSON Schemas | |
250
+ | `modernize` | supported | coupling hubs, cycles, dead zones, refactor candidates | |
251
+ | `review-pr` / `fix-bug` / `prepare-context` | supported | diff review, symptom triage, task-shaped context | |
252
+ | `plan` / `compare` / `delta` / `contract-diff` | supported | what to review for a change; candidates by measured cost; outcome of a change; public-contract break | no verdicts, measured cost only |
253
+ | `validation` | supported | request-body validation coverage and gaps | |
254
+ | `baseline capture\|diff\|trend` | supported | versioned architectural metrics over time | trend reporting, not gating |
255
+ | `retrieve` | experimental | typed knowledge queries over the model | |
256
+ | `archetype` | experimental | evidence-based architectural archetype | |
257
+ | `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
258
+ | `cache status\|warm\|model\|clear` · `auth` · `telemetry` · `mcp` · `config` · `version` | supported | housekeeping | `activate` too |
259
+
260
+ ---
261
+
162
262
  ## What it does — and doesn't
163
263
 
164
264
  **ASK Engine reduces exploration cost.** It accelerates context acquisition and computes
@@ -182,6 +282,13 @@ Honest limits worth knowing before you rely on it:
182
282
  > **🎉 Early-adoption: Pro is currently unlocked for everyone.** Every install runs with
183
283
  > full Pro entitlements — no size gate, no key. The tiers below describe the model the
184
284
  > paywall will return to later.
285
+ >
286
+ > **What that means concretely.** `ask auth status` reports `"status": "unauthenticated"`
287
+ > together with `"pro": true`, `"pro_reason": "early-adoption unlock"` — that combination is
288
+ > expected, not a bug: you are unauthenticated *and* unlocked. When the unlock ends, gating
289
+ > returns **by repo size and automation, never by command**: `posture`, `endpoints`,
290
+ > `spring-audit` and `migrate-check` stay in the base tier at full output. Nothing you can run
291
+ > today becomes a paid-only command tomorrow.
185
292
 
186
293
  **Gating is by repo size and automation — never by command.** Every command runs at full
187
294
  power on Free for small and mid-size repos; you upgrade when the work gets bigger or automated.
@@ -204,12 +311,18 @@ Full breakdown: [docs/PRODUCT_TIERS.md](docs/PRODUCT_TIERS.md).
204
311
 
205
312
  ```bash
206
313
  ask config # version, config file path, telemetry status
207
- ask telemetry disable # anonymous telemetry is on by default (opt-out)
314
+ ask telemetry enable # anonymous telemetry is OFF by default (opt-in)
208
315
  ```
209
316
 
210
- Telemetry collects version, OS, commands, flags, duration, repo-size range, and errors
211
- **no source code, paths, secrets, or output**. Disable any time with
212
- `export SOURCECODE_TELEMETRY=0` (or `DO_NOT_TRACK=1`).
317
+ **Nothing is collected or transmitted unless you turn telemetry on** not on the first run,
318
+ not in CI. If you do opt in, it collects version, OS, commands, flags, duration, repo-size
319
+ range, and errors: **no source code, paths, secrets, or output**. Turn it off again with
320
+ `ask telemetry disable`, `export SOURCECODE_TELEMETRY=0`, or `DO_NOT_TRACK=1`.
321
+
322
+ > **Auditing someone else's code — regulated, client-owned or public-sector?** Nothing to do.
323
+ > Telemetry was opt-out until 3.3.0; it is opt-in now (`docs/DEFECT-LEDGER.md` P-1), because a
324
+ > default you must remember to disable is the wrong default for third-party code. An explicit
325
+ > choice you made before is unchanged.
213
326
 
214
327
  **Custom security annotations.** Teach `endpoints`, `spring-audit`, and `explain` about
215
328
  project-specific authorization annotations via an optional `sourcecode.config.json` at the
@@ -241,3 +354,4 @@ Matching endpoints report `policy: "custom"` and drop out of the `no_security_si
241
354
  | [MANUAL-USUARIO.md](docs/MANUAL-USUARIO.md) | Guía de usuario en español |
242
355
  | [PRODUCT_IDENTITY.md](docs/PRODUCT_IDENTITY.md) | `ask` (command) vs `sourcecode` (package/alias) |
243
356
  | [privacy.md](docs/privacy.md) | Telemetry and data-handling policy |
357
+ | [DEFECT-LEDGER.md](docs/DEFECT-LEDGER.md) | Every defect found in the field, its class, and which release closed it — published on purpose |