sourcecode 1.29.0__tar.gz → 1.30.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. sourcecode-1.30.1/.continue-here.md +129 -0
  2. {sourcecode-1.29.0 → sourcecode-1.30.1}/PKG-INFO +3 -3
  3. {sourcecode-1.29.0 → sourcecode-1.30.1}/README.md +2 -2
  4. {sourcecode-1.29.0 → sourcecode-1.30.1}/pyproject.toml +1 -1
  5. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/__init__.py +1 -1
  6. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/prepare_context.py +168 -11
  7. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_v1_10_regressions.py +5 -5
  8. sourcecode-1.29.0/.continue-here.md +0 -108
  9. {sourcecode-1.29.0 → sourcecode-1.30.1}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
  10. {sourcecode-1.29.0 → sourcecode-1.30.1}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
  11. {sourcecode-1.29.0 → sourcecode-1.30.1}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
  12. {sourcecode-1.29.0 → sourcecode-1.30.1}/.github/workflows/build-windows.yml +0 -0
  13. {sourcecode-1.29.0 → sourcecode-1.30.1}/.gitignore +0 -0
  14. {sourcecode-1.29.0 → sourcecode-1.30.1}/.ruff.toml +0 -0
  15. {sourcecode-1.29.0 → sourcecode-1.30.1}/CONTRIBUTING.md +0 -0
  16. {sourcecode-1.29.0 → sourcecode-1.30.1}/LICENSE +0 -0
  17. {sourcecode-1.29.0 → sourcecode-1.30.1}/SECURITY.md +0 -0
  18. {sourcecode-1.29.0 → sourcecode-1.30.1}/docs/privacy.md +0 -0
  19. {sourcecode-1.29.0 → sourcecode-1.30.1}/docs/schema.md +0 -0
  20. {sourcecode-1.29.0 → sourcecode-1.30.1}/raw +0 -0
  21. {sourcecode-1.29.0 → sourcecode-1.30.1}/run_cli.py +0 -0
  22. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/adaptive_scanner.py +0 -0
  23. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/architecture_analyzer.py +0 -0
  24. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/architecture_summary.py +0 -0
  25. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/ast_extractor.py +0 -0
  26. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/classifier.py +0 -0
  27. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/cli.py +0 -0
  28. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/code_notes_analyzer.py +0 -0
  29. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/confidence_analyzer.py +0 -0
  30. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/context_scorer.py +0 -0
  31. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/context_summarizer.py +0 -0
  32. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/contract_model.py +0 -0
  33. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/contract_pipeline.py +0 -0
  34. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/coverage_parser.py +0 -0
  35. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/dependency_analyzer.py +0 -0
  36. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/__init__.py +0 -0
  37. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/base.py +0 -0
  38. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/csproj_parser.py +0 -0
  39. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/dart.py +0 -0
  40. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/dotnet.py +0 -0
  41. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/elixir.py +0 -0
  42. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/go.py +0 -0
  43. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/heuristic.py +0 -0
  44. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/hybrid.py +0 -0
  45. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/java.py +0 -0
  46. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/jvm_ext.py +0 -0
  47. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/nodejs.py +0 -0
  48. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/parsers.py +0 -0
  49. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/php.py +0 -0
  50. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/project.py +0 -0
  51. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/python.py +0 -0
  52. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/ruby.py +0 -0
  53. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/rust.py +0 -0
  54. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/systems.py +0 -0
  55. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/terraform.py +0 -0
  56. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/detectors/tooling.py +0 -0
  57. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/doc_analyzer.py +0 -0
  58. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/entrypoint_classifier.py +0 -0
  59. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/env_analyzer.py +0 -0
  60. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/file_classifier.py +0 -0
  61. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/git_analyzer.py +0 -0
  62. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/graph_analyzer.py +0 -0
  63. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/metrics_analyzer.py +0 -0
  64. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/progress.py +0 -0
  65. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/ranking_engine.py +0 -0
  66. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/redactor.py +0 -0
  67. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/relevance_scorer.py +0 -0
  68. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/repo_classifier.py +0 -0
  69. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/runtime_classifier.py +0 -0
  70. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/scanner.py +0 -0
  71. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/schema.py +0 -0
  72. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/semantic_analyzer.py +0 -0
  73. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/serializer.py +0 -0
  74. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/summarizer.py +0 -0
  75. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/telemetry/__init__.py +0 -0
  76. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/telemetry/config.py +0 -0
  77. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/telemetry/consent.py +0 -0
  78. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/telemetry/events.py +0 -0
  79. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/telemetry/filters.py +0 -0
  80. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/telemetry/transport.py +0 -0
  81. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/tree_utils.py +0 -0
  82. {sourcecode-1.29.0 → sourcecode-1.30.1}/src/sourcecode/workspace.py +0 -0
  83. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/__init__.py +0 -0
  84. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/conftest.py +0 -0
  85. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/coverage.xml +0 -0
  86. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
  87. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/fastapi_app/src/main.py +0 -0
  88. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/go_service/cmd/api/main.go +0 -0
  89. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/go_service/go.mod +0 -0
  90. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/jacoco.xml +0 -0
  91. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/latin1_sample.java +0 -0
  92. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/latin1_sample_iso.java +0 -0
  93. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/lcov.info +0 -0
  94. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
  95. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/nextjs_app/package.json +0 -0
  96. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
  97. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
  98. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
  99. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
  100. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
  101. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
  102. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
  103. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/application/service/FindAusenteService.java +0 -0
  104. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/domain/entities/Ausente.java +0 -0
  105. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/infrastructure/rest/AusenteRestController.java +0 -0
  106. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/application/service/FindAutocoberturasService.java +0 -0
  107. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/domain/entities/Autocoberturas.java +0 -0
  108. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/infrastructure/rest/AutocoberturasRestController.java +0 -0
  109. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/application/service/FindCalendarioTrabajadorService.java +0 -0
  110. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/domain/entities/CalendarioTrabajador.java +0 -0
  111. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/infrastructure/rest/CalendarioTrabajadorRestController.java +0 -0
  112. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/application/service/FindDepartamentoService.java +0 -0
  113. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/domain/entities/Departamento.java +0 -0
  114. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/infrastructure/rest/DepartamentoRestController.java +0 -0
  115. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/application/service/FindEmpleadoService.java +0 -0
  116. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/domain/entities/Empleado.java +0 -0
  117. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/infrastructure/rest/EmpleadoRestController.java +0 -0
  118. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
  119. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/config/FilterConfig.java +0 -0
  120. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
  121. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
  122. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
  123. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
  124. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
  125. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/NominaRestController.java +0 -0
  126. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
  127. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
  128. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/fixtures/spring_boot_minimal/src/main/resources/mapper/HealthMapper.xml +0 -0
  129. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_architecture_analyzer.py +0 -0
  130. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_architecture_summary.py +0 -0
  131. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_ast_extractor.py +0 -0
  132. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_block1_reliability.py +0 -0
  133. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_block2_coverage.py +0 -0
  134. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_block5_quality.py +0 -0
  135. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_bug_fixes_v16.py +0 -0
  136. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_classifier.py +0 -0
  137. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_cli.py +0 -0
  138. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_code_notes_analyzer.py +0 -0
  139. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_context_scorer.py +0 -0
  140. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_contract_pipeline.py +0 -0
  141. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_coverage_parser.py +0 -0
  142. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_cross_consistency.py +0 -0
  143. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_dependency_analyzer_node_python.py +0 -0
  144. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_dependency_analyzer_polyglot.py +0 -0
  145. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_dependency_schema.py +0 -0
  146. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_detector_dotnet.py +0 -0
  147. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_detector_go_rust_java.py +0 -0
  148. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_detector_nodejs.py +0 -0
  149. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_detector_php_ruby_dart.py +0 -0
  150. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_detector_python.py +0 -0
  151. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_detector_universal_managed.py +0 -0
  152. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_detector_universal_systems.py +0 -0
  153. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_detectors_base.py +0 -0
  154. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_doc_analyzer_jsdom.py +0 -0
  155. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_doc_analyzer_python.py +0 -0
  156. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_encoding_regression.py +0 -0
  157. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_graph_analyzer_polyglot.py +0 -0
  158. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_graph_analyzer_python_node.py +0 -0
  159. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_graph_schema.py +0 -0
  160. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_hybrid_inference.py +0 -0
  161. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_integration.py +0 -0
  162. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_integration_dependencies.py +0 -0
  163. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_integration_detection.py +0 -0
  164. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_integration_docs.py +0 -0
  165. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_integration_graph_modules.py +0 -0
  166. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_integration_lqn.py +0 -0
  167. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_integration_metrics.py +0 -0
  168. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_integration_multistack.py +0 -0
  169. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_integration_semantics.py +0 -0
  170. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_integration_universal.py +0 -0
  171. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_java_spring_integration.py +0 -0
  172. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_metrics_analyzer.py +0 -0
  173. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_packaging.py +0 -0
  174. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_phase1_improvements.py +0 -0
  175. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_pipeline_integrity.py +0 -0
  176. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_real_projects.py +0 -0
  177. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_redactor.py +0 -0
  178. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_scanner.py +0 -0
  179. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_schema.py +0 -0
  180. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_schema_normalization.py +0 -0
  181. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_semantic_analyzer_node.py +0 -0
  182. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_semantic_analyzer_python.py +0 -0
  183. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_semantic_import_resolution.py +0 -0
  184. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_semantic_schema.py +0 -0
  185. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_signal_hierarchy.py +0 -0
  186. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_summarizer.py +0 -0
  187. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_surface_honesty.py +0 -0
  188. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_task_differentiation.py +0 -0
  189. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_telemetry.py +0 -0
  190. {sourcecode-1.29.0 → sourcecode-1.30.1}/tests/test_workspace_analyzer.py +0 -0
@@ -0,0 +1,129 @@
1
+ # Continue Here — atlas-cli session 6
2
+
3
+ **Paused:** 2026-05-16 (sesión 6)
4
+ **Repo:** `/Users/user/Downloads/atlas-cli`
5
+ **Branch:** master
6
+ **Último commit:** `772a01e` (fix false positives review-pr)
7
+ **Working tree:** DIRTY — `src/sourcecode/prepare_context.py` modificado (28 ins / 8 del), sin commit
8
+
9
+ ---
10
+
11
+ ## Lo que se hizo esta sesión
12
+
13
+ ### Fix 1 — `review-pr` false positive cuando `since=None`
14
+
15
+ Commit `772a01e` (ya en repo). Root cause: `_get_git_changed_files(since=None)` usaba `HEAD~1` como default → devolvía archivos del último commit committeado → `review-pr` los trataba como "PR diff". Fix: nuevo método `_get_uncommitted_changed_files()` llamado desde gate review-pr cuando `since=None`. Tests actualizados en `test_v1_10_regressions.py` para mockear el nuevo método.
16
+
17
+ ---
18
+
19
+ ### Fix 2 — BFS over-expansion en `_build_delta_impact` (SIN COMMIT — PENDIENTE)
20
+
21
+ **Problema confirmado en `~/Documents/workspace/spring-boot-realworld-example-app`:**
22
+ Con 2 archivos cambiados (`User.java`, `ArticleFavorite.java`), `review-pr` devolvía 24 `relevant_files` incluyendo todos los controllers REST, todos los GraphQL resolvers, y 2 test files.
23
+
24
+ **3 bugs identificados y corregidos:**
25
+
26
+ | Bug | Línea orig | Descripción | Fix |
27
+ |-----|-----------|-------------|-----|
28
+ | Tests en `_bfs_collected` | ~2081 | `_bfs_collected.append()` fuera de `if not _is_test:` → TestHelper.java, ArticleApiTest.java incluidos | Movido dentro del bloque |
29
+ | Sin per-hop cap | ~2091 | `_max_results` (8) limitaba solo el frontier, no `_bfs_collected`. Hop-1 llenaba los 20 slots, expulsando hop-2/3 | Nuevo `_hop_bfs_staged`: acumula por hop, ordena por score desc, extiende con `[:_max_results]` |
30
+ | Sin truncation guard | — | Sin señal cuando expansión excesiva | Flag `_expansion_truncated` + mensaje `truncated_dependency_graph` en `analysis_gaps` cuando `len(relevant) > 40` |
31
+
32
+ **Resultado smoke test:**
33
+
34
+ | Métrica | Antes | Después |
35
+ |---------|-------|---------|
36
+ | `relevant_files` total | 24 | 14 |
37
+ | Tests incluidos | 2 | **0** |
38
+ | GraphQL resolvers | 8 | **0** |
39
+ | REST controllers | 7 | 5 (top-5 score) |
40
+ | Security hop-1 legítimos | 3 | 3 |
41
+ | JwtTokenFilter (hop-2) | 1 | 1 |
42
+ | WebSecurityConfig (hop-3) | 0 | 1 |
43
+
44
+ **Tests:** 771 passed, 3 skipped
45
+
46
+ ---
47
+
48
+ ## Estado de tests al pausar
49
+
50
+ ```
51
+ 771 passed, 3 skipped
52
+ ```
53
+
54
+ Pre-existing failures (excluidos del run):
55
+ - `test_block2_coverage.py::test_java_marked_unsupported` — DocRecord bug en doc_analyzer.py
56
+ - `test_dependency_analyzer_node_python.py::test_python_requirements_without_lockfile_keeps_declared_versions` — typer version mismatch
57
+ - `test_packaging.py::test_console_script_reports_version` — installed v1.29 vs source v1.30 (se resolverá al reinstalar post-commit)
58
+
59
+ ---
60
+
61
+ ## Decisiones técnicas de esta sesión
62
+
63
+ - **`_get_uncommitted_changed_files()`**: Método extraído para que sea mockeado en tests. Delta sigue usando HEAD~1 — correcto, no afectado.
64
+ - **`_hop_bfs_staged` per-hop cap**: Elegido sobre threshold de score porque 0.30 seguía incluyendo GraphQL (score 0.32). Cap determinístico.
65
+ - **`_bfs_cap = sum(budget[0])`**: 8+6+4=18, derivado de `_BFS_HOP_BUDGET`, no hardcodeado.
66
+ - **WebSecurityConfig sigue apareciendo (hop-3)**: Legítimo. Cadena real: JwtService→JwtTokenFilter→WebSecurityConfig. Para eliminar: reducir `_BFS_HOP_BUDGET` a 2 hops.
67
+
68
+ ---
69
+
70
+ ## Pendiente / próximos pasos
71
+
72
+ 1. **COMMIT fix BFS** — diff listo, tests verdes:
73
+ ```bash
74
+ cd /Users/user/Downloads/atlas-cli
75
+ git add src/sourcecode/prepare_context.py
76
+ git commit -m "fix: BFS over-expansion en review-pr — per-hop cap, tests excluidos, truncation guard"
77
+ ```
78
+
79
+ 2. **Opcional — reducir a 2 hops** si se quiere eliminar WebSecurityConfig (hop-3):
80
+ Cambiar `_BFS_HOP_BUDGET` en `prepare_context.py` de 3 a 2 elementos.
81
+
82
+ 3. **Opcional — cross-module guard en BFS**: No incluir archivos cuyo módulo (`_extract_ddd_domain`) difiere del módulo de los changed files. Eliminaría AuthorizationService/JwtService (módulo "service" ≠ "user"/"favorite") de hop-1.
83
+
84
+ 4. **Smoke test `delta`** con BFS fix (verificar no afectado):
85
+ ```bash
86
+ cd ~/Documents/workspace/spring-boot-realworld-example-app
87
+ sourcecode prepare-context delta . --since HEAD~1 2>&1 | python3 -c "import json,sys; d=json.load(sys.stdin); print('relevant_files:', len(d.get('relevant_files', [])))"
88
+ ```
89
+
90
+ 5. **Smoke tests sesiones anteriores** (saint-server) — ver handoff sesión 4/5.
91
+
92
+ ---
93
+
94
+ ## Para retomar
95
+
96
+ ```bash
97
+ cd /Users/user/Downloads/atlas-cli
98
+ git log --oneline -3
99
+ # debe mostrar:
100
+ # 772a01e (fix) corrigiendo bug que identificaba falsos positivos en review-pr
101
+ # 5c06ef3 (feature) implementando mejoras significativas en prepare-context review-pr
102
+ # e5a1a05 corrigiendo bug en delta --since en windows
103
+
104
+ git diff --stat HEAD
105
+ # debe mostrar: prepare_context.py | 36 +++--- (BFS fix pendiente de commit)
106
+
107
+ # Tests
108
+ python3 -m pytest tests/ \
109
+ --ignore=tests/test_block2_coverage.py \
110
+ --ignore=tests/test_packaging.py \
111
+ --deselect=tests/test_dependency_analyzer_node_python.py::test_python_requirements_without_lockfile_keeps_declared_versions \
112
+ -q
113
+ # Expected: 771 passed, 3 skipped
114
+
115
+ # Smoke test review-pr
116
+ cd ~/Documents/workspace/spring-boot-realworld-example-app
117
+ sourcecode prepare-context review-pr . 2>&1 | python3 -c "
118
+ import json, sys
119
+ d = json.load(sys.stdin)
120
+ print('relevant_files:', len(d.get('relevant_files', [])))
121
+ for f in d.get('relevant_files', []):
122
+ print(' ', f.get('score'), f.get('path').split('/')[-1])
123
+ "
124
+ # Expected: 14 files, no tests, no GraphQL
125
+ ```
126
+
127
+ ---
128
+
129
+ *Pausado 2026-05-16 sesión 6 — gsd:pause-work*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 1.29.0
3
+ Version: 1.30.1
4
4
  Summary: Deterministic codebase context for AI coding agents
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -221,7 +221,7 @@ Description-Content-Type: text/markdown
221
221
 
222
222
  **Compressed AI-ready context for Java/Spring enterprise codebases.**
223
223
 
224
- ![Version](https://img.shields.io/badge/version-1.29.0-blue)
224
+ ![Version](https://img.shields.io/badge/version-1.30.1-blue)
225
225
  ![Python](https://img.shields.io/badge/python-3.10%2B-green)
226
226
 
227
227
  ---
@@ -255,7 +255,7 @@ pipx install sourcecode
255
255
 
256
256
  ```bash
257
257
  sourcecode version
258
- # sourcecode 1.29.0
258
+ # sourcecode 1.30.1
259
259
  ```
260
260
 
261
261
  ---
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Compressed AI-ready context for Java/Spring enterprise codebases.**
4
4
 
5
- ![Version](https://img.shields.io/badge/version-1.29.0-blue)
5
+ ![Version](https://img.shields.io/badge/version-1.30.1-blue)
6
6
  ![Python](https://img.shields.io/badge/python-3.10%2B-green)
7
7
 
8
8
  ---
@@ -36,7 +36,7 @@ pipx install sourcecode
36
36
 
37
37
  ```bash
38
38
  sourcecode version
39
- # sourcecode 1.29.0
39
+ # sourcecode 1.30.1
40
40
  ```
41
41
 
42
42
  ---
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "1.29.0"
7
+ version = "1.30.1"
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.29.0"
3
+ __version__ = "1.30.1"
@@ -681,7 +681,13 @@ class TaskContextBuilder:
681
681
  error_message="review-pr requires a git repository.",
682
682
  ci_decision="no_git_repo",
683
683
  )
684
- _pr_raw = self._get_git_changed_files(since=since)
684
+ if since is None:
685
+ # review-pr with no --since: check only uncommitted changes.
686
+ # _get_git_changed_files(since=None) defaults to HEAD~1 which
687
+ # returns the last *committed* diff — a false positive here.
688
+ _pr_raw: Optional[list[str]] = self._get_uncommitted_changed_files()
689
+ else:
690
+ _pr_raw = self._get_git_changed_files(since=since)
685
691
  if _pr_raw is None:
686
692
  _avail_pr, _sug_pr = self._get_available_refs(since or "")
687
693
  _pr_hints: list[str] = []
@@ -1599,6 +1605,78 @@ class TaskContextBuilder:
1599
1605
  # Binaries, images, lock files — treat as noise (closed taxonomy: no unknown_*)
1600
1606
  return {"artifact_type": "ide_noise", "risk_areas": [], "impact_level": "noise", "is_noise": True, "module": module, "confidence": "low"}
1601
1607
 
1608
+ def _classify_diff_severity(self, path: str, since: Optional[str]) -> str:
1609
+ """Classify the semantic severity of a file's diff to gate BFS expansion.
1610
+
1611
+ Returns: 'trivial' | 'field_change' | 'api_change' | 'security_change' | 'unknown'
1612
+
1613
+ - trivial: only comments/whitespace changed — no BFS expansion seeded
1614
+ - field_change: field/attribute declarations changed — hop-1 only, no hop-2+ frontier
1615
+ - api_change: method signatures or class structure changed — full BFS
1616
+ - security_change: auth/security keywords in changed lines — full BFS + security chain
1617
+ - unknown: diff unreadable — treated as api_change (safe default)
1618
+ """
1619
+ import subprocess as _subprocess
1620
+ import re as _re
1621
+
1622
+ try:
1623
+ if since:
1624
+ cmd = ["git", "diff", since, "HEAD", "--", path]
1625
+ else:
1626
+ cmd = ["git", "diff", "HEAD", "--", path]
1627
+ result = _subprocess.run(
1628
+ cmd, capture_output=True, text=True, timeout=5,
1629
+ cwd=str(self.root), encoding="utf-8", errors="ignore",
1630
+ )
1631
+ diff_text = result.stdout
1632
+ except Exception:
1633
+ return "unknown"
1634
+
1635
+ if not diff_text.strip():
1636
+ return "unknown"
1637
+
1638
+ changed_lines = [
1639
+ line[1:] for line in diff_text.splitlines()
1640
+ if line.startswith(("+", "-")) and not line.startswith(("+++", "---"))
1641
+ ]
1642
+ if not changed_lines:
1643
+ return "trivial"
1644
+
1645
+ suffix = Path(path).suffix.lower()
1646
+ if suffix in (".java", ".kt"):
1647
+ _TRIVIAL = _re.compile(r'^\s*(?://|/\*|\*)')
1648
+ _FIELD = _re.compile(r'^\s*(?:private|protected|public|final|static)\s+\w[\w<>, ]*\s+\w+\s*[;=]')
1649
+ _API = _re.compile(r'^\s*(?:public|protected)\s+\S.*\(')
1650
+ # Exclude 'password', 'role', 'permission' — these are common field names
1651
+ # in domain models and don't indicate auth logic changes. Keep mechanism
1652
+ # keywords: jwt, auth (as class prefix), token, credential, encrypt, decrypt, oauth.
1653
+ _SECURITY = _re.compile(r'\b(?:jwt|auth|token|credential|encrypt|decrypt|oauth|saml|ldap|principal|Security)\b')
1654
+ _STRUCT = _re.compile(r'^\s*(?:class|interface|enum|record|import|package)\s')
1655
+ elif suffix == ".py":
1656
+ _TRIVIAL = _re.compile(r'^\s*#')
1657
+ _FIELD = _re.compile(r'^\s*(?:self\.\w+\s*=|\w+:\s*\w)')
1658
+ _API = _re.compile(r'^\s*def\s+\w')
1659
+ _SECURITY = _re.compile(r'\b(?:jwt|auth|token|credential|encrypt|decrypt|oauth|saml|ldap|principal|security)\b', _re.IGNORECASE)
1660
+ _STRUCT = _re.compile(r'^\s*(?:class|import|from)\s')
1661
+ elif suffix in (".ts", ".tsx", ".js", ".jsx", ".mjs"):
1662
+ _TRIVIAL = _re.compile(r'^\s*(?://|/\*|\*)')
1663
+ _FIELD = _re.compile(r'^\s*(?:private|readonly|public)?\s*\w+[?!]?\s*[=:]')
1664
+ _API = _re.compile(r'^\s*(?:(?:public|private|protected|async|export)\s+)*(?:function\s+\w|\w+\s*\()')
1665
+ _SECURITY = _re.compile(r'\b(?:jwt|auth|token|credential|encrypt|decrypt|oauth|saml|ldap|principal|security)\b', _re.IGNORECASE)
1666
+ _STRUCT = _re.compile(r'^\s*(?:class|interface|import|export\s+(?:class|interface|type))\s')
1667
+ else:
1668
+ return "unknown"
1669
+
1670
+ if any(_SECURITY.search(line) for line in changed_lines):
1671
+ return "security_change"
1672
+ if any(_API.match(line) or _STRUCT.match(line) for line in changed_lines):
1673
+ return "api_change"
1674
+ if any(_FIELD.match(line) for line in changed_lines):
1675
+ return "field_change"
1676
+ if all(_TRIVIAL.match(line) or not line.strip() for line in changed_lines):
1677
+ return "trivial"
1678
+ return "field_change" # safe default: treat unknown non-trivial as field-level
1679
+
1602
1680
  def _scan_import_dependents(
1603
1681
  self,
1604
1682
  changed_paths: list[str],
@@ -1882,6 +1960,16 @@ class TaskContextBuilder:
1882
1960
  f: self._classify_changed_file(f) for f in changed_files
1883
1961
  }
1884
1962
 
1963
+ # ── Step 1b: classify diff severity to gate BFS expansion ─────────────
1964
+ # trivial → no BFS seeding (comments/whitespace only)
1965
+ # field_change → hop-1 BFS only, deps excluded from hop-2+ frontier
1966
+ # api_change → full BFS (method signature or class structure changed)
1967
+ # security_change → full BFS + security chain allowed cross-module
1968
+ # unknown → treated as api_change (safe default)
1969
+ diff_severities: dict[str, str] = {
1970
+ f: self._classify_diff_severity(f, since) for f in changed_files
1971
+ }
1972
+
1885
1973
  # ── Step 2: build relevant_files from the changed set ─────────────────
1886
1974
  relevant: list[RelevantFile] = []
1887
1975
  why: dict[str, str] = {}
@@ -1998,9 +2086,12 @@ class TaskContextBuilder:
1998
2086
  ]
1999
2087
 
2000
2088
  _bfs_seen: set[str] = {rf.path for rf in relevant}
2089
+ # trivial changes (comments/whitespace only) don't seed BFS — nothing structural
2090
+ # to propagate, so excluding them prevents false expansion on cosmetic commits
2001
2091
  _bfs_frontier: list[str] = [
2002
2092
  f for f in changed_files
2003
2093
  if Path(f).suffix.lower() in _BFS_SCANNABLE
2094
+ and diff_severities.get(f, "unknown") != "trivial"
2004
2095
  ]
2005
2096
 
2006
2097
  # (max results added from this hop, max_candidates scanned per seed)
@@ -2029,6 +2120,8 @@ class TaskContextBuilder:
2029
2120
 
2030
2121
  # collect (score, path) pairs for this hop to build the next frontier
2031
2122
  _hop_scored: list[tuple[float, str]] = []
2123
+ # per-hop staging list — capped at _max_results before merging into _bfs_collected
2124
+ _hop_bfs_staged: list[tuple[int, float, str, RelevantFile]] = []
2032
2125
 
2033
2126
  for _seed_path, _dep_paths in _hop_dep_map.items():
2034
2127
  _seed_atype = (
@@ -2036,6 +2129,9 @@ class TaskContextBuilder:
2036
2129
  if _seed_path in classifications
2037
2130
  else self._classify_changed_file(_seed_path)["artifact_type"]
2038
2131
  )
2132
+ # diff severity for original changed files only (hop-1 seeds);
2133
+ # hop-2+ seeds are dep files not in diff_severities → "unknown"
2134
+ _seed_severity = diff_severities.get(_seed_path, "unknown")
2039
2135
  for _dep_path in _dep_paths:
2040
2136
  if _dep_path in _bfs_seen:
2041
2137
  continue
@@ -2046,9 +2142,29 @@ class TaskContextBuilder:
2046
2142
  continue
2047
2143
 
2048
2144
  _dep_atype = _dep_cls["artifact_type"]
2145
+ _dep_module = _dep_cls["module"]
2146
+
2147
+ # Cross-module gating: if dep lives in a different domain module,
2148
+ # only allow it if:
2149
+ # hop-1 AND dep_atype is explicitly in seed's _EXPANSION_TARGETS
2150
+ # For hop-2+, cross-module deps are always excluded — transitives
2151
+ # must stay within the changed modules to avoid system-wide explosion.
2152
+ _is_cross_module = bool(_dep_module) and _dep_module not in affected_modules_set
2153
+ if _is_cross_module:
2154
+ _seed_expansion = _EXPANSION_TARGETS.get(_seed_atype, frozenset())
2155
+ # security_change seeds are allowed to cross into the security chain
2156
+ # even when their base expansion targets don't include those types
2157
+ if _seed_severity == "security_change":
2158
+ _seed_expansion = _seed_expansion | frozenset({"security", "spring_config", "config"})
2159
+ if _hop_num >= 2 or _dep_atype not in _seed_expansion:
2160
+ continue
2161
+
2049
2162
  _dep_score_base = _ARTIFACT_SCORE.get(_dep_atype, 0.45)
2050
2163
  # score decays 30% per hop so transitives rank below direct dependents
2051
- _dep_score = round(_dep_score_base * (0.70 ** _hop_num), 2)
2164
+ # cross-module deps get additional 40% penalty so same-module files
2165
+ # always rank higher in the per-hop cap
2166
+ _cross_module_factor = 0.60 if _is_cross_module else 1.0
2167
+ _dep_score = round(_dep_score_base * (0.70 ** _hop_num) * _cross_module_factor, 2)
2052
2168
  _dep_role = _role_in_system(_dep_path, _dep_atype, _dep_path in ep_paths)
2053
2169
 
2054
2170
  _why_str = (
@@ -2063,27 +2179,44 @@ class TaskContextBuilder:
2063
2179
  f" ({_seed_atype}) | score: {_dep_score:.2f}"
2064
2180
  )
2065
2181
  why[_dep_path] = _why_str
2066
- # Tests are consumers, not structural dependencies — exclude from import graph.
2067
- # They remain in relevant_files but must not seed further BFS hops.
2182
+ # Tests import production code but are not structural dependencies —
2183
+ # exclude from graph, frontier, and bfs_collected entirely.
2068
2184
  _is_test = _dep_atype == "test"
2069
2185
  if not _is_test:
2070
2186
  graph_edges.append({
2071
2187
  "from": _seed_path, "to": _dep_path,
2072
2188
  "edge_type": "import_dependency", "hop": _hop_num,
2073
2189
  })
2074
- _hop_scored.append((_dep_score, _dep_path))
2075
- _bfs_collected.append((_hop_num, _dep_score, _dep_path, RelevantFile(
2076
- path=_dep_path, role=_dep_role, score=_dep_score,
2077
- reason=_reason, why=_why_str,
2078
- )))
2190
+ # field_change seeds don't propagate to hop-2+ frontier:
2191
+ # a field-level change (getter, attribute) is collected at hop-1
2192
+ # but its callers are not recursively expanded further
2193
+ if _seed_severity != "field_change":
2194
+ _hop_scored.append((_dep_score, _dep_path))
2195
+ _hop_bfs_staged.append((_hop_num, _dep_score, _dep_path, RelevantFile(
2196
+ path=_dep_path, role=_dep_role, score=_dep_score,
2197
+ reason=_reason, why=_why_str,
2198
+ )))
2199
+
2200
+ # Per-hop cap: keep only the top-_max_results by score before merging.
2201
+ # Prevents a single high-fanout seed (e.g. User.java imported by every
2202
+ # controller) from flooding _bfs_collected and pushing out hop-2/3 results.
2203
+ _hop_bfs_staged.sort(key=lambda x: (-x[1], x[2]))
2204
+ _bfs_collected.extend(_hop_bfs_staged[:_max_results])
2079
2205
 
2080
2206
  # next frontier = top-N files by score from this hop
2081
2207
  _hop_scored.sort(key=lambda x: -x[0])
2082
2208
  _bfs_frontier = [p for _, p in _hop_scored[:_max_results]]
2083
2209
 
2084
- # merge into relevant: closer hops first, then higher score; cap total at 20
2210
+ # merge into relevant: closer hops first, then higher score; cap total at 18
2085
2211
  _bfs_collected.sort(key=lambda x: (x[0], -x[1], x[2]))
2086
- relevant.extend(rf for _, _, _, rf in _bfs_collected[:20])
2212
+ _bfs_cap = sum(budget[0] for budget in _BFS_HOP_BUDGET) # 8+6+4 = 18
2213
+ relevant.extend(rf for _, _, _, rf in _bfs_collected[:_bfs_cap])
2214
+
2215
+ # Truncation guard: flag excess expansion — gap message added in Step 6.
2216
+ _EXPANSION_HARD_LIMIT = 40
2217
+ _expansion_truncated = len(relevant) > _EXPANSION_HARD_LIMIT
2218
+ if _expansion_truncated:
2219
+ relevant = relevant[:_EXPANSION_HARD_LIMIT]
2087
2220
 
2088
2221
  # ── Step 3d: per-file impact scores, change_type, system_impact ─────────
2089
2222
  # Downstream fanout: count graph edges originating from each changed file
@@ -2257,6 +2390,11 @@ class TaskContextBuilder:
2257
2390
  analysis_gaps: list[str] = [
2258
2391
  f"Related file expansion: type-aware chain expansion + {_bfs_note} + module/directory heuristics",
2259
2392
  ]
2393
+ if _expansion_truncated:
2394
+ analysis_gaps.insert(0,
2395
+ f"truncated_dependency_graph: expansion exceeded {_EXPANSION_HARD_LIMIT} nodes"
2396
+ " — lower-priority files omitted. Narrow scope with --since <ref> for precision."
2397
+ )
2260
2398
  if noise_count > 0 and meaningful > 0:
2261
2399
  analysis_gaps.append(
2262
2400
  f"{noise_count} IDE/tooling file(s) in diff excluded from impact analysis"
@@ -2410,6 +2548,25 @@ class TaskContextBuilder:
2410
2548
  "error": True,
2411
2549
  }
2412
2550
 
2551
+ def _get_uncommitted_changed_files(self) -> list[str]:
2552
+ """Return files with uncommitted working-tree changes (unstaged only).
2553
+
2554
+ Used by review-pr when no --since ref is given, so we don't confuse
2555
+ the last *committed* diff (HEAD~1 vs HEAD) with an actual PR diff.
2556
+ """
2557
+ import subprocess
2558
+ try:
2559
+ result = subprocess.run(
2560
+ ["git", "diff", "--name-only", "--relative"],
2561
+ cwd=str(self.root), capture_output=True, text=True,
2562
+ encoding="utf-8", errors="replace", timeout=10,
2563
+ )
2564
+ if result.returncode == 0:
2565
+ return [l.strip() for l in (result.stdout or "").splitlines() if l.strip()]
2566
+ except (subprocess.TimeoutExpired, FileNotFoundError):
2567
+ pass
2568
+ return []
2569
+
2413
2570
  def _get_git_changed_files(self, since: Optional[str] = None) -> Optional[list[str]]:
2414
2571
  """Get files changed since a git ref (default: HEAD~1) relative to self.root.
2415
2572
 
@@ -552,10 +552,10 @@ class TestReviewPrSuspectedAreas:
552
552
  assert "ci_decision" in data
553
553
 
554
554
  def test_review_pr_no_diff_error_when_git_but_no_changes(self, monkeypatch):
555
- # Simulate: is_git_repo=True but no changed files
555
+ # Simulate: is_git_repo=True but no uncommitted changes
556
556
  from sourcecode import prepare_context as _pc
557
557
  monkeypatch.setattr(_pc.TaskContextBuilder, "_is_git_repo", lambda self: True)
558
- monkeypatch.setattr(_pc.TaskContextBuilder, "_get_git_changed_files", lambda self, since=None: [])
558
+ monkeypatch.setattr(_pc.TaskContextBuilder, "_get_uncommitted_changed_files", lambda self: [])
559
559
  result = _invoke("prepare-context", "review-pr", str(FIXTURE))
560
560
  assert result.exit_code == 1
561
561
  data = _json(result)
@@ -563,12 +563,12 @@ class TestReviewPrSuspectedAreas:
563
563
  assert data.get("ci_decision") == "no_changes"
564
564
 
565
565
  def test_review_pr_with_mocked_diff_returns_pr_fields(self, monkeypatch):
566
- # Simulate: valid git repo with one changed controller file
566
+ # Simulate: valid git repo with one changed controller file (no --since → uncommitted path)
567
567
  from sourcecode import prepare_context as _pc
568
568
  monkeypatch.setattr(_pc.TaskContextBuilder, "_is_git_repo", lambda self: True)
569
569
  monkeypatch.setattr(
570
- _pc.TaskContextBuilder, "_get_git_changed_files",
571
- lambda self, since=None: ["src/main/java/com/example/UserController.java"],
570
+ _pc.TaskContextBuilder, "_get_uncommitted_changed_files",
571
+ lambda self: ["src/main/java/com/example/UserController.java"],
572
572
  )
573
573
  result = _invoke("prepare-context", "review-pr", str(FIXTURE))
574
574
  assert result.exit_code == 0, result.output
@@ -1,108 +0,0 @@
1
- # Continue Here — atlas-cli --agent token reduction
2
-
3
- **Paused:** 2026-05-16 (sesión 4)
4
- **Repo:** `/Users/user/Downloads/atlas-cli`
5
- **Branch:** master
6
- **Commit:** `f1cb001 corrigiendo bug --agent que duplicaba tokens sin justificación` (committed)
7
-
8
- ---
9
-
10
- ## Estado actual
11
-
12
- Sesión 4: refactorización de `agent_view()` en `serializer.py` completada. **Todo committed.** Working tree limpio.
13
-
14
- ---
15
-
16
- ## Qué se hizo esta sesión
17
-
18
- ### Problema resuelto
19
-
20
- `--agent` producía ~11.337 tokens en SAS vs ~5.885 de `--compact`, con contenido casi idéntico. Objetivo: reducir tokens significativamente manteniendo solo lo que diferencia `--agent`.
21
-
22
- ### Cambios en `agent_view()` (`src/sourcecode/serializer.py`)
23
-
24
- | Cambio | Impacto |
25
- |--------|---------|
26
- | Elimina `production_dependencies` / `dev_tools` / `test_utilities` / `build_tooling` (dep_groups asdict completo) | Mayor fuente de bloat: -3.000-5.000 tokens en repos grandes |
27
- | `key_dependencies`: de asdict+50 items → `name+version+role+risk_flags` solo, cap 20 | -500-1.500 tokens |
28
- | Elimina `confidence_summary.hard_signals` / `soft_signals` / `ignored_signals` | -500-1.000 tokens |
29
- | Elimina bloque `agent_mode` (contenido estático sin señal) | -80 tokens siempre |
30
- | Elimina `signals.env_vars.keys[]` (duplica compact `env_map`) | -300-500 tokens |
31
- | `signals.code_notes.top` cap 10→5, strip a `kind+path+line+text` | -200 tokens |
32
- | Entry points (no-bootstrap): strip a `path+kind+confidence` (como compact) | reducción moderada |
33
- | Elimina `development_entry_points` (noise para agentes de producción) | pequeña |
34
- | `architecture.layers` capado a 5 | pequeña |
35
-
36
- **Reducción estimada para SAS:** −40–60% tokens vs `--agent` anterior.
37
-
38
- ### Campos que permanecen únicos de `--agent`
39
-
40
- | Campo | Por qué justifica tokens extra vs `--compact` |
41
- |-------|----------------------------------------------|
42
- | `file_relevance` (top-20 scored) | Compact no tiene equivalente. Agente sabe qué leer sin explorar. |
43
- | `architecture.layers` | Compact solo tiene `architecture_summary` string. |
44
- | `suspicious_dependencies` | Deps declarados sin import observado. Compact no lo tiene. |
45
- | `confidence_reasons` | Explicación accionable de secciones low-confidence. Compact no lo tiene. |
46
-
47
- ### Tests actualizados
48
-
49
- - `tests/test_block5_quality.py` — 5 tests de `agent_mode` reemplazados por tests de las nuevas garantías (no `agent_mode`, no `hard_signals`, no `env_vars.keys`, no dep_groups)
50
- - `tests/test_pipeline_integrity.py` — `test_agent_splits_development_and_auxiliary_eps` → verifica que dev/aux EPs NO aparecen
51
-
52
- ---
53
-
54
- ## Tests al pausar
55
-
56
- Suite completa (sin fallos pre-existentes): **todo verde**
57
-
58
- Fallos pre-existentes (no relacionados, ya presentes antes):
59
- - `test_block2_coverage.py::test_java_marked_unsupported` — DocRecord bug en doc_analyzer.py
60
- - `test_dependency_analyzer_node_python.py::test_python_requirements_without_lockfile` — versión typer mismatch
61
-
62
- ---
63
-
64
- ## Pendiente / próximos pasos opcionales
65
-
66
- 1. **Smoke test en saint-server** para medir tokens reales antes/después:
67
- ```bash
68
- sourcecode saint-server --agent --output /tmp/agent_new.json
69
- python3 -c "import json,sys; d=json.load(open('/tmp/agent_new.json')); print('agent tokens (est):', len(json.dumps(d))//4)"
70
- ```
71
-
72
- 2. **Verificar que `suspicious_dependencies` es útil en repos reales** — en repos Python/JS (no JVM, donde el index de imports no funciona). En JVM siempre vacío por diseño.
73
-
74
- 3. **Ajustar caps según medición real**: si `file_relevance` (20 files) sigue siendo el mayor contribuyente de tokens, considerar reducir a 15. Medir con `--full` vs default.
75
-
76
- 4. **Smoke tests delta pendientes** de sesión anterior — ver sección "Smoke tests sesión 3" en historial de commits.
77
-
78
- ---
79
-
80
- ## Para retomar
81
-
82
- ```bash
83
- cd /Users/user/Downloads/atlas-cli
84
- git log --oneline -3
85
- # debe mostrar: f1cb001 corrigiendo bug --agent que duplicaba tokens sin justificación
86
-
87
- python3 -m pytest tests/ \
88
- --ignore=tests/test_block2_coverage.py \
89
- --deselect=tests/test_dependency_analyzer_node_python.py::test_python_requirements_without_lockfile_keeps_declared_versions \
90
- -q
91
- # Expected: todo verde
92
-
93
- # Verificación rápida agent_view
94
- python3 -c "
95
- from sourcecode.serializer import agent_view
96
- from sourcecode.schema import SourceMap, StackInfo, SourceMapMetadata
97
- sm = SourceMap(stacks=[StackInfo(stack='python', primary=True)], project_type='python', project_summary='test')
98
- r = agent_view(sm)
99
- assert 'agent_mode' not in r
100
- assert 'production_dependencies' not in r
101
- assert 'hard_signals' not in r.get('confidence_summary', {})
102
- print('OK — agent_mode/dep_groups/hard_signals all absent')
103
- "
104
- ```
105
-
106
- ---
107
-
108
- *Pausado 2026-05-16 sesión 4 — gsd:pause-work*
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