sourcecode 4.1.0__tar.gz → 4.3.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-4.1.0 → sourcecode-4.3.0}/CHANGELOG.md +335 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/PKG-INFO +41 -8
- {sourcecode-4.1.0 → sourcecode-4.3.0}/README.md +40 -7
- {sourcecode-4.1.0 → sourcecode-4.3.0}/pyproject.toml +1 -1
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/__init__.py +1 -1
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/architectural_baseline.py +19 -0
- sourcecode-4.3.0/src/sourcecode/baseline_autocapture.py +375 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/cache_model.py +19 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/caller_reach.py +16 -7
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/canonical_ir.py +29 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/cli.py +787 -26
- sourcecode-4.3.0/src/sourcecode/client_calls.py +305 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/context_graph.py +11 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/contract_diff.py +5 -4
- sourcecode-4.3.0/src/sourcecode/data_exposure.py +353 -0
- sourcecode-4.3.0/src/sourcecode/data_labels.py +200 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/dynamic_argument_surface.py +12 -5
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/environment_resolution.py +100 -6
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/facts/registry.json +15 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/format_contract.py +1 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/git_checkout.py +5 -2
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/non_coverage.py +70 -0
- sourcecode-4.3.0/src/sourcecode/openrewrite_recipe.py +278 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/posture.py +425 -7
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/remedies.py +18 -1
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/repository_ir.py +24 -3
- sourcecode-4.3.0/src/sourcecode/risk.py +764 -0
- sourcecode-4.3.0/src/sourcecode/sarif.py +618 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/spring_impact.py +14 -3
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/validation_inference.py +33 -4
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/verify_repo.py +22 -2
- sourcecode-4.1.0/src/sourcecode/risk.py +0 -345
- {sourcecode-4.1.0 → sourcecode-4.3.0}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/.gitignore +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/.ruff.toml +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/CONTRIBUTING.md +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/LICENSE +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/SECURITY.md +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/raw +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/scripts/compare_integration_engines.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/scripts/customer_smoke_test.sh +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/scripts/generate_jdk_exports.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/scripts/perf_harness.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/archetype.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/architectural_delta.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/cache.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/call_surface.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/caller_metrics.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/chain_rules.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/change_plan.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/classifier.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/compare.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/constraint_diff.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/context_cache.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/contract_init.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/defect_identity.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/degradation.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/deployment_prefix.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/endpoint_literals.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/endpoint_metrics.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/envelope.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/evidence_provider.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/explain.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/facts/__init__.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/filter_surface.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/graph_evidence.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/hibernate_strat.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/identity_fallback.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/integration_coordinates.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/jdk_exports.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/license.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/migrate_check.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/migration_blast.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/parse_cache.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/path_admission.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/perf.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/pipe_contract.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/progress.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/readiness_timeline.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/reconciliation.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/redactor.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/reference_facts.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/release_info.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/__init__.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/context.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/errors.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/executor.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/planner.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/query.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/request.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/resolution.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/result.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/retriever.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/runtime.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/steps.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/steps_graph.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/steps_impact.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/steps_intf.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/steps_struct.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/retrieval/steps_txsec.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/ris.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/rule_catalog.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/scanner.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/schema.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/security_config.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/security_config_scan.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/security_posture.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/semantic_impact_engine.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/semantic_integration_engine.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/semantic_services.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/serializer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/spring_findings.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/spring_profiles.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/spring_properties.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/spring_security_audit.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/spring_tx_analyzer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/target_admission.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/test_gap_ranking.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/test_sources.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/token_estimate.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/type_usage_surface.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/validation_surface.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/verify_edit.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/verify_rules.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/version_check.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/src/sourcecode/workspace.py +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/supabase/functions/README.md +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/supabase/sql/licensing_schema.sql +0 -0
- {sourcecode-4.1.0 → sourcecode-4.3.0}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -2,6 +2,341 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`ask migrate-recipe` — the migration report in the form the executor takes**
|
|
8
|
+
(roadmap M10.5 item 5 / M8.5, experimental). `migrate-check` already names the
|
|
9
|
+
OpenRewrite recipe each finding carries (296 of 309 on openmrs-core) and a reader
|
|
10
|
+
still had to copy them out of a JSON payload by hand — field evaluation #4's verdict
|
|
11
|
+
on that gap was *"el informe muere en un cajón; el codemod se convierte en PRs"*. The
|
|
12
|
+
command emits the declarative composite recipe naming exactly those recipes, the
|
|
13
|
+
artifact coordinates derived from their packages, and the invocation for the build the
|
|
14
|
+
repository declares (Maven or Gradle). It writes nothing without `--write`, so an audit
|
|
15
|
+
of somebody else's repository can run it; `--write` refuses to replace an existing
|
|
16
|
+
`rewrite.yml` without `--force`. **Nothing here edits source** — that is NC-005's
|
|
17
|
+
position, not a gap: OpenRewrite is the executor and this is its input.
|
|
18
|
+
- The recipe list comes from the findings, never from a catalogue of what OpenRewrite
|
|
19
|
+
can do: a recipe nobody's finding asked for would rewrite code nobody measured.
|
|
20
|
+
- Every finding with no recipe is published under `manual_remainder`. Measured on
|
|
21
|
+
BroadleafCommerce: **25 blocking findings in product code and not one automatable**,
|
|
22
|
+
which is an answer, not an empty result — and the reason an empty recipe list prints
|
|
23
|
+
*no* runnable command, because `mvn … rewrite:run` over nothing is a green executor
|
|
24
|
+
run that reads as "the migration is automated".
|
|
25
|
+
- Advisory hygiene is excluded by default (`--include-hygiene` opts in): on openmrs-core
|
|
26
|
+
it takes the population from 125 findings to 309 and adds `JavaTimeAPIs`, and a
|
|
27
|
+
migration diff that also modernises date handling cannot be reviewed as one change.
|
|
28
|
+
- The coverage block names **both** populations — its own and `migrate-check`'s narrower
|
|
29
|
+
`blocking_count` (125 against 114 on openmrs-core) — because two populations under one
|
|
30
|
+
name is the defect this project keeps finding in its own output.
|
|
31
|
+
|
|
32
|
+
## [4.3.0] — 2026-08-03
|
|
33
|
+
|
|
34
|
+
Minor, not a patch: two commands are new (`ask enrich`, `ask data-exposure`), the
|
|
35
|
+
composed risk model gains two factors, and `ask verify` writes a file where it
|
|
36
|
+
wrote none — every one of them additive, none of them removing a published field
|
|
37
|
+
or moving an exit code. A pipeline that reads this release the way it read 4.2.0
|
|
38
|
+
gets the same answers, plus blocks it can ignore.
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- **`ask baseline capture --auto` — an architectural history that does not depend on
|
|
43
|
+
somebody remembering** (roadmap M10.5, head of the milestone). The snapshot has
|
|
44
|
+
shipped since D5; the *series* is the asset a competitor cannot backfill, and in
|
|
45
|
+
every repository measured so far its length is zero, because capture is a command a
|
|
46
|
+
human has to type. `--auto` is the form a pipeline can keep: it captures one baseline
|
|
47
|
+
per commit, keeps an already-captured commit instead of relabelling it, refuses to
|
|
48
|
+
file a tree with uncommitted changes under the commit it would be stored as, and
|
|
49
|
+
**exits 0 whatever happens** — a build never goes red because a snapshot could not be
|
|
50
|
+
taken. Every outcome names itself (`captured` / `skipped` with the reason and a
|
|
51
|
+
sentence of effect), so a pipeline log says which happened rather than going quiet.
|
|
52
|
+
A skip costs no analysis: the decision is taken before the IR is built, so the common
|
|
53
|
+
case in a per-push job is ~0.2 s against 1.8 s for a capture. New authority
|
|
54
|
+
`sourcecode/baseline_autocapture.py`; `docs/baseline-ci.yml` now captures per merge
|
|
55
|
+
as well as per tag.
|
|
56
|
+
- **`ask data-exposure` — which routes can carry the data you labelled, and who
|
|
57
|
+
reaches them** (roadmap M10.5 item 3, experimental). Nothing here detects sensitive
|
|
58
|
+
data: a label is a judgement about a domain, a field named `dni` is a national
|
|
59
|
+
identifier in one repository and a column name in another, and the engine never
|
|
60
|
+
branches on a name (VAI). It is declared once under `dataLabels` in
|
|
61
|
+
`sourcecode.config.json`; everything after that is measured over authorities that
|
|
62
|
+
already exist — the call reach `impact-chain` walks, the endpoint security surface
|
|
63
|
+
`risk` weighs, the profile resolution `posture` publishes (`--profile`). Two evidence
|
|
64
|
+
classes, published apart and never added together: `signature` (the handler names the
|
|
65
|
+
labelled type in its own signature) and `call_reach` (the chain reaches it — a
|
|
66
|
+
supremum, not a proof, because the mapping in between is not modelled: NC-008).
|
|
67
|
+
Measured: petclinic labelling `Owner#telephone` → **7 routes by signature**;
|
|
68
|
+
BroadleafCommerce labelling `Customer` → **6 by call reach and none by signature**,
|
|
69
|
+
because those controllers return view names. A repository that declared nothing is
|
|
70
|
+
`answered: false`, never zero exposed routes, and a declared type the graph never
|
|
71
|
+
resolved is named with the note that this is not evidence it is unexposed.
|
|
72
|
+
- **A request handler declares types too.** `_extract_class_type_refs` enumerated
|
|
73
|
+
`symbol_kind == "method"`, and a handler is classified `endpoint` at emission (a
|
|
74
|
+
factory method `bean`), so the class-scope type surface contained **no controller
|
|
75
|
+
signature anywhere in a repository**: `structural_references_to_type("Owner")` on
|
|
76
|
+
petclinic returned 3 atoms, none of them a route that takes an `Owner` as its request
|
|
77
|
+
body, and "which routes accept or return this type" answered nothing while looking
|
|
78
|
+
like an answer. Now 10 atoms, 7 of them handler signatures. Same shape as the F.4-1
|
|
79
|
+
body-surface seam, one scope up; `member_kind` still publishes the kind the symbol was
|
|
80
|
+
classified with.
|
|
81
|
+
- **The history answers from the repository path.** `ask trend .` and
|
|
82
|
+
`ask baseline trend .` now take either a repository or a directory of baselines, and
|
|
83
|
+
`ask baseline diff .` defaults to the newest point in that repository's own history
|
|
84
|
+
instead of requiring `--baseline <file>`. Capture writes to `<repo>/.ask/baselines`,
|
|
85
|
+
so making the reader name the storage directory was the same friction that kept the
|
|
86
|
+
series empty. An explicit directory (the `--dir` case) is unchanged, and a repository
|
|
87
|
+
with no history gets an error that names how to start one. New
|
|
88
|
+
`architectural_baseline.latest_baseline_path`, ordered exactly as the trend series is
|
|
89
|
+
ordered so "the last point" and "the base of a default diff" cannot disagree.
|
|
90
|
+
- **`ask verify` carries the history for free.** The gate is the run that already happens
|
|
91
|
+
on every push and already builds the IR a baseline is extracted from, so where a
|
|
92
|
+
repository keeps `.ask/baselines` the gate adds the current commit to it and publishes
|
|
93
|
+
what it did under `architectural_history` — on every run, including the ones that
|
|
94
|
+
captured nothing, because a series that silently stopped growing is invisible until the
|
|
95
|
+
day somebody needs it (I-8). Measured on BroadleafCommerce: 3.9 s with the capture
|
|
96
|
+
against 4.0 s without, i.e. inside the noise; eureka 1.8 s against 0.8 s (its IR is
|
|
97
|
+
smaller, the extraction is not). The passenger cannot move the gate: the verdict, the
|
|
98
|
+
exit code and every other field are identical with and without it, and an exception
|
|
99
|
+
inside it is swallowed. `ASK_BASELINE_AUTOCAPTURE=0/1` overrides in both directions.
|
|
100
|
+
- ⚠One measured cost stated rather than hidden: a baseline is ~730 KB on a 3 300-file
|
|
101
|
+
monolith, because it stores the full endpoint surface and fan-in map so a later
|
|
102
|
+
`baseline diff` is faithful. A point per merge is a megabyte-scale history; a point
|
|
103
|
+
per release is not. `--dir` sends them outside the repository.
|
|
104
|
+
- ⚠Found by the battery, not by the field: the first capture writes an untracked file
|
|
105
|
+
**inside the repository**, so a plain `git status --porcelain` check would have
|
|
106
|
+
reported a dirty tree from then on and every later run would have skipped — a
|
|
107
|
+
history of exactly one. The dirtiness question excludes this tool's own footprint
|
|
108
|
+
(`.ask/`) and nothing else, because everything else is what the baseline measures —
|
|
109
|
+
and the second half of that came from eureka, where `verify --init` writes
|
|
110
|
+
`.ask/contracts.yml` and, counted as a modification, would stop the history from
|
|
111
|
+
ever starting.
|
|
112
|
+
- **`ask enrich --sarif <log>` — somebody else's detection, ranked by what this
|
|
113
|
+
repository does with it** (roadmap M10, first deliverable). This product does not
|
|
114
|
+
detect injection, CVEs or secrets and says so in every security payload (NC-001,
|
|
115
|
+
NC-002); the scanners that do have no bean graph, no profile model and no endpoint
|
|
116
|
+
id they share with anything, so their output is a list nobody can order. `enrich`
|
|
117
|
+
reads a SARIF 2.1.0 log from Semgrep, CodeQL or Trivy and runs the **same
|
|
118
|
+
composition** `ask risk` runs over each finding — same axes, same weights, same
|
|
119
|
+
`RiskComposer` — with one difference: `defect_severity` is the scanner's own
|
|
120
|
+
verdict (`security-severity` when the tool published one, `level` otherwise),
|
|
121
|
+
carried through with the scanner named as its authority. Nothing re-rates,
|
|
122
|
+
confirms or contradicts a finding. Results sharing (tool, rule, symbol) are one
|
|
123
|
+
defect with several witnesses; a result the join could not place — a file outside
|
|
124
|
+
the population this build read, a line with no declaration above it — is published
|
|
125
|
+
under `unresolved` with the reason, never dropped.
|
|
126
|
+
- **The CVE half of the same command: a dependency finding is joined through the
|
|
127
|
+
coordinate, not through a line.** A result located on `pom.xml` or
|
|
128
|
+
`build.gradle` is about a library, so the coordinate is read back out of the
|
|
129
|
+
manifest the scanner named and the reach is the worst of the types that import
|
|
130
|
+
it — *of forty vulnerable dependencies, which ones does an unauthenticated route
|
|
131
|
+
actually reach?* Importers are found from the IR's existing `imports` edges, by
|
|
132
|
+
the coordinate's group id or by its artifact id as a package segment, and each
|
|
133
|
+
row publishes which basis found them. A library nothing imports is `unresolved`
|
|
134
|
+
and never "unreachable": reflection, a service loader and use through another
|
|
135
|
+
dependency all leave no import edge. Both kinds rank in one list, because a CVE
|
|
136
|
+
in a reachable library and an injection finding in a handler are the same
|
|
137
|
+
question to whoever decides what to fix first.
|
|
138
|
+
- **`--profile <set>` on `ask risk` and `ask enrich` — profile context per finding**
|
|
139
|
+
(M10 exit criterion). The access axis stops answering for *the repository as
|
|
140
|
+
configured* and answers for *that deployment*: `posture` resolves the conditional
|
|
141
|
+
bean graph and the request chain under the named set, through a new published
|
|
142
|
+
seam (`posture.endpoint_access_under`, `posture.access_verdict`), so a composed
|
|
143
|
+
row and a `posture` run can never disagree about the same profile set. A decision
|
|
144
|
+
resolves an endpoint the repository-wide surface left at `coverage_unknown`, in
|
|
145
|
+
either direction — measured on a fixture, one defect scores 11.52/`open` under
|
|
146
|
+
`dev`, 8.06/`unknown` with no set named, and 5.76/`protected` under `prod`. When
|
|
147
|
+
both authorities decided, the worse of them wins, per endpoint.
|
|
148
|
+
- **`ask risk` gains a fifth factor: `query_construction`** (roadmap F.4-1). The
|
|
149
|
+
field asked the question this answers the structural half of — *"con 618 HQL
|
|
150
|
+
concatenados, ¿alguno concatena entrada de request?"* Following request input to
|
|
151
|
+
a query is dataflow, is declared out of scope in NC-001, and stays there. What
|
|
152
|
+
is publishable without it is the adjacency: this defect's own code assembles a
|
|
153
|
+
query string by concatenation, and the four factors beside it already say whether
|
|
154
|
+
that code is reachable, unauthenticated and writing. Read from the α
|
|
155
|
+
argument-shape atoms the IR already carries (`dynamic_argument_surface`) — no new
|
|
156
|
+
analysis, one pass, joined per defect. `not_observed` means the shape was absent
|
|
157
|
+
from the body facts; it is never a claim that a query is safely parameterised.
|
|
158
|
+
- **…and a sixth: `input_constraints`** — the other half of the same field question
|
|
159
|
+
(*"1 201 bodies sin validación"*). Joined by route against `validation`'s gap
|
|
160
|
+
list: `absent` means one of the endpoints reaching this defect accepts a request
|
|
161
|
+
body with no declared constraint, taking the worst of the reached routes for the
|
|
162
|
+
reason the auth axis does. `ask risk` now publishes the `non_coverage` block too,
|
|
163
|
+
because two axes describing the input path, composed with an open access verdict,
|
|
164
|
+
read as *injection* unless the payload states that no dataflow was followed.
|
|
165
|
+
|
|
166
|
+
### Fixed
|
|
167
|
+
|
|
168
|
+
- **`validation` counted handlers that take no argument as body endpoints.** The
|
|
169
|
+
body surface was the verb alone (POST/PUT/PATCH) and the declared limitation said
|
|
170
|
+
the parameter list was not captured. It is now captured (`_handler_params`) and
|
|
171
|
+
read in the negative direction only: an empty parameter list proves no body can
|
|
172
|
+
bind. A handler whose parameters are all path or query values still counts, and
|
|
173
|
+
the limitation says so.
|
|
174
|
+
|
|
175
|
+
- **The α argument-shape surface was blind to every controller body.**
|
|
176
|
+
`dynamic_argument_surface` walked `kind="method"` and `kind="constructor"` symbol
|
|
177
|
+
nodes; a request handler is a `kind="endpoint"` node. The owner population is now
|
|
178
|
+
the body-fact layer's own (`ContextGraph.body_owners()`).
|
|
179
|
+
|
|
180
|
+
### Changed
|
|
181
|
+
|
|
182
|
+
- `severity_effective` in `ask risk` can now be larger for a row whose code
|
|
183
|
+
concatenates a query. Every factor's neutral value is 1.0, so a new axis only
|
|
184
|
+
ever moves a row **up**: no band a reader has already acted on is demoted by
|
|
185
|
+
this release.
|
|
186
|
+
|
|
187
|
+
## [4.2.0] — 2026-08-03
|
|
188
|
+
|
|
189
|
+
Minor, not a patch, by this project's own criterion: two published figures move
|
|
190
|
+
and a verdict changes, so a pipeline reading either can change colour.
|
|
191
|
+
`posture --resolve-environments` answers `NOT DECIDED IN THIS REPOSITORY` where
|
|
192
|
+
it answered `artefacts_disagree` on a repository whose build properties nothing
|
|
193
|
+
consumes (C1-22), and `ask risk` publishes defects where it published findings,
|
|
194
|
+
so `total_defects` and `by_band` move (C1-23) — 20 → 15 on BroadleafCommerce.
|
|
195
|
+
`risk` also drops `rule_id` for `rule_ids`: it is in the `experimental` tier,
|
|
196
|
+
whose published promise is exactly that its shape may change in a minor.
|
|
197
|
+
|
|
198
|
+
Field evaluation #9 (8/10, same 3 337-file monolith as #6–#8) opened nine rows
|
|
199
|
+
and this release closes seven of them. The two left open are open on purpose:
|
|
200
|
+
`C3-39` needs a Windows runner before it needs a fix, and `P-7` is a pricing
|
|
201
|
+
decision. Every complaint was re-measured against HEAD before a row was written
|
|
202
|
+
— five reproduced, one was half false, one was not reproducible here, and one
|
|
203
|
+
was a capability that already shipped.
|
|
204
|
+
|
|
205
|
+
### Added
|
|
206
|
+
|
|
207
|
+
- **`ask posture --diff-ref <base>:<head>` and `--since <ref>` — one profile set,
|
|
208
|
+
two git refs** (roadmap M10.5 item 1). `--diff` holds the tree fixed and moves
|
|
209
|
+
the profile set; this holds the profile set fixed and moves the tree, which is
|
|
210
|
+
the question a pull request asks: *does this change what a client can reach
|
|
211
|
+
without authenticating?* `--since` compares a ref with the working tree,
|
|
212
|
+
uncommitted edits included. Both refs are read with `git archive`: nothing is
|
|
213
|
+
written to the repository, no worktree is created and the index is not touched.
|
|
214
|
+
`docs/posture.md` had declared this as the one requested extension with no
|
|
215
|
+
feature behind it.
|
|
216
|
+
- **`--fail-on opened|any|never` — the gate half.** Default `never`, so no
|
|
217
|
+
invocation that worked yesterday changes colour today; `opened` exits 1 when a
|
|
218
|
+
request a readable rule leaves reachable unauthenticated was not one before.
|
|
219
|
+
The payload is emitted before the exit code, because a red pipeline with no
|
|
220
|
+
statement of what opened is a gate nobody keeps. It requires a ref comparison —
|
|
221
|
+
gating a single run would gate on pre-existing debt, which is `spring-audit --ci`.
|
|
222
|
+
- **`endpoint_request_identity` registered as a fact** (ADR-0008 R11,
|
|
223
|
+
`sourcecode.canonical_ir:request_identity`). The comparison unit is the request
|
|
224
|
+
(`METHOD path`), not the endpoint id, which carries the controller FQN and the
|
|
225
|
+
handler symbol and therefore changes when a handler moves between classes
|
|
226
|
+
without the URL changing. `contract_diff` re-derived the same identity and now
|
|
227
|
+
binds to the authority. Path-variable patterns are deliberately **not**
|
|
228
|
+
normalised: `{id:.*}` and `{id:[^0-9].*}` are different URLs to a caller, and
|
|
229
|
+
one field repository moved 93 requests with exactly that edit in a single commit.
|
|
230
|
+
|
|
231
|
+
### Added
|
|
232
|
+
|
|
233
|
+
- **`ask endpoints --compact` — the census instead of the rows** (C2-22, field
|
|
234
|
+
evaluation #9). Asked how exposed a repository was, the command answered with
|
|
235
|
+
1.9 MB of JSON for 3 574 endpoints and no summary mode, and the evaluator
|
|
236
|
+
aggregated it by hand. Every answer now carries an `exposure` block — counts by
|
|
237
|
+
method, by security policy, by controller and by first path area — and
|
|
238
|
+
`--compact` returns it without the rows, declaring what it dropped. Two rules
|
|
239
|
+
it obeys against itself: the census is measured over the population the filters
|
|
240
|
+
chose and never over what `--limit` left rendered, and every ranked rollup
|
|
241
|
+
states its own total when it cuts. Measured on BroadleafCommerce: 95 KB → 11 KB,
|
|
242
|
+
every count unchanged. (The other half of the complaint is recorded as false:
|
|
243
|
+
`spring-audit` has shipped `--compact`, `--min-severity` and `--scope` for
|
|
244
|
+
releases.)
|
|
245
|
+
|
|
246
|
+
- **NC-007 — the endpoint population is declared** (CL-12, field evaluation #9).
|
|
247
|
+
`endpoints` projects Spring handler mappings; a servlet declared in `web.xml`
|
|
248
|
+
or registered as a `ServletRegistrationBean` is reachable over HTTP and is in
|
|
249
|
+
no part of that model. Six published non-coverage rows are exactly what let a
|
|
250
|
+
reader treat the list as the whole HTTP surface, and the evaluation lost a
|
|
251
|
+
monitoring console that way — at a path behind the credential the same run
|
|
252
|
+
reported as SEC-007. The row is published in the `endpoints` payload and inside
|
|
253
|
+
`posture.endpoints`, because the reader who counts open requests is reading
|
|
254
|
+
`posture`. Admission of a servlet surface is deliberately **not** in this
|
|
255
|
+
change: it is a second population and merging it into `endpoints.total` would
|
|
256
|
+
move a published count and every ratio keyed on it.
|
|
257
|
+
|
|
258
|
+
### Fixed
|
|
259
|
+
|
|
260
|
+
- **A reach figure that did not name its scope** (C2-23, field evaluation #9).
|
|
261
|
+
`risk` reported `endpoints_reached: 1` for a symbol whose class `impact-chain`
|
|
262
|
+
said reached 8 — both correct, both documented, in two payloads, so reconciling
|
|
263
|
+
them cost the reader three unit notes. Each row now carries
|
|
264
|
+
`endpoints_reached_basis`: what the figure is a reach *of* (a defect sits at the
|
|
265
|
+
symbol that carries the remedy, so a method-level defect walks from the method)
|
|
266
|
+
and, where that is narrower than a class, the command that answers the wider
|
|
267
|
+
question. The relationship is asserted by measurement rather than stated in
|
|
268
|
+
prose.
|
|
269
|
+
|
|
270
|
+
- **The remedy registry now follows the status, not only the limitation** (C4-13,
|
|
271
|
+
field evaluation #9 — the sixth appearance of the C4 shape). The evaluation met
|
|
272
|
+
`verify`'s `contract_count: 0` → `unverified` → exit 2 under a read-only
|
|
273
|
+
constraint, concluded the command was unusable and asked for a `--dry-run` that
|
|
274
|
+
shipped in 3.7.0. The state named one next move and the reader could not take
|
|
275
|
+
it. `Remedy` gained `also` (the further options an answer needs — a remedy is an
|
|
276
|
+
invocation, not a flag), the new entry is `ask verify . --init --dry-run`, and
|
|
277
|
+
the `unverified` reason names both forms. The guard grew with it: every option
|
|
278
|
+
of an invocation must be accepted by the command it names, and the README check
|
|
279
|
+
matches a line carrying the command with all of its options, so a front page
|
|
280
|
+
that lists `--init` and omits `--dry-run` fails the build.
|
|
281
|
+
|
|
282
|
+
- **The hub-class guard contradicted the payload beside it** (C2-21, field
|
|
283
|
+
evaluation #9). It printed *"symbol has > 500 direct callers"* while the same
|
|
284
|
+
run published 215 of them on openmrs-core's `Context`: the guard trips on
|
|
285
|
+
caller **reference sites** (method-level keys included) and the payload
|
|
286
|
+
publishes caller **classes**, so the stated reason was checkably false while
|
|
287
|
+
the decision was right. `caller_reach.bfs_callers` now returns the population it
|
|
288
|
+
read, and the warning names it with its unit next to the class count it takes
|
|
289
|
+
from `caller_metrics.caller_classes` — *"792 caller reference sites … exceed the
|
|
290
|
+
cap of 500 … The 215 direct caller classes this run publishes stay exact"*.
|
|
291
|
+
|
|
292
|
+
- **`ask risk` ranked findings under the label `spring-audit` deduplicates**
|
|
293
|
+
(C1-23, field evaluation #9). One SEC-004 appeared three times for three call
|
|
294
|
+
sites in one class and `by_band` was an observation census under a defect
|
|
295
|
+
label — measured on BroadleafCommerce, 20 rows over 15 distinct `defect_id`
|
|
296
|
+
beside `spring-audit`'s own 15 defects / 20 findings. `build_risk` now iterates
|
|
297
|
+
`defect_identity.group_by_defect`, so one row is one thing to fix and both
|
|
298
|
+
commands report the same count (asserted against each other, not against a
|
|
299
|
+
literal). Nothing is dropped: `witness_count` and `witness_sites` carry where
|
|
300
|
+
each observation was seen, `total_findings` publishes the census under its own
|
|
301
|
+
name, and `rule_id` becomes **`rule_ids`** because one defect can be witnessed
|
|
302
|
+
by TX-001 and TX-006 at once and a singular field would have to pick one.
|
|
303
|
+
`severity` is the strongest across the witnesses, and
|
|
304
|
+
`factors.defect_severity.basis` says so.
|
|
305
|
+
|
|
306
|
+
- **A Maven build property was published as a runtime activation** (C1-22, field
|
|
307
|
+
evaluation #9 — the row it called the most expensive in its report). Two
|
|
308
|
+
`<properties>` entries setting `spring.profiles.active` made
|
|
309
|
+
`posture --resolve-environments` answer `artefacts_disagree` — *"different
|
|
310
|
+
deployments, pick one"* — on a repository where **nothing activates a profile at
|
|
311
|
+
run time**. The honest verdict, which the command already implements, is
|
|
312
|
+
`NOT DECIDED IN THIS REPOSITORY`: the default set applies and the permissive
|
|
313
|
+
profile wins, which is exactly where that audit's most severe finding lived. The
|
|
314
|
+
command turned a fail-open into a deployment ambiguity, in the scenario it is
|
|
315
|
+
sold for. A build property is now admitted as an activation only when a resource
|
|
316
|
+
in the repository consumes it (`@spring.profiles.active@`, or
|
|
317
|
+
`${spring.profiles.active}` where the build declares its resources filtered).
|
|
318
|
+
Unconsumed, the value is kept — it is still the profile set a build of it would
|
|
319
|
+
produce, so the worst case keeps ranking it — and carries the reason it decides
|
|
320
|
+
nothing, beside a `build_properties_not_consumed` count. The positive control is
|
|
321
|
+
half the battery: before this, the case where the property genuinely does decide
|
|
322
|
+
produced the identical verdict, which is how the defect stayed invisible. No
|
|
323
|
+
movement on the field repositories.
|
|
324
|
+
|
|
325
|
+
- **A rule that disappeared was reported as protection gained.** Found by the
|
|
326
|
+
negative control, not in the field: delete a security configuration and every
|
|
327
|
+
request it decided goes `permit_all` → undecided, which a two-bucket
|
|
328
|
+
opened/closed split published as *"2 requests no longer reachable
|
|
329
|
+
unauthenticated"*. Four buckets now: `opened` and `closed` (attributable to the
|
|
330
|
+
change), `no_longer_decided` (coverage lost) and `now_open_previously_undecided`
|
|
331
|
+
(our reading moved, not necessarily the system — it never turns a gate red on
|
|
332
|
+
its own). Requests undecided on either side are counted in
|
|
333
|
+
`access_not_decided_either_side`, the delta publishes `direction`, and
|
|
334
|
+
`gate.reading` states the floor (I-8).
|
|
335
|
+
- **`git_checkout` no longer offers a remedy half its callers do not have.** The
|
|
336
|
+
not-a-repository message told every caller to "pass two checkouts positionally";
|
|
337
|
+
`posture` takes none. The message states the fact and each command supplies its
|
|
338
|
+
own hint.
|
|
339
|
+
|
|
5
340
|
## [4.1.0] — 2026-08-03
|
|
6
341
|
|
|
7
342
|
Minor, not a patch, and the criterion is this project's own: a new rule can trip
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.3.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
|
|
@@ -156,8 +156,12 @@ ask posture /path/to/repo --resolve-environments
|
|
|
156
156
|
# writing it, and populate .ask/contracts.yml from the measurement instead of by hand.
|
|
157
157
|
ask verify /path/to/repo --init
|
|
158
158
|
|
|
159
|
-
#
|
|
160
|
-
#
|
|
159
|
+
# Same derivation under a read-only constraint: prints what it would declare and
|
|
160
|
+
# writes nothing — the form an audit of somebody else's repository can run.
|
|
161
|
+
ask verify /path/to/repo --init --dry-run
|
|
162
|
+
|
|
163
|
+
# What each defect actually costs once reach, access, write effect and the shape of
|
|
164
|
+
# the input path are in it — ordered, every factor traceable to the command that owns it.
|
|
161
165
|
ask risk /path/to/repo
|
|
162
166
|
```
|
|
163
167
|
|
|
@@ -230,6 +234,9 @@ What a profile set **actually wires**: which conditional beans register, which d
|
|
|
230
234
|
`ask posture` · `ask posture --diff dev:prod` · `ask posture --property k=v`
|
|
231
235
|
→ [posture.md](docs/posture.md)
|
|
232
236
|
|
|
237
|
+
**`--diff-ref` makes it a gate instead of a report.** `--diff` moves the profile set; `--diff-ref origin/main:HEAD` (or `--since origin/main`, which compares a ref with the working tree) moves the *tree* under one profile set and answers *did this branch open an endpoint*. `--fail-on opened` exits 1 when it did. Both refs are read with `git archive` — nothing is written to the repository. The comparison is keyed on the request (`METHOD path`), counts requests only one side serves, and never reports a rule that disappeared as protection gained.
|
|
238
|
+
`ask posture . --since origin/main --fail-on opened`
|
|
239
|
+
|
|
233
240
|
**`--resolve-environments` carries it past the edge of the repository.** Every answer above
|
|
234
241
|
is conditional on a profile set, and which set runs is decided by the deployment. This flag
|
|
235
242
|
reads every artefact in the tree that can set `spring.profiles.active` — Maven/Gradle,
|
|
@@ -247,12 +254,16 @@ guesses is a confident security falsehood — the worst failure mode this tool h
|
|
|
247
254
|
### 5c · Composed Risk *(experimental)*
|
|
248
255
|
Every command above answers one axis, and a reader composes them by hand. `ask risk` does the
|
|
249
256
|
join over the endpoint and symbol ids these commands already share with each other:
|
|
250
|
-
`severity_effective = defect_severity × reachability × auth_verdict × write_effect`. The
|
|
251
|
-
product of the published factors **is** the published score — decomposable to the
|
|
257
|
+
`severity_effective = defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`. The
|
|
258
|
+
product of the published factors **is** the published score — decomposable to the six
|
|
252
259
|
figures and the authority behind each — and an axis this build cannot measure is `unknown`,
|
|
253
260
|
weighted 1.0 and named in `blind_axes` rather than silently treated as safe. Measured on a
|
|
254
261
|
field case: a defect both `spring-audit` and `impact-chain` called *medium* composes to
|
|
255
262
|
**high (8.06)** once *reachable unauthenticated* and *writes to the database* are in it.
|
|
263
|
+
The last two factors describe the input path — a query assembled by concatenation, a route
|
|
264
|
+
accepting a body with no declared constraint. They are **adjacencies, not dataflow**: no
|
|
265
|
+
value is followed from a request to a sink, which is `NC-001` and is published in the
|
|
266
|
+
payload's own `non_coverage` block.
|
|
256
267
|
`ask risk .` · `ask risk . --min-band high` · `ask risk . --limit 10`
|
|
257
268
|
→ [reference](docs/USER_GUIDE.md)
|
|
258
269
|
|
|
@@ -278,7 +289,7 @@ experimental: both are true, and they are two different facts.
|
|
|
278
289
|
|---|---|---|
|
|
279
290
|
| **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
|
|
280
291
|
| **supported** | maintained; fields are added, never removed without a major | every command not named in another row |
|
|
281
|
-
| **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `posture` · `archetype` |
|
|
292
|
+
| **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `enrich` · `data-exposure` · `migrate-recipe` · `posture` · `archetype` |
|
|
282
293
|
| **parked** | kept working, no longer developed | `retrieve` |
|
|
283
294
|
|
|
284
295
|
The same table is printed by `ask --help`, and both are generated from one authority
|
|
@@ -295,7 +306,10 @@ from it.
|
|
|
295
306
|
| Command | Tier | Answers | Note |
|
|
296
307
|
|---|---|---|---|
|
|
297
308
|
| `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
|
|
298
|
-
| `risk` | experimental | what each defect actually costs, once reach, access
|
|
309
|
+
| `risk` | experimental | what each defect actually costs, once reach, access, write effect and the shape of the input path are in it | `defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`; every factor names its authority |
|
|
310
|
+
| `enrich` | experimental | another scanner's SARIF findings, ranked by what this repository does with them | `--sarif <log>`; the same composition as `risk`, with the scanner as the severity authority |
|
|
311
|
+
| `migrate-recipe` | experimental | the migration report as the OpenRewrite recipe that applies it | only recipes a finding named; the manual remainder published beside them; writes nothing without `--write`, and never a runnable command for an empty recipe list |
|
|
312
|
+
| `data-exposure` | experimental | which routes can carry the data you labelled, and who reaches them | labels declared in `sourcecode.config.json` — never inferred from a name; `signature` and `call_reach` evidence published apart, field-level flow out of scope (NC-008) |
|
|
299
313
|
| `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators) |
|
|
300
314
|
| `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment` |
|
|
301
315
|
| `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan |
|
|
@@ -310,7 +324,7 @@ from it.
|
|
|
310
324
|
| `review-pr` / `fix-bug` / `prepare-context` | supported | diff review, symptom triage, task-shaped context | |
|
|
311
325
|
| `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 |
|
|
312
326
|
| `validation` | supported | request-body validation coverage and gaps | |
|
|
313
|
-
| `baseline capture\|diff` · `trend` | supported | versioned architectural metrics over time; `ask trend
|
|
327
|
+
| `baseline capture\|diff` · `trend` | supported | versioned architectural metrics over time; `ask trend .` reads the series (a repository path or a baselines directory), `ask baseline diff .` compares the tree against its newest point | 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`. `capture --auto` is the unattended form (one baseline per commit, never rewrites one, never fails the build) — automate it: [baseline-ci.yml](docs/baseline-ci.yml) |
|
|
314
328
|
| `retrieve` | parked | typed knowledge queries over the model | |
|
|
315
329
|
| `archetype` | experimental | evidence-based architectural archetype | |
|
|
316
330
|
| `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
|
|
@@ -354,6 +368,25 @@ Two more boundaries worth stating in the same voice:
|
|
|
354
368
|
| **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. |
|
|
355
369
|
| **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. |
|
|
356
370
|
|
|
371
|
+
|
|
372
|
+
And one about the endpoint surface itself:
|
|
373
|
+
|
|
374
|
+
| Not covered | Why | What answers it |
|
|
375
|
+
|---|---|---|
|
|
376
|
+
| **HTTP surface that is not a Spring handler mapping — a servlet declared in `web.xml` or registered as a `ServletRegistrationBean`, a container-level mapping, a static console mounted by a library.** | The endpoint population is projected from the Spring route model: one entry per handler mapping. A servlet is reachable over HTTP and is not in that model, so it is absent from `endpoints`, from the access verdicts derived from it, and from every ratio keyed on the total. Merging a second population into that count would move a published figure and every ratio with it, so the population is declared before it is widened. | Read the deployment descriptors for `<servlet-mapping>` entries and the Spring configuration for `ServletRegistrationBean` beans. Field evaluation #9 found a monitoring console mounted this way, behind a credential `ask spring-audit` did report (SEC-007) at a path nothing here listed. |
|
|
377
|
+
|
|
378
|
+
And one about labelled data:
|
|
379
|
+
|
|
380
|
+
| Not covered | Why | What answers it |
|
|
381
|
+
|---|---|---|
|
|
382
|
+
| **Whether a labelled member actually leaves the process on a given route — field-level dataflow through mappers, DTOs, serializers and projections.** | Exposure here is measured at TYPE granularity over the same call reach every other command walks: a route reaches the labelled type, or its signature names it. Whether the mapping in between keeps the labelled member is a dataflow question, and answering it by approximation would put a confident `no` on a route that does leak. So `call_reach` is published as a supremum and says so. | Read the mapping on the routes this answer ranks first — they are the ones worth a human — and label the DTO too if it carries the member, which makes the route `signature` instead of `call_reach`. |
|
|
383
|
+
|
|
384
|
+
And one about who calls a route:
|
|
385
|
+
|
|
386
|
+
| Not covered | Why | What answers it |
|
|
387
|
+
|---|---|---|
|
|
388
|
+
| **Whether a route is called from outside this repository — another service, a mobile app, a partner, a cron job, or a client whose URL is assembled at run time.** | The join reads the TypeScript/JavaScript checked in beside the server and only the call shapes whose verb and path are written at the call site. That is a floor on who calls a route and can never be a ceiling: the repository cannot observe consumers it does not contain. So a route with no call site here is published as a candidate for deletion, never as dead API. | Access logs or an API gateway answer who really calls a route. The opposite direction is decisive without them: a client call matching no route is a request this repository's own front end makes and its server does not serve. |
|
|
389
|
+
|
|
357
390
|
**Positioning.** Until an executor ships, this is the **diagnosis layer**: it measures what
|
|
358
391
|
must change, what each change reaches, and what a gate should block — and it removes none of
|
|
359
392
|
it. Field evaluation scored it 7/10 as a report generator and 5.5/10 as a development tool,
|
|
@@ -118,8 +118,12 @@ ask posture /path/to/repo --resolve-environments
|
|
|
118
118
|
# writing it, and populate .ask/contracts.yml from the measurement instead of by hand.
|
|
119
119
|
ask verify /path/to/repo --init
|
|
120
120
|
|
|
121
|
-
#
|
|
122
|
-
#
|
|
121
|
+
# Same derivation under a read-only constraint: prints what it would declare and
|
|
122
|
+
# writes nothing — the form an audit of somebody else's repository can run.
|
|
123
|
+
ask verify /path/to/repo --init --dry-run
|
|
124
|
+
|
|
125
|
+
# What each defect actually costs once reach, access, write effect and the shape of
|
|
126
|
+
# the input path are in it — ordered, every factor traceable to the command that owns it.
|
|
123
127
|
ask risk /path/to/repo
|
|
124
128
|
```
|
|
125
129
|
|
|
@@ -192,6 +196,9 @@ What a profile set **actually wires**: which conditional beans register, which d
|
|
|
192
196
|
`ask posture` · `ask posture --diff dev:prod` · `ask posture --property k=v`
|
|
193
197
|
→ [posture.md](docs/posture.md)
|
|
194
198
|
|
|
199
|
+
**`--diff-ref` makes it a gate instead of a report.** `--diff` moves the profile set; `--diff-ref origin/main:HEAD` (or `--since origin/main`, which compares a ref with the working tree) moves the *tree* under one profile set and answers *did this branch open an endpoint*. `--fail-on opened` exits 1 when it did. Both refs are read with `git archive` — nothing is written to the repository. The comparison is keyed on the request (`METHOD path`), counts requests only one side serves, and never reports a rule that disappeared as protection gained.
|
|
200
|
+
`ask posture . --since origin/main --fail-on opened`
|
|
201
|
+
|
|
195
202
|
**`--resolve-environments` carries it past the edge of the repository.** Every answer above
|
|
196
203
|
is conditional on a profile set, and which set runs is decided by the deployment. This flag
|
|
197
204
|
reads every artefact in the tree that can set `spring.profiles.active` — Maven/Gradle,
|
|
@@ -209,12 +216,16 @@ guesses is a confident security falsehood — the worst failure mode this tool h
|
|
|
209
216
|
### 5c · Composed Risk *(experimental)*
|
|
210
217
|
Every command above answers one axis, and a reader composes them by hand. `ask risk` does the
|
|
211
218
|
join over the endpoint and symbol ids these commands already share with each other:
|
|
212
|
-
`severity_effective = defect_severity × reachability × auth_verdict × write_effect`. The
|
|
213
|
-
product of the published factors **is** the published score — decomposable to the
|
|
219
|
+
`severity_effective = defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`. The
|
|
220
|
+
product of the published factors **is** the published score — decomposable to the six
|
|
214
221
|
figures and the authority behind each — and an axis this build cannot measure is `unknown`,
|
|
215
222
|
weighted 1.0 and named in `blind_axes` rather than silently treated as safe. Measured on a
|
|
216
223
|
field case: a defect both `spring-audit` and `impact-chain` called *medium* composes to
|
|
217
224
|
**high (8.06)** once *reachable unauthenticated* and *writes to the database* are in it.
|
|
225
|
+
The last two factors describe the input path — a query assembled by concatenation, a route
|
|
226
|
+
accepting a body with no declared constraint. They are **adjacencies, not dataflow**: no
|
|
227
|
+
value is followed from a request to a sink, which is `NC-001` and is published in the
|
|
228
|
+
payload's own `non_coverage` block.
|
|
218
229
|
`ask risk .` · `ask risk . --min-band high` · `ask risk . --limit 10`
|
|
219
230
|
→ [reference](docs/USER_GUIDE.md)
|
|
220
231
|
|
|
@@ -240,7 +251,7 @@ experimental: both are true, and they are two different facts.
|
|
|
240
251
|
|---|---|---|
|
|
241
252
|
| **core** | contract stable within a major — safe to gate CI on | `endpoints` · `spring-audit` · `migrate-check` · `impact` · `impact-chain` · `pr-impact` · `verify` |
|
|
242
253
|
| **supported** | maintained; fields are added, never removed without a major | every command not named in another row |
|
|
243
|
-
| **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `posture` · `archetype` |
|
|
254
|
+
| **experimental** | shape may change in a minor — do not gate CI on it | `risk` · `enrich` · `data-exposure` · `migrate-recipe` · `posture` · `archetype` |
|
|
244
255
|
| **parked** | kept working, no longer developed | `retrieve` |
|
|
245
256
|
|
|
246
257
|
The same table is printed by `ask --help`, and both are generated from one authority
|
|
@@ -257,7 +268,10 @@ from it.
|
|
|
257
268
|
| Command | Tier | Answers | Note |
|
|
258
269
|
|---|---|---|---|
|
|
259
270
|
| `posture` | experimental | which beans a profile set wires, and how effective endpoint access differs between two sets | the most differentiated capability here |
|
|
260
|
-
| `risk` | experimental | what each defect actually costs, once reach, access
|
|
271
|
+
| `risk` | experimental | what each defect actually costs, once reach, access, write effect and the shape of the input path are in it | `defect_severity × reachability × auth_verdict × write_effect × query_construction × input_constraints`; every factor names its authority |
|
|
272
|
+
| `enrich` | experimental | another scanner's SARIF findings, ranked by what this repository does with them | `--sarif <log>`; the same composition as `risk`, with the scanner as the severity authority |
|
|
273
|
+
| `migrate-recipe` | experimental | the migration report as the OpenRewrite recipe that applies it | only recipes a finding named; the manual remainder published beside them; writes nothing without `--write`, and never a runnable command for an empty recipe list |
|
|
274
|
+
| `data-exposure` | experimental | which routes can carry the data you labelled, and who reaches them | labels declared in `sourcecode.config.json` — never inferred from a name; `signature` and `call_reach` evidence published apart, field-level flow out of scope (NC-008) |
|
|
261
275
|
| `endpoints` | core | every REST endpoint, effective path, security policy, confidence | Spring MVC + JAX-RS (~65 % recall on JAX-RS sub-resource locators) |
|
|
262
276
|
| `spring-audit` | core | transactional anomalies + security surface + validation gaps | `--ci`, `-f github-comment` |
|
|
263
277
|
| `migrate-check` | core | Boot 2→3 readiness: located blockers, per-dimension score, effort | `--blast-radius` orders the re-test plan |
|
|
@@ -272,7 +286,7 @@ from it.
|
|
|
272
286
|
| `review-pr` / `fix-bug` / `prepare-context` | supported | diff review, symptom triage, task-shaped context | |
|
|
273
287
|
| `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 |
|
|
274
288
|
| `validation` | supported | request-body validation coverage and gaps | |
|
|
275
|
-
| `baseline capture\|diff` · `trend` | supported | versioned architectural metrics over time; `ask trend
|
|
289
|
+
| `baseline capture\|diff` · `trend` | supported | versioned architectural metrics over time; `ask trend .` reads the series (a repository path or a baselines directory), `ask baseline diff .` compares the tree against its newest point | 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`. `capture --auto` is the unattended form (one baseline per commit, never rewrites one, never fails the build) — automate it: [baseline-ci.yml](docs/baseline-ci.yml) |
|
|
276
290
|
| `retrieve` | parked | typed knowledge queries over the model | |
|
|
277
291
|
| `archetype` | experimental | evidence-based architectural archetype | |
|
|
278
292
|
| `rename-class` / `chunk-file` | supported | word-boundary Java rename; split a large file for an agent | |
|
|
@@ -316,6 +330,25 @@ Two more boundaries worth stating in the same voice:
|
|
|
316
330
|
| **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. |
|
|
317
331
|
| **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. |
|
|
318
332
|
|
|
333
|
+
|
|
334
|
+
And one about the endpoint surface itself:
|
|
335
|
+
|
|
336
|
+
| Not covered | Why | What answers it |
|
|
337
|
+
|---|---|---|
|
|
338
|
+
| **HTTP surface that is not a Spring handler mapping — a servlet declared in `web.xml` or registered as a `ServletRegistrationBean`, a container-level mapping, a static console mounted by a library.** | The endpoint population is projected from the Spring route model: one entry per handler mapping. A servlet is reachable over HTTP and is not in that model, so it is absent from `endpoints`, from the access verdicts derived from it, and from every ratio keyed on the total. Merging a second population into that count would move a published figure and every ratio with it, so the population is declared before it is widened. | Read the deployment descriptors for `<servlet-mapping>` entries and the Spring configuration for `ServletRegistrationBean` beans. Field evaluation #9 found a monitoring console mounted this way, behind a credential `ask spring-audit` did report (SEC-007) at a path nothing here listed. |
|
|
339
|
+
|
|
340
|
+
And one about labelled data:
|
|
341
|
+
|
|
342
|
+
| Not covered | Why | What answers it |
|
|
343
|
+
|---|---|---|
|
|
344
|
+
| **Whether a labelled member actually leaves the process on a given route — field-level dataflow through mappers, DTOs, serializers and projections.** | Exposure here is measured at TYPE granularity over the same call reach every other command walks: a route reaches the labelled type, or its signature names it. Whether the mapping in between keeps the labelled member is a dataflow question, and answering it by approximation would put a confident `no` on a route that does leak. So `call_reach` is published as a supremum and says so. | Read the mapping on the routes this answer ranks first — they are the ones worth a human — and label the DTO too if it carries the member, which makes the route `signature` instead of `call_reach`. |
|
|
345
|
+
|
|
346
|
+
And one about who calls a route:
|
|
347
|
+
|
|
348
|
+
| Not covered | Why | What answers it |
|
|
349
|
+
|---|---|---|
|
|
350
|
+
| **Whether a route is called from outside this repository — another service, a mobile app, a partner, a cron job, or a client whose URL is assembled at run time.** | The join reads the TypeScript/JavaScript checked in beside the server and only the call shapes whose verb and path are written at the call site. That is a floor on who calls a route and can never be a ceiling: the repository cannot observe consumers it does not contain. So a route with no call site here is published as a candidate for deletion, never as dead API. | Access logs or an API gateway answer who really calls a route. The opposite direction is decisive without them: a client call matching no route is a request this repository's own front end makes and its server does not serve. |
|
|
351
|
+
|
|
319
352
|
**Positioning.** Until an executor ships, this is the **diagnosis layer**: it measures what
|
|
320
353
|
must change, what each change reaches, and what a gate should block — and it removes none of
|
|
321
354
|
it. Field evaluation scored it 7/10 as a report generator and 5.5/10 as a development tool,
|
|
@@ -312,6 +312,25 @@ def load_baseline(path: Path) -> dict:
|
|
|
312
312
|
return data
|
|
313
313
|
|
|
314
314
|
|
|
315
|
+
def latest_baseline_path(directory: Path) -> "Path | None":
|
|
316
|
+
"""The most recently captured baseline in `directory`, or None if there is none.
|
|
317
|
+
|
|
318
|
+
Ordered exactly as `load_baselines_dir` orders its series (capture time, commit
|
|
319
|
+
as the tie-break), so "the last point in the trend" and "the base a diff uses by
|
|
320
|
+
default" can never disagree about which artifact that is.
|
|
321
|
+
"""
|
|
322
|
+
dated: list[tuple[str, str, Path]] = []
|
|
323
|
+
for p in sorted(Path(directory).glob("*.json")):
|
|
324
|
+
try:
|
|
325
|
+
b = load_baseline(p)
|
|
326
|
+
except (OSError, ValueError, json.JSONDecodeError):
|
|
327
|
+
continue
|
|
328
|
+
dated.append((str(b.get("captured_at", "")), str(b.get("commit", "")), p))
|
|
329
|
+
if not dated:
|
|
330
|
+
return None
|
|
331
|
+
return max(dated, key=lambda t: (t[0], t[1]))[2]
|
|
332
|
+
|
|
333
|
+
|
|
315
334
|
def load_baselines_dir(directory: Path) -> list[dict]:
|
|
316
335
|
"""Load every architectural baseline in `directory`, sorted by capture time."""
|
|
317
336
|
out: list[dict] = []
|