sourcecode 5.4.0__tar.gz → 5.4.2__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.0 → sourcecode-5.4.2}/CHANGELOG.md +44 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/PKG-INFO +3 -3
- {sourcecode-5.4.0 → sourcecode-5.4.2}/README.md +2 -2
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/DEFECT-LEDGER.md +8 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/DEVELOPMENT-ROADMAP.md +97 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/USER_GUIDE.md +1 -1
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/semantic-ir-roadmap.md +40 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/pyproject.toml +1 -1
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/__init__.py +1 -1
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/cli.py +6 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/consumer_join.py +22 -3
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/repository_ir.py +42 -4
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/risk.py +99 -9
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/sql_taint.py +99 -18
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/test_sources.py +6 -4
- {sourcecode-5.4.0 → sourcecode-5.4.2}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/.github/workflows/perf-gate.yml +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/.gitignore +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/.ruff.toml +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/CLAUDE.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/CONTRIBUTING.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/LICENSE +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/SECURITY.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/CACHE.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/COMMERCIAL-OFFER.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/CUSTOMER-VALIDATION.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/DEMO-5MIN.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/EXECUTION-PLAN-12MO.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/EXECUTIVE-ROADMAP.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/MANUAL-USUARIO.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/MODERNIZATION.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/PRODUCT_AUDIT.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/PRODUCT_IDENTITY.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/PRODUCT_TIERS.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/RC1-CHECKLIST.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/RELEASE-CHECKLIST.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/CATALOG-retrieval-intents.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/DESIGN-knowledge-provider-integration.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/DESIGN-p5.3b-statement-surface.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/DESIGN-p5.5-span-index.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/DESIGN-p6-semantic-impact-engine.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/DESIGN-p6-semantic-integration-engine.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/DESIGN-p7-semantic-services.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/DESIGN-robustness-security-inference.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/DESIGN-semantic-retrieval.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/EPV-p6-class-typeref.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/REPORT-p6-flow-analyzer-comparison.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/REPORT-p6-integration-detector-comparison.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/REPORT-p8-flow-analyzer-migration.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/REPORT-p9-integration-detector-migration.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/adr/0001-semantic-ir.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/adr/0002-source-evidence-boundary.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/adr/0003-architectural-characterization.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/adr/0004-semantic-retrieval.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/adr/0005-evidence-reconciliation.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/adr/0006-performance-harness.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/adr/0007-composition-semantics.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/adr/0008-answer-coherence.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/consumer-disposition-inventory.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/overview.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/product-architecture-review.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/product-strategy-layering.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/architecture/semantic-ir-consumer-matrix.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/baseline-ci.yml +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/commercial-pipeline-audit.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/contracts-ci.yml +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/contracts.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/eval/2026-06-15-petclinic-rest-issue11-vets-pagination.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/eval/2026-06-15-petclinic-rest-issue147-validation.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/eval/2026-06-15-petclinic-rest-workflow.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/eval/2026-06-15-phase18-openapi-surface.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/eval/2026-06-15-phase20-validation-surface.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/eval/2026-06-16-broadleaf-checkout-impact-fieldtest.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/eval/2026-06-16-petclinic-rest-issue11-weakness2-closed.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/eval/2026-06-16-spring-petclinic-issue2333-dead-vets.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/licensing-schema.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/migrate-check.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/README.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/REGRESSION-GATE.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/SUMMARY.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/alfresco__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/alfresco__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/broadleaf__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/broadleaf__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/eureka__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/eureka__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/jenkins__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/jenkins__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/jobrunr__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/jobrunr__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/keycloak__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/keycloak__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/neo4j__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/neo4j__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/ofbiz__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/ofbiz__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/openmrs__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/openmrs__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/petclinic__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.15/petclinic__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/SUMMARY.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/alfresco__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/alfresco__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/broadleaf__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/broadleaf__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/eureka__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/eureka__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/jenkins__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/jenkins__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/jobrunr__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/jobrunr__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/keycloak__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/keycloak__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/neo4j__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/neo4j__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/ofbiz__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/ofbiz__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/openmrs__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/openmrs__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/petclinic__ask__cold.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/2.5.16/petclinic__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/gate-latest/README.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/gate-latest/broadleaf__ask__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/gate-latest/broadleaf__endpoints__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/gate-latest/broadleaf__migrate-check__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/gate-latest/broadleaf__posture__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/gate-latest/broadleaf__spring-audit__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/gate-latest/broadleaf__validation__warm.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/perf/baselines/reference-best/README.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/posture.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/privacy.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/pro-experience-audit.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/schema.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/spec/envelope-v1.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/docs/spring-audit-ci.yml +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/raw +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/scripts/compare_integration_engines.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/scripts/customer_smoke_test.sh +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/scripts/generate_jdk_exports.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/scripts/perf_gate.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/scripts/perf_harness.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/scripts/sync_gate_anchors.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/archetype.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/architectural_baseline.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/architectural_delta.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/audit_report.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/baseline_autocapture.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/bundled_docs.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/cache.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/cache_model.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/call_surface.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/caller_metrics.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/caller_reach.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/chain_rules.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/change_plan.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/classifier.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/client_calls.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/compare.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/constraint_diff.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/container_wiring.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/context_cache.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/context_graph.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/contract_diff.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/contract_init.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/data_exposure.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/data_labels.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/declarations.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/defect_identity.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/degradation.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/deployment_prefix.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detach.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/dynamic_argument_surface.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/endpoint_literals.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/endpoint_metrics.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/envelope.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/environment_resolution.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/evidence_provider.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/execution_plan.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/explain.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/facts/__init__.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/facts/registry.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/filter_surface.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/format_contract.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/gate_anchors.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/git_checkout.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/graph_evidence.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/hibernate_strat.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/identity_fallback.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/integration_coordinates.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/jdk_exports.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/license.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/mcp/dependency_import.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/migrate_check.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/migration_blast.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/non_coverage.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/openapi_surface.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/openrewrite_recipe.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/output_encoding.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/parallel.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/parse_cache.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/partial_contract.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/path_admission.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/perf.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/phased_run.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/pipe_contract.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/posture.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/progress.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/provenance.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/readiness_timeline.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/readonly.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/reconciliation.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/redactor.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/reference_facts.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/release_info.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/remedies.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/__init__.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/context.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/errors.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/executor.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/planner.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/query.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/request.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/resolution.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/result.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/retriever.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/runtime.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/steps.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/steps_endpoint.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/steps_graph.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/steps_impact.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/steps_intf.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/steps_struct.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/retrieval/steps_txsec.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/ris.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/rule_catalog.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/rule_pass.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/runs.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/sarif.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/scanner.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/schema.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/schemas/envelope-v1.schema.json +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/security_chain.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/security_config.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/security_config_scan.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/security_posture.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/semantic_impact_engine.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/semantic_integration_engine.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/semantic_services.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/serializer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/servlet_surface.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/source_text.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/spring_findings.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/spring_impact.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/spring_profiles.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/spring_properties.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/spring_security_audit.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/spring_tx_analyzer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/target_admission.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/test_gap_ranking.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/text_input.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/timeline.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/token_estimate.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/type_usage_surface.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/validation_inference.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/validation_surface.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/verify_edit.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/verify_repo.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/verify_rules.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/version_check.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/waivers.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/src/sourcecode/workspace.py +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/supabase/functions/README.md +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/supabase/sql/licensing_schema.sql +0 -0
- {sourcecode-5.4.0 → sourcecode-5.4.2}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -2,6 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.4.2] — 2026-08-12
|
|
6
|
+
|
|
7
|
+
**External audit fixes and roadmap alignment.**
|
|
8
|
+
This release preserves bounded SQL interpolation evidence in composed risk
|
|
9
|
+
payloads, declares the population of existing test counts, and removes routes
|
|
10
|
+
declared only by abstract controller classes. The external audit queue and
|
|
11
|
+
defect ledger are synchronized with the shipped behavior.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **Bounded SQL interpolations remain auditable in `risk` and `enrich`.** The
|
|
15
|
+
`sql_taint.bounded_interpolations` rows now survive composition serialization
|
|
16
|
+
beside `sinks_total`.
|
|
17
|
+
- **`existing_test_count` declares its population.** The payload now identifies
|
|
18
|
+
the all-path, multi-language `prepare-context` population and distinguishes it
|
|
19
|
+
from the Java IR test-gap population.
|
|
20
|
+
- **Abstract controller declarations no longer emit phantom routes.** Their
|
|
21
|
+
endpoints remain available for projection onto concrete subtypes, but the
|
|
22
|
+
abstract class itself is not treated as a registered handler bean.
|
|
23
|
+
|
|
24
|
+
### Documentation
|
|
25
|
+
- Added the external 5.4.2 audit queue and recommended capability work to the
|
|
26
|
+
semantic IR roadmap.
|
|
27
|
+
- Synchronized the distributed defect ledger with the 5.4.1/5.4.2 build state.
|
|
28
|
+
|
|
29
|
+
## [5.4.1] — 2026-08-12
|
|
30
|
+
|
|
31
|
+
**Two correctness fixes and a release bump.**
|
|
32
|
+
ASK now stops treating ambiguous `it` directory segments as test roots, so
|
|
33
|
+
business paths like `src/app/shared/akita/it/` no longer inflate test counts or
|
|
34
|
+
test-source facts. It also stops publishing static asset requests such as
|
|
35
|
+
`/assets/i18n/en.json` as `broken_integrations`; those are served files, not
|
|
36
|
+
server routes.
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
- **Ambiguous `it` segments no longer promote arbitrary business paths to test roots.**
|
|
40
|
+
The `test_sources` authority now leaves the bare `it` segment out of the
|
|
41
|
+
repository-level test-directory set, while `src/it` remains a declared test
|
|
42
|
+
source root. That closes the false-positive path in Angular and similar apps
|
|
43
|
+
where `it` is a domain token, not an integration-test marker.
|
|
44
|
+
- **Static asset calls are no longer reported as broken integrations.**
|
|
45
|
+
`consumer_join` now filters unmatched client calls under `/assets/`,
|
|
46
|
+
`/static/` and `/public/`, plus calls ending in static file extensions, and
|
|
47
|
+
documents that exclusion in the payload meaning.
|
|
48
|
+
|
|
5
49
|
## [5.4.0] — 2026-08-12
|
|
6
50
|
|
|
7
51
|
**Fourteen rows from one audit, and the worst defect this ledger has recorded.**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 5.4.
|
|
3
|
+
Version: 5.4.2
|
|
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.4.
|
|
129
|
+
ask version # ask 5.4.2 — 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.4.
|
|
91
|
+
ask version # ask 5.4.2 — and, on a build that has aged,
|
|
92
92
|
# how many releases have probably shipped since
|
|
93
93
|
```
|
|
94
94
|
|
|
@@ -59,6 +59,7 @@ The facts these rows are keyed to are published: `ask schema facts-v1` prints th
|
|
|
59
59
|
| C1-40 | **`cache model` promises `onboard` an answer-level cache hit and the second run recomputes.** `ask cache model .` publishes `onboard` → *"the answer (repeat cached)"* `[task, ris]`. Measured: first run 56 s (cold, expected), **second run on a warm cache 23,5 s** — not an answer hit, a partial recomputation. Corroborated by `cache context-stats .`: `Contexts: 1 · Hits: 1 · Misses: 1 · Hit ratio: 0.5 · Avg lookup 1029,1 ms (p95 1955,2 ms) · Avg build 18332,5 ms · Bytes stored 9 969 057`. A **full second to decide whether there is a hit**, over a single 10 MB entry, is the signature of deserialising the whole payload to read its key | 4.10.4 (eval #14) | **Medium** — `cache model` exists so a user can plan instead of guess; a row that overstates what a warm buys is the one defect that command cannot afford. The lookup half is the second field measurement of C3-47 | **closed (4.10.6), and the claim was the false half.** Reproduced at home on keycloak (5 486 sources): **with** a `cache warm`, `onboard` costs 0,7 s — the row's promise holds. **Without** one, a second identical run costs 9,4 s against 10,2 s cold: the warm is what stores the answer, and the command does not store its own. The row said `repeat cached`, the field ran it twice with no warm, and got 56 s → 23,5 s. `repeat` is now `false` for `onboard` and the measured figures are published at two scales, with and without a warm, so the reader can tell which run they are about to make. Half (b) shipped too: the validity keys (`ev`/`kl`/`sig`) live in an uncompressed sidecar beside the blob, so deciding *is this entry still valid?* is a small file read instead of decompressing and parsing a 10 MB envelope — the case that matters most, an entry invalidated by a changed signature, used to pay all of it and then discard the result. A genuine hit still pays for the payload it returns; that is the answer, not overhead. Entries written before the sidecar existed fall back to the old full read. Original remedy note: two halves. (a) Reconcile the claim: either `onboard` really caches its answer, or its row says `shared work`, not `the answer`. (b) Split key metadata (hash + validity) from the payload into a sidecar index so a hit is decided without deserialising the blob; target < 5 ms against the ~1 029 ms measured. Related F-AA |
|
|
60
60
|
| C1-43 | **"Does this repository configure a request filter chain?" has two authorities, and the one that decides whether a `high` finding family runs is the older, weaker one.** `posture._security_config_types` reads the question off the IR's own edges — a type that `extends`/`implements` a chain SPI type, **or a member that `returns` one**, i.e. the `@Bean SecurityFilterChain` shape — and the docstring beside it records why: *"a repository that wires its chain with a `@Bean SecurityFilterChain` and no `@EnableWebSecurity` reported `security.active: 0` — a false zero on the axis this command exists for."* `repository_ir._filter_based`, which decides `security_model` and therefore whether **SEC-001 runs at all**, still tests only `@EnableWebSecurity` (`_FILTER_SECURITY_ANNOTATIONS`, deliberately one entry) and `extends WebSecurityConfigurerAdapter`. A Spring Security 6 repository that declares its chain as a bean is therefore classified `annotation_based`, and SEC-001 then asserts, per unannotated handler, *"In an annotation_based security model there is no centralized filter — any caller can reach this endpoint without authentication"* | 4.18.0 (eval #24) | **High** — a confident falsehood on the strongest axis, and the only one of the series: measured on a greenfield Boot 3 module, the single SEC-001 finding is `POST /api/v1/auth/login`, which the repository's `SecurityConfig` lists in `PUBLIC_ENDPOINTS` with `permitAll()` under a closing `anyRequest().authenticated()` — the chain the model says does not exist both admits that route *and* protects the other 24. The evaluator adjudicated it by reading the source: *"la herramienta lo marca `high` porque solo lee la anotación del método, no la cadena de filtros"* | **in-progress** — the premise half shipped on `fix/sec-001-chain-authority`. One authority, `security_chain`, holds the request-chain SPI vocabulary, the member rule (*a member returning the SPI type makes its declaring class the configuration*) and the name normalisation; `posture` and both `repository_ir` sites read it, so the mechanism can no longer differ. **Two questions are named apart there rather than merged, because only one of them may silence a finding:** `declares_request_chain` (is there a chain at all — the annotation, the pre-5.7 adapter, or a member producing a `SecurityFilterChain`) is SEC-001's premise and is deliberately narrow, while `chain_participant_types` (what takes part in configuring it, filters included) is `posture`'s question. Widening the first to the second would silence SEC-001 on repositories with no centralized authorization — the P1-A failure mode, and the one with no symptom. Measured end-to-end on a fixture of the reported shape: `security_model` `annotation_based` → `mixed`, and the SEC-001 finding on `POST /api/v1/auth/login` disappears; recall asserted in the same battery (no chain → still reported; `@EnableMethodSecurity` alone → still reported). Fleet A/B over 5 repositories × 3 commands: 15/15 payloads identical in content, which is the expected result and the point of running it — no fleet repository declares a chain in either shape, so nothing could move. **Open: the verdict half.** Where the chain resolves, the per-endpoint answer should come from the resolved chain rather than from the model classification (C1-8's `matched_path` machinery already exists), and where it does not resolve, SEC-001 abstains — never *"any caller can reach this endpoint"* over a chain the run did not read |
|
|
61
61
|
| C1-44 | **`has_uncommitted_changes: false` sits in the same document as `git_context.uncommitted_files: 1`, and it is the field cache freshness is decided on.** `ask <repo> --compact --git-context` publishes both, one run, one payload: `git_context.uncommitted_files` counts the file, `_cache.has_uncommitted_changes` says there is none, and `git status --porcelain` on the same tree prints `?? .claude/settings.json`. The third authority in the build agrees with the first — `--changed-only` reports `changed_files_count: 1` for that file and its `--help` defines the set it counts as *"staged, unstaged, untracked"* — so two of three surfaces admit the file and the one a consumer trusts for staleness does not. Under that published definition the boolean is simply false | 5.3.1 (audit #28) | Medium | **closed 5.4.0** — one predicate (`baseline_autocapture.counts_as_dirty`), extracted from `worktree_dirty` and read by the count in both the fresh path and the cache-hit patch, so the boolean cannot drift from the function that defines it. What it excludes is published (`uncommitted_files_not_read`, `uncommitted_files_basis`) rather than subtracted in silence, and only when something was actually excluded. Original remedy note: one predicate over one definition of *the working set*, read by both fields; the boolean is derived from the count rather than measured a second time, and where the two cannot be derived from one another the document may not publish both |
|
|
62
|
+
| C1-46 | **`existing_test_count: 6` sits beside `test_files: 0` and `has_test_sources: false` in one `prepare-context generate-tests` payload, and the 6 are five production files in a business package.** C3-115 closed the half that was reported — `test_gaps` now declares its population — and left a second authority for *"how many tests are there"* answering a different number in the same document. Re-measured in the field: 0 Java tests, 1 `.spec.ts`, 3 karma/jest configs; no population is worth 6. Root cause is in `test_sources.declared_test_root`: `_TEST_DIR_NAMES` carries the bare segment `it`, the final loop accepts it **at any depth**, and the only disarm — `_under_main_root` — knows `src/main` alone, which is a Maven layout. An Angular app lives under `src/app`, so `saint-client/src/app/shared/akita/it/` — *Incapacidad Temporal*, a business entity whose `it.model.ts` declares `ENFERMEDAD COMÚN` and `ACCIDENTE DE TRABAJO` — is read as a test source root and contributes 5 files; the 6th is the one real `.spec.ts`, and the reconciliation is exact. **It generalizes off this repository:** `it` is also the ISO 639-1 code for Italian, so `web/src/assets/i18n/it/messages.json` and `app/locales/it/common.ts` both answer `is_test_path: true` on the shipped build. Sibling of C1-28, in the direction C1-28 was written to prevent | 5.4.0 (audit #29) | **Medium** — the path-classification half is closed in 5.4.1; `existing_test_count_unit` now declares its all-path, multi-language task population in 5.4.2, distinct from the Java IR population | **closed 5.4.2** |
|
|
62
63
|
| C1-45 | **The SQL taint join keys a sink on a bare statement id, so a mapper method in one namespace is joined to a call site that resolves to another — and the result is published as the repository's #1 critical risk with a call trace that does not exist.** `risk`'s top row on a 3 342-file monolith is `severity_effective: 29.57` at `ProcesosGerenciaMapper.xml:74`, `factors.query_construction = http_input_reaches_sql_interpolation`, with evidence naming `AutocoberturasRestController#actualizar(id, obj)` *calls* `actualizar(…)` in `ProcesosGerenciaMapper`. The controller calls its own service's `actualizar`; the join matched on the method name alone. **The correct key already exists in the code and is not used** — `sql_taint` line 76 returns `f"{self.namespace}#{self.statement_id}" if self.namespace else self.statement_id`, and `namespace` is captured (141, 151) and then spent only on an explanatory sentence (313-314), while the published basis claims the sinks are *"keyed by namespace and statement id"*. **Accompanying defect, same row:** the interpolated expression is stored (72, 144) and emitted (86) and never inspected, so `bloqueada = ${dto.bloqueada ? "'S'" : "'N'"}` — an OGNL ternary whose two branches are string literals, a closed allowlist by construction and precisely the mitigation SEC-008's own `fix_hint` recommends — is ranked as a text-controllable sink | 5.3.1 (audit #28) | **High** — F-BF's whole argument is that this axis fires on evidence rather than on multiplication by 1,0; a name-collision join inverts the first row of the ranking, which is the product | **closed 5.4.0** — both sides keyed on `namespace#statement_id`: a call carries the type its receiver resolves to and is that statement's only when the receiver resolves to the mapper it lives in; an unresolved receiver is not the same answer as any type name, so the sink stays `undecidable` rather than `reaches`. `does_not_reach` carries the same qualification, because it is a confident no. `splices_free_text` reads the interpolation at last — anything it cannot prove closed is free text, and what it closes leaves the population into a published `bounded_interpolations` list. The regression fixture this row specified is in the suite. Original remedy note: key both sides on `namespace#statement_id` (the property is already written, the call sites read the wrong half), and give the interpolation a three-state read: an expression whose reachable values are all literals is `does_not_reach`, an unresolvable one stays `undecidable`, never `reaches` by default. Regression fixture: two mappers in different namespaces sharing a `statement_id`, one reached by HTTP input and one not — expected one `reaches`, one `undecidable`; today, two `reaches` |
|
|
63
64
|
|
|
64
65
|
|
|
@@ -227,6 +228,11 @@ The facts these rows are keyed to are published: `ask schema facts-v1` prints th
|
|
|
227
228
|
| C3-117 | **`--env-map` is inert: the section it advertises as an opt-in is emitted whether the flag is passed or not.** `ask <repo> --compact -o a.json` and `ask <repo> --compact --env-map -o b.json` are **byte-identical** (sha256 equal), and `env_map` is populated with the same 6 variables in both. The `--help` describes an opt-in (*"Map environment variables referenced across the codebase"*) that does not exist | 5.3.1 (audit #28) | Low — the payload is not wrong, the flag's contract is | **closed 5.4.0** — the behaviour stays (a compact payload with a null section is a hole where a reader expects one) and the claim is corrected: `_IMPLIED_NOTE`, one sentence in one place, appended by every flag it is true of, asserted against the parameter list including the negative. Original remedy note: either bind the flag (and pay the C3-103 attention: two views of one state must not become two analyses) or retire it and say the section is unconditional. A flag that changes nothing is a claim the build does not keep |
|
|
228
229
|
| C3-118 | **`prepare-context generate-tests` spends 56,45 s enforcing a 30 000 ms budget, and returns nothing.** No `--timeout`: wall clock 56,45 s, payload `analysis_budget.limit_ms: 30000`, `exhausted: true`, `relevant_files: 0` — an 88 % overshoot of the budget it was enforcing, to publish an empty answer. C3-1 closed this command's budget contract (published flag, `analysis_budget` block, budget in the cache key, an exhausted result never stored) on a measurement of **3,35 s over 3 300 files**; at 3 342 files with 6 947 sources the same default is 19× that and does not bind. This is C3-83's provenance question asked of the value rather than the source: the default is a constant, not a function of the scope | 5.3.1 (audit #28) | Medium — the default is unusable at the scale the product is sold for, and it costs double what it promises to return nothing | **closed 5.4.0** — the overshoot was the walk being *waited for*: `concurrent.futures` joins abandoned workers at interpreter shutdown, so the process paid the walk's full duration whatever the budget said. It runs on a daemon thread, which is not joined, and two subprocess assertions pin that property in both directions. The default is derived from the scope (`_tests_budget_ms`: 60 ms per Java file between the old 30 s figure as a floor and a 300 s ceiling) and publishes the count it derived it from. Original remedy note: the budget must bind (check it where the walk can be cut, not only between phases — C3-82's shape), and the default must be derived from the scope the command already measures rather than fixed at 30 s. When it is exhausted the payload already says so honestly; that half stays |
|
|
229
230
|
| C3-119 | **A client call whose URL is an expression is promoted to `broken_integration` — the one verdict this command presents as unconditional.** `ask endpoints <repo> --consumer <repo>/saint-client` reports **20 calls resolved, 115 unresolved** with a single reason (*"the URL is an expression, not a literal at the call site"*), `routes consumed: 0 / 3 574`, `delete_candidates: 2 637` — and 16 of the unresolved arrive as `broken_integrations`. The consumer centralises its base URL in a service (``this.httpGet(`${this.END_POINT}/porAgrupacion/${id}/${fecha}`)``, `planificacion-especial.service.ts:109`) and only the literal tail is captured, so the join key is a fragment and the route is then declared unserved. F-BH's own framing is that this direction *"needs no assumption about coverage to be true"*; it is the one verdict presented as incondicional and the one that is wrong. **Second facet, same extractor:** the TypeScript scan does not strip comments — `"GET /to/your/validation/service"` at `seguro-grid.component.ts:204` is a commented-out DevExpress documentation placeholder admitted as a live call. That is the E-1/E-2 predicate, applied in Java and not in TypeScript | 5.3.1 (audit #28) | Medium-High — a team acting on `broken_integrations` chases 16 integrations that are not broken, and the `delete_candidates` list inherits the same error at 2 637 rows | **closed 5.4.0** — a call whose head was an interpolation travels as `path_resolution: prefix_stripped`; it still matches where it matches, and where it does not it leaves `broken_integrations` for `partial_client_calls` with the reason and a count, on both join surfaces. `broken_integrations`' own `meaning` now states the condition it holds under. The comment model is `blank_comments`, offsets and line count preserved so every call still points at a line a reader can open, and string/template literals are state. Original remedy note: an unresolvable URL degrades to `unresolved_client_call` and never to `broken_integration` (absence of evidence is not evidence — INV-F1-1); the comment model the Java side has runs on the TypeScript side too. The resolution half is **F-BO**, not this row |
|
|
231
|
+
| C3-120 | **The composition engine became unusable at 3 342 files, and one line of C1-45's fix is why.** Measured against 5.3.1 artefacts on the same subject: `risk` 38,37 s → **601,74 s** under a 300 s budget, returning `partial: true` with **0 of 98** defects composed; `risk` under a 3 000 s budget → 444 s complete (×11,6); `enrich` 36,30 s → **>600 s**, stopped without completing; `audit-report` not run at all after two hangs. Median ratio over 48 comparable pairs is **1,00x** — the regression is confined to this family. Root cause is `sql_taint._receiver_type`: `_RECEIVER_RE` is anchored `…\s*$` and is applied as `search(method.body[:body_index])`, which copies an O(body_index) prefix **and** makes the regex engine try every start position in it before concluding. `_called_names` pays that for **every call of every method in the repository**, unfiltered and unbounded, where 5.3.1 did `names.add(call.group(1))` at O(1); a service body of 1 650+ lines makes the pass quadratic. Auditor's microbenchmark on the shipped regex, results byte-identical to a windowed `search(body, start, endpos)`: 8,6 KB/200 calls **36,9×**, 43 KB/1 000 calls **186,9×**, 215 KB/5 000 calls **916,5×** — 5× the calls, 25× the time | 5.4.0 (audit #29) | **Critical** — three of the seven experimental commands, and the ones that carry the price premium, do not return on the repository this product is sold for | **closed 5.4.1** — the read is windowed (`search(body, start, body_index)`: the `$` still ends at the call, no prefix is copied and the engine is offered a bounded number of start positions), and the window start retreats over any identifier it lands inside so a receiver wider than 128 characters is resolved whole rather than by its suffix — `""` is *unresolved* here and must never be reached by truncation. Second half: `_called_names` takes the statement ids being decided as its scope, because the only question asked of that set is `(mapper, statement id) in called`, so a name no statement carries can change no verdict. Re-measured on the shipped regex: 5 000 calls over a 159 KB body, **18 079 ms → 28 ms**, results identical at every call site. Four regression assertions, including a wall-clock gate on the pass |
|
|
232
|
+
| C3-121 | **The budget does not bind in the composition family, and one invocation froze the process.** `ASK_MAX_ANALYSIS_SECONDS=300 ask risk .` ran **601,74 s** of wall clock and wrote `elapsed_seconds: 600.92` into its own `_partial`; `ASK_MAX_ANALYSIS_SECONDS=150 ask enrich . --sarif` passed 600 s and was stopped by hand; a third `risk` invocation stopped responding until the working session was killed. This is the failure mode C3-82/C3-118 closed for `generate-tests` — *the budget must be checked where the walk can be cut, not only between phases* — reappearing in another family, and the lesson did not travel. Second half, independent of the overrun: a **respected** budget yields no answer — at 300 s the payload is `phases_completed: ["audit"]`, `phases_pending: ["compose"]`, `composition_stopped_after.defects_composed: 0`, which in CI is an empty envelope after ten minutes. The degradation shape itself is exemplary and is not what this row is against: `_partial` names the completed and pending phases, `why_stopped`, the repo-wide walks it skipped and the axes left `unknown`. ⚠ Re-measure after C3-120 before investigating separately — same subsystem, same triage C3-114 got against E-3 | 5.4.0 (audit #29) | **High** — a budget that does not cut is worse than no budget: it sells CI a guarantee it does not keep, and a hard freeze consumes the runner | **closed 5.4.1** — the deadline is asked *inside* the two repository-wide walks that hold the wall time, not only at their doors: the method parse samples the clock every 16 files and the two propagation walks sample it on their own units. A walk cut while running raises rather than returning what it had — every verdict these walks publish below `reaches` is a statement about the **whole** repository, and a negative over a partial universe is a confident no built on an unfinished read — so the measurement is dropped, the axis reads `unknown`, and the walk is named in `_partial.composition_walks_not_run` exactly as a walk that never started is. Nothing partial is cached on the CIR, so a later caller cannot be served a repository with files missing. Two assertions, both non-vacuous: the walk cut inside, and the composer naming it. ⚠ The residue this row does not close: the walks that are still gated only at the door (`inferring the security posture`, `indexing the validation surface`, `resolving the conditional bean graph`) — none of them was measured holding the overrun, and giving each a sampling seam is its own increment |
|
|
233
|
+
| C3-122 | **`ask risk <repo> -o <path>` spent 444 s, exited 0, printed nothing and wrote no file.** One occurrence, from bash with a Windows path in forward slashes; a later recursive search found the file nowhere in the user tree. The same path shapes worked in the same session for `ask endpoints -o`, `ask config` and `ask baseline capture --dir`. Not reproduced — the auditor stopped invoking `risk` after the freeze in C3-121 — and recorded with that limitation. An analysis command that consumes 444 s and reports success without producing its output owes the reader a line on stderr at minimum | 5.4.0 (audit #29) | **Low** (unreproduced) — but it is a C5 shape: the exit code is the published fact and it is wrong | **open** |
|
|
234
|
+
| C3-123 | **A static asset reaches `broken_integrations`, the one verdict this command presents as unconditional.** C3-119 did the main work — 19 → 1, with 14 relocated to `partial_client_calls` and the `meaning` stating its condition. The survivor is `GET /assets/i18n/{}.json` from `transloco-root.module.ts:18`: a translation bundle served by the container, not a Spring route. True under the published definition and not a broken integration in any sense a reader means. Remedy: exclude paths under known asset roots (`/assets/`, `/static/`, `/public/`) or ending in a static file extension, and say so in the `meaning` | 5.4.0 (audit #29) | **Low** | **closed 5.4.1** — static asset roots and file extensions are excluded and the meaning names the exclusion |
|
|
235
|
+
| C3-124 | **`risk` renamed three published keys inside a minor with no alias.** 5.3.1 emitted `total_defects`, `total_findings` and `risks_cap`; 5.4.0 emits `total_defects_floor`, `total_findings_floor` (plus `counts_basis`, `counts_are_floor`, `partial`, `_partial`) and dropped `risks_cap`. Permitted by the command's own experimental tier — *shape may change in a minor* — and the new names are better; the payload still carries no notice, so a consumer bound to the old keys reads `None` with nothing telling it why. `auth status` already publishes a `deprecated_fields` block: the channel exists and this command did not use it | 5.4.0 (audit #29) | **Informative** | **closed 5.4.1 as not a defect** — a complete 5.4.1 run retains the legacy keys; the renamed floor fields are emitted only for budget-cut payloads and are explicitly marked as floors |
|
|
230
236
|
|
|
231
237
|
## Class C4 — Discoverability (the ceiling as of 3.2.0)
|
|
232
238
|
|
|
@@ -278,6 +284,7 @@ robustness **4/10** — the lowest number any evaluation has given any axis.*
|
|
|
278
284
|
| `impact.stats.endpoints_affected_count` | C1-16 | ~~`0` where `impact-chain` returns a populated list~~ → **closed 3.5.0**: one reach authority (`caller_reach`), 0 → 20 of 21 endpoints on `Money`, exact parity on two other repositories |
|
|
279
285
|
| `ask <cmd> \| head` | C3-28 | ~~the answer is produced and the exit code says failure~~ → **closed 3.7.0**: a broken output stream changes nothing but where the bytes go; the command still exits on its own terms, so a failure keeps its code and its envelope |
|
|
280
286
|
| `spring-audit` cut by its own budget | C2-31 | ~~`summary` reads `total_defects: 15`, `confidence_level: high` where the complete run measures 98 — the truncation is declared only in `_partial`, at the root~~ → **closed 4.14.0**: a partial answer is capped at `low` confidence and `summary` carries `partial` / `counts_are_floor` / `counts_basis`, so the mark is where the numbers are |
|
|
287
|
+
| `risk -o <path>` | C3-122 | 444 s, exit **0**, no stdout and no file written — one occurrence, unreproduced |
|
|
281
288
|
| `plan <unknown target>` | C3-29 | ~~exit **0** over a payload of zeros while `impact` answers the same fact with exit 1~~ → **closed 3.7.0**: one authority, four commands, and ambiguity recognised as the same fact |
|
|
282
289
|
|
|
283
290
|
**Two witnesses arrived after the invariant.** Both are exit codes, and I-8 governs payloads —
|
|
@@ -327,6 +334,7 @@ provenance: E-3 was found from outside, on the surface where silence is loudest.
|
|
|
327
334
|
| E-1 | **Prose opened a declaration, and the file left the graph.** The declaration joiner decided whether a line *starts* a type declaration by scanning raw text. A comment carrying `class`/`interface`/`enum`/`record` followed by an identifier — `/** Implements the interface only for the legacy path. */`, or a trailing `// starter class is not an utility class` on an annotation — matched, so the join swallowed the annotation and the real declaration into one entry beginning with `@`, which the main loop reads as a pending annotation and never examines. The file then yields **zero symbols**: no type, no endpoint, no transaction boundary, nothing | 3.7.0 (battery, while building the C3-13 fixture) | Medium | **closed 3.7.0**. Comments are stripped before the keyword scan, block state carried across lines and string-literal aware; the join's terminating `{` must also be code, so a commented brace no longer cuts a real multi-line declaration in half. Measured A/B over six repositories (petclinic, eureka, open-banking-gateway, openmrs-core, Broadleaf, keycloak): **open-banking-gateway recovers 6 types — three of them Spring Boot application classes** — and **no repository loses a single symbol** |
|
|
328
335
|
| E-2 | **The security configuration scan cannot tell code from a comment.** `security_config_scan._scan_java` and `_scan_descriptor` match on raw text with no comment model. Reproduced at unit scope: `SEC-004` is returned identically for a live statement, a `//` comment and a `/* */` block; `SEC-007` identically for a live and a commented-out XML block. **Measured cost in the field: 4 of 13 `high` findings were false — 31 %** — and the damage is worse than the count, because the correlation engine wrote a persuasive paragraph over a commented-out block (*"these deployments share one credential, so the least protected decides the strength of all"*). **Confident prose about dead code is worse than a terse warning: it invites trust.** The same blindness runs in reverse and costs a *finding*: a transport-guarantee constraint that is commented out is invisible, so a mitigation somebody switched off is never reported, and it aggravates a cookie finding reported beside it. E-1 fixed exactly this class for the declaration joiner in 3.7.0; the configuration scan was written afterwards without the lesson | 4.5.1-class (eval #10) | **High** — it is the precision axis (scored 5,5/10) and the reason the evaluator concludes the output *"no es publicable sin verificación humana"* | **closed 4.5.3** — one authority, `source_text`, wired at the **three points a file is read** rather than inside each rule, so a rule added later is covered by construction instead of by whoever remembers. Comments are **blanked, not deleted**: offsets and line count are preserved, so every observation still points at the line a reader can open (asserted). Two properties are asserted as hard as the fix, because getting either wrong trades one wrong answer for another — **string literals survive** (`hibernate_strat._strip_comments_strings` blanks literal *content* on purpose, and these rules carry their evidence *inside* the literal: `MessageDigestPasswordEncoder("SHA-1")`, `<param-value>admin:{SHA-256}…`), and a `//` or `/*` **inside** a string is not a comment (`"http://example.com"`). A/B over the battery: BroadleafCommerce, openmrs-core, keycloak and spring-petclinic report byte-identical security findings — the fix removes false positives and loses no true one. `source_text.commented_spans` is published unused, so the *reverse* half — a control that is present but switched off — has a seam to be reported from rather than a second parser (DEAD-001, queued as F-A) |
|
|
329
336
|
| E-3 | **A handler that inherits its `@RequestMapping` loses the authorization annotation it declares, and 54,7 % of a monolith's HTTP surface is published as unguarded.** The inheritance projection in `_build_route_surface` indexes a projected route under the **declaring** member — the abstract method on the superclass that owns the mapping — and every security lookup downstream reads that symbol. The gate lives on the `@Override` in the concrete controller, which carries no mapping annotation and is therefore never consulted. Census on the subject (3 574 endpoints, parser validated 15/15 against hand-checked cases): **1 955 handlers inherit their mapping, carry a live gate in source, and are published `none_detected`**; 909 that declare their own mapping and carry the same gate are published `custom_gate_inferred`; 363 inherit and genuinely carry nothing; 115 declare and carry nothing; 111 carry a gate that is commented out (correctly `none_detected`, DEAD-001). The shape is the generic CRUD base class — one abstract class with the mappings and no security, 235 controllers extending it. Runtime semantics confirm the direction: the aspect's pointcut is `@Before("@annotation(…)")`, which matches the executing method — the override — so the annotation **is** applied and only the reading stops at the declaration. **Propagates to eight commands**: `endpoints`, `spring-audit`, `posture`, `data-exposure`, `risk`, `impact`, `enrich`, `audit-report`, plus `retrieve endpoint-security|security-surface`. It also retires this repository's own headline: *"2 635 endpoints with no security policy (73,7 %)"* is really **≈659** | 5.3.1 (audit #28) — **the first E row found in the field** | **Critical** — the largest single mis-classification this ledger has recorded, running in the unsafe direction, on the axis the product is bought for, in the answer the field quotes most | **closed 5.4.0** — the projection now names the member that runs. A projected route carries `effective_symbol` (the override where one exists, the declaration otherwise) beside `symbol`; the phase-3 security projection reads a gate the override declares for itself **method-level only**, so the fix can add a policy and never widen one away; and both `custom_gate_inferred` carry sites — the assembled route surface every CIR consumer reads, and the `endpoints` extractor — read the annotation set of **both** members of the pair. Second half, same root and found while fixing it: `_infer_gate_annotations` classified an inherited-mapping override as a non-handler, which puts the only members carrying the gate on the wrong side of the specificity ratio — diluting it at this subject's scale and **suppressing the gate outright** on a repository where most controllers extend a generic base. A member the route surface publishes as a route is a handler. 7 regression assertions over both surfaces and both vocabularies (a repository-declared gate and `@PreAuthorize`), **5 of 7 red on the previous build**; the two that are green are the negative controls — an ungated override stays ungated, because a fix in this direction must not invent a policy either. Suite 8 149 |
|
|
337
|
+
| E-4 | **E-3's residue: the annotation-to-method pairing is decided on raw text, so a blank line switches a security verdict off.** 24 endpoints in 14 controllers still publish `none_detected` with a live gate, out of the 1 955 E-3 corrected, and they partition perfectly into two lexical triggers. **(a) 18 endpoints** — a blank line between the annotation and the declaration (`@Override`, `@M3FiltroSeguridad(...)`, *blank*, `public List<MutuaDto> obtenerTodos()`): **0/18** detected, against 1 931/1 937 = 99,7 % where no blank line intervenes. `repository_ir` clears `pending_anns` in the fall-through at the end of the per-line loop, and the only blank-line guard sits **inside** the block-comment branch, so a genuinely empty line reaches the reset and empties the buffer. **(b) 6 endpoints** — a space between the type and its generic argument (`public List <CategoriaProfesionalDto> obtenerTodos()`): **0/6**. The `return_type` group is `[\w.<>\[\]?,]+`, which admits no space, so `List` matches, `\s+` eats the space, and `(?P<name>[a-z_]\w*)` is offered `<Categoria…>` and fails — **the whole declaration fails to match and the method is dropped**, which is the exact loss the regex's own comment three lines above warns about for modifier-position annotations. Java applies the annotation identically in both forms. In every one of the 14 controllers only `obtenerTodos` fails while its siblings (`crear`, `borrar`, `actualizar`, `obtenerPorId`) resolve. **E-3's 7 regression assertions cover neither form** | 5.4.0 (audit #29) | **Medium** — small population, unsafe direction, and it shows the pairing is still lexical rather than structural | **closed 5.4.1** — two edits, one per trigger. A blank line is skipped before the fall-through that clears the pending-annotation buffer: Java binds an annotation to the next declaration whatever whitespace separates them, and nothing about an empty line is a statement the reader must forget. The `return_type` group admits a space before the generic argument, so `List <Dto>` matches and the method exists again with its endpoint, its gate and its return-type edge. The spelling is normalised where it enters `stable_id` — `List <Dto>` and `List<Dto>` are one type and may not become two identities — and only the space *before* a bracket is removed, so `Map<String, List<X>>` keeps the id it already had. Four assertions added to E-3's battery, all four red on the previous build's source: both forms on the assembled route surface, both on the `endpoints` extractor, and the identity. ⚠ The class of defect is not closed by this row: the pairing is still lexical, which is what F-BP is queued for |
|
|
330
338
|
|
|
331
339
|
|
|
332
340
|
## Class P — Product and procurement (not analysis defects)
|
|
@@ -3,6 +3,103 @@
|
|
|
3
3
|
*Chief-engineer development record. This is the internal, dev-facing counterpart to the
|
|
4
4
|
customer-facing `docs/EXECUTIVE-ROADMAP.md`.*
|
|
5
5
|
|
|
6
|
+
> **PHASE UPDATE 2026-08-12 (audit #29 — the re-audit of 5.4.0, published the
|
|
7
|
+
> same day, `age_days: 0`).** Same subject (`saint-server @ 3dde037`, branch
|
|
8
|
+
> `banyan-v2`, 3 342 Java / 3 574 endpoints), same protocol (`ASK_READONLY=1` +
|
|
9
|
+
> `--no-write`), same instrumented harness and the same self-validated parser
|
|
10
|
+
> (15/15), compared directly against the 89 artefacts kept from the 5.3.1 round.
|
|
11
|
+
> ~45 commands re-run. **8,05/10** (5.3.1: 8,41) — and the composite hides the
|
|
12
|
+
> story, which has to be told whole: **what the product answers got much better
|
|
13
|
+
> and what delivers it got worse.** Correctness +1,3, performance −2,5,
|
|
14
|
+
> reliability −2,5.
|
|
15
|
+
>
|
|
16
|
+
> **Ten of the twelve rows verified closed independently, one partial, one closed
|
|
17
|
+
> by correcting the claim.** The security axis moved from unusable to reliable:
|
|
18
|
+
> detection on inherited-mapping handlers **0,0 % → 98,8 %** (0/1 955 →
|
|
19
|
+
> 1 931/1 955), affected controllers 232 → 14, and the 909/909 that already
|
|
20
|
+
> declared their own mapping stayed at 100 % — no collateral damage. Measured
|
|
21
|
+
> downstream: `impact.stats.security_surface_count` 894 → 1 888, and `endpoints
|
|
22
|
+
> --consumer` `delete_candidates` 2 637 → 701. The two that did not close clean
|
|
23
|
+
> are **DEF-04** (closed against a narrower restatement than the one reported)
|
|
24
|
+
> and **DEF-07** (`--env-map`, closed by correcting the `--help` text rather than
|
|
25
|
+
> the behaviour — accepted, recorded, not re-opened).
|
|
26
|
+
>
|
|
27
|
+
> ⚠ **The finding of this round is a regression, not a false answer: the
|
|
28
|
+
> composition engine no longer returns on this repository.** `risk` 38,37 s →
|
|
29
|
+
> 601,74 s under a 300 s budget with **0 of 98** defects composed; `enrich`
|
|
30
|
+
> 36,30 s → >600 s stopped by hand; `audit-report` not run after two hangs; one
|
|
31
|
+
> `risk` invocation froze the process until the working session was killed.
|
|
32
|
+
> Median ratio over 48 comparable pairs: **1,00x** — nothing else moved. The
|
|
33
|
+
> auditor localised it to one line of C1-45's own fix by microbenchmark, without
|
|
34
|
+
> invoking `risk` again: `sql_taint._receiver_type` searches an end-anchored
|
|
35
|
+
> pattern over a **copied prefix** of the method body, and `_called_names` pays
|
|
36
|
+
> it for every call of every method in the repository. **916× measured at
|
|
37
|
+
> 215 KB / 5 000 calls, results byte-identical to a windowed search.**
|
|
38
|
+
>
|
|
39
|
+
> **Seven rows opened.** C3-120 (critical, the quadratic receiver resolution) ·
|
|
40
|
+
> C3-121 (the budget does not bind in this family, plus one hard freeze) · E-4
|
|
41
|
+
> (E-3's residue: 24 endpoints whose gate is switched off by a blank line or by
|
|
42
|
+
> `List <T>`) · C1-46 (`existing_test_count: 6` against `test_files: 0`, and the
|
|
43
|
+
> six are a business package called `it`) · C3-122 (`risk -o` exit 0 with no
|
|
44
|
+
> file) · C3-123 (a static asset in `broken_integrations`) · C3-124 (`risk`
|
|
45
|
+
> renamed three published keys inside a minor with no alias).
|
|
46
|
+
>
|
|
47
|
+
> **Order of work: fixes only, one commit each, no features in this batch.**
|
|
48
|
+
> C3-120 → C3-121 (re-measure after C3-120 before investigating separately —
|
|
49
|
+
> same subsystem, the triage C3-114 got against E-3) → E-4 → C1-46 → C3-122 →
|
|
50
|
+
> C3-123 → C3-124. C3-120 first because it is one line with a verified
|
|
51
|
+
> equivalence and it probably closes C3-121 on its way.
|
|
52
|
+
>
|
|
53
|
+
> ⏸ **BATTERY PAUSED AFTER THREE ROWS (user directive, 2026-08-12).** Closed and
|
|
54
|
+
> committed, one commit each, suite green at every one (8 244 → 8 246 → 8 250):
|
|
55
|
+
> **C3-120** `5f28829` (windowed receiver read + the scope on `_called_names`:
|
|
56
|
+
> 18 079 ms → 28 ms over 5 000 calls, identical results) · **C3-121** `b2abec6`
|
|
57
|
+
> (the deadline sampled *inside* the two walks that hold the wall time; a walk
|
|
58
|
+
> cut inside answers `unknown` and is named, never a partial universe) · **E-4**
|
|
59
|
+
> (blank line and `List <T>`, four assertions red on the previous build).
|
|
60
|
+
> **STILL OPEN, in order, when the battery resumes: C1-46 · C3-122 · C3-123 ·
|
|
61
|
+
> C3-124.** No release commit and no version bump has been made — the tree
|
|
62
|
+
> carries 5.4.0's version with three fixes on top, and C3-120/C3-121 are the two
|
|
63
|
+
> that would need re-measuring on the field's subject before any release claims
|
|
64
|
+
> the composition family is back.
|
|
65
|
+
>
|
|
66
|
+
> **What the round confirms, and it is worth keeping:** remediation speed (12
|
|
67
|
+
> reported, 10 closed and verifiable in a release published the same day); the
|
|
68
|
+
> published ledger read as *"an asset, not marketing"*, including how many
|
|
69
|
+
> regression assertions were red before each fix; fixes that move the authority
|
|
70
|
+
> rather than patching the surface (`CONFIG_KEYS` as a registry readers consult,
|
|
71
|
+
> two derived fields off one predicate); first-class degradation under budget
|
|
72
|
+
> (`_partial` names phases completed and pending, `why_stopped`, the skipped
|
|
73
|
+
> walks and the axes left `unknown` — *"an absent measurement, never a zero"*);
|
|
74
|
+
> instrumented progress with stage, counter and ETA; both documents distributed
|
|
75
|
+
> **and the build verifying it against the wheel manifest**; and non-persistence
|
|
76
|
+
> intact over ~45 commands with the repository byte-identical.
|
|
77
|
+
>
|
|
78
|
+
> **Price, re-derived on the same method** (EUR per developer seat per year, 8
|
|
79
|
+
> seats): floor €180 → **€200**, mid €420 → **€450**, ceiling €780 → **€650**.
|
|
80
|
+
> The ceiling fell because `risk` / `enrich` / `data-exposure` are what carries
|
|
81
|
+
> the premium over a SAST and two of the three do not finish here — *capacity
|
|
82
|
+
> that does not terminate cannot be charged for*. **The ceiling is conditional
|
|
83
|
+
> and recoverable: closing C3-120 returns it to €780 and above, because the input
|
|
84
|
+
> to that composition is now correct — in 5.3.1 it finished over bad data.** The
|
|
85
|
+
> Boot 2→3 migration engagement is unchanged at €3 000–6 000 (`migrate-check` /
|
|
86
|
+
> `migrate-recipe` byte-identical: 61,0 days, 532 blocking findings).
|
|
87
|
+
>
|
|
88
|
+
> **Amendment V — three capabilities, all of them recommended by this round and
|
|
89
|
+
> all deferred behind the fix battery.** They are features, not fixes: none of
|
|
90
|
+
> them corrects a false claim.
|
|
91
|
+
>
|
|
92
|
+
> | | what it closes | shape |
|
|
93
|
+
> |---|---|---|
|
|
94
|
+
> | **F-BP** structural annotation↔member binding | E-4 is the second time a whitespace form has switched a security verdict off, and the fix for it is two more lexical tolerances. The pairing wants to be decided on the declaration the IR already builds, not on adjacency in raw text | a member's annotation set comes from the member, not from a line-buffer that anything unrecognised can clear. Bounded to the Java path that already produces `effective_symbol` |
|
|
95
|
+
> | **F-BQ** a deprecation channel for experimental payload keys | C3-124: an experimental tier is permission to change shape, not permission to change it in silence. `auth status` already publishes `deprecated_fields` and nothing else reuses it | one alias table per command, emitted beside the new key for one minor, with the release that removes it named in the payload |
|
|
96
|
+
> | **F-BR** a cost gate in the release battery for the composition family | C3-120 is a ×15,7 regression that a release shipped, and the performance gate that exists (C3-110/C3-113) has never had a cell for `risk` or `enrich` on a body of this size | a synthetic fixture — one ~200 KB method, ~5 000 calls — with a wall-clock assertion on `build_sql_taint`, and warm cells for the three composition commands in the release gate's baseline |
|
|
97
|
+
>
|
|
98
|
+
> ⚠ **Still queued from Amendment U, untouched by this round:** F-BK, F-BL,
|
|
99
|
+
> F-BM, F-BN, F-BO. F-BN (`ask explain-endpoint`) gains an argument from E-4:
|
|
100
|
+
> the derivation it would print is exactly what makes a residue like this
|
|
101
|
+
> visible in one command instead of in a census.
|
|
102
|
+
|
|
6
103
|
> **PHASE UPDATE 2026-08-12 (audit #28 of 5.3.1 — the first round run under a
|
|
7
104
|
> written non-persistence protocol, and the round that finds the worst defect
|
|
8
105
|
> this ledger has recorded).** Same subject (`saint-server @ 3dde037`, branch
|
|
@@ -297,3 +297,43 @@ milestone; hash-neutral; suite green.
|
|
|
297
297
|
> completion), then `integration_detector` migration (Move 3). Both are named here
|
|
298
298
|
> only to show the arc — neither is begun until P6.0's evidence is in hand and the
|
|
299
299
|
> user selects it.
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Part V — External re-audit queue (5.4.1 → 5.4.2)
|
|
304
|
+
|
|
305
|
+
The latest external re-audit was run against the installed `5.4.1` build using
|
|
306
|
+
the same read-only harness and repository as the previous rounds. This section
|
|
307
|
+
records only findings that are not already represented elsewhere in this
|
|
308
|
+
roadmap; previously closed findings remain historical evidence, not duplicate
|
|
309
|
+
work items.
|
|
310
|
+
|
|
311
|
+
### Bugs to fix
|
|
312
|
+
|
|
313
|
+
| ID | Finding | Severity | Resolution / acceptance criterion |
|
|
314
|
+
|----|---------|----------|------------------------------------|
|
|
315
|
+
| D-01 | `risk` drops `bounded_interpolations` while serializing the `sql_taint` block, so `sinks_total` is not auditable. | Medium | Preserve the bounded rows in the published payload. A fixture with one bounded and one free interpolation must report `sinks_total == 1` and one `bounded_interpolations` entry in both `risk` and `enrich`. |
|
|
316
|
+
| D-02 | `existing_test_count` has no population/unit declaration and is confused with the IR's `test_gap_ranking.population.test_files`. | Medium | Publish an explicit unit naming the all-paths, multi-language task population, or remove the redundant field. The chosen authority must be covered end to end. |
|
|
317
|
+
| D-03 | Route projection emits endpoints declared by abstract controller classes, creating phantom routes and inflating the unprotected census. | Low | Carry class modifiers into route-surface metadata and exclude abstract declarers from emitted routes; concrete subtype projection remains unchanged. |
|
|
318
|
+
| D-04 | The distributed defect ledger can claim `C3-123` is open although the `5.4.1` build already excludes static assets. | Informational | Synchronize ledger status with the shipped build and close the stale row. Documentation artifacts must describe the wheel they accompany. |
|
|
319
|
+
| D-05 | `risk -o` once exited successfully without writing a file; the four current invocations did write correctly. | Unreproduced | Keep as an observation only. Do not implement or mark it closed without a reproducible fixture. |
|
|
320
|
+
|
|
321
|
+
The audit explicitly retracted the apparent `N-01` global performance regression
|
|
322
|
+
after cache-settled, consecutive measurements, and retracted `REG-07` schema
|
|
323
|
+
breakage after a complete run preserved the legacy keys. Neither is a bug queue
|
|
324
|
+
item. The already closed `REG-01` through `REG-06` findings are likewise not
|
|
325
|
+
reopened here.
|
|
326
|
+
|
|
327
|
+
### Recommended capabilities and engineering work
|
|
328
|
+
|
|
329
|
+
These are recommendations from the audit, not fixes to mix into the bug commits:
|
|
330
|
+
|
|
331
|
+
| Item | Recommendation | Product rationale |
|
|
332
|
+
|------|----------------|-------------------|
|
|
333
|
+
| Performance budget gate | Add a release-time assertion for IR construction and keep comparable cold/warm measurements. | Two consecutive releases had performance concerns before the cache-settled protocol separated real regressions from first-build cost. |
|
|
334
|
+
| Cache measurement protocol | Require an established cache and two concordant runs before publishing a performance claim; retain cold/warm values separately. | A single measurement inside a warming batch is not a stable comparison. |
|
|
335
|
+
| CLI grammar closure | Finish the unresolved CLI grammar/command-surface work tracked by `C4-25`. | The audit still identifies inconsistent or incomplete command syntax as an open usability risk. |
|
|
336
|
+
|
|
337
|
+
The existing P6.0 semantic-IR milestone is intentionally not repeated here;
|
|
338
|
+
its class-level type usage and semantic impact work remains the roadmap's
|
|
339
|
+
architectural feature track.
|
|
@@ -5461,6 +5461,12 @@ def prepare_context_cmd(
|
|
|
5461
5461
|
_et_count = getattr(output, "existing_test_count", None)
|
|
5462
5462
|
if _et_count is not None:
|
|
5463
5463
|
out["existing_test_count"] = _et_count
|
|
5464
|
+
out["existing_test_count_unit"] = (
|
|
5465
|
+
"test source files present in the complete prepare-context path "
|
|
5466
|
+
"universe, across all detected languages; this is a task-scope "
|
|
5467
|
+
"count and is not the Java IR population in "
|
|
5468
|
+
"`test_gap_ranking.population.test_files`"
|
|
5469
|
+
)
|
|
5464
5470
|
# C3-13: the basis of the ranked list travels with it — emitted even when the
|
|
5465
5471
|
# list is empty, because "no gaps" and "no measurement" are different answers.
|
|
5466
5472
|
if task == "generate-tests":
|
|
@@ -112,6 +112,13 @@ _VERB_FROM_OP = {
|
|
|
112
112
|
"delete": "DELETE",
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
_STATIC_ASSET_ROOTS = ("/assets/", "/static/", "/public/")
|
|
116
|
+
_STATIC_ASSET_EXTS = frozenset({
|
|
117
|
+
".css", ".js", ".mjs", ".cjs", ".ts", ".tsx", ".json", ".map",
|
|
118
|
+
".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".ico",
|
|
119
|
+
".woff", ".woff2", ".ttf", ".eot",
|
|
120
|
+
})
|
|
121
|
+
|
|
115
122
|
|
|
116
123
|
def _java_files(base: Path) -> list[Path]:
|
|
117
124
|
out: list[Path] = []
|
|
@@ -227,6 +234,14 @@ def _slug(path: str) -> str:
|
|
|
227
234
|
return re.sub(r"[^a-z0-9/{}]", "", normalize_path(path).lower())
|
|
228
235
|
|
|
229
236
|
|
|
237
|
+
def _is_static_asset_path(path: str) -> bool:
|
|
238
|
+
norm = normalize_path(path).lower()
|
|
239
|
+
if any(root in norm for root in _STATIC_ASSET_ROOTS):
|
|
240
|
+
return True
|
|
241
|
+
suffix = Path(norm).suffix
|
|
242
|
+
return suffix in _STATIC_ASSET_EXTS
|
|
243
|
+
|
|
244
|
+
|
|
230
245
|
def build_consumer_join(
|
|
231
246
|
root: Path,
|
|
232
247
|
endpoints: "Iterable[dict]",
|
|
@@ -316,7 +331,8 @@ def build_consumer_join(
|
|
|
316
331
|
unmatched = [
|
|
317
332
|
{"join_key": key, "call_sites": group[:5],
|
|
318
333
|
"consumers": sorted({g["consumer"] for g in group})}
|
|
319
|
-
for key, group in _unmatched_groups
|
|
334
|
+
for key, group in _unmatched_groups
|
|
335
|
+
if not _is_partial(group) and not _is_static_asset_path(group[0]["path"])
|
|
320
336
|
]
|
|
321
337
|
partial_unmatched = [
|
|
322
338
|
{"join_key": key, "call_sites": group[:5],
|
|
@@ -394,8 +410,11 @@ def build_consumer_join(
|
|
|
394
410
|
"meaning": (
|
|
395
411
|
"a consumer makes this request and this server serves no route "
|
|
396
412
|
"for it — the one direction that needs no assumption about "
|
|
397
|
-
"coverage to be true.
|
|
398
|
-
"
|
|
413
|
+
"coverage to be true. static asset paths under /assets/, "
|
|
414
|
+
"/static/ or /public/, and paths ending in static file "
|
|
415
|
+
"extensions, are excluded because they are served files, not "
|
|
416
|
+
"server routes. It holds only for calls whose whole path is "
|
|
417
|
+
"written at the call site; a call whose head is an "
|
|
399
418
|
"interpolation is in `partial_client_calls`, because the path "
|
|
400
419
|
"matched against is the written tail (C3-119)"
|
|
401
420
|
),
|
|
@@ -199,7 +199,16 @@ _METHOD_DECL_RE = re.compile(
|
|
|
199
199
|
# the method (its endpoint + return-type edge) is silently dropped (CH-003/Fase 22).
|
|
200
200
|
r'(?P<inline_anns>(?:@[\w.]+(?:\s*\([^)]*\))?\s+)*)'
|
|
201
201
|
r'(?:<[\w,\s?]+>\s+)?'
|
|
202
|
-
|
|
202
|
+
# E-4: the generic argument may be written apart from its type — `List <Dto>`
|
|
203
|
+
# is legal Java and the annotation applies identically. The character class
|
|
204
|
+
# below admits no space, so `List` matched, the `\s+` ate the space and the
|
|
205
|
+
# name group was offered `<Dto>`: the whole declaration failed and the method
|
|
206
|
+
# was dropped with its endpoint, its gate and its return-type edge — the exact
|
|
207
|
+
# loss the comment above warns about, from a different direction. Measured:
|
|
208
|
+
# 6 endpoints of the field's subject, all in the unsafe direction.
|
|
209
|
+
r'(?P<return_type>(?:void|boolean|byte|char|short|int|long|float|double|String'
|
|
210
|
+
r'|[\w.\[\]?]+\s*<[\w.<>\[\]?,\s]*>(?:\s*\[\s*\])*'
|
|
211
|
+
r'|[\w.<>\[\]?,]+)\s+)'
|
|
203
212
|
r'(?P<name>[a-z_]\w*)\s*\(',
|
|
204
213
|
)
|
|
205
214
|
|
|
@@ -874,8 +883,16 @@ def _parse_param_types(params_str: str) -> list[str]:
|
|
|
874
883
|
|
|
875
884
|
|
|
876
885
|
def _normalize_return_type(raw: str) -> str:
|
|
877
|
-
"""Normalize return type string: strip whitespace, keep generics.
|
|
878
|
-
|
|
886
|
+
"""Normalize return type string: strip whitespace, keep generics.
|
|
887
|
+
|
|
888
|
+
E-4: `List <Dto>` and `List<Dto>` are one type written two ways, and once the
|
|
889
|
+
first spelling is extracted at all it must not become a second identity —
|
|
890
|
+
this string is part of `stable_id`, which is what a baseline, a delta and a
|
|
891
|
+
contract diff are keyed on. Only the space *before* a bracket is removed:
|
|
892
|
+
`Map<String, List<X>>` keeps the spelling it already had, so nothing that
|
|
893
|
+
parsed before changes id.
|
|
894
|
+
"""
|
|
895
|
+
return re.sub(r"\s+(?=[<>])", "", raw.strip())
|
|
879
896
|
|
|
880
897
|
|
|
881
898
|
def _compute_stable_id(
|
|
@@ -1144,6 +1161,18 @@ def _extract_symbols(
|
|
|
1144
1161
|
stripped = stripped.strip()
|
|
1145
1162
|
if not stripped:
|
|
1146
1163
|
continue
|
|
1164
|
+
if not stripped:
|
|
1165
|
+
# E-4. A blank line is not a statement about anything, and clearing
|
|
1166
|
+
# the annotation buffer on it made one switch a security verdict off:
|
|
1167
|
+
# 18 endpoints of the field's subject published `none_detected` with
|
|
1168
|
+
# a live gate written two lines above the method, because
|
|
1169
|
+
# `@Override`, `@M3FiltroSeguridad(...)`, blank, `public List<Dto>
|
|
1170
|
+
# obtenerTodos()` reached the fall-through reset at the end of this
|
|
1171
|
+
# loop. Java binds an annotation to the next declaration whatever
|
|
1172
|
+
# whitespace separates them. The only blank-line guard used to sit
|
|
1173
|
+
# inside the block-comment branch above, which a genuinely empty line
|
|
1174
|
+
# never enters.
|
|
1175
|
+
continue
|
|
1147
1176
|
if stripped.startswith("//") or stripped.startswith("*"):
|
|
1148
1177
|
continue
|
|
1149
1178
|
|
|
@@ -1261,7 +1290,9 @@ def _extract_symbols(
|
|
|
1261
1290
|
conf = "high" if ("public" in modifiers or pending_anns) else "medium"
|
|
1262
1291
|
|
|
1263
1292
|
# Extract return type and params from matched line
|
|
1264
|
-
_ret_raw = (
|
|
1293
|
+
_ret_raw = _normalize_return_type(
|
|
1294
|
+
mth_m.group("return_type") or ""
|
|
1295
|
+
)
|
|
1265
1296
|
_after_paren = stripped[mth_m.end():]
|
|
1266
1297
|
# Paren-balanced close (DR-1): a naive first-')' truncated the
|
|
1267
1298
|
# parameter list at the first annotation ')' — e.g.
|
|
@@ -4928,6 +4959,7 @@ def _build_route_surface(
|
|
|
4928
4959
|
"fqn": sym.symbol,
|
|
4929
4960
|
"prefixes": prefixes,
|
|
4930
4961
|
"own_endpoints": [],
|
|
4962
|
+
"abstract": "abstract" in (sym.modifiers or []),
|
|
4931
4963
|
"has_path_ann": "@Path" in sym.annotations or "@RequestMapping" in sym.annotations,
|
|
4932
4964
|
}
|
|
4933
4965
|
|
|
@@ -4985,6 +5017,12 @@ def _build_route_surface(
|
|
|
4985
5017
|
(method, suffix, sym.symbol, sym.stable_id)
|
|
4986
5018
|
)
|
|
4987
5019
|
|
|
5020
|
+
# Abstract controllers contribute declarations for concrete subtype
|
|
5021
|
+
# projection, but Spring does not register the abstract class itself as
|
|
5022
|
+
# a handler bean.
|
|
5023
|
+
if class_info.get(cls_simple, {}).get("abstract"):
|
|
5024
|
+
continue
|
|
5025
|
+
|
|
4988
5026
|
# P1 FIX: extract security annotations (method-level first, class fallback)
|
|
4989
5027
|
_cls_sym_for_sec = class_sym_by_simple.get(cls_simple)
|
|
4990
5028
|
_sec = _route_security_from_sym(sym, _cls_sym_for_sec, custom_security)
|