smart-spatial-system 0.2.1__tar.gz → 0.2.2__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 (432) hide show
  1. {smart_spatial_system-0.2.1/smart_spatial_system.egg-info → smart_spatial_system-0.2.2}/PKG-INFO +1 -1
  2. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/llm_spec_generator.py +196 -0
  3. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/pyproject.toml +1 -1
  4. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2/smart_spatial_system.egg-info}/PKG-INFO +1 -1
  5. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_llm_spec_generator.py +217 -0
  6. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/LICENSE +0 -0
  7. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/README.md +0 -0
  8. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/api/__init__.py +0 -0
  9. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/api/auth.py +0 -0
  10. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/api/main.py +0 -0
  11. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/api/routers/__init__.py +0 -0
  12. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/api/routers/data_source_connectors.py +0 -0
  13. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/api/routers/data_sources.py +0 -0
  14. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/api/routers/plugins_settings.py +0 -0
  15. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/api/routers/projects.py +0 -0
  16. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/api/routers/query_planner.py +0 -0
  17. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/api/routers/requests_outputs.py +0 -0
  18. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/api/routers/system.py +0 -0
  19. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/api/routers/uploads.py +0 -0
  20. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/api/routers/weights.py +0 -0
  21. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/api/support.py +0 -0
  22. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/__init__.py +0 -0
  23. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/__init__.py +0 -0
  24. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/area_perimeter_calc.example.yaml +0 -0
  25. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/area_perimeter_calc.yaml +0 -0
  26. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/attribute_statistics.example.yaml +0 -0
  27. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/attribute_statistics.yaml +0 -0
  28. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/band_math.example.yaml +0 -0
  29. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/band_math.yaml +0 -0
  30. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/buffer_analysis.example.yaml +0 -0
  31. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/buffer_analysis.yaml +0 -0
  32. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/centroid_extractor.example.yaml +0 -0
  33. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/centroid_extractor.yaml +0 -0
  34. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/core_vector.example.yaml +0 -0
  35. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/core_vector.yaml +0 -0
  36. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/crs_transformer.example.yaml +0 -0
  37. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/crs_transformer.yaml +0 -0
  38. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/data_writer_exporter.example.yaml +0 -0
  39. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/data_writer_exporter.yaml +0 -0
  40. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/dissolve_aggregator.example.yaml +0 -0
  41. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/dissolve_aggregator.yaml +0 -0
  42. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/distance_calculator.example.yaml +0 -0
  43. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/distance_calculator.yaml +0 -0
  44. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/feature_enrichment.example.yaml +0 -0
  45. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/feature_enrichment.yaml +0 -0
  46. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/feature_scoring.example.yaml +0 -0
  47. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/feature_scoring.yaml +0 -0
  48. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/geocoding_resolver.example.yaml +0 -0
  49. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/geocoding_resolver.yaml +0 -0
  50. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/geometry_validator.example.yaml +0 -0
  51. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/geometry_validator.yaml +0 -0
  52. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/local_raster_loader.example.yaml +0 -0
  53. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/local_raster_loader.yaml +0 -0
  54. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/local_vector_loader.example.yaml +0 -0
  55. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/local_vector_loader.yaml +0 -0
  56. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/ndvi_calculator.example.yaml +0 -0
  57. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/ndvi_calculator.yaml +0 -0
  58. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/nearest_neighbor.example.yaml +0 -0
  59. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/nearest_neighbor.yaml +0 -0
  60. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/postgis_connector.example.yaml +0 -0
  61. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/postgis_connector.yaml +0 -0
  62. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/raster_clip_mask.example.yaml +0 -0
  63. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/raster_clip_mask.yaml +0 -0
  64. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/raster_reclassify.example.yaml +0 -0
  65. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/raster_reclassify.yaml +0 -0
  66. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/raster_statistics.example.yaml +0 -0
  67. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/raster_statistics.yaml +0 -0
  68. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/raster_threshold.example.yaml +0 -0
  69. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/raster_threshold.yaml +0 -0
  70. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/raster_to_vector.example.yaml +0 -0
  71. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/raster_to_vector.yaml +0 -0
  72. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/risk_enrichment.example.yaml +0 -0
  73. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/risk_enrichment.yaml +0 -0
  74. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/slope_aspect.yaml +0 -0
  75. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/spatial_intersection.example.yaml +0 -0
  76. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/spatial_intersection.yaml +0 -0
  77. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/spatial_join.example.yaml +0 -0
  78. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/spatial_join.yaml +0 -0
  79. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/spatial_predicate.example.yaml +0 -0
  80. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/spatial_predicate.yaml +0 -0
  81. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/spatial_query_filter.example.yaml +0 -0
  82. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/spatial_query_filter.yaml +0 -0
  83. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/spectral_indices.example.yaml +0 -0
  84. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/spectral_indices.yaml +0 -0
  85. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/wms_wfs_fetcher.example.yaml +0 -0
  86. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/wms_wfs_fetcher.yaml +0 -0
  87. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/zonal_statistics.example.yaml +0 -0
  88. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/config/plugins/zonal_statistics.yaml +0 -0
  89. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/__init__.py +0 -0
  90. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/audit.py +0 -0
  91. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/capability_registry.py +0 -0
  92. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/capability_router.py +0 -0
  93. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/capability_scoring.py +0 -0
  94. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/data_source_service.py +0 -0
  95. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/error_contract.py +0 -0
  96. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/feedback.py +0 -0
  97. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/feedback_proposal_service.py +0 -0
  98. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/input_error_mapping.py +0 -0
  99. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/input_reference_resolver.py +0 -0
  100. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/kernel_artifacts.py +0 -0
  101. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/learning_signals.py +0 -0
  102. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/llm_client.py +0 -0
  103. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/llm_gate.py +0 -0
  104. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/llm_intent_planner.py +0 -0
  105. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/loader_plugin_contract.py +0 -0
  106. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/map_layer_service.py +0 -0
  107. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/map_layers.py +0 -0
  108. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/models.py +0 -0
  109. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/natural_query_runner.py +0 -0
  110. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/output_service.py +0 -0
  111. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/output_storage.py +0 -0
  112. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/pipeline_executor.py +0 -0
  113. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/plan_builder.py +0 -0
  114. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/__init__.py +0 -0
  115. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/capability_resolver.py +0 -0
  116. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/dag.py +0 -0
  117. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/dag_executor.py +0 -0
  118. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/error_mapping.py +0 -0
  119. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/kernel_execution_bridge.py +0 -0
  120. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/kernel_plan_adapter.py +0 -0
  121. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/llm_query_spec.py +0 -0
  122. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/op_catalog.py +0 -0
  123. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/output_parity.py +0 -0
  124. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/planner.py +0 -0
  125. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/postgis_semantic_resolver.py +0 -0
  126. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/query_spec_contract.py +0 -0
  127. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/report_spec.py +0 -0
  128. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/runner.py +0 -0
  129. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/semantic_planning_context.py +0 -0
  130. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/planning/spec.py +0 -0
  131. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/plugin_config_store.py +0 -0
  132. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/plugin_error_mapping.py +0 -0
  133. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/plugin_modules.py +0 -0
  134. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/plugin_runtime_service.py +0 -0
  135. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/plugin_state.py +0 -0
  136. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/production_response.py +0 -0
  137. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/project_service.py +0 -0
  138. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/project_store.py +0 -0
  139. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/provider_error_mapping.py +0 -0
  140. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/query_execution_service.py +0 -0
  141. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/query_parser.py +0 -0
  142. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/request_history_service.py +0 -0
  143. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/response_assembler.py +0 -0
  144. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/response_builder.py +0 -0
  145. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/router_decision.py +0 -0
  146. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/routing_aware_natural_query_runner.py +0 -0
  147. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/routing_aware_plan_builder.py +0 -0
  148. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/runtime_paths.py +0 -0
  149. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/service.py +0 -0
  150. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/statistics.py +0 -0
  151. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/upload_service.py +0 -0
  152. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/upload_storage.py +0 -0
  153. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/weight_proposals.py +0 -0
  154. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/weight_store_persistence.py +0 -0
  155. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/orchestrator/weighted_router.py +0 -0
  156. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/__init__.py +0 -0
  157. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/_shared/__init__.py +0 -0
  158. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/_shared/local_path_validation.py +0 -0
  159. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/_shared/numeric_validation.py +0 -0
  160. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/_shared/plugin_config.py +0 -0
  161. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/area_perimeter_calc.py +0 -0
  162. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/attribute_statistics.py +0 -0
  163. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/band_math.py +0 -0
  164. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/buffer_analysis.py +0 -0
  165. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/centroid_extractor.py +0 -0
  166. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/core_vector.py +0 -0
  167. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/crs_transformer.py +0 -0
  168. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/data_writer_exporter.py +0 -0
  169. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/dissolve_aggregator.py +0 -0
  170. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/distance_calculator.py +0 -0
  171. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/feature_enrichment.py +0 -0
  172. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/feature_scoring.py +0 -0
  173. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/geocoding_resolver.py +0 -0
  174. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/geometry_validator.py +0 -0
  175. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/local_raster_loader.py +0 -0
  176. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/local_vector_loader.py +0 -0
  177. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/ndvi_analysis.py +0 -0
  178. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/ndvi_calculator.py +0 -0
  179. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/nearest_neighbor.py +0 -0
  180. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/pdf_renderer.py +0 -0
  181. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/postgis_connector.py +0 -0
  182. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/raster_clip_mask.py +0 -0
  183. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/raster_reclassify.py +0 -0
  184. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/raster_statistics.py +0 -0
  185. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/raster_threshold.py +0 -0
  186. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/raster_to_vector.py +0 -0
  187. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/real_estate_scoring.py +0 -0
  188. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/real_estate_spatial_enrichment.py +0 -0
  189. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/report_builder.py +0 -0
  190. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/risk_enrichment.py +0 -0
  191. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/slope_aspect.py +0 -0
  192. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/spatial_intersection.py +0 -0
  193. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/spatial_join.py +0 -0
  194. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/spatial_predicate.py +0 -0
  195. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/spatial_query_filter.py +0 -0
  196. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/spectral_indices.py +0 -0
  197. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/wms_wfs_fetcher.py +0 -0
  198. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/plugins/zonal_statistics.py +0 -0
  199. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/setup.cfg +0 -0
  200. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/__init__.py +0 -0
  201. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/__main__.py +0 -0
  202. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/__init__.py +0 -0
  203. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/__init__.py +0 -0
  204. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/data_source_service.py +0 -0
  205. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/feedback_proposal_service.py +0 -0
  206. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/llm_intent_adapter.py +0 -0
  207. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/map_layer_service.py +0 -0
  208. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/output_service.py +0 -0
  209. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/planning_execution_policy.py +0 -0
  210. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/planning_response_adapter.py +0 -0
  211. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/plugin_runtime_service.py +0 -0
  212. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/project_service.py +0 -0
  213. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/__init__.py +0 -0
  214. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/accessibility_query_spec.py +0 -0
  215. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/direct_query_dispatch.py +0 -0
  216. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/natural_query_context.py +0 -0
  217. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/natural_query_dispatch.py +0 -0
  218. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/natural_query_execution.py +0 -0
  219. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/natural_query_failure.py +0 -0
  220. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/natural_query_persistence.py +0 -0
  221. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/planning_context.py +0 -0
  222. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/planning_execution.py +0 -0
  223. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/planning_persistence.py +0 -0
  224. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/planning_response.py +0 -0
  225. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/postgis_planning_context.py +0 -0
  226. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/real_estate_analysis_inspector.py +0 -0
  227. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/real_estate_classifier.py +0 -0
  228. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/real_estate_context.py +0 -0
  229. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/real_estate_document_renderer.py +0 -0
  230. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/real_estate_missing_inputs.py +0 -0
  231. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/real_estate_ranking_artifacts.py +0 -0
  232. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/real_estate_ranking_direct_handler.py +0 -0
  233. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/real_estate_ranking_execution.py +0 -0
  234. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/real_estate_ranking_query_spec.py +0 -0
  235. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/real_estate_ranking_response.py +0 -0
  236. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/real_estate_report_payload.py +0 -0
  237. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution/real_estate_scoring.py +0 -0
  238. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_execution_service.py +0 -0
  239. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/query_spec_enrichment.py +0 -0
  240. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/real_estate_spatial_helpers.py +0 -0
  241. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/request_history_service.py +0 -0
  242. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/system_status_query_handler.py +0 -0
  243. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/upload_service.py +0 -0
  244. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/vector_display_handler.py +0 -0
  245. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/vector_geojson_helpers.py +0 -0
  246. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/application/services/vector_query_classifier.py +0 -0
  247. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/cli.py +0 -0
  248. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/domain/__init__.py +0 -0
  249. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/domain/contracts/__init__.py +0 -0
  250. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/domain/models/__init__.py +0 -0
  251. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/infrastructure/__init__.py +0 -0
  252. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/infrastructure/stores/__init__.py +0 -0
  253. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/interfaces/__init__.py +0 -0
  254. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/interfaces/api/__init__.py +0 -0
  255. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/interfaces/api/routers/__init__.py +0 -0
  256. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/plugins/__init__.py +0 -0
  257. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/runtime/__init__.py +0 -0
  258. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/shared/__init__.py +0 -0
  259. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/workflows/__init__.py +0 -0
  260. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/workflows/ndvi/__init__.py +0 -0
  261. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system/workflows/real_estate/__init__.py +0 -0
  262. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system.egg-info/SOURCES.txt +0 -0
  263. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system.egg-info/dependency_links.txt +0 -0
  264. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system.egg-info/entry_points.txt +0 -0
  265. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system.egg-info/requires.txt +0 -0
  266. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/smart_spatial_system.egg-info/top_level.txt +0 -0
  267. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/templates/__init__.py +0 -0
  268. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/templates/reports/__init__.py +0 -0
  269. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/templates/reports/real_estate_report.html +0 -0
  270. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_accessibility_query_spec.py +0 -0
  271. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_api_auth.py +0 -0
  272. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_api_contract_smoke.py +0 -0
  273. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_api_data_source_connectors_e2e.py +0 -0
  274. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_api_map_layers.py +0 -0
  275. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_api_mvp.py +0 -0
  276. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_api_outputs.py +0 -0
  277. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_api_projects.py +0 -0
  278. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_api_structured_error_normalization.py +0 -0
  279. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_api_upload_plugin_resolver.py +0 -0
  280. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_api_uploads.py +0 -0
  281. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_area_perimeter_calc.py +0 -0
  282. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_attribute_statistics.py +0 -0
  283. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_band_math.py +0 -0
  284. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_buffer_analysis.py +0 -0
  285. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_centroid_extractor.py +0 -0
  286. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_cli.py +0 -0
  287. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_crs_transformer.py +0 -0
  288. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_data_source_service.py +0 -0
  289. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_data_writer_exporter.py +0 -0
  290. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_deterministic_planner.py +0 -0
  291. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_dissolve_aggregator.py +0 -0
  292. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_distance_calculator.py +0 -0
  293. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_document_file_report_contract.py +0 -0
  294. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_end_to_end_natural_query_pipeline.py +0 -0
  295. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_error_contract.py +0 -0
  296. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_feature_enrichment.py +0 -0
  297. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_feature_scoring.py +0 -0
  298. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_frontend_api_surface_contract.py +0 -0
  299. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_geocoding_resolver.py +0 -0
  300. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_geocoding_resolver_error_redaction.py +0 -0
  301. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_geometry_validator.py +0 -0
  302. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_input_error_mapping.py +0 -0
  303. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_input_reference_resolver.py +0 -0
  304. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_input_reference_resolver_contract.py +0 -0
  305. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_kernel_artifacts.py +0 -0
  306. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_kernel_execution_bridge.py +0 -0
  307. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_kernel_plan_adapter.py +0 -0
  308. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_llm_intent_adapter.py +0 -0
  309. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_llm_raster_queryspec_normalization.py +0 -0
  310. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_llm_spec_generator_prenormalize.py +0 -0
  311. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_llm_spec_generator_semantic_context.py +0 -0
  312. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_llm_spec_generator_semantic_query_database_enrich.py +0 -0
  313. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_llm_spec_generator_semantic_queryspec_repair.py +0 -0
  314. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_loader_plugin_contract.py +0 -0
  315. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_local_path_validation.py +0 -0
  316. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_local_raster_loader.py +0 -0
  317. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_local_raster_loader_contract.py +0 -0
  318. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_local_vector_loader.py +0 -0
  319. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_local_vector_loader_contract.py +0 -0
  320. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_map_layer_contract.py +0 -0
  321. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_map_layer_service.py +0 -0
  322. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_ndvi_calculator.py +0 -0
  323. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_nearest_neighbor.py +0 -0
  324. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_numeric_validation.py +0 -0
  325. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_op_catalog_semantic_aliases.py +0 -0
  326. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_audit.py +0 -0
  327. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_audit_integration.py +0 -0
  328. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_data_source_service_integration.py +0 -0
  329. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_feedback.py +0 -0
  330. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_feedback_integration.py +0 -0
  331. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_keyword_scoring_router.py +0 -0
  332. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_learning_signals.py +0 -0
  333. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_learning_signals_integration.py +0 -0
  334. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_llm_gate.py +0 -0
  335. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_llm_gate_integration.py +0 -0
  336. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_map_layer_service_integration.py +0 -0
  337. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_natural_query_pipeline.py +0 -0
  338. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_output_service_integration.py +0 -0
  339. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_production_response.py +0 -0
  340. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_production_response_integration.py +0 -0
  341. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_project_service_integration.py +0 -0
  342. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_query_execution_service_integration.py +0 -0
  343. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_registry_router.py +0 -0
  344. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_router_decision.py +0 -0
  345. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_router_decision_integration.py +0 -0
  346. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_routing_aware_plan_builder.py +0 -0
  347. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_runtime_paths.py +0 -0
  348. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_service.py +0 -0
  349. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_service_domain_boundary_contract.py +0 -0
  350. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_service_integration.py +0 -0
  351. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_service_postgis_dedup_contract.py +0 -0
  352. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_statistics.py +0 -0
  353. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_statistics_integration.py +0 -0
  354. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_upload_service_integration.py +0 -0
  355. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_weight_proposals.py +0 -0
  356. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_weight_proposals_integration.py +0 -0
  357. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_weight_store_persistence.py +0 -0
  358. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_weight_store_persistence_integration.py +0 -0
  359. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_weighted_router.py +0 -0
  360. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_orchestrator_weighted_router_integration.py +0 -0
  361. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_output_service.py +0 -0
  362. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_output_storage.py +0 -0
  363. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_pdf_renderer.py +0 -0
  364. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_phase3_kernel_registry_coverage.py +0 -0
  365. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_phase3_output_parity.py +0 -0
  366. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_phase3_postgis_provider_kernel_execution.py +0 -0
  367. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_planning_dag_executor.py +0 -0
  368. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_planning_dag_executor_async_capability.py +0 -0
  369. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_planning_error_mapping.py +0 -0
  370. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_planning_execution_policy.py +0 -0
  371. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_planning_raster_op_catalog_mapping.py +0 -0
  372. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_planning_raster_queryspec_execution.py +0 -0
  373. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_planning_registry_backed_raster_execution.py +0 -0
  374. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_planning_registry_backed_real_estate_execution.py +0 -0
  375. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_planning_runner.py +0 -0
  376. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_plugin_boundary_contract.py +0 -0
  377. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_plugin_config.py +0 -0
  378. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_plugin_config_store.py +0 -0
  379. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_plugin_error_mapping.py +0 -0
  380. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_plugin_modules.py +0 -0
  381. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_postgis_connector.py +0 -0
  382. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_postgis_connector_percent_escape.py +0 -0
  383. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_postgis_semantic_resolver.py +0 -0
  384. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_project_service.py +0 -0
  385. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_project_store.py +0 -0
  386. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_provider_error_mapping.py +0 -0
  387. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_query_dispatch_domain_boundary_contract.py +0 -0
  388. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_query_execution_postgis_planning_context.py +0 -0
  389. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_query_execution_service.py +0 -0
  390. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_query_execution_service_domain_import_boundary_contract.py +0 -0
  391. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_query_response_shape_golden.py +0 -0
  392. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_query_spec_enrichment.py +0 -0
  393. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_raster_capability_registry_contract.py +0 -0
  394. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_raster_clip_mask.py +0 -0
  395. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_raster_reclassify.py +0 -0
  396. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_raster_statistics.py +0 -0
  397. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_raster_threshold.py +0 -0
  398. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_raster_to_vector.py +0 -0
  399. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_real_estate_ranking_bridge.py +0 -0
  400. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_real_estate_ranking_golden.py +0 -0
  401. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_real_estate_ranking_query_spec_planning.py +0 -0
  402. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_real_estate_scoring_plugin.py +0 -0
  403. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_real_estate_spatial_enrichment_plugin.py +0 -0
  404. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_real_estate_spatial_helpers.py +0 -0
  405. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_report_builder.py +0 -0
  406. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_report_spec.py +0 -0
  407. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_request_document_download_contract.py +0 -0
  408. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_response_assembler.py +0 -0
  409. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_response_output_contract.py +0 -0
  410. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_risk_enrichment.py +0 -0
  411. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_runtime_paths.py +0 -0
  412. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_semantic_planning_context.py +0 -0
  413. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_service_auto_postgis_semantic_context.py +0 -0
  414. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_service_planning_artifacts.py +0 -0
  415. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_service_postgis_runtime_connection_injection.py +0 -0
  416. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_service_semantic_planning_context.py +0 -0
  417. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_service_strict_loader_contract.py +0 -0
  418. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_service_structured_error_normalization.py +0 -0
  419. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_slope_aspect.py +0 -0
  420. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_spatial_intersection.py +0 -0
  421. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_spatial_join.py +0 -0
  422. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_spatial_query_filter.py +0 -0
  423. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_spectral_indices.py +0 -0
  424. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_system_status_query_handler.py +0 -0
  425. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_upload_service.py +0 -0
  426. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_upload_storage.py +0 -0
  427. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_vector_display_handler.py +0 -0
  428. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_vector_geojson_helpers.py +0 -0
  429. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_vector_query_classifier.py +0 -0
  430. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_wms_wfs_fetcher.py +0 -0
  431. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_wms_wfs_fetcher_error_redaction.py +0 -0
  432. {smart_spatial_system-0.2.1 → smart_spatial_system-0.2.2}/tests/test_zonal_statistics.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smart_spatial_system
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Plugin-based GeoAI backend: natural-language questions become QuerySpecs, DAG plans, and map/table/report outputs.
5
5
  Author: Araz Shah
6
6
  License-Expression: MIT
@@ -1052,6 +1052,45 @@ Important mappings:
1052
1052
  - "score/rank":
1053
1053
  use score_features then rank_features.
1054
1054
 
1055
+ - CRITICAL - scoring against MORE THAN ONE computed field (e.g. distance to
1056
+ several different amenities/references): each computation must be CHAINED
1057
+ onto the previous one's output, not all computed separately from the
1058
+ original base vector. score_features.inputs.vector must be the output of
1059
+ the LAST computation in the chain - the only ref that actually carries
1060
+ every field the scoring factors reference. A score_features op reading
1061
+ from the base vector, or from any computation earlier than the last one,
1062
+ is missing every field computed after that point, and every factor
1063
+ referencing a missing field silently scores 0 - this does not raise an
1064
+ error, so a degenerate all-zero/near-zero score on every feature is a
1065
+ sign this happened.
1066
+
1067
+ WRONG - three computations all read "sites", so only one field ever
1068
+ reaches score_features:
1069
+ spatial_nearest(source="sites", target="metro") -> "sites_with_metro"
1070
+ spatial_nearest(source="sites", target="schools") -> "sites_with_schools"
1071
+ spatial_nearest(source="sites", target="parks") -> "sites_with_parks"
1072
+ score_features(vector="sites") - WRONG: none of the three computed
1073
+ distance fields are on "sites" itself.
1074
+
1075
+ CORRECT - each step reads the PREVIOUS step's output, so fields
1076
+ accumulate onto one ref:
1077
+ spatial_nearest(source="sites", target="metro",
1078
+ params={{"distance_field": "distance_to_metro"}}) -> "sites_with_metro"
1079
+ spatial_nearest(source="sites_with_metro", target="schools",
1080
+ params={{"distance_field": "distance_to_schools"}}) -> "sites_with_schools"
1081
+ spatial_nearest(source="sites_with_schools", target="parks",
1082
+ params={{"distance_field": "distance_to_parks"}}) -> "sites_with_parks"
1083
+ score_features(vector="sites_with_parks") - CORRECT: this ref alone
1084
+ carries distance_to_metro, distance_to_schools AND distance_to_parks,
1085
+ because each step's "source" was the previous step's output, not
1086
+ "sites" again. Set params.distance_field on each spatial_nearest call
1087
+ so the fields get distinct names instead of overwriting each other.
1088
+
1089
+ If two computations genuinely cannot be chained (they operate on
1090
+ unrelated feature sets that must be merged by a shared key rather than
1091
+ by being the same features), use join_feature_properties to merge them
1092
+ before scoring instead of chaining.
1093
+
1055
1094
  - If user asks for PDF/report but report plugin is not executable yet:
1056
1095
  include outputs with kind="report", format="pdf".
1057
1096
  Do not invent unsupported operation nodes.
@@ -1625,6 +1664,162 @@ def _validate_operation_input_roles(spec: QuerySpec) -> None:
1625
1664
  )
1626
1665
 
1627
1666
 
1667
+ _NEAREST_OPS_WITH_DISTANCE_FIELD = {"spatial_nearest", "nearest_neighbor", "filter_by_distance"}
1668
+
1669
+
1670
+ def _extract_scoring_factor_fields(params: dict[str, Any]) -> list[str]:
1671
+ """
1672
+ Pull the "field" name out of every factor a score_features op's
1673
+ params declare, across the shapes _normalize_scoring_spec (in
1674
+ plugins/feature_scoring.py) accepts: top-level "factors", or
1675
+ "scoring_spec.factors", or the older nested "scoring_spec.scoring.factors".
1676
+ """
1677
+ factors = params.get("factors")
1678
+
1679
+ if not isinstance(factors, list):
1680
+ scoring_spec = params.get("scoring_spec")
1681
+ if isinstance(scoring_spec, dict):
1682
+ inner = scoring_spec.get("scoring")
1683
+ if isinstance(inner, dict) and isinstance(inner.get("factors"), list):
1684
+ factors = inner["factors"]
1685
+ elif isinstance(scoring_spec.get("factors"), list):
1686
+ factors = scoring_spec["factors"]
1687
+
1688
+ if not isinstance(factors, list):
1689
+ return []
1690
+
1691
+ return [
1692
+ str(factor["field"])
1693
+ for factor in factors
1694
+ if isinstance(factor, dict) and factor.get("field")
1695
+ ]
1696
+
1697
+
1698
+ def _op_declared_output_fields(op: OperationSpec) -> list[str]:
1699
+ """
1700
+ Field names an operation declares it writes, from the two mechanisms
1701
+ the system currently has for naming a computed field: an explicit
1702
+ "distance_field" param (spatial_nearest/nearest_neighbor/
1703
+ filter_by_distance), or enrich_feature_properties's rule targets.
1704
+
1705
+ Deliberately narrow: these are the only field-naming mechanisms an LLM
1706
+ plan can currently use, so this stays a precise signal rather than a
1707
+ guess. An op not covered here is simply not a candidate producer -
1708
+ see _validate_score_features_field_chaining's docstring for why that
1709
+ makes this check conservative rather than exhaustive.
1710
+ """
1711
+ if op.op in _NEAREST_OPS_WITH_DISTANCE_FIELD:
1712
+ field = op.params.get("distance_field")
1713
+ return [str(field)] if field else []
1714
+
1715
+ if op.op == "enrich_feature_properties":
1716
+ rules = op.params.get("rules")
1717
+ if isinstance(rules, list):
1718
+ return [
1719
+ str(rule["target"])
1720
+ for rule in rules
1721
+ if isinstance(rule, dict) and rule.get("target")
1722
+ ]
1723
+
1724
+ return []
1725
+
1726
+
1727
+ def _ancestor_refs(start_ref: str, ops_by_output: dict[str, OperationSpec]) -> set[str]:
1728
+ """
1729
+ Every ref start_ref transitively depends on, by walking operation
1730
+ inputs backward. Stops at any ref that isn't a known operation output
1731
+ (an entity or an initial input), rather than erroring - this function
1732
+ only needs to answer "was this ref produced upstream of start_ref?".
1733
+ """
1734
+ seen: set[str] = set()
1735
+ stack = [start_ref]
1736
+
1737
+ while stack:
1738
+ ref = stack.pop()
1739
+ if ref in seen:
1740
+ continue
1741
+ seen.add(ref)
1742
+
1743
+ op = ops_by_output.get(ref)
1744
+ if op is None:
1745
+ continue
1746
+
1747
+ for dependency_ref in op.inputs.values():
1748
+ if dependency_ref not in seen:
1749
+ stack.append(str(dependency_ref))
1750
+
1751
+ return seen
1752
+
1753
+
1754
+ def _validate_score_features_field_chaining(spec: QuerySpec) -> None:
1755
+ """
1756
+ Catch a score_features op reading from a ref that never accumulated a
1757
+ field its own scoring factors need.
1758
+
1759
+ This is the fan-out/chaining gap: an LLM asked to score against
1760
+ distance to several different amenities routinely computes each
1761
+ distance as its own operation off the SAME original vector (a fan-out)
1762
+ instead of chaining each computation onto the previous one's output
1763
+ (an accumulating chain - see the worked example in _domain_guidance).
1764
+ The result plans and executes without error - every required input
1765
+ role is present - but every factor referencing a field that landed on
1766
+ a sibling branch instead of the scored ref silently scores 0. A
1767
+ all-zero/degenerate score on every feature is exactly what that looks
1768
+ like from the outside, with no exception to point at the cause.
1769
+
1770
+ Deliberately conservative to avoid false positives: only fields this
1771
+ module can trace to a specific producing operation (see
1772
+ _op_declared_output_fields) are checked. A factor field that already
1773
+ exists on the raw input data, or that this function doesn't recognize
1774
+ as a producible field, is left unvalidated rather than guessed at -
1775
+ under-catching is the safe failure mode for a check like this, not
1776
+ over-catching.
1777
+ """
1778
+ ops_by_output: dict[str, OperationSpec] = {
1779
+ op.output: op for op in spec.operations if op.output
1780
+ }
1781
+
1782
+ field_producers: dict[str, list[OperationSpec]] = {}
1783
+ for op in spec.operations:
1784
+ for field in _op_declared_output_fields(op):
1785
+ field_producers.setdefault(field, []).append(op)
1786
+
1787
+ for op in spec.operations:
1788
+ if op.op != "score_features":
1789
+ continue
1790
+
1791
+ needed_fields = _extract_scoring_factor_fields(op.params)
1792
+ if not needed_fields:
1793
+ continue
1794
+
1795
+ scored_ref = op.inputs.get("vector")
1796
+ if not scored_ref:
1797
+ continue
1798
+
1799
+ ancestors = _ancestor_refs(str(scored_ref), ops_by_output)
1800
+
1801
+ for field in needed_fields:
1802
+ producers = field_producers.get(field)
1803
+ if not producers:
1804
+ # Not a field this module can trace to an operation -
1805
+ # could be a pre-existing attribute on the raw data.
1806
+ continue
1807
+
1808
+ if not any(producer.output in ancestors for producer in producers):
1809
+ producer_outputs = [p.output for p in producers]
1810
+ raise LLMSpecGenerationError(
1811
+ f"score_features (output={op.output!r}) scores on field "
1812
+ f"{field!r}, but that field is produced by "
1813
+ f"{producer_outputs!r}, none of which is chained into "
1814
+ f"its input {scored_ref!r} (or anything {scored_ref!r} "
1815
+ "depends on). Each computed field must be chained onto "
1816
+ "the previous operation's output before scoring - see "
1817
+ "the 'scoring against MORE THAN ONE computed field' "
1818
+ "guidance - otherwise this field is silently absent and "
1819
+ "its factor scores 0 for every feature."
1820
+ )
1821
+
1822
+
1628
1823
  class LLMQuerySpecGenerator:
1629
1824
  def __init__(
1630
1825
  self,
@@ -1673,6 +1868,7 @@ class LLMQuerySpecGenerator:
1673
1868
  spec = query_spec_from_dict(data, raw_query_fallback=raw_query)
1674
1869
  spec = normalize_llm_query_spec_for_planning(spec)
1675
1870
  _validate_operation_input_roles(spec)
1871
+ _validate_score_features_field_chaining(spec)
1676
1872
  return spec
1677
1873
 
1678
1874
 
@@ -12,7 +12,7 @@ build-backend = "setuptools.build_meta"
12
12
  # "Open design questions" for why a namespace migration was deliberately
13
13
  # not done here.
14
14
  name = "smart_spatial_system"
15
- version = "0.2.1"
15
+ version = "0.2.2"
16
16
  description = "Plugin-based GeoAI backend: natural-language questions become QuerySpecs, DAG plans, and map/table/report outputs."
17
17
  readme = "README.md"
18
18
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smart_spatial_system
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Plugin-based GeoAI backend: natural-language questions become QuerySpecs, DAG plans, and map/table/report outputs.
5
5
  Author: Araz Shah
6
6
  License-Expression: MIT
@@ -906,3 +906,220 @@ def test_domain_guidance_documents_every_operations_required_input_roles():
906
906
 
907
907
  assert "distance_to: inputs keys = {" in system_prompt
908
908
  assert "target" in system_prompt.split("distance_to: inputs keys = {", 1)[1].split("}", 1)[0]
909
+
910
+
911
+ # ------------------------------------------------------------------ #
912
+ # Bug 4: fan-out instead of chaining across multiple computed fields
913
+ # ------------------------------------------------------------------ #
914
+
915
+ def _fanout_scoring_operations(sites_ref_for_score: str) -> list[dict]:
916
+ """
917
+ Three distance computations, each reading the original "sites" vector
918
+ (a fan-out) rather than each other's output (a chain) - the exact
919
+ structural mistake reported from the Vienna accessibility case study:
920
+ every LLM-generated plan across two independent 20-run batches made
921
+ this same mistake, with score_features left pointed at a ref that
922
+ carries none of the three computed distance fields.
923
+ """
924
+ return [
925
+ {
926
+ "op": "spatial_nearest",
927
+ "inputs": {"source": "sites", "target": "metro"},
928
+ "params": {"k": 1, "distance_field": "distance_to_metro"},
929
+ "output": "sites_with_metro",
930
+ },
931
+ {
932
+ "op": "spatial_nearest",
933
+ "inputs": {"source": "sites", "target": "schools"},
934
+ "params": {"k": 1, "distance_field": "distance_to_schools"},
935
+ "output": "sites_with_schools",
936
+ },
937
+ {
938
+ "op": "spatial_nearest",
939
+ "inputs": {"source": "sites", "target": "parks"},
940
+ "params": {"k": 1, "distance_field": "distance_to_parks"},
941
+ "output": "sites_with_parks",
942
+ },
943
+ {
944
+ "op": "score_features",
945
+ "inputs": {"vector": sites_ref_for_score},
946
+ "params": {
947
+ "scoring_spec": {
948
+ "output_field": "accessibility_score",
949
+ "factors": [
950
+ {
951
+ "name": "metro",
952
+ "field": "distance_to_metro",
953
+ "type": "inverse_distance",
954
+ "max_distance": 800,
955
+ "weight": 1,
956
+ },
957
+ {
958
+ "name": "schools",
959
+ "field": "distance_to_schools",
960
+ "type": "inverse_distance",
961
+ "max_distance": 1200,
962
+ "weight": 1,
963
+ },
964
+ {
965
+ "name": "parks",
966
+ "field": "distance_to_parks",
967
+ "type": "inverse_distance",
968
+ "max_distance": 1000,
969
+ "weight": 1,
970
+ },
971
+ ],
972
+ }
973
+ },
974
+ "output": "scored",
975
+ },
976
+ {
977
+ "op": "rank_features",
978
+ "inputs": {"vector": "scored"},
979
+ "params": {},
980
+ "output": "ranked",
981
+ },
982
+ ]
983
+
984
+
985
+ def _fanout_spec_json(sites_ref_for_score: str) -> dict:
986
+ return {
987
+ "raw_query": "rank sites by accessibility to metro, schools and parks",
988
+ "goal": "score_accessibility",
989
+ "entities": [
990
+ {"ref": "sites", "kind": "vector"},
991
+ {"ref": "metro", "kind": "vector"},
992
+ {"ref": "schools", "kind": "vector"},
993
+ {"ref": "parks", "kind": "vector"},
994
+ ],
995
+ "operations": _fanout_scoring_operations(sites_ref_for_score),
996
+ "outputs": [{"kind": "vector", "source": "ranked"}],
997
+ }
998
+
999
+
1000
+ def test_generate_raises_when_score_features_is_not_fed_the_chained_output():
1001
+ """
1002
+ Regression test for the fan-out bug: score_features pointed at the
1003
+ original "sites" vector, while the three distance fields its factors
1004
+ reference were each computed onto a separate sibling branch
1005
+ ("sites_with_metro"/"_schools"/"_parks") instead of being chained onto
1006
+ one another. This must raise, naming a missing field, rather than
1007
+ silently plan and later execute to an all-zero score.
1008
+ """
1009
+ llm_json = _fanout_spec_json(sites_ref_for_score="sites")
1010
+
1011
+ client = StaticLLMClient(json.dumps(llm_json, ensure_ascii=False))
1012
+ generator = LLMQuerySpecGenerator(client)
1013
+
1014
+ with pytest.raises(LLMSpecGenerationError, match="distance_to_"):
1015
+ generator.generate("rank sites by accessibility to metro, schools and parks")
1016
+
1017
+
1018
+ def test_generate_raises_when_score_features_reads_only_one_of_three_branches():
1019
+ """
1020
+ Same fan-out shape, but score_features reads one of the three sibling
1021
+ branches (sites_with_metro) instead of the original vector - still
1022
+ missing the other two computed fields, so this must raise too, not
1023
+ just the "reads the original vector" case.
1024
+ """
1025
+ llm_json = _fanout_spec_json(sites_ref_for_score="sites_with_metro")
1026
+
1027
+ client = StaticLLMClient(json.dumps(llm_json, ensure_ascii=False))
1028
+ generator = LLMQuerySpecGenerator(client)
1029
+
1030
+ with pytest.raises(LLMSpecGenerationError, match="distance_to_"):
1031
+ generator.generate("rank sites by accessibility to metro, schools and parks")
1032
+
1033
+
1034
+ def test_generate_accepts_the_correctly_chained_equivalent():
1035
+ """
1036
+ The correct fix for the fan-out case: each distance computation reads
1037
+ the previous one's output, so score_features's input ref alone carries
1038
+ all three fields. Must plan successfully with no repairs masking a
1039
+ real issue.
1040
+ """
1041
+ llm_json = _fanout_spec_json(sites_ref_for_score="sites_with_parks")
1042
+ llm_json["operations"][1]["inputs"]["source"] = "sites_with_metro"
1043
+ llm_json["operations"][2]["inputs"]["source"] = "sites_with_schools"
1044
+
1045
+ client = StaticLLMClient(json.dumps(llm_json, ensure_ascii=False))
1046
+ generator = LLMQuerySpecGenerator(client)
1047
+
1048
+ spec = generator.generate("rank sites by accessibility to metro, schools and parks")
1049
+
1050
+ assert [op.op for op in spec.operations] == [
1051
+ "spatial_nearest",
1052
+ "spatial_nearest",
1053
+ "spatial_nearest",
1054
+ "score_features",
1055
+ "rank_features",
1056
+ ]
1057
+
1058
+ plan = DeterministicPlanner().build(spec)
1059
+ assert [node.capability_name for node in plan.nodes] == [
1060
+ "find_nearest_neighbors",
1061
+ "find_nearest_neighbors",
1062
+ "find_nearest_neighbors",
1063
+ "score_features",
1064
+ "rank_features",
1065
+ ]
1066
+
1067
+
1068
+ def test_field_chaining_check_does_not_flag_fields_it_cannot_trace():
1069
+ """
1070
+ A factor referencing a field with no known producer (e.g. an
1071
+ attribute already present on the raw uploaded data) must not be
1072
+ flagged - under-catching is the deliberately safe failure mode here,
1073
+ since this module has no way to know the raw data's own schema.
1074
+ """
1075
+ llm_json = {
1076
+ "raw_query": "score sites by an existing attribute",
1077
+ "goal": "score_sites",
1078
+ "entities": [{"ref": "sites", "kind": "vector"}],
1079
+ "operations": [
1080
+ {
1081
+ "op": "score_features",
1082
+ "inputs": {"vector": "sites"},
1083
+ "params": {
1084
+ "scoring_spec": {
1085
+ "output_field": "score",
1086
+ "factors": [
1087
+ {
1088
+ "name": "existing",
1089
+ "field": "pre_existing_attribute",
1090
+ "type": "inverse_distance",
1091
+ "max_distance": 500,
1092
+ "weight": 1,
1093
+ }
1094
+ ],
1095
+ }
1096
+ },
1097
+ "output": "scored",
1098
+ },
1099
+ {
1100
+ "op": "rank_features",
1101
+ "inputs": {"vector": "scored"},
1102
+ "params": {},
1103
+ "output": "ranked",
1104
+ },
1105
+ ],
1106
+ "outputs": [{"kind": "vector", "source": "ranked"}],
1107
+ }
1108
+
1109
+ client = StaticLLMClient(json.dumps(llm_json, ensure_ascii=False))
1110
+ spec = LLMQuerySpecGenerator(client).generate("score sites by an existing attribute")
1111
+
1112
+ assert [op.op for op in spec.operations] == ["score_features", "rank_features"]
1113
+
1114
+
1115
+ def test_domain_guidance_documents_multi_factor_chaining_and_join_alternative():
1116
+ """
1117
+ The chaining-vs-fan-out guidance and the join_feature_properties
1118
+ escape hatch for genuinely unchainable branches must both be present
1119
+ in the LLM-facing prompt - neither existed before this fix, which is
1120
+ exactly why the model had no way to get this right.
1121
+ """
1122
+ system_prompt = build_llm_messages("q")[0]["content"]
1123
+
1124
+ assert "MORE THAN ONE computed field" in system_prompt
1125
+ assert "join_feature_properties" in system_prompt