sourcecode 1.5.0__tar.gz → 1.7.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.
Files changed (180) hide show
  1. sourcecode-1.7.0/.continue-here.md +105 -0
  2. {sourcecode-1.5.0 → sourcecode-1.7.0}/PKG-INFO +1 -1
  3. {sourcecode-1.5.0 → sourcecode-1.7.0}/pyproject.toml +1 -1
  4. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/__init__.py +1 -1
  5. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/adaptive_scanner.py +2 -1
  6. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/cli.py +61 -44
  7. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/contract_pipeline.py +19 -3
  8. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/java.py +40 -0
  9. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/prepare_context.py +74 -5
  10. sourcecode-1.7.0/src/sourcecode/progress.py +110 -0
  11. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/serializer.py +4 -0
  12. sourcecode-1.7.0/tests/test_bug_fixes_v16.py +250 -0
  13. {sourcecode-1.5.0 → sourcecode-1.7.0}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
  14. {sourcecode-1.5.0 → sourcecode-1.7.0}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
  15. {sourcecode-1.5.0 → sourcecode-1.7.0}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
  16. {sourcecode-1.5.0 → sourcecode-1.7.0}/.github/workflows/build-windows.yml +0 -0
  17. {sourcecode-1.5.0 → sourcecode-1.7.0}/.gitignore +0 -0
  18. {sourcecode-1.5.0 → sourcecode-1.7.0}/.ruff.toml +0 -0
  19. {sourcecode-1.5.0 → sourcecode-1.7.0}/CONTRIBUTING.md +0 -0
  20. {sourcecode-1.5.0 → sourcecode-1.7.0}/LICENSE +0 -0
  21. {sourcecode-1.5.0 → sourcecode-1.7.0}/README.md +0 -0
  22. {sourcecode-1.5.0 → sourcecode-1.7.0}/SECURITY.md +0 -0
  23. {sourcecode-1.5.0 → sourcecode-1.7.0}/docs/privacy.md +0 -0
  24. {sourcecode-1.5.0 → sourcecode-1.7.0}/docs/schema.md +0 -0
  25. {sourcecode-1.5.0 → sourcecode-1.7.0}/raw +0 -0
  26. {sourcecode-1.5.0 → sourcecode-1.7.0}/run_cli.py +0 -0
  27. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/architecture_analyzer.py +0 -0
  28. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/architecture_summary.py +0 -0
  29. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/ast_extractor.py +0 -0
  30. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/classifier.py +0 -0
  31. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  32. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/confidence_analyzer.py +0 -0
  33. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/context_scorer.py +0 -0
  34. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/context_summarizer.py +0 -0
  35. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/contract_model.py +0 -0
  36. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/coverage_parser.py +0 -0
  37. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/dependency_analyzer.py +0 -0
  38. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/__init__.py +0 -0
  39. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/base.py +0 -0
  40. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  41. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/dart.py +0 -0
  42. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/dotnet.py +0 -0
  43. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/elixir.py +0 -0
  44. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/go.py +0 -0
  45. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/heuristic.py +0 -0
  46. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/hybrid.py +0 -0
  47. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  48. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/nodejs.py +0 -0
  49. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/parsers.py +0 -0
  50. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/php.py +0 -0
  51. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/project.py +0 -0
  52. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/python.py +0 -0
  53. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/ruby.py +0 -0
  54. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/rust.py +0 -0
  55. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/systems.py +0 -0
  56. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/terraform.py +0 -0
  57. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/detectors/tooling.py +0 -0
  58. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/doc_analyzer.py +0 -0
  59. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  60. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/env_analyzer.py +0 -0
  61. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/file_classifier.py +0 -0
  62. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/git_analyzer.py +0 -0
  63. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/graph_analyzer.py +0 -0
  64. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/metrics_analyzer.py +0 -0
  65. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/ranking_engine.py +0 -0
  66. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/redactor.py +0 -0
  67. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/relevance_scorer.py +0 -0
  68. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/repo_classifier.py +0 -0
  69. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/runtime_classifier.py +0 -0
  70. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/scanner.py +0 -0
  71. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/schema.py +0 -0
  72. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/semantic_analyzer.py +0 -0
  73. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/summarizer.py +0 -0
  74. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/telemetry/__init__.py +0 -0
  75. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/telemetry/config.py +0 -0
  76. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/telemetry/consent.py +0 -0
  77. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/telemetry/events.py +0 -0
  78. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/telemetry/filters.py +0 -0
  79. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/telemetry/transport.py +0 -0
  80. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/tree_utils.py +0 -0
  81. {sourcecode-1.5.0 → sourcecode-1.7.0}/src/sourcecode/workspace.py +0 -0
  82. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/__init__.py +0 -0
  83. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/conftest.py +0 -0
  84. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/coverage.xml +0 -0
  85. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
  86. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/fastapi_app/src/main.py +0 -0
  87. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/go_service/cmd/api/main.go +0 -0
  88. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/go_service/go.mod +0 -0
  89. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/jacoco.xml +0 -0
  90. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/lcov.info +0 -0
  91. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
  92. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/nextjs_app/package.json +0 -0
  93. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
  94. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
  95. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
  96. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
  97. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
  98. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
  99. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
  100. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/application/service/FindAusenteService.java +0 -0
  101. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/domain/entities/Ausente.java +0 -0
  102. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/infrastructure/rest/AusenteRestController.java +0 -0
  103. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/application/service/FindAutocoberturasService.java +0 -0
  104. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/domain/entities/Autocoberturas.java +0 -0
  105. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/infrastructure/rest/AutocoberturasRestController.java +0 -0
  106. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/application/service/FindCalendarioTrabajadorService.java +0 -0
  107. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/domain/entities/CalendarioTrabajador.java +0 -0
  108. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/infrastructure/rest/CalendarioTrabajadorRestController.java +0 -0
  109. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/application/service/FindDepartamentoService.java +0 -0
  110. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/domain/entities/Departamento.java +0 -0
  111. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/infrastructure/rest/DepartamentoRestController.java +0 -0
  112. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/application/service/FindEmpleadoService.java +0 -0
  113. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/domain/entities/Empleado.java +0 -0
  114. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/infrastructure/rest/EmpleadoRestController.java +0 -0
  115. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
  116. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
  117. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
  118. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
  119. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
  120. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
  121. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
  122. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
  123. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_architecture_analyzer.py +0 -0
  124. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_architecture_summary.py +0 -0
  125. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_ast_extractor.py +0 -0
  126. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_block1_reliability.py +0 -0
  127. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_block2_coverage.py +0 -0
  128. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_block5_quality.py +0 -0
  129. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_classifier.py +0 -0
  130. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_cli.py +0 -0
  131. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_code_notes_analyzer.py +0 -0
  132. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_context_scorer.py +0 -0
  133. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_contract_pipeline.py +0 -0
  134. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_coverage_parser.py +0 -0
  135. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_cross_consistency.py +0 -0
  136. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_dependency_analyzer_node_python.py +0 -0
  137. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_dependency_analyzer_polyglot.py +0 -0
  138. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_dependency_schema.py +0 -0
  139. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_detector_dotnet.py +0 -0
  140. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_detector_go_rust_java.py +0 -0
  141. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_detector_nodejs.py +0 -0
  142. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_detector_php_ruby_dart.py +0 -0
  143. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_detector_python.py +0 -0
  144. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_detector_universal_managed.py +0 -0
  145. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_detector_universal_systems.py +0 -0
  146. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_detectors_base.py +0 -0
  147. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_doc_analyzer_jsdom.py +0 -0
  148. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_doc_analyzer_python.py +0 -0
  149. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_graph_analyzer_polyglot.py +0 -0
  150. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_graph_analyzer_python_node.py +0 -0
  151. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_graph_schema.py +0 -0
  152. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_hybrid_inference.py +0 -0
  153. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_integration.py +0 -0
  154. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_integration_dependencies.py +0 -0
  155. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_integration_detection.py +0 -0
  156. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_integration_docs.py +0 -0
  157. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_integration_graph_modules.py +0 -0
  158. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_integration_lqn.py +0 -0
  159. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_integration_metrics.py +0 -0
  160. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_integration_multistack.py +0 -0
  161. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_integration_semantics.py +0 -0
  162. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_integration_universal.py +0 -0
  163. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_java_spring_integration.py +0 -0
  164. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_metrics_analyzer.py +0 -0
  165. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_packaging.py +0 -0
  166. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_phase1_improvements.py +0 -0
  167. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_pipeline_integrity.py +0 -0
  168. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_real_projects.py +0 -0
  169. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_redactor.py +0 -0
  170. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_scanner.py +0 -0
  171. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_schema.py +0 -0
  172. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_schema_normalization.py +0 -0
  173. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_semantic_analyzer_node.py +0 -0
  174. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_semantic_analyzer_python.py +0 -0
  175. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_semantic_import_resolution.py +0 -0
  176. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_semantic_schema.py +0 -0
  177. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_signal_hierarchy.py +0 -0
  178. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_summarizer.py +0 -0
  179. {sourcecode-1.5.0 → sourcecode-1.7.0}/tests/test_telemetry.py +0 -0
  180. {sourcecode-1.5.0 → sourcecode-1.7.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`
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 1.5.0
3
+ Version: 1.7.0
4
4
  Summary: Deterministic codebase context for AI coding agents
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "1.5.0"
7
+ version = "1.7.0"
8
8
  description = "Deterministic codebase context for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1,3 +1,3 @@
1
1
  """sourcecode — Deterministic codebase context maps for AI coding agents."""
2
2
 
3
- __version__ = "1.5.0"
3
+ __version__ = "1.7.0"
@@ -135,7 +135,8 @@ class AdaptiveScanner:
135
135
  if current_depth >= n:
136
136
  # At or inside the source root
137
137
  if rel_parts[:n] == src_parts:
138
- return src_max # definite source territoryearly exit
138
+ # base_depth acts as a floor explicit --depth always wins
139
+ return max(src_max, self.base_depth)
139
140
  else:
140
141
  # Ancestor check: src_parts starts with rel_parts?
141
142
  if src_parts[:current_depth] == rel_parts:
@@ -10,6 +10,7 @@ import typer
10
10
 
11
11
  from sourcecode import __version__
12
12
  from sourcecode.entrypoint_classifier import is_production_entry_point, normalize_entry_point
13
+ from sourcecode.progress import Progress
13
14
 
14
15
 
15
16
  # ---------------------------------------------------------------------------
@@ -138,18 +139,19 @@ def _check_pipeline_coherence(sm: "SourceMap") -> list[str]: # type: ignore[nam
138
139
  return issues
139
140
 
140
141
  _HELP = """\
141
- Deterministic codebase context for AI coding agents.
142
+ Compressed AI-ready context for Java/Spring enterprise codebases.
142
143
 
143
- [bold]Usage:[/bold]
144
- sourcecode [dim]# analyze current directory[/dim]
145
- sourcecode /path/to/repo [dim]# analyze specific path[/dim]
146
- sourcecode --agent [dim]# structured output for AI agents[/dim]
144
+ [bold]Examples:[/bold]
145
+ sourcecode saint-server --compact
146
+ sourcecode . --changed-only --git-context
147
+ sourcecode saint-server --symbol SeguridadRestController
148
+ sourcecode prepare-context onboard saint-server
149
+ sourcecode prepare-context delta . --since main
147
150
 
148
151
  [bold]Subcommands:[/bold]
149
- prepare-context TASK [PATH] [dim]# task-specific context[/dim]
152
+ prepare-context TASK [PATH] [dim]# task-specific context (onboard, delta, fix-bug, ...)[/dim]
150
153
  telemetry status|enable|disable
151
154
  version
152
- config
153
155
  """
154
156
 
155
157
  # Known subcommand names — tokens matching these are routed as subcommands,
@@ -382,28 +384,28 @@ def main(
382
384
  graph_modules: bool = typer.Option(
383
385
  False,
384
386
  "--graph-modules",
385
- help=(
386
- "Include a structural module graph: nodes (files/symbols) and edges (imports, calls, contains). "
387
- "Useful for understanding coupling and call flows. Adds module_graph to output. "
388
- "Combine with --graph-detail and --graph-edges to control scope."
389
- ),
387
+ hidden=True,
388
+ help="Include a structural module graph in output.",
390
389
  ),
391
390
  graph_detail: str = typer.Option(
392
391
  "high",
393
392
  "--graph-detail",
394
- help="Detail level for --graph-modules: high (top modules by importance), medium (filtered by relevance), full (all nodes and edges). Default: high.",
393
+ hidden=True,
394
+ help="Detail level for --graph-modules: high, medium, full.",
395
395
  show_default=True,
396
396
  ),
397
397
  max_nodes: Optional[int] = typer.Option(
398
398
  None,
399
399
  "--max-nodes",
400
- help="Maximum number of nodes in --graph-modules output when using high or medium detail. Prevents oversized graphs in large codebases.",
400
+ hidden=True,
401
+ help="Maximum nodes in --graph-modules output.",
401
402
  min=1,
402
403
  ),
403
404
  graph_edges: Optional[str] = typer.Option(
404
405
  None,
405
406
  "--graph-edges",
406
- help="Edge types for --graph-modules, comma-separated: imports,calls,contains,extends. Default: all available. Example: --graph-edges imports,calls",
407
+ hidden=True,
408
+ help="Edge types for --graph-modules, comma-separated: imports,calls,contains,extends.",
407
409
  ),
408
410
  no_tree: bool = typer.Option(
409
411
  False,
@@ -414,10 +416,8 @@ def main(
414
416
  tree: bool = typer.Option(
415
417
  False,
416
418
  "--tree",
417
- help=(
418
- "Include the full file_tree and flat file_paths list in output (deep-dive layer). "
419
- "Adds significant size — use when the agent needs to browse the full file structure."
420
- ),
419
+ hidden=True,
420
+ help="Include the full file_tree and flat file_paths list in output.",
421
421
  ),
422
422
  no_redact: bool = typer.Option(
423
423
  False,
@@ -448,41 +448,33 @@ def main(
448
448
  docs: bool = typer.Option(
449
449
  False,
450
450
  "--docs",
451
- help="Extract documentation: docstrings, function signatures, and module-level comments. Adds doc_summary and docs to output. Combine with --docs-depth to control coverage.",
451
+ hidden=True,
452
+ help="Extract documentation: docstrings, function signatures, and module-level comments.",
452
453
  ),
453
454
  docs_depth: str = typer.Option(
454
455
  "symbols",
455
456
  "--docs-depth",
456
- help="Documentation extraction depth: module (module-level only), symbols (functions and classes), full (all symbols including private). Default: symbols.",
457
+ hidden=True,
458
+ help="Documentation extraction depth: module, symbols, full.",
457
459
  show_default=True,
458
460
  ),
459
461
  full_metrics: bool = typer.Option(
460
462
  False,
461
463
  "--full-metrics",
462
- help=(
463
- "Technical audit: lines of code, symbol counts, cyclomatic complexity, and test coverage per file. "
464
- "Produces file_metrics and metrics_summary. "
465
- "Not included in --agent output — designed for CI pipelines and code review tools, not as primary agent context."
466
- ),
464
+ hidden=True,
465
+ help="Technical audit: LOC, complexity, test coverage per file.",
467
466
  ),
468
467
  semantics: bool = typer.Option(
469
468
  False,
470
469
  "--semantics",
471
- help=(
472
- "Semantic analysis: cross-file symbol resolution, call graph with confidence levels, and import linking. "
473
- "Adds semantic_calls, semantic_symbols, semantic_links, semantic_summary, and hotspots (files ranked by fan-in/fan-out). "
474
- "Slower than default analysis — skip for quick scans. "
475
- "Confidence degrades on dynamic dispatch, decorators, and generated code."
476
- ),
470
+ hidden=True,
471
+ help="Cross-file symbol resolution and call graph analysis.",
477
472
  ),
478
473
  architecture: bool = typer.Option(
479
474
  False,
480
475
  "--architecture",
481
- help=(
482
- "Architectural inference: detect functional layers (MVC/layered/hexagonal), bounded contexts, "
483
- "and dominant structural patterns. Adds architecture to output. "
484
- "Confidence is low when based on directory names alone — combine with --semantics for higher accuracy."
485
- ),
476
+ hidden=True,
477
+ help="Architectural layer inference (MVC/hexagonal/layered).",
486
478
  ),
487
479
  git_context: bool = typer.Option(
488
480
  False,
@@ -788,7 +780,7 @@ def main(
788
780
  # Require at least 8: src(1)+main(2)+java(3)+com(4)+co(5)+app(6)+module(7)+file.
789
781
  _java_manifest_names = {"pom.xml", "build.gradle", "build.gradle.kts"}
790
782
  _is_java = any(Path(m).name in _java_manifest_names for m in manifests)
791
- _java_min_depth = 10
783
+ _java_min_depth = 12
792
784
  effective_depth = max(depth, _java_min_depth) if _is_java and depth < _java_min_depth else depth
793
785
 
794
786
  # --agent: enable signal analyzers; output via agent_view (not compact)
@@ -1399,11 +1391,30 @@ def main(
1399
1391
  ))
1400
1392
  sm = _replace(sm, pipeline_trace=_trace.build_trace())
1401
1393
 
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"
1394
+ # Pre-compute uncommitted files for --changed-only.
1395
+ # The contract pipeline filter and git_context are two separate subsystems;
1396
+ # wire them here so the pipeline uses git_context data, not an independent git call.
1397
+ _allowed_changed_files: Optional[set[str]] = None
1398
+ if changed_only:
1399
+ from sourcecode.git_analyzer import GitAnalyzer as _GitAnalyzerEarly
1400
+ try:
1401
+ _gc_early = _GitAnalyzerEarly().analyze(target, depth=1, days=1)
1402
+ _bad_gc = {"no_git_repo", "git_not_found", "git_timeout"}
1403
+ if _gc_early and not (_bad_gc & set(_gc_early.limitations)):
1404
+ _uc = _gc_early.uncommitted_changes
1405
+ if _uc:
1406
+ _allowed_changed_files = (
1407
+ set(_uc.staged) | set(_uc.unstaged) | set(_uc.untracked)
1408
+ )
1409
+ if not _allowed_changed_files:
1410
+ typer.echo(
1411
+ "[changed-only] git unavailable or no uncommitted changes — falling back to full scan.",
1412
+ err=True,
1413
+ )
1414
+ changed_only = False
1415
+ except Exception:
1416
+ typer.echo("[changed-only] git error — falling back to full scan.", err=True)
1417
+ changed_only = False
1407
1418
 
1408
1419
  # Contract pipeline — runs for mode=contract|standard|deep|hybrid (skip for raw)
1409
1420
  _is_contract_mode = mode in ("contract", "standard")
@@ -1438,6 +1449,7 @@ def main(
1438
1449
  max_importers=max_importers,
1439
1450
  semantic_calls=sm.semantic_calls or None,
1440
1451
  code_notes=sm.code_notes or None,
1452
+ allowed_changed_files=_allowed_changed_files,
1441
1453
  **_java_pipeline_kwargs,
1442
1454
  )
1443
1455
  except Exception as _exc:
@@ -1712,8 +1724,13 @@ def prepare_context_cmd(
1712
1724
  if llm_prompt:
1713
1725
  out["llm_prompt"] = builder.render_prompt(output)
1714
1726
 
1727
+ import sys as _sys
1715
1728
  _pc_content = json.dumps(out, indent=2, ensure_ascii=False)
1716
- typer.echo(_pc_content)
1729
+ _pc_bytes = _pc_content.encode("utf-8")
1730
+ _sys.stdout.buffer.write(_pc_bytes)
1731
+ if not _pc_content.endswith("\n"):
1732
+ _sys.stdout.buffer.write(b"\n")
1733
+ _sys.stdout.buffer.flush()
1717
1734
 
1718
1735
  if copy:
1719
1736
  _trimmed = _pc_content.strip()
@@ -183,6 +183,7 @@ class ContractPipeline:
183
183
  code_notes: Optional[list] = None,
184
184
  max_contracts: Optional[int] = _MAX_CONTRACTS,
185
185
  min_score: Optional[float] = None,
186
+ allowed_changed_files: Optional[set[str]] = None,
186
187
  ) -> tuple[list[FileContract], ContractSummary]:
187
188
  """Run the full extraction pipeline.
188
189
 
@@ -200,9 +201,14 @@ class ContractPipeline:
200
201
  engine = RankingEngine(monorepo_packages)
201
202
 
202
203
  # 1. Changed files (for --changed-only and ranking)
204
+ # When allowed_changed_files is provided (from pre-computed git uncommitted_changes),
205
+ # use it directly. Otherwise fall back to independent git commands.
203
206
  changed_files: set[str] = set()
204
207
  if changed_only or rank_by == "git-churn":
205
- changed_files = _get_changed_files(root)
208
+ if allowed_changed_files is not None:
209
+ changed_files = allowed_changed_files
210
+ else:
211
+ changed_files = _get_changed_files(root)
206
212
 
207
213
  # 2. Select files to extract
208
214
  # Exclude test files by default — they dominate by count but add noise
@@ -240,10 +246,18 @@ class ContractPipeline:
240
246
 
241
247
  # Apply max_files cap — bypass when symbol search to ensure defining files are found.
242
248
  # A symbol query over a large repo needs all files; result set is small after filtering.
249
+ # MyBatis Mapper.xml contracts rank below Java files on path score alone (.xml has no
250
+ # suffix boost). Give them the same priority slot as entry_points so they survive the cap.
251
+ def _is_priority(p: str) -> bool:
252
+ if p in entry_paths:
253
+ return True
254
+ name = p.rsplit("/", 1)[-1]
255
+ return name.lower().endswith("mapper.xml")
256
+
243
257
  if symbol is None and len(src_paths) > self.max_files:
244
258
  src_paths = sorted(
245
259
  src_paths,
246
- key=lambda p: (p in entry_paths, scorer.score(p)),
260
+ key=lambda p: (_is_priority(p), scorer.score(p)),
247
261
  reverse=True,
248
262
  )[:self.max_files]
249
263
 
@@ -362,7 +376,9 @@ class ContractPipeline:
362
376
 
363
377
  def _rank(self, contracts: list[FileContract], rank_by: RankStrategy) -> list[FileContract]:
364
378
  if rank_by == "centrality":
365
- return sorted(contracts, key=lambda c: (-(c.fan_in + c.fan_out), c.path))
379
+ # Entrypoints (REST controllers, main classes) surface first even in centrality mode:
380
+ # they have low fan_in (not imported) but are the primary API surface.
381
+ return sorted(contracts, key=lambda c: (-c.is_entrypoint, -(c.fan_in + c.fan_out), c.path))
366
382
  if rank_by == "git-churn":
367
383
  return sorted(contracts, key=lambda c: (-c.is_changed, -c.relevance_score, c.path))
368
384
  # Default: relevance — path breaks ties deterministically
@@ -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
@@ -270,6 +276,40 @@ class JavaDetector(AbstractDetector):
270
276
  unique_eps.append(ep)
271
277
  return unique_eps
272
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
+
273
313
  def _scan_java_file_for_entry_points(self, abs_path: Path, rel_path: str) -> list[EntryPoint]:
274
314
  try:
275
315
  if abs_path.stat().st_size > _MAX_FILE_SIZE:
@@ -398,11 +398,27 @@ class TaskContextBuilder:
398
398
  from sourcecode.tree_utils import flatten_file_tree
399
399
 
400
400
  _topology = RepoClassifier().classify(self.root)
401
- scanner = AdaptiveScanner(self.root, topology=_topology, base_depth=6)
401
+ # Shallow pre-scan to detect Java manifests before choosing depth.
402
+ from sourcecode.scanner import FileScanner as _FileScanner
403
+ _pre = _FileScanner(self.root, max_depth=1)
404
+ _pre_manifests = _pre.find_manifests()
405
+ _java_names = {"pom.xml", "build.gradle", "build.gradle.kts"}
406
+ _is_java = any(Path(m).name in _java_names for m in _pre_manifests)
407
+ _base_depth = 12 if _is_java else 6
408
+ scanner = AdaptiveScanner(self.root, topology=_topology, base_depth=_base_depth)
402
409
  file_tree = scanner.scan_tree()
403
410
  manifests = scanner.find_manifests()
404
411
  all_paths = [p.replace("\\", "/") for p in flatten_file_tree(file_tree)]
405
412
 
413
+ # Warn when Java project has no Mapper.xml — suggests files below scan depth.
414
+ _mybatis_warning: dict | None = None
415
+ if _is_java and not any(p.endswith("Mapper.xml") for p in all_paths):
416
+ _mybatis_warning = {
417
+ "area": "mybatis",
418
+ "reason": "Mapper XML files may exist below scan depth. Re-run with --depth 12.",
419
+ "impact": "high",
420
+ }
421
+
406
422
  # ── 2. Detect stacks + entry points ───────────────────────────────
407
423
  from dataclasses import replace as _replace
408
424
  from sourcecode.detectors import ProjectDetector, build_default_detectors
@@ -500,6 +516,7 @@ class TaskContextBuilder:
500
516
  code_notes_summary: Optional[dict[str, Any]] = None
501
517
  suspected_areas: list[str] = []
502
518
  improvement_opportunities: list[str] = []
519
+ cn_notes_for_ranking: list = []
503
520
 
504
521
  if spec.enable_code_notes:
505
522
  from dataclasses import asdict
@@ -507,6 +524,7 @@ class TaskContextBuilder:
507
524
 
508
525
  cn_notes, _cn_adrs, cn_summary = CodeNotesAnalyzer().analyze(self.root)
509
526
  code_notes_summary = asdict(cn_summary)
527
+ cn_notes_for_ranking = cn_notes
510
528
 
511
529
  if task_name == "fix-bug":
512
530
  bug_kinds = {"FIXME", "BUG", "HACK", "XXX"}
@@ -555,6 +573,7 @@ class TaskContextBuilder:
555
573
  monorepo_packages=sm.monorepo_packages if sm.monorepo_packages else None,
556
574
  git_hotspots=git_hotspots,
557
575
  uncommitted_files=uncommitted_files,
576
+ code_notes=cn_notes_for_ranking if cn_notes_for_ranking else None,
558
577
  )
559
578
 
560
579
  # ── 7. Test gaps (generate-tests only) ────────────────────────────
@@ -594,6 +613,8 @@ class TaskContextBuilder:
594
613
  conf_summary, analysis_gaps = ConfidenceAnalyzer().analyze(sm_for_conf)
595
614
  confidence = conf_summary.overall
596
615
  gaps = [g.reason for g in analysis_gaps]
616
+ if _mybatis_warning:
617
+ gaps.append(_mybatis_warning["reason"])
597
618
 
598
619
  # ── 9. why_these_files ────────────────────────────────────────────────
599
620
  why_these_files: dict[str, str] = {
@@ -705,6 +726,7 @@ class TaskContextBuilder:
705
726
  monorepo_packages: Optional[list] = None,
706
727
  git_hotspots: Optional[dict[str, int]] = None,
707
728
  uncommitted_files: Optional[set[str]] = None,
729
+ code_notes: Optional[list] = None,
708
730
  ) -> list[RelevantFile]:
709
731
  from sourcecode.ranking_engine import RankingEngine
710
732
  from sourcecode.file_classifier import FileClassifier
@@ -719,6 +741,35 @@ class TaskContextBuilder:
719
741
  _uncommitted = uncommitted_files or set()
720
742
  _max_churn = max(_hotspots.values(), default=1)
721
743
 
744
+ # Pre-compute fix-bug signals (used only when task_name == "fix-bug")
745
+ _annotated_files: set[str] = set()
746
+ _dominant_stack = ""
747
+ _recently_changed_stacks: set[str] = set()
748
+ if task_name == "fix-bug":
749
+ _bug_kinds = {"FIXME", "BUG"}
750
+ for _n in (code_notes or []):
751
+ if getattr(_n, "kind", "").upper() in _bug_kinds:
752
+ _annotated_files.add(getattr(_n, "path", ""))
753
+
754
+ def _file_stack(p: str) -> str:
755
+ ext = Path(p).suffix.lower()
756
+ if ext == ".java": return "java"
757
+ if ext in (".ts", ".tsx", ".js", ".jsx", ".mjs"): return "typescript"
758
+ if ext == ".py": return "python"
759
+ if ext == ".go": return "go"
760
+ if ext in (".kt", ".kts"): return "kotlin"
761
+ if ext == ".rs": return "rust"
762
+ if ext == ".rb": return "ruby"
763
+ return "unknown"
764
+
765
+ from collections import Counter as _Counter
766
+ _stk_counts: _Counter[str] = _Counter(
767
+ _file_stack(f) for f in _uncommitted if _file_stack(f) != "unknown"
768
+ )
769
+ if _stk_counts:
770
+ _dominant_stack = _stk_counts.most_common(1)[0][0]
771
+ _recently_changed_stacks = set(_stk_counts.keys())
772
+
722
773
  scored: list[tuple[float, str, RelevantFile]] = []
723
774
 
724
775
  for path in all_paths:
@@ -762,10 +813,28 @@ class TaskContextBuilder:
762
813
 
763
814
  # Task-specific boosts for differentiated file weighting
764
815
  path_lower = path.lower()
816
+ _fix_bug_why = ""
765
817
  if task_name == "fix-bug":
766
- if any(x in path_lower for x in ("exception", "error", "handler", "advice")):
767
- content_boost += 1.5
768
- content_reasons.append("exception handler — high risk area")
818
+ _why_parts: list[str] = []
819
+ if path in _uncommitted:
820
+ content_boost += 0.40
821
+ _why_parts.append("uncommitted change (+0.40)")
822
+ _recency = min(0.30, _hotspots.get(path, 0) * 0.05)
823
+ if _recency > 0:
824
+ content_boost += _recency
825
+ _why_parts.append(f"recent commits (+{_recency:.2f})")
826
+ if path in _annotated_files:
827
+ content_boost += 0.20
828
+ _why_parts.append("FIXME/BUG annotation (+0.20)")
829
+ _file_stk = _file_stack(path)
830
+ if _dominant_stack and _file_stk == _dominant_stack:
831
+ content_boost += 0.10
832
+ _why_parts.append("dominant changed stack (+0.10)")
833
+ if _recently_changed_stacks and _file_stk not in _recently_changed_stacks and _file_stk != "unknown":
834
+ content_boost -= 0.30
835
+ _why_parts.append("different stack from recent changes (-0.30)")
836
+ if _why_parts:
837
+ _fix_bug_why = ", ".join(_why_parts)
769
838
  elif task_name == "generate-tests":
770
839
  stem = Path(path).stem.lower()
771
840
  has_test = any(
@@ -797,7 +866,7 @@ class TaskContextBuilder:
797
866
  )
798
867
  all_reasons = [r for r in fs.reasons if r != "source file"] + content_reasons
799
868
  reason_str = ", ".join(all_reasons) if all_reasons else "source file"
800
- why_str = _java_why(path, file_class)
869
+ why_str = _fix_bug_why if _fix_bug_why else _java_why(path, file_class)
801
870
 
802
871
  scored.append((total, path, RelevantFile(
803
872
  path=path,