sourcecode 1.30.19__tar.gz → 1.30.21__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sourcecode-1.30.19 → sourcecode-1.30.21}/PKG-INFO +3 -3
- {sourcecode-1.30.19 → sourcecode-1.30.21}/README.md +2 -2
- {sourcecode-1.30.19 → sourcecode-1.30.21}/pyproject.toml +1 -1
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/__init__.py +1 -1
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/cli.py +109 -10
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/prepare_context.py +11 -11
- sourcecode-1.30.21/tests/test_output_ux.py +235 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/.continue-here.md +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/.gitignore +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/.ruff.toml +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/CONTRIBUTING.md +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/LICENSE +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/SECURITY.md +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/docs/privacy.md +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/docs/schema.md +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/raw +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/run_cli.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/classifier.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/flow_analyzer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/progress.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/redactor.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/repository_ir.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/scanner.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/schema.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/serializer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/src/sourcecode/workspace.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/__init__.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/conftest.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/coverage.xml +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/fastapi_app/src/main.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/go_service/cmd/api/main.go +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/go_service/go.mod +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/jacoco.xml +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/latin1_sample.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/latin1_sample_iso.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/lcov.info +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/nextjs_app/package.json +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/application/service/FindAusenteService.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/domain/entities/Ausente.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/infrastructure/rest/AusenteRestController.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/application/service/FindAutocoberturasService.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/domain/entities/Autocoberturas.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/infrastructure/rest/AutocoberturasRestController.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/application/service/FindCalendarioTrabajadorService.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/domain/entities/CalendarioTrabajador.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/infrastructure/rest/CalendarioTrabajadorRestController.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/application/service/FindDepartamentoService.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/domain/entities/Departamento.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/infrastructure/rest/DepartamentoRestController.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/application/service/FindEmpleadoService.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/domain/entities/Empleado.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/infrastructure/rest/EmpleadoRestController.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/config/FilterConfig.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/NominaRestController.java +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/fixtures/spring_boot_minimal/src/main/resources/mapper/HealthMapper.xml +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_architecture_analyzer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_architecture_summary.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_ast_extractor.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_block1_reliability.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_block2_coverage.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_block5_quality.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_bug_fixes_v16.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_classifier.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_cli.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_code_notes_analyzer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_context_scorer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_contract_pipeline.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_coverage_parser.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_cross_consistency.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_dependency_analyzer_node_python.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_dependency_analyzer_polyglot.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_dependency_schema.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_detector_dotnet.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_detector_go_rust_java.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_detector_nodejs.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_detector_php_ruby_dart.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_detector_python.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_detector_universal_managed.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_detector_universal_systems.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_detectors_base.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_doc_analyzer_jsdom.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_doc_analyzer_python.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_encoding_regression.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_graph_analyzer_polyglot.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_graph_analyzer_python_node.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_graph_schema.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_hybrid_inference.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_integration.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_integration_dependencies.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_integration_detection.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_integration_docs.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_integration_graph_modules.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_integration_lqn.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_integration_metrics.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_integration_multistack.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_integration_semantics.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_integration_universal.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_java_spring_integration.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_metrics_analyzer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_packaging.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_phase1_improvements.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_pipeline_integrity.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_real_projects.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_redactor.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_repository_ir.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_scanner.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_schema.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_schema_normalization.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_semantic_analyzer_node.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_semantic_analyzer_python.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_semantic_import_resolution.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_semantic_schema.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_signal_hierarchy.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_summarizer.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_surface_honesty.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_task_differentiation.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_telemetry.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_v131_improvements.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_v1_10_regressions.py +0 -0
- {sourcecode-1.30.19 → sourcecode-1.30.21}/tests/test_workspace_analyzer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 1.30.
|
|
3
|
+
Version: 1.30.21
|
|
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
|
**Deterministic, behavior-aware codebase context for AI agents and PR review.**
|
|
223
223
|
|
|
224
|
-

|
|
225
225
|

|
|
226
226
|
|
|
227
227
|
---
|
|
@@ -257,7 +257,7 @@ pipx install sourcecode
|
|
|
257
257
|
|
|
258
258
|
```bash
|
|
259
259
|
sourcecode version
|
|
260
|
-
# sourcecode 1.30.
|
|
260
|
+
# sourcecode 1.30.21
|
|
261
261
|
```
|
|
262
262
|
|
|
263
263
|
---
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Deterministic, behavior-aware codebase context for AI agents and PR review.**
|
|
4
4
|
|
|
5
|
-

|
|
6
6
|

|
|
7
7
|
|
|
8
8
|
---
|
|
@@ -38,7 +38,7 @@ pipx install sourcecode
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
sourcecode version
|
|
41
|
-
# sourcecode 1.30.
|
|
41
|
+
# sourcecode 1.30.21
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
---
|
|
@@ -1596,6 +1596,87 @@ def main(
|
|
|
1596
1596
|
typer.echo("✓ copied to clipboard", err=True)
|
|
1597
1597
|
|
|
1598
1598
|
|
|
1599
|
+
# ── prepare-context output helpers ────────────────────────────────────────────
|
|
1600
|
+
|
|
1601
|
+
def _make_explanation(reason: str, why: str) -> str:
|
|
1602
|
+
"""Merge reason+why into one human string. Drop internal pipe-format jargon."""
|
|
1603
|
+
if why and not why.startswith("artifact_type:"):
|
|
1604
|
+
return why
|
|
1605
|
+
return reason
|
|
1606
|
+
|
|
1607
|
+
|
|
1608
|
+
def _serialize_relevant_file(f: Any) -> dict:
|
|
1609
|
+
from dataclasses import asdict as _asdict
|
|
1610
|
+
d = {k: v for k, v in _asdict(f).items() if v != "" and v is not None}
|
|
1611
|
+
reason = d.pop("reason", "") or ""
|
|
1612
|
+
why = d.pop("why", "") or ""
|
|
1613
|
+
explanation = _make_explanation(reason, why)
|
|
1614
|
+
if explanation:
|
|
1615
|
+
d["explanation"] = explanation
|
|
1616
|
+
if reason:
|
|
1617
|
+
d["reason"] = reason
|
|
1618
|
+
return d
|
|
1619
|
+
|
|
1620
|
+
|
|
1621
|
+
def _transform_impact_scores(scores: dict) -> dict:
|
|
1622
|
+
"""Convert internal impact_score_per_file to human-readable review signals."""
|
|
1623
|
+
_THRESHOLDS = [(0.60, "high"), (0.40, "medium")]
|
|
1624
|
+
_CT_LABELS: dict[str, str] = {
|
|
1625
|
+
"security_change": "security-sensitive change",
|
|
1626
|
+
"behavioral_change": "behavioral change",
|
|
1627
|
+
"structural_change": "structural modification",
|
|
1628
|
+
"configuration_change": "configuration change",
|
|
1629
|
+
"dependency_change": "dependency update",
|
|
1630
|
+
"ui_change": "UI change",
|
|
1631
|
+
}
|
|
1632
|
+
result: dict = {}
|
|
1633
|
+
for path, entry in scores.items():
|
|
1634
|
+
raw = entry.get("_rank_score", 0.0)
|
|
1635
|
+
priority = next((p for thresh, p in _THRESHOLDS if raw >= thresh), "low")
|
|
1636
|
+
signals: list[str] = [
|
|
1637
|
+
_CT_LABELS[ct] for ct in entry.get("change_types", []) if ct in _CT_LABELS
|
|
1638
|
+
]
|
|
1639
|
+
ev = entry.get("evidence", {})
|
|
1640
|
+
callers = ev.get("reverse_edge_count", 0)
|
|
1641
|
+
if callers:
|
|
1642
|
+
signals.append(f"imported by {callers} other file{'s' if callers > 1 else ''}")
|
|
1643
|
+
out_entry: dict = {"review_priority": priority}
|
|
1644
|
+
if signals:
|
|
1645
|
+
out_entry["signals"] = signals
|
|
1646
|
+
result[path] = out_entry
|
|
1647
|
+
return result
|
|
1648
|
+
|
|
1649
|
+
|
|
1650
|
+
def _clean_system_impact(si: dict) -> dict:
|
|
1651
|
+
"""Remove empty lists/dicts from system_impact — only emit positive signals."""
|
|
1652
|
+
return {k: v for k, v in si.items() if v}
|
|
1653
|
+
|
|
1654
|
+
|
|
1655
|
+
def _build_human_summary(output: Any) -> dict:
|
|
1656
|
+
"""Human-readable summary block for delta/review-pr output."""
|
|
1657
|
+
concerns: list[str] = []
|
|
1658
|
+
si = getattr(output, "system_impact", {}) or {}
|
|
1659
|
+
for ri in si.get("runtime_impact", []):
|
|
1660
|
+
sig = ri.get("signal", "")
|
|
1661
|
+
if sig:
|
|
1662
|
+
concerns.append(sig)
|
|
1663
|
+
for bc in si.get("behavioral_changes", []):
|
|
1664
|
+
stmt = bc.get("statement", "")
|
|
1665
|
+
if stmt:
|
|
1666
|
+
concerns.append(stmt)
|
|
1667
|
+
cov = getattr(output, "test_coverage_risk", {}) or {}
|
|
1668
|
+
missing = cov.get("changed_files_without_tests", [])
|
|
1669
|
+
if missing:
|
|
1670
|
+
concerns.append(f"{len(missing)} changed file(s) without test coverage detected")
|
|
1671
|
+
summary: dict = {}
|
|
1672
|
+
if getattr(output, "impact_summary", None):
|
|
1673
|
+
summary["description"] = output.impact_summary
|
|
1674
|
+
if concerns:
|
|
1675
|
+
summary["review_concerns"] = concerns[:6]
|
|
1676
|
+
summary["confidence"] = (getattr(output, "confidence", None) or "medium").upper()
|
|
1677
|
+
return summary
|
|
1678
|
+
|
|
1679
|
+
|
|
1599
1680
|
@app.command("prepare-context")
|
|
1600
1681
|
def prepare_context_cmd(
|
|
1601
1682
|
task: Optional[str] = typer.Argument(
|
|
@@ -1723,8 +1804,16 @@ def prepare_context_cmd(
|
|
|
1723
1804
|
import time as _time
|
|
1724
1805
|
|
|
1725
1806
|
builder = TaskContextBuilder(target)
|
|
1807
|
+
_progress = Progress()
|
|
1808
|
+
_phase = f"analyzing ({task})"
|
|
1809
|
+
if since:
|
|
1810
|
+
_phase += f" since {since}"
|
|
1811
|
+
_progress.start(_phase)
|
|
1726
1812
|
_t0 = _time.perf_counter()
|
|
1727
|
-
|
|
1813
|
+
try:
|
|
1814
|
+
output = builder.build(task, since=since, symptom=symptom)
|
|
1815
|
+
finally:
|
|
1816
|
+
_progress.finish()
|
|
1728
1817
|
_t_total = (_time.perf_counter() - _t0) * 1000
|
|
1729
1818
|
|
|
1730
1819
|
if debug_perf:
|
|
@@ -1805,7 +1894,7 @@ def prepare_context_cmd(
|
|
|
1805
1894
|
out["confidence"] = output.confidence
|
|
1806
1895
|
if task != "review-pr" and _task_include("relevant_files"):
|
|
1807
1896
|
out["relevant_files"] = [
|
|
1808
|
-
|
|
1897
|
+
_serialize_relevant_file(f)
|
|
1809
1898
|
for f in output.relevant_files
|
|
1810
1899
|
]
|
|
1811
1900
|
if _task_include("key_dependencies") and output.key_dependencies:
|
|
@@ -1856,16 +1945,19 @@ def prepare_context_cmd(
|
|
|
1856
1945
|
out["affected_modules"] = output.affected_modules
|
|
1857
1946
|
if output.risk_areas:
|
|
1858
1947
|
out["risk_areas"] = output.risk_areas
|
|
1859
|
-
if output.why_these_files:
|
|
1860
|
-
out["reasoning"] = output.why_these_files
|
|
1861
1948
|
if output.change_type:
|
|
1862
1949
|
out["change_type"] = output.change_type
|
|
1863
1950
|
if output.system_impact:
|
|
1864
|
-
|
|
1951
|
+
_si = _clean_system_impact(output.system_impact)
|
|
1952
|
+
if _si:
|
|
1953
|
+
out["system_impact"] = _si
|
|
1865
1954
|
if output.dependency_graph_summary:
|
|
1866
|
-
|
|
1955
|
+
_dgraph = {k: v for k, v in output.dependency_graph_summary.items() if v is not None}
|
|
1956
|
+
if _dgraph:
|
|
1957
|
+
out["dependency_graph_summary"] = _dgraph
|
|
1867
1958
|
if output.impact_score_per_file:
|
|
1868
|
-
out["impact_score_per_file"] = output.impact_score_per_file
|
|
1959
|
+
out["impact_score_per_file"] = _transform_impact_scores(output.impact_score_per_file)
|
|
1960
|
+
out["summary"] = _build_human_summary(output)
|
|
1869
1961
|
# review-pr specific fields
|
|
1870
1962
|
if task == "review-pr":
|
|
1871
1963
|
if output.error_code:
|
|
@@ -1920,8 +2012,7 @@ def prepare_context_cmd(
|
|
|
1920
2012
|
out["behavioral_impact"] = output.behavioral_impact
|
|
1921
2013
|
if output.impact_summary:
|
|
1922
2014
|
out["impact_summary"] = output.impact_summary
|
|
1923
|
-
|
|
1924
|
-
out["reasoning"] = output.why_these_files
|
|
2015
|
+
out["summary"] = _build_human_summary(output)
|
|
1925
2016
|
# git-first scope metadata
|
|
1926
2017
|
out["scope"] = {
|
|
1927
2018
|
"source": output.scope_source or "git_diff",
|
|
@@ -2105,7 +2196,15 @@ def repo_ir_cmd(
|
|
|
2105
2196
|
)
|
|
2106
2197
|
return
|
|
2107
2198
|
|
|
2108
|
-
|
|
2199
|
+
_ir_phase = f"extracting IR ({len(file_list)} files)"
|
|
2200
|
+
if since:
|
|
2201
|
+
_ir_phase += f" since {since}"
|
|
2202
|
+
_ir_progress = Progress()
|
|
2203
|
+
_ir_progress.start(_ir_phase)
|
|
2204
|
+
try:
|
|
2205
|
+
ir = build_repo_ir(file_list, root, since=since)
|
|
2206
|
+
finally:
|
|
2207
|
+
_ir_progress.finish()
|
|
2109
2208
|
ir = apply_ir_size_limits(
|
|
2110
2209
|
ir,
|
|
2111
2210
|
max_nodes=max_nodes,
|
|
@@ -556,7 +556,7 @@ _ARTIFACT_CHANGE_EFFECT: dict[str, str] = {
|
|
|
556
556
|
"test": "test file (no production code modified)",
|
|
557
557
|
"documentation": "documentation file (no runtime impact)",
|
|
558
558
|
"ide_noise": "IDE/tooling artifact (no application impact)",
|
|
559
|
-
"source": "application source (
|
|
559
|
+
"source": "application source file (role could not be confirmed from code signals)",
|
|
560
560
|
}
|
|
561
561
|
|
|
562
562
|
# Maps frontend symptom keywords → backend terms likely to contain the root cause.
|
|
@@ -1156,22 +1156,24 @@ class TaskContextBuilder:
|
|
|
1156
1156
|
else "unknown"
|
|
1157
1157
|
)
|
|
1158
1158
|
_impact_entry = _delta_impact_score_per_file.get(_f) or {}
|
|
1159
|
-
|
|
1159
|
+
_ev_complete = {k: v for k, v in _impact_entry.get("evidence", {}).items() if v}
|
|
1160
|
+
_entry: dict = {
|
|
1160
1161
|
"path": _f,
|
|
1161
1162
|
"diff_source": _diff_source,
|
|
1162
1163
|
"role": _role_obj,
|
|
1163
1164
|
"artifact_type": _f_atype,
|
|
1164
1165
|
"evidence": _evidence,
|
|
1165
1166
|
"change_effect": {
|
|
1166
|
-
"statement": _ARTIFACT_CHANGE_EFFECT.get(_f_atype, "application source (
|
|
1167
|
+
"statement": _ARTIFACT_CHANGE_EFFECT.get(_f_atype, "application source file (role could not be confirmed)"),
|
|
1167
1168
|
"classification_method": _f_cls.get("confidence", "low"),
|
|
1168
1169
|
"epistemic_level": (
|
|
1169
1170
|
"STRUCTURAL SIGNAL" if _f_cls.get("confidence", "low") == "high"
|
|
1170
1171
|
else "INFERRED (LOW CONFIDENCE)"
|
|
1171
1172
|
),
|
|
1172
1173
|
},
|
|
1173
|
-
"evidence_completeness": _impact_entry.get("evidence", {}),
|
|
1174
1174
|
}
|
|
1175
|
+
if _ev_complete:
|
|
1176
|
+
_entry["evidence_completeness"] = _ev_complete
|
|
1175
1177
|
_pr_runtime_changes.append(_entry)
|
|
1176
1178
|
# Split committed vs uncommitted — never merged
|
|
1177
1179
|
if _f in _committed_set:
|
|
@@ -2992,12 +2994,12 @@ class TaskContextBuilder:
|
|
|
2992
2994
|
|
|
2993
2995
|
# ── Step 6: analysis gaps ──────────────────────────────────────────────
|
|
2994
2996
|
_bfs_note = (
|
|
2995
|
-
f"
|
|
2997
|
+
f"multi-hop import tracing performed (depth {_max_hop})"
|
|
2996
2998
|
if _max_hop >= 1
|
|
2997
|
-
else "no
|
|
2999
|
+
else "no downstream dependencies could be verified"
|
|
2998
3000
|
)
|
|
2999
3001
|
analysis_gaps: list[str] = [
|
|
3000
|
-
f"Related file expansion
|
|
3002
|
+
f"Related file expansion via import analysis and directory proximity ({_bfs_note})",
|
|
3001
3003
|
]
|
|
3002
3004
|
if _expansion_truncated:
|
|
3003
3005
|
analysis_gaps.insert(0,
|
|
@@ -3015,10 +3017,8 @@ class TaskContextBuilder:
|
|
|
3015
3017
|
low_confidence = [f for f, cls in classifications.items() if cls.get("confidence") == "low" and not cls["is_noise"]]
|
|
3016
3018
|
if low_confidence:
|
|
3017
3019
|
analysis_gaps.append(
|
|
3018
|
-
f"{len(low_confidence)} file(s)
|
|
3019
|
-
" (
|
|
3020
|
-
" — consider adding stem patterns to _classify_changed_file: "
|
|
3021
|
-
+ ", ".join(Path(f).name for f in low_confidence[:3])
|
|
3020
|
+
f"{len(low_confidence)} file(s) role inferred from filename only"
|
|
3021
|
+
f" (no code signal found): {', '.join(Path(f).name for f in low_confidence[:3])}"
|
|
3022
3022
|
)
|
|
3023
3023
|
if not affected_modules_set and any(not cls["is_noise"] for cls in classifications.values()):
|
|
3024
3024
|
analysis_gaps.append(
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""test_output_ux.py — Verify output UX: no internal jargon, no redundancy, correct structure.
|
|
2
|
+
|
|
3
|
+
Acceptance criteria (from spec):
|
|
4
|
+
1. impact_score_per_file: no _rank_score, no has_* booleans
|
|
5
|
+
2. relevant_files: no 'why' key; 'explanation' present when meaningful
|
|
6
|
+
3. reasoning block absent from delta/review-pr output
|
|
7
|
+
4. system_impact: no empty arrays
|
|
8
|
+
5. human summary (summary) present in delta/review-pr success output
|
|
9
|
+
6. analysis_gaps: no pipeline jargon ("BFS", "type-aware chain", "import-link propagation")
|
|
10
|
+
7. Output size ≥ 35% smaller than internal-dump baseline for impact_score_per_file
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
import pytest
|
|
19
|
+
from typer.testing import CliRunner
|
|
20
|
+
|
|
21
|
+
from sourcecode.cli import app
|
|
22
|
+
from sourcecode import prepare_context as _pc
|
|
23
|
+
|
|
24
|
+
runner = CliRunner()
|
|
25
|
+
|
|
26
|
+
FIXTURE = Path(__file__).parent / "fixtures" / "fastapi_app"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _invoke(*args: str) -> Any:
|
|
30
|
+
return runner.invoke(app, list(args))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _json(result: Any) -> dict:
|
|
34
|
+
return json.loads(result.output)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# ── helpers ───────────────────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
def _make_delta_output(monkeypatch, changed: list[str]) -> dict:
|
|
40
|
+
"""Return the parsed JSON output for a delta run with mocked changed files."""
|
|
41
|
+
monkeypatch.setattr(
|
|
42
|
+
_pc.TaskContextBuilder,
|
|
43
|
+
"_resolve_git_root",
|
|
44
|
+
lambda self: FIXTURE,
|
|
45
|
+
)
|
|
46
|
+
result = _invoke("prepare-context", "delta", str(FIXTURE), "--since", "HEAD~1")
|
|
47
|
+
assert result.exit_code in (0, 1), result.output
|
|
48
|
+
return _json(result)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _make_review_pr_output(monkeypatch) -> dict:
|
|
52
|
+
"""Return parsed JSON output for review-pr with a mocked changed controller."""
|
|
53
|
+
changed = ["src/main/java/com/example/UserController.java"]
|
|
54
|
+
monkeypatch.setattr(
|
|
55
|
+
_pc.TaskContextBuilder,
|
|
56
|
+
"_resolve_git_root",
|
|
57
|
+
lambda self: FIXTURE,
|
|
58
|
+
)
|
|
59
|
+
monkeypatch.setattr(
|
|
60
|
+
_pc.TaskContextBuilder,
|
|
61
|
+
"_get_pr_scope_files",
|
|
62
|
+
lambda self, since=None: (changed, "git_diff", changed, []),
|
|
63
|
+
)
|
|
64
|
+
result = _invoke("prepare-context", "review-pr", str(FIXTURE))
|
|
65
|
+
assert result.exit_code == 0, result.output
|
|
66
|
+
return _json(result)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# ── impact_score_per_file structure ──────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
class TestImpactScoreOutput:
|
|
72
|
+
"""impact_score_per_file must expose review_priority+signals, not internal scores."""
|
|
73
|
+
|
|
74
|
+
def test_no_rank_score_in_output(self, monkeypatch):
|
|
75
|
+
data = _make_review_pr_output(monkeypatch)
|
|
76
|
+
for entry in data.get("impact_score_per_file", {}).values():
|
|
77
|
+
assert "_rank_score" not in entry, f"_rank_score leaked into output: {entry}"
|
|
78
|
+
|
|
79
|
+
def test_no_boolean_evidence_spam(self, monkeypatch):
|
|
80
|
+
data = _make_review_pr_output(monkeypatch)
|
|
81
|
+
for path, entry in data.get("impact_score_per_file", {}).items():
|
|
82
|
+
ev = entry.get("evidence", {})
|
|
83
|
+
for k, v in ev.items():
|
|
84
|
+
assert v is not False, f"{path}: false evidence key '{k}' should be omitted"
|
|
85
|
+
assert "has_reverse_edges" not in entry, f"boolean key leaked: {path}"
|
|
86
|
+
assert "has_route_diff" not in entry, f"boolean key leaked: {path}"
|
|
87
|
+
assert "has_security_diff" not in entry, f"boolean key leaked: {path}"
|
|
88
|
+
assert "has_wiring_evidence" not in entry, f"boolean key leaked: {path}"
|
|
89
|
+
|
|
90
|
+
def test_review_priority_field_present(self, monkeypatch):
|
|
91
|
+
data = _make_review_pr_output(monkeypatch)
|
|
92
|
+
for path, entry in data.get("impact_score_per_file", {}).items():
|
|
93
|
+
assert "review_priority" in entry, f"review_priority missing for {path}"
|
|
94
|
+
assert entry["review_priority"] in ("high", "medium", "low"), (
|
|
95
|
+
f"unexpected priority value for {path}: {entry['review_priority']}"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def test_size_reduction_vs_internal(self, monkeypatch):
|
|
99
|
+
"""Transformed impact_score_per_file must be ≥35% smaller in bytes."""
|
|
100
|
+
from sourcecode.cli import _transform_impact_scores
|
|
101
|
+
internal = {
|
|
102
|
+
"src/Foo.java": {
|
|
103
|
+
"_rank_score": 0.325,
|
|
104
|
+
"change_types": ["behavioral_change"],
|
|
105
|
+
"diff_severity": "api_change",
|
|
106
|
+
"evidence": {
|
|
107
|
+
"has_reverse_edges": False,
|
|
108
|
+
"reverse_edge_count": 0,
|
|
109
|
+
"has_route_diff": True,
|
|
110
|
+
"has_security_diff": False,
|
|
111
|
+
"has_wiring_evidence": False,
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
before = len(json.dumps(internal))
|
|
116
|
+
after = len(json.dumps(_transform_impact_scores(internal)))
|
|
117
|
+
reduction = (before - after) / before
|
|
118
|
+
assert reduction >= 0.35, (
|
|
119
|
+
f"Expected ≥35% size reduction, got {reduction:.0%}. "
|
|
120
|
+
f"before={before}B after={after}B"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
# ── relevant_files structure ──────────────────────────────────────────────────
|
|
125
|
+
|
|
126
|
+
class TestRelevantFilesOutput:
|
|
127
|
+
"""relevant_files must not expose 'why' jargon field; explanation replaces it."""
|
|
128
|
+
|
|
129
|
+
def test_no_why_field_in_output(self):
|
|
130
|
+
result = _invoke("prepare-context", "explain", str(FIXTURE))
|
|
131
|
+
assert result.exit_code == 0, result.output
|
|
132
|
+
data = _json(result)
|
|
133
|
+
for rf in data.get("relevant_files", []):
|
|
134
|
+
assert "why" not in rf, (
|
|
135
|
+
f"'why' field leaked into output for {rf.get('path')}: {rf}"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
def test_explanation_or_reason_present(self):
|
|
139
|
+
result = _invoke("prepare-context", "explain", str(FIXTURE))
|
|
140
|
+
assert result.exit_code == 0, result.output
|
|
141
|
+
data = _json(result)
|
|
142
|
+
for rf in data.get("relevant_files", []):
|
|
143
|
+
has_info = "explanation" in rf or "reason" in rf
|
|
144
|
+
assert has_info, f"No explanation/reason in relevant_file: {rf}"
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# ── reasoning block removed ───────────────────────────────────────────────────
|
|
148
|
+
|
|
149
|
+
class TestReasoningBlockRemoved:
|
|
150
|
+
"""delta and review-pr must not emit 'reasoning' block (redundant with relevant_files)."""
|
|
151
|
+
|
|
152
|
+
def test_delta_no_reasoning_key(self):
|
|
153
|
+
result = _invoke("prepare-context", "delta", str(FIXTURE))
|
|
154
|
+
assert result.exit_code in (0, 1), result.output
|
|
155
|
+
data = _json(result)
|
|
156
|
+
if data.get("task") == "delta":
|
|
157
|
+
assert "reasoning" not in data, (
|
|
158
|
+
"'reasoning' block still in delta output — should be removed (duplicate)"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
def test_review_pr_no_reasoning_key(self, monkeypatch):
|
|
162
|
+
data = _make_review_pr_output(monkeypatch)
|
|
163
|
+
assert "reasoning" not in data, (
|
|
164
|
+
"'reasoning' block still in review-pr output — should be removed (duplicate)"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# ── system_impact clean ───────────────────────────────────────────────────────
|
|
169
|
+
|
|
170
|
+
class TestSystemImpactClean:
|
|
171
|
+
"""system_impact must not contain empty arrays."""
|
|
172
|
+
|
|
173
|
+
def test_no_empty_arrays_in_system_impact(self):
|
|
174
|
+
result = _invoke("prepare-context", "delta", str(FIXTURE))
|
|
175
|
+
assert result.exit_code in (0, 1), result.output
|
|
176
|
+
data = _json(result)
|
|
177
|
+
si = data.get("system_impact", {})
|
|
178
|
+
for k, v in si.items():
|
|
179
|
+
assert v != [], f"system_impact['{k}'] is empty list — should be omitted"
|
|
180
|
+
assert v != {}, f"system_impact['{k}'] is empty dict — should be omitted"
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
# ── human summary present ─────────────────────────────────────────────────────
|
|
184
|
+
|
|
185
|
+
class TestHumanSummary:
|
|
186
|
+
"""delta and review-pr success output must include a 'summary' block."""
|
|
187
|
+
|
|
188
|
+
def test_review_pr_has_summary(self, monkeypatch):
|
|
189
|
+
data = _make_review_pr_output(monkeypatch)
|
|
190
|
+
assert "summary" in data, "review-pr output missing 'summary' block"
|
|
191
|
+
s = data["summary"]
|
|
192
|
+
assert "confidence" in s, f"summary missing confidence field: {s}"
|
|
193
|
+
assert s["confidence"] in ("HIGH", "MEDIUM", "LOW"), (
|
|
194
|
+
f"confidence has unexpected value: {s['confidence']}"
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
# ── analysis_gaps language ────────────────────────────────────────────────────
|
|
199
|
+
|
|
200
|
+
class TestAnalysisGapsLanguage:
|
|
201
|
+
"""analysis_gaps must not contain pipeline-internal jargon."""
|
|
202
|
+
|
|
203
|
+
_JARGON = [
|
|
204
|
+
"BFS",
|
|
205
|
+
"type-aware chain expansion",
|
|
206
|
+
"import-link propagation",
|
|
207
|
+
"propagation_depth=",
|
|
208
|
+
"artifact role requires annotation inspection",
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
def test_no_jargon_in_analysis_gaps(self):
|
|
212
|
+
result = _invoke("prepare-context", "delta", str(FIXTURE))
|
|
213
|
+
assert result.exit_code in (0, 1), result.output
|
|
214
|
+
data = _json(result)
|
|
215
|
+
for gap in data.get("gaps", []):
|
|
216
|
+
for jargon in self._JARGON:
|
|
217
|
+
assert jargon not in gap, (
|
|
218
|
+
f"Internal jargon '{jargon}' found in analysis_gaps: {gap!r}"
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
# ── dependency_graph_summary clean ───────────────────────────────────────────
|
|
223
|
+
|
|
224
|
+
class TestDependencyGraphSummaryClean:
|
|
225
|
+
"""dependency_graph_summary must not emit null fields."""
|
|
226
|
+
|
|
227
|
+
def test_no_null_propagation_depth(self):
|
|
228
|
+
result = _invoke("prepare-context", "delta", str(FIXTURE))
|
|
229
|
+
assert result.exit_code in (0, 1), result.output
|
|
230
|
+
data = _json(result)
|
|
231
|
+
dgraph = data.get("dependency_graph_summary", {})
|
|
232
|
+
for k, v in dgraph.items():
|
|
233
|
+
assert v is not None, (
|
|
234
|
+
f"dependency_graph_summary['{k}'] is null — should be omitted"
|
|
235
|
+
)
|
{sourcecode-1.30.19 → sourcecode-1.30.21}/.agents/skills/source-command-gsd-join-discord/SKILL.md
RENAMED
|
File without changes
|
{sourcecode-1.30.19 → sourcecode-1.30.21}/.agents/skills/source-command-gsd-review-backlog/SKILL.md
RENAMED
|
File without changes
|
{sourcecode-1.30.19 → sourcecode-1.30.21}/.agents/skills/source-command-gsd-workstreams/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
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
|