sourcecode 5.4.2__tar.gz → 5.5.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.4.2 → sourcecode-5.5.1}/CHANGELOG.md +49 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/PKG-INFO +3 -3
- {sourcecode-5.4.2 → sourcecode-5.5.1}/README.md +2 -2
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/USER_GUIDE.md +1 -1
- {sourcecode-5.4.2 → sourcecode-5.5.1}/pyproject.toml +1 -1
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/__init__.py +1 -1
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/cache_model.py +9 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/cli.py +71 -7
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/non_coverage.py +21 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/reference_facts.py +51 -11
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/release_info.py +1 -1
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/repository_ir.py +54 -11
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/validation_surface.py +85 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/.github/workflows/perf-gate.yml +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/.gitignore +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/.ruff.toml +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/CLAUDE.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/CONTRIBUTING.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/LICENSE +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/SECURITY.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/CACHE.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/COMMERCIAL-OFFER.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/CUSTOMER-VALIDATION.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/DEFECT-LEDGER.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/DEMO-5MIN.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/DEVELOPMENT-ROADMAP.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/EXECUTION-PLAN-12MO.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/EXECUTIVE-ROADMAP.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/MANUAL-USUARIO.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/MODERNIZATION.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/PRODUCT_AUDIT.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/PRODUCT_IDENTITY.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/PRODUCT_TIERS.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/RC1-CHECKLIST.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/RELEASE-CHECKLIST.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/CATALOG-retrieval-intents.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/DESIGN-knowledge-provider-integration.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/DESIGN-p5.3b-statement-surface.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/DESIGN-p5.5-span-index.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/DESIGN-p6-semantic-impact-engine.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/DESIGN-p6-semantic-integration-engine.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/DESIGN-p7-semantic-services.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/DESIGN-robustness-security-inference.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/DESIGN-semantic-retrieval.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/EPV-p6-class-typeref.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/REPORT-p6-flow-analyzer-comparison.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/REPORT-p6-integration-detector-comparison.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/REPORT-p8-flow-analyzer-migration.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/REPORT-p9-integration-detector-migration.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/adr/0001-semantic-ir.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/adr/0002-source-evidence-boundary.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/adr/0003-architectural-characterization.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/adr/0004-semantic-retrieval.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/adr/0005-evidence-reconciliation.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/adr/0006-performance-harness.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/adr/0007-composition-semantics.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/adr/0008-answer-coherence.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/consumer-disposition-inventory.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/overview.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/product-architecture-review.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/product-strategy-layering.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/semantic-ir-consumer-matrix.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/architecture/semantic-ir-roadmap.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/baseline-ci.yml +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/commercial-pipeline-audit.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/contracts-ci.yml +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/contracts.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/eval/2026-06-15-petclinic-rest-issue11-vets-pagination.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/eval/2026-06-15-petclinic-rest-issue147-validation.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/eval/2026-06-15-petclinic-rest-workflow.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/eval/2026-06-15-phase18-openapi-surface.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/eval/2026-06-15-phase20-validation-surface.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/eval/2026-06-16-broadleaf-checkout-impact-fieldtest.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/eval/2026-06-16-petclinic-rest-issue11-weakness2-closed.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/eval/2026-06-16-spring-petclinic-issue2333-dead-vets.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/licensing-schema.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/migrate-check.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/README.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/REGRESSION-GATE.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/SUMMARY.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/alfresco__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/alfresco__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/broadleaf__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/broadleaf__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/eureka__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/eureka__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/jenkins__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/jenkins__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/jobrunr__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/jobrunr__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/keycloak__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/keycloak__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/neo4j__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/neo4j__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/ofbiz__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/ofbiz__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/openmrs__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/openmrs__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/petclinic__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.15/petclinic__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/SUMMARY.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/alfresco__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/alfresco__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/broadleaf__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/broadleaf__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/eureka__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/eureka__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/jenkins__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/jenkins__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/jobrunr__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/jobrunr__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/keycloak__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/keycloak__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/neo4j__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/neo4j__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/ofbiz__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/ofbiz__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/openmrs__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/openmrs__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/petclinic__ask__cold.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/2.5.16/petclinic__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/gate-latest/README.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/gate-latest/broadleaf__ask__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/gate-latest/broadleaf__endpoints__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/gate-latest/broadleaf__migrate-check__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/gate-latest/broadleaf__posture__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/gate-latest/broadleaf__spring-audit__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/gate-latest/broadleaf__validation__warm.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/perf/baselines/reference-best/README.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/posture.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/privacy.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/pro-experience-audit.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/schema.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/spec/envelope-v1.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/docs/spring-audit-ci.yml +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/raw +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/scripts/compare_integration_engines.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/scripts/customer_smoke_test.sh +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/scripts/generate_jdk_exports.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/scripts/perf_gate.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/scripts/perf_harness.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/scripts/sync_gate_anchors.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/archetype.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/architectural_baseline.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/architectural_delta.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/audit_report.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/baseline_autocapture.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/bundled_docs.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/cache.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/call_surface.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/caller_metrics.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/caller_reach.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/chain_rules.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/change_plan.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/classifier.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/client_calls.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/compare.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/constraint_diff.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/consumer_join.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/container_wiring.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/context_cache.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/context_graph.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/contract_diff.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/contract_init.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/data_exposure.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/data_labels.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/declarations.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/defect_identity.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/degradation.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/deployment_prefix.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detach.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/dynamic_argument_surface.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/endpoint_literals.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/endpoint_metrics.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/envelope.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/environment_resolution.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/evidence_provider.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/execution_plan.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/explain.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/facts/__init__.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/facts/registry.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/filter_surface.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/format_contract.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/gate_anchors.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/git_checkout.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/graph_evidence.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/hibernate_strat.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/identity_fallback.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/integration_coordinates.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/jdk_exports.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/license.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/mcp/dependency_import.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/migrate_check.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/migration_blast.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/openrewrite_recipe.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/output_encoding.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/parallel.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/parse_cache.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/partial_contract.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/path_admission.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/perf.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/phased_run.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/pipe_contract.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/posture.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/progress.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/provenance.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/readiness_timeline.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/readonly.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/reconciliation.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/redactor.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/remedies.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/__init__.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/context.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/errors.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/executor.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/planner.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/query.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/request.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/resolution.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/result.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/retriever.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/runtime.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/steps.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/steps_graph.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/steps_impact.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/steps_intf.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/steps_struct.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/retrieval/steps_txsec.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/ris.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/risk.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/rule_catalog.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/rule_pass.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/runs.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/sarif.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/scanner.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/schema.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/security_chain.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/security_config.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/security_config_scan.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/security_posture.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/semantic_impact_engine.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/semantic_integration_engine.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/semantic_services.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/serializer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/servlet_surface.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/source_text.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/spring_findings.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/spring_impact.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/spring_profiles.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/spring_properties.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/spring_security_audit.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/spring_tx_analyzer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/sql_taint.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/target_admission.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/test_gap_ranking.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/test_sources.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/text_input.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/timeline.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/token_estimate.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/type_usage_surface.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/validation_inference.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/verify_edit.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/verify_repo.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/verify_rules.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/version_check.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/waivers.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/src/sourcecode/workspace.py +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/supabase/functions/README.md +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/supabase/sql/licensing_schema.sql +0 -0
- {sourcecode-5.4.2 → sourcecode-5.5.1}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -2,6 +2,55 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.5.1] — 2026-08-13
|
|
6
|
+
|
|
7
|
+
**External audit corrections and command execution performance.**
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- **Impact callers** now expand accessor and interface frontiers consistently,
|
|
11
|
+
with caller symbols remaining a refinement of caller classes.
|
|
12
|
+
- **Endpoint and validation contracts** now expose test-surface policy, reuse
|
|
13
|
+
servlet declarations, and require real `Validator`/`setValidator` evidence.
|
|
14
|
+
- **Modernization references** now recognize nested types used by their
|
|
15
|
+
enclosing class.
|
|
16
|
+
- **Spring audit output** is bounded by default while explicit full output
|
|
17
|
+
remains available through `--output` and `--compact`.
|
|
18
|
+
- **Repeated command execution** reuses the cached analysis context and reports
|
|
19
|
+
independent cache-layer states for context, parse, snapshot, and RIS.
|
|
20
|
+
|
|
21
|
+
### Documentation
|
|
22
|
+
- Closed the 2026-08-13 external audit backlog in the roadmap with fix hashes
|
|
23
|
+
and regression coverage.
|
|
24
|
+
|
|
25
|
+
## [5.5.0] — 2026-08-12
|
|
26
|
+
|
|
27
|
+
**Audit backlog resolved and performance signals made explicit.**
|
|
28
|
+
This release folds in the latest external audit queue: programmatic Spring
|
|
29
|
+
validation now contributes to `validation` gaps and confidence, servlet and
|
|
30
|
+
endpoint publishing preserve extension mappings and `ANY` methods, reference
|
|
31
|
+
classification distinguishes class literals from config wires, and the cache
|
|
32
|
+
model now warns about large repositories against the correct scale. The roadmap
|
|
33
|
+
also records the audit backlog, including the command-execution timing
|
|
34
|
+
regression called out in the report.
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
- **Programmatic validation is now surfaced.** `Validator` and `@InitBinder`
|
|
38
|
+
evidence now affect `validation` gaps and overall confidence, and the payload
|
|
39
|
+
carries the non-coverage note for that limit.
|
|
40
|
+
- **Servlet extension mappings stay visible.** Patterns such as `*.ftl` and
|
|
41
|
+
`*.vm` are preserved in the servlet surface instead of being dropped.
|
|
42
|
+
- **Methodless request mappings publish as `ANY`.** `@RequestMapping` without a
|
|
43
|
+
declared method is no longer narrowed to `GET`.
|
|
44
|
+
- **Class literals count as references.** `Foo.class` hits now promote the
|
|
45
|
+
type to `referenced` instead of `unknown_framework_dispatch`.
|
|
46
|
+
- **Large-repository cache advice compares against the right scale.** The size
|
|
47
|
+
warning now tells the operator when the repository exceeds the measured
|
|
48
|
+
reference population.
|
|
49
|
+
|
|
50
|
+
### Documentation
|
|
51
|
+
- Added the external 2026-08-12 audit queue and its performance backlog to the
|
|
52
|
+
roadmap.
|
|
53
|
+
|
|
5
54
|
## [5.4.2] — 2026-08-12
|
|
6
55
|
|
|
7
56
|
**External audit fixes and roadmap alignment.**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.5.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.
|
|
129
|
+
ask version # ask 5.5.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.
|
|
91
|
+
ask version # ask 5.5.1 — and, on a build that has aged,
|
|
92
92
|
# how many releases have probably shipped since
|
|
93
93
|
```
|
|
94
94
|
|
|
@@ -492,6 +492,7 @@ class Conditioning:
|
|
|
492
492
|
scope: str # "3 342 Java files, cache cold"
|
|
493
493
|
transfers: "Optional[bool]" # do the reference figures apply here?
|
|
494
494
|
per_command: "dict[str, str]" # command → how it can be run here
|
|
495
|
+
java_files: "Optional[int]" = None # measured scope size, if available
|
|
495
496
|
|
|
496
497
|
def statement(self) -> str:
|
|
497
498
|
"""One sentence about whether the figures below transfer to this scope."""
|
|
@@ -500,6 +501,14 @@ class Conditioning:
|
|
|
500
501
|
f"This repository ({self.scope}) was not measured, so nothing below "
|
|
501
502
|
f"is claimed about it: the figures are the reference repository's."
|
|
502
503
|
)
|
|
504
|
+
if self.java_files is not None and self.java_files > REFERENCE_JAVA_FILES:
|
|
505
|
+
return (
|
|
506
|
+
f"This repository ({self.scope}) is larger than the repository the "
|
|
507
|
+
f"figures below were measured on ({REFERENCE_JAVA_FILES} Java files), "
|
|
508
|
+
f"and what cost tracks here is the build rather than the file count: "
|
|
509
|
+
f"{FIELD_ANCHOR}. Read each figure as the reference's, not as yours; "
|
|
510
|
+
f"the `here:` lines say how each command can be run on this one."
|
|
511
|
+
)
|
|
503
512
|
if self.transfers:
|
|
504
513
|
return (
|
|
505
514
|
f"This repository ({self.scope}) is within the size the figures "
|
|
@@ -27,6 +27,7 @@ from sourcecode.phased_run import PhasedRun
|
|
|
27
27
|
from sourcecode.partial_contract import PARTIAL_EXIT_CODE as _PARTIAL_EXIT
|
|
28
28
|
from sourcecode.partial_contract import read_count as _read_count
|
|
29
29
|
from sourcecode import perf
|
|
30
|
+
from sourcecode.non_coverage import block as _non_coverage_block
|
|
30
31
|
from sourcecode.caller_metrics import (
|
|
31
32
|
CALLER_METRIC_RECONCILIATION,
|
|
32
33
|
CYCLE_METRIC_RECONCILIATION,
|
|
@@ -3456,6 +3457,9 @@ def main(
|
|
|
3456
3457
|
_core_hash = ""
|
|
3457
3458
|
_core_flags_str = ""
|
|
3458
3459
|
_view_flags_str = ""
|
|
3460
|
+
# Reuse the freshness decision for cache metadata; otherwise the root
|
|
3461
|
+
# command repeats a full Git status walk after the analysis completes.
|
|
3462
|
+
_tree_is_dirty: Optional[bool] = None
|
|
3459
3463
|
|
|
3460
3464
|
if not no_cache:
|
|
3461
3465
|
try:
|
|
@@ -3505,6 +3509,8 @@ def main(
|
|
|
3505
3509
|
Path(_git_root_str) if _git_root_str else target,
|
|
3506
3510
|
scope=target,
|
|
3507
3511
|
)
|
|
3512
|
+
if _tree_sig and _git_sha:
|
|
3513
|
+
_tree_is_dirty = _tree_sig != _git_sha
|
|
3508
3514
|
if _tree_sig:
|
|
3509
3515
|
_core_key = f"{_tree_sig}-{_core_h}"
|
|
3510
3516
|
else:
|
|
@@ -3820,7 +3826,11 @@ def main(
|
|
|
3820
3826
|
if format == "json":
|
|
3821
3827
|
try:
|
|
3822
3828
|
from sourcecode.ris import _has_uncommitted_changes as _huc
|
|
3823
|
-
_uncommitted =
|
|
3829
|
+
_uncommitted = (
|
|
3830
|
+
_tree_is_dirty
|
|
3831
|
+
if _tree_is_dirty is not None
|
|
3832
|
+
else _huc(target)
|
|
3833
|
+
)
|
|
3824
3834
|
except Exception:
|
|
3825
3835
|
_uncommitted = False
|
|
3826
3836
|
_data_scope = "COMPACT" if compact else ("AGENT" if agent else "FULL")
|
|
@@ -4716,7 +4726,11 @@ def main(
|
|
|
4716
4726
|
if format == "json":
|
|
4717
4727
|
try:
|
|
4718
4728
|
from sourcecode.ris import _has_uncommitted_changes as _huc_fresh
|
|
4719
|
-
_uncommitted_fresh =
|
|
4729
|
+
_uncommitted_fresh = (
|
|
4730
|
+
_tree_is_dirty
|
|
4731
|
+
if _tree_is_dirty is not None
|
|
4732
|
+
else _huc_fresh(target)
|
|
4733
|
+
)
|
|
4720
4734
|
# _huc_fresh uses --untracked-files=no — it misses repos where all
|
|
4721
4735
|
# files are untracked (no staged/unstaged changes to tracked files).
|
|
4722
4736
|
# Promote to True when _allowed_changed_files contains untracked files.
|
|
@@ -6502,6 +6516,10 @@ def endpoints_cmd(
|
|
|
6502
6516
|
"the endpoint count, and the endpoint total is carried across as one "
|
|
6503
6517
|
"number rather than 3 500 rows.",
|
|
6504
6518
|
),
|
|
6519
|
+
include_tests: bool = typer.Option(
|
|
6520
|
+
False, "--include-tests",
|
|
6521
|
+
help="Include endpoints from test source and test-fixture modules; excluded by default.",
|
|
6522
|
+
),
|
|
6505
6523
|
client_usage: bool = typer.Option(
|
|
6506
6524
|
False, "--client-usage",
|
|
6507
6525
|
help="Join the routes against the HTTP calls written in the TypeScript/"
|
|
@@ -6562,7 +6580,7 @@ def endpoints_cmd(
|
|
|
6562
6580
|
_prog = Progress()
|
|
6563
6581
|
_prog.start("scanning endpoints")
|
|
6564
6582
|
try:
|
|
6565
|
-
data = _extract_java_endpoints(target)
|
|
6583
|
+
data = _extract_java_endpoints(target, include_tests=include_tests)
|
|
6566
6584
|
finally:
|
|
6567
6585
|
_prog.finish()
|
|
6568
6586
|
|
|
@@ -7287,6 +7305,23 @@ def validation_cmd(
|
|
|
7287
7305
|
except Exception:
|
|
7288
7306
|
pass
|
|
7289
7307
|
|
|
7308
|
+
if data.get("programmatic_validation", {}).get("detected"):
|
|
7309
|
+
data.setdefault("non_coverage", _non_coverage_block("validation"))
|
|
7310
|
+
_vc = data.get("validation_confidence")
|
|
7311
|
+
if isinstance(_vc, dict):
|
|
7312
|
+
_vc["overall"] = "Likely"
|
|
7313
|
+
_vc["claim"] = (
|
|
7314
|
+
"Declared constraints are present, but programmatic Spring "
|
|
7315
|
+
"Validator wiring was detected outside this surface's model"
|
|
7316
|
+
)
|
|
7317
|
+
limits = _vc.setdefault("known_precision_limits", [])
|
|
7318
|
+
note = (
|
|
7319
|
+
"Programmatic Spring Validator / @InitBinder wiring is outside the "
|
|
7320
|
+
"declared-constraint surface."
|
|
7321
|
+
)
|
|
7322
|
+
if note not in limits:
|
|
7323
|
+
limits.append(note)
|
|
7324
|
+
|
|
7290
7325
|
if path_prefix:
|
|
7291
7326
|
data["endpoints"] = [
|
|
7292
7327
|
e for e in data.get("endpoints", [])
|
|
@@ -8971,9 +9006,26 @@ def spring_audit_cmd(
|
|
|
8971
9006
|
# 9,53 s on a 1 303-file repository) and it is the same parse the other
|
|
8972
9007
|
# knowledge commands share, so it is fetched rather than rebuilt — which
|
|
8973
9008
|
# is what makes a warm worth anything here (cold == warm before C3-94).
|
|
8974
|
-
|
|
8975
|
-
|
|
9009
|
+
_repo_root = _ctxcache.repo_root_of(target)
|
|
9010
|
+
cir, _cir_lookup = _ctxcache.get_or_build_cir(
|
|
9011
|
+
_repo_root, target, file_list, progress=_work_sink(_prog)
|
|
8976
9012
|
)
|
|
9013
|
+
_cache_state = {
|
|
9014
|
+
"context": "warm" if _cir_lookup.hit else "cold",
|
|
9015
|
+
"parse": "warm" if _cir_lookup.hit else "cold",
|
|
9016
|
+
}
|
|
9017
|
+
try:
|
|
9018
|
+
from sourcecode import cache as _cache_state_mod
|
|
9019
|
+
_cache_status = _cache_state_mod.status(target)
|
|
9020
|
+
_cache_state["snapshot"] = (
|
|
9021
|
+
"warm" if _cache_status.get("cached_cores") else "cold"
|
|
9022
|
+
)
|
|
9023
|
+
_cache_state["ris"] = (
|
|
9024
|
+
"warm" if _cache_status.get("ris_exists") else "cold"
|
|
9025
|
+
)
|
|
9026
|
+
except Exception:
|
|
9027
|
+
_cache_state["snapshot"] = "unknown"
|
|
9028
|
+
_cache_state["ris"] = "unknown"
|
|
8977
9029
|
# C3-85: the stretch between the last `linking` tick and the first rule
|
|
8978
9030
|
# tick reports nothing, and what stays on the line is `n/n` — a counter
|
|
8979
9031
|
# that finished, reading as a stage still running. Measured on keycloak
|
|
@@ -9124,7 +9176,18 @@ def spring_audit_cmd(
|
|
|
9124
9176
|
"phase that never ran is not evidence there is none."
|
|
9125
9177
|
)
|
|
9126
9178
|
|
|
9127
|
-
|
|
9179
|
+
_bounded_default = (
|
|
9180
|
+
not compact and output_path is None and format == "json" and not table
|
|
9181
|
+
)
|
|
9182
|
+
data = (
|
|
9183
|
+
combined.to_compact_dict()
|
|
9184
|
+
if compact or _bounded_default
|
|
9185
|
+
else combined.to_dict()
|
|
9186
|
+
)
|
|
9187
|
+
if _bounded_default:
|
|
9188
|
+
data.pop("mode", None)
|
|
9189
|
+
data["default_output"] = "bounded"
|
|
9190
|
+
data.setdefault("metadata", {})["cache_layers"] = _cache_state
|
|
9128
9191
|
if _stopped_early:
|
|
9129
9192
|
# C3-87: the block is composed by `PhasedRun.status`, which is the
|
|
9130
9193
|
# authority `risk` is now bound to as well — one vocabulary for
|
|
@@ -14387,7 +14450,8 @@ def _cache_model_conditioning(path: Path) -> Any:
|
|
|
14387
14450
|
line += f" ({found.reference})"
|
|
14388
14451
|
per_command[row.command] = line
|
|
14389
14452
|
return _cmodel.Conditioning(
|
|
14390
|
-
scope=scope.describe(), transfers=transfers, per_command=per_command
|
|
14453
|
+
scope=scope.describe(), transfers=transfers, per_command=per_command,
|
|
14454
|
+
java_files=scope.java_files,
|
|
14391
14455
|
)
|
|
14392
14456
|
except Exception:
|
|
14393
14457
|
# A cost note is never worth failing a command that answers.
|
|
@@ -321,6 +321,27 @@ NON_COVERAGE: tuple[NonCoverage, ...] = (
|
|
|
321
321
|
"routes) is a measurement this command does not yet make."
|
|
322
322
|
),
|
|
323
323
|
),
|
|
324
|
+
NonCoverage(
|
|
325
|
+
id="NC-011",
|
|
326
|
+
surface="validation",
|
|
327
|
+
not_covered=(
|
|
328
|
+
"Programmatic Spring request-body validation wired with "
|
|
329
|
+
"`org.springframework.validation.Validator` or `@InitBinder`."
|
|
330
|
+
),
|
|
331
|
+
why=(
|
|
332
|
+
"This surface reads declared bean-validation constraints recovered from "
|
|
333
|
+
"OpenAPI or DTO annotations. A validator registered in controller code "
|
|
334
|
+
"can enforce body rules without any declarative constraint on the "
|
|
335
|
+
"payload, so treating the result as fully verified would overstate what "
|
|
336
|
+
"the declared-constraint scan proves."
|
|
337
|
+
),
|
|
338
|
+
instead=(
|
|
339
|
+
"`@InitBinder` / `setValidator(...)` wiring, or a Spring `Validator` "
|
|
340
|
+
"implementation, which this surface reports only as a coverage "
|
|
341
|
+
"boundary. `validation` still shows the declared rules; the programmatic "
|
|
342
|
+
"validator remains outside that model."
|
|
343
|
+
),
|
|
344
|
+
),
|
|
324
345
|
)
|
|
325
346
|
|
|
326
347
|
|
|
@@ -162,7 +162,7 @@ _QUALIFIED_TYPE_RE = re.compile(r"\b[A-Z][A-Za-z0-9_$]*\.[A-Z][A-Za-z0-9_$]*")
|
|
|
162
162
|
|
|
163
163
|
def _scan_repository(
|
|
164
164
|
root: Path, simple_names: "set[str]", nested: "dict[str, tuple[str, str]]"
|
|
165
|
-
) -> "tuple[dict[str, str], dict[str, str]]":
|
|
165
|
+
) -> "tuple[dict[str, str], dict[str, str], dict[str, str]]":
|
|
166
166
|
"""One walk, two questions — `(config-wired names, nested types other code names)`.
|
|
167
167
|
|
|
168
168
|
Both scans need the whole tree, and walking it twice doubled the cost of the
|
|
@@ -175,6 +175,7 @@ def _scan_repository(
|
|
|
175
175
|
"""
|
|
176
176
|
config_hits: dict[str, str] = {}
|
|
177
177
|
nested_hits: dict[str, str] = {}
|
|
178
|
+
literal_hits: dict[str, str] = {}
|
|
178
179
|
pending = set(simple_names)
|
|
179
180
|
by_qualified: dict[str, list[str]] = {}
|
|
180
181
|
for fqn, (qualified, _own) in nested.items():
|
|
@@ -183,7 +184,7 @@ def _scan_repository(
|
|
|
183
184
|
scan_config = bool(pending)
|
|
184
185
|
scan_java = bool(by_qualified)
|
|
185
186
|
if not scan_config and not scan_java:
|
|
186
|
-
return config_hits, nested_hits
|
|
187
|
+
return config_hits, nested_hits, literal_hits
|
|
187
188
|
|
|
188
189
|
scanned = 0
|
|
189
190
|
for dirpath, dirnames, filenames in os.walk(root):
|
|
@@ -191,7 +192,7 @@ def _scan_repository(
|
|
|
191
192
|
for filename in filenames:
|
|
192
193
|
is_java = filename.endswith(".java")
|
|
193
194
|
is_config = os.path.splitext(filename)[1].lower() in _CONFIG_REF_EXTS
|
|
194
|
-
if not ((is_java and scan_java) or (is_config and scan_config)):
|
|
195
|
+
if not ((is_java and (scan_java or scan_config)) or (is_config and scan_config)):
|
|
195
196
|
continue
|
|
196
197
|
if scanned >= _SCAN_MAX_FILES:
|
|
197
198
|
break
|
|
@@ -206,17 +207,40 @@ def _scan_repository(
|
|
|
206
207
|
pending.discard(hit)
|
|
207
208
|
config_hits[hit] = rel
|
|
208
209
|
scan_config = bool(pending)
|
|
210
|
+
if is_java and scan_config:
|
|
211
|
+
# A `Foo.class` literal is a real static reference, and the
|
|
212
|
+
# field audit found one of these on the annotation-dispatch path.
|
|
213
|
+
class_hits = {
|
|
214
|
+
hit for hit in pending
|
|
215
|
+
if f"{hit}.class" in text
|
|
216
|
+
}
|
|
217
|
+
for hit in class_hits:
|
|
218
|
+
pending.discard(hit)
|
|
219
|
+
literal_hits[hit] = rel
|
|
220
|
+
scan_config = bool(pending)
|
|
209
221
|
if is_java and scan_java:
|
|
210
222
|
for hit in set(_QUALIFIED_TYPE_RE.findall(text)) & set(by_qualified):
|
|
211
223
|
for fqn in by_qualified[hit]:
|
|
212
224
|
if fqn not in nested_hits and nested[fqn][1] != rel:
|
|
213
225
|
nested_hits[fqn] = rel
|
|
226
|
+
# Nested types are often used unqualified by their enclosing
|
|
227
|
+
# class (`private Operation operation` or `Map<String, DATATYPE>`).
|
|
228
|
+
# The declaration is not a reference; a second occurrence is.
|
|
229
|
+
for fqn, (qualified, owner_file) in nested.items():
|
|
230
|
+
if owner_file != rel or fqn in nested_hits:
|
|
231
|
+
continue
|
|
232
|
+
nested_name = qualified.rsplit(".", 1)[-1]
|
|
233
|
+
unqualified = re.findall(
|
|
234
|
+
rf"(?<!\.)\b{re.escape(nested_name)}\b", text
|
|
235
|
+
)
|
|
236
|
+
if len(unqualified) > 1:
|
|
237
|
+
nested_hits[fqn] = rel
|
|
214
238
|
scan_java = len(nested_hits) < len(nested)
|
|
215
239
|
if not scan_config and not scan_java:
|
|
216
|
-
return config_hits, nested_hits
|
|
240
|
+
return config_hits, nested_hits, literal_hits
|
|
217
241
|
if scanned >= _SCAN_MAX_FILES:
|
|
218
242
|
break
|
|
219
|
-
return config_hits, nested_hits
|
|
243
|
+
return config_hits, nested_hits, literal_hits
|
|
220
244
|
|
|
221
245
|
|
|
222
246
|
def analyze_type_references(nodes: "list[dict]", root: Path) -> ReferenceFacts:
|
|
@@ -226,7 +250,15 @@ def analyze_type_references(nodes: "list[dict]", root: Path) -> ReferenceFacts:
|
|
|
226
250
|
examined, because a method with no callers is a different question.
|
|
227
251
|
"""
|
|
228
252
|
root = Path(root)
|
|
229
|
-
|
|
253
|
+
def _node_kind(node: dict) -> str:
|
|
254
|
+
kind = str(node.get("symbol_kind") or node.get("kind") or node.get("type") or "")
|
|
255
|
+
if kind in ("class", "interface", "enum", "annotation", "record"):
|
|
256
|
+
return kind
|
|
257
|
+
if kind == "@interface":
|
|
258
|
+
return "annotation"
|
|
259
|
+
return str(node.get("type") or "")
|
|
260
|
+
|
|
261
|
+
types = [n for n in nodes or [] if _node_kind(n) in ("class", "interface", "enum", "annotation", "record") and n.get("fqn")]
|
|
230
262
|
if not types:
|
|
231
263
|
return ReferenceFacts(0, {s: 0 for s in STATUSES}, ())
|
|
232
264
|
|
|
@@ -237,7 +269,7 @@ def analyze_type_references(nodes: "list[dict]", root: Path) -> ReferenceFacts:
|
|
|
237
269
|
entries.append(TypeReference(
|
|
238
270
|
fqn=str(node["fqn"]), status=REFERENCED,
|
|
239
271
|
basis="incoming edge in the call-graph",
|
|
240
|
-
type=
|
|
272
|
+
type=_node_kind(node), role=str(node.get("role") or "other"),
|
|
241
273
|
))
|
|
242
274
|
else:
|
|
243
275
|
candidates.append(node)
|
|
@@ -271,22 +303,30 @@ def analyze_type_references(nodes: "list[dict]", root: Path) -> ReferenceFacts:
|
|
|
271
303
|
f"{parts[-2]}.{parts[-1]}",
|
|
272
304
|
str(node.get("source_file") or "").replace("\\", "/"),
|
|
273
305
|
)
|
|
274
|
-
config_hits, nested_hits = _scan_repository(root, set(by_simple), nested_candidates)
|
|
306
|
+
config_hits, nested_hits, literal_hits = _scan_repository(root, set(by_simple), nested_candidates)
|
|
307
|
+
literal_refs: dict[str, str] = {}
|
|
275
308
|
for simple, config_file in config_hits.items():
|
|
276
309
|
for node in by_simple.get(simple, []):
|
|
277
310
|
dispatch_basis[str(node["fqn"])] = f"named in {config_file}"
|
|
311
|
+
for simple, literal_file in literal_hits.items():
|
|
312
|
+
for node in by_simple.get(simple, []):
|
|
313
|
+
literal_refs[str(node["fqn"])] = literal_file
|
|
278
314
|
|
|
279
315
|
for node in candidates:
|
|
280
316
|
fqn = str(node["fqn"])
|
|
281
317
|
common = {
|
|
282
318
|
"fqn": fqn,
|
|
283
|
-
"type":
|
|
319
|
+
"type": _node_kind(node),
|
|
284
320
|
"role": str(node.get("role") or "other"),
|
|
285
321
|
}
|
|
286
|
-
if fqn in nested_hits:
|
|
322
|
+
if fqn in nested_hits or fqn in literal_refs:
|
|
287
323
|
entries.append(TypeReference(
|
|
288
324
|
status=REFERENCED,
|
|
289
|
-
basis=
|
|
325
|
+
basis=(
|
|
326
|
+
f"referenced by its enclosing source in {nested_hits[fqn]}"
|
|
327
|
+
if fqn in nested_hits
|
|
328
|
+
else f"referenced by a class literal in {literal_refs[fqn]}"
|
|
329
|
+
),
|
|
290
330
|
**common,
|
|
291
331
|
))
|
|
292
332
|
elif fqn in dispatch_basis:
|
|
@@ -27,7 +27,7 @@ from typing import Any, Optional
|
|
|
27
27
|
#: The date `__version__` was released, from that version's CHANGELOG entry.
|
|
28
28
|
#: `tests/test_release_info.py` fails the build if the two disagree, so this is
|
|
29
29
|
#: a copy of a fact rather than a second authority for it.
|
|
30
|
-
RELEASE_DATE = "2026-08-
|
|
30
|
+
RELEASE_DATE = "2026-08-13"
|
|
31
31
|
|
|
32
32
|
#: Releases per day, measured over the 30 releases before this one (the same
|
|
33
33
|
#: computation the test re-runs against the CHANGELOG). Stable across window
|
|
@@ -3778,7 +3778,11 @@ def _parse_route_http_method(ann_name: str, args_str: str) -> str:
|
|
|
3778
3778
|
if explicit:
|
|
3779
3779
|
return explicit
|
|
3780
3780
|
m = re.search(r'method\s*=\s*(?:RequestMethod\.)?(\w+)', args_str or "")
|
|
3781
|
-
|
|
3781
|
+
if m:
|
|
3782
|
+
return m.group(1).upper()
|
|
3783
|
+
if ann_name == "@RequestMapping":
|
|
3784
|
+
return "ANY"
|
|
3785
|
+
return ""
|
|
3782
3786
|
|
|
3783
3787
|
|
|
3784
3788
|
def _parse_route_extras(args_str: str) -> dict:
|
|
@@ -6358,10 +6362,13 @@ def is_test_source_file(rel_path: str) -> bool:
|
|
|
6358
6362
|
# Convenience: find Java files in a repo
|
|
6359
6363
|
# ---------------------------------------------------------------------------
|
|
6360
6364
|
|
|
6361
|
-
def extract_java_endpoints(
|
|
6365
|
+
def extract_java_endpoints(
|
|
6366
|
+
root: Path, *, include_tests: bool = False
|
|
6367
|
+
) -> "dict[str, Any]":
|
|
6362
6368
|
"""Extract REST endpoint surface from Java source files.
|
|
6363
6369
|
|
|
6364
6370
|
Canonical endpoint extractor — uses IR symbol extraction + _build_route_surface().
|
|
6371
|
+
Test-fixture modules remain auditable by default and can be included explicitly.
|
|
6365
6372
|
Security extraction delegated to _route_security_from_sym (single source of truth);
|
|
6366
6373
|
results stored in route["security_annotations"] by _build_route_surface.
|
|
6367
6374
|
|
|
@@ -6670,7 +6677,8 @@ def extract_java_endpoints(root: Path) -> "dict[str, Any]":
|
|
|
6670
6677
|
# counted with, the real API surface — but they are preserved in their own bucket
|
|
6671
6678
|
# so nothing is silently dropped and the exclusion is auditable.
|
|
6672
6679
|
_test_util_endpoints = [e for e in endpoints if e.get("scope") == "test_util"]
|
|
6673
|
-
|
|
6680
|
+
if not include_tests:
|
|
6681
|
+
endpoints = [e for e in endpoints if e.get("scope") != "test_util"]
|
|
6674
6682
|
|
|
6675
6683
|
# "no_security_signal" = no recognized security annotation at method OR class level.
|
|
6676
6684
|
# Note: repos may use framework-level security (e.g. Keycloak itself) with no
|
|
@@ -6894,7 +6902,7 @@ def extract_java_endpoints(root: Path) -> "dict[str, Any]":
|
|
|
6894
6902
|
pass
|
|
6895
6903
|
# Surface test-fixture endpoints excluded from the production surface above.
|
|
6896
6904
|
# Reported separately (not hidden) so the exclusion is transparent and auditable.
|
|
6897
|
-
if _test_util_endpoints:
|
|
6905
|
+
if _test_util_endpoints and not include_tests:
|
|
6898
6906
|
result["test_util_endpoints"] = _test_util_endpoints
|
|
6899
6907
|
result["test_util_excluded"] = len(_test_util_endpoints)
|
|
6900
6908
|
result.setdefault("notes", []).append(
|
|
@@ -6902,6 +6910,8 @@ def extract_java_endpoints(root: Path) -> "dict[str, Any]":
|
|
|
6902
6910
|
f"module(s) under src/main were excluded from the production surface "
|
|
6903
6911
|
f"(see test_util_endpoints)."
|
|
6904
6912
|
)
|
|
6913
|
+
elif _test_util_endpoints:
|
|
6914
|
+
result["test_util_included"] = len(_test_util_endpoints)
|
|
6905
6915
|
# Surface incomplete-endpoint warnings (interface-defined controllers) only when
|
|
6906
6916
|
# present, to keep output backward-compatible for the common case.
|
|
6907
6917
|
if endpoint_warnings:
|
|
@@ -6960,6 +6970,17 @@ def extract_java_endpoints(root: Path) -> "dict[str, Any]":
|
|
|
6960
6970
|
if any(r.get("framework") == "jax_rs" for r in routes):
|
|
6961
6971
|
_nonspring.pop("jax_rs", None)
|
|
6962
6972
|
|
|
6973
|
+
# Servlet mappings are a URL declaration population, not a count of
|
|
6974
|
+
# HttpServlet classes. Reuse the servlet extractor so `endpoints` and
|
|
6975
|
+
# `endpoints --servlets` publish the same authoritative census.
|
|
6976
|
+
try:
|
|
6977
|
+
from sourcecode.servlet_surface import build_servlet_surface
|
|
6978
|
+
|
|
6979
|
+
_nonspring["servlets"] = int(
|
|
6980
|
+
build_servlet_surface(root).get("declarations", 0)
|
|
6981
|
+
)
|
|
6982
|
+
except Exception:
|
|
6983
|
+
pass
|
|
6963
6984
|
_nonspring_total = sum(_nonspring.values())
|
|
6964
6985
|
if _nonspring_total:
|
|
6965
6986
|
_frameworks = [k for k, v in _nonspring.items() if v]
|
|
@@ -7260,6 +7281,23 @@ def compute_blast_radius(
|
|
|
7260
7281
|
# class-level node traversable at all (C1-16), and rebuilding it per node
|
|
7261
7282
|
# would make the walk quadratic in the graph.
|
|
7262
7283
|
_rg_index = _class_method_index(reverse_graph)
|
|
7284
|
+
|
|
7285
|
+
def _walk_callers(_node: str) -> list[str]:
|
|
7286
|
+
"""Expand method frontiers through their owning class as well.
|
|
7287
|
+
|
|
7288
|
+
Service-locator accessors enter the frontier as ``Class#accessor`` while
|
|
7289
|
+
callers of the class are indexed under its method keys. Keeping the
|
|
7290
|
+
exact lookup preserves method-level reach; adding the enclosing class
|
|
7291
|
+
lookup prevents that frontier from becoming a false terminal node.
|
|
7292
|
+
"""
|
|
7293
|
+
candidates = list(_all_callers_from_rg(
|
|
7294
|
+
_node, reverse_graph, _rg_index, _impl_graph
|
|
7295
|
+
))
|
|
7296
|
+
if "#" in _node:
|
|
7297
|
+
candidates.extend(_all_callers_from_rg(
|
|
7298
|
+
_enclosing_class(_node), reverse_graph, _rg_index, _impl_graph
|
|
7299
|
+
))
|
|
7300
|
+
return list(dict.fromkeys(candidates))
|
|
7263
7301
|
# Callers inject the interface, not the implementation, so a walk that does not
|
|
7264
7302
|
# know the implements relation stops one hop short of every DI consumer. Without
|
|
7265
7303
|
# it this traversal reached 200 classes and **no controller at all** for
|
|
@@ -7294,14 +7332,14 @@ def compute_blast_radius(
|
|
|
7294
7332
|
_expanded.add(_sym)
|
|
7295
7333
|
matched_fqns = _expanded
|
|
7296
7334
|
for seed in matched_fqns:
|
|
7297
|
-
_seed_callers =
|
|
7335
|
+
_seed_callers = _walk_callers(seed)
|
|
7298
7336
|
if len(_seed_callers) > _HUB_CALLER_THRESHOLD and max_depth > 1:
|
|
7299
7337
|
_effective_depth = 1
|
|
7300
7338
|
_hub_class_guard = True
|
|
7301
7339
|
break
|
|
7302
7340
|
|
|
7303
7341
|
for seed in matched_fqns:
|
|
7304
|
-
callers =
|
|
7342
|
+
callers = _walk_callers(seed)
|
|
7305
7343
|
for c in callers:
|
|
7306
7344
|
if c not in all_affected:
|
|
7307
7345
|
all_affected[c] = 1
|
|
@@ -7387,7 +7425,7 @@ def compute_blast_radius(
|
|
|
7387
7425
|
node, depth = queue.pop(0)
|
|
7388
7426
|
if depth >= _effective_depth:
|
|
7389
7427
|
continue
|
|
7390
|
-
for caller in
|
|
7428
|
+
for caller in _walk_callers(node):
|
|
7391
7429
|
if caller not in visited:
|
|
7392
7430
|
visited.add(caller)
|
|
7393
7431
|
all_affected[caller] = depth + 1
|
|
@@ -7410,7 +7448,7 @@ def compute_blast_radius(
|
|
|
7410
7448
|
_snode, _sdepth = _sample_queue.pop(0)
|
|
7411
7449
|
if _sdepth >= _HUB_SAMPLE_DEPTH:
|
|
7412
7450
|
continue
|
|
7413
|
-
for _scaller in
|
|
7451
|
+
for _scaller in _walk_callers(_snode):
|
|
7414
7452
|
if _scaller not in _sample_visited:
|
|
7415
7453
|
_sample_visited.add(_scaller)
|
|
7416
7454
|
all_affected[_scaller] = _sdepth + 1
|
|
@@ -7611,7 +7649,12 @@ def compute_blast_radius(
|
|
|
7611
7649
|
_direct_caller_classes = sorted(
|
|
7612
7650
|
caller_classes(direct_callers, exclude=matched_fqns)
|
|
7613
7651
|
)
|
|
7614
|
-
|
|
7652
|
+
_direct_class_set = set(_direct_caller_classes)
|
|
7653
|
+
_direct_caller_symbols = sorted(
|
|
7654
|
+
symbol for symbol in direct_callers
|
|
7655
|
+
if _enclosing_class(symbol) in _direct_class_set
|
|
7656
|
+
)
|
|
7657
|
+
n_direct_symbols = len(_direct_caller_symbols)
|
|
7615
7658
|
n_direct_classes = len(_direct_caller_classes)
|
|
7616
7659
|
n_direct = n_direct_symbols
|
|
7617
7660
|
n_indirect = len(indirect_callers)
|
|
@@ -7823,8 +7866,8 @@ def compute_blast_radius(
|
|
|
7823
7866
|
else _direct_caller_classes[:_direct_cap]
|
|
7824
7867
|
),
|
|
7825
7868
|
"direct_caller_symbols": (
|
|
7826
|
-
|
|
7827
|
-
else
|
|
7869
|
+
_direct_caller_symbols if _direct_cap is None
|
|
7870
|
+
else _direct_caller_symbols[:_direct_cap]
|
|
7828
7871
|
),
|
|
7829
7872
|
"indirect_callers": _indirect_summary,
|
|
7830
7873
|
"container_wired": [w.to_dict() for w in _container_wired],
|