smart-spatial-system 0.2.7__tar.gz → 0.2.9__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 (438) hide show
  1. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/PKG-INFO +1 -1
  2. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/llm_spec_generator.py +59 -0
  3. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/spatial_join.py +114 -1
  4. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/pyproject.toml +1 -1
  5. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system.egg-info/PKG-INFO +1 -1
  6. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system.egg-info/SOURCES.txt +2 -0
  7. smart_spatial_system-0.2.9/tests/test_spatial_join_ring_buffer_cardinality.py +215 -0
  8. smart_spatial_system-0.2.9/tests/test_spatial_join_strtree_performance.py +202 -0
  9. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/LICENSE +0 -0
  10. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/README.md +0 -0
  11. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/api/__init__.py +0 -0
  12. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/api/auth.py +0 -0
  13. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/api/main.py +0 -0
  14. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/api/routers/__init__.py +0 -0
  15. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/api/routers/data_source_connectors.py +0 -0
  16. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/api/routers/data_sources.py +0 -0
  17. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/api/routers/plugins_settings.py +0 -0
  18. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/api/routers/projects.py +0 -0
  19. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/api/routers/query_planner.py +0 -0
  20. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/api/routers/requests_outputs.py +0 -0
  21. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/api/routers/system.py +0 -0
  22. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/api/routers/uploads.py +0 -0
  23. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/api/routers/weights.py +0 -0
  24. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/api/support.py +0 -0
  25. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/__init__.py +0 -0
  26. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/__init__.py +0 -0
  27. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/area_perimeter_calc.example.yaml +0 -0
  28. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/area_perimeter_calc.yaml +0 -0
  29. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/attribute_statistics.example.yaml +0 -0
  30. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/attribute_statistics.yaml +0 -0
  31. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/band_math.example.yaml +0 -0
  32. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/band_math.yaml +0 -0
  33. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/buffer_analysis.example.yaml +0 -0
  34. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/buffer_analysis.yaml +0 -0
  35. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/centroid_extractor.example.yaml +0 -0
  36. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/centroid_extractor.yaml +0 -0
  37. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/core_vector.example.yaml +0 -0
  38. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/core_vector.yaml +0 -0
  39. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/crs_transformer.example.yaml +0 -0
  40. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/crs_transformer.yaml +0 -0
  41. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/data_writer_exporter.example.yaml +0 -0
  42. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/data_writer_exporter.yaml +0 -0
  43. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/dissolve_aggregator.example.yaml +0 -0
  44. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/dissolve_aggregator.yaml +0 -0
  45. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/distance_calculator.example.yaml +0 -0
  46. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/distance_calculator.yaml +0 -0
  47. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/feature_enrichment.example.yaml +0 -0
  48. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/feature_enrichment.yaml +0 -0
  49. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/feature_scoring.example.yaml +0 -0
  50. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/feature_scoring.yaml +0 -0
  51. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/geocoding_resolver.example.yaml +0 -0
  52. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/geocoding_resolver.yaml +0 -0
  53. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/geometry_validator.example.yaml +0 -0
  54. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/geometry_validator.yaml +0 -0
  55. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/local_raster_loader.example.yaml +0 -0
  56. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/local_raster_loader.yaml +0 -0
  57. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/local_vector_loader.example.yaml +0 -0
  58. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/local_vector_loader.yaml +0 -0
  59. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/ndvi_calculator.example.yaml +0 -0
  60. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/ndvi_calculator.yaml +0 -0
  61. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/nearest_neighbor.example.yaml +0 -0
  62. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/nearest_neighbor.yaml +0 -0
  63. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/postgis_connector.example.yaml +0 -0
  64. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/postgis_connector.yaml +0 -0
  65. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/raster_clip_mask.example.yaml +0 -0
  66. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/raster_clip_mask.yaml +0 -0
  67. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/raster_reclassify.example.yaml +0 -0
  68. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/raster_reclassify.yaml +0 -0
  69. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/raster_statistics.example.yaml +0 -0
  70. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/raster_statistics.yaml +0 -0
  71. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/raster_threshold.example.yaml +0 -0
  72. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/raster_threshold.yaml +0 -0
  73. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/raster_to_vector.example.yaml +0 -0
  74. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/raster_to_vector.yaml +0 -0
  75. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/ring_buffer_analysis.example.yaml +0 -0
  76. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/ring_buffer_analysis.yaml +0 -0
  77. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/risk_enrichment.example.yaml +0 -0
  78. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/risk_enrichment.yaml +0 -0
  79. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/slope_aspect.yaml +0 -0
  80. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/spatial_intersection.example.yaml +0 -0
  81. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/spatial_intersection.yaml +0 -0
  82. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/spatial_join.example.yaml +0 -0
  83. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/spatial_join.yaml +0 -0
  84. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/spatial_predicate.example.yaml +0 -0
  85. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/spatial_predicate.yaml +0 -0
  86. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/spatial_query_filter.example.yaml +0 -0
  87. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/spatial_query_filter.yaml +0 -0
  88. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/spectral_indices.example.yaml +0 -0
  89. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/spectral_indices.yaml +0 -0
  90. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/wms_wfs_fetcher.example.yaml +0 -0
  91. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/wms_wfs_fetcher.yaml +0 -0
  92. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/zonal_statistics.example.yaml +0 -0
  93. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/config/plugins/zonal_statistics.yaml +0 -0
  94. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/__init__.py +0 -0
  95. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/audit.py +0 -0
  96. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/capability_registry.py +0 -0
  97. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/capability_router.py +0 -0
  98. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/capability_scoring.py +0 -0
  99. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/data_source_service.py +0 -0
  100. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/error_contract.py +0 -0
  101. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/feedback.py +0 -0
  102. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/feedback_proposal_service.py +0 -0
  103. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/input_error_mapping.py +0 -0
  104. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/input_reference_resolver.py +0 -0
  105. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/kernel_artifacts.py +0 -0
  106. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/learning_signals.py +0 -0
  107. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/llm_client.py +0 -0
  108. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/llm_gate.py +0 -0
  109. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/llm_intent_planner.py +0 -0
  110. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/loader_plugin_contract.py +0 -0
  111. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/map_layer_service.py +0 -0
  112. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/map_layers.py +0 -0
  113. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/models.py +0 -0
  114. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/natural_query_runner.py +0 -0
  115. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/output_service.py +0 -0
  116. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/output_storage.py +0 -0
  117. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/pipeline_executor.py +0 -0
  118. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/plan_builder.py +0 -0
  119. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/__init__.py +0 -0
  120. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/capability_resolver.py +0 -0
  121. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/dag.py +0 -0
  122. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/dag_executor.py +0 -0
  123. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/error_mapping.py +0 -0
  124. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/kernel_execution_bridge.py +0 -0
  125. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/kernel_plan_adapter.py +0 -0
  126. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/llm_query_spec.py +0 -0
  127. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/op_catalog.py +0 -0
  128. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/output_parity.py +0 -0
  129. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/planner.py +0 -0
  130. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/postgis_semantic_resolver.py +0 -0
  131. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/query_spec_contract.py +0 -0
  132. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/report_spec.py +0 -0
  133. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/runner.py +0 -0
  134. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/semantic_planning_context.py +0 -0
  135. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/planning/spec.py +0 -0
  136. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/plugin_config_store.py +0 -0
  137. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/plugin_error_mapping.py +0 -0
  138. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/plugin_modules.py +0 -0
  139. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/plugin_runtime_service.py +0 -0
  140. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/plugin_state.py +0 -0
  141. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/production_response.py +0 -0
  142. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/project_service.py +0 -0
  143. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/project_store.py +0 -0
  144. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/provider_error_mapping.py +0 -0
  145. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/query_execution_service.py +0 -0
  146. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/query_parser.py +0 -0
  147. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/request_history_service.py +0 -0
  148. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/response_assembler.py +0 -0
  149. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/response_builder.py +0 -0
  150. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/router_decision.py +0 -0
  151. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/routing_aware_natural_query_runner.py +0 -0
  152. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/routing_aware_plan_builder.py +0 -0
  153. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/runtime_paths.py +0 -0
  154. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/service.py +0 -0
  155. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/statistics.py +0 -0
  156. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/upload_service.py +0 -0
  157. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/upload_storage.py +0 -0
  158. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/weight_proposals.py +0 -0
  159. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/weight_store_persistence.py +0 -0
  160. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/orchestrator/weighted_router.py +0 -0
  161. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/__init__.py +0 -0
  162. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/_shared/__init__.py +0 -0
  163. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/_shared/local_path_validation.py +0 -0
  164. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/_shared/numeric_validation.py +0 -0
  165. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/_shared/plugin_config.py +0 -0
  166. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/area_perimeter_calc.py +0 -0
  167. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/attribute_statistics.py +0 -0
  168. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/band_math.py +0 -0
  169. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/buffer_analysis.py +0 -0
  170. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/centroid_extractor.py +0 -0
  171. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/core_vector.py +0 -0
  172. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/crs_transformer.py +0 -0
  173. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/data_writer_exporter.py +0 -0
  174. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/dissolve_aggregator.py +0 -0
  175. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/distance_calculator.py +0 -0
  176. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/feature_enrichment.py +0 -0
  177. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/feature_scoring.py +0 -0
  178. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/geocoding_resolver.py +0 -0
  179. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/geometry_validator.py +0 -0
  180. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/local_raster_loader.py +0 -0
  181. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/local_vector_loader.py +0 -0
  182. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/ndvi_analysis.py +0 -0
  183. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/ndvi_calculator.py +0 -0
  184. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/nearest_neighbor.py +0 -0
  185. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/pdf_renderer.py +0 -0
  186. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/postgis_connector.py +0 -0
  187. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/raster_clip_mask.py +0 -0
  188. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/raster_reclassify.py +0 -0
  189. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/raster_statistics.py +0 -0
  190. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/raster_threshold.py +0 -0
  191. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/raster_to_vector.py +0 -0
  192. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/real_estate_scoring.py +0 -0
  193. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/real_estate_spatial_enrichment.py +0 -0
  194. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/report_builder.py +0 -0
  195. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/ring_buffer_analysis.py +0 -0
  196. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/risk_enrichment.py +0 -0
  197. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/slope_aspect.py +0 -0
  198. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/spatial_intersection.py +0 -0
  199. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/spatial_predicate.py +0 -0
  200. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/spatial_query_filter.py +0 -0
  201. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/spectral_indices.py +0 -0
  202. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/wms_wfs_fetcher.py +0 -0
  203. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/plugins/zonal_statistics.py +0 -0
  204. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/setup.cfg +0 -0
  205. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/__init__.py +0 -0
  206. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/__main__.py +0 -0
  207. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/__init__.py +0 -0
  208. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/__init__.py +0 -0
  209. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/data_source_service.py +0 -0
  210. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/feedback_proposal_service.py +0 -0
  211. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/llm_intent_adapter.py +0 -0
  212. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/map_layer_service.py +0 -0
  213. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/output_service.py +0 -0
  214. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/planning_execution_policy.py +0 -0
  215. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/planning_response_adapter.py +0 -0
  216. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/plugin_runtime_service.py +0 -0
  217. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/project_service.py +0 -0
  218. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/__init__.py +0 -0
  219. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/accessibility_query_spec.py +0 -0
  220. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/direct_query_dispatch.py +0 -0
  221. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/natural_query_context.py +0 -0
  222. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/natural_query_dispatch.py +0 -0
  223. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/natural_query_execution.py +0 -0
  224. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/natural_query_failure.py +0 -0
  225. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/natural_query_persistence.py +0 -0
  226. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/planning_context.py +0 -0
  227. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/planning_execution.py +0 -0
  228. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/planning_persistence.py +0 -0
  229. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/planning_response.py +0 -0
  230. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/postgis_planning_context.py +0 -0
  231. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/real_estate_analysis_inspector.py +0 -0
  232. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/real_estate_classifier.py +0 -0
  233. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/real_estate_context.py +0 -0
  234. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/real_estate_document_renderer.py +0 -0
  235. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/real_estate_missing_inputs.py +0 -0
  236. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/real_estate_ranking_artifacts.py +0 -0
  237. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/real_estate_ranking_direct_handler.py +0 -0
  238. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/real_estate_ranking_execution.py +0 -0
  239. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/real_estate_ranking_query_spec.py +0 -0
  240. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/real_estate_ranking_response.py +0 -0
  241. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/real_estate_report_payload.py +0 -0
  242. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution/real_estate_scoring.py +0 -0
  243. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_execution_service.py +0 -0
  244. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/query_spec_enrichment.py +0 -0
  245. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/real_estate_spatial_helpers.py +0 -0
  246. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/request_history_service.py +0 -0
  247. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/system_status_query_handler.py +0 -0
  248. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/upload_service.py +0 -0
  249. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/vector_display_handler.py +0 -0
  250. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/vector_geojson_helpers.py +0 -0
  251. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/application/services/vector_query_classifier.py +0 -0
  252. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/cli.py +0 -0
  253. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/domain/__init__.py +0 -0
  254. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/domain/contracts/__init__.py +0 -0
  255. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/domain/models/__init__.py +0 -0
  256. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/infrastructure/__init__.py +0 -0
  257. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/infrastructure/stores/__init__.py +0 -0
  258. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/interfaces/__init__.py +0 -0
  259. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/interfaces/api/__init__.py +0 -0
  260. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/interfaces/api/routers/__init__.py +0 -0
  261. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/plugins/__init__.py +0 -0
  262. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/runtime/__init__.py +0 -0
  263. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/shared/__init__.py +0 -0
  264. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/workflows/__init__.py +0 -0
  265. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/workflows/ndvi/__init__.py +0 -0
  266. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system/workflows/real_estate/__init__.py +0 -0
  267. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system.egg-info/dependency_links.txt +0 -0
  268. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system.egg-info/entry_points.txt +0 -0
  269. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system.egg-info/requires.txt +0 -0
  270. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/smart_spatial_system.egg-info/top_level.txt +0 -0
  271. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/templates/__init__.py +0 -0
  272. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/templates/reports/__init__.py +0 -0
  273. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/templates/reports/real_estate_report.html +0 -0
  274. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_accessibility_query_spec.py +0 -0
  275. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_api_auth.py +0 -0
  276. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_api_contract_smoke.py +0 -0
  277. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_api_data_source_connectors_e2e.py +0 -0
  278. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_api_map_layers.py +0 -0
  279. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_api_mvp.py +0 -0
  280. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_api_outputs.py +0 -0
  281. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_api_projects.py +0 -0
  282. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_api_structured_error_normalization.py +0 -0
  283. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_api_upload_plugin_resolver.py +0 -0
  284. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_api_uploads.py +0 -0
  285. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_area_perimeter_calc.py +0 -0
  286. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_attribute_statistics.py +0 -0
  287. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_band_math.py +0 -0
  288. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_buffer_analysis.py +0 -0
  289. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_centroid_extractor.py +0 -0
  290. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_cli.py +0 -0
  291. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_crs_transformer.py +0 -0
  292. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_data_source_service.py +0 -0
  293. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_data_writer_exporter.py +0 -0
  294. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_deterministic_planner.py +0 -0
  295. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_dissolve_aggregator.py +0 -0
  296. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_distance_calculator.py +0 -0
  297. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_document_file_report_contract.py +0 -0
  298. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_end_to_end_natural_query_pipeline.py +0 -0
  299. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_error_contract.py +0 -0
  300. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_feature_enrichment.py +0 -0
  301. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_feature_scoring.py +0 -0
  302. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_frontend_api_surface_contract.py +0 -0
  303. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_geocoding_resolver.py +0 -0
  304. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_geocoding_resolver_error_redaction.py +0 -0
  305. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_geometry_validator.py +0 -0
  306. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_input_error_mapping.py +0 -0
  307. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_input_reference_resolver.py +0 -0
  308. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_input_reference_resolver_contract.py +0 -0
  309. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_kernel_artifacts.py +0 -0
  310. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_kernel_execution_bridge.py +0 -0
  311. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_kernel_plan_adapter.py +0 -0
  312. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_llm_intent_adapter.py +0 -0
  313. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_llm_raster_queryspec_normalization.py +0 -0
  314. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_llm_spec_generator.py +0 -0
  315. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_llm_spec_generator_prenormalize.py +0 -0
  316. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_llm_spec_generator_semantic_context.py +0 -0
  317. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_llm_spec_generator_semantic_query_database_enrich.py +0 -0
  318. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_llm_spec_generator_semantic_queryspec_repair.py +0 -0
  319. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_loader_plugin_contract.py +0 -0
  320. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_local_path_validation.py +0 -0
  321. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_local_raster_loader.py +0 -0
  322. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_local_raster_loader_contract.py +0 -0
  323. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_local_vector_loader.py +0 -0
  324. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_local_vector_loader_contract.py +0 -0
  325. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_map_layer_contract.py +0 -0
  326. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_map_layer_service.py +0 -0
  327. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_ndvi_calculator.py +0 -0
  328. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_nearest_neighbor.py +0 -0
  329. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_numeric_validation.py +0 -0
  330. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_op_catalog_semantic_aliases.py +0 -0
  331. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_audit.py +0 -0
  332. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_audit_integration.py +0 -0
  333. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_data_source_service_integration.py +0 -0
  334. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_feedback.py +0 -0
  335. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_feedback_integration.py +0 -0
  336. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_keyword_scoring_router.py +0 -0
  337. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_learning_signals.py +0 -0
  338. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_learning_signals_integration.py +0 -0
  339. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_llm_gate.py +0 -0
  340. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_llm_gate_integration.py +0 -0
  341. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_map_layer_service_integration.py +0 -0
  342. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_natural_query_pipeline.py +0 -0
  343. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_output_service_integration.py +0 -0
  344. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_production_response.py +0 -0
  345. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_production_response_integration.py +0 -0
  346. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_project_service_integration.py +0 -0
  347. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_query_execution_service_integration.py +0 -0
  348. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_registry_router.py +0 -0
  349. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_router_decision.py +0 -0
  350. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_router_decision_integration.py +0 -0
  351. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_routing_aware_plan_builder.py +0 -0
  352. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_runtime_paths.py +0 -0
  353. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_service.py +0 -0
  354. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_service_domain_boundary_contract.py +0 -0
  355. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_service_integration.py +0 -0
  356. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_service_postgis_dedup_contract.py +0 -0
  357. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_statistics.py +0 -0
  358. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_statistics_integration.py +0 -0
  359. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_upload_service_integration.py +0 -0
  360. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_weight_proposals.py +0 -0
  361. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_weight_proposals_integration.py +0 -0
  362. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_weight_store_persistence.py +0 -0
  363. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_weight_store_persistence_integration.py +0 -0
  364. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_weighted_router.py +0 -0
  365. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_orchestrator_weighted_router_integration.py +0 -0
  366. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_output_service.py +0 -0
  367. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_output_storage.py +0 -0
  368. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_pdf_renderer.py +0 -0
  369. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_phase3_kernel_registry_coverage.py +0 -0
  370. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_phase3_output_parity.py +0 -0
  371. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_phase3_postgis_provider_kernel_execution.py +0 -0
  372. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_planning_dag_executor.py +0 -0
  373. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_planning_dag_executor_async_capability.py +0 -0
  374. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_planning_error_mapping.py +0 -0
  375. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_planning_execution_policy.py +0 -0
  376. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_planning_raster_op_catalog_mapping.py +0 -0
  377. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_planning_raster_queryspec_execution.py +0 -0
  378. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_planning_registry_backed_raster_execution.py +0 -0
  379. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_planning_registry_backed_real_estate_execution.py +0 -0
  380. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_planning_runner.py +0 -0
  381. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_plugin_boundary_contract.py +0 -0
  382. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_plugin_config.py +0 -0
  383. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_plugin_config_store.py +0 -0
  384. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_plugin_error_mapping.py +0 -0
  385. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_plugin_modules.py +0 -0
  386. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_postgis_connector.py +0 -0
  387. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_postgis_connector_percent_escape.py +0 -0
  388. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_postgis_semantic_resolver.py +0 -0
  389. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_project_service.py +0 -0
  390. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_project_store.py +0 -0
  391. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_provider_error_mapping.py +0 -0
  392. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_query_dispatch_domain_boundary_contract.py +0 -0
  393. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_query_execution_postgis_planning_context.py +0 -0
  394. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_query_execution_service.py +0 -0
  395. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_query_execution_service_domain_import_boundary_contract.py +0 -0
  396. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_query_response_shape_golden.py +0 -0
  397. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_query_spec_enrichment.py +0 -0
  398. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_raster_capability_registry_contract.py +0 -0
  399. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_raster_clip_mask.py +0 -0
  400. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_raster_reclassify.py +0 -0
  401. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_raster_statistics.py +0 -0
  402. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_raster_threshold.py +0 -0
  403. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_raster_to_vector.py +0 -0
  404. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_real_estate_ranking_bridge.py +0 -0
  405. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_real_estate_ranking_golden.py +0 -0
  406. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_real_estate_ranking_query_spec_planning.py +0 -0
  407. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_real_estate_scoring_plugin.py +0 -0
  408. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_real_estate_spatial_enrichment_plugin.py +0 -0
  409. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_real_estate_spatial_helpers.py +0 -0
  410. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_report_builder.py +0 -0
  411. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_report_spec.py +0 -0
  412. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_request_document_download_contract.py +0 -0
  413. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_response_assembler.py +0 -0
  414. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_response_output_contract.py +0 -0
  415. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_ring_buffer_analysis.py +0 -0
  416. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_risk_enrichment.py +0 -0
  417. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_runtime_paths.py +0 -0
  418. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_semantic_planning_context.py +0 -0
  419. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_service_auto_postgis_semantic_context.py +0 -0
  420. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_service_planning_artifacts.py +0 -0
  421. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_service_postgis_runtime_connection_injection.py +0 -0
  422. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_service_semantic_planning_context.py +0 -0
  423. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_service_strict_loader_contract.py +0 -0
  424. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_service_structured_error_normalization.py +0 -0
  425. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_slope_aspect.py +0 -0
  426. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_spatial_intersection.py +0 -0
  427. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_spatial_join.py +0 -0
  428. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_spatial_query_filter.py +0 -0
  429. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_spectral_indices.py +0 -0
  430. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_system_status_query_handler.py +0 -0
  431. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_upload_service.py +0 -0
  432. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_upload_storage.py +0 -0
  433. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_vector_display_handler.py +0 -0
  434. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_vector_geojson_helpers.py +0 -0
  435. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_vector_query_classifier.py +0 -0
  436. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_wms_wfs_fetcher.py +0 -0
  437. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/tests/test_wms_wfs_fetcher_error_redaction.py +0 -0
  438. {smart_spatial_system-0.2.7 → smart_spatial_system-0.2.9}/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.7
3
+ Version: 0.2.9
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
@@ -1056,6 +1056,22 @@ Important mappings:
1056
1056
  ones), never the annulus/gap BETWEEN two radii, which is what "ring" or
1057
1057
  "band" means here.
1058
1058
 
1059
+ - CRITICAL - spatial_join's params.cardinality defaults to "first": each
1060
+ source feature is joined to only ONE matching target feature (the first
1061
+ one found), even if it actually matches several. This silently
1062
+ undercounts whenever the target layer's zones can overlap - most
1063
+ commonly a spatial_join whose target is a ring_buffer output (or any
1064
+ other layer with multiple zones generated from separate input
1065
+ features, e.g. several stations' service areas). A point inside two
1066
+ overlapping rings/zones would only be counted for one of them with the
1067
+ default. Whenever the query means for a source feature matching several
1068
+ zones to be counted under EACH of them (e.g. "for every station, which
1069
+ points are within its rings", "for each amenity, list every zone it
1070
+ falls into" - i.e. a point can legitimately belong to more than one
1071
+ zone), set params={{"cardinality": "one_to_many", "include_target_properties": true}}
1072
+ explicitly on that spatial_join. Do not leave cardinality unset and
1073
+ rely on the default when the target can have overlapping zones.
1074
+
1059
1075
  - "inside permitted/buildable polygon":
1060
1076
  op="filter_points_in_polygon"
1061
1077
  inputs={{"vector": "<points>", "polygon": "<polygon_layer>"}}
@@ -1268,6 +1284,18 @@ def _unique_ref(base: str, used: set[str]) -> str:
1268
1284
  return candidate
1269
1285
 
1270
1286
 
1287
+ # Operations known to be able to produce several overlapping output zones
1288
+ # from separate input features - e.g. ring_buffer builds one ring set per
1289
+ # input feature, and two features' rings routinely overlap (two metro
1290
+ # stations 1500m apart both have a 1200m ring covering the space between
1291
+ # them). A spatial_join whose target traces back to one of these needs
1292
+ # cardinality="one_to_many" or it silently drops every match after the
1293
+ # first for any source feature that falls inside more than one zone - see
1294
+ # _default_spatial_join_cardinality_for_overlapping_zones below. Currently
1295
+ # just ring_buffer; add here if a future op gains the same shape.
1296
+ _OVERLAP_PRONE_ZONE_OPS = frozenset({"ring_buffer"})
1297
+
1298
+
1271
1299
  def normalize_llm_query_spec_for_planning(spec: QuerySpec) -> QuerySpec:
1272
1300
  """
1273
1301
  Harden and improve LLM-produced QuerySpec before deterministic planning.
@@ -1276,6 +1304,11 @@ def normalize_llm_query_spec_for_planning(spec: QuerySpec) -> QuerySpec:
1276
1304
  - Remove unsupported input roles.
1277
1305
  - Add default scoring_spec when score_features misses it.
1278
1306
  - Add score_field/rank_field to rank_features when missing.
1307
+ - Default spatial_join's cardinality to "one_to_many" when its
1308
+ target traces back to an op that can produce overlapping zones
1309
+ (see _OVERLAP_PRONE_ZONE_OPS) and the caller left cardinality
1310
+ unset - the plugin's own default ("first") silently keeps only
1311
+ one match per source feature otherwise.
1279
1312
  - If default scoring is used, inject enrichment nodes after spatial
1280
1313
  operations to create stable semantic scoring fields:
1281
1314
  distance_to_poi
@@ -1285,6 +1318,10 @@ def normalize_llm_query_spec_for_planning(spec: QuerySpec) -> QuerySpec:
1285
1318
  repairs: list[str] = []
1286
1319
  normalized_ops: list[OperationSpec] = []
1287
1320
 
1321
+ ops_by_output: dict[str, OperationSpec] = {
1322
+ op.output: op for op in spec.operations if op.output
1323
+ }
1324
+
1288
1325
  used_refs: set[str] = set()
1289
1326
  for op in spec.operations:
1290
1327
  if op.output:
@@ -1374,6 +1411,28 @@ def normalize_llm_query_spec_for_planning(spec: QuerySpec) -> QuerySpec:
1374
1411
  clean_params["rank_field"] = "rank"
1375
1412
  repairs.append("added rank_field='rank' to rank_features")
1376
1413
 
1414
+ if op.op == "spatial_join" and "cardinality" not in clean_params:
1415
+ target_ref = clean_inputs.get("target")
1416
+ if target_ref is not None:
1417
+ ancestors = _ancestor_refs(str(target_ref), ops_by_output)
1418
+ traces_to_overlap_prone_op = any(
1419
+ ops_by_output.get(ref) is not None
1420
+ and ops_by_output[ref].op in _OVERLAP_PRONE_ZONE_OPS
1421
+ for ref in ancestors
1422
+ )
1423
+
1424
+ if traces_to_overlap_prone_op:
1425
+ clean_params["cardinality"] = "one_to_many"
1426
+ repairs.append(
1427
+ f"set cardinality='one_to_many' on spatial_join "
1428
+ f"(output={op.output!r}) because its target "
1429
+ f"{target_ref!r} traces back to an operation that "
1430
+ "can produce overlapping zones - the plugin's own "
1431
+ "default cardinality='first' would silently keep "
1432
+ "only one match for any source feature that falls "
1433
+ "in more than one zone"
1434
+ )
1435
+
1377
1436
  normalized_op = OperationSpec(
1378
1437
  op=op.op,
1379
1438
  inputs=clean_inputs,
@@ -35,6 +35,20 @@ Engines:
35
35
  - python:
36
36
  Bbox-based fallback.
37
37
 
38
+ Performance:
39
+ The shapely engine indexes target geometries in an STRtree (shapely's
40
+ own R-tree, no extra dependency) and narrows each source feature's
41
+ candidate targets by bounding-box overlap before evaluating the exact
42
+ predicate, instead of checking every source against every target.
43
+ This turns the join from O(n*m) into roughly O((n+m) * log(m)) for
44
+ the common case where every target geometry is valid - a large
45
+ difference at real-world scale (tens of thousands of source features
46
+ against hundreds of target zones). Falls back to the full O(n*m)
47
+ double loop automatically if shapely is unavailable, if engine is
48
+ forced to "python", or if any target geometry cannot be parsed by
49
+ shapely (that specific edge case keeps the previous per-pair error
50
+ handling instead of being silently skipped by the index).
51
+
38
52
  Important:
39
53
  The python engine is bbox-based and approximate. For production-grade
40
54
  spatial join, install shapely:
@@ -331,6 +345,44 @@ def _get_shapely_tools():
331
345
  return shape
332
346
 
333
347
 
348
+ def _get_strtree_tools():
349
+ try:
350
+ from shapely.geometry import shape
351
+ from shapely.strtree import STRtree
352
+ except ImportError as exc:
353
+ raise SDKDependencyError(
354
+ "spatial_join requires 'shapely' for this engine. "
355
+ "Install it with: pip install shapely"
356
+ ) from exc
357
+
358
+ return shape, STRtree
359
+
360
+
361
+ def _strtree_query_indices(tree: Any, geometry: Any, geometries: list[Any]) -> list[int]:
362
+ """
363
+ Query an STRtree and return integer indices into `geometries`.
364
+
365
+ Handles both STRtree.query() return shapes across shapely versions:
366
+ - shapely>=2.0: an array-like of integer positions into the list
367
+ the tree was built from.
368
+ - shapely<2.0: a list of the matched geometry objects themselves,
369
+ not indices - resolved back to positions by identity, since the
370
+ tree stores references to the exact objects it was built from.
371
+ """
372
+ result = tree.query(geometry)
373
+
374
+ if len(result) == 0:
375
+ return []
376
+
377
+ first = result[0]
378
+
379
+ if hasattr(first, "geom_type"):
380
+ id_to_index = {id(g): i for i, g in enumerate(geometries)}
381
+ return [id_to_index[id(g)] for g in result if id(g) in id_to_index]
382
+
383
+ return [int(i) for i in result]
384
+
385
+
334
386
  def _shapely_predicate(
335
387
  source_geometry: dict[str, Any] | None,
336
388
  target_geometry: dict[str, Any] | None,
@@ -656,12 +708,72 @@ def spatial_join_features(
656
708
  failed_pair_count = 0
657
709
  dropped_failed_count = 0
658
710
 
711
+ # Spatial-index fast path: an STRtree of target geometries narrows the
712
+ # O(n*m) naive double loop down to O(n*log(m) + m*log(m)) by ruling out
713
+ # target features whose bbox cannot possibly satisfy any predicate
714
+ # against a given source feature's bbox (a necessary condition for
715
+ # intersects/within/contains alike), before the exact predicate is
716
+ # evaluated on the surviving candidates only. Only attempted when the
717
+ # engine can use shapely at all, and only used when every target
718
+ # geometry is a valid, parseable dict - any invalid target bails the
719
+ # whole call back to the naive loop below, which already handles a
720
+ # malformed geometry per-pair via _evaluate_predicate's own try/except
721
+ # (failed_pair_count), so that edge case's behavior is unaffected.
722
+ shape_fn = None
723
+ target_tree = None
724
+ target_geometries: list[Any] = []
725
+
726
+ if final_engine in ("shapely", "auto"):
727
+ try:
728
+ shape_fn, STRtree = _get_strtree_tools()
729
+ built_target_geometries: list[Any] = []
730
+ all_targets_valid = True
731
+
732
+ for target_feature in target_items:
733
+ geometry = target_feature.get("geometry")
734
+ if not isinstance(geometry, dict):
735
+ all_targets_valid = False
736
+ break
737
+ try:
738
+ built_target_geometries.append(shape_fn(geometry))
739
+ except Exception:
740
+ all_targets_valid = False
741
+ break
742
+
743
+ if all_targets_valid and built_target_geometries:
744
+ target_geometries = built_target_geometries
745
+ target_tree = STRtree(target_geometries)
746
+ except SDKDependencyError:
747
+ target_tree = None
748
+
659
749
  for source_index, source_feature in enumerate(source_items):
660
750
  matches: list[tuple[int, dict[str, Any], str]] = []
661
751
  last_engine_used = final_engine
662
752
  last_error: str | None = None
663
753
 
664
- for target_index, target_feature in enumerate(target_items):
754
+ candidate_target_indices: list[int] | None = None
755
+
756
+ if target_tree is not None:
757
+ source_geometry = source_feature.get("geometry")
758
+ source_geom = None
759
+
760
+ if isinstance(source_geometry, dict):
761
+ try:
762
+ source_geom = shape_fn(source_geometry)
763
+ except Exception:
764
+ source_geom = None
765
+
766
+ if source_geom is not None:
767
+ candidate_target_indices = _strtree_query_indices(
768
+ target_tree, source_geom, target_geometries
769
+ )
770
+
771
+ if candidate_target_indices is not None:
772
+ target_pairs = [(i, target_items[i]) for i in candidate_target_indices]
773
+ else:
774
+ target_pairs = list(enumerate(target_items))
775
+
776
+ for target_index, target_feature in target_pairs:
665
777
  pair_count += 1
666
778
 
667
779
  try:
@@ -758,6 +870,7 @@ def spatial_join_features(
758
870
  "operation": "spatial_join",
759
871
  "engine_requested": final_engine,
760
872
  "engines_used": sorted(engines_used),
873
+ "spatial_index_used": target_tree is not None,
761
874
  "predicate": final_predicate,
762
875
  "join_type": final_join_type,
763
876
  "cardinality": final_cardinality,
@@ -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.7"
15
+ version = "0.2.9"
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.7
3
+ Version: 0.2.9
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
@@ -421,6 +421,8 @@ tests/test_service_structured_error_normalization.py
421
421
  tests/test_slope_aspect.py
422
422
  tests/test_spatial_intersection.py
423
423
  tests/test_spatial_join.py
424
+ tests/test_spatial_join_ring_buffer_cardinality.py
425
+ tests/test_spatial_join_strtree_performance.py
424
426
  tests/test_spatial_query_filter.py
425
427
  tests/test_spectral_indices.py
426
428
  tests/test_system_status_query_handler.py
@@ -0,0 +1,215 @@
1
+ """
2
+ Regression tests for the spatial_join cardinality / overlapping-ring-buffer
3
+ undercounting bug found in the smart-spatial-tehran-tod-gradient case
4
+ study.
5
+
6
+ spatial_join_features defaults params.cardinality to "first": a source
7
+ feature matching several target features is only joined to the first one
8
+ found, not all of them. When the target layer is a ring_buffer output (or
9
+ any layer with multiple zones generated from separate input features),
10
+ those zones routinely overlap - so a source feature inside more than one
11
+ zone is silently undercounted with the default.
12
+
13
+ Two things are tested here:
14
+ 1. The underlying plugin behavior itself: with cardinality="first"
15
+ (the default), a point inside two overlapping station rings is
16
+ only counted once; with cardinality="one_to_many" it is counted
17
+ once per matching ring/station, as it should be.
18
+ 2. That LLMQuerySpecGenerator.generate() now defaults cardinality to
19
+ "one_to_many" automatically when a spatial_join's target traces
20
+ back to a ring_buffer op and the caller left cardinality unset -
21
+ so this is fixed at the system level, not just documented in the
22
+ prompt.
23
+
24
+ Run:
25
+ pytest tests/test_spatial_join_ring_buffer_cardinality.py -v
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import json
31
+ import sys
32
+ from pathlib import Path
33
+
34
+ import pytest
35
+
36
+ PROJECT_ROOT = Path(__file__).resolve().parents[1]
37
+ if str(PROJECT_ROOT) not in sys.path:
38
+ sys.path.insert(0, str(PROJECT_ROOT))
39
+
40
+ pytest.importorskip("shapely")
41
+
42
+ from orchestrator.planning.llm_spec_generator import ( # noqa: E402
43
+ LLMQuerySpecGenerator,
44
+ StaticLLMClient,
45
+ )
46
+ from plugins.ring_buffer_analysis import generate_ring_buffers # noqa: E402
47
+ from plugins.spatial_join import spatial_join_features # noqa: E402
48
+
49
+
50
+ def _two_overlapping_stations():
51
+ return [
52
+ {
53
+ "type": "Feature",
54
+ "geometry": {"type": "Point", "coordinates": [0.0, 0.0]},
55
+ "properties": {"station_id": "A"},
56
+ },
57
+ {
58
+ "type": "Feature",
59
+ "geometry": {"type": "Point", "coordinates": [1000.0, 0.0]},
60
+ "properties": {"station_id": "B"},
61
+ },
62
+ ]
63
+
64
+
65
+ def _amenity_point_between_them():
66
+ return [
67
+ {
68
+ "type": "Feature",
69
+ "geometry": {"type": "Point", "coordinates": [500.0, 0.0]},
70
+ "properties": {"amenity_id": "cafe-1"},
71
+ }
72
+ ]
73
+
74
+
75
+ # ------------------------------------------------------------------ #
76
+ # 1. Plugin-level behavior: cardinality="first" undercounts overlapping
77
+ # ring-buffer zones; cardinality="one_to_many" does not.
78
+ # ------------------------------------------------------------------ #
79
+
80
+ def test_default_cardinality_undercounts_a_point_in_two_overlapping_rings():
81
+ stations = _two_overlapping_stations()
82
+ amenity = _amenity_point_between_them()
83
+
84
+ rings = generate_ring_buffers(
85
+ features=stations,
86
+ distances=[1200],
87
+ engine="shapely",
88
+ )
89
+
90
+ # Sanity check on the fixture: the amenity point (500m from each
91
+ # station, stations 1000m apart) must fall inside BOTH 1200m rings.
92
+ assert rings.metadata["output_feature_count"] == 2
93
+
94
+ joined = spatial_join_features(
95
+ source_features=amenity,
96
+ target_features=rings,
97
+ predicate="within",
98
+ # cardinality intentionally omitted - exercising the plugin's
99
+ # own default ("first").
100
+ )
101
+
102
+ assert joined.metadata["cardinality"] == "first"
103
+ assert len(joined.features) == 1
104
+
105
+ matched_station_ids = {
106
+ f["properties"]["_joined_target_properties"]["station_id"]
107
+ for f in joined.features
108
+ }
109
+ assert len(matched_station_ids) == 1
110
+
111
+
112
+ def test_one_to_many_cardinality_counts_the_point_for_every_overlapping_ring():
113
+ stations = _two_overlapping_stations()
114
+ amenity = _amenity_point_between_them()
115
+
116
+ rings = generate_ring_buffers(
117
+ features=stations,
118
+ distances=[1200],
119
+ engine="shapely",
120
+ )
121
+
122
+ joined = spatial_join_features(
123
+ source_features=amenity,
124
+ target_features=rings,
125
+ predicate="within",
126
+ cardinality="one_to_many",
127
+ include_target_properties=True,
128
+ )
129
+
130
+ assert joined.metadata["cardinality"] == "one_to_many"
131
+ assert len(joined.features) == 2
132
+
133
+ matched_station_ids = {
134
+ f["properties"]["_joined_target_properties"]["station_id"]
135
+ for f in joined.features
136
+ }
137
+ assert matched_station_ids == {"A", "B"}
138
+
139
+
140
+ # ------------------------------------------------------------------ #
141
+ # 2. LLMQuerySpecGenerator: cardinality auto-defaults to "one_to_many"
142
+ # when spatial_join's target traces back to ring_buffer and the
143
+ # caller left cardinality unset.
144
+ # ------------------------------------------------------------------ #
145
+
146
+ def _tod_gradient_spec_json(*, include_cardinality: bool) -> dict:
147
+ join_params = {"predicate": "within", "include_target_properties": True}
148
+ if include_cardinality:
149
+ join_params["cardinality"] = "first"
150
+
151
+ return {
152
+ "raw_query": "for each amenity point, which station rings does it fall into",
153
+ "goal": "tod_gradient",
154
+ "entities": [
155
+ {"ref": "amenity", "kind": "vector"},
156
+ {"ref": "stations", "kind": "vector"},
157
+ ],
158
+ "operations": [
159
+ {
160
+ "op": "crs_transform",
161
+ "inputs": {"vector": "amenity"},
162
+ "params": {"source_crs": "EPSG:4326", "target_crs": "EPSG:32639"},
163
+ "output": "amenity_metric",
164
+ },
165
+ {
166
+ "op": "crs_transform",
167
+ "inputs": {"vector": "stations"},
168
+ "params": {"source_crs": "EPSG:4326", "target_crs": "EPSG:32639"},
169
+ "output": "stations_metric",
170
+ },
171
+ {
172
+ "op": "ring_buffer",
173
+ "inputs": {"vector": "stations_metric"},
174
+ "params": {"distances": [200, 500, 800, 1200]},
175
+ "output": "stations_rings",
176
+ },
177
+ {
178
+ "op": "spatial_join",
179
+ "inputs": {"source": "amenity_metric", "target": "stations_rings"},
180
+ "params": join_params,
181
+ "output": "amenity_with_zone",
182
+ },
183
+ ],
184
+ "outputs": [
185
+ {"kind": "vector_layer", "source": "amenity_with_zone", "config": {}}
186
+ ],
187
+ }
188
+
189
+
190
+ def test_generate_defaults_cardinality_to_one_to_many_for_ring_buffer_target():
191
+ llm_json = _tod_gradient_spec_json(include_cardinality=False)
192
+
193
+ client = StaticLLMClient(json.dumps(llm_json, ensure_ascii=False))
194
+ generator = LLMQuerySpecGenerator(client)
195
+
196
+ spec = generator.generate(
197
+ "for each amenity point, which station rings does it fall into"
198
+ )
199
+
200
+ join_op = next(op for op in spec.operations if op.op == "spatial_join")
201
+ assert join_op.params["cardinality"] == "one_to_many"
202
+
203
+
204
+ def test_generate_does_not_override_an_explicit_cardinality():
205
+ llm_json = _tod_gradient_spec_json(include_cardinality=True)
206
+
207
+ client = StaticLLMClient(json.dumps(llm_json, ensure_ascii=False))
208
+ generator = LLMQuerySpecGenerator(client)
209
+
210
+ spec = generator.generate(
211
+ "for each amenity point, which station rings does it fall into"
212
+ )
213
+
214
+ join_op = next(op for op in spec.operations if op.op == "spatial_join")
215
+ assert join_op.params["cardinality"] == "first"