sourcecode 3.7.0__tar.gz → 4.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sourcecode-3.7.0 → sourcecode-4.0.0}/CHANGELOG.md +452 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/PKG-INFO +34 -4
- {sourcecode-3.7.0 → sourcecode-4.0.0}/README.md +33 -3
- {sourcecode-3.7.0 → sourcecode-4.0.0}/pyproject.toml +1 -1
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/__init__.py +1 -1
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/archetype.py +43 -16
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/cache.py +48 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/cache_model.py +17 -7
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/cli.py +562 -127
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/confidence_analyzer.py +7 -2
- sourcecode-4.0.0/src/sourcecode/contract_init.py +419 -0
- sourcecode-4.0.0/src/sourcecode/defect_identity.py +166 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/degradation.py +52 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/java.py +15 -31
- sourcecode-4.0.0/src/sourcecode/environment_resolution.py +361 -0
- sourcecode-4.0.0/src/sourcecode/filter_surface.py +404 -0
- sourcecode-4.0.0/src/sourcecode/git_checkout.py +149 -0
- sourcecode-4.0.0/src/sourcecode/identity_fallback.py +244 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/migrate_check.py +79 -7
- sourcecode-4.0.0/src/sourcecode/non_coverage.py +198 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/parse_cache.py +23 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/posture.py +201 -6
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/pr_comment_renderer.py +13 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/prepare_context.py +110 -3
- sourcecode-4.0.0/src/sourcecode/remedies.py +87 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/repository_ir.py +43 -4
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/result.py +24 -9
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/steps.py +3 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/steps_endpoint.py +5 -5
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/steps_graph.py +5 -5
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/steps_impact.py +19 -7
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/steps_intf.py +4 -4
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/steps_struct.py +5 -5
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/steps_txsec.py +5 -5
- sourcecode-4.0.0/src/sourcecode/risk.py +345 -0
- sourcecode-4.0.0/src/sourcecode/security_config_scan.py +262 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/security_posture.py +216 -23
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/serializer.py +39 -5
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/spring_findings.py +67 -4
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/spring_profiles.py +199 -3
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/spring_properties.py +1 -1
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/spring_security_audit.py +88 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/spring_tx_analyzer.py +52 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/summarizer.py +7 -2
- sourcecode-4.0.0/src/sourcecode/test_gap_ranking.py +363 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/token_estimate.py +36 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/verify_repo.py +8 -0
- sourcecode-3.7.0/src/sourcecode/filter_surface.py +0 -173
- {sourcecode-3.7.0 → sourcecode-4.0.0}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/.gitignore +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/.ruff.toml +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/CONTRIBUTING.md +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/LICENSE +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/SECURITY.md +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/raw +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/scripts/compare_integration_engines.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/scripts/customer_smoke_test.sh +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/scripts/generate_jdk_exports.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/scripts/perf_harness.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/architectural_baseline.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/architectural_delta.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/call_surface.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/caller_metrics.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/caller_reach.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/chain_rules.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/change_plan.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/classifier.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/compare.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/constraint_diff.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/context_cache.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/context_graph.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/contract_diff.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/deployment_prefix.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/dynamic_argument_surface.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/endpoint_literals.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/endpoint_metrics.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/envelope.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/evidence_provider.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/explain.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/facts/__init__.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/facts/registry.json +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/format_contract.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/graph_evidence.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/hibernate_strat.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/integration_coordinates.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/jdk_exports.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/license.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/migration_blast.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/path_admission.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/perf.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/pipe_contract.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/progress.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/readiness_timeline.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/reconciliation.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/redactor.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/reference_facts.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/__init__.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/context.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/errors.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/executor.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/planner.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/query.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/request.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/resolution.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/retriever.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/retrieval/runtime.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/ris.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/scanner.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/schema.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/security_config.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/semantic_impact_engine.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/semantic_integration_engine.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/semantic_services.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/spring_impact.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/target_admission.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/test_sources.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/type_usage_surface.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/validation_inference.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/validation_surface.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/verify_edit.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/verify_rules.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/version_check.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/src/sourcecode/workspace.py +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/supabase/functions/README.md +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/supabase/sql/licensing_schema.sql +0 -0
- {sourcecode-3.7.0 → sourcecode-4.0.0}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -1,5 +1,457 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [4.0.0] — 2026-08-02
|
|
6
|
+
|
|
7
|
+
Major because two published `gate_coverage` fields are removed, not because the
|
|
8
|
+
engine changed shape: `total_controller_handlers` / `gate_bearing` /
|
|
9
|
+
`not_carrying_gate` (C2-14, the announced end of their two-minor window) and
|
|
10
|
+
`possibly_filter_covered` (C1-20, which had no window — it counted the wrong thing).
|
|
11
|
+
`removed_fields` in the same block maps each retired name to its successor.
|
|
12
|
+
|
|
13
|
+
This release closes fourteen of the sixteen rows opened by the seventh field
|
|
14
|
+
evaluation, in the order that record argued for, and ships `ask risk` — the first
|
|
15
|
+
command that composes the other answers instead of adding one.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **`ask risk` — the composition layer** (M10 head; [EXPERIMENTAL]). The seventh
|
|
20
|
+
evaluation's thesis was *"ASK tiene todos los átomos y no forma moléculas"*: one
|
|
21
|
+
class was `medium` in `spring-audit`, `medium/5.0` in `impact-chain`,
|
|
22
|
+
`coverage_unknown → permit_all` in `posture`, and executed a stored procedure that
|
|
23
|
+
mutates the database. Composed, that is unauthenticated write access under the
|
|
24
|
+
release build; separately, it was two commands saying "medium" and a reader doing
|
|
25
|
+
the join by hand.
|
|
26
|
+
`severity_effective = defect_severity × reachability × auth_verdict × write_effect`,
|
|
27
|
+
emitted as an ordered list. No new analysis — every factor is read from the
|
|
28
|
+
authority that already publishes it, and every row carries its four factors with
|
|
29
|
+
their sources, so a reader can reject one and keep the rest. An axis that could
|
|
30
|
+
not be measured is `unknown`, multiplies by 1.0, and is named in `blind_axes`:
|
|
31
|
+
the composition may not invent what nobody measured. This is the item that
|
|
32
|
+
*"crea producto"* rather than correcting data, and the one nobody replicates by
|
|
33
|
+
combining three scanners, because none of them shares an endpoint id with the
|
|
34
|
+
others.
|
|
35
|
+
|
|
36
|
+
- **Three textbook security rules, because silence has to mean something** (CL-9).
|
|
37
|
+
The seventh evaluation got one security finding out of 3 342 files, then found
|
|
38
|
+
three more by hand in three files ASK had pointed it at. `SEC-004` (passwords
|
|
39
|
+
stored under a fast unsalted digest), `SEC-005` (CSRF disabled under
|
|
40
|
+
session-bearing authentication) and `SEC-006` (a cookie created without the Secure
|
|
41
|
+
attribute) ship in the `spring-audit` security surface, from one scan
|
|
42
|
+
(`sourcecode/security_config_scan.py`) with `file:line`. Each requires a
|
|
43
|
+
security-configuration context, so SHA-1 over a response body stays an ETag and a
|
|
44
|
+
stateless API that disables CSRF is not reported — a rule that cannot tell those
|
|
45
|
+
apart is one teams switch off, after which it protects nothing. These are table
|
|
46
|
+
stakes rather than differentiation: closing them avoids losing the sale.
|
|
47
|
+
|
|
48
|
+
- **A third verdict for a gate that authorises against an identity nobody proved**
|
|
49
|
+
(C1-21). 939 endpoints in the field were reported `protected_custom` for carrying a
|
|
50
|
+
real gate — whose aspect resolves the caller through a method that returns a
|
|
51
|
+
database user when the authentication is null. The check runs; what it decides on,
|
|
52
|
+
for a request carrying no credential, is an identity the application invented, and
|
|
53
|
+
the vocabulary had no way to say so.
|
|
54
|
+
- `sourcecode/identity_fallback.py` (extractor) reports a method that reads the
|
|
55
|
+
platform's identity and, in a branch guarded by that identity being absent,
|
|
56
|
+
returns one anyway. Throwing, denying and returning null are correct handling and
|
|
57
|
+
are never reported; nothing branches on a method or class name (VAI).
|
|
58
|
+
- `security_posture` follows the enforcement path — types carrying published AOP
|
|
59
|
+
advice vocabulary or implementing a request-chain SPI — over `calls` edges, and
|
|
60
|
+
emits `protected_custom_degraded` (confidence `RequiresManualReview`) with an
|
|
61
|
+
`identity_resolution` block naming the method, the absence test and what it
|
|
62
|
+
returns. A fallback the enforcement path does not reach is not charged to the
|
|
63
|
+
gate.
|
|
64
|
+
|
|
65
|
+
- **The remedy travels with the limitation** (C4-8, C3-37). The evaluation's requests
|
|
66
|
+
#1 and #5 — written by hand with invented syntax — are `posture
|
|
67
|
+
--resolve-environments` and `verify --init`, both shipped in the build it audited.
|
|
68
|
+
Four earlier rows say the same thing: discoverability cannot live in a document,
|
|
69
|
+
because a reader looking at an output does not go and read `--help`. One registry
|
|
70
|
+
(`sourcecode/remedies.py`), keyed by the question rather than by the flag, is read
|
|
71
|
+
by `posture.activation`, `posture --diff`, the `security_posture` limitation that is
|
|
72
|
+
conditional on the profile set, and `verify`'s exit-2 reason. A test refuses any
|
|
73
|
+
remedy naming a command or option the CLI does not accept, so a renamed flag breaks
|
|
74
|
+
the build instead of sending a reader to an invocation that no longer exists.
|
|
75
|
+
|
|
76
|
+
- **A filter that matches a path is not a filter that checks the caller** (C1-20).
|
|
77
|
+
`gate_coverage` published `possibly_filter_covered: 2635` over patterns `/*`,
|
|
78
|
+
`/api/*` and `/api/v1/*` — and those three filters were CORS, headers and logging,
|
|
79
|
+
while the only filter that authenticates covered two prefixes. The wording was
|
|
80
|
+
technically honest and the number was still *"falso consuelo"*: the corrected split
|
|
81
|
+
on that repository is 12 covered against 2 623 in the gap. Both halves of the join
|
|
82
|
+
were already in the same process, so the fix is an intersection **per filter**
|
|
83
|
+
rather than per pattern-set:
|
|
84
|
+
- `sourcecode/filter_surface.py` now records each declared filter (`@WebFilter`, and
|
|
85
|
+
`web.xml` mappings correlated with their `<filter-class>`) with a verdict —
|
|
86
|
+
`authenticates`, `does_not_authenticate`, `unknown` — decided structurally, never
|
|
87
|
+
by name (VAI): the filter establishes an identity, or it reads a credential *and*
|
|
88
|
+
refuses over it. A body that is not in this repository stays `unknown`, because
|
|
89
|
+
absence of evidence published as evidence of absence is the same defect mirrored.
|
|
90
|
+
- `gate_coverage` replaces the single count with four that partition the escape set:
|
|
91
|
+
`filter_covered_authenticating`, `filter_gap_non_authenticating`,
|
|
92
|
+
`filter_authentication_unknown`, `no_matching_filter_pattern`, plus a `filters`
|
|
93
|
+
list naming each filter, its patterns and the evidence behind its verdict.
|
|
94
|
+
|
|
95
|
+
- **Seven presentation rows, none of them an analysis error, two of which led a
|
|
96
|
+
reader to the inverse conclusion** (C2-15…C2-20, C1-19).
|
|
97
|
+
- `validation` printed *"0 body endpoints, 1179 gaps"* over a payload carrying
|
|
98
|
+
`body_endpoints_in_code: 1201` — the declared-constraint count under the
|
|
99
|
+
code-surface name. Both axes are named in their own units (C2-15).
|
|
100
|
+
- TX-006's witnesses all carried the callee's line, because that is where the
|
|
101
|
+
remedy goes, so several rows shared one number and read as duplicates. Each
|
|
102
|
+
finding now carries its `call_site` from the IR's span index, and the defect row
|
|
103
|
+
publishes the distinct sites with their count (C2-16).
|
|
104
|
+
- `limitations` merged across scopes repeated an entry verbatim; deduplicated once
|
|
105
|
+
in `finalize`, in first-seen order (C2-17).
|
|
106
|
+
- `spring_profiles.conditional_beans[].source_file` used the platform's native path
|
|
107
|
+
separator while the rest of the document used `/`; posix everywhere, including the
|
|
108
|
+
two other extractors that did the same (C2-18).
|
|
109
|
+
- `estimated_effort_range_days` published `{low: 60.7, high: 60.7}` — not a range,
|
|
110
|
+
at a precision the model does not have. The band declares `point_estimate` and
|
|
111
|
+
`precision_days`, and rounds to it (C2-19).
|
|
112
|
+
- `posture` cut four endpoint lists and its evidence map at 200 and declared
|
|
113
|
+
nothing, in the command whose declared caps the same evaluation calls a feature.
|
|
114
|
+
Each cut publishes total/shown/omitted and the registered cap effect; a list that
|
|
115
|
+
was not cut declares nothing (C2-20).
|
|
116
|
+
- Three commands published a file count for one repository — 3 337, 3 336, 3 342 —
|
|
117
|
+
and none said what it counted. Measured rather than equalised: all code-extension
|
|
118
|
+
files in any language, the non-test denominator of a test ratio, and the `.java`
|
|
119
|
+
files handed to the migration rules. Each names its population (C1-19).
|
|
120
|
+
|
|
121
|
+
- **`cache status` counts every store a warm fills** (C3-36). It printed `CAS blobs:
|
|
122
|
+
0`, `Total size: 0.1 MB` immediately after an 89-second warm of 3 342 files: true of
|
|
123
|
+
the per-repository core store, and the warm's output mostly lands in the shared
|
|
124
|
+
Canonical IR and the content-addressed parse cache, which the command never counted.
|
|
125
|
+
The status now breaks down by store, says what each holds, and labels the parse
|
|
126
|
+
cache shared across repositories so its size is not read as this repository's.
|
|
127
|
+
|
|
128
|
+
### Removed
|
|
129
|
+
|
|
130
|
+
- **BREAKING — `gate_coverage` no longer emits the three deprecated aliases** (C2-14).
|
|
131
|
+
`total_controller_handlers` counted *endpoints* under a name that says handlers,
|
|
132
|
+
`gate_bearing` counted *handler methods* while sitting beside an endpoint count, and
|
|
133
|
+
`not_carrying_gate` duplicated `endpoints_not_carrying_gate`. They were kept for a
|
|
134
|
+
two-minor window after C1-5 named the units; the seventh field evaluation read the
|
|
135
|
+
aliases anyway and quoted `total_controller_handlers: 3574` as handlers next to
|
|
136
|
+
`handler_methods_total: 913`. An alias that still ships is a live claim, and two of
|
|
137
|
+
these claimed the wrong unit. Read `endpoints_total`,
|
|
138
|
+
`handler_methods_carrying_gate` and `endpoints_not_carrying_gate`; the block now
|
|
139
|
+
carries `removed_fields` mapping each retired name to its successor, so a consumer
|
|
140
|
+
meets the answer rather than a `KeyError`. `possibly_filter_covered` is retired in
|
|
141
|
+
the same block and for the same reason (C1-20): it counted "a filter runs here" and
|
|
142
|
+
was read as "a filter checks here".
|
|
143
|
+
|
|
144
|
+
## [3.8.0] — 2026-08-02
|
|
145
|
+
|
|
146
|
+
### Added
|
|
147
|
+
|
|
148
|
+
- **The security surface publishes what it does not answer** (CL-2, CL-7, and the framing half
|
|
149
|
+
of CL-5). A report that lists what it found and says nothing about what it never looks at
|
|
150
|
+
invites silence to be read as absence — and the audit that raised this found a credential
|
|
151
|
+
versioned in three deployment descriptors *by hand*, because nothing here reads outside Java
|
|
152
|
+
and Spring configuration.
|
|
153
|
+
- One authority, `sourcecode/non_coverage.py`, read by three surfaces: the `non_coverage`
|
|
154
|
+
block in the `spring-audit` payload, the command's own `--help`, and the README section —
|
|
155
|
+
all rendered from the same table, because a curated list beside a generated one is how
|
|
156
|
+
`endpoints` went missing from every help list.
|
|
157
|
+
- Four rows for the security surface: no dataflow or taint (NC-001), no secrets outside Java
|
|
158
|
+
and Spring configuration (NC-002), filter-chain order not reconstructed (NC-003), no CVE
|
|
159
|
+
matching (NC-004). Each states why it is out of scope rather than unimplemented, and what
|
|
160
|
+
does answer it. Two more state the migration boundary (NC-005, OpenRewrite takes the
|
|
161
|
+
recipes this publishes) and the environment boundary (NC-006, answered as far as a
|
|
162
|
+
repository can by `posture --resolve-environments`).
|
|
163
|
+
- The evaluator's argument for publishing it is commercial, not ethical: *"un producto que
|
|
164
|
+
publica sus límites no se compara por amplitud; se compara por profundidad, que es donde
|
|
165
|
+
gana."*
|
|
166
|
+
|
|
167
|
+
### Changed
|
|
168
|
+
|
|
169
|
+
- **Two claims corrected with measured figures.** `--compact` is documented as the smallest
|
|
170
|
+
answer, **not the cheapest run** — 13.3 s cold on BroadleafCommerce against `spring-audit`
|
|
171
|
+
3.6 s and `posture` 1.9 s, 0.3 s warm — with the reason to warm before a session stated where
|
|
172
|
+
the claim is made (CL-3). And the product is positioned as the **diagnosis layer** until an
|
|
173
|
+
executor ships, in the field's own numbers (7/10 as a report generator, 5.5/10 as a
|
|
174
|
+
development tool) rather than argued with (CL-5).
|
|
175
|
+
|
|
176
|
+
- **`ask trend` is a top-level command, and capture is automatable** (P-4). The *series* is the
|
|
177
|
+
asset — a repository that captured a baseline at each release has a history nobody can
|
|
178
|
+
reconstruct afterwards, and one that did not never will — so reading it is no longer two words
|
|
179
|
+
deep, and [`docs/baseline-ci.yml`](docs/baseline-ci.yml) captures one per tag and publishes the
|
|
180
|
+
trend as a build artifact. `ask baseline trend` is the same command.
|
|
181
|
+
- The read-only half was a **documentation** gap and is closed where the auditor meets it:
|
|
182
|
+
`--dir` already existed, and the default now says *why* it is inside the repository (the
|
|
183
|
+
history travels with the code, not with a vendor) and that an audit which must leave the tree
|
|
184
|
+
untouched writes elsewhere. README and the user guide say the same.
|
|
185
|
+
- ⚠Adding the command surfaced the **C4-1 shape a sixth time**: `ask trend` was registered,
|
|
186
|
+
working and documented, and the CLI answered *"'trend' does not exist"* — because the
|
|
187
|
+
dispatcher matched against a **hand-written set of subcommand names**. It is derived from the
|
|
188
|
+
registry now, and the battery asserts every registered command is dispatchable.
|
|
189
|
+
|
|
190
|
+
- **`ask posture --resolve-environments` — which profile set actually runs, and the worst one
|
|
191
|
+
that could** (CL-8 / M9.5). `posture --diff` was called the strongest thing this product does
|
|
192
|
+
and it stopped at the repository boundary: which profile set runs is decided by the
|
|
193
|
+
deployment, so the answer was conditional and a field evaluator closed the last hops by hand
|
|
194
|
+
with `grep` (build profile → the property the build filters → a placeholder present in no
|
|
195
|
+
config file → no `context-param` in any descriptor → therefore nothing decides it).
|
|
196
|
+
- Those hops are now mechanical. Every artefact that can set `spring.profiles.active` is read
|
|
197
|
+
— config files, Maven/Gradle properties, `web.xml` context parameters, `Dockerfile` `ENV`
|
|
198
|
+
and `-D` arguments, Compose and Kubernetes manifests, launch scripts — each publishing what
|
|
199
|
+
it says with `file:line`. The verdict is `decided_in_repository`, `artefacts_disagree` (two
|
|
200
|
+
deployments, never a contradiction to resolve by picking one), or **`NOT DECIDED IN THIS
|
|
201
|
+
REPOSITORY`**.
|
|
202
|
+
- Every admissible profile set is then resolved over one parse and ranked by what it leaves
|
|
203
|
+
open, so the payload names the worst case and, where the repository does decide, how far the
|
|
204
|
+
shipped set is from it: *"one environment variable away from dev"*.
|
|
205
|
+
- **`open_by_rule` and `access_not_decided` are counted separately.** A readable rule that
|
|
206
|
+
permits a request unauthenticated is not the same fact as no readable rule matching it, and
|
|
207
|
+
folding them together would publish the confident security falsehood this command exists to
|
|
208
|
+
prevent. The reading says which is which.
|
|
209
|
+
- A value found in the repository is published as a default, never a guarantee:
|
|
210
|
+
`SPRING_PROFILES_ACTIVE` in the process environment outranks every artefact, and this
|
|
211
|
+
analysis cannot see the process environment.
|
|
212
|
+
|
|
213
|
+
- **`ask verify --init` derives the contracts a repository already satisfies** (C3-30). The gate
|
|
214
|
+
had no way to acquire what it gates on: nobody hand-writes contracts for a 3 300-file
|
|
215
|
+
monolith, so the honest gate (zero contracts is `unverified`, closed as C3-15) stayed empty —
|
|
216
|
+
and the gate is the recurring half of the value story, where an audit is bought once.
|
|
217
|
+
- Three shapes, each written with the measurement behind it: a path prefix whose endpoints all
|
|
218
|
+
carry the same policy today (`require_endpoint_security`), an audit pattern that fires
|
|
219
|
+
nowhere (`forbid_finding`), and an injection edge between two annotated populations that
|
|
220
|
+
does not occur, both populations large enough that the absence is a pattern rather than an
|
|
221
|
+
accident (`forbidden_edge`).
|
|
222
|
+
- **Every rule is executed before it is written.** The derived set runs through the same engine
|
|
223
|
+
`verify` runs, and anything that fails on the tree it came from is dropped and reported —
|
|
224
|
+
`verify --init` followed by `verify` passes by construction, asserted as a round trip in the
|
|
225
|
+
battery, together with the proof that the populated gate goes red when the invariant breaks.
|
|
226
|
+
- Violations that exist today are deliberately not proposed: that is debt for
|
|
227
|
+
`--capture-baseline`, a different claim from an invariant, and the payload says so per
|
|
228
|
+
rejected candidate.
|
|
229
|
+
- `--dry-run` prints without writing; an existing contracts file is never replaced without
|
|
230
|
+
`--force`.
|
|
231
|
+
|
|
232
|
+
- **`delta` and `contract-diff` take git refs** (C3-33). Both compared two *checkouts* while
|
|
233
|
+
`review-pr` in the same CLI already took `--since`, so comparing two commits meant
|
|
234
|
+
orchestrating worktrees first. In the evaluation that recorded this, that cost coverage rather
|
|
235
|
+
than convenience: the evaluator ran the full catalogue against a client monolith under a
|
|
236
|
+
promise to leave the environment byte-identical and **omitted both commands** rather than
|
|
237
|
+
create worktrees in someone else's repository.
|
|
238
|
+
- `ask delta --base-ref origin/main --head-ref HEAD [--repo <path>]`, same for
|
|
239
|
+
`contract-diff`. Two checkouts positionally still work, and the payload publishes a
|
|
240
|
+
`comparison` block saying which basis it used — with both refs and their resolved commits.
|
|
241
|
+
- **Reading a ref writes nothing to the repository.** `git archive` streams the tree into a
|
|
242
|
+
temporary directory that is removed on the way out: no `git worktree add` (which registers
|
|
243
|
+
administrative state under `.git/worktrees` and leaves it behind if the process dies), no
|
|
244
|
+
checkout, no stash, no index read. The battery asserts `git status` and `git worktree list`
|
|
245
|
+
are identical before and after.
|
|
246
|
+
- A ref this repository does not have is refused by name (`git_ref_not_found`, exit 1) and
|
|
247
|
+
never substituted with something nearby.
|
|
248
|
+
|
|
249
|
+
### Fixed
|
|
250
|
+
|
|
251
|
+
- **`retrieve` stopped publishing scores nothing computed** (C3-19, **`entities[].score` and
|
|
252
|
+
`explanation.score` are nullable**). `retrieve blast-radius` returned eighty dependents each
|
|
253
|
+
carrying `"score": 0.0`, beside an explanation whose own score was 92.43 — and the step that
|
|
254
|
+
orders those entities says in its own docstring that no score is computed. The same default put
|
|
255
|
+
a zero on every entity of every intent, and an `explanation` block with `winner: null,
|
|
256
|
+
score: 0.0` on the intents that return what they found rather than choose a winner: the shape
|
|
257
|
+
the field called *a ranking block that never ran*.
|
|
258
|
+
- Both fields are `None` when nothing wrote them. The order is real and structural, so the
|
|
259
|
+
payload states it: `entities_ranked_by` — *"reach from the target (direct before indirect),
|
|
260
|
+
then identity — a structural order, not a per-entity score"*.
|
|
261
|
+
- `retrieve` remains `[PARKED]`; this is the honesty fix the tier does not excuse.
|
|
262
|
+
|
|
263
|
+
- **`archetype` no longer scores an unmeasured HTTP surface as an absent one** (C3-7). The
|
|
264
|
+
command declares `endpoints` as a missing signal on runs with no root to read — and then
|
|
265
|
+
scored as if the answer were **0**, which is a measured statement. Inside the scorer that zero
|
|
266
|
+
did two things at once: it refuted `api-first` and it fired `worker`'s `event_no_http`
|
|
267
|
+
evidence, so a repository nobody measured came back classified as an event worker with the
|
|
268
|
+
reason published as if it were a finding (I-3/R9, inside a score).
|
|
269
|
+
- The count is nullable now. Unmeasured contributes nothing and says so in its own evidence
|
|
270
|
+
row; `event_no_http` requires the absence of HTTP as a *measured* fact. A measured zero
|
|
271
|
+
behaves exactly as before, which the battery asserts alongside the unmeasured case.
|
|
272
|
+
- Measured while closing it, and recorded rather than acted on: `archetype` on
|
|
273
|
+
BroadleafCommerce takes **9.3 s** (the field reported 22 s) and returns two high-confidence
|
|
274
|
+
dimensions of four, so the tier stays `[EXPERIMENTAL]` — the cost complaint does not
|
|
275
|
+
reproduce at that magnitude, and a command with two high-confidence answers is not a
|
|
276
|
+
candidate for `parked`.
|
|
277
|
+
|
|
278
|
+
- **The summary stopped costing more than the analyses it summarises** (C3-6, C3-21). Measured on
|
|
279
|
+
BroadleafCommerce with nothing warm: `--compact` **19.3 s → 13.3 s**, and with the parse cache
|
|
280
|
+
warm **14.0 s → 7.9 s**; `endpoints` **3.3 s → 1.4 s**. Two duplications inside one process, both
|
|
281
|
+
removed:
|
|
282
|
+
- The **core view was built twice on every cold run** — once for the L1 cache write and once for
|
|
283
|
+
the RIS update — and building it rebuilds the CIR. One repository state has one core view; both
|
|
284
|
+
writers now read it.
|
|
285
|
+
- The **endpoint extractor parsed every file itself** while `build_repo_ir` read the
|
|
286
|
+
content-addressed parse cache for the same bytes. A run that does both paid for the same parse
|
|
287
|
+
twice, and a warm cache measurably bought `endpoints` nothing — a fact this product published
|
|
288
|
+
in its own cache model. Same key, same extractor, same capture signature: the entry either side
|
|
289
|
+
writes is the entry the other reads. The cache-model rows for `endpoints` and the root command
|
|
290
|
+
are re-measured accordingly.
|
|
291
|
+
- The inversion is **narrowed, not gone**: `--compact` is still slower than `spring-audit`
|
|
292
|
+
(3.6 s) or `posture` (1.9 s), because it builds the summary *and* the core view where those
|
|
293
|
+
build one analysis each.
|
|
294
|
+
- **C3-21 does not reproduce on 3.7.0**: the cache hit that cost 2 647 ms now costs 1.6 s for
|
|
295
|
+
`explain` against a 1.6 s cold run, and the snapshot hit for `--compact` is 0.29 s. Recorded as
|
|
296
|
+
measured, not assumed closed.
|
|
297
|
+
- The battery pins the two mechanisms rather than wall-clock figures: a second extraction must
|
|
298
|
+
re-parse nothing, the cached and uncached answers must be identical, and one root run must
|
|
299
|
+
build the core view once.
|
|
300
|
+
|
|
301
|
+
- **A comment can no longer take a whole file out of the graph** (E-1). The declaration joiner
|
|
302
|
+
decided whether a line *starts* a type declaration by scanning raw text, so a comment carrying
|
|
303
|
+
`class` or `interface` followed by an identifier looked like a declaration head with its brace
|
|
304
|
+
on a later line — `/** Implements the interface only for the legacy path. */`, or a trailing
|
|
305
|
+
`// starter class is not an utility class` on an annotation. The join then swallowed the
|
|
306
|
+
annotation and the real declaration into one entry beginning with `@`, which the parser reads
|
|
307
|
+
as a pending annotation and never examines: the file contributed **zero symbols** — no type,
|
|
308
|
+
no endpoint, no transaction boundary — and a file that contributes nothing looks exactly like
|
|
309
|
+
a file with nothing in it, which is why no field report could ever name this.
|
|
310
|
+
- Comments are stripped before the keyword scan (block state carried across lines, string
|
|
311
|
+
literal aware), and the brace that ends a join must also be code, so a commented `{` no
|
|
312
|
+
longer cuts a real multi-line declaration in half.
|
|
313
|
+
- Measured A/B over six repositories: **open-banking-gateway recovers 6 types, three of them
|
|
314
|
+
Spring Boot application classes**; petclinic, eureka, openmrs-core, BroadleafCommerce and
|
|
315
|
+
keycloak are unchanged, and **no repository loses a symbol**.
|
|
316
|
+
|
|
317
|
+
- **`generate-tests` ranks by what depends on the file, not by how the file is named**
|
|
318
|
+
(C3-13, **`untested_sources[]` entries change shape**). Two rules, both name matching, both
|
|
319
|
+
measured on openmrs-core: admission kept only files whose name ends in one of five suffixes
|
|
320
|
+
(`Service.java`, `Controller.java`, `Repository.java`, `Mapper.java`, `RestController.java`),
|
|
321
|
+
reducing **866 production files to 11 candidates**; and coverage was a filename pair, so
|
|
322
|
+
`PersonServiceImpl` was a gap for want of a `PersonServiceImplTest`. What remained was ordered
|
|
323
|
+
by how often the substring `"public "` appears in the first 16 KB — while `blast_radius`,
|
|
324
|
+
transaction boundaries and endpoint exposure were already computed elsewhere in the same
|
|
325
|
+
product and never consulted.
|
|
326
|
+
- **Coverage is now a reach fact**: a type is covered when a test source reaches it — named
|
|
327
|
+
directly, or reached along the call, instantiation and injection edges a blast radius
|
|
328
|
+
already walks, through the interface the container wires it behind, or as a supertype of
|
|
329
|
+
something a test exercises. One forward traversal from every test type: 0.01 s on
|
|
330
|
+
BroadleafCommerce. Reaching is not asserting, so the coverage figure is a floor and the gap
|
|
331
|
+
list is a ceiling, and `notes` says so.
|
|
332
|
+
- **Admission is the population**, not a naming convention: openmrs-core 866 production files
|
|
333
|
+
→ **161 untested**, BroadleafCommerce 2 765 → **1 494**, published as `population` beside
|
|
334
|
+
the list.
|
|
335
|
+
- **Order is the measured axes** — endpoints reached, transaction boundaries declared, classes
|
|
336
|
+
that depend on it — reusing `caller_reach`, `spring_impact._collect_endpoints` and
|
|
337
|
+
`spring_semantic.boundaries_declared_within` rather than deriving them again. The weights
|
|
338
|
+
that fold the three into `score` are published with `rank_weights_basis: "assumption, not a
|
|
339
|
+
measurement"`, and the order is reproducible from the axes without accepting them.
|
|
340
|
+
- `untested_sources[]`/`test_gaps[]` rows drop `rank_score`, `public_method_count` and
|
|
341
|
+
`has_framework_annotations` — measurements of the replaced basis — and carry
|
|
342
|
+
`endpoints_reached`, `transaction_boundaries` and `caller_classes` instead. `path`, `score`
|
|
343
|
+
and `reason` are unchanged. The new `test_gap_ranking` block publishes the basis, the
|
|
344
|
+
population and the caps.
|
|
345
|
+
- Cost, measured cold: BroadleafCommerce 11.1 s → **15.3 s**, openmrs-core 5.1 s → 10.2 s. A
|
|
346
|
+
run whose IR cannot be built keeps the filename algorithm and publishes the
|
|
347
|
+
`test_reach_graph` signal with what taking it costs the answer (I-8).
|
|
348
|
+
|
|
349
|
+
- **`generate-tests` publishes its time budget, and a cache no longer defeats it** (C3-1). The
|
|
350
|
+
30 s cap was reachable only through `SOURCECODE_TESTS_TIMEOUT_MS`, a name in no help text —
|
|
351
|
+
the one knob that turns an empty answer into an answer was invisible to whoever was holding
|
|
352
|
+
the empty answer. `--timeout <seconds>` is now a documented flag (the variable still works;
|
|
353
|
+
the flag wins), and an exhausted budget publishes `analysis_budget` carrying the new
|
|
354
|
+
`time_budget` cap: *"an empty list here means the walk stopped, NOT that the repository has
|
|
355
|
+
nothing"*, with the budget, its source, and how to raise it.
|
|
356
|
+
- Closing it surfaced a sharper defect, measured: **the cache key ignored the budget**, so a
|
|
357
|
+
run that exhausted 2 s answered the re-run at 30 s from cache — the remedy the payload
|
|
358
|
+
names did nothing at all. The budget is now part of the cache identity, and an exhausted
|
|
359
|
+
result is never stored: an unfinished walk is worth re-running.
|
|
360
|
+
- Measured while closing it: the full scan on openmrs-core (3 300 files, cold cache) takes
|
|
361
|
+
**3.35 s** and returns 13 untested sources, so the field's empty payload does not reproduce
|
|
362
|
+
and the default budget is not the constraint it was taken for. The ranking half of C3-13
|
|
363
|
+
stays open — the command still matches file names while `blast_radius`, transactional
|
|
364
|
+
writes and endpoint exposure are already computed.
|
|
365
|
+
|
|
366
|
+
- **`review-pr` no longer counts documentation as a runtime change** (C3-11b). The field
|
|
367
|
+
reported a diff of 227 `.md` files as `runtime_changes: 228` — while every one of those
|
|
368
|
+
entries carried `artifact_type: "documentation"` and `change_effect: "documentation file (no
|
|
369
|
+
runtime impact)"`. The list contradicted its own members. Reproduced on a real git repository
|
|
370
|
+
(12 `.md` files + one touched controller): **13 → 1**. The classifier was never wrong;
|
|
371
|
+
membership was "not noise and not a build manifest", which admits everything else, and the
|
|
372
|
+
admission seam (K2) now asks whether the admitted type can carry runtime behaviour at all.
|
|
373
|
+
- Nothing is dropped: the twelve are reported under `non_runtime_changes` with the same
|
|
374
|
+
evidence and effect statement, and the GitHub comment names them by count so it cannot look
|
|
375
|
+
like it missed part of the diff.
|
|
376
|
+
- The split is asserted **against the effect statements themselves** — a type whose published
|
|
377
|
+
statement disclaims impact must be in the non-runtime set — so it cannot drift from the
|
|
378
|
+
prose it is derived from (C4-1).
|
|
379
|
+
|
|
380
|
+
- **One profile population, whatever surface is asked** (C1-18, **`spring_profiles` changes on
|
|
381
|
+
repositories with resource bundles or resource folders**). Reproduced on a fixture first: the
|
|
382
|
+
same repository in one session answered `["qa","dev"]` in the default view, `["dev","prod",
|
|
383
|
+
"staging"]` in `posture` and `["dev","prod","qa","staging"]` under `--agent`. Three
|
|
384
|
+
populations under one name — and every conditional-security finding is keyed on that set, so
|
|
385
|
+
the default agent surface was answering the profile question with the population that had
|
|
386
|
+
lost the environments.
|
|
387
|
+
- Authority `spring_profiles.profile_population`: four named signals — the
|
|
388
|
+
`application-{profile}` filename, the per-environment overlay directory,
|
|
389
|
+
`spring.config.activate.on-profile` / `spring.profiles` inside config documents, and
|
|
390
|
+
`@Profile` on a bean — unioned once, with `by_signal` published so each name's provenance
|
|
391
|
+
is auditable. The Java stack detector, `posture` and the serializer's profile section all
|
|
392
|
+
read it, asserted per surface.
|
|
393
|
+
- Closing it exposed two false positives in the signals it inherited, both fixed
|
|
394
|
+
structurally rather than by name (VAI): an `application-{x}` file counts only **beside its
|
|
395
|
+
base config** — alfresco-community-repo's `alfresco/messages/application-model_de.properties`
|
|
396
|
+
and 19 siblings were reported as twenty environments, now none — and an overlay directory
|
|
397
|
+
counts only when it **holds a config file** — spring-petclinic's `db/`, `messages/`,
|
|
398
|
+
`static/` and `templates/` were reported as four environments, now `mysql, postgres`, its
|
|
399
|
+
real profiles.
|
|
400
|
+
|
|
401
|
+
- **The token-saving ratio is published, and published as a ceiling** (CL-1). `token_economy`
|
|
402
|
+
emitted `emitted`, `baseline_raw_read` and `saved` — three numbers a reader divides into a
|
|
403
|
+
multiple and then quotes. The multiple travelled without the label the block put on the
|
|
404
|
+
inputs, which is how "up to 55×" ends up in a room. `ratio_upper_bound` is now emitted with
|
|
405
|
+
a `ratio_basis` that states the counterfactual making it a ceiling — every cited file and
|
|
406
|
+
build manifest read **in full and once** — the band we measured for the ceiling itself
|
|
407
|
+
(**3.8×–37.6×** over `--compact` and `--agent` on spring-petclinic, BroadleafCommerce,
|
|
408
|
+
openmrs-core and keycloak; nothing near 55×), and the field's 10×–20× read of the saving an
|
|
409
|
+
agent actually realizes.
|
|
410
|
+
- `realized_saving` is `null` with its reason rather than a number: which files an agent would
|
|
411
|
+
truly have read is not observable from this process, and a `0` there would read as "no
|
|
412
|
+
saving" (I-3).
|
|
413
|
+
|
|
414
|
+
- **`spring-audit` counts defects as well as observations** (C2-5). A rule fires per
|
|
415
|
+
observation; a reader counts repairs. The audit published only the first number and let it
|
|
416
|
+
stand for the second: on openmrs-core `ConceptServiceImpl#checkIfLocked` carried **six
|
|
417
|
+
TX-006 findings, one per call site, for one annotated method with one fix**, and the
|
|
418
|
+
ledger's original witness is a private `@Transactional` method that draws TX-001 *and*
|
|
419
|
+
TX-006 for the same repair. Measured on the fleet: **openmrs-core 38 findings → 29
|
|
420
|
+
defects, BroadleafCommerce 19 → 14**.
|
|
421
|
+
- A defect is `(category, defect_kind, symbol)` — the thing you edit, and what is wrong
|
|
422
|
+
with it. `defect_kind` is **declared by the rule itself** (TX-001 and TX-006 both
|
|
423
|
+
declare `proxy_bypass`) and defaults to the rule's own id, so a rule that declares
|
|
424
|
+
nothing is never merged into another by omission, and there is no rule table maintained
|
|
425
|
+
beside the rules to drift out of date (C4-1).
|
|
426
|
+
- Nothing is filtered. `findings[]` keeps every observation and each one now names its
|
|
427
|
+
`defect_id`; the new `defects[]` rows carry `rule_ids`, `witness_count` and the witness
|
|
428
|
+
ids, so the grouping is auditable in both directions. `summary` publishes
|
|
429
|
+
`total_findings`, `total_defects`, `defects_by_severity` and a `counts_note` stating
|
|
430
|
+
which is which — `by_severity` and `by_category` keep counting observations, because a
|
|
431
|
+
count that changes basis under an unchanged name is the same defect wearing a new suit.
|
|
432
|
+
- A defect takes the **strongest** severity and confidence among its witnesses, and its id
|
|
433
|
+
is keyed on the identity, not the witnesses — acquiring a second witness next run does
|
|
434
|
+
not rename it, so a baseline keeps matching it.
|
|
435
|
+
|
|
436
|
+
- **`migrate-check` lists the blockers; hygiene is counted, not listed** (C2-6, **default
|
|
437
|
+
payload changes**). On openmrs-core the default report carried 310 findings of which **184
|
|
438
|
+
were `java_8_best_practice` advisory hygiene** — findings that block no version and that
|
|
439
|
+
every readiness score already excludes. A reader scanning the array met three advisory
|
|
440
|
+
entries for every two blockers. The emitted list now carries the blockers, ordered
|
|
441
|
+
most-severe first (**310 → 126 listed, 912 KB → 717 KB**), and `--include-hygiene` restores
|
|
442
|
+
the entries.
|
|
443
|
+
- **The floor cuts the list, never a figure.** `summary.by_severity`, `by_rule`,
|
|
444
|
+
`by_migration_target`, `total_findings`, `hygiene_findings`, `blocking_count` and every
|
|
445
|
+
dimension score are byte-identical to the unfloored run and still cover the whole
|
|
446
|
+
population — verified as an equality, not a claim.
|
|
447
|
+
- It is published as a cap, not applied in silence: `findings_floor` (the `severity_floor`
|
|
448
|
+
row of `CAP_EFFECTS`, I-8) states what was removed, what stayed exact, and the flag that
|
|
449
|
+
restores it, so `len(findings)` is never read as the total.
|
|
450
|
+
- The other half of the ledger row — "headline score reads 0/100 while real blockers are
|
|
451
|
+
481" — was already closed and re-measured here: hygiene is out of the aggregate, and
|
|
452
|
+
openmrs's 0 is `min(jakarta 0, hibernate 0)` with `jdk_modernization` (58) excluded by
|
|
453
|
+
design. The score was honest; the finding list was the noise.
|
|
454
|
+
|
|
3
455
|
## [3.7.0] — 2026-08-01
|
|
4
456
|
|
|
5
457
|
**The exit-code contract and the C3 surface block.** Seven rows closed: the two the field named
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.0
|
|
4
4
|
Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Keywords: agents,ai,codebase,context,developer-tools,llm
|
|
@@ -220,7 +220,7 @@ experimental: both are true, and they are two different facts.
|
|
|
220
220
|
|---|---|---|
|
|
221
221
|
| **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
|
|
222
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` |
|
|
223
|
+
| **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `posture` · `archetype` |
|
|
224
224
|
| **parked** | kept working, no longer developed | `retrieve` |
|
|
225
225
|
|
|
226
226
|
The same table is printed by `ask --help`, and both are generated from one authority
|
|
@@ -237,6 +237,7 @@ from it.
|
|
|
237
237
|
| Command | Tier | Answers | Note |
|
|
238
238
|
|---|---|---|---|
|
|
239
239
|
| `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
|
|
240
|
+
| `risk` | experimental | what each defect actually costs, once reach, access and write effect are in it | `defect_severity × reachability × auth_verdict × write_effect`; every factor names its authority |
|
|
240
241
|
| `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators) |
|
|
241
242
|
| `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment` |
|
|
242
243
|
| `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan |
|
|
@@ -251,7 +252,7 @@ from it.
|
|
|
251
252
|
| `review-pr` / `fix-bug` / `prepare-context` | supported | diff review, symptom triage, task-shaped context | |
|
|
252
253
|
| `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
254
|
| `validation` | supported | request-body validation coverage and gaps | |
|
|
254
|
-
| `baseline capture\|diff
|
|
255
|
+
| `baseline capture\|diff` · `trend` | supported | versioned architectural metrics over time; `ask trend <dir>` reads the series | trend reporting, not gating. Baselines land in `.ask/baselines` **inside the repository** — the history travels with the code, not with a vendor; an audit that must not write passes `--dir`. Automate it: [baseline-ci.yml](docs/baseline-ci.yml) |
|
|
255
256
|
| `retrieve` | parked | typed knowledge queries over the model | |
|
|
256
257
|
| `archetype` | experimental | evidence-based architectural archetype | |
|
|
257
258
|
| `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
|
|
@@ -275,6 +276,34 @@ Honest limits worth knowing before you rely on it:
|
|
|
275
276
|
- Architecture classification is tuned for Spring MVC layered apps; SPI/plugin models (e.g. Quarkus extensions) may be misclassified. JAX-RS subresource-locator endpoint recall is ~65%.
|
|
276
277
|
- Self-invocation `@Transactional` bypass (same-class call skipping the proxy) is not detected.
|
|
277
278
|
|
|
279
|
+
### What the security surface does not answer
|
|
280
|
+
|
|
281
|
+
Published because a product that states its limits is not compared on breadth — it is
|
|
282
|
+
compared on depth. Each row is emitted in the payload too (`non_coverage`), so an agent
|
|
283
|
+
reading JSON sees the same boundary a buyer reads here.
|
|
284
|
+
|
|
285
|
+
| Not covered | Why | What answers it |
|
|
286
|
+
|---|---|---|
|
|
287
|
+
| **Whether request input reaches a sink — no dataflow or taint analysis.** | This engine resolves structure and wiring without compiling. Taint needs value flow through a program, which is a different analysis with a different failure mode: an unsound one produces confident findings that are wrong, and every claim here is meant to be checkable against the line that produced it. | A dataflow scanner (Semgrep, CodeQL). What this product adds on top is reachability: which of that tool's findings sit behind an endpoint that is reachable unauthenticated. |
|
|
288
|
+
| **Secrets outside Java and Spring configuration — a credential in a deployment descriptor, a Helm value, a CI variable file.** | The file population this analyzer reads is the Java source and the Spring configuration convention. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
|
|
289
|
+
| **Filter-chain order and per-filter URL patterns — the presence of a custom filter is structural only.** | Which filter runs first is decided by bean ordering this analyzer does not resolve. Where two active configurations both match a request, the answer published is `undecided` rather than a guess. | `ask posture --profile <set>` states per endpoint what the readable rules decide and what they leave undecided. |
|
|
290
|
+
| **Known vulnerabilities in dependencies — no CVE database, no version advisory matching.** | Enriching a vulnerability feed is a different product with a different update cadence; a stale embedded database is worse than no database, because it reads as a clean bill of health. | A dependency scanner (Trivy, OWASP Dependency-Check). `impact-chain` then answers which of its findings anything actually reaches. |
|
|
291
|
+
|
|
292
|
+
Two more boundaries worth stating in the same voice:
|
|
293
|
+
|
|
294
|
+
| Not covered | Why | What answers it |
|
|
295
|
+
|---|---|---|
|
|
296
|
+
| **Applying a migration — nothing here edits source.** | This is the diagnosis layer: it measures what must change and what each change would reach. Rewriting code is an execution problem with an established executor, and duplicating it would mean maintaining a second, worse one. | OpenRewrite. `migrate-check` publishes the recipe each finding carries (`recipes[]`), which is the input that executor takes. |
|
|
297
|
+
| **What the process environment sets at start-up — the profile set, properties and secrets a container is given.** | Nothing in a repository can observe the environment of a process that has not started. A value read from a file here is the default the repository ships, never a guarantee of what runs. | `ask posture --resolve-environments` reads every artefact in the repository that names the profile set, says when none of them decides it, and ranks the admissible sets by what each leaves open. |
|
|
298
|
+
|
|
299
|
+
**Positioning.** Until an executor ships, this is the **diagnosis layer**: it measures what
|
|
300
|
+
must change, what each change reaches, and what a gate should block — and it removes none of
|
|
301
|
+
it. Field evaluation scored it 7/10 as a report generator and 5.5/10 as a development tool,
|
|
302
|
+
and that gap is the honest description, not a defect to argue with. `migrate-check` publishes
|
|
303
|
+
the OpenRewrite recipe each finding carries so the executor that does apply changes has its
|
|
304
|
+
input.
|
|
305
|
+
|
|
306
|
+
|
|
278
307
|
---
|
|
279
308
|
|
|
280
309
|
## Pricing
|
|
@@ -348,7 +377,8 @@ Matching endpoints report `policy: "custom"` and drop out of the `no_security_si
|
|
|
348
377
|
| Doc | What it covers |
|
|
349
378
|
|-----|----------------|
|
|
350
379
|
| [USER_GUIDE.md](docs/USER_GUIDE.md) | Full command reference, flags, output schema, workflows |
|
|
351
|
-
| [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml
|
|
380
|
+
| [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml` (or derive them with `ask verify --init`), enforce them in the edit loop and in CI |
|
|
381
|
+
| [baseline-ci.yml](docs/baseline-ci.yml) | Capture an architectural baseline per release, so the series exists when you want to read it |
|
|
352
382
|
| [posture.md](docs/posture.md) | What a profile set actually wires — down to which endpoints its filter chain permits — and what could not be decided (experimental) |
|
|
353
383
|
| [migrate-check.md](docs/migrate-check.md) | Migration rule catalogue (MIG-001..043) + Hibernate stratification |
|
|
354
384
|
| [MODERNIZATION.md](docs/MODERNIZATION.md) | The modernization product: assess → understand → plan → execute |
|
|
@@ -182,7 +182,7 @@ experimental: both are true, and they are two different facts.
|
|
|
182
182
|
|---|---|---|
|
|
183
183
|
| **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
|
|
184
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` |
|
|
185
|
+
| **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `posture` · `archetype` |
|
|
186
186
|
| **parked** | kept working, no longer developed | `retrieve` |
|
|
187
187
|
|
|
188
188
|
The same table is printed by `ask --help`, and both are generated from one authority
|
|
@@ -199,6 +199,7 @@ from it.
|
|
|
199
199
|
| Command | Tier | Answers | Note |
|
|
200
200
|
|---|---|---|---|
|
|
201
201
|
| `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
|
|
202
|
+
| `risk` | experimental | what each defect actually costs, once reach, access and write effect are in it | `defect_severity × reachability × auth_verdict × write_effect`; every factor names its authority |
|
|
202
203
|
| `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators) |
|
|
203
204
|
| `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment` |
|
|
204
205
|
| `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan |
|
|
@@ -213,7 +214,7 @@ from it.
|
|
|
213
214
|
| `review-pr` / `fix-bug` / `prepare-context` | supported | diff review, symptom triage, task-shaped context | |
|
|
214
215
|
| `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
216
|
| `validation` | supported | request-body validation coverage and gaps | |
|
|
216
|
-
| `baseline capture\|diff
|
|
217
|
+
| `baseline capture\|diff` · `trend` | supported | versioned architectural metrics over time; `ask trend <dir>` reads the series | trend reporting, not gating. Baselines land in `.ask/baselines` **inside the repository** — the history travels with the code, not with a vendor; an audit that must not write passes `--dir`. Automate it: [baseline-ci.yml](docs/baseline-ci.yml) |
|
|
217
218
|
| `retrieve` | parked | typed knowledge queries over the model | |
|
|
218
219
|
| `archetype` | experimental | evidence-based architectural archetype | |
|
|
219
220
|
| `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
|
|
@@ -237,6 +238,34 @@ Honest limits worth knowing before you rely on it:
|
|
|
237
238
|
- Architecture classification is tuned for Spring MVC layered apps; SPI/plugin models (e.g. Quarkus extensions) may be misclassified. JAX-RS subresource-locator endpoint recall is ~65%.
|
|
238
239
|
- Self-invocation `@Transactional` bypass (same-class call skipping the proxy) is not detected.
|
|
239
240
|
|
|
241
|
+
### What the security surface does not answer
|
|
242
|
+
|
|
243
|
+
Published because a product that states its limits is not compared on breadth — it is
|
|
244
|
+
compared on depth. Each row is emitted in the payload too (`non_coverage`), so an agent
|
|
245
|
+
reading JSON sees the same boundary a buyer reads here.
|
|
246
|
+
|
|
247
|
+
| Not covered | Why | What answers it |
|
|
248
|
+
|---|---|---|
|
|
249
|
+
| **Whether request input reaches a sink — no dataflow or taint analysis.** | This engine resolves structure and wiring without compiling. Taint needs value flow through a program, which is a different analysis with a different failure mode: an unsound one produces confident findings that are wrong, and every claim here is meant to be checkable against the line that produced it. | A dataflow scanner (Semgrep, CodeQL). What this product adds on top is reachability: which of that tool's findings sit behind an endpoint that is reachable unauthenticated. |
|
|
250
|
+
| **Secrets outside Java and Spring configuration — a credential in a deployment descriptor, a Helm value, a CI variable file.** | The file population this analyzer reads is the Java source and the Spring configuration convention. A secret elsewhere is not missed by a weak rule; it is outside the set of files anything here opens. | A dedicated secret scanner over the whole tree (gitleaks, trufflehog). |
|
|
251
|
+
| **Filter-chain order and per-filter URL patterns — the presence of a custom filter is structural only.** | Which filter runs first is decided by bean ordering this analyzer does not resolve. Where two active configurations both match a request, the answer published is `undecided` rather than a guess. | `ask posture --profile <set>` states per endpoint what the readable rules decide and what they leave undecided. |
|
|
252
|
+
| **Known vulnerabilities in dependencies — no CVE database, no version advisory matching.** | Enriching a vulnerability feed is a different product with a different update cadence; a stale embedded database is worse than no database, because it reads as a clean bill of health. | A dependency scanner (Trivy, OWASP Dependency-Check). `impact-chain` then answers which of its findings anything actually reaches. |
|
|
253
|
+
|
|
254
|
+
Two more boundaries worth stating in the same voice:
|
|
255
|
+
|
|
256
|
+
| Not covered | Why | What answers it |
|
|
257
|
+
|---|---|---|
|
|
258
|
+
| **Applying a migration — nothing here edits source.** | This is the diagnosis layer: it measures what must change and what each change would reach. Rewriting code is an execution problem with an established executor, and duplicating it would mean maintaining a second, worse one. | OpenRewrite. `migrate-check` publishes the recipe each finding carries (`recipes[]`), which is the input that executor takes. |
|
|
259
|
+
| **What the process environment sets at start-up — the profile set, properties and secrets a container is given.** | Nothing in a repository can observe the environment of a process that has not started. A value read from a file here is the default the repository ships, never a guarantee of what runs. | `ask posture --resolve-environments` reads every artefact in the repository that names the profile set, says when none of them decides it, and ranks the admissible sets by what each leaves open. |
|
|
260
|
+
|
|
261
|
+
**Positioning.** Until an executor ships, this is the **diagnosis layer**: it measures what
|
|
262
|
+
must change, what each change reaches, and what a gate should block — and it removes none of
|
|
263
|
+
it. Field evaluation scored it 7/10 as a report generator and 5.5/10 as a development tool,
|
|
264
|
+
and that gap is the honest description, not a defect to argue with. `migrate-check` publishes
|
|
265
|
+
the OpenRewrite recipe each finding carries so the executor that does apply changes has its
|
|
266
|
+
input.
|
|
267
|
+
|
|
268
|
+
|
|
240
269
|
---
|
|
241
270
|
|
|
242
271
|
## Pricing
|
|
@@ -310,7 +339,8 @@ Matching endpoints report `policy: "custom"` and drop out of the `no_security_si
|
|
|
310
339
|
| Doc | What it covers |
|
|
311
340
|
|-----|----------------|
|
|
312
341
|
| [USER_GUIDE.md](docs/USER_GUIDE.md) | Full command reference, flags, output schema, workflows |
|
|
313
|
-
| [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml
|
|
342
|
+
| [contracts.md](docs/contracts.md) | Declare invariants in `.ask/contracts.yml` (or derive them with `ask verify --init`), enforce them in the edit loop and in CI |
|
|
343
|
+
| [baseline-ci.yml](docs/baseline-ci.yml) | Capture an architectural baseline per release, so the series exists when you want to read it |
|
|
314
344
|
| [posture.md](docs/posture.md) | What a profile set actually wires — down to which endpoints its filter chain permits — and what could not be decided (experimental) |
|
|
315
345
|
| [migrate-check.md](docs/migrate-check.md) | Migration rule catalogue (MIG-001..043) + Hibernate stratification |
|
|
316
346
|
| [MODERNIZATION.md](docs/MODERNIZATION.md) | The modernization product: assess → understand → plan → execute |
|