sourcecode 1.4.0__tar.gz → 1.6.0__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.6.0/.continue-here.md +105 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/PKG-INFO +1 -1
- {sourcecode-1.4.0 → sourcecode-1.6.0}/pyproject.toml +1 -1
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/__init__.py +1 -1
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/architecture_analyzer.py +12 -1
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/ast_extractor.py +55 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/cli.py +0 -6
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/contract_pipeline.py +22 -3
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/dependency_analyzer.py +12 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/java.py +47 -5
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/serializer.py +31 -1
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_contract_pipeline.py +4 -4
- {sourcecode-1.4.0 → sourcecode-1.6.0}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/.gitignore +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/.ruff.toml +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/CONTRIBUTING.md +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/LICENSE +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/README.md +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/SECURITY.md +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/docs/privacy.md +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/docs/schema.md +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/raw +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/run_cli.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/classifier.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/redactor.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/scanner.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/schema.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/src/sourcecode/workspace.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/__init__.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/conftest.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/coverage.xml +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/fastapi_app/src/main.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/go_service/cmd/api/main.go +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/go_service/go.mod +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/jacoco.xml +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/lcov.info +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/nextjs_app/package.json +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/application/service/FindAusenteService.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/domain/entities/Ausente.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/infrastructure/rest/AusenteRestController.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/application/service/FindAutocoberturasService.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/domain/entities/Autocoberturas.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/infrastructure/rest/AutocoberturasRestController.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/application/service/FindCalendarioTrabajadorService.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/domain/entities/CalendarioTrabajador.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/infrastructure/rest/CalendarioTrabajadorRestController.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/application/service/FindDepartamentoService.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/domain/entities/Departamento.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/infrastructure/rest/DepartamentoRestController.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/application/service/FindEmpleadoService.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/domain/entities/Empleado.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/infrastructure/rest/EmpleadoRestController.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_architecture_analyzer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_architecture_summary.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_ast_extractor.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_block1_reliability.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_block2_coverage.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_block5_quality.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_classifier.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_cli.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_code_notes_analyzer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_context_scorer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_coverage_parser.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_cross_consistency.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_dependency_analyzer_node_python.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_dependency_analyzer_polyglot.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_dependency_schema.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_detector_dotnet.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_detector_go_rust_java.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_detector_nodejs.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_detector_php_ruby_dart.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_detector_python.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_detector_universal_managed.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_detector_universal_systems.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_detectors_base.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_doc_analyzer_jsdom.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_doc_analyzer_python.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_graph_analyzer_polyglot.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_graph_analyzer_python_node.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_graph_schema.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_hybrid_inference.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_integration.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_integration_dependencies.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_integration_detection.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_integration_docs.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_integration_graph_modules.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_integration_lqn.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_integration_metrics.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_integration_multistack.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_integration_semantics.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_integration_universal.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_java_spring_integration.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_metrics_analyzer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_packaging.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_phase1_improvements.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_pipeline_integrity.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_real_projects.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_redactor.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_scanner.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_schema.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_schema_normalization.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_semantic_analyzer_node.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_semantic_analyzer_python.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_semantic_import_resolution.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_semantic_schema.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_signal_hierarchy.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_summarizer.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_telemetry.py +0 -0
- {sourcecode-1.4.0 → sourcecode-1.6.0}/tests/test_workspace_analyzer.py +0 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Continue Here — sourcecode Java/Spring Enterprise Bug Fixes v1.5.x
|
|
2
|
+
**Created:** 2026-05-08
|
|
3
|
+
**Session context:** Ad-hoc benchmark-driven bug fixes (not a GSD phase execution)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What Was Done This Session
|
|
8
|
+
|
|
9
|
+
Applied 5 fixes targeting regressions in v1.5.0 benchmark report on saint-server (3681 .java, 460 *RestController*, 52 *Mapper.xml, Spring Boot 2.7.18 DDD+legacy layout).
|
|
10
|
+
|
|
11
|
+
### Root Causes Found and Fixed
|
|
12
|
+
|
|
13
|
+
| ID | File(s) | Root Cause | Fix |
|
|
14
|
+
|----|---------|-----------|-----|
|
|
15
|
+
| N1 | `detectors/java.py` | Scanner `depth >= max_depth=10` cuts `ddd/*/infraestructure/rest/` files silently. Path `src/main/java/com/m3/saint/ddd/domain/infraestructure/rest/` = 10 parts → excluded from file_tree → not in entry_points. | New `_augment_deep_java_controllers()`: direct `os.walk` of `src/main/java/` for `*Controller*.java` files not in file_tree |
|
|
16
|
+
| G3 | `contract_pipeline.py` | Mapper.xml score=0.3 (no `.xml` suffix boost) < Java score=0.4. 3000+ files compete for 2500-file cap — all 52 Mapper.xml cut. | `_is_priority()`: Mapper.xml gets same priority as entry_points in cap sort |
|
|
17
|
+
| T11 | `contract_pipeline.py` | Centrality sort key ignored `is_entrypoint`. REST controllers have low fan_in → ranked below JPA entities. | Added `-c.is_entrypoint` as primary key in centrality sort |
|
|
18
|
+
| P3-B | `cli.py` | Auto-switch to centrality when DDD architecture detected — actively hurt REST controller visibility. | Removed 5-line P3-B block |
|
|
19
|
+
| N2 | `serializer.py` | `hotspots` removed from top-level output in v1.5.0, only in `semantic_summary`. Breaking for consumers using `d["hotspots"]`. | Restore `result["hotspots"]` at top level when `semantic_summary.hotspots` exists |
|
|
20
|
+
|
|
21
|
+
### Modified Files (uncommitted — user requested no commits)
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
src/sourcecode/cli.py # P3-B removed (DDD auto-centrality switch)
|
|
25
|
+
src/sourcecode/contract_pipeline.py # G3: _is_priority() + T11: centrality sort key
|
|
26
|
+
src/sourcecode/detectors/java.py # N1: _augment_deep_java_controllers() method
|
|
27
|
+
src/sourcecode/serializer.py # N2: result["hotspots"] top-level restored
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Test Status
|
|
31
|
+
- 651 passed, 3 skipped (subset excluding pre-existing failures) — zero regressions
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## What Remains
|
|
36
|
+
|
|
37
|
+
### Not Fixed (deferred)
|
|
38
|
+
|
|
39
|
+
| ID | Description |
|
|
40
|
+
|----|-------------|
|
|
41
|
+
| M1 | `prepare-context` from monorepo root detects Angular instead of saint-server Java. Requires monorepo subproject routing in `prepare_context.py` → `TaskContextBuilder` / `RepoClassifier`. |
|
|
42
|
+
| M2 | `@M3FiltroSeguridad` custom security annotation not aggregated into security map |
|
|
43
|
+
| M3 | Spring profiles detected but not linked to `application-{profile}.yml` files |
|
|
44
|
+
|
|
45
|
+
### Verification Commands (run against saint-server after commit)
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# N1: DDD controllers now captured (need --depth 12+ for tree, augment works at any depth)
|
|
49
|
+
sourcecode saint-server --depth 12 --entrypoints-only --format json | python -c "
|
|
50
|
+
import sys, json
|
|
51
|
+
d = json.load(sys.stdin)
|
|
52
|
+
rest = [x for x in d.get('contracts', []) if 'RestController' in x.get('path','')]
|
|
53
|
+
ddd = [x for x in rest if '/ddd/' in x['path'] or '/infraestructure/' in x['path']]
|
|
54
|
+
print(f'REST total: {len(rest)} | DDD: {len(ddd)}')"
|
|
55
|
+
|
|
56
|
+
# G3: MyBatis XML in contracts
|
|
57
|
+
sourcecode saint-server --depth 10 --format json | python -c "
|
|
58
|
+
import sys, json
|
|
59
|
+
d = json.load(sys.stdin)
|
|
60
|
+
xml = [x for x in d.get('contracts', []) if x.get('language') == 'mybatis-xml']
|
|
61
|
+
print(f'MyBatis contracts: {len(xml)}')"
|
|
62
|
+
|
|
63
|
+
# N2: hotspots at top level restored
|
|
64
|
+
sourcecode saint-server --semantics --format json | python -c "
|
|
65
|
+
import sys, json
|
|
66
|
+
d = json.load(sys.stdin)
|
|
67
|
+
print('top-level hotspots:', len(d.get('hotspots', [])))
|
|
68
|
+
print('semantic_summary.hotspots:', len(d.get('semantic_summary',{}).get('hotspots',[])))"
|
|
69
|
+
|
|
70
|
+
# T11: centrality now surfaces REST controllers
|
|
71
|
+
sourcecode saint-server --rank-by centrality --depth 10 --format json | python -c "
|
|
72
|
+
import sys, json
|
|
73
|
+
d = json.load(sys.stdin)
|
|
74
|
+
rest = [x for x in d.get('contracts', []) if 'RestController' in x.get('path','')]
|
|
75
|
+
print(f'REST in centrality: {len(rest)}')"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Note on N1 depth:** `_augment_deep_java_controllers` bypasses the scanner depth limit and always walks `src/main/java/` directly. DDD controllers will be detected as entry_points regardless of `--depth`. However, for these same files to appear in the general file_paths (not just entry_points), the scanner itself needs `--depth >= 11`.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Previous Session Fixes (already committed)
|
|
83
|
+
|
|
84
|
+
C1/C2/C3/G1/G2/G3 from v1.4.0→v1.5.0:
|
|
85
|
+
- `--mode standard` key `file_contracts` → `contracts`
|
|
86
|
+
- Controller-first scan, cap 500→1000
|
|
87
|
+
- DDD bounded contexts from package structure
|
|
88
|
+
- Maven BOM limitation warning
|
|
89
|
+
- MyBatis XML extractor (code existed but files were cut by cap — fixed in this session)
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## GSD Project State (unchanged)
|
|
94
|
+
|
|
95
|
+
All 13 phases complete (see `.planning/STATE.md`). Both sessions were ad-hoc bug work from benchmark reports, not planned phase executions.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Resume Instructions
|
|
100
|
+
|
|
101
|
+
1. `git diff --stat` — verify 4 uncommitted files
|
|
102
|
+
2. `python -m pytest tests/ --ignore=tests/test_block2_coverage.py --ignore=tests/test_dependency_analyzer_node_python.py --ignore=tests/test_pipeline_integrity.py -q`
|
|
103
|
+
3. Commit the fixes
|
|
104
|
+
4. Run verification commands above against saint-server
|
|
105
|
+
5. If tackling M1, entry point is `prepare_context.py:TaskContextBuilder.build()` + `repo_classifier.py`
|
|
@@ -182,8 +182,19 @@ class ArchitectureAnalyzer:
|
|
|
182
182
|
ddd_result = self._detect_ddd(sm.file_paths)
|
|
183
183
|
if ddd_result is not None:
|
|
184
184
|
ddd_pattern, ddd_layers, ddd_contexts, ddd_layer_names = ddd_result
|
|
185
|
-
domains_for_ddd = self._cluster_domains(filtered) if len(filtered) >= 2 else []
|
|
186
185
|
module_files = self._build_ddd_module_files(sm.file_paths, ddd_contexts)
|
|
186
|
+
# Use DDD bounded context names as domains so --architecture shows each
|
|
187
|
+
# context as a distinct domain instead of collapsing all files under
|
|
188
|
+
# the Maven path segment (e.g. "java").
|
|
189
|
+
domains_for_ddd = [
|
|
190
|
+
ArchitectureDomain(
|
|
191
|
+
name=n,
|
|
192
|
+
files=module_files.get(n, []),
|
|
193
|
+
role="DDD bounded context",
|
|
194
|
+
confidence="high",
|
|
195
|
+
)
|
|
196
|
+
for n in ddd_contexts
|
|
197
|
+
]
|
|
187
198
|
bc_list = [
|
|
188
199
|
BoundedContext(name=n, modules=module_files.get(n, []), confidence="high")
|
|
189
200
|
for n in ddd_contexts
|
|
@@ -1172,6 +1172,51 @@ def _detect_role(path: str, contract: FileContract) -> str:
|
|
|
1172
1172
|
return "util"
|
|
1173
1173
|
|
|
1174
1174
|
|
|
1175
|
+
# ---------------------------------------------------------------------------
|
|
1176
|
+
# MyBatis XML mapper extractor
|
|
1177
|
+
# ---------------------------------------------------------------------------
|
|
1178
|
+
|
|
1179
|
+
def _extract_mybatis_xml(rel_path: str, source: str) -> FileContract:
|
|
1180
|
+
"""Extract namespace and SQL operations from a MyBatis *Mapper.xml file."""
|
|
1181
|
+
import re as _re
|
|
1182
|
+
from xml.etree import ElementTree
|
|
1183
|
+
|
|
1184
|
+
_NS_STRIP = _re.compile(r"\{[^}]+\}")
|
|
1185
|
+
_SQL_OPS = frozenset({"select", "insert", "update", "delete"})
|
|
1186
|
+
|
|
1187
|
+
exports: list[ExportRecord] = []
|
|
1188
|
+
namespace: str | None = None
|
|
1189
|
+
|
|
1190
|
+
try:
|
|
1191
|
+
root_elem = ElementTree.fromstring(source.encode("utf-8"))
|
|
1192
|
+
namespace = root_elem.get("namespace") or None
|
|
1193
|
+
for elem in root_elem:
|
|
1194
|
+
tag = _NS_STRIP.sub("", elem.tag).lower()
|
|
1195
|
+
if tag in _SQL_OPS:
|
|
1196
|
+
op_id = (elem.get("id") or "").strip()
|
|
1197
|
+
if op_id:
|
|
1198
|
+
# type_ref carries select/insert/update/delete for the serializer
|
|
1199
|
+
exports.append(ExportRecord(kind="query", name=op_id, type_ref=tag))
|
|
1200
|
+
except Exception:
|
|
1201
|
+
return FileContract(
|
|
1202
|
+
path=rel_path,
|
|
1203
|
+
language="mybatis-xml",
|
|
1204
|
+
role="mybatis-mapper",
|
|
1205
|
+
extraction_method="heuristic",
|
|
1206
|
+
limitations=["xml_parse_error: failed to parse mapper XML"],
|
|
1207
|
+
)
|
|
1208
|
+
|
|
1209
|
+
deps = [f"namespace:{namespace}"] if namespace else []
|
|
1210
|
+
return FileContract(
|
|
1211
|
+
path=rel_path,
|
|
1212
|
+
language="mybatis-xml",
|
|
1213
|
+
role="mybatis-mapper",
|
|
1214
|
+
exports=exports,
|
|
1215
|
+
dependencies=deps,
|
|
1216
|
+
extraction_method="heuristic",
|
|
1217
|
+
)
|
|
1218
|
+
|
|
1219
|
+
|
|
1175
1220
|
# ---------------------------------------------------------------------------
|
|
1176
1221
|
# AstExtractor public class
|
|
1177
1222
|
# ---------------------------------------------------------------------------
|
|
@@ -1191,6 +1236,16 @@ class AstExtractor:
|
|
|
1191
1236
|
return self._ts_ok
|
|
1192
1237
|
|
|
1193
1238
|
def extract(self, path: Path, root: Optional[Path] = None) -> Optional[FileContract]:
|
|
1239
|
+
# MyBatis mapper XML — handled before the language map lookup so .xml
|
|
1240
|
+
# files are only processed when they match the mapper naming convention.
|
|
1241
|
+
if path.suffix.lower() == ".xml" and path.name.endswith("Mapper.xml"):
|
|
1242
|
+
try:
|
|
1243
|
+
source = path.read_text(encoding="utf-8", errors="replace")
|
|
1244
|
+
except OSError:
|
|
1245
|
+
return None
|
|
1246
|
+
rel_path = str(path.relative_to(root)).replace("\\", "/") if root else path.name
|
|
1247
|
+
return _extract_mybatis_xml(rel_path, source)
|
|
1248
|
+
|
|
1194
1249
|
ext = path.suffix.lower()
|
|
1195
1250
|
language = _LANGUAGE_MAP.get(ext)
|
|
1196
1251
|
if language is None:
|
|
@@ -1399,12 +1399,6 @@ def main(
|
|
|
1399
1399
|
))
|
|
1400
1400
|
sm = _replace(sm, pipeline_trace=_trace.build_trace())
|
|
1401
1401
|
|
|
1402
|
-
# P3-B: Auto-switch to centrality ranking when DDD layout detected
|
|
1403
|
-
if (rank_by == "relevance"
|
|
1404
|
-
and sm.architecture is not None
|
|
1405
|
-
and sm.architecture.pattern == "ddd"):
|
|
1406
|
-
rank_by = "centrality"
|
|
1407
|
-
|
|
1408
1402
|
# Contract pipeline — runs for mode=contract|standard|deep|hybrid (skip for raw)
|
|
1409
1403
|
_is_contract_mode = mode in ("contract", "standard")
|
|
1410
1404
|
_pipeline_error = False
|
|
@@ -219,9 +219,18 @@ class ContractPipeline:
|
|
|
219
219
|
fname = Path(pn).name
|
|
220
220
|
return any(fname.startswith(pat) or f".{pat.strip('.')}" in fname for pat in _TEST_PATTERNS)
|
|
221
221
|
|
|
222
|
+
def _is_extractable(p: str) -> bool:
|
|
223
|
+
suf = Path(p).suffix.lower()
|
|
224
|
+
if suf in _SRC_EXTENSIONS:
|
|
225
|
+
return True
|
|
226
|
+
# MyBatis mapper XML files — only *Mapper.xml, not all XML
|
|
227
|
+
if suf == ".xml" and p.endswith("Mapper.xml"):
|
|
228
|
+
return True
|
|
229
|
+
return False
|
|
230
|
+
|
|
222
231
|
src_paths = [
|
|
223
232
|
p for p in file_paths
|
|
224
|
-
if
|
|
233
|
+
if _is_extractable(p)
|
|
225
234
|
and not scorer.is_noise(p)
|
|
226
235
|
and (symbol is not None or changed_only or not _is_test(p))
|
|
227
236
|
]
|
|
@@ -231,10 +240,18 @@ class ContractPipeline:
|
|
|
231
240
|
|
|
232
241
|
# Apply max_files cap — bypass when symbol search to ensure defining files are found.
|
|
233
242
|
# A symbol query over a large repo needs all files; result set is small after filtering.
|
|
243
|
+
# MyBatis Mapper.xml contracts rank below Java files on path score alone (.xml has no
|
|
244
|
+
# suffix boost). Give them the same priority slot as entry_points so they survive the cap.
|
|
245
|
+
def _is_priority(p: str) -> bool:
|
|
246
|
+
if p in entry_paths:
|
|
247
|
+
return True
|
|
248
|
+
name = p.rsplit("/", 1)[-1]
|
|
249
|
+
return name.lower().endswith("mapper.xml")
|
|
250
|
+
|
|
234
251
|
if symbol is None and len(src_paths) > self.max_files:
|
|
235
252
|
src_paths = sorted(
|
|
236
253
|
src_paths,
|
|
237
|
-
key=lambda p: (p
|
|
254
|
+
key=lambda p: (_is_priority(p), scorer.score(p)),
|
|
238
255
|
reverse=True,
|
|
239
256
|
)[:self.max_files]
|
|
240
257
|
|
|
@@ -353,7 +370,9 @@ class ContractPipeline:
|
|
|
353
370
|
|
|
354
371
|
def _rank(self, contracts: list[FileContract], rank_by: RankStrategy) -> list[FileContract]:
|
|
355
372
|
if rank_by == "centrality":
|
|
356
|
-
|
|
373
|
+
# Entrypoints (REST controllers, main classes) surface first even in centrality mode:
|
|
374
|
+
# they have low fan_in (not imported) but are the primary API surface.
|
|
375
|
+
return sorted(contracts, key=lambda c: (-c.is_entrypoint, -(c.fan_in + c.fan_out), c.path))
|
|
357
376
|
if rank_by == "git-churn":
|
|
358
377
|
return sorted(contracts, key=lambda c: (-c.is_changed, -c.relevance_score, c.path))
|
|
359
378
|
# Default: relevance — path breaks ties deterministically
|
|
@@ -1191,6 +1191,18 @@ class DependencyAnalyzer:
|
|
|
1191
1191
|
limitations: list[str] = []
|
|
1192
1192
|
if not records:
|
|
1193
1193
|
limitations.append("java: pom.xml sin dependencias parseables (puede usar BOM o propiedades)")
|
|
1194
|
+
|
|
1195
|
+
# Warn when Spring Boot BOM manages transitive deps — they can't be resolved statically.
|
|
1196
|
+
parent_artifact_local = (
|
|
1197
|
+
root_elem.findtext(f"{ns}parent/{ns}artifactId") or ""
|
|
1198
|
+
).strip() if parent_elem is not None else ""
|
|
1199
|
+
if parent_artifact_local == "spring-boot-starter-parent" and parent_version:
|
|
1200
|
+
limitations.append(
|
|
1201
|
+
f"spring_boot_bom_detected: transitive deps managed by Spring Boot BOM "
|
|
1202
|
+
f"v{parent_version}, not resolved statically. "
|
|
1203
|
+
"Run 'mvn dependency:tree' for the full transitive tree."
|
|
1204
|
+
)
|
|
1205
|
+
|
|
1194
1206
|
return records, limitations
|
|
1195
1207
|
|
|
1196
1208
|
def _analyze_gradle(self, root: Path) -> tuple[list[DependencyRecord], list[str]]:
|
|
@@ -18,7 +18,7 @@ _NS_TAG_RE = re.compile(r"\{[^}]+\}")
|
|
|
18
18
|
|
|
19
19
|
_MAX_FILE_SIZE = 256 * 1024 # 256 KB
|
|
20
20
|
_MAX_JAVA_ENTRY_SCAN = 1000
|
|
21
|
-
_MAX_ANNOTATION_ENTRY_POINTS =
|
|
21
|
+
_MAX_ANNOTATION_ENTRY_POINTS = 1000
|
|
22
22
|
|
|
23
23
|
_REST_CONTROLLER_RE = re.compile(r'@RestController\b')
|
|
24
24
|
_MVC_CONTROLLER_RE = re.compile(r'@Controller\b')
|
|
@@ -225,6 +225,12 @@ class JavaDetector(AbstractDetector):
|
|
|
225
225
|
all_paths = flatten_file_tree(context.file_tree)
|
|
226
226
|
all_java = [p for p in all_paths if p.endswith(".java")]
|
|
227
227
|
|
|
228
|
+
# Augment with a direct scan of standard Java source roots for Controller-named
|
|
229
|
+
# files that the depth-limited file_tree scanner may have missed.
|
|
230
|
+
# DDD layouts place REST controllers at depth 10+ (e.g.
|
|
231
|
+
# src/main/java/com/org/app/ddd/domain/infraestructure/rest/XxxRestController.java).
|
|
232
|
+
self._augment_deep_java_controllers(context, all_java)
|
|
233
|
+
|
|
228
234
|
# 1. @SpringBootApplication entry: Application.java / Main.java by name
|
|
229
235
|
app_candidates = [
|
|
230
236
|
p for p in all_java
|
|
@@ -236,10 +242,12 @@ class JavaDetector(AbstractDetector):
|
|
|
236
242
|
]
|
|
237
243
|
|
|
238
244
|
# 2. Annotation-based scan: @RestController, @WebFilter, FilterRegistrationBean
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
245
|
+
# Prioritize Controller-named files so all REST controllers are detected
|
|
246
|
+
# even in large codebases where total files > _MAX_JAVA_ENTRY_SCAN.
|
|
247
|
+
_non_test = [p for p in all_java if "/test/" not in p and "/tests/" not in p]
|
|
248
|
+
_ctrl_files = [p for p in _non_test if "Controller" in p]
|
|
249
|
+
_other_files = [p for p in _non_test if "Controller" not in p]
|
|
250
|
+
scan_candidates = _ctrl_files + _other_files[:max(0, _MAX_JAVA_ENTRY_SCAN - len(_ctrl_files))]
|
|
243
251
|
|
|
244
252
|
annotation_eps: list[EntryPoint] = []
|
|
245
253
|
for rel_path in scan_candidates:
|
|
@@ -268,6 +276,40 @@ class JavaDetector(AbstractDetector):
|
|
|
268
276
|
unique_eps.append(ep)
|
|
269
277
|
return unique_eps
|
|
270
278
|
|
|
279
|
+
def _augment_deep_java_controllers(self, context: DetectionContext, all_java: list[str]) -> None:
|
|
280
|
+
"""Scan standard Java source roots for *Controller*.java files not in all_java.
|
|
281
|
+
|
|
282
|
+
The depth-limited file_tree scanner misses files at depth >= max_depth.
|
|
283
|
+
DDD layouts place REST controllers deep (e.g. depth 10+), so we supplement
|
|
284
|
+
with a direct filesystem walk scoped to the standard Maven/Gradle source root.
|
|
285
|
+
"""
|
|
286
|
+
import os as _os
|
|
287
|
+
existing = set(all_java)
|
|
288
|
+
# Standard Java source root candidates (Maven first, then Gradle/other)
|
|
289
|
+
_SRC_ROOTS = ("src/main/java", "src/main/kotlin", "src/java", "src")
|
|
290
|
+
for src_root_name in _SRC_ROOTS:
|
|
291
|
+
src_root = context.root / src_root_name
|
|
292
|
+
if not src_root.is_dir():
|
|
293
|
+
continue
|
|
294
|
+
try:
|
|
295
|
+
for dirpath, _dirs, filenames in _os.walk(str(src_root)):
|
|
296
|
+
for fname in filenames:
|
|
297
|
+
if "Controller" not in fname or not fname.endswith(".java"):
|
|
298
|
+
continue
|
|
299
|
+
full = Path(dirpath) / fname
|
|
300
|
+
if full.is_symlink():
|
|
301
|
+
continue
|
|
302
|
+
try:
|
|
303
|
+
rel = str(full.relative_to(context.root)).replace("\\", "/")
|
|
304
|
+
if rel not in existing:
|
|
305
|
+
all_java.append(rel)
|
|
306
|
+
existing.add(rel)
|
|
307
|
+
except ValueError:
|
|
308
|
+
pass
|
|
309
|
+
except OSError:
|
|
310
|
+
pass
|
|
311
|
+
return # use only first matching source root
|
|
312
|
+
|
|
271
313
|
def _scan_java_file_for_entry_points(self, abs_path: Path, rel_path: str) -> list[EntryPoint]:
|
|
272
314
|
try:
|
|
273
315
|
if abs_path.stat().st_size > _MAX_FILE_SIZE:
|
|
@@ -1110,6 +1110,10 @@ def standard_view(sm: SourceMap, *, include_tree: bool = False) -> dict[str, Any
|
|
|
1110
1110
|
|
|
1111
1111
|
if sm.semantic_summary is not None and sm.semantic_summary.requested:
|
|
1112
1112
|
result["semantic_summary"] = asdict(sm.semantic_summary)
|
|
1113
|
+
# Backward compat: also emit hotspots at top level (moved to semantic_summary in v1.5.0).
|
|
1114
|
+
# Consumers reading d["hotspots"] directly still work.
|
|
1115
|
+
if sm.semantic_summary.hotspots:
|
|
1116
|
+
result["hotspots"] = sm.semantic_summary.hotspots[:10]
|
|
1113
1117
|
# Defensive filter: never emit objects with null required fields.
|
|
1114
1118
|
# A null entry in these arrays is worse than a shorter array — it causes
|
|
1115
1119
|
# agents to misinterpret the analysis as valid when it is not.
|
|
@@ -1439,10 +1443,31 @@ def _serialize_contract_java(c: Any) -> dict[str, Any]:
|
|
|
1439
1443
|
return item
|
|
1440
1444
|
|
|
1441
1445
|
|
|
1446
|
+
def _serialize_contract_mybatis_xml(c: Any) -> dict[str, Any]:
|
|
1447
|
+
"""Serialize a MyBatis *Mapper.xml contract."""
|
|
1448
|
+
item: dict[str, Any] = {"path": c.path, "language": "mybatis-xml"}
|
|
1449
|
+
# Extract namespace stored as "namespace:<fqn>" in dependencies
|
|
1450
|
+
for dep in (c.dependencies or []):
|
|
1451
|
+
if dep.startswith("namespace:"):
|
|
1452
|
+
item["namespace"] = dep[len("namespace:"):]
|
|
1453
|
+
break
|
|
1454
|
+
exports_out: list[dict] = []
|
|
1455
|
+
for e in c.exports:
|
|
1456
|
+
entry: dict = {"kind": e.kind, "name": e.name}
|
|
1457
|
+
if getattr(e, "type_ref", None):
|
|
1458
|
+
entry["type"] = e.type_ref
|
|
1459
|
+
exports_out.append(entry)
|
|
1460
|
+
if exports_out:
|
|
1461
|
+
item["exports"] = exports_out
|
|
1462
|
+
return item
|
|
1463
|
+
|
|
1464
|
+
|
|
1442
1465
|
def _serialize_contract_minimal(c: Any) -> dict[str, Any]:
|
|
1443
1466
|
"""Serialize one FileContract to minimal format."""
|
|
1444
1467
|
if getattr(c, "language", None) == "java":
|
|
1445
1468
|
return _serialize_contract_java(c)
|
|
1469
|
+
if getattr(c, "language", None) == "mybatis-xml":
|
|
1470
|
+
return _serialize_contract_mybatis_xml(c)
|
|
1446
1471
|
item: dict[str, Any] = {"path": c.path, "role": c.role}
|
|
1447
1472
|
|
|
1448
1473
|
if c.is_changed:
|
|
@@ -1560,6 +1585,11 @@ def _contract_view_standard(
|
|
|
1560
1585
|
if contracts:
|
|
1561
1586
|
serialized: list[dict[str, Any]] = []
|
|
1562
1587
|
for c in contracts:
|
|
1588
|
+
if getattr(c, "language", None) == "mybatis-xml":
|
|
1589
|
+
item = _serialize_contract_mybatis_xml(c)
|
|
1590
|
+
item["relevance_score"] = round(c.relevance_score, 3)
|
|
1591
|
+
serialized.append(item)
|
|
1592
|
+
continue
|
|
1563
1593
|
item: dict[str, Any] = {
|
|
1564
1594
|
"path": c.path,
|
|
1565
1595
|
"language": c.language,
|
|
@@ -1609,7 +1639,7 @@ def _contract_view_standard(
|
|
|
1609
1639
|
item["ranking_reasons"] = non_trivial
|
|
1610
1640
|
item["method"] = c.extraction_method
|
|
1611
1641
|
serialized.append(item)
|
|
1612
|
-
result["
|
|
1642
|
+
result["contracts"] = serialized
|
|
1613
1643
|
|
|
1614
1644
|
# Optional analysis sections (deep mode or when analyzers ran)
|
|
1615
1645
|
if include_optional:
|
|
@@ -188,7 +188,7 @@ def test_cli_raw_mode_preserves_standard_output(tmp_path: Path) -> None:
|
|
|
188
188
|
data = json.loads(result.output)
|
|
189
189
|
assert "metadata" in data
|
|
190
190
|
assert data["metadata"]["schema_version"] == "1.0"
|
|
191
|
-
assert "
|
|
191
|
+
assert "contracts" not in data
|
|
192
192
|
|
|
193
193
|
|
|
194
194
|
def test_cli_max_symbols_flag(tmp_path: Path) -> None:
|
|
@@ -198,11 +198,11 @@ def test_cli_max_symbols_flag(tmp_path: Path) -> None:
|
|
|
198
198
|
f"def func{i}a(): pass\ndef func{i}b(): pass\n"
|
|
199
199
|
)
|
|
200
200
|
|
|
201
|
-
# Use --mode standard to get
|
|
201
|
+
# Use --mode standard to get contracts with full per-symbol detail
|
|
202
202
|
result = runner.invoke(app, ["--mode", "standard", "--max-symbols", "5", str(tmp_path)])
|
|
203
203
|
assert result.exit_code == 0, result.output
|
|
204
204
|
data = json.loads(result.output)
|
|
205
|
-
contracts = data.get("
|
|
205
|
+
contracts = data.get("contracts", [])
|
|
206
206
|
total = sum(
|
|
207
207
|
len(c.get("exports", [])) + len(c.get("functions", [])) + len(c.get("types", []))
|
|
208
208
|
for c in contracts
|
|
@@ -250,7 +250,7 @@ def test_cli_standard_mode_includes_detail_fields(tmp_path: Path) -> None:
|
|
|
250
250
|
assert "schema_version" in data
|
|
251
251
|
assert "stacks" in data
|
|
252
252
|
assert "entry_points" in data
|
|
253
|
-
assert "
|
|
253
|
+
assert "contracts" in data
|
|
254
254
|
|
|
255
255
|
|
|
256
256
|
def test_cli_invalid_mode_exits_nonzero(tmp_path: Path) -> None:
|
{sourcecode-1.4.0 → sourcecode-1.6.0}/.agents/skills/source-command-gsd-join-discord/SKILL.md
RENAMED
|
File without changes
|
{sourcecode-1.4.0 → sourcecode-1.6.0}/.agents/skills/source-command-gsd-review-backlog/SKILL.md
RENAMED
|
File without changes
|
{sourcecode-1.4.0 → sourcecode-1.6.0}/.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sourcecode-1.4.0 → sourcecode-1.6.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|