sourcecode 3.8.0__tar.gz → 4.0.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.8.0 → sourcecode-4.0.1}/CHANGELOG.md +180 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/PKG-INFO +52 -5
- {sourcecode-3.8.0 → sourcecode-4.0.1}/README.md +51 -4
- {sourcecode-3.8.0 → sourcecode-4.0.1}/pyproject.toml +1 -1
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/__init__.py +1 -1
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/cache.py +48 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/cache_model.py +7 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/cli.py +162 -23
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/confidence_analyzer.py +7 -2
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/defect_identity.py +24 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/environment_resolution.py +1 -1
- sourcecode-4.0.1/src/sourcecode/filter_surface.py +404 -0
- sourcecode-4.0.1/src/sourcecode/identity_fallback.py +244 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/migrate_check.py +27 -5
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/parse_cache.py +23 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/posture.py +57 -4
- sourcecode-4.0.1/src/sourcecode/remedies.py +104 -0
- sourcecode-4.0.1/src/sourcecode/risk.py +345 -0
- sourcecode-4.0.1/src/sourcecode/rule_catalog.py +107 -0
- sourcecode-4.0.1/src/sourcecode/security_config_scan.py +262 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/security_posture.py +216 -23
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_findings.py +13 -3
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_profiles.py +6 -2
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_properties.py +1 -1
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_security_audit.py +91 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_tx_analyzer.py +42 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/summarizer.py +7 -2
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/verify_repo.py +8 -0
- sourcecode-3.8.0/src/sourcecode/filter_surface.py +0 -173
- {sourcecode-3.8.0 → sourcecode-4.0.1}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/.gitignore +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/.ruff.toml +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/CONTRIBUTING.md +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/LICENSE +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/SECURITY.md +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/raw +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/scripts/compare_integration_engines.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/scripts/customer_smoke_test.sh +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/scripts/generate_jdk_exports.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/scripts/perf_harness.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/archetype.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/architectural_baseline.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/architectural_delta.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/call_surface.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/caller_metrics.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/caller_reach.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/chain_rules.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/change_plan.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/classifier.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/compare.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/constraint_diff.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/context_cache.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/context_graph.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/contract_diff.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/contract_init.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/degradation.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/deployment_prefix.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/dynamic_argument_surface.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/endpoint_literals.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/endpoint_metrics.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/envelope.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/evidence_provider.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/explain.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/facts/__init__.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/facts/registry.json +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/format_contract.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/git_checkout.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/graph_evidence.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/hibernate_strat.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/integration_coordinates.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/jdk_exports.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/license.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/migration_blast.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/non_coverage.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/path_admission.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/perf.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/pipe_contract.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/progress.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/readiness_timeline.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/reconciliation.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/redactor.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/reference_facts.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/repository_ir.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/__init__.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/context.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/errors.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/executor.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/planner.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/query.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/request.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/resolution.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/result.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/retriever.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/runtime.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/steps.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/steps_graph.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/steps_impact.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/steps_intf.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/steps_struct.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/retrieval/steps_txsec.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/ris.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/scanner.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/schema.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/security_config.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/semantic_impact_engine.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/semantic_integration_engine.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/semantic_services.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/serializer.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_impact.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/target_admission.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/test_gap_ranking.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/test_sources.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/token_estimate.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/type_usage_surface.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/validation_inference.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/validation_surface.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/verify_edit.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/verify_rules.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/version_check.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/src/sourcecode/workspace.py +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/supabase/functions/README.md +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/supabase/sql/licensing_schema.sql +0 -0
- {sourcecode-3.8.0 → sourcecode-4.0.1}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -2,6 +2,186 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [4.0.1] — 2026-08-02
|
|
6
|
+
|
|
7
|
+
Patch, and the criterion is the one this project has used since 3.2.0: nothing here
|
|
8
|
+
moves a published field, an exit code or a default. Three surfaces stopped
|
|
9
|
+
misdescribing an engine that did not change — the release advertised half its own
|
|
10
|
+
security ruleset, the front page led to neither capability the field asked for by
|
|
11
|
+
name, and the document both of them call the full command reference covered fewer
|
|
12
|
+
than half the commands. All three were found in-house.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **`spring-audit --help` advertised three security rules and the build ships six**
|
|
17
|
+
(C4-9). The one-liner the root panel prints, and the command's own screen, said
|
|
18
|
+
`security surface (SEC-001..003)` two releases after CL-9 shipped SEC-004, SEC-005
|
|
19
|
+
and SEC-006; `docs/PRODUCT_TIERS.md` said `TX-001..005 + SEC-001..003` and
|
|
20
|
+
`docs/USER_GUIDE.md` said `TX-001..TX-005`. The engine was right in every case —
|
|
21
|
+
the product advertised half its ruleset, in the release that answered the field's
|
|
22
|
+
complaint about security recall. `sourcecode/rule_catalog.py` now holds one summary
|
|
23
|
+
line per rule and the help renders from it, while the id *set* is derived from the
|
|
24
|
+
shipped pattern registries by `tests/test_rule_catalog.py`: a seventh rule fails the
|
|
25
|
+
build until it is documented, and no surface may name a rule the build cannot emit.
|
|
26
|
+
The non-coverage block in the same help is rendered from `non_coverage` too, which
|
|
27
|
+
had a renderer with no consumer beside four rows restated by hand.
|
|
28
|
+
- **The front page did not lead to either remedy that C4-8 closed** (C4-10). The
|
|
29
|
+
pointer lived in the payload that states the limitation, which reaches an agent and
|
|
30
|
+
not a reader who has not run the command yet — the same reader who wrote
|
|
31
|
+
`ask posture --provenance` and `ask contracts init` by hand after a full session.
|
|
32
|
+
`ask --help` now renders a *Questions the repository alone does not answer* block
|
|
33
|
+
from `remedies.REMEDIES`, and lists `risk .` in Start here; the README carries
|
|
34
|
+
`--resolve-environments`, `verify --init` and `ask risk` in the Quickstart,
|
|
35
|
+
`--resolve-environments` in §5b beside the `--diff` it qualifies, and a §5c for
|
|
36
|
+
composed risk. `tests/test_remedies.py` fails when a remedy is absent from either
|
|
37
|
+
surface.
|
|
38
|
+
- **The "full command reference" documented 14 of 32 commands** (C4-11). `verify`,
|
|
39
|
+
`verify-edit` and `pr-impact` — the three gate commands — appeared only as names in
|
|
40
|
+
the tier table, and eight more had no occurrence in the file at all. Sections added
|
|
41
|
+
for the gate family (with the exit-code contract they share), for `plan`, `compare`,
|
|
42
|
+
`delta` and `contract-diff`, and a table for the rest.
|
|
43
|
+
`tests/test_user_guide_coverage.py` takes the command population from the CLI and
|
|
44
|
+
parses every invocation the guide prints against it.
|
|
45
|
+
|
|
46
|
+
## [4.0.0] — 2026-08-02
|
|
47
|
+
|
|
48
|
+
Major because two published `gate_coverage` fields are removed, not because the
|
|
49
|
+
engine changed shape: `total_controller_handlers` / `gate_bearing` /
|
|
50
|
+
`not_carrying_gate` (C2-14, the announced end of their two-minor window) and
|
|
51
|
+
`possibly_filter_covered` (C1-20, which had no window — it counted the wrong thing).
|
|
52
|
+
`removed_fields` in the same block maps each retired name to its successor.
|
|
53
|
+
|
|
54
|
+
This release closes fourteen of the sixteen rows opened by the seventh field
|
|
55
|
+
evaluation, in the order that record argued for, and ships `ask risk` — the first
|
|
56
|
+
command that composes the other answers instead of adding one.
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
|
|
60
|
+
- **`ask risk` — the composition layer** (M10 head; [EXPERIMENTAL]). The seventh
|
|
61
|
+
evaluation's thesis was *"ASK tiene todos los átomos y no forma moléculas"*: one
|
|
62
|
+
class was `medium` in `spring-audit`, `medium/5.0` in `impact-chain`,
|
|
63
|
+
`coverage_unknown → permit_all` in `posture`, and executed a stored procedure that
|
|
64
|
+
mutates the database. Composed, that is unauthenticated write access under the
|
|
65
|
+
release build; separately, it was two commands saying "medium" and a reader doing
|
|
66
|
+
the join by hand.
|
|
67
|
+
`severity_effective = defect_severity × reachability × auth_verdict × write_effect`,
|
|
68
|
+
emitted as an ordered list. No new analysis — every factor is read from the
|
|
69
|
+
authority that already publishes it, and every row carries its four factors with
|
|
70
|
+
their sources, so a reader can reject one and keep the rest. An axis that could
|
|
71
|
+
not be measured is `unknown`, multiplies by 1.0, and is named in `blind_axes`:
|
|
72
|
+
the composition may not invent what nobody measured. This is the item that
|
|
73
|
+
*"crea producto"* rather than correcting data, and the one nobody replicates by
|
|
74
|
+
combining three scanners, because none of them shares an endpoint id with the
|
|
75
|
+
others.
|
|
76
|
+
|
|
77
|
+
- **Three textbook security rules, because silence has to mean something** (CL-9).
|
|
78
|
+
The seventh evaluation got one security finding out of 3 342 files, then found
|
|
79
|
+
three more by hand in three files ASK had pointed it at. `SEC-004` (passwords
|
|
80
|
+
stored under a fast unsalted digest), `SEC-005` (CSRF disabled under
|
|
81
|
+
session-bearing authentication) and `SEC-006` (a cookie created without the Secure
|
|
82
|
+
attribute) ship in the `spring-audit` security surface, from one scan
|
|
83
|
+
(`sourcecode/security_config_scan.py`) with `file:line`. Each requires a
|
|
84
|
+
security-configuration context, so SHA-1 over a response body stays an ETag and a
|
|
85
|
+
stateless API that disables CSRF is not reported — a rule that cannot tell those
|
|
86
|
+
apart is one teams switch off, after which it protects nothing. These are table
|
|
87
|
+
stakes rather than differentiation: closing them avoids losing the sale.
|
|
88
|
+
|
|
89
|
+
- **A third verdict for a gate that authorises against an identity nobody proved**
|
|
90
|
+
(C1-21). 939 endpoints in the field were reported `protected_custom` for carrying a
|
|
91
|
+
real gate — whose aspect resolves the caller through a method that returns a
|
|
92
|
+
database user when the authentication is null. The check runs; what it decides on,
|
|
93
|
+
for a request carrying no credential, is an identity the application invented, and
|
|
94
|
+
the vocabulary had no way to say so.
|
|
95
|
+
- `sourcecode/identity_fallback.py` (extractor) reports a method that reads the
|
|
96
|
+
platform's identity and, in a branch guarded by that identity being absent,
|
|
97
|
+
returns one anyway. Throwing, denying and returning null are correct handling and
|
|
98
|
+
are never reported; nothing branches on a method or class name (VAI).
|
|
99
|
+
- `security_posture` follows the enforcement path — types carrying published AOP
|
|
100
|
+
advice vocabulary or implementing a request-chain SPI — over `calls` edges, and
|
|
101
|
+
emits `protected_custom_degraded` (confidence `RequiresManualReview`) with an
|
|
102
|
+
`identity_resolution` block naming the method, the absence test and what it
|
|
103
|
+
returns. A fallback the enforcement path does not reach is not charged to the
|
|
104
|
+
gate.
|
|
105
|
+
|
|
106
|
+
- **The remedy travels with the limitation** (C4-8, C3-37). The evaluation's requests
|
|
107
|
+
#1 and #5 — written by hand with invented syntax — are `posture
|
|
108
|
+
--resolve-environments` and `verify --init`, both shipped in the build it audited.
|
|
109
|
+
Four earlier rows say the same thing: discoverability cannot live in a document,
|
|
110
|
+
because a reader looking at an output does not go and read `--help`. One registry
|
|
111
|
+
(`sourcecode/remedies.py`), keyed by the question rather than by the flag, is read
|
|
112
|
+
by `posture.activation`, `posture --diff`, the `security_posture` limitation that is
|
|
113
|
+
conditional on the profile set, and `verify`'s exit-2 reason. A test refuses any
|
|
114
|
+
remedy naming a command or option the CLI does not accept, so a renamed flag breaks
|
|
115
|
+
the build instead of sending a reader to an invocation that no longer exists.
|
|
116
|
+
|
|
117
|
+
- **A filter that matches a path is not a filter that checks the caller** (C1-20).
|
|
118
|
+
`gate_coverage` published `possibly_filter_covered: 2635` over patterns `/*`,
|
|
119
|
+
`/api/*` and `/api/v1/*` — and those three filters were CORS, headers and logging,
|
|
120
|
+
while the only filter that authenticates covered two prefixes. The wording was
|
|
121
|
+
technically honest and the number was still *"falso consuelo"*: the corrected split
|
|
122
|
+
on that repository is 12 covered against 2 623 in the gap. Both halves of the join
|
|
123
|
+
were already in the same process, so the fix is an intersection **per filter**
|
|
124
|
+
rather than per pattern-set:
|
|
125
|
+
- `sourcecode/filter_surface.py` now records each declared filter (`@WebFilter`, and
|
|
126
|
+
`web.xml` mappings correlated with their `<filter-class>`) with a verdict —
|
|
127
|
+
`authenticates`, `does_not_authenticate`, `unknown` — decided structurally, never
|
|
128
|
+
by name (VAI): the filter establishes an identity, or it reads a credential *and*
|
|
129
|
+
refuses over it. A body that is not in this repository stays `unknown`, because
|
|
130
|
+
absence of evidence published as evidence of absence is the same defect mirrored.
|
|
131
|
+
- `gate_coverage` replaces the single count with four that partition the escape set:
|
|
132
|
+
`filter_covered_authenticating`, `filter_gap_non_authenticating`,
|
|
133
|
+
`filter_authentication_unknown`, `no_matching_filter_pattern`, plus a `filters`
|
|
134
|
+
list naming each filter, its patterns and the evidence behind its verdict.
|
|
135
|
+
|
|
136
|
+
- **Seven presentation rows, none of them an analysis error, two of which led a
|
|
137
|
+
reader to the inverse conclusion** (C2-15…C2-20, C1-19).
|
|
138
|
+
- `validation` printed *"0 body endpoints, 1179 gaps"* over a payload carrying
|
|
139
|
+
`body_endpoints_in_code: 1201` — the declared-constraint count under the
|
|
140
|
+
code-surface name. Both axes are named in their own units (C2-15).
|
|
141
|
+
- TX-006's witnesses all carried the callee's line, because that is where the
|
|
142
|
+
remedy goes, so several rows shared one number and read as duplicates. Each
|
|
143
|
+
finding now carries its `call_site` from the IR's span index, and the defect row
|
|
144
|
+
publishes the distinct sites with their count (C2-16).
|
|
145
|
+
- `limitations` merged across scopes repeated an entry verbatim; deduplicated once
|
|
146
|
+
in `finalize`, in first-seen order (C2-17).
|
|
147
|
+
- `spring_profiles.conditional_beans[].source_file` used the platform's native path
|
|
148
|
+
separator while the rest of the document used `/`; posix everywhere, including the
|
|
149
|
+
two other extractors that did the same (C2-18).
|
|
150
|
+
- `estimated_effort_range_days` published `{low: 60.7, high: 60.7}` — not a range,
|
|
151
|
+
at a precision the model does not have. The band declares `point_estimate` and
|
|
152
|
+
`precision_days`, and rounds to it (C2-19).
|
|
153
|
+
- `posture` cut four endpoint lists and its evidence map at 200 and declared
|
|
154
|
+
nothing, in the command whose declared caps the same evaluation calls a feature.
|
|
155
|
+
Each cut publishes total/shown/omitted and the registered cap effect; a list that
|
|
156
|
+
was not cut declares nothing (C2-20).
|
|
157
|
+
- Three commands published a file count for one repository — 3 337, 3 336, 3 342 —
|
|
158
|
+
and none said what it counted. Measured rather than equalised: all code-extension
|
|
159
|
+
files in any language, the non-test denominator of a test ratio, and the `.java`
|
|
160
|
+
files handed to the migration rules. Each names its population (C1-19).
|
|
161
|
+
|
|
162
|
+
- **`cache status` counts every store a warm fills** (C3-36). It printed `CAS blobs:
|
|
163
|
+
0`, `Total size: 0.1 MB` immediately after an 89-second warm of 3 342 files: true of
|
|
164
|
+
the per-repository core store, and the warm's output mostly lands in the shared
|
|
165
|
+
Canonical IR and the content-addressed parse cache, which the command never counted.
|
|
166
|
+
The status now breaks down by store, says what each holds, and labels the parse
|
|
167
|
+
cache shared across repositories so its size is not read as this repository's.
|
|
168
|
+
|
|
169
|
+
### Removed
|
|
170
|
+
|
|
171
|
+
- **BREAKING — `gate_coverage` no longer emits the three deprecated aliases** (C2-14).
|
|
172
|
+
`total_controller_handlers` counted *endpoints* under a name that says handlers,
|
|
173
|
+
`gate_bearing` counted *handler methods* while sitting beside an endpoint count, and
|
|
174
|
+
`not_carrying_gate` duplicated `endpoints_not_carrying_gate`. They were kept for a
|
|
175
|
+
two-minor window after C1-5 named the units; the seventh field evaluation read the
|
|
176
|
+
aliases anyway and quoted `total_controller_handlers: 3574` as handlers next to
|
|
177
|
+
`handler_methods_total: 913`. An alias that still ships is a live claim, and two of
|
|
178
|
+
these claimed the wrong unit. Read `endpoints_total`,
|
|
179
|
+
`handler_methods_carrying_gate` and `endpoints_not_carrying_gate`; the block now
|
|
180
|
+
carries `removed_fields` mapping each retired name to its successor, so a consumer
|
|
181
|
+
meets the answer rather than a `KeyError`. `possibly_filter_covered` is retired in
|
|
182
|
+
the same block and for the same reason (C1-20): it counted "a filter runs here" and
|
|
183
|
+
was read as "a filter checks here".
|
|
184
|
+
|
|
5
185
|
## [3.8.0] — 2026-08-02
|
|
6
186
|
|
|
7
187
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.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
|
|
@@ -129,6 +129,26 @@ ask spring-audit /path/to/repo
|
|
|
129
129
|
ask migrate-check /path/to/repo --compact
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
+
**Then the three that finish the sentence the four above start.** A profile-set answer stays
|
|
133
|
+
conditional until you know which set the deployment starts with, a gate nobody can populate is
|
|
134
|
+
a gate nobody runs, and a defect ranked without its reach is a linter note:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# Which profile set ACTUALLY runs? Reads every artefact that can set it — build,
|
|
138
|
+
# descriptors, Dockerfile, Compose, Kubernetes, launch scripts — with file:line, and
|
|
139
|
+
# says NOT DECIDED IN THIS REPOSITORY when nothing in the tree decides it. Then ranks
|
|
140
|
+
# every admissible set by what it leaves reachable without authentication.
|
|
141
|
+
ask posture /path/to/repo --resolve-environments
|
|
142
|
+
|
|
143
|
+
# Derive the contracts this repository already satisfies, execute each one before
|
|
144
|
+
# writing it, and populate .ask/contracts.yml from the measurement instead of by hand.
|
|
145
|
+
ask verify /path/to/repo --init
|
|
146
|
+
|
|
147
|
+
# What each defect actually costs once reach, access and write effect are in it:
|
|
148
|
+
# severity × reachability × auth_verdict × write_effect, ordered, every factor traceable.
|
|
149
|
+
ask risk /path/to/repo
|
|
150
|
+
```
|
|
151
|
+
|
|
132
152
|
Then the everyday loop:
|
|
133
153
|
|
|
134
154
|
```bash
|
|
@@ -145,13 +165,17 @@ ask onboard /path/to/repo
|
|
|
145
165
|
ask review-pr /path/to/repo --since main
|
|
146
166
|
|
|
147
167
|
# CI gate on NEW violations only, instead of on pre-existing debt
|
|
168
|
+
ask verify /path/to/repo --init # derive the contracts, don't hand-write them
|
|
148
169
|
ask verify /path/to/repo --capture-baseline # accept today's debt, once
|
|
149
170
|
ask verify /path/to/repo # then: only new violations block
|
|
150
171
|
```
|
|
151
172
|
|
|
152
|
-
> **Adopting a gate on a real codebase.**
|
|
153
|
-
>
|
|
154
|
-
>
|
|
173
|
+
> **Adopting a gate on a real codebase.** Nobody hand-writes contracts for a 3 000-file
|
|
174
|
+
> monolith, so `ask verify --init` derives the ones the repository satisfies **today** and
|
|
175
|
+
> executes each before writing it — init followed by verify passes by construction.
|
|
176
|
+
> A repository that starts declaring contracts already violates them somewhere; `ask verify`
|
|
177
|
+
> is **baseline-relative by default** (`--fail-on new`) so the gate survives contact with
|
|
178
|
+
> reality instead of being switched off on day one.
|
|
155
179
|
> `ask baseline capture|diff|trend` is a different thing: versioned architectural metrics over
|
|
156
180
|
> time, for trend reporting rather than blocking.
|
|
157
181
|
|
|
@@ -194,10 +218,32 @@ What a profile set **actually wires**: which conditional beans register, which d
|
|
|
194
218
|
`ask posture` · `ask posture --diff dev:prod` · `ask posture --property k=v`
|
|
195
219
|
→ [posture.md](docs/posture.md)
|
|
196
220
|
|
|
221
|
+
**`--resolve-environments` carries it past the edge of the repository.** Every answer above
|
|
222
|
+
is conditional on a profile set, and which set runs is decided by the deployment. This flag
|
|
223
|
+
reads every artefact in the tree that can set `spring.profiles.active` — Maven/Gradle,
|
|
224
|
+
`web.xml`, `Dockerfile`, Compose, Kubernetes, launch scripts — with `file:line`, and returns
|
|
225
|
+
`decided_in_repository`, `artefacts_disagree` (two deployments, never resolved by picking
|
|
226
|
+
one) or **`NOT DECIDED IN THIS REPOSITORY`**. Then it resolves every admissible set over one
|
|
227
|
+
parse and publishes the worst. A field audit closed those five hops by hand with grep before
|
|
228
|
+
the flag existed.
|
|
229
|
+
`ask posture . --resolve-environments`
|
|
230
|
+
|
|
197
231
|
Unresolved is a first-class outcome: a condition the resolver cannot decide is reported as a
|
|
198
232
|
hole with the condition named, never folded into active or inactive. **A posture answer that
|
|
199
233
|
guesses is a confident security falsehood — the worst failure mode this tool has.**
|
|
200
234
|
|
|
235
|
+
### 5c · Composed Risk *(experimental)*
|
|
236
|
+
Every command above answers one axis, and a reader composes them by hand. `ask risk` does the
|
|
237
|
+
join over the endpoint and symbol ids these commands already share with each other:
|
|
238
|
+
`severity_effective = defect_severity × reachability × auth_verdict × write_effect`. The
|
|
239
|
+
product of the published factors **is** the published score — decomposable to the four
|
|
240
|
+
figures and the authority behind each — and an axis this build cannot measure is `unknown`,
|
|
241
|
+
weighted 1.0 and named in `blind_axes` rather than silently treated as safe. Measured on a
|
|
242
|
+
field case: a defect both `spring-audit` and `impact-chain` called *medium* composes to
|
|
243
|
+
**high (8.06)** once *reachable unauthenticated* and *writes to the database* are in it.
|
|
244
|
+
`ask risk .` · `ask risk . --min-band high` · `ask risk . --limit 10`
|
|
245
|
+
→ [reference](docs/USER_GUIDE.md)
|
|
246
|
+
|
|
201
247
|
### 6 · Developer Workflows
|
|
202
248
|
The everyday loop: diff-based PR review, symptom-driven bug triage, and delta context for continuous agent runs.
|
|
203
249
|
`ask review-pr` · `ask fix-bug` · `ask prepare-context`
|
|
@@ -220,7 +266,7 @@ experimental: both are true, and they are two different facts.
|
|
|
220
266
|
|---|---|---|
|
|
221
267
|
| **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
|
|
222
268
|
| **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` |
|
|
269
|
+
| **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `posture` · `archetype` |
|
|
224
270
|
| **parked** | kept working, no longer developed | `retrieve` |
|
|
225
271
|
|
|
226
272
|
The same table is printed by `ask --help`, and both are generated from one authority
|
|
@@ -237,6 +283,7 @@ from it.
|
|
|
237
283
|
| Command | Tier | Answers | Note |
|
|
238
284
|
|---|---|---|---|
|
|
239
285
|
| `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
|
|
286
|
+
| `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
287
|
| `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators) |
|
|
241
288
|
| `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment` |
|
|
242
289
|
| `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan |
|
|
@@ -91,6 +91,26 @@ ask spring-audit /path/to/repo
|
|
|
91
91
|
ask migrate-check /path/to/repo --compact
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
+
**Then the three that finish the sentence the four above start.** A profile-set answer stays
|
|
95
|
+
conditional until you know which set the deployment starts with, a gate nobody can populate is
|
|
96
|
+
a gate nobody runs, and a defect ranked without its reach is a linter note:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Which profile set ACTUALLY runs? Reads every artefact that can set it — build,
|
|
100
|
+
# descriptors, Dockerfile, Compose, Kubernetes, launch scripts — with file:line, and
|
|
101
|
+
# says NOT DECIDED IN THIS REPOSITORY when nothing in the tree decides it. Then ranks
|
|
102
|
+
# every admissible set by what it leaves reachable without authentication.
|
|
103
|
+
ask posture /path/to/repo --resolve-environments
|
|
104
|
+
|
|
105
|
+
# Derive the contracts this repository already satisfies, execute each one before
|
|
106
|
+
# writing it, and populate .ask/contracts.yml from the measurement instead of by hand.
|
|
107
|
+
ask verify /path/to/repo --init
|
|
108
|
+
|
|
109
|
+
# What each defect actually costs once reach, access and write effect are in it:
|
|
110
|
+
# severity × reachability × auth_verdict × write_effect, ordered, every factor traceable.
|
|
111
|
+
ask risk /path/to/repo
|
|
112
|
+
```
|
|
113
|
+
|
|
94
114
|
Then the everyday loop:
|
|
95
115
|
|
|
96
116
|
```bash
|
|
@@ -107,13 +127,17 @@ ask onboard /path/to/repo
|
|
|
107
127
|
ask review-pr /path/to/repo --since main
|
|
108
128
|
|
|
109
129
|
# CI gate on NEW violations only, instead of on pre-existing debt
|
|
130
|
+
ask verify /path/to/repo --init # derive the contracts, don't hand-write them
|
|
110
131
|
ask verify /path/to/repo --capture-baseline # accept today's debt, once
|
|
111
132
|
ask verify /path/to/repo # then: only new violations block
|
|
112
133
|
```
|
|
113
134
|
|
|
114
|
-
> **Adopting a gate on a real codebase.**
|
|
115
|
-
>
|
|
116
|
-
>
|
|
135
|
+
> **Adopting a gate on a real codebase.** Nobody hand-writes contracts for a 3 000-file
|
|
136
|
+
> monolith, so `ask verify --init` derives the ones the repository satisfies **today** and
|
|
137
|
+
> executes each before writing it — init followed by verify passes by construction.
|
|
138
|
+
> A repository that starts declaring contracts already violates them somewhere; `ask verify`
|
|
139
|
+
> is **baseline-relative by default** (`--fail-on new`) so the gate survives contact with
|
|
140
|
+
> reality instead of being switched off on day one.
|
|
117
141
|
> `ask baseline capture|diff|trend` is a different thing: versioned architectural metrics over
|
|
118
142
|
> time, for trend reporting rather than blocking.
|
|
119
143
|
|
|
@@ -156,10 +180,32 @@ What a profile set **actually wires**: which conditional beans register, which d
|
|
|
156
180
|
`ask posture` · `ask posture --diff dev:prod` · `ask posture --property k=v`
|
|
157
181
|
→ [posture.md](docs/posture.md)
|
|
158
182
|
|
|
183
|
+
**`--resolve-environments` carries it past the edge of the repository.** Every answer above
|
|
184
|
+
is conditional on a profile set, and which set runs is decided by the deployment. This flag
|
|
185
|
+
reads every artefact in the tree that can set `spring.profiles.active` — Maven/Gradle,
|
|
186
|
+
`web.xml`, `Dockerfile`, Compose, Kubernetes, launch scripts — with `file:line`, and returns
|
|
187
|
+
`decided_in_repository`, `artefacts_disagree` (two deployments, never resolved by picking
|
|
188
|
+
one) or **`NOT DECIDED IN THIS REPOSITORY`**. Then it resolves every admissible set over one
|
|
189
|
+
parse and publishes the worst. A field audit closed those five hops by hand with grep before
|
|
190
|
+
the flag existed.
|
|
191
|
+
`ask posture . --resolve-environments`
|
|
192
|
+
|
|
159
193
|
Unresolved is a first-class outcome: a condition the resolver cannot decide is reported as a
|
|
160
194
|
hole with the condition named, never folded into active or inactive. **A posture answer that
|
|
161
195
|
guesses is a confident security falsehood — the worst failure mode this tool has.**
|
|
162
196
|
|
|
197
|
+
### 5c · Composed Risk *(experimental)*
|
|
198
|
+
Every command above answers one axis, and a reader composes them by hand. `ask risk` does the
|
|
199
|
+
join over the endpoint and symbol ids these commands already share with each other:
|
|
200
|
+
`severity_effective = defect_severity × reachability × auth_verdict × write_effect`. The
|
|
201
|
+
product of the published factors **is** the published score — decomposable to the four
|
|
202
|
+
figures and the authority behind each — and an axis this build cannot measure is `unknown`,
|
|
203
|
+
weighted 1.0 and named in `blind_axes` rather than silently treated as safe. Measured on a
|
|
204
|
+
field case: a defect both `spring-audit` and `impact-chain` called *medium* composes to
|
|
205
|
+
**high (8.06)** once *reachable unauthenticated* and *writes to the database* are in it.
|
|
206
|
+
`ask risk .` · `ask risk . --min-band high` · `ask risk . --limit 10`
|
|
207
|
+
→ [reference](docs/USER_GUIDE.md)
|
|
208
|
+
|
|
163
209
|
### 6 · Developer Workflows
|
|
164
210
|
The everyday loop: diff-based PR review, symptom-driven bug triage, and delta context for continuous agent runs.
|
|
165
211
|
`ask review-pr` · `ask fix-bug` · `ask prepare-context`
|
|
@@ -182,7 +228,7 @@ experimental: both are true, and they are two different facts.
|
|
|
182
228
|
|---|---|---|
|
|
183
229
|
| **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
|
|
184
230
|
| **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` |
|
|
231
|
+
| **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `posture` · `archetype` |
|
|
186
232
|
| **parked** | kept working, no longer developed | `retrieve` |
|
|
187
233
|
|
|
188
234
|
The same table is printed by `ask --help`, and both are generated from one authority
|
|
@@ -199,6 +245,7 @@ from it.
|
|
|
199
245
|
| Command | Tier | Answers | Note |
|
|
200
246
|
|---|---|---|---|
|
|
201
247
|
| `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
|
|
248
|
+
| `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
249
|
| `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators) |
|
|
203
250
|
| `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment` |
|
|
204
251
|
| `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan |
|
|
@@ -354,6 +354,7 @@ def status(repo_root: Path) -> dict[str, Any]:
|
|
|
354
354
|
"cores": 0, "snapshots": 0, "views": 0, "cas_blobs": 0,
|
|
355
355
|
"total_size_bytes": 0, "total_size_mb": 0.0,
|
|
356
356
|
"current_git_head": current_head,
|
|
357
|
+
"stores": _store_breakdown(repo_root, 0),
|
|
357
358
|
**ris_fields,
|
|
358
359
|
}
|
|
359
360
|
cores = list(cache_d.glob("core-*.json.gz"))
|
|
@@ -371,10 +372,57 @@ def status(repo_root: Path) -> dict[str, Any]:
|
|
|
371
372
|
"total_size_bytes": total_bytes,
|
|
372
373
|
"total_size_mb": round(total_bytes / (1024 * 1024), 2),
|
|
373
374
|
"current_git_head": current_head,
|
|
375
|
+
# C3-36: `CAS blobs: 0`, `Total size: 0.1 MB` immediately after an 89-second
|
|
376
|
+
# warm of 3 342 files. Every figure above was true and described one store
|
|
377
|
+
# of three — the warm's output mostly lands in the shared CIR and the parse
|
|
378
|
+
# cache, which this command never counted. A status that reports a third of
|
|
379
|
+
# the state reads as a warm that did nothing.
|
|
380
|
+
"stores": _store_breakdown(repo_root, total_bytes),
|
|
374
381
|
**ris_fields,
|
|
375
382
|
}
|
|
376
383
|
|
|
377
384
|
|
|
385
|
+
def _store_breakdown(repo_root: Path, core_bytes: int) -> "dict[str, Any]":
|
|
386
|
+
"""What a warm actually populated, by store. Best-effort per store: a store
|
|
387
|
+
that cannot be inspected is reported as unavailable, never as empty."""
|
|
388
|
+
out: "dict[str, Any]" = {
|
|
389
|
+
"core": {
|
|
390
|
+
"cache_dir": str(cache_dir(repo_root)),
|
|
391
|
+
"bytes": core_bytes,
|
|
392
|
+
"scope": "this repository",
|
|
393
|
+
"holds": "core snapshots, rendered views and their CAS blobs",
|
|
394
|
+
},
|
|
395
|
+
}
|
|
396
|
+
try:
|
|
397
|
+
from sourcecode.context_cache import ContextCache # noqa: PLC0415
|
|
398
|
+
|
|
399
|
+
ctx = ContextCache.for_repo(repo_root).stats()
|
|
400
|
+
out["shared_cir"] = {
|
|
401
|
+
"cache_dir": ctx["cache_dir"],
|
|
402
|
+
"entries": ctx["contexts"],
|
|
403
|
+
"bytes": ctx["bytes_stored"],
|
|
404
|
+
"scope": "this repository",
|
|
405
|
+
"holds": "the shared Canonical IR that explain/impact/posture reuse",
|
|
406
|
+
}
|
|
407
|
+
except Exception:
|
|
408
|
+
out["shared_cir"] = {"available": False}
|
|
409
|
+
try:
|
|
410
|
+
from sourcecode import parse_cache as _pc # noqa: PLC0415
|
|
411
|
+
|
|
412
|
+
out["parse"] = {
|
|
413
|
+
**_pc.store_stats(),
|
|
414
|
+
"holds": "per-file parses, content-addressed across every repository",
|
|
415
|
+
}
|
|
416
|
+
except Exception:
|
|
417
|
+
out["parse"] = {"available": False}
|
|
418
|
+
out["note"] = (
|
|
419
|
+
"`cache warm` populates all of these; the core store alone is a third of "
|
|
420
|
+
"the answer, and reading it as the whole is how a completed warm looks like "
|
|
421
|
+
"an empty cache."
|
|
422
|
+
)
|
|
423
|
+
return out
|
|
424
|
+
|
|
425
|
+
|
|
378
426
|
def clear(repo_root: Path, *, clear_ris: bool = False) -> int:
|
|
379
427
|
"""Delete cache files for *repo_root*. Returns the number of files removed.
|
|
380
428
|
|
|
@@ -131,6 +131,13 @@ COMMANDS: tuple[CommandCache, ...] = (
|
|
|
131
131
|
"builds — the parse it used to repeat for itself. `--diff` compares two profile "
|
|
132
132
|
"sets over that one IR, so the second side costs the resolution only.",
|
|
133
133
|
"10.1 s → 1.6 s"),
|
|
134
|
+
CommandCache("risk", ("cir", "parse"), "shared", False,
|
|
135
|
+
"Composes what the audit, impact-chain and the posture already answer, so it "
|
|
136
|
+
"pays each of their costs once over the shared CIR a warm builds — one parse "
|
|
137
|
+
"for the whole composition, and the reachability query is cached per symbol "
|
|
138
|
+
"within the run.",
|
|
139
|
+
"not measured on the battery yet — the composition is bounded by the "
|
|
140
|
+
"`spring-audit` + `impact-chain` costs listed here, not by new analysis"),
|
|
134
141
|
CommandCache("endpoints", ("ris", "parse"), "shared", False,
|
|
135
142
|
"Recomputes the endpoint surface on every run, over a parse a warm has already "
|
|
136
143
|
"paid for. Until 3.7.0 the extractor parsed every file itself instead of reading "
|