sourcecode 5.0.0__tar.gz → 5.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-5.0.0 → sourcecode-5.0.1}/CHANGELOG.md +44 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/PKG-INFO +3 -3
- {sourcecode-5.0.0 → sourcecode-5.0.1}/README.md +2 -2
- {sourcecode-5.0.0 → sourcecode-5.0.1}/pyproject.toml +1 -1
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/__init__.py +1 -1
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/cache_model.py +156 -32
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/execution_plan.py +44 -6
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/posture.py +13 -26
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/repository_ir.py +21 -31
- sourcecode-5.0.1/src/sourcecode/security_chain.py +148 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/security_config_scan.py +54 -4
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/source_text.py +18 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/.github/workflows/perf-gate.yml +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/.gitignore +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/.ruff.toml +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/CLAUDE.md +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/CONTRIBUTING.md +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/LICENSE +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/SECURITY.md +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/raw +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/scripts/compare_integration_engines.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/scripts/customer_smoke_test.sh +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/scripts/generate_jdk_exports.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/scripts/perf_gate.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/scripts/perf_harness.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/archetype.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/architectural_baseline.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/architectural_delta.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/audit_report.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/baseline_autocapture.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/cache.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/call_surface.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/caller_metrics.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/caller_reach.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/chain_rules.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/change_plan.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/classifier.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/cli.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/client_calls.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/compare.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/constraint_diff.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/container_wiring.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/context_cache.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/context_graph.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/contract_diff.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/contract_init.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/data_exposure.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/data_labels.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/declarations.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/defect_identity.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/degradation.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/deployment_prefix.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detach.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/dynamic_argument_surface.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/endpoint_literals.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/endpoint_metrics.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/envelope.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/environment_resolution.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/evidence_provider.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/explain.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/facts/__init__.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/facts/registry.json +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/filter_surface.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/format_contract.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/git_checkout.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/graph_evidence.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/hibernate_strat.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/identity_fallback.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/integration_coordinates.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/jdk_exports.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/license.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/mcp/dependency_import.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/migrate_check.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/migration_blast.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/non_coverage.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/openrewrite_recipe.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/output_encoding.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/parallel.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/parse_cache.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/partial_contract.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/path_admission.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/perf.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/phased_run.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/pipe_contract.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/progress.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/provenance.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/readiness_timeline.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/readonly.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/reconciliation.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/redactor.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/reference_facts.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/release_info.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/remedies.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/__init__.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/context.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/errors.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/executor.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/planner.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/query.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/request.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/resolution.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/result.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/retriever.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/runtime.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/steps.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/steps_graph.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/steps_impact.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/steps_intf.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/steps_struct.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/retrieval/steps_txsec.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/ris.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/risk.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/rule_catalog.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/rule_pass.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/runs.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/sarif.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/scanner.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/schema.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/security_config.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/security_posture.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/semantic_impact_engine.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/semantic_integration_engine.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/semantic_services.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/serializer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/servlet_surface.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/spring_findings.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/spring_impact.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/spring_profiles.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/spring_properties.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/spring_security_audit.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/spring_tx_analyzer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/target_admission.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/test_gap_ranking.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/test_sources.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/text_input.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/token_estimate.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/type_usage_surface.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/validation_inference.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/validation_surface.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/verify_edit.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/verify_repo.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/verify_rules.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/version_check.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/src/sourcecode/workspace.py +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/supabase/functions/README.md +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/supabase/sql/licensing_schema.sql +0 -0
- {sourcecode-5.0.0 → sourcecode-5.0.1}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -2,6 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.0.1] — 2026-08-11
|
|
6
|
+
|
|
7
|
+
**A patch on the release that made the product's own cost figures honest, for the
|
|
8
|
+
four cells that refresh did not reach.** No analysis changes: `onboard` payloads
|
|
9
|
+
on spring-petclinic and jobrunr are byte-identical against 5.0.0. What moves is
|
|
10
|
+
the operational advice on two commands — `repo-ir` and `baseline capture` are
|
|
11
|
+
foreground work at field scale, where 5.0.0 still sent them to a nightly job on a
|
|
12
|
+
4.10.4 outcome.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **Four cost cells the 5.0.0 refresh did not reach, and two of them said the
|
|
17
|
+
field could not run a command it has since run twice (C3-100).** C3-97 gave
|
|
18
|
+
every field figure the build it was taken on and re-measured what evaluation
|
|
19
|
+
#22 had run; what #22 had not run kept its 4.10.4 cell. `ask` (root) published
|
|
20
|
+
115 s, `baseline` 11 s, and — worse, because the claim is categorical rather
|
|
21
|
+
than numeric — `repo-ir` and `verify-edit` published `field_blocked`, which the
|
|
22
|
+
model renders as *"did not finish in an interactive session"*. Evaluation #23
|
|
23
|
+
ran all four from a purged cache on the same repository: root **72,3 s**,
|
|
24
|
+
`repo-ir` **9,8 s**, `baseline capture` **2,2 s**, `verify-edit` **76,6 s**.
|
|
25
|
+
`repo-ir` and `baseline` are foreground work at field scale where the product
|
|
26
|
+
was sending them to a nightly job.
|
|
27
|
+
- **An outcome is a measurement, so it expires like one.** `field_blocked` was the
|
|
28
|
+
strongest claim in the table and the only one that could be written without a
|
|
29
|
+
build behind it. It is dated now wherever it is published (*"did not finish in
|
|
30
|
+
an interactive session on 4.10.4 … and nothing has re-measured it since"*), and
|
|
31
|
+
the battery rejects an undated one.
|
|
32
|
+
- **A figure now states the cache state it was taken in.** The root analysis is
|
|
33
|
+
72,3 s from a purged cache and 0,3 s from a warm one; publishing one number
|
|
34
|
+
without saying which invites a reader to compare two different facts. Every
|
|
35
|
+
field figure carries `warm`/`cold`/`mixed`, in the `here:` line, the `cache
|
|
36
|
+
model` rows and the JSON.
|
|
37
|
+
- **The headline anchor is read off the table instead of copied beside it.**
|
|
38
|
+
`FIELD_ANCHOR`, `FIELD_ANCHOR_SECONDS` and `FIELD_ANCHOR_MEASURED_VERSION` are
|
|
39
|
+
derived from the `spring-audit` row — the missed copy is what C3-100 was — and
|
|
40
|
+
`field_currency()` now also names every row measured before the newest figure in
|
|
41
|
+
the same table (`rows_behind_the_newest_field_measurement`), which is the
|
|
42
|
+
staleness that hid for three releases: not *"older than the build you are
|
|
43
|
+
running"* but *"older than the refresh that reached the row next to it"*.
|
|
44
|
+
- **The root row was invisible to the surface its measurement exists for.**
|
|
45
|
+
`cost_row("ask (root)")` resolved to no row, so `cache model`'s `here:` line for
|
|
46
|
+
the root analysis was published from the command's *class*, with no figure in
|
|
47
|
+
it, on every repository. Found while checking the refresh on a real one.
|
|
48
|
+
|
|
5
49
|
## [5.0.0] — 2026-08-11
|
|
6
50
|
|
|
7
51
|
**The engine got 280× faster in 4.18.0 and every number the product quoted about
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 5.0.
|
|
3
|
+
Version: 5.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
|
|
@@ -42,7 +42,7 @@ Description-Content-Type: text/markdown
|
|
|
42
42
|
|
|
43
43
|
**Context · Impact · Migration · Architecture · Review — everything from one structural model.**
|
|
44
44
|
|
|
45
|
-

|
|
46
46
|

|
|
47
47
|
|
|
48
48
|
> **ASK Engine** is the product. The CLI command is **`ask`**. The legacy **`sourcecode`**
|
|
@@ -126,7 +126,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
|
|
|
126
126
|
# pip / pipx
|
|
127
127
|
pipx install sourcecode # or: pip install sourcecode
|
|
128
128
|
|
|
129
|
-
ask version # ask 5.0.
|
|
129
|
+
ask version # ask 5.0.1 — and, on a build that has aged,
|
|
130
130
|
# how many releases have probably shipped since
|
|
131
131
|
```
|
|
132
132
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
**Context · Impact · Migration · Architecture · Review — everything from one structural model.**
|
|
6
6
|
|
|
7
|
-

|
|
8
8
|

|
|
9
9
|
|
|
10
10
|
> **ASK Engine** is the product. The CLI command is **`ask`**. The legacy **`sourcecode`**
|
|
@@ -88,7 +88,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
|
|
|
88
88
|
# pip / pipx
|
|
89
89
|
pipx install sourcecode # or: pip install sourcecode
|
|
90
90
|
|
|
91
|
-
ask version # ask 5.0.
|
|
91
|
+
ask version # ask 5.0.1 — and, on a build that has aged,
|
|
92
92
|
# how many releases have probably shipped since
|
|
93
93
|
```
|
|
94
94
|
|
|
@@ -87,7 +87,28 @@ class CommandCache:
|
|
|
87
87
|
#: releases (spring-audit, 408 s in #13 against 2 351 s in #16) is itself the
|
|
88
88
|
#: measurement C3-76 exists for.
|
|
89
89
|
field_seconds: "Optional[float]" = None
|
|
90
|
+
#: **C3-100.** `field_blocked` is a *measurement outcome*, not a property of the
|
|
91
|
+
#: command: it says "this run did not finish on that build, at that size", and
|
|
92
|
+
#: like every other measurement here it belongs to the build named in
|
|
93
|
+
#: `field_measured_version` and expires with it. It was read as a property for
|
|
94
|
+
#: three releases — `repo-ir` and `verify-edit` carried a 4.10.4 outcome while
|
|
95
|
+
#: eval #23 ran them in 9,8 s and 76,6 s — which is worse than a stale number,
|
|
96
|
+
#: because a stale number is a measurement and *"the field could not run this"*
|
|
97
|
+
#: is an incapacity the product does not have. A blocked row without a build is
|
|
98
|
+
#: rejected by the battery for the same reason a figure without one is.
|
|
90
99
|
field_blocked: bool = False
|
|
100
|
+
#: The cache state the field figure was taken in. Eval #22 measured a warm
|
|
101
|
+
#: machine; eval #23 purged every cache first (`cache clear --all`,
|
|
102
|
+
#: `context-clear`, `rm -rf parse-cache-v1`) and then ran the whole catalogue
|
|
103
|
+
#: in one round, so its first figures are cold and its later ones are neither —
|
|
104
|
+
#: the shared layers filled as the round went on. Published because *72,3 s
|
|
105
|
+
#: cold* and *72,3 s warm* are two different facts about the same command, and
|
|
106
|
+
#: the row that says which is the only thing standing between the two:
|
|
107
|
+
#: ``warm`` — the caches were warmed before the run
|
|
108
|
+
#: ``cold`` — every cache was purged before the run
|
|
109
|
+
#: ``mixed`` — inside a round that began purged: earlier commands had already
|
|
110
|
+
#: filled some of the shared layers this one reads
|
|
111
|
+
field_cache_state: str = "warm"
|
|
91
112
|
#: **C3-97.** The build the field figure was taken on. An anchor without one is
|
|
92
113
|
#: a measurement that can outlive its build and keep deciding: 4.18.0 deleted
|
|
93
114
|
#: two catastrophic-backtracking patterns (C3-95, C3-96) and every figure taken
|
|
@@ -137,21 +158,20 @@ REFERENCE_MEASURED_VERSION = "3.2.2"
|
|
|
137
158
|
#: What can be said honestly is the class, the two measured anchors, **the build
|
|
138
159
|
#: each was measured on**, and how to run it.
|
|
139
160
|
#:
|
|
140
|
-
#: History of
|
|
161
|
+
#: History of the anchor, kept because it is the measurement C3-76 exists for:
|
|
141
162
|
#: 408 s (#13) → 2 351 s (#16, C3-72) → 8,4 s (#22, C3-97). The middle figure was
|
|
142
163
|
#: quoted as an operational anchor for four releases after the build that produced
|
|
143
164
|
#: it, and told operators to detach commands that finish in seconds.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
165
|
+
#:
|
|
166
|
+
#: ⚠ `FIELD_ANCHOR`, `FIELD_ANCHOR_SECONDS` and `FIELD_ANCHOR_MEASURED_VERSION`
|
|
167
|
+
#: are **derived from the `spring-audit` row**, below `COMMANDS`. They used to be
|
|
168
|
+
#: written out here as well, which made the anchor two facts kept in step by hand:
|
|
169
|
+
#: C3-97 refreshed both, and C3-100 is what it costs when the next refresh reaches
|
|
170
|
+
#: only one of the copies. One authority per fact — the table — and the headline
|
|
171
|
+
#: reads itself off it.
|
|
172
|
+
#:
|
|
173
|
+
#: The size of the field repository every `field_seconds` below was taken on.
|
|
148
174
|
FIELD_ANCHOR_JAVA_FILES = 3342
|
|
149
|
-
FIELD_ANCHOR_SECONDS = 8.4
|
|
150
|
-
|
|
151
|
-
#: The build the field anchors above were taken on. Rows carrying a different
|
|
152
|
-
#: `field_measured_version` are published with that build's name attached rather
|
|
153
|
-
#: than as figures for this one (C3-97).
|
|
154
|
-
FIELD_ANCHOR_MEASURED_VERSION = "4.18.0"
|
|
155
175
|
|
|
156
176
|
|
|
157
177
|
#: Every layer keys on `cache.worktree_signature` — the exact tree state (C1-9).
|
|
@@ -217,9 +237,12 @@ COMMANDS: tuple[CommandCache, ...] = (
|
|
|
217
237
|
CommandCache("ask (root)", ("snapshot", "ris", "parse"), "answer", True,
|
|
218
238
|
"`--compact` is what a warm stores by default; `--agent` needs `cache warm --agent`. "
|
|
219
239
|
"`--env-map`, `--depth N` and `--exclude` change the *analysis*, so they miss the "
|
|
220
|
-
"warmed core and rescan —
|
|
240
|
+
"warmed core and rescan — the 171 s the field measured after a 103 s warm on 4.10.4. "
|
|
241
|
+
"Eval #23 timed the same invocation at 72,3 s from a purged cache, and then paid "
|
|
242
|
+
"71,7 s again for `--agent` on the state it had just analysed (C3-103).",
|
|
221
243
|
"--compact 13.3 s cold → 0.3 s warm (cold re-measured on 3.7.0: was 19.3 s, C3-6); "
|
|
222
|
-
"--agent --full --env-map --depth 20 34.7 s → 33.9 s (no gain)", analysis_class="repo-wide", cold_seconds=13.3, warm_seconds=0.3,
|
|
244
|
+
"--agent --full --env-map --depth 20 34.7 s → 33.9 s (no gain)", analysis_class="repo-wide", cold_seconds=13.3, warm_seconds=0.3,
|
|
245
|
+
field_seconds=72.3, field_cache_state="cold", field_measured_version="5.0.0"),
|
|
223
246
|
CommandCache("posture", ("cir", "parse"), "shared", False,
|
|
224
247
|
"Resolves the conditional bean graph on every run, over the shared CIR a warm "
|
|
225
248
|
"builds — the parse it used to repeat for itself. `--diff` compares two profile "
|
|
@@ -284,9 +307,11 @@ COMMANDS: tuple[CommandCache, ...] = (
|
|
|
284
307
|
CommandCache("verify", (), "none", False, "Runs the contracts against a fresh reading.", analysis_class="core"),
|
|
285
308
|
CommandCache("verify-edit", ("parse",), "shared", True,
|
|
286
309
|
"Built for the edit loop: the parse cache is what keeps an unchanged file out of the "
|
|
287
|
-
"next run. Its own second run is faster again."
|
|
310
|
+
"next run. Its own second run is faster again. At field size that loop is not short "
|
|
311
|
+
"yet: eval #23 measured 76,6 s on a tree with no edits, because the HEAD side is "
|
|
312
|
+
"still built in a throwaway worktree instead of reusing the shared CIR (C3-102).",
|
|
288
313
|
"14.6 s → 9.6 s → 5.6 s on repeat", analysis_class="repo-wide", cold_seconds=14.6, warm_seconds=9.6,
|
|
289
|
-
|
|
314
|
+
field_seconds=76.6, field_cache_state="mixed", field_measured_version="5.0.0"),
|
|
290
315
|
CommandCache("review-pr", ("cir",), "none", False,
|
|
291
316
|
"Diff-dependent, and it reuses the CIR only if one exists. On a small diff, loading "
|
|
292
317
|
"the warmed CIR costs more than the work it saves.",
|
|
@@ -318,8 +343,12 @@ COMMANDS: tuple[CommandCache, ...] = (
|
|
|
318
343
|
"9.8 s → 1.6 s", analysis_class="core", cold_seconds=9.8, warm_seconds=1.6,
|
|
319
344
|
field_seconds=4.4, field_measured_version="4.18.0"),
|
|
320
345
|
CommandCache("export", ("parse",), "shared", False, "", "8.8 s → 3.7 s", analysis_class="repo-wide", cold_seconds=8.8, warm_seconds=3.7),
|
|
321
|
-
CommandCache("repo-ir", ("parse",), "shared", False,
|
|
322
|
-
|
|
346
|
+
CommandCache("repo-ir", ("parse",), "shared", False,
|
|
347
|
+
"Carried as *did not finish* from 4.10.4 until eval #23 ran it at field size in "
|
|
348
|
+
"9,8 s — a run that did not finish once is not a command that cannot finish "
|
|
349
|
+
"(C3-100, and the same correction `modernize` needed).",
|
|
350
|
+
"5.1 s → 2.9 s", analysis_class="repo-wide", cold_seconds=5.1, warm_seconds=2.9,
|
|
351
|
+
field_seconds=9.8, field_cache_state="mixed", field_measured_version="5.0.0"),
|
|
323
352
|
CommandCache("validation", ("parse",), "shared", False, "", "11.6 s → 6.4 s", analysis_class="repo-wide", cold_seconds=11.6, warm_seconds=6.4,
|
|
324
353
|
field_seconds=17.4, field_measured_version="4.18.0"),
|
|
325
354
|
CommandCache("modernize", ("parse",), "shared", False,
|
|
@@ -333,8 +362,11 @@ COMMANDS: tuple[CommandCache, ...] = (
|
|
|
333
362
|
"`no_ris` instead of a snapshot.",
|
|
334
363
|
"0.2 s either way", analysis_class="core", cold_seconds=0.2, warm_seconds=0.2),
|
|
335
364
|
CommandCache("trend", (), "none", False, "Reads stored baseline artifacts from disk; analyses no source, so no cache layer applies. Same command as `baseline trend`.", analysis_class="none"),
|
|
336
|
-
CommandCache("baseline", ("parse",), "shared", False,
|
|
337
|
-
"capture
|
|
365
|
+
CommandCache("baseline", ("parse",), "shared", False,
|
|
366
|
+
"`capture`/`diff`/`trend` over architectural metrics. The field figure is `capture`, "
|
|
367
|
+
"the subcommand that analyses; `trend` reads stored artifacts and has its own row.",
|
|
368
|
+
"capture 8.7 s → 3.6 s", analysis_class="repo-wide", cold_seconds=8.7, warm_seconds=3.6,
|
|
369
|
+
field_seconds=2.2, field_cache_state="mixed", field_measured_version="5.0.0"),
|
|
338
370
|
CommandCache("retrieve", ("cir", "parse"), "shared", False,
|
|
339
371
|
"Every query builds or reuses the shared CIR a warm builds.", analysis_class="core"),
|
|
340
372
|
CommandCache("archetype", ("parse",), "shared", False, "", "9.3 s → 5.6 s", analysis_class="repo-wide", cold_seconds=9.3, warm_seconds=5.6),
|
|
@@ -355,6 +387,73 @@ _WARM_LABEL = {
|
|
|
355
387
|
"none": "nothing",
|
|
356
388
|
}
|
|
357
389
|
|
|
390
|
+
#: The cache states a field figure may declare. A row outside this set is a
|
|
391
|
+
#: measurement whose conditions nobody can read (C3-100).
|
|
392
|
+
FIELD_CACHE_STATES = ("warm", "cold", "mixed")
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def _thousands(n: int) -> str:
|
|
396
|
+
return f"{n:,}".replace(",", " ")
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def _row(command: str) -> "CommandCache":
|
|
400
|
+
for entry in COMMANDS:
|
|
401
|
+
if entry.command == command:
|
|
402
|
+
return entry
|
|
403
|
+
raise KeyError(command)
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
#: The headline anchor, read off the table rather than written twice (C3-100).
|
|
407
|
+
#: `spring-audit` is the command the whole series measured — 408 s (#13), 2 351 s
|
|
408
|
+
#: (#16), 8,4 s (#22) — so it is the row the front page quotes, and quoting it
|
|
409
|
+
#: means reading it, not copying it.
|
|
410
|
+
_FIELD_ANCHOR_ROW = _row("spring-audit")
|
|
411
|
+
FIELD_ANCHOR_SECONDS = _FIELD_ANCHOR_ROW.field_seconds
|
|
412
|
+
FIELD_ANCHOR_MEASURED_VERSION = _FIELD_ANCHOR_ROW.field_measured_version
|
|
413
|
+
FIELD_ANCHOR = (
|
|
414
|
+
f"field evaluation #22: spring-audit on {_thousands(FIELD_ANCHOR_JAVA_FILES)} "
|
|
415
|
+
f"Java files took {FIELD_ANCHOR_SECONDS:g} s (Windows, pipx, "
|
|
416
|
+
f"{_FIELD_ANCHOR_ROW.field_cache_state} cache) against "
|
|
417
|
+
f"{_FIELD_ANCHOR_ROW.cold_seconds:g} s on the "
|
|
418
|
+
f"{_thousands(REFERENCE_JAVA_FILES)}-file reference"
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def _version_key(version: "Optional[str]") -> tuple:
|
|
423
|
+
"""A comparable key for a release name, for ordering measurements only.
|
|
424
|
+
|
|
425
|
+
Not a distance — `reference_currency` refuses to invent one and this does not
|
|
426
|
+
either. It answers exactly one question: is this row's build older than the
|
|
427
|
+
newest build anything in the table was measured on (C3-100)? Anything
|
|
428
|
+
unparseable sorts oldest, which is the safe direction: it gets labelled.
|
|
429
|
+
"""
|
|
430
|
+
if not version:
|
|
431
|
+
return ()
|
|
432
|
+
parts: list[int] = []
|
|
433
|
+
for chunk in version.split("."):
|
|
434
|
+
digits = "".join(c for c in chunk if c.isdigit())
|
|
435
|
+
if not digits:
|
|
436
|
+
break
|
|
437
|
+
parts.append(int(digits))
|
|
438
|
+
return tuple(parts)
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def newest_field_measurement_version() -> "Optional[str]":
|
|
442
|
+
"""The most recent build any field figure in the table was taken on.
|
|
443
|
+
|
|
444
|
+
The reference point for *"this row is older than the table it sits in"* — the
|
|
445
|
+
state C3-100 lived in for three releases, where a refresh reached five rows
|
|
446
|
+
and left four behind on a build four releases older, with nothing anywhere
|
|
447
|
+
saying so.
|
|
448
|
+
"""
|
|
449
|
+
versions = [
|
|
450
|
+
row.field_measured_version
|
|
451
|
+
for row in COMMANDS
|
|
452
|
+
if (row.field_seconds is not None or row.field_blocked)
|
|
453
|
+
and row.field_measured_version
|
|
454
|
+
]
|
|
455
|
+
return max(versions, key=_version_key) if versions else None
|
|
456
|
+
|
|
358
457
|
|
|
359
458
|
def layer(layer_id: str) -> Layer:
|
|
360
459
|
for entry in LAYERS:
|
|
@@ -459,10 +558,6 @@ def cost_sentence() -> str:
|
|
|
459
558
|
)
|
|
460
559
|
|
|
461
560
|
|
|
462
|
-
def _thousands(n: int) -> str:
|
|
463
|
-
return f"{n:,}".replace(",", " ")
|
|
464
|
-
|
|
465
|
-
|
|
466
561
|
def field_currency() -> dict:
|
|
467
562
|
"""The same statement as `reference_currency`, for the field anchors (C3-97).
|
|
468
563
|
|
|
@@ -473,11 +568,32 @@ def field_currency() -> dict:
|
|
|
473
568
|
from sourcecode import __version__
|
|
474
569
|
|
|
475
570
|
current = __version__
|
|
571
|
+
measured = [
|
|
572
|
+
row for row in COMMANDS
|
|
573
|
+
if row.field_seconds is not None or row.field_blocked
|
|
574
|
+
]
|
|
476
575
|
stale = sorted(
|
|
477
576
|
row.command
|
|
478
|
-
for row in
|
|
479
|
-
if
|
|
480
|
-
|
|
577
|
+
for row in measured
|
|
578
|
+
if row.field_measured_version not in (None, current)
|
|
579
|
+
)
|
|
580
|
+
# C3-100: the other staleness, and the one that hid for three releases — not
|
|
581
|
+
# "older than the build you are running" (every row is, the day after a
|
|
582
|
+
# release) but "older than the newest measurement in this same table", which
|
|
583
|
+
# is a refresh that reached some rows and not others. Named here so the gap is
|
|
584
|
+
# readable without diffing the rows by hand.
|
|
585
|
+
newest = newest_field_measurement_version()
|
|
586
|
+
behind = sorted(
|
|
587
|
+
row.command
|
|
588
|
+
for row in measured
|
|
589
|
+
if _version_key(row.field_measured_version) < _version_key(newest)
|
|
590
|
+
)
|
|
591
|
+
lagging = (
|
|
592
|
+
f" {len(behind)} of the {len(measured)} field figures were taken before "
|
|
593
|
+
f"the newest one in this table ({newest}): "
|
|
594
|
+
f"{', '.join(behind)}."
|
|
595
|
+
if behind
|
|
596
|
+
else ""
|
|
481
597
|
)
|
|
482
598
|
return {
|
|
483
599
|
"anchor": FIELD_ANCHOR,
|
|
@@ -485,12 +601,17 @@ def field_currency() -> dict:
|
|
|
485
601
|
"running_version": current,
|
|
486
602
|
"current": FIELD_ANCHOR_MEASURED_VERSION == current,
|
|
487
603
|
"rows_measured_on_an_earlier_build": stale,
|
|
604
|
+
"newest_field_measurement_version": newest,
|
|
605
|
+
"rows_behind_the_newest_field_measurement": behind,
|
|
488
606
|
"statement": (
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
607
|
+
(
|
|
608
|
+
f"The field anchors were taken on {FIELD_ANCHOR_MEASURED_VERSION}; you "
|
|
609
|
+
f"are running {current}. Each row states the build its field figure "
|
|
610
|
+
f"belongs to, and no figure is projected onto this one."
|
|
611
|
+
if FIELD_ANCHOR_MEASURED_VERSION != current
|
|
612
|
+
else f"The field anchors were taken on {current}, the build you are running."
|
|
613
|
+
)
|
|
614
|
+
+ lagging
|
|
494
615
|
),
|
|
495
616
|
}
|
|
496
617
|
|
|
@@ -590,6 +711,7 @@ def as_dict(here: "Optional[Conditioning]" = None) -> dict:
|
|
|
590
711
|
"seconds": cmd.field_seconds,
|
|
591
712
|
"did_not_finish": cmd.field_blocked,
|
|
592
713
|
"java_files": FIELD_ANCHOR_JAVA_FILES,
|
|
714
|
+
"cache_state": cmd.field_cache_state,
|
|
593
715
|
"measured_on_version": cmd.field_measured_version,
|
|
594
716
|
"note": field_anchor_note(cmd),
|
|
595
717
|
}
|
|
@@ -713,13 +835,15 @@ def render_text(here: "Optional[Conditioning]" = None) -> str:
|
|
|
713
835
|
lines.append(f" {' ' * width} measured: {cmd.measured}")
|
|
714
836
|
if cmd.field_seconds is not None or cmd.field_blocked:
|
|
715
837
|
# C3-97: never the seconds without the build they were taken on.
|
|
838
|
+
# C3-100: nor without the cache state they were taken in.
|
|
716
839
|
note = field_anchor_note(cmd)
|
|
717
840
|
shown = (
|
|
718
841
|
"did not finish in an interactive session"
|
|
719
842
|
if cmd.field_seconds is None
|
|
720
843
|
else f"{cmd.field_seconds:g} s"
|
|
721
844
|
)
|
|
722
|
-
|
|
845
|
+
qualifiers = [f"{cmd.field_cache_state} cache"] + ([note] if note else [])
|
|
846
|
+
suffix = f" ({', '.join(qualifiers)})"
|
|
723
847
|
lines.append(
|
|
724
848
|
f" {' ' * width} field: {shown} at "
|
|
725
849
|
f"{_thousands(FIELD_ANCHOR_JAVA_FILES)} Java files{suffix}"
|
|
@@ -204,7 +204,16 @@ def cost_row(command: str):
|
|
|
204
204
|
`retrieve blast-radius <sym> .` — because that is what the front page and the
|
|
205
205
|
remedies hold. Flags and arguments are dropped; what is left is the command.
|
|
206
206
|
"""
|
|
207
|
-
|
|
207
|
+
named = (command or "").strip()
|
|
208
|
+
if named in _BY_COMMAND:
|
|
209
|
+
# A caller may also ask by the name the table itself gives a row, which is
|
|
210
|
+
# how `cache model` builds its `here:` lines. The root analysis is filed as
|
|
211
|
+
# "ask (root)" — a name the tokenizer below strips to `(root)` and then
|
|
212
|
+
# fails to find, so the root row's `here:` line was the only one published
|
|
213
|
+
# from its class instead of from its measurement (C3-100: a cell nothing
|
|
214
|
+
# reads is the cell that goes stale).
|
|
215
|
+
return _BY_COMMAND[named]
|
|
216
|
+
tokens = [t for t in named.split() if not t.startswith("-")]
|
|
208
217
|
if tokens and tokens[0] in ("ask", "sourcecode"):
|
|
209
218
|
tokens = tokens[1:]
|
|
210
219
|
if not tokens:
|
|
@@ -259,16 +268,22 @@ def _reference(row) -> Optional[str]:
|
|
|
259
268
|
f"{row.cold_seconds:g} s cold{warm} at {REFERENCE_JAVA_FILES} files"
|
|
260
269
|
)
|
|
261
270
|
note = field_anchor_note(row)
|
|
262
|
-
|
|
271
|
+
# C3-100: the cache state travels with the figure for the same reason the
|
|
272
|
+
# build does — a root analysis is 72,3 s from a purged cache and 0,3 s from a
|
|
273
|
+
# warm one, so a figure that does not say which is not a measurement anybody
|
|
274
|
+
# can act on.
|
|
275
|
+
qualified = ", ".join(
|
|
276
|
+
["field", f"{row.field_cache_state} cache"] + ([note] if note else [])
|
|
277
|
+
)
|
|
263
278
|
if row.field_seconds is not None:
|
|
264
279
|
parts.append(
|
|
265
280
|
f"{row.field_seconds:g} s at {_files(FIELD_ANCHOR_JAVA_FILES)} files "
|
|
266
|
-
f"(
|
|
281
|
+
f"({qualified})"
|
|
267
282
|
)
|
|
268
283
|
elif row.field_blocked:
|
|
269
284
|
parts.append(
|
|
270
285
|
f"did not finish in an interactive session at "
|
|
271
|
-
f"{_files(FIELD_ANCHOR_JAVA_FILES)} files (
|
|
286
|
+
f"{_files(FIELD_ANCHOR_JAVA_FILES)} files ({qualified})"
|
|
272
287
|
)
|
|
273
288
|
return " · ".join(parts) or None
|
|
274
289
|
|
|
@@ -310,11 +325,27 @@ def verdict(command: str, scope: Scope) -> Verdict:
|
|
|
310
325
|
# critical finding — under "too big for this session" because its class
|
|
311
326
|
# is repo-wide would repeat C4-19 in the other direction.
|
|
312
327
|
if row is not None and row.field_blocked:
|
|
328
|
+
# C3-100: an outcome is a measurement, so it is dated like one. "It did
|
|
329
|
+
# not finish" is the strongest claim this table makes about a command,
|
|
330
|
+
# and it was published undated while the field was running two of those
|
|
331
|
+
# commands in 9,8 s and 76,6 s. It still decides — an outcome at this
|
|
332
|
+
# size outranks a class, as C3-97 established for seconds — but it says
|
|
333
|
+
# which build it happened on and that nothing has re-measured it since.
|
|
334
|
+
note = field_anchor_note(row)
|
|
335
|
+
dated = ""
|
|
336
|
+
if note:
|
|
337
|
+
dated = (
|
|
338
|
+
f" on {row.field_measured_version}"
|
|
339
|
+
if row.field_measured_version
|
|
340
|
+
else " on a build the row does not record"
|
|
341
|
+
)
|
|
342
|
+
since = ", and nothing has re-measured it since" if note else ""
|
|
313
343
|
return Verdict(
|
|
314
344
|
command, DETACH,
|
|
315
345
|
(
|
|
316
346
|
f"measured at this size and it did not finish in an interactive "
|
|
317
|
-
f"session ({_files(FIELD_ANCHOR_JAVA_FILES)} Java files,
|
|
347
|
+
f"session{dated} ({_files(FIELD_ANCHOR_JAVA_FILES)} Java files, "
|
|
348
|
+
f"{row.field_cache_state} cache){since} — "
|
|
318
349
|
f"run it with `--output` and `--detach`, or nightly"
|
|
319
350
|
),
|
|
320
351
|
cls, reference,
|
|
@@ -325,7 +356,14 @@ def verdict(command: str, scope: Scope) -> Verdict:
|
|
|
325
356
|
# a measurement at this size and the class is not — but it is never
|
|
326
357
|
# printed as though it described the build in hand.
|
|
327
358
|
note = field_anchor_note(row)
|
|
328
|
-
|
|
359
|
+
# C3-100: and the cache state it was taken in. `ask --compact` is the
|
|
360
|
+
# row this matters most on — 72,3 s from a purged cache against 0,3 s
|
|
361
|
+
# warm on the reference — and the honest thing to publish is the
|
|
362
|
+
# measurement's conditions, not a warm figure nobody took at this size.
|
|
363
|
+
qualifiers = ", ".join(
|
|
364
|
+
[f"{row.field_cache_state} cache"] + ([note] if note else [])
|
|
365
|
+
)
|
|
366
|
+
dated = f" ({qualifiers})"
|
|
329
367
|
if row.field_seconds <= FOREGROUND_SECONDS:
|
|
330
368
|
return Verdict(
|
|
331
369
|
command, RUNS_NOW,
|
|
@@ -33,6 +33,9 @@ from pathlib import Path
|
|
|
33
33
|
from typing import TYPE_CHECKING, Any, Optional
|
|
34
34
|
|
|
35
35
|
from sourcecode.remedies import remedy
|
|
36
|
+
from sourcecode.security_chain import CHAIN_PARTICIPANT_TYPES as _CHAIN_PARTICIPANT_TYPES
|
|
37
|
+
from sourcecode.security_chain import simple_name as _chain_simple_name
|
|
38
|
+
from sourcecode.security_chain import types_from_edges as _chain_types_from_edges
|
|
36
39
|
|
|
37
40
|
if TYPE_CHECKING:
|
|
38
41
|
from sourcecode.canonical_ir import CanonicalRepositoryIR
|
|
@@ -478,20 +481,17 @@ _SECURITY_CONFIG_ANNOTATIONS = frozenset({
|
|
|
478
481
|
"@EnableWebSecurity", "@EnableMethodSecurity", "@EnableGlobalMethodSecurity",
|
|
479
482
|
"@EnableReactiveMethodSecurity", "@EnableWebFluxSecurity",
|
|
480
483
|
})
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
#: Edge types that say "this type IS one of those" — the inheritance half of the
|
|
488
|
-
#: request-chain SPI test.
|
|
489
|
-
_SUPERTYPE_EDGES = frozenset({"extends", "implements"})
|
|
484
|
+
#: C1-43: the request-chain SPI vocabulary is `security_chain`'s, not a second
|
|
485
|
+
#: copy here. This command asks the *participant* question — a filter takes part
|
|
486
|
+
#: in configuring the chain without declaring one — while the endpoint surface
|
|
487
|
+
#: asks the narrower declaration question. Same vocabulary, same member rule, two
|
|
488
|
+
#: named subsets.
|
|
489
|
+
_SECURITY_CONFIG_SUPERTYPES = _CHAIN_PARTICIPANT_TYPES
|
|
490
490
|
|
|
491
491
|
|
|
492
492
|
def _simple_name(type_ref: str) -> str:
|
|
493
493
|
"""`a.b.Chain<T>` → `Chain`. Generic arguments are not part of the type's name."""
|
|
494
|
-
return
|
|
494
|
+
return _chain_simple_name(type_ref)
|
|
495
495
|
|
|
496
496
|
|
|
497
497
|
def _security_config_types(cir: "CanonicalRepositoryIR") -> "frozenset[str]":
|
|
@@ -520,25 +520,12 @@ def _security_config_types(cir: "CanonicalRepositoryIR") -> "frozenset[str]":
|
|
|
520
520
|
cached = getattr(cir, "_posture_security_types", None)
|
|
521
521
|
if cached is not None:
|
|
522
522
|
return cached
|
|
523
|
-
relevant: set[str] = set()
|
|
524
523
|
raw = getattr(cir, "_raw_ir", None) or {}
|
|
525
524
|
graph = raw.get("graph") if isinstance(raw, dict) else None
|
|
526
525
|
edges = (graph or {}).get("edges") if isinstance(graph, dict) else None
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
kind = edge.get("type")
|
|
531
|
-
if kind not in _SUPERTYPE_EDGES and kind != "returns":
|
|
532
|
-
continue
|
|
533
|
-
if _simple_name(edge.get("to") or "") not in _SECURITY_CONFIG_SUPERTYPES:
|
|
534
|
-
continue
|
|
535
|
-
source = str(edge.get("from") or "")
|
|
536
|
-
if not source:
|
|
537
|
-
continue
|
|
538
|
-
# A member returning the SPI type makes its *declaring class* the
|
|
539
|
-
# configuration; a type extending it is the configuration itself.
|
|
540
|
-
relevant.add(source.partition("#")[0] if kind == "returns" else source)
|
|
541
|
-
result = frozenset(relevant)
|
|
526
|
+
# C1-43: the scan itself lives in `security_chain`, so the endpoint surface's
|
|
527
|
+
# narrower reading of the same edges cannot drift from this one.
|
|
528
|
+
result = _chain_types_from_edges(edges or [], targets=_SECURITY_CONFIG_SUPERTYPES)
|
|
542
529
|
try:
|
|
543
530
|
object.__setattr__(cir, "_posture_security_types", result)
|
|
544
531
|
except Exception:
|
|
@@ -348,15 +348,19 @@ _SECURITY_MARKER_ANNOTATIONS: frozenset[str] = frozenset({
|
|
|
348
348
|
"@PermitAll", "@DenyAll", "@Authenticated",
|
|
349
349
|
})
|
|
350
350
|
|
|
351
|
-
#
|
|
352
|
-
#
|
|
353
|
-
#
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
351
|
+
# A centralized security filter chain: when the repository declares one,
|
|
352
|
+
# per-endpoint no_security_signal is expected and does NOT mean endpoints are
|
|
353
|
+
# unprotected.
|
|
354
|
+
#: C1-43: "does this repository declare a request filter chain?" is one fact with
|
|
355
|
+
#: one reading, and it lives in `security_chain` — which is also where the reason
|
|
356
|
+
#: `@EnableMethodSecurity` is *not* in it is written down. This module used to
|
|
357
|
+
#: answer it from annotations and `extends WebSecurityConfigurerAdapter` alone,
|
|
358
|
+
#: i.e. Spring Security 5 vocabulary, while `posture` had already learned that a
|
|
359
|
+
#: chain can be a `@Bean SecurityFilterChain` and nothing else. The consequence
|
|
360
|
+
#: was not a missing signal: it was SEC-001 telling the reader that a Security 6
|
|
361
|
+
#: repository has no centralized filter, and naming a route the chain admits on
|
|
362
|
+
#: purpose as reachable without authentication.
|
|
363
|
+
from sourcecode.security_chain import declares_request_chain as _declares_request_chain
|
|
360
364
|
|
|
361
365
|
# Programmatic security: method-call patterns that indicate runtime auth enforcement.
|
|
362
366
|
# Requires method-call or field-access context — bare class name mentions (imports,
|
|
@@ -4586,16 +4590,10 @@ def _assemble(
|
|
|
4586
4590
|
# Stored here so CIR projections (project_endpoint_surface) can read it without
|
|
4587
4591
|
# re-parsing symbols.
|
|
4588
4592
|
_class_syms_asm = [s for s in sorted_syms if s.type in ("class", "interface")]
|
|
4589
|
-
_filter_based_asm = (
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
for ann in sym.annotations
|
|
4594
|
-
)
|
|
4595
|
-
or any(
|
|
4596
|
-
_extends_map.get(sym.symbol, "") == "WebSecurityConfigurerAdapter"
|
|
4597
|
-
for sym in _class_syms_asm
|
|
4598
|
-
)
|
|
4593
|
+
_filter_based_asm = _declares_request_chain(
|
|
4594
|
+
annotations=(a for sym in _class_syms_asm for a in sym.annotations),
|
|
4595
|
+
supertypes=(_extends_map.get(sym.symbol, "") for sym in _class_syms_asm),
|
|
4596
|
+
return_types=(s.return_type for s in sorted_syms if s.type == "method"),
|
|
4599
4597
|
)
|
|
4600
4598
|
# A repo whose authorization runs through its OWN annotation is not an
|
|
4601
4599
|
# unsecured repo. The `endpoints` command applied this predicate to its own
|
|
@@ -6487,18 +6485,10 @@ def extract_java_endpoints(root: Path) -> "dict[str, Any]":
|
|
|
6487
6485
|
# When present, high no_security_signal is expected — security is enforced by
|
|
6488
6486
|
# the filter chain, not per-endpoint annotations.
|
|
6489
6487
|
_class_syms = [s for s in all_symbols if s.type in ("class", "interface")]
|
|
6490
|
-
_filter_based = (
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
for sym in _class_syms
|
|
6495
|
-
for ann in sym.annotations
|
|
6496
|
-
)
|
|
6497
|
-
# Class extends WebSecurityConfigurerAdapter (pre-Spring 5.7 style)
|
|
6498
|
-
or any(
|
|
6499
|
-
extends_map.get(sym.symbol, "") == "WebSecurityConfigurerAdapter"
|
|
6500
|
-
for sym in _class_syms
|
|
6501
|
-
)
|
|
6488
|
+
_filter_based = _declares_request_chain(
|
|
6489
|
+
annotations=(a for sym in _class_syms for a in sym.annotations),
|
|
6490
|
+
supertypes=(extends_map.get(sym.symbol, "") for sym in _class_syms),
|
|
6491
|
+
return_types=(s.return_type for s in all_symbols if s.type == "method"),
|
|
6502
6492
|
)
|
|
6503
6493
|
# A repo whose authorization runs through its OWN annotation is not an
|
|
6504
6494
|
# unsecured repo. The structural gate predicate (coverage + specificity over
|