sourcecode 3.2.1__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.
- {sourcecode-3.2.1 → sourcecode-3.2.2}/CHANGELOG.md +105 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/PKG-INFO +64 -40
- {sourcecode-3.2.1 → sourcecode-3.2.2}/README.md +63 -39
- {sourcecode-3.2.1 → sourcecode-3.2.2}/pyproject.toml +1 -1
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/__init__.py +1 -1
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/cache.py +104 -0
- sourcecode-3.2.2/src/sourcecode/cache_model.py +295 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/cli.py +201 -29
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/context_cache.py +7 -27
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/license.py +1 -1
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/mcp/server.py +2 -2
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/prepare_context.py +7 -7
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/ris.py +27 -1
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/telemetry/__init__.py +4 -3
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/telemetry/config.py +31 -23
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/telemetry/consent.py +20 -16
- {sourcecode-3.2.1 → sourcecode-3.2.2}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/.gitignore +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/.ruff.toml +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/CONTRIBUTING.md +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/LICENSE +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/SECURITY.md +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/raw +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/scripts/compare_integration_engines.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/scripts/customer_smoke_test.sh +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/scripts/generate_jdk_exports.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/scripts/perf_harness.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/archetype.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/architectural_baseline.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/architectural_delta.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/call_surface.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/caller_metrics.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/chain_rules.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/change_plan.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/classifier.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/compare.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/constraint_diff.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/context_graph.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/contract_diff.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/deployment_prefix.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/dynamic_argument_surface.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/endpoint_literals.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/endpoint_metrics.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/envelope.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/evidence_provider.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/explain.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/facts/__init__.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/facts/registry.json +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/filter_surface.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/format_contract.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/graph_evidence.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/hibernate_strat.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/integration_coordinates.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/jdk_exports.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/migrate_check.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/migration_blast.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/parse_cache.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/perf.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/posture.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/progress.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/readiness_timeline.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/reconciliation.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/redactor.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/reference_facts.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/repository_ir.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/__init__.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/context.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/errors.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/executor.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/planner.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/query.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/request.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/resolution.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/result.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/retriever.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/runtime.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/steps.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/steps_graph.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/steps_impact.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/steps_intf.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/steps_struct.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/retrieval/steps_txsec.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/scanner.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/schema.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/security_config.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/security_posture.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/semantic_impact_engine.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/semantic_integration_engine.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/semantic_services.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/serializer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/spring_findings.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/spring_impact.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/spring_profiles.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/spring_properties.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/spring_security_audit.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/spring_tx_analyzer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/test_sources.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/token_estimate.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/type_usage_surface.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/validation_inference.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/validation_surface.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/verify_edit.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/verify_repo.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/verify_rules.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/version_check.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/src/sourcecode/workspace.py +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/supabase/functions/README.md +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/supabase/sql/licensing_schema.sql +0 -0
- {sourcecode-3.2.1 → sourcecode-3.2.2}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -1,5 +1,110 @@
|
|
|
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
|
+
|
|
3
108
|
## [3.2.1] — 2026-07-29
|
|
4
109
|
|
|
5
110
|
**M7 complete — the last four seams, the fact registry, and a `--help` that leads with the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 3.2.
|
|
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
|
|
@@ -74,13 +74,17 @@ Cache keyed on content hashes — invalidated only when source changes. On repea
|
|
|
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
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
|
|
78
|
-
view**. Pass `--agent` to warm the agent view as well. Deeper projections
|
|
79
|
-
keys and are *not* covered by either — `--full`, `--env-map` and a raised `--depth`
|
|
80
|
-
on first use, as do most `prepare-context` tasks. Measured on a 3,342-file Spring
|
|
81
|
-
`cache warm` 103s → `--compact --git-context` 1s (hit), but `--agent --full --env-map
|
|
82
|
-
--depth 20` still 171s (miss).
|
|
83
|
-
|
|
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).
|
|
84
88
|
|
|
85
89
|
---
|
|
86
90
|
|
|
@@ -200,38 +204,58 @@ The everyday loop: diff-based PR review, symptom-driven bug triage, and delta co
|
|
|
200
204
|
→ [reference](docs/USER_GUIDE.md#typical-workflows)
|
|
201
205
|
|
|
202
206
|
### 7 · Utilities
|
|
203
|
-
`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)
|
|
204
208
|
→ [reference](docs/USER_GUIDE.md)
|
|
205
209
|
|
|
206
210
|
---
|
|
207
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
|
+
|
|
208
232
|
## Every command, in one table
|
|
209
233
|
|
|
210
234
|
*`ask --help` shows a short header; this is the full surface. If you only read one row, read
|
|
211
235
|
`posture`.*
|
|
212
236
|
|
|
213
|
-
| Command | Answers | Note |
|
|
214
|
-
|
|
215
|
-
| `posture` | which beans a profile set wires, and how effective endpoint access differs between two sets |
|
|
216
|
-
| `endpoints` | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators) |
|
|
217
|
-
| `spring-audit` | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment` |
|
|
218
|
-
| `migrate-check` | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan |
|
|
219
|
-
| `impact` / `impact-chain` | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
|
|
220
|
-
| `pr-impact` | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
|
|
221
|
-
| `verify` | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
|
|
222
|
-
| `verify-edit` | did the working-tree edits change runtime behaviour | semantic diff gate for the edit loop |
|
|
223
|
-
| `--compact` / `--agent` | bounded structural context for an agent |
|
|
224
|
-
| `onboard` / `explain` / `cold-start` | orientation in an unfamiliar repo; per-class summary; bootstrap snapshot | |
|
|
225
|
-
| `export` / `repo-ir` / `schema` | tool-agnostic views (C4, module graph, integrations); symbol-level IR; published JSON Schemas | |
|
|
226
|
-
| `modernize` | coupling hubs, cycles, dead zones, refactor candidates | |
|
|
227
|
-
| `review-pr` / `fix-bug` / `prepare-context` | diff review, symptom triage, task-shaped context | |
|
|
228
|
-
| `plan` / `compare` / `delta` / `contract-diff` | what to review for a change; candidates by measured cost; outcome of a change; public-contract break | no verdicts, measured cost only |
|
|
229
|
-
| `validation` | request-body validation coverage and gaps | |
|
|
230
|
-
| `baseline capture\|diff\|trend` | versioned architectural metrics over time | trend reporting, not gating |
|
|
231
|
-
| `retrieve` | typed knowledge queries over the model |
|
|
232
|
-
| `archetype` | evidence-based architectural archetype |
|
|
233
|
-
| `rename-class` / `chunk-file` | word-boundary Java rename; split a large file for an agent | |
|
|
234
|
-
| `cache status\|warm\|clear` · `auth` · `telemetry` · `mcp` · `config` · `version` | housekeeping | |
|
|
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 |
|
|
235
259
|
|
|
236
260
|
---
|
|
237
261
|
|
|
@@ -287,18 +311,18 @@ Full breakdown: [docs/PRODUCT_TIERS.md](docs/PRODUCT_TIERS.md).
|
|
|
287
311
|
|
|
288
312
|
```bash
|
|
289
313
|
ask config # version, config file path, telemetry status
|
|
290
|
-
ask telemetry
|
|
314
|
+
ask telemetry enable # anonymous telemetry is OFF by default (opt-in)
|
|
291
315
|
```
|
|
292
316
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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`.
|
|
296
321
|
|
|
297
|
-
> **Auditing someone else's code — regulated, client-owned or public-sector?**
|
|
298
|
-
>
|
|
299
|
-
>
|
|
300
|
-
>
|
|
301
|
-
> wrong default for third-party code.
|
|
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.
|
|
302
326
|
|
|
303
327
|
**Custom security annotations.** Teach `endpoints`, `spring-audit`, and `explain` about
|
|
304
328
|
project-specific authorization annotations via an optional `sourcecode.config.json` at the
|
|
@@ -36,13 +36,17 @@ Cache keyed on content hashes — invalidated only when source changes. On repea
|
|
|
36
36
|
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.
|
|
37
37
|
|
|
38
38
|
**What a warm actually covers.** `ask cache warm` runs the compact analysis: it rebuilds the
|
|
39
|
-
shared structural layers (L1/L2 + the Repository Intelligence Snapshot
|
|
40
|
-
view**. Pass `--agent` to warm the agent view as well. Deeper projections
|
|
41
|
-
keys and are *not* covered by either — `--full`, `--env-map` and a raised `--depth`
|
|
42
|
-
on first use, as do most `prepare-context` tasks. Measured on a 3,342-file Spring
|
|
43
|
-
`cache warm` 103s → `--compact --git-context` 1s (hit), but `--agent --full --env-map
|
|
44
|
-
--depth 20` still 171s (miss).
|
|
45
|
-
|
|
39
|
+
shared structural layers (L1/L2 + the Repository Intelligence Snapshot + the shared Canonical
|
|
40
|
+
IR) and the **compact view**. Pass `--agent` to warm the agent view as well. Deeper projections
|
|
41
|
+
are separate keys and are *not* covered by either — `--full`, `--env-map` and a raised `--depth`
|
|
42
|
+
recompute on first use, as do most `prepare-context` tasks. Measured on a 3,342-file Spring
|
|
43
|
+
monolith: `cache warm` 103s → `--compact --git-context` 1s (hit), but `--agent --full --env-map
|
|
44
|
+
--depth 20` still 171s (miss).
|
|
45
|
+
|
|
46
|
+
**One rule for invalidation, and a table that names every command.** Every layer keys on the
|
|
47
|
+
exact tree state: any change to the analysed files invalidates it, committed or not. Which of
|
|
48
|
+
*your* commands a warm helps — the answer, only the shared work, or nothing — is published per
|
|
49
|
+
command: `ask cache model`, or [docs/CACHE.md](docs/CACHE.md).
|
|
46
50
|
|
|
47
51
|
---
|
|
48
52
|
|
|
@@ -162,38 +166,58 @@ The everyday loop: diff-based PR review, symptom-driven bug triage, and delta co
|
|
|
162
166
|
→ [reference](docs/USER_GUIDE.md#typical-workflows)
|
|
163
167
|
|
|
164
168
|
### 7 · Utilities
|
|
165
|
-
`ask rename-class` (word-boundary Java rename) · `ask chunk-file` (split large files for agents) · `ask cache` (status / warm / clear / freshness)
|
|
169
|
+
`ask rename-class` (word-boundary Java rename) · `ask chunk-file` (split large files for agents) · `ask cache` (status / warm / model / clear / freshness)
|
|
166
170
|
→ [reference](docs/USER_GUIDE.md)
|
|
167
171
|
|
|
168
172
|
---
|
|
169
173
|
|
|
174
|
+
## Command tiers
|
|
175
|
+
|
|
176
|
+
A tier says **what an output is worth relying on** — it is a stability promise, not a value
|
|
177
|
+
ranking, and not the [pricing tier](docs/PRODUCT_TIERS.md) (Free/Pro gates repository size,
|
|
178
|
+
never capability). `posture` is the most differentiated command in the product *and* it is
|
|
179
|
+
experimental: both are true, and they are two different facts.
|
|
180
|
+
|
|
181
|
+
| Tier | Promise | Commands |
|
|
182
|
+
|---|---|---|
|
|
183
|
+
| **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
|
|
184
|
+
| **supported** | maintained; fields are added, never removed without a major | every command not named in another row |
|
|
185
|
+
| **experimental** | shape may change in a minor — do not gate CI on it | `posture` · `archetype` · `retrieve` |
|
|
186
|
+
| **parked** | kept working, no longer developed | none today |
|
|
187
|
+
|
|
188
|
+
The same table is printed by `ask --help`, and both are generated from one authority
|
|
189
|
+
(`cli.COMMAND_TIERS`) — the battery fails if a command is in no tier, or if this file drifts
|
|
190
|
+
from it.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
170
194
|
## Every command, in one table
|
|
171
195
|
|
|
172
196
|
*`ask --help` shows a short header; this is the full surface. If you only read one row, read
|
|
173
197
|
`posture`.*
|
|
174
198
|
|
|
175
|
-
| Command | Answers | Note |
|
|
176
|
-
|
|
177
|
-
| `posture` | which beans a profile set wires, and how effective endpoint access differs between two sets |
|
|
178
|
-
| `endpoints` | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators) |
|
|
179
|
-
| `spring-audit` | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment` |
|
|
180
|
-
| `migrate-check` | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan |
|
|
181
|
-
| `impact` / `impact-chain` | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
|
|
182
|
-
| `pr-impact` | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
|
|
183
|
-
| `verify` | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
|
|
184
|
-
| `verify-edit` | did the working-tree edits change runtime behaviour | semantic diff gate for the edit loop |
|
|
185
|
-
| `--compact` / `--agent` | bounded structural context for an agent |
|
|
186
|
-
| `onboard` / `explain` / `cold-start` | orientation in an unfamiliar repo; per-class summary; bootstrap snapshot | |
|
|
187
|
-
| `export` / `repo-ir` / `schema` | tool-agnostic views (C4, module graph, integrations); symbol-level IR; published JSON Schemas | |
|
|
188
|
-
| `modernize` | coupling hubs, cycles, dead zones, refactor candidates | |
|
|
189
|
-
| `review-pr` / `fix-bug` / `prepare-context` | diff review, symptom triage, task-shaped context | |
|
|
190
|
-
| `plan` / `compare` / `delta` / `contract-diff` | what to review for a change; candidates by measured cost; outcome of a change; public-contract break | no verdicts, measured cost only |
|
|
191
|
-
| `validation` | request-body validation coverage and gaps | |
|
|
192
|
-
| `baseline capture\|diff\|trend` | versioned architectural metrics over time | trend reporting, not gating |
|
|
193
|
-
| `retrieve` | typed knowledge queries over the model |
|
|
194
|
-
| `archetype` | evidence-based architectural archetype |
|
|
195
|
-
| `rename-class` / `chunk-file` | word-boundary Java rename; split a large file for an agent | |
|
|
196
|
-
| `cache status\|warm\|clear` · `auth` · `telemetry` · `mcp` · `config` · `version` | housekeeping | |
|
|
199
|
+
| Command | Tier | Answers | Note |
|
|
200
|
+
|---|---|---|---|
|
|
201
|
+
| `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
|
|
202
|
+
| `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators) |
|
|
203
|
+
| `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment` |
|
|
204
|
+
| `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan |
|
|
205
|
+
| `impact` / `impact-chain` | core | blast radius of a change, to the endpoints it reaches | target the **interface**, not the `Impl` |
|
|
206
|
+
| `pr-impact` | core | the same, scoped to a PR diff | gating command: `--fail-on`, exit codes |
|
|
207
|
+
| `verify` | core | does the repo satisfy its declared contracts, **relative to a baseline** | `.ask/contracts.yml`; exit 0/1/2 |
|
|
208
|
+
| `verify-edit` | supported | did the working-tree edits change runtime behaviour | semantic diff gate for the edit loop |
|
|
209
|
+
| `--compact` / `--agent` | — | bounded structural context for an agent | flags of the root command, not commands: not tiered |
|
|
210
|
+
| `onboard` / `explain` / `cold-start` | supported | orientation in an unfamiliar repo; per-class summary; bootstrap snapshot | |
|
|
211
|
+
| `export` / `repo-ir` / `schema` | supported | tool-agnostic views (C4, module graph, integrations); symbol-level IR; published JSON Schemas | |
|
|
212
|
+
| `modernize` | supported | coupling hubs, cycles, dead zones, refactor candidates | |
|
|
213
|
+
| `review-pr` / `fix-bug` / `prepare-context` | supported | diff review, symptom triage, task-shaped context | |
|
|
214
|
+
| `plan` / `compare` / `delta` / `contract-diff` | supported | what to review for a change; candidates by measured cost; outcome of a change; public-contract break | no verdicts, measured cost only |
|
|
215
|
+
| `validation` | supported | request-body validation coverage and gaps | |
|
|
216
|
+
| `baseline capture\|diff\|trend` | supported | versioned architectural metrics over time | trend reporting, not gating |
|
|
217
|
+
| `retrieve` | experimental | typed knowledge queries over the model | |
|
|
218
|
+
| `archetype` | experimental | evidence-based architectural archetype | |
|
|
219
|
+
| `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
|
|
220
|
+
| `cache status\|warm\|model\|clear` · `auth` · `telemetry` · `mcp` · `config` · `version` | supported | housekeeping | `activate` too |
|
|
197
221
|
|
|
198
222
|
---
|
|
199
223
|
|
|
@@ -249,18 +273,18 @@ Full breakdown: [docs/PRODUCT_TIERS.md](docs/PRODUCT_TIERS.md).
|
|
|
249
273
|
|
|
250
274
|
```bash
|
|
251
275
|
ask config # version, config file path, telemetry status
|
|
252
|
-
ask telemetry
|
|
276
|
+
ask telemetry enable # anonymous telemetry is OFF by default (opt-in)
|
|
253
277
|
```
|
|
254
278
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
279
|
+
**Nothing is collected or transmitted unless you turn telemetry on** — not on the first run,
|
|
280
|
+
not in CI. If you do opt in, it collects version, OS, commands, flags, duration, repo-size
|
|
281
|
+
range, and errors: **no source code, paths, secrets, or output**. Turn it off again with
|
|
282
|
+
`ask telemetry disable`, `export SOURCECODE_TELEMETRY=0`, or `DO_NOT_TRACK=1`.
|
|
258
283
|
|
|
259
|
-
> **Auditing someone else's code — regulated, client-owned or public-sector?**
|
|
260
|
-
>
|
|
261
|
-
>
|
|
262
|
-
>
|
|
263
|
-
> wrong default for third-party code.
|
|
284
|
+
> **Auditing someone else's code — regulated, client-owned or public-sector?** Nothing to do.
|
|
285
|
+
> Telemetry was opt-out until 3.3.0; it is opt-in now (`docs/DEFECT-LEDGER.md` P-1), because a
|
|
286
|
+
> default you must remember to disable is the wrong default for third-party code. An explicit
|
|
287
|
+
> choice you made before is unchanged.
|
|
264
288
|
|
|
265
289
|
**Custom security annotations.** Teach `endpoints`, `spring-audit`, and `explain` about
|
|
266
290
|
project-specific authorization annotations via an optional `sourcecode.config.json` at the
|
|
@@ -178,6 +178,110 @@ def _get_git_head(repo_root: Path) -> str:
|
|
|
178
178
|
return ""
|
|
179
179
|
|
|
180
180
|
|
|
181
|
+
#: Directories never read as source, so their contents cannot change an answer.
|
|
182
|
+
#: Used only by the non-git fingerprint below (git ignores them by .gitignore).
|
|
183
|
+
_SIG_SKIP_DIRS: frozenset[str] = frozenset({
|
|
184
|
+
".git", ".hg", ".svn", "target", "build", "out", "dist", "bin",
|
|
185
|
+
"node_modules", ".gradle", ".idea", ".vscode", "__pycache__", ".venv",
|
|
186
|
+
"venv", ".sourcecode-cache", ".mypy_cache", ".pytest_cache",
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _untracked_tree_fingerprint(target: Path) -> str:
|
|
191
|
+
"""Fingerprint of a tree git cannot describe (no repository, or no commit).
|
|
192
|
+
|
|
193
|
+
Hashes ``(relative path, size, mtime_ns)`` of every non-ignored file. It is a
|
|
194
|
+
fingerprint of the tree, not of a commit — which is the point: without it the
|
|
195
|
+
key for a non-git tree is constant, and the cache answers forever with the
|
|
196
|
+
first analysis it ever ran.
|
|
197
|
+
"""
|
|
198
|
+
h = hashlib.sha256()
|
|
199
|
+
try:
|
|
200
|
+
root = Path(target).resolve()
|
|
201
|
+
for dirpath, dirnames, filenames in os.walk(root):
|
|
202
|
+
dirnames[:] = sorted(d for d in dirnames if d not in _SIG_SKIP_DIRS)
|
|
203
|
+
for name in sorted(filenames):
|
|
204
|
+
p = Path(dirpath) / name
|
|
205
|
+
try:
|
|
206
|
+
st = p.stat()
|
|
207
|
+
except OSError:
|
|
208
|
+
continue
|
|
209
|
+
h.update(str(p.relative_to(root)).encode("utf-8", "replace"))
|
|
210
|
+
h.update(f"\x00{st.st_size}\x00{st.st_mtime_ns}\x00".encode())
|
|
211
|
+
except Exception:
|
|
212
|
+
return ""
|
|
213
|
+
return f"ff{h.hexdigest()[:14]}"
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def worktree_signature(repo_root: Path, scope: Optional[Path] = None) -> str:
|
|
217
|
+
"""Hex fingerprint of the **exact tree state an analysis would read**.
|
|
218
|
+
|
|
219
|
+
This is the single authority for cache freshness (ADR-0008): every layer that
|
|
220
|
+
stores an answer about the tree keys on this, so one rule describes them all —
|
|
221
|
+
*any change to the analysed files invalidates, committed or not*. Keying on the
|
|
222
|
+
committed HEAD alone made the root command serve an answer for a tree it had
|
|
223
|
+
not read: a dependency added to an uncommitted ``pom.xml`` stayed invisible
|
|
224
|
+
while the payload reported ``is_stale: false``.
|
|
225
|
+
|
|
226
|
+
Clean tree → the HEAD sha, so repeated runs hit. Dirty tree → HEAD plus a hash
|
|
227
|
+
of the porcelain status, the diff against HEAD, and the size/mtime of untracked
|
|
228
|
+
files (whose bytes the diff does not carry). *scope* restricts the status and
|
|
229
|
+
the diff to a subdirectory, so an edit in a sibling module does not invalidate
|
|
230
|
+
the module actually analysed.
|
|
231
|
+
|
|
232
|
+
Returns hex only — cache file names embed it and the GC parses them. Empty
|
|
233
|
+
string when the tree cannot be described at all; callers then skip the cache.
|
|
234
|
+
"""
|
|
235
|
+
root = Path(repo_root)
|
|
236
|
+
head = _get_git_head(root)
|
|
237
|
+
if not head:
|
|
238
|
+
return _untracked_tree_fingerprint(scope if scope is not None else root)
|
|
239
|
+
|
|
240
|
+
pathspec: list[str] = []
|
|
241
|
+
try:
|
|
242
|
+
if scope is not None and Path(scope).resolve() != root.resolve():
|
|
243
|
+
pathspec = ["--", str(Path(scope).resolve())]
|
|
244
|
+
except Exception:
|
|
245
|
+
pathspec = []
|
|
246
|
+
|
|
247
|
+
try:
|
|
248
|
+
st = subprocess.run(
|
|
249
|
+
["git", "-C", str(root), "status", "--porcelain", *pathspec],
|
|
250
|
+
capture_output=True, text=True, timeout=10,
|
|
251
|
+
)
|
|
252
|
+
porcelain = st.stdout if st.returncode == 0 else ""
|
|
253
|
+
except Exception:
|
|
254
|
+
porcelain = ""
|
|
255
|
+
if not porcelain.strip():
|
|
256
|
+
return head # clean — HEAD fully describes the tree
|
|
257
|
+
|
|
258
|
+
try:
|
|
259
|
+
df = subprocess.run(
|
|
260
|
+
["git", "-C", str(root), "diff", "HEAD", *pathspec],
|
|
261
|
+
capture_output=True, text=True, timeout=20,
|
|
262
|
+
)
|
|
263
|
+
diff_txt = df.stdout if df.returncode == 0 else ""
|
|
264
|
+
except Exception:
|
|
265
|
+
diff_txt = ""
|
|
266
|
+
|
|
267
|
+
h = hashlib.sha256()
|
|
268
|
+
h.update(porcelain.encode("utf-8", "replace"))
|
|
269
|
+
h.update(b"\x00")
|
|
270
|
+
h.update(diff_txt.encode("utf-8", "replace"))
|
|
271
|
+
# Untracked files appear in the porcelain by name only; their bytes are in no
|
|
272
|
+
# diff, so an edit to one would be invisible without their stat.
|
|
273
|
+
for line in porcelain.splitlines():
|
|
274
|
+
if not line.startswith("?? "):
|
|
275
|
+
continue
|
|
276
|
+
try:
|
|
277
|
+
p = root / line[3:].strip().strip('"')
|
|
278
|
+
st_u = p.stat()
|
|
279
|
+
h.update(f"\x00{line[3:]}\x00{st_u.st_size}\x00{st_u.st_mtime_ns}".encode("utf-8", "replace"))
|
|
280
|
+
except OSError:
|
|
281
|
+
continue
|
|
282
|
+
return f"{head}d{h.hexdigest()[:12]}"
|
|
283
|
+
|
|
284
|
+
|
|
181
285
|
# ---------------------------------------------------------------------------
|
|
182
286
|
# Public API — location helpers
|
|
183
287
|
# ---------------------------------------------------------------------------
|