sourcecode 3.1.1__tar.gz → 3.2.1__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.1.1 → sourcecode-3.2.1}/CHANGELOG.md +341 -1
- {sourcecode-3.1.1 → sourcecode-3.2.1}/PKG-INFO +100 -10
- {sourcecode-3.1.1 → sourcecode-3.2.1}/README.md +99 -9
- {sourcecode-3.1.1 → sourcecode-3.2.1}/pyproject.toml +1 -1
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/__init__.py +1 -1
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/chain_rules.py +49 -8
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/cli.py +272 -185
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/confidence_analyzer.py +10 -6
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/deployment_prefix.py +85 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/java.py +10 -5
- sourcecode-3.2.1/src/sourcecode/facts/__init__.py +71 -0
- sourcecode-3.2.1/src/sourcecode/facts/registry.json +158 -0
- sourcecode-3.2.1/src/sourcecode/integration_coordinates.py +175 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/mcp/registry.py +4 -2
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/mcp/server.py +6 -3
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/metrics_analyzer.py +8 -5
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/posture.py +78 -6
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/prepare_context.py +44 -19
- sourcecode-3.2.1/src/sourcecode/reference_facts.py +307 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/repository_ir.py +25 -17
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/steps_graph.py +10 -8
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/steps_intf.py +23 -1
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/security_posture.py +165 -19
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/semantic_integration_engine.py +54 -2
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/serializer.py +36 -9
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/spring_impact.py +124 -7
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/spring_profiles.py +93 -13
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/spring_semantic.py +56 -4
- sourcecode-3.2.1/src/sourcecode/test_sources.py +178 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/.gitignore +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/.ruff.toml +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/CONTRIBUTING.md +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/LICENSE +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/SECURITY.md +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/raw +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/scripts/compare_integration_engines.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/scripts/customer_smoke_test.sh +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/scripts/generate_jdk_exports.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/scripts/perf_harness.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/archetype.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/architectural_baseline.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/architectural_delta.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/cache.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/call_surface.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/caller_metrics.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/change_plan.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/classifier.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/compare.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/constraint_diff.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/context_cache.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/context_graph.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/contract_diff.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/dynamic_argument_surface.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/endpoint_literals.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/endpoint_metrics.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/envelope.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/evidence_provider.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/explain.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/filter_surface.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/format_contract.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/graph_evidence.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/hibernate_strat.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/jdk_exports.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/license.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/migrate_check.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/migration_blast.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/parse_cache.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/perf.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/progress.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/readiness_timeline.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/reconciliation.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/redactor.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/__init__.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/context.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/errors.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/executor.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/planner.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/query.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/request.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/resolution.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/result.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/retriever.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/runtime.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/steps.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/steps_impact.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/steps_struct.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/retrieval/steps_txsec.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/ris.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/scanner.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/schema.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/security_config.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/semantic_impact_engine.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/semantic_services.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/spring_findings.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/spring_properties.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/spring_security_audit.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/spring_tx_analyzer.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/token_estimate.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/type_usage_surface.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/validation_inference.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/validation_surface.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/verify_edit.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/verify_repo.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/verify_rules.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/version_check.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/src/sourcecode/workspace.py +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/supabase/functions/README.md +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/supabase/sql/licensing_schema.sql +0 -0
- {sourcecode-3.1.1 → sourcecode-3.2.1}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -1,9 +1,349 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [3.2.1] — 2026-07-29
|
|
4
|
+
|
|
5
|
+
**M7 complete — the last four seams, the fact registry, and a `--help` that leads with the
|
|
6
|
+
product.** Every fact ADR-0008 named now has one authority, a registered consumer list and an
|
|
7
|
+
assertion that keeps its emitters agreeing. Two of the four seams closed here were found by
|
|
8
|
+
field evaluation #3 *between the two commands it valued most*, and reproducing them showed
|
|
9
|
+
both were worse than reported.
|
|
10
|
+
|
|
11
|
+
**Upgrade note.** Three published numbers change value. None is a schema break; all are
|
|
12
|
+
corrections, and a pinned threshold may move:
|
|
13
|
+
|
|
14
|
+
- `modernize.summary.statically_unreferenced` grows sharply — the population it is measured
|
|
15
|
+
over never matched its own definition (keycloak 14 → 108, BroadleafCommerce 10 → 36,
|
|
16
|
+
alfresco 13 → 88). `summary.high_coupling_nodes` likewise stops reporting the display cap
|
|
17
|
+
of 20 and reports the measured count.
|
|
18
|
+
- `endpoints --limit N` no longer reports `total: N`. `total` and the security counters
|
|
19
|
+
describe the endpoints the *filters* selected; the new `shown` says how many are listed.
|
|
20
|
+
- `posture` verdicts change on repositories that declare `spring.mvc.servlet.path`: rules are
|
|
21
|
+
matched against the URL the filter chain actually receives, so endpoints previously reported
|
|
22
|
+
`no_rule_matched` — or, with a catch-all behind the rule, `permit_all` — now carry the
|
|
23
|
+
decision the matcher makes. Repositories without a declared servlet path are byte-identical.
|
|
24
|
+
|
|
25
|
+
New keys (`summary.reference_status`, `effective_access.path_basis`, `matched_path`, `shown`,
|
|
26
|
+
and `registries` in both `ask schema` and `ask version`) are additive.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- **`--help` no longer introduces the product with its weakest 20 %.** The command table was
|
|
31
|
+
ordered by the order commands are registered in the source, so a reader met
|
|
32
|
+
`prepare-context` and `repo-ir` — the two surfaces field evaluation #3 scored lowest —
|
|
33
|
+
before `posture` and `endpoints`, which the same evaluation called "the product". Commands
|
|
34
|
+
are now grouped into ordered panels, led by **Java/Spring analysis — start here**
|
|
35
|
+
(`posture`, `endpoints`, `spring-audit`, `migrate-check`), then *Change and risk*, *Context
|
|
36
|
+
for AI agents*, *Setup and inspection*, and *Experimental*. Nothing is hidden and nothing is
|
|
37
|
+
removed; the ordering is one table (`cli.HELP_PANELS`) and the battery fails if a registered
|
|
38
|
+
command is missing from it, if the table names a command that does not exist, or if the core
|
|
39
|
+
four stop leading the rendering.
|
|
40
|
+
- **The hand-written "Also available:" catalogue is gone.** A curated list beside a generated
|
|
41
|
+
one drifts, and it did: it is how `endpoints` shipped while appearing in no `--help` list at
|
|
42
|
+
all, leaving an evaluator to find the command they valued most inside another command's JSON.
|
|
43
|
+
- **`ask spring-audit --help` now says which gate it is.** `--ci` fails on *any* finding,
|
|
44
|
+
including debt that was already there — the field read it as baseline-relative and concluded
|
|
45
|
+
the gate was unusable on a legacy repository. The help now states the gate is absolute and
|
|
46
|
+
names the baseline-relative one (`ask verify --fail-on new`, `ask pr-impact --fail-on`) and
|
|
47
|
+
`ask baseline` for tracking the debt. A test asserts those commands and flags exist.
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
|
|
51
|
+
- **Invariant I-3 in the battery: every registered fact declares what it says when it cannot
|
|
52
|
+
decide.** ADR-0008 R9 is easy to state and easy to lose — `statically_unreferenced: 0` over
|
|
53
|
+
3 374 classes is what losing it costs. Each registry entry now carries `unresolved_answer`
|
|
54
|
+
(the outcome the fact emits when undecidable) plus the reason, or `null` with an explanation
|
|
55
|
+
of why the fact is total. A declared outcome must exist in the authority that derives it, so
|
|
56
|
+
the registry cannot document an `unknown` nothing emits — a check that immediately corrected
|
|
57
|
+
two entries where the unresolved answer belongs to the consumer, not the authority.
|
|
58
|
+
|
|
59
|
+
- **Invariant I-2 in the battery: a published count may not come from a truncated list.**
|
|
60
|
+
A static audit over every module (`tests/test_invariant_counts_from_measurement.py`): inside
|
|
61
|
+
one function, a name bound to a slice and then measured with `len()` in a payload position
|
|
62
|
+
fails the suite. Display sizes stay legal under an explicit key (`shown`, `omitted`, …),
|
|
63
|
+
because "how many did you show me" is a different question from "how many are there". The
|
|
64
|
+
audit is itself guarded against being vacuous.
|
|
65
|
+
- It found two live ones. `modernize.summary.high_coupling_nodes` reported the display cap
|
|
66
|
+
(20) as the number of high-coupling classes — a repository with 300 of them said 20; the
|
|
67
|
+
exact count now ships alongside `high_coupling_nodes_shown`. And `endpoints --limit N`
|
|
68
|
+
reported `total: N`: `--limit` cuts the rendering, not the population.
|
|
69
|
+
- **Value change:** with `--limit`, `endpoints` now reports `total` (and the security
|
|
70
|
+
counters) for the endpoints the *filters* selected, plus a new `shown` for how many are
|
|
71
|
+
listed. Before, all of them collapsed to the limit. Filters (`--path-prefix`,
|
|
72
|
+
`--controller`) genuinely change the population and still move `total`.
|
|
73
|
+
|
|
74
|
+
- **The fact registry ADR-0008 asks for (R11), shipped inside the package and enforced.**
|
|
75
|
+
`src/sourcecode/facts/registry.json` names every fact that has a single authority: what it
|
|
76
|
+
means, which `module:symbol` derives it, which modules may emit it, and the parity assertion
|
|
77
|
+
that keeps those emitters agreeing. Read it from an installed version with
|
|
78
|
+
`ask schema facts-v1` — a release states its own contract instead of pointing at
|
|
79
|
+
documentation that can drift from it. No new command: `ask schema` lists it under
|
|
80
|
+
`registries`, beside the output `schemas`.
|
|
81
|
+
- The registry is checked, not asserted: the battery fails if an authority does not exist,
|
|
82
|
+
if a registered consumer does not bind to it (R13 — the LDAP defect survived two releases
|
|
83
|
+
exactly because a consumer was never rebound), or if a fact carries no parity test (R12).
|
|
84
|
+
Writing it found two claims of mine that were untrue and one surface — the endpoint
|
|
85
|
+
security verdict — whose only real consumer is `impact`.
|
|
86
|
+
- Eleven facts registered, one per M7 seam plus the two each seam split apart.
|
|
87
|
+
|
|
88
|
+
### Fixed
|
|
89
|
+
|
|
90
|
+
- **A repository with no tests at all reported `has_tests: true` and "N test files".** Third
|
|
91
|
+
field evaluation: a Spring monolith whose `src/test` does not exist was described as having
|
|
92
|
+
4 test files, because production classes living in a package named `test` matched a
|
|
93
|
+
substring rule. The same document's `analysis_gaps` contradicted it — one document, two
|
|
94
|
+
derivations of one fact.
|
|
95
|
+
- New authority `test_sources`: a file is a test source when it sits under a **declared
|
|
96
|
+
test source root** (`src/test`, `src/it`, `src/androidTest`, `src/testFixtures`, or a
|
|
97
|
+
repository-level `tests/`, `spec/`, `__tests__/`) or matches an ecosystem **naming
|
|
98
|
+
convention** (`FooTest.java`, `test_foo.py`, `foo.spec.ts`, `foo_test.go`). A `test`
|
|
99
|
+
package **inside a main source root is production code** — the build tool's own layout
|
|
100
|
+
outranks any name.
|
|
101
|
+
- Five consumers now bind to it instead of re-deriving: `signals.has_tests`, the
|
|
102
|
+
`analysis_gaps` backend-coverage check (which now also states its basis),
|
|
103
|
+
`metrics_analyzer.is_test_file`, `prepare-context`'s test/source split, and the review-pr
|
|
104
|
+
coverage risk.
|
|
105
|
+
- **Value change:** files under a *main* source root in a directory named `test`/`tests`
|
|
106
|
+
stop counting as tests. Measured on the fleet: keycloak 2 220 → 1 777 Java test files
|
|
107
|
+
(443 files under `testsuite/…/src/main/java/…`), BroadleafCommerce 201 → 197,
|
|
108
|
+
spring-petclinic and openmrs-core unchanged.
|
|
109
|
+
- **`review-pr` reported `test_coverage_risk: "low"` for a diff containing no source files.**
|
|
110
|
+
In a repository with no tests, a documentation-only PR read as "covered" — the traffic light
|
|
111
|
+
inverted exactly where a reviewer relies on it. The surface now emits `unknown` with the
|
|
112
|
+
reason (`no source files changed in this diff`, or `repository declares no test sources`),
|
|
113
|
+
plus `changed_source_files` and `repository_has_test_sources`. `low` is now reachable only
|
|
114
|
+
when changed source files were checked and matched (ADR-0008 R9).
|
|
115
|
+
|
|
116
|
+
- **A class was reported as conditional on a profile *and* on its negation, contradicting
|
|
117
|
+
`ask posture` in the same run.** Found in the third field evaluation (3.2.0): a
|
|
118
|
+
configuration class declaring `@Profile("!m3")` — active exactly when `m3` is **absent** —
|
|
119
|
+
appeared in `signals.spring_profiles.profile_conditional_beans` under `m3` as well. Read as
|
|
120
|
+
a security fact, it inverts the answer.
|
|
121
|
+
- Root cause, reproduced: the source scan attributed every `@Profile` to *the next type
|
|
122
|
+
declaration ahead of it*, falling back to the file name when there was none. A
|
|
123
|
+
`@Profile("m3")` on a `@Bean` **method** inside that class was therefore attributed to the
|
|
124
|
+
class itself, next to the class-level `@Profile("!m3")`.
|
|
125
|
+
- Attribution is now the declaration the annotation actually annotates: only annotations
|
|
126
|
+
and modifiers may stand between it and a type declaration; a member-level annotation is
|
|
127
|
+
reported as `Type#member`, and an annotation whose target cannot be read is **not
|
|
128
|
+
reported at all** rather than attributed to a guess (ADR-0008 R9).
|
|
129
|
+
- **Value change:** member-level declarations move from the enclosing type to the member.
|
|
130
|
+
On the reference fleet this affects one symbol (`spring-petclinic`:
|
|
131
|
+
`MysqlTestApplication` → `MysqlTestApplication#container`); on repositories that put
|
|
132
|
+
`@Profile` on `@Bean` methods it affects each such method.
|
|
133
|
+
- New in the payload: `signals.spring_profiles.conditional_beans[]` with `symbol`,
|
|
134
|
+
`profiles`, `expression` (as written) and `source_file`. The token map
|
|
135
|
+
(`profile_conditional_beans`) buckets `@Profile("a & !b")` under `a` and `!b` with the
|
|
136
|
+
operator lost; the list keeps the expression, and both are now projections of **one**
|
|
137
|
+
derivation, so they cannot disagree.
|
|
138
|
+
- Parity assertion added: no symbol may be reported as conditional on a profile that
|
|
139
|
+
`posture` resolves it inactive under (invariant I-1).
|
|
140
|
+
|
|
141
|
+
- **`ask modernize` reported `statically_unreferenced: 0` across a 3 374-class monolith.**
|
|
142
|
+
Read as "there is no unreferenced code here", when what it meant was "a check that cannot
|
|
143
|
+
see framework dispatch found nothing" — the one place the product broke its own rule about
|
|
144
|
+
never publishing a number where the honest answer is `unknown` (ADR-0008 R9). Two causes:
|
|
145
|
+
- The population never matched the published definition. The note said "zero static
|
|
146
|
+
callers", the code examined only types with **no edges in either direction** — so a type
|
|
147
|
+
that calls something but is called by nothing was never a candidate at all.
|
|
148
|
+
- The surface had two buckets and the question has three answers.
|
|
149
|
+
- One authority now derives it, `reference_facts`, as a partition that sums to the classes
|
|
150
|
+
examined: `referenced` (an incoming edge, or another source naming it) /
|
|
151
|
+
`unknown_framework_dispatch` (no static caller, but a published annotation, an entry-point
|
|
152
|
+
signature, or the name wired from a configuration file) / `no_static_callers` (neither —
|
|
153
|
+
**absence of evidence, never "dead code"**). `summary.reference_status` carries the exact
|
|
154
|
+
counts and a `statement` that explains a zero instead of publishing it bare.
|
|
155
|
+
- Counts come from the measurement, not from `len()` of the lists, which are cut to 20 for
|
|
156
|
+
display (R5). Every listed type carries the `basis` for being there.
|
|
157
|
+
- Dispatch detection extended with published stereotype, persistence and entry-point
|
|
158
|
+
vocabulary (`@Component`/`@Service`/`@Repository`/`@Controller`/`@RestController`/
|
|
159
|
+
`@Configuration`/`@Entity`/`@Embeddable`/`@MappedSuperclass`/`@Aspect`/`@WebServlet`/
|
|
160
|
+
`@WebFilter`/`@WebListener`/`@SpringBootApplication`, `public static void main`), and the
|
|
161
|
+
configuration-name scan now matches whole names — `Order` inside `OrderItemImpl` was
|
|
162
|
+
marking live-looking classes dispatched.
|
|
163
|
+
- **Value change:** the candidate population is much larger, so the counts move.
|
|
164
|
+
keycloak 14 → 108 `no_static_callers`, BroadleafCommerce 10 → 36, alfresco 13 → 88;
|
|
165
|
+
spring-petclinic stays 0 and now says why (its one callerless type is an `@Entity`, so
|
|
166
|
+
the answer is `unknown`). The scan is also faster than the one it replaces: one repository
|
|
167
|
+
walk instead of two, and fixed patterns intersected with the candidate set rather than an
|
|
168
|
+
alternation over it (keycloak 2.5 s → 1.2 s).
|
|
169
|
+
|
|
170
|
+
- **`ask posture` decided endpoint access against a URL the application never serves.** A
|
|
171
|
+
repository declaring `spring.mvc.servlet.path=/api` is served at `/api/orders`, and that is
|
|
172
|
+
the URL its filter chain matches — but the chain rules were compared against the
|
|
173
|
+
mapping-relative `/orders`. A rule reading `.antMatchers("/api/**").authenticated()`
|
|
174
|
+
therefore covered nothing. Reported from the field as 2 632 endpoints falsely
|
|
175
|
+
`no_rule_matched`; reproduced in a fixture, it is worse than that — where a catch-all
|
|
176
|
+
`anyRequest().permitAll()` follows the rule, those endpoints were reported **`permit_all`**,
|
|
177
|
+
which states a protected endpoint is open.
|
|
178
|
+
- One authority for the prefix: `deployment_prefix`, the same module `ask endpoints` reads
|
|
179
|
+
for `effective_path`. `posture` asks it for the part a matcher actually sees — the
|
|
180
|
+
**servlet path**, resolved for the profile set you asked about, so a servlet path declared
|
|
181
|
+
only under `prod` applies exactly when `prod` does. The servlet **context** path is
|
|
182
|
+
excluded on purpose: the container strips it before the filter chain runs.
|
|
183
|
+
- Matcher semantics are honoured rather than averaged: `antMatchers`/`regexMatchers` match
|
|
184
|
+
the servlet-path-prefixed URL, `mvcMatchers` matches relative to the servlet mapping, and
|
|
185
|
+
`requestMatchers` is either one depending on the Spring Security version and classpath —
|
|
186
|
+
unreadable from source, so a rule covering the request under either reading is honoured.
|
|
187
|
+
- New in the payload: `effective_access.path_basis` states the servlet path used and where
|
|
188
|
+
it came from, and each stated endpoint carries `matched_path` in its evidence when the
|
|
189
|
+
matched URL differs from the endpoint's mapping-relative path.
|
|
190
|
+
- **Never a guessed URL** (ADR-0008 R9): where a servlet path is declared but cannot be
|
|
191
|
+
resolved (a `${PLACEHOLDER}`, or documents that disagree), every verdict that depends on a
|
|
192
|
+
path pattern is reported `undecided` with `decision_if_unprefixed`, instead of computed
|
|
193
|
+
against an assumed empty prefix.
|
|
194
|
+
- **Value change:** none on a repository that declares no servlet path — the two readings
|
|
195
|
+
coincide and the matching is unchanged. Verified byte-identical on spring-petclinic,
|
|
196
|
+
keycloak, BroadleafCommerce and spaghetti-api, none of which declare one.
|
|
197
|
+
|
|
198
|
+
## [3.2.0] — 2026-07-28
|
|
199
|
+
|
|
200
|
+
**Answer coherence (M7, first four seams).** One fact, one authority (ADR-0008). Four
|
|
201
|
+
questions this tool answered twice — transaction boundaries, endpoint denominators, endpoint
|
|
202
|
+
security coverage, outbound integrations — now have a single authority each, and every
|
|
203
|
+
consumer binds to it instead of re-deriving.
|
|
204
|
+
|
|
205
|
+
**Upgrade note.** Two behaviours change for anyone gating on the output:
|
|
206
|
+
|
|
207
|
+
- `impact` / `impact-chain` / `plan` / `compare` now count transaction boundaries that were
|
|
208
|
+
structurally reported as `0` on every repository. Risk scores move **up**: on a
|
|
209
|
+
200-class BroadleafCommerce sample, 42 classes go from 0 to ≥1 boundary and 11 change
|
|
210
|
+
`risk_level`, always upward. A pinned `--fail-on` threshold can now trip where it did not.
|
|
211
|
+
- `impact-chain.security_surfaces[]` and `endpoints_affected[]` gain `verdict` +
|
|
212
|
+
`confidence` and no longer let the declared annotation policy stand as a coverage answer.
|
|
213
|
+
`security_policy` is kept as a deprecated alias of `declared_policy` (two minor versions),
|
|
214
|
+
with its value unchanged.
|
|
215
|
+
|
|
216
|
+
New payload keys (`population`, `declared_clients`, three-part endpoint partitions) are
|
|
217
|
+
additive; the deprecated aliases listed below keep their previous values.
|
|
218
|
+
|
|
219
|
+
### Fixed
|
|
220
|
+
|
|
221
|
+
- **`export --integrations` answered "0 LDAP" in documents whose stack block named Spring
|
|
222
|
+
LDAP.** Reported in two field evaluations two majors apart. Reproduced on a Boot app that
|
|
223
|
+
declares `spring-boot-starter-data-ldap` and configures `spring.ldap.urls` in YAML: the
|
|
224
|
+
directory is wired entirely by properties, so no LDAP client type is ever imported and the
|
|
225
|
+
construct scan is *right* to find nothing — but the report never mentioned the declaration
|
|
226
|
+
it could see, and the document as a whole said the system has no outbound integrations
|
|
227
|
+
while naming a directory client library elsewhere.
|
|
228
|
+
- New authority `integration_coordinates.declared_integration_coordinates(root)` answers
|
|
229
|
+
one question — which client libraries the build declares — from Maven/Gradle
|
|
230
|
+
coordinates with `file:line` evidence, excluding test/provided scope.
|
|
231
|
+
- `export --integrations` (and `export --c4`) now carry `declared_clients`
|
|
232
|
+
(`kind`, `coordinate`, `evidence`, `observed_in_source`), `declared_clients_count` and
|
|
233
|
+
`kinds_declared_not_observed`, and the coverage reason names the declared kind and its
|
|
234
|
+
coordinate. A declared coordinate is never counted as an integration: `count` and
|
|
235
|
+
`by_kind` are unchanged and still report observed constructs only.
|
|
236
|
+
- `retrieve integration-inventory` states the same declared-not-observed kinds as
|
|
237
|
+
observations.
|
|
238
|
+
- `detectors/java.py` reads its directory coordinates from that one list, so the stack
|
|
239
|
+
block and the integration report can never recognize different libraries for the same
|
|
240
|
+
external system (ADR-0008 R12).
|
|
241
|
+
- Measured: alfresco declares `cxf-rt-frontend-jaxws` with no SOAP construct in source —
|
|
242
|
+
previously invisible, now stated. Broadleaf's declared JMS/LDAP coordinates are all
|
|
243
|
+
marked `observed_in_source: true`; repositories that declare no client library keep an
|
|
244
|
+
empty block. The `export --integrations` and `export --c4` baseline cells drift by
|
|
245
|
+
these added keys, by design.
|
|
246
|
+
|
|
247
|
+
- **`impact-chain` called endpoints "none_detected" that the same run classified as guarded
|
|
248
|
+
by a custom authorization mechanism.** Measured on keycloak: `security_posture` reports
|
|
249
|
+
406 endpoints `protected_custom` (Likely) — 324 of them carrying the declared policy
|
|
250
|
+
`none_detected`, because their gate is a bespoke annotation outside every published
|
|
251
|
+
vocabulary — while `impact-chain` printed `security_policy: none_detected` for those same
|
|
252
|
+
`endpoint_id`s. One document answered both "guarded by a custom mechanism" and "no
|
|
253
|
+
security detected" about `DELETE /admin/realms/{realm}`. The declared policy is a fact
|
|
254
|
+
about an annotation; it was never an answer about coverage.
|
|
255
|
+
- New authority `security_posture.endpoint_security_surface(cir)` returns the per-endpoint
|
|
256
|
+
answer keyed by `endpoint_id` (ADR-0008 R1). `impact-chain` binds to it and reuses the
|
|
257
|
+
projection the security audit already derived — no second derivation, memoized per CIR
|
|
258
|
+
so `pr-impact`'s per-class queries pay for it once.
|
|
259
|
+
- `security_surfaces[]` and `endpoints_affected[]` now carry `verdict` + `confidence`
|
|
260
|
+
(`security_verdict` / `security_confidence` on affected endpoints) from the four-way
|
|
261
|
+
posture vocabulary, plus `declared_policy` for the annotation actually found. On the
|
|
262
|
+
28 endpoints reachable from `RealmAdminResource`, all 28 move `none_detected` →
|
|
263
|
+
`protected_custom` (Likely), matching `spring-audit` exactly.
|
|
264
|
+
- An endpoint the authority cannot speak about — or a repository with no posture
|
|
265
|
+
projection — is `coverage_unknown` with the reason stated, never a manufactured "none"
|
|
266
|
+
(ADR-0008 R9). On spring-petclinic all 17 endpoints read `coverage_unknown` in both
|
|
267
|
+
commands instead of `none_detected` in one and `coverage_unknown` in the other.
|
|
268
|
+
- `security_policy` is kept as a deprecated alias of `declared_policy` for two minor
|
|
269
|
+
versions; its value is unchanged.
|
|
270
|
+
|
|
271
|
+
- **The security posture reported three counts under names that all read as "handlers", and
|
|
272
|
+
they did not reconcile.** The field report put `custom_authorization_mechanisms` at
|
|
273
|
+
713/936, `gate_coverage` at 698 and 2635, and a rollup of 939 + 2635 = 3574 — the only
|
|
274
|
+
figure matching `endpoints.total`. None was arithmetically wrong: they counted three
|
|
275
|
+
different populations, and no key said which. Reproduced exactly on keycloak, where the
|
|
276
|
+
old payload showed `gate_bearing: 337` beside `not_carrying_gate: 270` against a stated
|
|
277
|
+
total of 676 — a partition that visibly loses 69 endpoints, because the first number
|
|
278
|
+
counts handler *methods* and the second counts *endpoints*.
|
|
279
|
+
- One authority, `security_posture.endpoint_population`, now supplies every denominator,
|
|
280
|
+
and the posture payload carries a `population` block stating both units once
|
|
281
|
+
(ADR-0008 R1).
|
|
282
|
+
- `gate_coverage` gains an explicit three-part endpoint partition —
|
|
283
|
+
`endpoints_carrying_gate` + `endpoints_standard_guarded` +
|
|
284
|
+
`endpoints_not_carrying_gate` = `endpoints_total` — counted in the single loop that
|
|
285
|
+
visits each endpoint once, so the parts sum by construction. On keycloak:
|
|
286
|
+
406 + 0 + 270 = 676. Handler-method figures keep their own names
|
|
287
|
+
(`handler_methods_total`, `handler_methods_carrying_gate`) and are never part of that
|
|
288
|
+
sum.
|
|
289
|
+
- Custom-gate detection states the unit its percentage used: the denominator is handler
|
|
290
|
+
method *declarations* (overloads share an FQN, so keycloak has 551 distinct handler
|
|
291
|
+
methods across 601 declarations), and `endpoints_total` / `handler_methods_total` are
|
|
292
|
+
printed beside it so no reader has to infer which one a coverage figure meant.
|
|
293
|
+
- `total_controller_handlers`, `gate_bearing`, `not_carrying_gate` and `handler_total`
|
|
294
|
+
are kept as deprecated aliases with their existing values for two minor versions. No
|
|
295
|
+
consumer breaks; the numbers they held did not change.
|
|
296
|
+
|
|
297
|
+
- **`impact` counted zero transaction boundaries on every repository — corrected, and the
|
|
298
|
+
two commands that answer this question now answer it once.** The field report was that
|
|
299
|
+
`impact` reported `transactional_boundaries_count: 0` for a symbol while `retrieve
|
|
300
|
+
transactions-reaching` reported 47 for the same one. The cause was worse than a
|
|
301
|
+
disagreement: the blast radius derived boundaries from a call-graph node
|
|
302
|
+
`role == "transaction_boundary"` that no producer ever assigns — 0 of 28 662 nodes carry
|
|
303
|
+
it on BroadleafCommerce — so the figure was **structurally always zero**, and the
|
|
304
|
+
`n_txn` term never contributed to `risk_score` or to the `n_txn >= 2` escalation rule
|
|
305
|
+
behind `risk_level`.
|
|
306
|
+
- Both consumers now ask one authority, `spring_semantic.boundaries_declared_within`
|
|
307
|
+
over the transaction-boundary index (ADR-0008 R1), which follows Spring's own
|
|
308
|
+
inheritance in both directions: a method carries its class's boundary, a class carries
|
|
309
|
+
the boundaries of the methods it declares, and asking about one method never sweeps in
|
|
310
|
+
a sibling's.
|
|
311
|
+
- Two named facts, one authority (ADR-0008 R3): `transactional_boundaries_touched` is
|
|
312
|
+
the target plus everything that calls it; the new `transactional_boundaries_reaching`
|
|
313
|
+
is the callers-only subset — what would run this change inside a transaction — and is
|
|
314
|
+
the number `retrieve transactions-reaching` reports, now by construction rather than
|
|
315
|
+
by coincidence.
|
|
316
|
+
- **Figures move, upward, because a real cost was being counted as nothing.** Measured
|
|
317
|
+
on BroadleafCommerce (161 declared boundaries): `CatalogServiceImpl` 0 → 10 boundaries
|
|
318
|
+
and `risk_score` 76.73 → 77.54; `OrderServiceImpl` 0 → 32 and 73.83 → 76.86;
|
|
319
|
+
`CustomerServiceImpl` 0 → 32 and 66.10 → 71.01. Across a 200-class sample, 42 classes
|
|
320
|
+
now report at least one boundary and 11 change `risk_level` — every one of them
|
|
321
|
+
upward. A pinned `--fail-on` threshold may therefore trip where it did not before;
|
|
322
|
+
that is the correction, not a regression.
|
|
4
323
|
|
|
5
324
|
### Added
|
|
6
325
|
|
|
326
|
+
- **ADR-0008 "Answer Coherence" — one fact, one authority (normative, no behaviour change
|
|
327
|
+
yet).** Two independent field evaluations, on releases two majors apart, scored the
|
|
328
|
+
product identically and named the same ceiling: not a missing capability, but the same
|
|
329
|
+
question answered twice with different numbers (`impact` reporting 0 transactional
|
|
330
|
+
boundaries where `retrieve` reports 47; `compare` ranking on caller arrays truncated at
|
|
331
|
+
30 while the exact magnitudes sit in `stats`; `has_tests` contradicting `analysis_gaps`
|
|
332
|
+
inside one document). The ADR fixes the rule the codebase had never stated: a fact has
|
|
333
|
+
exactly one authority, consumers transport it, quantities never come from the length of a
|
|
334
|
+
rendered collection, and a surface that cannot resolve emits `unknown` — never `0`. It
|
|
335
|
+
also changes the unit of remediation from *defect* to *fact*: a coherence fix is complete
|
|
336
|
+
only when the authority is corrected, every consumer is rebound, and a cross-command
|
|
337
|
+
parity assertion is added to the release battery.
|
|
338
|
+
- `docs/architecture/adr/0008-answer-coherence.md` — the rule, with the code-verified seam
|
|
339
|
+
inventory in Appendix A.
|
|
340
|
+
- `docs/DEFECT-LEDGER.md` — every field defect, its class, and the release that closed it,
|
|
341
|
+
published rather than tracked privately.
|
|
342
|
+
- `.planning/FIELD-EVAL-SYNTHESIS-2026-07-28.md` and
|
|
343
|
+
`.planning/ROADMAP-STRATEGIC-2026-07-28.md` — the evidence and the resulting direction
|
|
344
|
+
(M7 Coherence → M8 Payload economy → M9 Core & surface → M10 Enrichment interop →
|
|
345
|
+
M11 Compliance substrate).
|
|
346
|
+
|
|
7
347
|
- **`migrate-check --blast-radius` states the regression scope behind each blocker.** The
|
|
8
348
|
finding list says what must change; a migration plan is built around what has to be
|
|
9
349
|
re-tested when that change lands. Each affected product file now resolves to the types
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.1
|
|
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,15 @@ 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) and the **compact
|
|
78
|
+
view**. Pass `--agent` to warm the agent view as well. Deeper projections are separate view
|
|
79
|
+
keys and are *not* covered by either — `--full`, `--env-map` and a raised `--depth` recompute
|
|
80
|
+
on first use, as do most `prepare-context` tasks. Measured on a 3,342-file Spring monolith:
|
|
81
|
+
`cache warm` 103s → `--compact --git-context` 1s (hit), but `--agent --full --env-map
|
|
82
|
+
--depth 20` still 171s (miss). Budget the deep run explicitly in CI, or warm exactly the view
|
|
83
|
+
your pipeline consumes. Full model: [USER_GUIDE.md#caching](docs/USER_GUIDE.md#caching).
|
|
84
|
+
|
|
76
85
|
---
|
|
77
86
|
|
|
78
87
|
## Install
|
|
@@ -95,27 +104,55 @@ ask version # ask 2.5.1
|
|
|
95
104
|
|
|
96
105
|
## Quickstart
|
|
97
106
|
|
|
107
|
+
**Start with these four.** In three independent field evaluations they carried most of the
|
|
108
|
+
measured value, and `posture --diff` is the one no evaluator found an equivalent for —
|
|
109
|
+
commercial or open source.
|
|
110
|
+
|
|
98
111
|
```bash
|
|
99
|
-
#
|
|
100
|
-
|
|
112
|
+
# What does each profile set ACTUALLY wire — and what changes between them?
|
|
113
|
+
# Resolves conditional beans and the filter chain, then diffs effective endpoint access.
|
|
114
|
+
ask posture /path/to/repo --diff dev:prod
|
|
101
115
|
|
|
102
|
-
#
|
|
103
|
-
|
|
116
|
+
# Every REST endpoint with its effective path (context-path + servlet path resolved),
|
|
117
|
+
# its inferred security policy and a confidence per endpoint.
|
|
118
|
+
ask endpoints /path/to/repo
|
|
119
|
+
|
|
120
|
+
# Spring semantic audit: transactional anomalies (private @Transactional = silent
|
|
121
|
+
# CGLIB no-op), security surface, request-body validation.
|
|
122
|
+
ask spring-audit /path/to/repo
|
|
104
123
|
|
|
105
|
-
# Spring Boot 2→3
|
|
124
|
+
# Spring Boot 2→3 readiness: located blockers, per-dimension score, effort estimate.
|
|
106
125
|
ask migrate-check /path/to/repo --compact
|
|
126
|
+
```
|
|
107
127
|
|
|
108
|
-
|
|
109
|
-
|
|
128
|
+
Then the everyday loop:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# High-signal structural summary — warm cache ~0.3s, cold 2–10s
|
|
132
|
+
ask --compact
|
|
133
|
+
|
|
134
|
+
# Blast radius: what breaks if this class changes? (target the INTERFACE, not the Impl)
|
|
135
|
+
ask impact OrderService /path/to/repo
|
|
110
136
|
|
|
111
137
|
# Onboard to an unfamiliar codebase
|
|
112
138
|
ask onboard /path/to/repo
|
|
113
139
|
|
|
114
140
|
# PR review: risk, test gaps, changed modules
|
|
115
141
|
ask review-pr /path/to/repo --since main
|
|
142
|
+
|
|
143
|
+
# CI gate on NEW violations only, instead of on pre-existing debt
|
|
144
|
+
ask verify /path/to/repo --capture-baseline # accept today's debt, once
|
|
145
|
+
ask verify /path/to/repo # then: only new violations block
|
|
116
146
|
```
|
|
117
147
|
|
|
118
|
-
|
|
148
|
+
> **Adopting a gate on a real codebase.** A repository that starts declaring contracts already
|
|
149
|
+
> violates them somewhere; `ask verify` is **baseline-relative by default** (`--fail-on new`)
|
|
150
|
+
> so the gate survives contact with reality instead of being switched off on day one.
|
|
151
|
+
> `ask baseline capture|diff|trend` is a different thing: versioned architectural metrics over
|
|
152
|
+
> time, for trend reporting rather than blocking.
|
|
153
|
+
|
|
154
|
+
Full command reference: **[docs/USER_GUIDE.md](docs/USER_GUIDE.md)** · posture in depth:
|
|
155
|
+
**[docs/posture.md](docs/posture.md)**.
|
|
119
156
|
|
|
120
157
|
---
|
|
121
158
|
|
|
@@ -148,6 +185,15 @@ Deterministic Spring semantics: transactional anomalies (e.g. `@Transactional` o
|
|
|
148
185
|
`ask spring-audit` · `ask validation`
|
|
149
186
|
→ [reference](docs/USER_GUIDE.md#core-commands)
|
|
150
187
|
|
|
188
|
+
### 5b · Runtime Posture *(experimental — and the most differentiated thing here)*
|
|
189
|
+
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.*
|
|
190
|
+
`ask posture` · `ask posture --diff dev:prod` · `ask posture --property k=v`
|
|
191
|
+
→ [posture.md](docs/posture.md)
|
|
192
|
+
|
|
193
|
+
Unresolved is a first-class outcome: a condition the resolver cannot decide is reported as a
|
|
194
|
+
hole with the condition named, never folded into active or inactive. **A posture answer that
|
|
195
|
+
guesses is a confident security falsehood — the worst failure mode this tool has.**
|
|
196
|
+
|
|
151
197
|
### 6 · Developer Workflows
|
|
152
198
|
The everyday loop: diff-based PR review, symptom-driven bug triage, and delta context for continuous agent runs.
|
|
153
199
|
`ask review-pr` · `ask fix-bug` · `ask prepare-context`
|
|
@@ -159,6 +205,36 @@ The everyday loop: diff-based PR review, symptom-driven bug triage, and delta co
|
|
|
159
205
|
|
|
160
206
|
---
|
|
161
207
|
|
|
208
|
+
## Every command, in one table
|
|
209
|
+
|
|
210
|
+
*`ask --help` shows a short header; this is the full surface. If you only read one row, read
|
|
211
|
+
`posture`.*
|
|
212
|
+
|
|
213
|
+
| Command | Answers | Note |
|
|
214
|
+
|---|---|---|
|
|
215
|
+
| `posture` | which beans a profile set wires, and how effective endpoint access differs between two sets | **experimental**, most differentiated |
|
|
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 | `--compact` is the token-cheap one |
|
|
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 | **experimental** |
|
|
232
|
+
| `archetype` | evidence-based architectural archetype | **experimental** |
|
|
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 | |
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
162
238
|
## What it does — and doesn't
|
|
163
239
|
|
|
164
240
|
**ASK Engine reduces exploration cost.** It accelerates context acquisition and computes
|
|
@@ -182,6 +258,13 @@ Honest limits worth knowing before you rely on it:
|
|
|
182
258
|
> **🎉 Early-adoption: Pro is currently unlocked for everyone.** Every install runs with
|
|
183
259
|
> full Pro entitlements — no size gate, no key. The tiers below describe the model the
|
|
184
260
|
> paywall will return to later.
|
|
261
|
+
>
|
|
262
|
+
> **What that means concretely.** `ask auth status` reports `"status": "unauthenticated"`
|
|
263
|
+
> together with `"pro": true`, `"pro_reason": "early-adoption unlock"` — that combination is
|
|
264
|
+
> expected, not a bug: you are unauthenticated *and* unlocked. When the unlock ends, gating
|
|
265
|
+
> returns **by repo size and automation, never by command**: `posture`, `endpoints`,
|
|
266
|
+
> `spring-audit` and `migrate-check` stay in the base tier at full output. Nothing you can run
|
|
267
|
+
> today becomes a paid-only command tomorrow.
|
|
185
268
|
|
|
186
269
|
**Gating is by repo size and automation — never by command.** Every command runs at full
|
|
187
270
|
power on Free for small and mid-size repos; you upgrade when the work gets bigger or automated.
|
|
@@ -209,7 +292,13 @@ ask telemetry disable # anonymous telemetry is on by default (opt-out)
|
|
|
209
292
|
|
|
210
293
|
Telemetry collects version, OS, commands, flags, duration, repo-size range, and errors —
|
|
211
294
|
**no source code, paths, secrets, or output**. Disable any time with
|
|
212
|
-
`export SOURCECODE_TELEMETRY=0` (or `DO_NOT_TRACK=1`).
|
|
295
|
+
`export SOURCECODE_TELEMETRY=0` (or `DO_NOT_TRACK=1`). It defaults to **off in CI**.
|
|
296
|
+
|
|
297
|
+
> **Auditing someone else's code — regulated, client-owned or public-sector?** Turn it off
|
|
298
|
+
> *before* the first run, not after: `SOURCECODE_TELEMETRY=0 ask …`, or `ask telemetry disable`
|
|
299
|
+
> once (remembered). The default is opt-out today; **moving it to opt-in is on the roadmap**
|
|
300
|
+
> (`docs/DEFECT-LEDGER.md` P-1) precisely because a default you must remember to disable is the
|
|
301
|
+
> wrong default for third-party code.
|
|
213
302
|
|
|
214
303
|
**Custom security annotations.** Teach `endpoints`, `spring-audit`, and `explain` about
|
|
215
304
|
project-specific authorization annotations via an optional `sourcecode.config.json` at the
|
|
@@ -241,3 +330,4 @@ Matching endpoints report `policy: "custom"` and drop out of the `no_security_si
|
|
|
241
330
|
| [MANUAL-USUARIO.md](docs/MANUAL-USUARIO.md) | Guía de usuario en español |
|
|
242
331
|
| [PRODUCT_IDENTITY.md](docs/PRODUCT_IDENTITY.md) | `ask` (command) vs `sourcecode` (package/alias) |
|
|
243
332
|
| [privacy.md](docs/privacy.md) | Telemetry and data-handling policy |
|
|
333
|
+
| [DEFECT-LEDGER.md](docs/DEFECT-LEDGER.md) | Every defect found in the field, its class, and which release closed it — published on purpose |
|