sourcecode 5.3.0__tar.gz → 5.3.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.3.0 → sourcecode-5.3.1}/CHANGELOG.md +52 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/PKG-INFO +3 -3
- {sourcecode-5.3.0 → sourcecode-5.3.1}/README.md +2 -2
- {sourcecode-5.3.0 → sourcecode-5.3.1}/pyproject.toml +1 -1
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/__init__.py +1 -1
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/audit_report.py +19 -2
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/cli.py +4 -1
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/consumer_join.py +36 -1
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/repository_ir.py +66 -39
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/ris.py +54 -8
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/runs.py +21 -2
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/summarizer.py +8 -2
- {sourcecode-5.3.0 → sourcecode-5.3.1}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/.github/workflows/perf-gate.yml +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/.gitignore +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/.ruff.toml +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/CLAUDE.md +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/CONTRIBUTING.md +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/LICENSE +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/SECURITY.md +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/raw +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/scripts/compare_integration_engines.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/scripts/customer_smoke_test.sh +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/scripts/generate_jdk_exports.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/scripts/perf_gate.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/scripts/perf_harness.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/scripts/sync_gate_anchors.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/archetype.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/architectural_baseline.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/architectural_delta.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/baseline_autocapture.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/cache.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/cache_model.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/call_surface.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/caller_metrics.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/caller_reach.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/chain_rules.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/change_plan.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/classifier.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/client_calls.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/compare.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/constraint_diff.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/container_wiring.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/context_cache.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/context_graph.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/contract_diff.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/contract_init.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/data_exposure.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/data_labels.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/declarations.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/defect_identity.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/degradation.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/deployment_prefix.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detach.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/dynamic_argument_surface.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/endpoint_literals.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/endpoint_metrics.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/envelope.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/environment_resolution.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/evidence_provider.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/execution_plan.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/explain.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/facts/__init__.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/facts/registry.json +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/filter_surface.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/format_contract.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/gate_anchors.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/git_checkout.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/graph_evidence.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/hibernate_strat.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/identity_fallback.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/integration_coordinates.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/jdk_exports.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/license.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/mcp/dependency_import.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/migrate_check.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/migration_blast.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/non_coverage.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/openrewrite_recipe.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/output_encoding.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/parallel.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/parse_cache.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/partial_contract.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/path_admission.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/perf.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/phased_run.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/pipe_contract.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/posture.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/progress.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/provenance.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/readiness_timeline.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/readonly.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/reconciliation.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/redactor.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/reference_facts.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/release_info.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/remedies.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/__init__.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/context.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/errors.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/executor.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/planner.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/query.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/request.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/resolution.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/result.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/retriever.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/runtime.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/steps.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/steps_graph.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/steps_impact.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/steps_intf.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/steps_struct.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/retrieval/steps_txsec.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/risk.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/rule_catalog.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/rule_pass.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/sarif.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/scanner.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/schema.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/security_chain.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/security_config.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/security_config_scan.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/security_posture.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/semantic_impact_engine.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/semantic_integration_engine.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/semantic_services.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/serializer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/servlet_surface.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/source_text.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/spring_findings.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/spring_impact.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/spring_profiles.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/spring_properties.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/spring_security_audit.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/spring_tx_analyzer.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/sql_taint.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/target_admission.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/test_gap_ranking.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/test_sources.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/text_input.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/timeline.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/token_estimate.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/type_usage_surface.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/validation_inference.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/validation_surface.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/verify_edit.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/verify_repo.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/verify_rules.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/version_check.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/waivers.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/src/sourcecode/workspace.py +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/supabase/functions/README.md +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/supabase/sql/licensing_schema.sql +0 -0
- {sourcecode-5.3.0 → sourcecode-5.3.1}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -2,6 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.3.1] — 2026-08-11
|
|
6
|
+
|
|
7
|
+
**Six fixes from one field battery.** 5.3.0 was run over the 14 repositories in
|
|
8
|
+
the field corpus — 22 commands each, plus the symbol-level commands and the
|
|
9
|
+
edge-input battery. No command crashed on its own account: every non-zero exit
|
|
10
|
+
was a well-formed input error. What the battery found instead is the class this
|
|
11
|
+
series keeps returning to — two surfaces answering one question with two
|
|
12
|
+
numbers, and a count published under the name of a population it does not count.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- **One admission authority for the route population.** `extract_java_endpoints`
|
|
16
|
+
filtered its Java files with `is_test_path` alone, while `find_java_files` —
|
|
17
|
+
which feeds the IR and therefore `spring-audit`, `impact`, `validation` and
|
|
18
|
+
`data-exposure` — also drops the `src/main` of a module that is itself test
|
|
19
|
+
infrastructure. Measured on jobrunr: `endpoints` published 3 annotation routes
|
|
20
|
+
from `quarkus-jobrunr-tests` that `spring-audit` could not see at all, 3
|
|
21
|
+
against `endpoints_analyzed: 0`, under the payload's own
|
|
22
|
+
`semantic_model_endpoints_note` declaring the two counts to be one figure. The
|
|
23
|
+
rule is now `repository_ir.is_test_source_file`, called by both builders
|
|
24
|
+
(jobrunr 14/3 → 12/0; every other repository in the corpus unchanged).
|
|
25
|
+
- **A call site is an HTTP call only where an HTTP client is.** The Java
|
|
26
|
+
consumer-join matcher admitted `<receiver>.put|patch|delete|exchange("…")` on
|
|
27
|
+
any receiver — HTTP verbs, and three of the most common method names in Java.
|
|
28
|
+
Measured on eureka joined against open-banking-gateway: all 20 rows of
|
|
29
|
+
`calls_unresolved` were `Map.put` literals in one file, and a
|
|
30
|
+
`map.put("/x", v)` would have been published as a consumer calling `/x` — the
|
|
31
|
+
direction the module declares decisive. A file must now import or declare an
|
|
32
|
+
HTTP client type before its call sites are read.
|
|
33
|
+
- **A snapshot that measured nothing reports unknown, not zero.**
|
|
34
|
+
`update_ris_api_surface` / `update_ris_spring_audit` write a stub snapshot so
|
|
35
|
+
their own section survives when no full one exists; `cold-start` read that stub
|
|
36
|
+
as a measurement. On alfresco-community-repo — 7 000+ Java files, 901
|
|
37
|
+
WebScripts — it answered `validation: {spring_detected: false,
|
|
38
|
+
controllers_found: 0, status: "valid"}` with every section empty. Now
|
|
39
|
+
`status: cold_start_incomplete`, `validation.status: empty_snapshot`, every
|
|
40
|
+
count `null`, with a statement naming what is unknown and how to build the
|
|
41
|
+
snapshot. A repository measured to have no Spring surface still reports its
|
|
42
|
+
zeroes — that is a fact.
|
|
43
|
+
- **The scale signal counts files, and says files.** The headline sentence of
|
|
44
|
+
every Java summary ended with "N Java classes" while counting `.java` paths.
|
|
45
|
+
BroadleafCommerce is 2 659 Java files and 3 032 declared types, so the label
|
|
46
|
+
contradicted `repo-ir.analysis_meta.classes` in the same run.
|
|
47
|
+
- **The human audit bundle prints counts, not Python objects.** The two
|
|
48
|
+
breakdown lines of the markdown report interpolated their dicts directly, so
|
|
49
|
+
the signed evidence bundle published `- Endpoint access: {'no_rule_matched':
|
|
50
|
+
676}` on keycloak, and a literal `None` for a section that was never measured.
|
|
51
|
+
- **Bookkeeping never takes down a finished analysis.** `RunRecord.write` had no
|
|
52
|
+
guard on its terminal write, so a run directory that disappeared during the
|
|
53
|
+
analysis — a concurrent `ask cache clear`, a tmp reaper, an evicted cache —
|
|
54
|
+
raised `FileNotFoundError` out of the analysis scope's exit. Observed on
|
|
55
|
+
`audit-report`, which died with a traceback having already composed the report.
|
|
56
|
+
|
|
5
57
|
## [5.3.0] — 2026-08-11
|
|
6
58
|
|
|
7
59
|
**The capability queue, built on the stable point.** 5.2.0 was the highest-scored
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 5.3.
|
|
3
|
+
Version: 5.3.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.3.
|
|
129
|
+
ask version # ask 5.3.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.3.
|
|
91
|
+
ask version # ask 5.3.1 — and, on a build that has aged,
|
|
92
92
|
# how many releases have probably shipped since
|
|
93
93
|
```
|
|
94
94
|
|
|
@@ -147,6 +147,23 @@ def build_audit_report(
|
|
|
147
147
|
return normalized
|
|
148
148
|
|
|
149
149
|
|
|
150
|
+
def _render_breakdown(value: Any) -> str:
|
|
151
|
+
"""A count-per-class map, written the way a reader of a report reads one.
|
|
152
|
+
|
|
153
|
+
The two breakdown lines were interpolated as Python objects, so the signed
|
|
154
|
+
human bundle published `{'no_rule_matched': 676}` on keycloak — and a literal
|
|
155
|
+
`None` for a section that was not measured at all, which is the one thing a
|
|
156
|
+
report of record must never say when it means "not measured".
|
|
157
|
+
"""
|
|
158
|
+
if value is None:
|
|
159
|
+
return "not measured"
|
|
160
|
+
if isinstance(value, dict):
|
|
161
|
+
if not value:
|
|
162
|
+
return "none reported"
|
|
163
|
+
return ", ".join(f"`{k}` {v}" for k, v in sorted(value.items()))
|
|
164
|
+
return f"`{value}`"
|
|
165
|
+
|
|
166
|
+
|
|
150
167
|
def render_markdown(report: dict[str, Any]) -> str:
|
|
151
168
|
"""Human report renderer over the JSON contract."""
|
|
152
169
|
summary = report.get("summary") or {}
|
|
@@ -160,8 +177,8 @@ def render_markdown(report: dict[str, Any]) -> str:
|
|
|
160
177
|
f"- Profile set: `{profile}`",
|
|
161
178
|
f"- Total defects: `{read_count(summary, 'total_defects')}`"
|
|
162
179
|
+ (" **(floor — this run was cut short)**" if summary.get("partial") else ""),
|
|
163
|
-
f"- Risk bands:
|
|
164
|
-
f"- Endpoint access:
|
|
180
|
+
f"- Risk bands: {_render_breakdown(summary.get('risk_bands'))}",
|
|
181
|
+
f"- Endpoint access: {_render_breakdown(summary.get('endpoint_access'))}",
|
|
165
182
|
"",
|
|
166
183
|
"## Top Risks",
|
|
167
184
|
"",
|
|
@@ -13240,7 +13240,10 @@ def cold_start_cmd(
|
|
|
13240
13240
|
"""Output Repository Intelligence Snapshot bootstrap context as JSON.
|
|
13241
13241
|
|
|
13242
13242
|
Returns instantly from persisted RIS — zero re-analysis cost.
|
|
13243
|
-
status: cold_start_ready | cold_start_stale | no_ris
|
|
13243
|
+
status: cold_start_ready | cold_start_stale | cold_start_incomplete | no_ris
|
|
13244
|
+
`cold_start_incomplete` means the snapshot is missing sections (or holds no
|
|
13245
|
+
measurement at all — `validation.status: empty_snapshot`, every count
|
|
13246
|
+
`null`): unknown, never zero.
|
|
13244
13247
|
|
|
13245
13248
|
\b
|
|
13246
13249
|
Note: Full output is large (~100K–200K tokens for medium repos).
|
|
@@ -71,6 +71,38 @@ _METHOD_ATTR = re.compile(r"RequestMethod\.(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIO
|
|
|
71
71
|
#: annotation-shaped path on a server controller is a route, not a call.
|
|
72
72
|
_DECLARATIVE_CLIENT = re.compile(r"@(\w*FeignClient|HttpExchange|RegisterRestClient)\b")
|
|
73
73
|
|
|
74
|
+
#: `put`, `patch` and `delete` are HTTP verbs and they are also three of the most
|
|
75
|
+
#: common method names in Java: `map.put("us-east-1", "us-east-1a")` matches the
|
|
76
|
+
#: call shape exactly. Measured on eureka, joined against open-banking-gateway:
|
|
77
|
+
#: all 20 "unresolved client calls" were `Map.put` literals in
|
|
78
|
+
#: `AbstractAzToRegionMapper`, and a `map.put("/x", v)` would have been published
|
|
79
|
+
#: as a real consumer call to `/x` — the direction this module declares decisive.
|
|
80
|
+
#: So the shape alone does not admit a call site: the FILE must carry evidence
|
|
81
|
+
#: that an HTTP client is in it. These are the published type names of the HTTP
|
|
82
|
+
#: client libraries themselves, matched as a declaration or an import — evidence,
|
|
83
|
+
#: never a rule about the calling code's own naming.
|
|
84
|
+
_HTTP_CLIENT_TYPE = re.compile(
|
|
85
|
+
r"\b(?:Async|Test|OAuth2)?RestTemplate\b"
|
|
86
|
+
r"|\bWeb(?:Test)?Client\b"
|
|
87
|
+
r"|\bRestClient\b"
|
|
88
|
+
r"|\bOkHttpClient\b"
|
|
89
|
+
r"|\bHttpClient\b"
|
|
90
|
+
r"|\bClientHttpRequest\w*\b"
|
|
91
|
+
r"|\bResteasyClient\b"
|
|
92
|
+
r"|\bjakarta\.ws\.rs\.client\b|\bjavax\.ws\.rs\.client\b"
|
|
93
|
+
r"|\bWebResource\b|\bWebTarget\b"
|
|
94
|
+
r"|\bRequestSpecification\b" # rest-assured
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _file_declares_http_client(text: str) -> bool:
|
|
99
|
+
"""True when this file imports or declares a type that speaks HTTP as a client.
|
|
100
|
+
|
|
101
|
+
A file with no such type has no `restTemplate` to call, so a `.put("…")` in it
|
|
102
|
+
is some other API with the same method name.
|
|
103
|
+
"""
|
|
104
|
+
return bool(_HTTP_CLIENT_TYPE.search(text) or _DECLARATIVE_CLIENT.search(text))
|
|
105
|
+
|
|
74
106
|
_JAVA_SKIP_DIRS = frozenset({
|
|
75
107
|
"target", "build", "out", ".git", "node_modules", ".gradle",
|
|
76
108
|
})
|
|
@@ -103,7 +135,10 @@ def extract_java_client_calls(base: Path) -> "tuple[list[ClientCall], list[dict]
|
|
|
103
135
|
except OSError:
|
|
104
136
|
continue
|
|
105
137
|
rel = path.relative_to(base).as_posix()
|
|
106
|
-
|
|
138
|
+
_http_client_file = _file_declares_http_client(text)
|
|
139
|
+
for match in (
|
|
140
|
+
_JAVA_TEMPLATE_CALL.finditer(text) if _http_client_file else ()
|
|
141
|
+
):
|
|
107
142
|
op = match.group("op").lower()
|
|
108
143
|
verb = next((v for k, v in _VERB_FROM_OP.items() if op.startswith(k)), "")
|
|
109
144
|
if not verb and op == "exchange":
|
|
@@ -6173,6 +6173,56 @@ def _recover_openapi_spec_routes(
|
|
|
6173
6173
|
_SEMANTIC_MODEL_ENDPOINT_SOURCES: frozenset[str] = frozenset({"annotation", "openapi-spec"})
|
|
6174
6174
|
|
|
6175
6175
|
|
|
6176
|
+
def is_test_source_file(rel_path: str) -> bool:
|
|
6177
|
+
"""Return True when *rel_path* is a test source and must not enter any surface.
|
|
6178
|
+
|
|
6179
|
+
One authority for the question both Java file-list builders ask —
|
|
6180
|
+
`find_java_files` (which feeds the IR and therefore every CIR consumer:
|
|
6181
|
+
spring-audit, impact, validation, data-exposure) and
|
|
6182
|
+
`extract_java_endpoints` (which feeds the `endpoints` command). They asked it
|
|
6183
|
+
separately until a field run on jobrunr made the divergence visible:
|
|
6184
|
+
`endpoints` published 3 annotation routes from
|
|
6185
|
+
`quarkus-jobrunr-tests/src/main/java/org/jobrunr/quarkus/it/` that
|
|
6186
|
+
`spring-audit` could not see at all, while the payload's own
|
|
6187
|
+
`semantic_model_endpoints_note` claims the two counts are the same figure —
|
|
6188
|
+
3 against `endpoints_analyzed: 0`.
|
|
6189
|
+
|
|
6190
|
+
Two facts, and C1-28 is why they are written as two.
|
|
6191
|
+
`is_test_path` answers "is this file a test source"; since the authority took
|
|
6192
|
+
over it never fires inside a declared main source root, which is correct
|
|
6193
|
+
everywhere except inside a module that is itself test infrastructure — a
|
|
6194
|
+
`test-framework` module has no product for its `src/main` to belong to. There
|
|
6195
|
+
the weaker question is the right one: does this file look like a test by name
|
|
6196
|
+
or by package. Both come from the one authority, so this stays a composition
|
|
6197
|
+
of published facts rather than a third rule.
|
|
6198
|
+
|
|
6199
|
+
A test *fixture* module (`*-test-utils`) is deliberately NOT excluded here:
|
|
6200
|
+
its endpoints are kept as raw evidence and tagged `scope: test_util`
|
|
6201
|
+
downstream, by both surfaces.
|
|
6202
|
+
"""
|
|
6203
|
+
rel = rel_path.replace("\\", "/").lstrip("/")
|
|
6204
|
+
if _is_test_path(rel):
|
|
6205
|
+
return True
|
|
6206
|
+
_rel_sl = "/" + rel # leading slash: the check below is prefix-safe
|
|
6207
|
+
if "/src/main/" in _rel_sl and _matches_test_naming(rel):
|
|
6208
|
+
_prefix = _rel_sl.split("/src/main/")[0]
|
|
6209
|
+
_prefix_parts = [p for p in _prefix.split("/") if p]
|
|
6210
|
+
# A module is a test module if is_test_path says so OR if any module
|
|
6211
|
+
# directory component starts with "test" (e.g. "test-framework",
|
|
6212
|
+
# "test-providers", "testsuite") OR contains "test"/"tests" as a
|
|
6213
|
+
# hyphen/underscore-separated word (e.g. "jobrunr-micronaut-tests").
|
|
6214
|
+
return (
|
|
6215
|
+
_is_test_path(_prefix + "/x.java")
|
|
6216
|
+
or any(p.lower().startswith("test") for p in _prefix_parts)
|
|
6217
|
+
or any(
|
|
6218
|
+
w in {"test", "tests", "spec", "specs"}
|
|
6219
|
+
for p in _prefix_parts
|
|
6220
|
+
for w in p.lower().replace("-", " ").replace("_", " ").split()
|
|
6221
|
+
)
|
|
6222
|
+
)
|
|
6223
|
+
return False
|
|
6224
|
+
|
|
6225
|
+
|
|
6176
6226
|
# ---------------------------------------------------------------------------
|
|
6177
6227
|
# Convenience: find Java files in a repo
|
|
6178
6228
|
# ---------------------------------------------------------------------------
|
|
@@ -6190,7 +6240,7 @@ def extract_java_endpoints(root: Path) -> "dict[str, Any]":
|
|
|
6190
6240
|
"""
|
|
6191
6241
|
import re as _re
|
|
6192
6242
|
from typing import Any as _Any
|
|
6193
|
-
from sourcecode.path_filters import
|
|
6243
|
+
from sourcecode.path_filters import is_test_fixture_module_path
|
|
6194
6244
|
|
|
6195
6245
|
_EXTENDS_FROM_SIG = _re.compile(r'\bextends\s+(\w+)')
|
|
6196
6246
|
|
|
@@ -6210,9 +6260,20 @@ def extract_java_endpoints(root: Path) -> "dict[str, Any]":
|
|
|
6210
6260
|
_CLIENT_PATH_FRAGMENTS = (
|
|
6211
6261
|
"/admin-client/", "/rest-client/", "/client-api/", "/api-client/",
|
|
6212
6262
|
)
|
|
6263
|
+
# Admission is `is_test_source_file`, the same authority `find_java_files`
|
|
6264
|
+
# uses, so this command's route population and the IR's cannot diverge:
|
|
6265
|
+
# `is_test_path` alone let a test MODULE's `src/main` resources through here
|
|
6266
|
+
# while the IR dropped them, and the two published counts then contradicted
|
|
6267
|
+
# each other (jobrunr: 3 annotation routes vs `endpoints_analyzed: 0`).
|
|
6268
|
+
def _rel(p: Path) -> str:
|
|
6269
|
+
try:
|
|
6270
|
+
return str(p.relative_to(root)).replace("\\", "/")
|
|
6271
|
+
except ValueError:
|
|
6272
|
+
return str(p).replace("\\", "/")
|
|
6273
|
+
|
|
6213
6274
|
java_files = sorted(
|
|
6214
6275
|
p for p in root.rglob("*.java")
|
|
6215
|
-
if not
|
|
6276
|
+
if not is_test_source_file(_rel(p))
|
|
6216
6277
|
and "target/" not in str(p).replace("\\", "/")
|
|
6217
6278
|
and not any(f in str(p).replace("\\", "/") for f in _CLIENT_PATH_FRAGMENTS)
|
|
6218
6279
|
)
|
|
@@ -6841,43 +6902,9 @@ def find_java_files(
|
|
|
6841
6902
|
except ValueError:
|
|
6842
6903
|
continue
|
|
6843
6904
|
parts = rel.split("/")
|
|
6844
|
-
# Skip test dirs —
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
if not include_tests:
|
|
6848
|
-
# Two facts, and C1-28 is why they are now written as two.
|
|
6849
|
-
# `is_test_path` answers "is this file a test source"; since the
|
|
6850
|
-
# authority took over it never fires inside a declared main source
|
|
6851
|
-
# root, which is correct everywhere except inside a module that is
|
|
6852
|
-
# itself test infrastructure — a `test-framework` module has no
|
|
6853
|
-
# product for its `src/main` to belong to. There the weaker question
|
|
6854
|
-
# is the right one: does this file look like a test by name or by
|
|
6855
|
-
# package. Both come from the one authority, so this stays a
|
|
6856
|
-
# composition of published facts rather than a third rule. A test
|
|
6857
|
-
# *fixture* module (`*-test-utils`) is deliberately NOT excluded
|
|
6858
|
-
# here: its endpoints are kept as raw evidence and tagged
|
|
6859
|
-
# `scope: test_util` downstream.
|
|
6860
|
-
_rel_sl = "/" + rel # leading slash: the checks below are prefix-safe
|
|
6861
|
-
if _is_test_path(rel):
|
|
6862
|
-
continue
|
|
6863
|
-
if "/src/main/" in _rel_sl and _matches_test_naming(rel):
|
|
6864
|
-
_prefix = _rel_sl.split("/src/main/")[0]
|
|
6865
|
-
_prefix_parts = [p for p in _prefix.split("/") if p]
|
|
6866
|
-
# A module is a test module if is_test_path says so OR if any
|
|
6867
|
-
# module directory component starts with "test" (e.g. "test-framework",
|
|
6868
|
-
# "test-providers", "testsuite") OR contains "test"/"tests" as a
|
|
6869
|
-
# hyphen/underscore-separated word (e.g. "jobrunr-micronaut-tests").
|
|
6870
|
-
_prefix_is_test = (
|
|
6871
|
-
_is_test_path(_prefix + "/x.java")
|
|
6872
|
-
or any(p.lower().startswith("test") for p in _prefix_parts)
|
|
6873
|
-
or any(
|
|
6874
|
-
w in {"test", "tests", "spec", "specs"}
|
|
6875
|
-
for p in _prefix_parts
|
|
6876
|
-
for w in p.lower().replace("-", " ").replace("_", " ").split()
|
|
6877
|
-
)
|
|
6878
|
-
)
|
|
6879
|
-
if _prefix_is_test:
|
|
6880
|
-
continue
|
|
6905
|
+
# Skip test dirs — one authority, shared with extract_java_endpoints.
|
|
6906
|
+
if not include_tests and is_test_source_file(rel):
|
|
6907
|
+
continue
|
|
6881
6908
|
# Skip vendor/generated/build dirs
|
|
6882
6909
|
if any(part in _VENDOR_DIRS for part in parts[:-1]):
|
|
6883
6910
|
continue
|
|
@@ -484,6 +484,20 @@ def _has_uncommitted_changes(repo_root: Path) -> bool:
|
|
|
484
484
|
return bool(worktree_dirty(root, ignore=own))
|
|
485
485
|
|
|
486
486
|
|
|
487
|
+
def _compact_probe(section: object) -> bool:
|
|
488
|
+
"""True when an RIS section holds something a reader could act on.
|
|
489
|
+
|
|
490
|
+
A stub writes `{"endpoints": [], "controllers_index": []}` — a truthy dict
|
|
491
|
+
that contains no measurement, so the section's emptiness has to be asked of
|
|
492
|
+
its values, not of the container.
|
|
493
|
+
"""
|
|
494
|
+
if isinstance(section, dict):
|
|
495
|
+
return any(_compact_probe(v) for v in section.values())
|
|
496
|
+
if isinstance(section, (list, tuple, set)):
|
|
497
|
+
return bool(section)
|
|
498
|
+
return section not in (None, "", 0, False)
|
|
499
|
+
|
|
500
|
+
|
|
487
501
|
def get_cold_start_context(repo_root: Path) -> dict:
|
|
488
502
|
"""Return a lightweight bootstrap object from the persisted RIS.
|
|
489
503
|
|
|
@@ -527,22 +541,54 @@ def get_cold_start_context(repo_root: Path) -> dict:
|
|
|
527
541
|
_endpoints_found = len(endpoints)
|
|
528
542
|
# Spring is detected when controllers exist in structural map or api surface.
|
|
529
543
|
_spring_detected = bool(_controllers_found) or bool(_controllers_in_api)
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
544
|
+
# A stub snapshot measured nothing. `update_ris_api_surface` /
|
|
545
|
+
# `update_ris_spring_audit` write one (`partial: True`, `confidence: 0.0`,
|
|
546
|
+
# `git_head: ""`) so their own section survives when no full snapshot
|
|
547
|
+
# exists yet — and on a repository whose Spring surface is genuinely
|
|
548
|
+
# empty, that stub is all there is. Measured on
|
|
549
|
+
# alfresco-community-repo (7 000+ Java files, 901 WebScripts): every
|
|
550
|
+
# section empty, and `validation: {spring_detected: false,
|
|
551
|
+
# controllers_found: 0, status: "valid"}` — an answer a bootstrapping
|
|
552
|
+
# agent reads as "this repository has no controllers and no entry
|
|
553
|
+
# points". Nothing was measured, so nothing is being reported: the
|
|
554
|
+
# sections are unknown, not zero.
|
|
555
|
+
_nothing_measured = not (
|
|
556
|
+
_compact_probe(ris.compact_summary)
|
|
557
|
+
or _compact_probe(ris.structural_map)
|
|
558
|
+
or _controllers_found
|
|
559
|
+
or _endpoints_found
|
|
560
|
+
or _compact_probe(ris.git_context_snapshot)
|
|
534
561
|
)
|
|
562
|
+
if _nothing_measured:
|
|
563
|
+
_validation_status = "empty_snapshot"
|
|
564
|
+
elif _is_java and _spring_detected and _endpoints_found == 0:
|
|
565
|
+
_validation_status = "incomplete_snapshot"
|
|
566
|
+
else:
|
|
567
|
+
_validation_status = "valid"
|
|
535
568
|
_validation: dict = {
|
|
536
|
-
"spring_detected": _spring_detected,
|
|
537
|
-
"controllers_found": _controllers_found,
|
|
538
|
-
"endpoints_found": _endpoints_found,
|
|
569
|
+
"spring_detected": None if _nothing_measured else _spring_detected,
|
|
570
|
+
"controllers_found": None if _nothing_measured else _controllers_found,
|
|
571
|
+
"endpoints_found": None if _nothing_measured else _endpoints_found,
|
|
539
572
|
"status": _validation_status,
|
|
540
573
|
}
|
|
574
|
+
if _nothing_measured:
|
|
575
|
+
_validation["statement"] = (
|
|
576
|
+
"This snapshot holds no measurement: it was written by a command "
|
|
577
|
+
"that persisted its own section only. Every field above is unknown "
|
|
578
|
+
"— not zero, and not evidence that the repository has no controllers, "
|
|
579
|
+
"endpoints or entry points. Build one with `ask cache warm <path>` "
|
|
580
|
+
"(or any analysis command) and re-run."
|
|
581
|
+
)
|
|
541
582
|
|
|
542
583
|
# When the snapshot is structurally incomplete, downgrade status so agents
|
|
543
584
|
# don't assume cold_start_ready when critical sections are missing.
|
|
544
585
|
_status_base = "cold_start_stale" if stale else "cold_start_ready"
|
|
545
|
-
if _validation_status
|
|
586
|
+
if _validation_status in ("incomplete_snapshot", "empty_snapshot") and not stale:
|
|
587
|
+
_status_base = "cold_start_incomplete"
|
|
588
|
+
if _validation_status == "empty_snapshot":
|
|
589
|
+
# A stub carries no head, so the staleness comparison it loses is not
|
|
590
|
+
# the fact worth reporting: `cold_start_stale` would send a reader to
|
|
591
|
+
# re-run against a newer tree, when what is missing is the snapshot.
|
|
546
592
|
_status_base = "cold_start_incomplete"
|
|
547
593
|
|
|
548
594
|
_compact = ris.compact_summary or {}
|
|
@@ -119,9 +119,28 @@ class RunRecord:
|
|
|
119
119
|
payload["output_size_bytes"] = output_size
|
|
120
120
|
if error:
|
|
121
121
|
payload["error"] = error
|
|
122
|
+
# Bookkeeping never takes down an answer. `RunRecord.create` already
|
|
123
|
+
# treats an unwritable directory as "no record"; the terminal write did
|
|
124
|
+
# not, so a run directory that disappeared *during* the analysis — a
|
|
125
|
+
# concurrent `ask cache clear`, a tmp reaper, an evicted cache — raised
|
|
126
|
+
# FileNotFoundError out of the `_expensive_analysis_scope` exit, after the
|
|
127
|
+
# analysis had completed. Observed: `ask audit-report` on langchain4j died
|
|
128
|
+
# with a traceback over a missing `runs/<id>.tmp`, having already built
|
|
129
|
+
# the report. The record is recovery metadata; the answer is the product.
|
|
130
|
+
blob = json.dumps(payload, indent=2, sort_keys=True)
|
|
122
131
|
tmp = self.path.with_suffix(".tmp")
|
|
123
|
-
|
|
124
|
-
|
|
132
|
+
for attempt in (0, 1):
|
|
133
|
+
try:
|
|
134
|
+
tmp.write_text(blob, encoding="utf-8")
|
|
135
|
+
tmp.replace(self.path)
|
|
136
|
+
return
|
|
137
|
+
except OSError:
|
|
138
|
+
if attempt:
|
|
139
|
+
return
|
|
140
|
+
try:
|
|
141
|
+
self.path.parent.mkdir(parents=True, exist_ok=True)
|
|
142
|
+
except OSError:
|
|
143
|
+
return
|
|
125
144
|
|
|
126
145
|
|
|
127
146
|
def classify_run(path: Path) -> dict[str, Any]:
|
|
@@ -389,14 +389,20 @@ class ProjectSummarizer:
|
|
|
389
389
|
parts.append(f"Domains: {', '.join(domains)}")
|
|
390
390
|
|
|
391
391
|
# Quantitative structural suffix for Java projects — adds concrete scale signals
|
|
392
|
-
# that README descriptions omit (
|
|
392
|
+
# that README descriptions omit (file count, transactional boundary count).
|
|
393
393
|
if primary is not None and primary.stack.lower() == "java":
|
|
394
394
|
quant_parts: list[str] = []
|
|
395
395
|
java_files = sum(
|
|
396
396
|
1 for p in sm.file_paths if p.endswith(".java")
|
|
397
397
|
)
|
|
398
398
|
if java_files >= 50:
|
|
399
|
-
|
|
399
|
+
# This counts files, and says so. It read "N Java classes" — the
|
|
400
|
+
# headline sentence of every summary, naming a population the tool
|
|
401
|
+
# measures separately and differently: BroadleafCommerce is 2 659
|
|
402
|
+
# Java files and 3 032 declared types (2 174 classes, 742
|
|
403
|
+
# interfaces), so the label was wrong by a nested type per file
|
|
404
|
+
# and contradicted `repo-ir.analysis_meta.classes`.
|
|
405
|
+
quant_parts.append(f"{java_files:,} Java files")
|
|
400
406
|
txn_classes: list[str] = []
|
|
401
407
|
for stack in non_tooling_stacks:
|
|
402
408
|
txn_classes.extend(getattr(stack, "transactional_classes", []))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|