sourcecode 1.31.20__tar.gz → 1.31.21__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-1.31.21/.continue-here.md +87 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/PKG-INFO +3 -3
- {sourcecode-1.31.20 → sourcecode-1.31.21}/README.md +2 -2
- {sourcecode-1.31.20 → sourcecode-1.31.21}/pyproject.toml +1 -1
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/__init__.py +1 -1
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/cli.py +14 -1
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/contract_pipeline.py +21 -1
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/mcp/server.py +26 -4
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_bug_fixes_v16.py +82 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_mcp_tools.py +47 -15
- sourcecode-1.31.20/.continue-here.md +0 -134
- {sourcecode-1.31.20 → sourcecode-1.31.21}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/.gitignore +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/.ruff.toml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/.sourcecode-cache/snapshot-3b5997a-fa5c742c.json +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/AUDIT_REAL_REPOS.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/CHANGELOG.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/CONTRIBUTING.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/LICENSE +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/SECURITY.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/docs/PRODUCT_TIERS.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/docs/privacy.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/docs/schema.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/raw +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/run_cli.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/cache.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/classifier.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/flow_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/progress.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/redactor.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/repository_ir.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/scanner.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/schema.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/serializer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/src/sourcecode/workspace.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/__init__.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/conftest.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/coverage.xml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/fastapi_app/src/main.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/go_service/cmd/api/main.go +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/go_service/go.mod +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/jacoco.xml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/latin1_sample.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/latin1_sample_iso.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/lcov.info +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/nextjs_app/package.json +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/application/service/FindAusenteService.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/domain/entities/Ausente.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/infrastructure/rest/AusenteRestController.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/application/service/FindAutocoberturasService.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/domain/entities/Autocoberturas.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/infrastructure/rest/AutocoberturasRestController.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/application/service/FindCalendarioTrabajadorService.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/domain/entities/CalendarioTrabajador.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/infrastructure/rest/CalendarioTrabajadorRestController.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/application/service/FindDepartamentoService.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/domain/entities/Departamento.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/infrastructure/rest/DepartamentoRestController.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/application/service/FindEmpleadoService.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/domain/entities/Empleado.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/infrastructure/rest/EmpleadoRestController.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/config/FilterConfig.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/NominaRestController.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/fixtures/spring_boot_minimal/src/main/resources/mapper/HealthMapper.xml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_architecture_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_architecture_summary.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_ast_extractor.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_audit_fixes.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_audit_sas_v2.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_block1_reliability.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_block2_coverage.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_block5_quality.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_broadleaf_fixes.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_bug_fixes_v1302.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_bug_fixes_v13115.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_bug_fixes_v1312.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_bug_fixes_v1313.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_bug_fixes_v2.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_cache.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_canonical_ir.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_classifier.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_cli.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_code_notes_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_context_scorer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_contract_pipeline.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_coverage_parser.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_cross_consistency.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_dependency_analyzer_node_python.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_dependency_analyzer_polyglot.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_dependency_schema.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_detector_dotnet.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_detector_go_rust_java.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_detector_nodejs.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_detector_php_ruby_dart.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_detector_python.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_detector_universal_managed.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_detector_universal_systems.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_detectors_base.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_doc_analyzer_jsdom.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_doc_analyzer_python.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_encoding_regression.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_enterprise_benchmarks.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_graph_analyzer_polyglot.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_graph_analyzer_python_node.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_graph_schema.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_hybrid_inference.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_integration.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_integration_dependencies.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_integration_detection.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_integration_docs.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_integration_graph_modules.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_integration_lqn.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_integration_metrics.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_integration_multistack.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_integration_semantics.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_integration_universal.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_java_spring_integration.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_mcp_runner.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_mcp_serve.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_metrics_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_output_ux.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_packaging.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_phase1_improvements.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_pipeline_integrity.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_real_projects.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_redactor.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_repository_ir.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_scanner.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_schema.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_schema_normalization.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_scoring_calibration.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_semantic_analyzer_node.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_semantic_analyzer_python.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_semantic_import_resolution.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_semantic_schema.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_signal_hierarchy.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_summarizer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_surface_honesty.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_task_differentiation.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_telemetry.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_v131_improvements.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_v1_10_regressions.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.21}/tests/test_workspace_analyzer.py +0 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Handoff — sesión 22
|
|
2
|
+
**Date:** 2026-05-25T09:10:25Z
|
|
3
|
+
**Branch:** master
|
|
4
|
+
**Last commit:** `f1e80b6 feat(cache): introduce two-layer cache (L1 core + L2 view)`
|
|
5
|
+
**Suite:** 1510 passed, 3 skipped — all green
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What was done this session
|
|
10
|
+
|
|
11
|
+
### Credibility audit (`AUDIT_REAL_REPOS.md`)
|
|
12
|
+
Full adversarial audit of `sourcecode` against Keycloak (7885 Java files) and BroadleafCommerce (2985 Java files). Findings logged in `AUDIT_REAL_REPOS.md` at repo root. Key bugs fixed in prior sessions (P0-01 Spring DI bridging, P0-02 repo-ir boundedness).
|
|
13
|
+
|
|
14
|
+
### Two-layer cache architecture (this session)
|
|
15
|
+
|
|
16
|
+
**Problem:** cache key was `(commit, ALL_flags)` → N flag combos × M commits = N×M full snapshots. Same commit with `--compact` vs `--agent` ran the full analysis pipeline twice.
|
|
17
|
+
|
|
18
|
+
**Solution implemented:**
|
|
19
|
+
- **L1 core** `core-<sha>-<analysis_hash>.json.gz` → pre-computed view data, keyed by analysis-affecting flags only
|
|
20
|
+
- **L2 view** `view-<core_hash16>-<view_hash>.json.gz` → rendered string, keyed by view-affecting flags
|
|
21
|
+
- Lookup: L2 hit → L1 hit + view rebuild → full analysis (skip analysis on L1 hit)
|
|
22
|
+
|
|
23
|
+
**Files changed:**
|
|
24
|
+
| File | What |
|
|
25
|
+
|------|------|
|
|
26
|
+
| `src/sourcecode/serializer.py` | Added `core_view(sm)` + `build_view_from_core()` + `CORE_VIEW_VERSION` |
|
|
27
|
+
| `src/sourcecode/cache.py` | Added `read_core/write_core`, `read_view/write_view`, `_gc_views()`, updated `_gc()` |
|
|
28
|
+
| `src/sourcecode/cli.py` | Replaced single-key cache block with 2-layer lookup + write; split flags into core vs view |
|
|
29
|
+
| `tests/test_cache.py` | +12 new tests: TestCoreCache, TestViewCache, TestGCLayered (44 total cache tests) |
|
|
30
|
+
|
|
31
|
+
**Flag split:**
|
|
32
|
+
- Core (analysis): `dep/gm/docs/fm/sem/arch/gc/em/cn/mode/exclude/depth` + version
|
|
33
|
+
- View (presentation): `compact/agent/format/full/no_tree/tree/rank_by/symbol/entrypoints_only/no_redact/graph_detail/docs_depth/max_nodes/graph_edges/max_importers/emit_graph`
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Current state
|
|
38
|
+
|
|
39
|
+
Working tree is **clean** — everything committed.
|
|
40
|
+
|
|
41
|
+
GSD state: milestone v1.0, 13 phases all complete (100%). No pending todos in `.planning/STATE.md`.
|
|
42
|
+
|
|
43
|
+
Outstanding work from `AUDIT_REAL_REPOS.md` (NOT yet implemented — only audit findings logged):
|
|
44
|
+
|
|
45
|
+
### P1 remaining (from audit):
|
|
46
|
+
- **BUG-P1-01** Risk score inconsistency: `OrderServiceImpl` 0 callers → risk_level: low vs `OrderDaoImpl` 0 callers → risk_level: high. Same root cause, different heuristics fire.
|
|
47
|
+
- **BUG-P1-02** `project_summary` copies README blurb instead of generating from code structure
|
|
48
|
+
- **BUG-P1-03** `fix-bug` returns 426 relevant files for generic NPE symptom — no score field, no cap
|
|
49
|
+
- **BUG-P1-04** `indirect_callers: 0` for KeycloakSession (1992 direct callers) — BFS exhausts at level 1
|
|
50
|
+
|
|
51
|
+
### P2 remaining:
|
|
52
|
+
- BUG-P2-01 `bounded_contexts` detection wrong (uses utility packages, not Maven modules)
|
|
53
|
+
- BUG-P2-02 `role: unknown` for all modernize high_coupling_nodes
|
|
54
|
+
- BUG-P2-03 `no_security_signal` always 100% for filter-based security (JAX-RS/XML)
|
|
55
|
+
- BUG-P2-04 JAX-RS sub-resource paths not composed with parent `@Path`
|
|
56
|
+
- BUG-P2-05 Broadleaf admin paths mixed into REST endpoints
|
|
57
|
+
- BUG-P2-06 Architecture confidence inconsistent between `--compact` and `--agent`
|
|
58
|
+
- BUG-P2-07 `entry_points.controllers.methods: 21` vs endpoints finding 130 (unexplained gap)
|
|
59
|
+
- BUG-P2-08 `--format`/`--no-cache` inconsistently available across subcommands
|
|
60
|
+
|
|
61
|
+
### Cosmetic:
|
|
62
|
+
- Code notes URLs truncated (`s.webkit.org/...`)
|
|
63
|
+
- `truncated: None` vs `truncated: false` inconsistency
|
|
64
|
+
- `--deep` flag referenced in output but absent from `--help`
|
|
65
|
+
- `--compact --help` claims 1000-3000 tokens; measured 2856-4031
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Next session: where to start
|
|
70
|
+
|
|
71
|
+
**Option A** — tackle P1 bugs from audit (highest credibility impact):
|
|
72
|
+
1. P1-01: risk score consistency when direct_callers=0 (Spring impl detection)
|
|
73
|
+
2. P1-02: `project_summary` generation from code structure not README
|
|
74
|
+
|
|
75
|
+
**Option B** — write integration tests for 2-layer cache (verify cli.py actually hits L1 on second run with different view flags)
|
|
76
|
+
|
|
77
|
+
**Option C** — version bump + changelog (v1.32.0) with 2-layer cache as headline
|
|
78
|
+
|
|
79
|
+
**Recommended: Option A → P1-01 first** (user-visible correctness, shortest fix).
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Resume
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
cat .continue-here.md
|
|
87
|
+
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 1.31.
|
|
3
|
+
Version: 1.31.21
|
|
4
4
|
Summary: Deterministic codebase context for AI coding agents
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -225,7 +225,7 @@ Description-Content-Type: text/markdown
|
|
|
225
225
|
|
|
226
226
|
**AI-ready change intelligence for Java/Spring enterprise monoliths.**
|
|
227
227
|
|
|
228
|
-

|
|
229
229
|

|
|
230
230
|
|
|
231
231
|
---
|
|
@@ -263,7 +263,7 @@ pipx install sourcecode
|
|
|
263
263
|
|
|
264
264
|
```bash
|
|
265
265
|
sourcecode version
|
|
266
|
-
# sourcecode 1.31.
|
|
266
|
+
# sourcecode 1.31.21
|
|
267
267
|
```
|
|
268
268
|
|
|
269
269
|
---
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**AI-ready change intelligence for Java/Spring enterprise monoliths.**
|
|
4
4
|
|
|
5
|
-

|
|
6
6
|

|
|
7
7
|
|
|
8
8
|
---
|
|
@@ -40,7 +40,7 @@ pipx install sourcecode
|
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
42
|
sourcecode version
|
|
43
|
-
# sourcecode 1.31.
|
|
43
|
+
# sourcecode 1.31.21
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
---
|
|
@@ -1776,8 +1776,21 @@ def main(
|
|
|
1776
1776
|
if changed_only and _allowed_changed_files:
|
|
1777
1777
|
# GAP-5: preserve full entry_points for architecture context even in
|
|
1778
1778
|
# --changed-only mode. Only filter file_paths and code_notes.
|
|
1779
|
+
# ALWAYS-INCLUDE: security-const files must stay in file_paths even when
|
|
1780
|
+
# not in the git diff — they resolve Java constant references used in
|
|
1781
|
+
# @M3FiltroSeguridad annotations (read-only anchors, not diff output).
|
|
1782
|
+
def _is_always_include_ref(p: str) -> bool:
|
|
1783
|
+
name = p.rsplit("/", 1)[-1].rsplit("\\", 1)[-1]
|
|
1784
|
+
if name.endswith("Const.java") or name.endswith("Constants.java"):
|
|
1785
|
+
return True
|
|
1786
|
+
parts = p.replace("\\", "/").lower().split("/")
|
|
1787
|
+
return any(seg in ("security", "seguridad", "constantes") for seg in parts)
|
|
1788
|
+
|
|
1779
1789
|
sm = _replace(sm,
|
|
1780
|
-
file_paths=[
|
|
1790
|
+
file_paths=[
|
|
1791
|
+
p for p in sm.file_paths
|
|
1792
|
+
if p in _allowed_changed_files or _is_always_include_ref(p)
|
|
1793
|
+
],
|
|
1781
1794
|
code_notes=[n for n in sm.code_notes if n.path in _allowed_changed_files],
|
|
1782
1795
|
)
|
|
1783
1796
|
data = compact_view(sm, no_tree=no_tree, full=full)
|
|
@@ -242,7 +242,27 @@ class ContractPipeline:
|
|
|
242
242
|
]
|
|
243
243
|
|
|
244
244
|
if changed_only:
|
|
245
|
-
|
|
245
|
+
def _is_always_include_ref(p: str) -> bool:
|
|
246
|
+
"""Always include security-const files regardless of diff status.
|
|
247
|
+
|
|
248
|
+
These are read-only reference anchors: they resolve Java constant
|
|
249
|
+
references (e.g. SeguridadRecursosConst.REC_X) used in security
|
|
250
|
+
annotations. They do NOT appear in diff output because
|
|
251
|
+
contract.is_changed is set from ``changed_files`` only (line below).
|
|
252
|
+
Criteria per bug-spec:
|
|
253
|
+
- name ends with Const.java or Constants.java
|
|
254
|
+
- any path segment is: security | seguridad | constantes
|
|
255
|
+
"""
|
|
256
|
+
name = p.rsplit("/", 1)[-1].rsplit("\\", 1)[-1]
|
|
257
|
+
if name.endswith("Const.java") or name.endswith("Constants.java"):
|
|
258
|
+
return True
|
|
259
|
+
parts = p.replace("\\", "/").lower().split("/")
|
|
260
|
+
return any(seg in ("security", "seguridad", "constantes") for seg in parts)
|
|
261
|
+
|
|
262
|
+
src_paths = [
|
|
263
|
+
p for p in src_paths
|
|
264
|
+
if p in changed_files or _is_always_include_ref(p)
|
|
265
|
+
]
|
|
246
266
|
|
|
247
267
|
# Apply max_files cap — bypass when symbol search to ensure defining files are found.
|
|
248
268
|
# A symbol query over a large repo needs all files; result set is small after filtering.
|
|
@@ -10,10 +10,12 @@ data is the parsed JSON object from the CLI output, not a shell string.
|
|
|
10
10
|
"""
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
|
+
import json
|
|
13
14
|
import os
|
|
14
15
|
from typing import Any
|
|
15
16
|
|
|
16
17
|
from mcp.server.fastmcp import FastMCP
|
|
18
|
+
from mcp.types import CallToolResult, TextContent
|
|
17
19
|
|
|
18
20
|
from sourcecode import __version__ as _sourcecode_version
|
|
19
21
|
from sourcecode.mcp.runner import run_command
|
|
@@ -30,15 +32,35 @@ def _ok(data: Any) -> dict:
|
|
|
30
32
|
return {"success": True, "data": data, "error": None}
|
|
31
33
|
|
|
32
34
|
|
|
33
|
-
def _err(message: str, code: str = "EXECUTION_FAILED") ->
|
|
34
|
-
|
|
35
|
+
def _err(message: str, code: str = "EXECUTION_FAILED") -> CallToolResult:
|
|
36
|
+
"""Return an MCP tool-error result with isError=True per MCP spec §tool-result."""
|
|
37
|
+
payload = {"success": False, "data": None, "error": {"code": code, "message": message}}
|
|
38
|
+
return CallToolResult(
|
|
39
|
+
content=[TextContent(type="text", text=json.dumps(payload))],
|
|
40
|
+
isError=True,
|
|
41
|
+
)
|
|
35
42
|
|
|
36
43
|
|
|
37
|
-
def _execute(args: list[str]) -> dict:
|
|
44
|
+
def _execute(args: list[str]) -> dict | CallToolResult:
|
|
38
45
|
try:
|
|
39
|
-
|
|
46
|
+
result = run_command(args)
|
|
40
47
|
except RuntimeError as exc:
|
|
41
48
|
return _err(str(exc))
|
|
49
|
+
# If CLI output itself signals failure via success:false, propagate as isError=True
|
|
50
|
+
if isinstance(result, dict) and result.get("success") is False:
|
|
51
|
+
payload = {
|
|
52
|
+
"success": False,
|
|
53
|
+
"data": None,
|
|
54
|
+
"error": result.get("error") or {
|
|
55
|
+
"code": "EXECUTION_FAILED",
|
|
56
|
+
"message": "Command returned success=false",
|
|
57
|
+
},
|
|
58
|
+
}
|
|
59
|
+
return CallToolResult(
|
|
60
|
+
content=[TextContent(type="text", text=json.dumps(payload))],
|
|
61
|
+
isError=True,
|
|
62
|
+
)
|
|
63
|
+
return _ok(result)
|
|
42
64
|
|
|
43
65
|
|
|
44
66
|
@mcp.tool()
|
|
@@ -248,3 +248,85 @@ def test_fix_bug_why_field_populated(tmp_path: Path) -> None:
|
|
|
248
248
|
assert "FIXME" in top.why or "annotation" in top.why, (
|
|
249
249
|
f"Expected FIXME signal in why, got: {top.why!r}"
|
|
250
250
|
)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
# ---------------------------------------------------------------------------
|
|
254
|
+
# Bug 5 — --changed-only always includes security-const files
|
|
255
|
+
# ---------------------------------------------------------------------------
|
|
256
|
+
|
|
257
|
+
def test_contract_pipeline_changed_only_always_includes_const_files(tmp_path: Path) -> None:
|
|
258
|
+
"""--changed-only must include *Const.java files regardless of diff status.
|
|
259
|
+
|
|
260
|
+
These are read-only reference anchors: included in the analysis to resolve
|
|
261
|
+
constant references but not marked as is_changed (not part of diff output).
|
|
262
|
+
"""
|
|
263
|
+
from sourcecode.contract_pipeline import ContractPipeline
|
|
264
|
+
|
|
265
|
+
changed = ["src/OrderService.java"]
|
|
266
|
+
const_file = "src/security/SeguridadRecursosConst.java"
|
|
267
|
+
all_files = changed + [const_file]
|
|
268
|
+
|
|
269
|
+
for f in all_files:
|
|
270
|
+
p = tmp_path / f
|
|
271
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
272
|
+
p.write_text("public class Placeholder {}")
|
|
273
|
+
|
|
274
|
+
cp = ContractPipeline(max_files=100)
|
|
275
|
+
contracts, _ = cp.run(
|
|
276
|
+
tmp_path,
|
|
277
|
+
all_files,
|
|
278
|
+
changed_only=True,
|
|
279
|
+
allowed_changed_files=set(changed),
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
contract_paths = {c.path for c in contracts}
|
|
283
|
+
assert const_file in contract_paths, (
|
|
284
|
+
"Const file must be always-included even when absent from diff"
|
|
285
|
+
)
|
|
286
|
+
# Read-only anchor — must NOT be marked as changed
|
|
287
|
+
const_contract = next(c for c in contracts if c.path == const_file)
|
|
288
|
+
assert not const_contract.is_changed, "Const file is read-only anchor: is_changed must be False"
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def test_changed_only_resource_names_unresolved_le5(tmp_path: Path) -> None:
|
|
292
|
+
"""With --changed-only active, resource_names_unresolved must be <= 5.
|
|
293
|
+
|
|
294
|
+
The always-include logic ensures *Const.java files remain in file_paths for
|
|
295
|
+
constant resolution even when they are absent from the git diff.
|
|
296
|
+
"""
|
|
297
|
+
from sourcecode.serializer import _security_surface_from_eps
|
|
298
|
+
|
|
299
|
+
# Create the const file on disk (not in the git diff)
|
|
300
|
+
const_dir = tmp_path / "src" / "security"
|
|
301
|
+
const_dir.mkdir(parents=True)
|
|
302
|
+
(const_dir / "SeguridadRecursosConst.java").write_text(
|
|
303
|
+
"public class SeguridadRecursosConst {\n"
|
|
304
|
+
' public static final String REC_PEDIDOS = "PEDIDOS";\n'
|
|
305
|
+
' public static final String REC_USUARIOS = "USUARIOS";\n'
|
|
306
|
+
' public static final String REC_FACTURAS = "FACTURAS";\n'
|
|
307
|
+
"}\n"
|
|
308
|
+
)
|
|
309
|
+
rel_const = "src/security/SeguridadRecursosConst.java"
|
|
310
|
+
|
|
311
|
+
class _MockEP:
|
|
312
|
+
def __init__(self, evidence: str) -> None:
|
|
313
|
+
self.evidence = evidence
|
|
314
|
+
|
|
315
|
+
eps = [
|
|
316
|
+
_MockEP('nombreRecurso="SeguridadRecursosConst.REC_PEDIDOS"'),
|
|
317
|
+
_MockEP('nombreRecurso="SeguridadRecursosConst.REC_USUARIOS"'),
|
|
318
|
+
_MockEP('nombreRecurso="SeguridadRecursosConst.REC_FACTURAS"'),
|
|
319
|
+
]
|
|
320
|
+
|
|
321
|
+
# Baseline (--changed-only WITHOUT always-include): const file absent → unresolved
|
|
322
|
+
without = _security_surface_from_eps(eps, root=tmp_path, file_paths=[])
|
|
323
|
+
n_without = len((without or {}).get("resource_names_unresolved", []))
|
|
324
|
+
assert n_without >= 1, "Baseline: absent const file must produce unresolved names"
|
|
325
|
+
|
|
326
|
+
# After fix (always-include): const file in file_paths → resolved
|
|
327
|
+
with_const = _security_surface_from_eps(eps, root=tmp_path, file_paths=[rel_const])
|
|
328
|
+
n_with = len((with_const or {}).get("resource_names_unresolved", []))
|
|
329
|
+
assert n_with <= 5, (
|
|
330
|
+
f"resource_names_unresolved must be <=5 when const file is always-included, got {n_with}"
|
|
331
|
+
)
|
|
332
|
+
assert n_with == 0, f"All 3 constants must resolve, got {n_with} unresolved"
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
"""Contract tests for sourcecode.mcp.server MCP tools.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Success contract (dict returned, FastMCP wraps with isError=False):
|
|
4
4
|
{"success": bool, "data": dict | str | None, "error": {"code": str, "message": str} | None}
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Failure contract (CallToolResult with isError=True per MCP spec §tool-result):
|
|
7
|
+
CallToolResult.isError == True
|
|
8
|
+
CallToolResult.content[0].text == JSON{"success": false, "data": null, "error": {...}}
|
|
7
9
|
|
|
8
10
|
Requires: pip install sourcecode[mcp]
|
|
9
11
|
"""
|
|
10
12
|
import json
|
|
13
|
+
from typing import Any
|
|
11
14
|
from unittest.mock import patch
|
|
12
15
|
|
|
13
16
|
import pytest
|
|
14
17
|
|
|
15
18
|
mcp_pkg = pytest.importorskip("mcp", reason="mcp extra not installed — skip MCP tool tests")
|
|
16
19
|
|
|
20
|
+
from mcp.types import CallToolResult, TextContent # noqa: E402
|
|
17
21
|
from sourcecode.mcp import server # noqa: E402 — after importorskip guard
|
|
18
22
|
|
|
19
23
|
_PARSED_OUTPUT = {"project": {"primary_stack": "python"}}
|
|
@@ -30,17 +34,23 @@ def _assert_success(result: dict) -> None:
|
|
|
30
34
|
json.dumps(result)
|
|
31
35
|
|
|
32
36
|
|
|
33
|
-
def _assert_failure(result:
|
|
34
|
-
|
|
35
|
-
assert
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
assert
|
|
39
|
-
assert "
|
|
40
|
-
|
|
37
|
+
def _assert_failure(result: Any, expected_code: str | None = None) -> None:
|
|
38
|
+
"""Assert tool returned CallToolResult with isError=True per MCP spec §tool-result."""
|
|
39
|
+
assert isinstance(result, CallToolResult), (
|
|
40
|
+
f"expected CallToolResult, got {type(result).__name__}"
|
|
41
|
+
)
|
|
42
|
+
assert result.isError is True, "isError must be True for tool failures"
|
|
43
|
+
assert len(result.content) == 1, "failure result must carry exactly one content item"
|
|
44
|
+
text = result.content[0]
|
|
45
|
+
assert isinstance(text, TextContent), f"content[0] must be TextContent, got {type(text).__name__}"
|
|
46
|
+
payload = json.loads(text.text)
|
|
47
|
+
assert payload["success"] is False
|
|
48
|
+
assert payload["data"] is None
|
|
49
|
+
assert isinstance(payload["error"], dict)
|
|
50
|
+
assert "code" in payload["error"]
|
|
51
|
+
assert "message" in payload["error"]
|
|
41
52
|
if expected_code:
|
|
42
|
-
assert
|
|
43
|
-
json.dumps(result)
|
|
53
|
+
assert payload["error"]["code"] == expected_code
|
|
44
54
|
|
|
45
55
|
|
|
46
56
|
# --- get_compact_context ---
|
|
@@ -82,7 +92,8 @@ def test_get_compact_context_failure():
|
|
|
82
92
|
with patch(_RUNNER_PATH, side_effect=RuntimeError("boom")):
|
|
83
93
|
result = server.get_compact_context("/some/repo")
|
|
84
94
|
_assert_failure(result, "EXECUTION_FAILED")
|
|
85
|
-
|
|
95
|
+
payload = json.loads(result.content[0].text)
|
|
96
|
+
assert "boom" in payload["error"]["message"]
|
|
86
97
|
|
|
87
98
|
|
|
88
99
|
# --- get_agent_context ---
|
|
@@ -328,11 +339,32 @@ def test_no_extra_keys_on_success():
|
|
|
328
339
|
|
|
329
340
|
|
|
330
341
|
def test_no_extra_keys_on_failure():
|
|
342
|
+
"""Runtime failures return CallToolResult with isError=True per MCP spec §tool-result."""
|
|
331
343
|
with patch(_RUNNER_PATH, side_effect=RuntimeError("x")):
|
|
332
344
|
r = server.get_compact_context("/p")
|
|
333
|
-
assert
|
|
345
|
+
assert isinstance(r, CallToolResult)
|
|
346
|
+
assert r.isError is True
|
|
334
347
|
|
|
335
348
|
|
|
336
349
|
def test_no_extra_keys_on_validation_error():
|
|
350
|
+
"""Validation failures return CallToolResult with isError=True per MCP spec §tool-result."""
|
|
337
351
|
r = server.get_module_context("/p", "")
|
|
338
|
-
assert
|
|
352
|
+
assert isinstance(r, CallToolResult)
|
|
353
|
+
assert r.isError is True
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def test_get_impact_context_nonexistent_class_returns_is_error():
|
|
357
|
+
"""Tool call with nonexistent class returns isError=True per MCP spec §tool-result.
|
|
358
|
+
|
|
359
|
+
When the subprocess exits non-zero (class not found), the MCP response must
|
|
360
|
+
carry isError=True so AI agents distinguish errors from successful results.
|
|
361
|
+
"""
|
|
362
|
+
with patch(_RUNNER_PATH, side_effect=RuntimeError("class 'NonExistentClass12345' not found")):
|
|
363
|
+
result = server.get_impact_context("/some/repo", target="NonExistentClass12345")
|
|
364
|
+
assert isinstance(result, CallToolResult), (
|
|
365
|
+
f"expected CallToolResult, got {type(result).__name__}"
|
|
366
|
+
)
|
|
367
|
+
assert result.isError is True, "isError must be True when target class does not exist"
|
|
368
|
+
payload = json.loads(result.content[0].text)
|
|
369
|
+
assert payload["success"] is False
|
|
370
|
+
assert "NonExistentClass12345" in payload["error"]["message"]
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
# Continue Here — atlas-cli sesión 21
|
|
2
|
-
|
|
3
|
-
**Paused:** 2026-05-24
|
|
4
|
-
**Repo:** `/Users/user/Documents/workspace/atlas-cli`
|
|
5
|
-
**Branch:** master
|
|
6
|
-
**Version:** sourcecode 1.31.17
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## Objetivo de esta sesión
|
|
11
|
-
|
|
12
|
-
Continuar corrección de bugs post-auditoría v1.31.16 (adversarial audit contra Keycloak + Broadleaf).
|
|
13
|
-
Sesión 21 atacó los dos P0s. Quedan P1s y P2s.
|
|
14
|
-
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
## Trabajo completado esta sesión
|
|
18
|
-
|
|
19
|
-
### P0-01 — `impact OrderServiceImpl` → 0 callers FIXED ✅
|
|
20
|
-
|
|
21
|
-
**Root cause:** `_build_reverse_adjacency` descartaba edges `implements` cuando `to` era
|
|
22
|
-
nombre corto no-resuelto (`"OrderService"` en vez de FQN). El `reverse_graph["OrderService"]`
|
|
23
|
-
no tenía clave `"implements"` → scan desde reverse side imposible.
|
|
24
|
-
|
|
25
|
-
**Fix:** Escanear `graph.edges` forward para `type=implements` FROM matched classes.
|
|
26
|
-
Resolver `to` (short/FQN) contra claves de `reverse_graph` via suffix match.
|
|
27
|
-
Callers de la interfaz se añaden a `direct_callers`. Output incluye `via_interface_resolution`
|
|
28
|
-
y `via_interface_note`.
|
|
29
|
-
|
|
30
|
-
**Resultado:** `impact OrderServiceImpl` en Broadleaf: 0 callers → **74 callers**, risk LOW → **HIGH**.
|
|
31
|
-
|
|
32
|
-
### P0-02 — `reverse_graph` unbounded por `--max-nodes`/`--max-edges` FIXED ✅
|
|
33
|
-
|
|
34
|
-
**Root cause:** `apply_ir_size_limits` sólo acotaba `graph.nodes`/`graph.edges`.
|
|
35
|
-
`reverse_graph` emitía 2685 claves (~3MB) aunque se pidieran 200 nodos.
|
|
36
|
-
|
|
37
|
-
**Fix:** Cuando `max_nodes` activo: restringir `reverse_graph` a `kept_fqns` + cap inner
|
|
38
|
-
caller lists a `max(20, max_nodes//4)`. Cuando sólo `max_edges`: cap a `max_edges` claves
|
|
39
|
-
por in-degree. Añade `reverse_graph_note` cuando trimmed.
|
|
40
|
-
|
|
41
|
-
**Resultado:** `--max-nodes 200 --max-edges 500`: 3.85MB → **939KB** (76% reducción).
|
|
42
|
-
|
|
43
|
-
### Commit esta sesión
|
|
44
|
-
|
|
45
|
-
```
|
|
46
|
-
e5fba19 fix(ir): resolve Spring DI interface bridging and bound reverse_graph
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## Estado archivos sin commitear
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
?? AUDIT_REAL_REPOS.md — auditoría 22 secciones (de sesión 20, no tocar)
|
|
55
|
-
?? docs/PRODUCT_TIERS.md — de sesión anterior (no tocar esta sesión)
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
Commitear estos docs antes de continuar con fixes:
|
|
59
|
-
```bash
|
|
60
|
-
git add AUDIT_REAL_REPOS.md docs/PRODUCT_TIERS.md
|
|
61
|
-
git commit -m "docs(audit): adversarial audit v1.31.16 — real benchmarks, P0/P1/P2 findings"
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## Bugs pendientes por ROI
|
|
67
|
-
|
|
68
|
-
### P1 — Altos
|
|
69
|
-
|
|
70
|
-
| # | Bug | Archivo | Tiempo est. |
|
|
71
|
-
|---|-----|---------|-------------|
|
|
72
|
-
| **P1-01** | Risk score inconsistente para 0-caller impls: `OrderServiceImpl`→low vs `OrderDaoImpl`→high (mismo 0 callers, distinta heurística). POST P0-01 fix: verificar si aún aplica o si interface bridging ya lo resuelve. | `repository_ir.py` → `compute_blast_radius` | 30 min |
|
|
73
|
-
| **P1-02** | `project_summary` = primera línea del README (license/marketing). Debe generarse de código: "N-module Spring Boot — M classes, K endpoints, J txn boundaries" | `serializer.py` o `summarizer.py` | 1h |
|
|
74
|
-
| **P1-03** | `fix-bug` devuelve 426 archivos para NPE genérico (14% repo, sin `score` field) | `prepare_context.py` → `fix_bug` | 30 min |
|
|
75
|
-
| **P1-04** | `indirect_callers:0` para KeycloakSession (1992 direct callers) — BFS para en nivel 1 por hub guard | `repository_ir.py` → `compute_blast_radius` hub guard logic | 45 min |
|
|
76
|
-
| **P1-05** | `fix-bug` 23s cold en Keycloak | profiling needed | ~1h |
|
|
77
|
-
|
|
78
|
-
### P2 — Medios (batch)
|
|
79
|
-
|
|
80
|
-
- `bounded_contexts: ["dto","file"]` Broadleaf — WRONG. Fix: usar Maven module names
|
|
81
|
-
- `role: unknown` para todos `high_coupling_nodes` en modernize — nunca clasifica annotation/interface/entity
|
|
82
|
-
- `no_security_signal: 100%` en ambos repos — filter-based security nunca detectado
|
|
83
|
-
- JAX-RS sub-resource paths no compuestos con parent `@Path`
|
|
84
|
-
- `hotspot_candidates: []` siempre — git churn ignorado
|
|
85
|
-
- `--format`/`--no-cache` ausentes en `impact`, `endpoints`, `fix-bug`, `onboard`, `modernize`, `review-pr`
|
|
86
|
-
- Architecture confidence diferente entre `--compact` y `--agent` mismo repo
|
|
87
|
-
|
|
88
|
-
---
|
|
89
|
-
|
|
90
|
-
## Primera acción al retomar
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
cd /Users/user/Documents/workspace/atlas-cli
|
|
94
|
-
|
|
95
|
-
# 1. Commitear docs pendientes
|
|
96
|
-
git add AUDIT_REAL_REPOS.md docs/PRODUCT_TIERS.md
|
|
97
|
-
git commit -m "docs(audit): adversarial audit v1.31.16 — Keycloak + Broadleaf findings"
|
|
98
|
-
|
|
99
|
-
# 2. Verificar si P1-01 aún existe post-fix P0-01:
|
|
100
|
-
sourcecode impact OrderDaoImpl ~/Documents/workspace/BroadleafCommerce 2>&1 | python3 -m json.tool | grep -E 'risk_level|confidence_level|direct_callers|via_interface'
|
|
101
|
-
# Si risk_level sigue siendo inconsistente → fix P1-01
|
|
102
|
-
# Si interface bridging ya lo resuelve → skip a P1-02
|
|
103
|
-
|
|
104
|
-
# 3. Si P1-01 persiste:
|
|
105
|
-
# En compute_blast_radius: cuando direct_callers=0 Y no hay interface bridging Y
|
|
106
|
-
# clase es @Service/@Repository impl → bajar confidence, añadir gap en explanation
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## Archivos clave del codebase
|
|
112
|
-
|
|
113
|
-
```
|
|
114
|
-
src/sourcecode/
|
|
115
|
-
repository_ir.py — impact analysis, blast radius, interface bridging (P0-01/02 fixeados aquí)
|
|
116
|
-
prepare_context.py — fix-bug, onboard, review-pr output (P1-03 aquí)
|
|
117
|
-
serializer.py — compact/agent output, project_summary (P1-02 aquí)
|
|
118
|
-
summarizer.py — ProjectSummarizer (P1-02 posiblemente aquí)
|
|
119
|
-
cli.py — top-level commands, cache logic
|
|
120
|
-
tests/
|
|
121
|
-
test_enterprise_benchmarks.py
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
## Contexto de versiones
|
|
127
|
-
|
|
128
|
-
- v1.31.16: bugs auditados en sesión 20
|
|
129
|
-
- v1.31.17: versión actual (bumpeada en 0cf28b1 por el usuario)
|
|
130
|
-
- Fixes P0-01/P0-02: commit e5fba19 (sesión 21)
|
|
131
|
-
|
|
132
|
-
---
|
|
133
|
-
|
|
134
|
-
*Pausado 2026-05-24 — gsd:pause-work (sesión 21)*
|
{sourcecode-1.31.20 → sourcecode-1.31.21}/.agents/skills/source-command-gsd-join-discord/SKILL.md
RENAMED
|
File without changes
|
{sourcecode-1.31.20 → sourcecode-1.31.21}/.agents/skills/source-command-gsd-review-backlog/SKILL.md
RENAMED
|
File without changes
|
{sourcecode-1.31.20 → sourcecode-1.31.21}/.agents/skills/source-command-gsd-workstreams/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|